Compare commits

..

10 Commits

Author SHA1 Message Date
Jakob Borg
1be4b8bb5d Merge pull request #486 from AudriusButkevicius/windows
Add Windows upgrade support
2014-08-07 23:20:26 +02:00
Jakob Borg
c832fc9917 Merge pull request #485 from tojrobinson/world-writable-root
World writable root
2014-08-07 23:17:42 +02:00
Jakob Borg
4797a94689 Add explicit GC calls after expensive db ops (ref #468) 2014-08-07 23:09:50 +02:00
Audrius Butkevicius
6948903084 Add Windows upgrade support 2014-08-07 21:07:21 +01:00
treefingers
94164611ae Fix root being left world writable 2014-08-08 05:45:50 +10:00
treefingers
ae298e8902 Merge branch 'master' of https://github.com/syncthing/syncthing 2014-08-08 05:06:42 +10:00
Jakob Borg
3d8771ecb0 Woops, broke the build 2014-08-07 15:58:48 +02:00
Jakob Borg
28db264e90 Upgrade debugging, fix upgrade on ARM (fixes #482) 2014-08-07 15:57:20 +02:00
Jakob Borg
6af9fa4b81 Localize Close button in standard modals (fixes #481) 2014-08-07 12:35:38 +02:00
Tully Robinson
c45b18cc75 Merge branch 'master' into browser-flag 2014-08-06 23:01:35 +10:00
10 changed files with 224 additions and 12 deletions

View File

@@ -153,7 +153,7 @@ func init() {
bs, _ = ioutil.ReadAll(gr)
Assets["logo-text-64.png"] = bs
bs, _ = hex.DecodeString("1f8b080000096e8800ff7c91416eac300c86f7ef1451166f5688cdac5ae8a62731c4402493a0c48c8410776f0269caa84c171013fbf3efdf544a3f444be07d2d47ab8044070ae5c73f217ea50aa5816c2f85e98b74bfde8e0cf5b73741e07adc76f68a6ead61349cf2571503066d2780d0f1f12ed6d533f0ecb72d73811ceecf206b263c1584123f818983eaae963a48cb6fa2a7651ae28dc851508947d4a8ca089e3badebde7ddb7ee4cbe19e4d94c1c56b478d55cbbe2f76607c4bb3c2d7649ab625eb513ef7e9ac6574e715343373f0c0cb84b53c3e32d3b011e129147630134ba18021fc3d3feadc3258dd57f4c7561c8ef6817927ff71f4d3fb679cae2a0fc50b2f394c413abe000000ffff010000ffffe37f5ed168020000")
bs, _ = hex.DecodeString("1f8b080000096e8800ff7c91b16e84300c86f73e4594a13721969bdae3963e89210622990425e6248478f72690a69cca758098d89fedffe7a6f4433404de5772b00a48b4a050dedf84f8932a9406b29d14a62bd2fd72d933d45d3e0481eb70ddd833bab186d170ca9f55f418663b01848ef777b12c9e8127bfae990b647f7d065933e1a12094f8114c5c54b795d461b4fc213a9ac73ede881c8529f188336e65048f9d9665ebbeaebfe3cbfe9a459441c56b45b555f3e6173b30bea149e16b326ddb90f5289ffbb4d632baa305f5c41c34f03c6225f78fccd46c44780a852d4cc4522860087fcf0f3ab70c52378bfe71c5e1601f983d79c7c18f9f3bb5c92160bc7fc56d53c5addc17399198c314a4e31b0000ffff010000ffff3e1bbdca7f020000")
gr, _ = gzip.NewReader(bytes.NewBuffer(bs))
bs, _ = ioutil.ReadAll(gr)
Assets["modal.html"] = bs

View File

@@ -515,7 +515,7 @@ func restPostUpgrade(w http.ResponseWriter, r *http.Request) {
}
if upgrade.CompareVersions(rel.Tag, Version) == 1 {
err = upgrade.UpgradeTo(rel)
err = upgrade.UpgradeTo(rel, GoArchExtra)
if err != nil {
l.Warnln(err)
http.Error(w, err.Error(), 500)

View File

@@ -47,6 +47,7 @@ var (
BuildHost = "unknown"
BuildUser = "unknown"
LongVersion string
GoArchExtra string // "", "v5", "v6", "v7"
)
var l = logger.DefaultLogger
@@ -194,7 +195,7 @@ func main() {
l.Infof("Upgrade available (current %q < latest %q)", Version, rel.Tag)
if doUpgrade {
err = upgrade.UpgradeTo(rel)
err = upgrade.UpgradeTo(rel, GoArchExtra)
if err != nil {
l.Fatalln("Upgrade:", err) // exits 1
}

View File

@@ -2,6 +2,7 @@ package files
import (
"bytes"
"runtime"
"sort"
"sync"
@@ -121,6 +122,8 @@ type deletionHandler func(db dbReader, batch dbWriter, repo, node, name []byte,
type fileIterator func(f protocol.FileInfo) bool
func ldbGenericReplace(db *leveldb.DB, repo, node []byte, fs []protocol.FileInfo, deleteFn deletionHandler) uint64 {
defer runtime.GC()
sort.Sort(fileList(fs)) // sort list on name, same as on disk
start := nodeKey(repo, node, nil) // before all repo/node files
@@ -246,6 +249,8 @@ func ldbReplaceWithDelete(db *leveldb.DB, repo, node []byte, fs []protocol.FileI
}
func ldbUpdate(db *leveldb.DB, repo, node []byte, fs []protocol.FileInfo) uint64 {
defer runtime.GC()
batch := new(leveldb.Batch)
snap, err := db.GetSnapshot()
if err != nil {
@@ -414,6 +419,8 @@ func ldbWithHave(db *leveldb.DB, repo, node []byte, fn fileIterator) {
}
func ldbWithAllRepo(db *leveldb.DB, repo []byte, fn func(node []byte, f protocol.FileInfo) bool) {
defer runtime.GC()
start := nodeKey(repo, nil, nil) // before all repo/node files
limit := nodeKey(repo, protocol.LocalNodeID[:], []byte{0xff, 0xff, 0xff, 0xff}) // after all repo/node files
snap, err := db.GetSnapshot()
@@ -530,6 +537,8 @@ func ldbGetGlobal(db *leveldb.DB, repo, file []byte) protocol.FileInfo {
}
func ldbWithGlobal(db *leveldb.DB, repo []byte, fn fileIterator) {
defer runtime.GC()
start := globalKey(repo, nil)
limit := globalKey(repo, []byte{0xff, 0xff, 0xff, 0xff})
snap, err := db.GetSnapshot()
@@ -597,6 +606,8 @@ func ldbAvailability(db *leveldb.DB, repo, file []byte) []protocol.NodeID {
}
func ldbWithNeed(db *leveldb.DB, repo, node []byte, fn fileIterator) {
defer runtime.GC()
start := globalKey(repo, nil)
limit := globalKey(repo, []byte{0xff, 0xff, 0xff, 0xff})
snap, err := db.GetSnapshot()

View File

@@ -10,7 +10,7 @@
<div class="modal-body" ng-transclude>
</div>
<div ng-if="close" class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal"><span class="glyphicon glyphicon-remove"></span>&emsp;Close</button>
<button type="button" class="btn btn-default" data-dismiss="modal"><span class="glyphicon glyphicon-remove"></span>&emsp;<span translate>Close</span></button>
</div>
</div>
</div>

View File

@@ -441,7 +441,9 @@ func (p *puller) handleBlock(b bqBlock) bool {
err = os.MkdirAll(dirName, 0777)
} else {
// We need to make sure the directory is writeable so we can create files in it
err = os.Chmod(dirName, 0777)
if (dirName != p.repoCfg.Directory) {
err = os.Chmod(dirName, 0777)
}
}
if err != nil {
l.Infof("mkdir: error: %q / %q: %v", p.repoCfg.ID, f.Name, err)
@@ -600,9 +602,13 @@ func (p *puller) handleEmptyBlock(b bqBlock) {
l.Debugf("pull: delete %q", f.Name)
}
os.Remove(of.temp)
// Ensure the file and the directory it is in is writeable so we can remove the file
dirName := filepath.Dir(of.filepath)
os.Chmod(of.filepath, 0666)
os.Chmod(filepath.Dir(of.filepath), 0777)
if (dirName != p.repoCfg.Directory) {
os.Chmod(dirName, 0777)
}
if p.versioner != nil {
if debug {
l.Debugln("pull: deleting with versioner")

17
upgrade/debug.go Normal file
View File

@@ -0,0 +1,17 @@
// Copyright (C) 2014 Jakob Borg and Contributors (see the CONTRIBUTORS file).
// All rights reserved. Use of this source code is governed by an MIT-style
// license that can be found in the LICENSE file.
package upgrade
import (
"os"
"strings"
"github.com/syncthing/syncthing/logger"
)
var (
debug = strings.Contains(os.Getenv("STTRACE"), "upgrade") || os.Getenv("STTRACE") == "all"
l = logger.DefaultLogger
)

View File

@@ -23,10 +23,8 @@ import (
"bitbucket.org/kardianos/osext"
)
var GoArchExtra string // "", "v5", "v6", "v7"
// Upgrade to the given release, saving the previous binary with a ".old" extension.
func UpgradeTo(rel Release) error {
func UpgradeTo(rel Release, archExtra string) error {
path, err := osext.Executable()
if err != nil {
return err
@@ -38,8 +36,14 @@ func UpgradeTo(rel Release) error {
// sense for people downloading them
osName = "macosx"
}
expectedRelease := fmt.Sprintf("syncthing-%s-%s%s-%s.", osName, runtime.GOARCH, GoArchExtra, rel.Tag)
expectedRelease := fmt.Sprintf("syncthing-%s-%s%s-%s.", osName, runtime.GOARCH, archExtra, rel.Tag)
if debug {
l.Debugf("expected release asset %q", expectedRelease)
}
for _, asset := range rel.Assets {
if debug {
l.Debugln("considering release", asset)
}
if strings.HasPrefix(asset.Name, expectedRelease) {
if strings.HasSuffix(asset.Name, ".tar.gz") {
fname, err := readTarGZ(asset.URL, filepath.Dir(path))
@@ -97,6 +101,10 @@ func LatestRelease(prerelease bool) (Release, error) {
}
func readTarGZ(url string, dir string) (string, error) {
if debug {
l.Debugf("loading %q", url)
}
req, err := http.NewRequest("GET", url, nil)
if err != nil {
return "", err
@@ -129,6 +137,9 @@ func readTarGZ(url string, dir string) (string, error) {
if err != nil {
return "", err
}
if debug {
l.Debugf("considering file %q", hdr.Name)
}
if path.Base(hdr.Name) == "syncthing" {
of, err := ioutil.TempFile(dir, "syncthing")

View File

@@ -2,11 +2,11 @@
// All rights reserved. Use of this source code is governed by an MIT-style
// license that can be found in the LICENSE file.
// +build windows solaris noupgrade
// +build solaris noupgrade
package upgrade
func UpgradeTo(rel Release) error {
func UpgradeTo(rel Release, extra string) error {
return ErrUpgradeUnsupported
}

166
upgrade/upgrade_windows.go Executable file
View File

@@ -0,0 +1,166 @@
// Copyright (C) 2014 Jakob Borg and Contributors (see the CONTRIBUTORS file).
// All rights reserved. Use of this source code is governed by an MIT-style
// license that can be found in the LICENSE file.
// +build windows,!noupgrade
package upgrade
import (
"archive/zip"
"bytes"
"encoding/json"
"fmt"
"io"
"io/ioutil"
"net/http"
"os"
"path"
"path/filepath"
"runtime"
"strings"
"bitbucket.org/kardianos/osext"
)
// Upgrade to the given release, saving the previous binary with a ".old" extension.
func UpgradeTo(rel Release, archExtra string) error {
path, err := osext.Executable()
if err != nil {
return err
}
expectedRelease := fmt.Sprintf("syncthing-%s-%s%s-%s.", runtime.GOOS, runtime.GOARCH, archExtra, rel.Tag)
if debug {
l.Debugf("expected release asset %q", expectedRelease)
}
for _, asset := range rel.Assets {
if debug {
l.Debugln("considering release", asset)
}
if strings.HasPrefix(asset.Name, expectedRelease) {
if strings.HasSuffix(asset.Name, ".zip") {
fname, err := readZip(asset.URL, filepath.Dir(path))
if err != nil {
return err
}
old := path + ".old"
os.Remove(old)
err = os.Rename(path, old)
if err != nil {
return err
}
err = os.Rename(fname, path)
if err != nil {
return err
}
return nil
}
}
}
return ErrVersionUnknown
}
// Returns the latest release, including prereleases or not depending on the argument
func LatestRelease(prerelease bool) (Release, error) {
resp, err := http.Get("https://api.github.com/repos/syncthing/syncthing/releases?per_page=10")
if err != nil {
return Release{}, err
}
if resp.StatusCode > 299 {
return Release{}, fmt.Errorf("API call returned HTTP error: %s", resp.Status)
}
var rels []Release
json.NewDecoder(resp.Body).Decode(&rels)
resp.Body.Close()
if len(rels) == 0 {
return Release{}, ErrVersionUnknown
}
if prerelease {
// We are a beta version. Use the latest.
return rels[0], nil
} else {
// We are a regular release. Only consider non-prerelease versions for upgrade.
for _, rel := range rels {
if !rel.Prerelease {
return rel, nil
}
}
return Release{}, ErrVersionUnknown
}
}
func readZip(url, dir string) (string, error) {
if debug {
l.Debugf("loading %q", url)
}
req, err := http.NewRequest("GET", url, nil)
if err != nil {
return "", err
}
req.Header.Add("Accept", "application/octet-stream")
resp, err := http.DefaultClient.Do(req)
if err != nil {
return "", err
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return "", err
}
archive, err := zip.NewReader(bytes.NewReader(body), resp.ContentLength)
if err != nil {
return "", err
}
// Iterate through the files in the archive.
for _, file := range archive.File {
if debug {
l.Debugf("considering file %q", file.Name)
}
if path.Base(file.Name) == "syncthing.exe" {
infile, err := file.Open()
if err != nil {
return "", err
}
outfile, err := ioutil.TempFile(dir, "syncthing")
if err != nil {
return "", err
}
_, err = io.Copy(outfile, infile)
if err != nil {
return "", err
}
err = infile.Close()
if err != nil {
return "", err
}
err = outfile.Close()
if err != nil {
os.Remove(outfile.Name())
return "", err
}
os.Chmod(outfile.Name(), file.Mode())
return outfile.Name(), nil
}
}
return "", fmt.Errorf("No upgrade found")
}