mirror of
https://github.com/safing/portmaster
synced 2025-09-01 18:19:12 +00:00
parent
9636777b30
commit
5b80a0b95e
7 changed files with 67 additions and 56 deletions
|
@ -15,6 +15,7 @@ import (
|
|||
"github.com/google/renameio"
|
||||
|
||||
"github.com/safing/portbase/log"
|
||||
"github.com/safing/portbase/utils"
|
||||
)
|
||||
|
||||
var (
|
||||
|
@ -37,15 +38,15 @@ func fetchFile(realFilepath, updateFilepath string, tries int) error {
|
|||
|
||||
// check destination dir
|
||||
dirPath := filepath.Dir(realFilepath)
|
||||
err = CheckDir(dirPath)
|
||||
err = utils.EnsureDirectory(dirPath, 0755)
|
||||
if err != nil {
|
||||
return fmt.Errorf("updates: could not create updates folder: %s", dirPath)
|
||||
return fmt.Errorf("could not create updates folder: %s", dirPath)
|
||||
}
|
||||
|
||||
// open file for writing
|
||||
atomicFile, err := renameio.TempFile(filepath.Join(updateStoragePath, "tmp"), realFilepath)
|
||||
atomicFile, err := renameio.TempFile(downloadTmpPath, realFilepath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("updates: could not create temp file for download: %s", err)
|
||||
return fmt.Errorf("could not create temp file for download: %s", err)
|
||||
}
|
||||
defer atomicFile.Cleanup()
|
||||
|
||||
|
@ -62,7 +63,7 @@ func fetchFile(realFilepath, updateFilepath string, tries int) error {
|
|||
return fmt.Errorf("failed downloading %s: %s", downloadURL, err)
|
||||
}
|
||||
if resp.ContentLength != n {
|
||||
return fmt.Errorf("download unfinished, written %d out of %d bytes.", n, resp.ContentLength)
|
||||
return fmt.Errorf("download unfinished, written %d out of %d bytes", n, resp.ContentLength)
|
||||
}
|
||||
|
||||
// finalize file
|
||||
|
@ -72,7 +73,8 @@ func fetchFile(realFilepath, updateFilepath string, tries int) error {
|
|||
}
|
||||
// set permissions
|
||||
if runtime.GOOS != "windows" {
|
||||
err = os.Chmod(realFilepath, 0644)
|
||||
// FIXME: only set executable files to 0755, set other to 0644
|
||||
err = os.Chmod(realFilepath, 0755)
|
||||
if err != nil {
|
||||
log.Warningf("updates: failed to set permissions on downloaded file %s: %s", realFilepath, err)
|
||||
}
|
||||
|
@ -108,7 +110,7 @@ func fetchData(downloadPath string, tries int) ([]byte, error) {
|
|||
return nil, fmt.Errorf("failed downloading %s: %s", downloadURL, err)
|
||||
}
|
||||
if resp.ContentLength != n {
|
||||
return nil, fmt.Errorf("download unfinished, written %d out of %d bytes.", n, resp.ContentLength)
|
||||
return nil, fmt.Errorf("download unfinished, written %d out of %d bytes", n, resp.ContentLength)
|
||||
}
|
||||
|
||||
return buf.Bytes(), nil
|
||||
|
|
|
@ -7,6 +7,7 @@ type File struct {
|
|||
stable bool
|
||||
}
|
||||
|
||||
// NewFile combines update file attributes into an easy to use object.
|
||||
func NewFile(filepath string, version string, stable bool) *File {
|
||||
return &File{
|
||||
filepath: filepath,
|
||||
|
|
|
@ -8,6 +8,7 @@ import (
|
|||
|
||||
var versionRegex = regexp.MustCompile("_v[0-9]+-[0-9]+-[0-9]+b?")
|
||||
|
||||
// GetIdentifierAndVersion splits the given file path into its identifier and version.
|
||||
func GetIdentifierAndVersion(versionedPath string) (identifier, version string, ok bool) {
|
||||
// extract version
|
||||
rawVersion := versionRegex.FindString(versionedPath)
|
||||
|
@ -27,6 +28,7 @@ func GetIdentifierAndVersion(versionedPath string) (identifier, version string,
|
|||
return versionedPath[:i] + versionedPath[i+len(rawVersion):], version, true
|
||||
}
|
||||
|
||||
// GetVersionedPath combines the identifier and version and returns it as a file path.
|
||||
func GetVersionedPath(identifier, version string) (versionedPath string) {
|
||||
// split in half
|
||||
splittedFilePath := strings.SplitN(identifier, ".", 2)
|
||||
|
|
|
@ -9,10 +9,12 @@ import (
|
|||
"runtime"
|
||||
|
||||
"github.com/safing/portbase/log"
|
||||
"github.com/safing/portbase/utils"
|
||||
)
|
||||
|
||||
// Errors
|
||||
var (
|
||||
ErrNotFound = errors.New("the requested file could not be found")
|
||||
ErrNotFound = errors.New("the requested file could not be found")
|
||||
ErrNotAvailableLocally = errors.New("the requested file is not available locally")
|
||||
)
|
||||
|
||||
|
@ -81,12 +83,12 @@ func loadOrFetchFile(identifier string, fetch bool) (*File, error) {
|
|||
}
|
||||
|
||||
// check download dir
|
||||
err := CheckDir(filepath.Join(updateStoragePath, "tmp"))
|
||||
err := utils.EnsureDirectory(downloadTmpPath, 0755)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not prepare tmp directory for download: %s", err)
|
||||
}
|
||||
|
||||
if (!fetch) {
|
||||
if !fetch {
|
||||
return nil, ErrNotAvailableLocally
|
||||
}
|
||||
|
||||
|
|
|
@ -62,6 +62,7 @@ func LoadLatest() error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// ScanForLatest scan the local update directory and returns a map of the latest/newest component versions.
|
||||
func ScanForLatest(baseDir string, hardFail bool) (latest map[string]string, lastError error) {
|
||||
var added int
|
||||
latest = make(map[string]string)
|
||||
|
@ -117,6 +118,7 @@ func ScanForLatest(baseDir string, hardFail bool) (latest map[string]string, las
|
|||
return latest, nil
|
||||
}
|
||||
|
||||
// LoadIndexes loads the current update indexes from disk.
|
||||
func LoadIndexes() error {
|
||||
data, err := ioutil.ReadFile(filepath.Join(updateStoragePath, "stable.json"))
|
||||
if err != nil {
|
||||
|
|
|
@ -2,7 +2,6 @@ package updates
|
|||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
|
@ -10,21 +9,24 @@ import (
|
|||
"github.com/safing/portbase/info"
|
||||
"github.com/safing/portbase/log"
|
||||
"github.com/safing/portbase/modules"
|
||||
"github.com/safing/portbase/utils"
|
||||
)
|
||||
|
||||
var (
|
||||
updateStoragePath string
|
||||
downloadTmpPath string
|
||||
)
|
||||
|
||||
// SetDatabaseRoot tells the updates module where the database is - and where to put its stuff.
|
||||
func SetDatabaseRoot(path string) {
|
||||
if updateStoragePath == "" {
|
||||
updateStoragePath = filepath.Join(path, "updates")
|
||||
downloadTmpPath = filepath.Join(updateStoragePath, "tmp")
|
||||
}
|
||||
}
|
||||
|
||||
func init() {
|
||||
modules.Register("updates", prep, start, nil, "core")
|
||||
modules.Register("updates", prep, start, stop, "core")
|
||||
}
|
||||
|
||||
func prep() error {
|
||||
|
@ -33,8 +35,14 @@ func prep() error {
|
|||
return errors.New("database root is not set")
|
||||
}
|
||||
updateStoragePath = filepath.Join(dbRoot, "updates")
|
||||
downloadTmpPath = filepath.Join(updateStoragePath, "tmp")
|
||||
|
||||
err := CheckDir(updateStoragePath)
|
||||
err := utils.EnsureDirectory(updateStoragePath, 0755)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = utils.EnsureDirectory(downloadTmpPath, 0700)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -70,34 +78,6 @@ func start() error {
|
|||
}
|
||||
|
||||
func stop() error {
|
||||
return os.RemoveAll(filepath.Join(updateStoragePath, "tmp"))
|
||||
}
|
||||
|
||||
func CheckDir(dirPath string) error {
|
||||
f, err := os.Stat(dirPath)
|
||||
if err == nil {
|
||||
// file exists
|
||||
if f.IsDir() {
|
||||
return nil
|
||||
}
|
||||
err = os.Remove(dirPath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not remove file %s to place dir: %s", dirPath, err)
|
||||
}
|
||||
err = os.MkdirAll(dirPath, 0755)
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not create dir %s: %s", dirPath, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
// file does not exist
|
||||
if os.IsNotExist(err) {
|
||||
err = os.MkdirAll(dirPath, 0755)
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not create dir %s: %s", dirPath, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
// other error
|
||||
return fmt.Errorf("failed to access %s: %s", dirPath, err)
|
||||
// delete download tmp dir
|
||||
return os.RemoveAll(downloadTmpPath)
|
||||
}
|
||||
|
|
|
@ -3,7 +3,9 @@ package updates
|
|||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"time"
|
||||
|
@ -22,18 +24,24 @@ func updater() {
|
|||
}
|
||||
}
|
||||
|
||||
func CheckForUpdates() error {
|
||||
func markFileForDownload(identifier string) {
|
||||
// get file
|
||||
_, ok := localUpdates[identifier]
|
||||
// only mark if it does not yet exist
|
||||
if !ok {
|
||||
localUpdates[identifier] = "loading..."
|
||||
}
|
||||
}
|
||||
|
||||
// ensure core components are updated
|
||||
var err error
|
||||
if runtime.GOOS == "windows" {
|
||||
_, err = GetPlatformFile("pmctl/pmctl.exe")
|
||||
} else {
|
||||
_, err = GetPlatformFile("pmctl/pmctl")
|
||||
}
|
||||
if err != nil {
|
||||
log.Errorf("updates: failed to mark pmctl/pmctl as used to ensure updates: %s", err)
|
||||
}
|
||||
func markPlatformFileForDownload(identifier string) {
|
||||
// add platform prefix
|
||||
identifier = path.Join(fmt.Sprintf("%s_%s", runtime.GOOS, runtime.GOARCH), identifier)
|
||||
// mark file
|
||||
markFileForDownload(identifier)
|
||||
}
|
||||
|
||||
// CheckForUpdates checks if updates are available and downloads updates of used components.
|
||||
func CheckForUpdates() (err error) {
|
||||
|
||||
// download new index
|
||||
var data []byte
|
||||
|
@ -60,6 +68,19 @@ func CheckForUpdates() error {
|
|||
// FIXME IN STABLE: correct log line
|
||||
log.Infof("updates: downloaded new update index: stable.json (alpha until we actually reach stable)")
|
||||
|
||||
// ensure important components are always updated
|
||||
updatesLock.Lock()
|
||||
if runtime.GOOS == "windows" {
|
||||
markPlatformFileForDownload("control/portmaster-control.exe")
|
||||
markPlatformFileForDownload("app/portmaster-app.exe")
|
||||
markPlatformFileForDownload("notifier/portmaster-notifier.exe")
|
||||
} else {
|
||||
markPlatformFileForDownload("control/portmaster-control")
|
||||
markPlatformFileForDownload("app/portmaster-app")
|
||||
markPlatformFileForDownload("notifier/portmaster-notifier")
|
||||
}
|
||||
updatesLock.Unlock()
|
||||
|
||||
// update existing files
|
||||
log.Tracef("updates: updating existing files")
|
||||
updatesLock.RLock()
|
||||
|
@ -67,16 +88,17 @@ func CheckForUpdates() error {
|
|||
oldVersion, ok := localUpdates[identifier]
|
||||
if ok && newVersion != oldVersion {
|
||||
|
||||
log.Tracef("updates: updating %s to %s", identifier, newVersion)
|
||||
filePath := GetVersionedPath(identifier, newVersion)
|
||||
realFilePath := filepath.Join(updateStoragePath, filePath)
|
||||
for tries := 0; tries < 3; tries++ {
|
||||
err := fetchFile(realFilePath, filePath, tries)
|
||||
err = fetchFile(realFilePath, filePath, tries)
|
||||
if err == nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
log.Warningf("failed to update %s to %s: %s", identifier, newVersion, err)
|
||||
log.Warningf("updates: failed to update %s to %s: %s", identifier, newVersion, err)
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue