From 102a2db1f3fca8a8f0a1b595b044b1b6deda570f Mon Sep 17 00:00:00 2001 From: Jakob Borg Date: Tue, 14 Apr 2015 19:31:25 +0900 Subject: [PATCH] Work around broken Lstat on Android --- cmd/syncthing/main.go | 2 +- internal/model/model.go | 2 +- internal/model/rwfolder.go | 4 ++-- internal/osutil/lstat_broken.go | 29 ++++++++++++++++++++++++++++ internal/osutil/lstat_ok.go | 15 ++++++++++++++ internal/scanner/walk.go | 5 +++-- internal/symlinks/symlink_windows.go | 2 +- internal/versioner/external.go | 6 ++++-- internal/versioner/simple.go | 2 +- internal/versioner/staggered.go | 4 ++-- 10 files changed, 59 insertions(+), 12 deletions(-) create mode 100644 internal/osutil/lstat_broken.go create mode 100644 internal/osutil/lstat_ok.go diff --git a/cmd/syncthing/main.go b/cmd/syncthing/main.go index 21b42722d..0e43d2593 100644 --- a/cmd/syncthing/main.go +++ b/cmd/syncthing/main.go @@ -1019,7 +1019,7 @@ func cleanConfigDirectory() { } for _, file := range files { - info, err := os.Lstat(file) + info, err := osutil.Lstat(file) if err != nil { l.Infoln("Cleaning:", err) continue diff --git a/internal/model/model.go b/internal/model/model.go index c1cd50162..40ba00539 100644 --- a/internal/model/model.go +++ b/internal/model/model.go @@ -1271,7 +1271,7 @@ nextSub: "size": f.Size(), }) batch = append(batch, nf) - } else if _, err := os.Lstat(filepath.Join(folderCfg.Path(), f.Name)); err != nil { + } else if _, err := osutil.Lstat(filepath.Join(folderCfg.Path(), f.Name)); err != nil { // File has been deleted. // We don't specifically verify that the error is diff --git a/internal/model/rwfolder.go b/internal/model/rwfolder.go index 4c57360a5..ceb8e0a92 100644 --- a/internal/model/rwfolder.go +++ b/internal/model/rwfolder.go @@ -499,7 +499,7 @@ func (p *rwFolder) handleDir(file protocol.FileInfo) { l.Debugf("need dir\n\t%v\n\t%v", file, curFile) } - info, err := os.Lstat(realName) + info, err := osutil.Lstat(realName) switch { // There is already something under that name, but it's a file/link. // Most likely a file/link is getting replaced with a directory. @@ -1044,7 +1044,7 @@ func (p *rwFolder) performFinish(state *sharedPullerState) { // If the target path is a symlink or a directory, we cannot copy // over it, hence remove it before proceeding. - stat, err := os.Lstat(state.realName) + stat, err := osutil.Lstat(state.realName) if err == nil && (stat.IsDir() || stat.Mode()&os.ModeSymlink != 0) { osutil.InWritableDir(os.Remove, state.realName) } diff --git a/internal/osutil/lstat_broken.go b/internal/osutil/lstat_broken.go new file mode 100644 index 000000000..11a20b1c9 --- /dev/null +++ b/internal/osutil/lstat_broken.go @@ -0,0 +1,29 @@ +// Copyright (C) 2015 The Syncthing Authors. +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this file, +// You can obtain one at http://mozilla.org/MPL/2.0/. + +// +build linux android + +package osutil + +import ( + "os" + "syscall" + "time" +) + +// Lstat is like os.Lstat, except lobotomized for Android. See +// https://forum.syncthing.net/t/2395 +func Lstat(name string) (fi os.FileInfo, err error) { + for i := 0; i < 10; i++ { // We have to draw the line somewhere + fi, err = os.Lstat(name) + if err, ok := err.(*os.PathError); ok && err.Err == syscall.EINTR { + time.Sleep(time.Duration(i+1) * time.Millisecond) + continue + } + return + } + return +} diff --git a/internal/osutil/lstat_ok.go b/internal/osutil/lstat_ok.go new file mode 100644 index 000000000..770e18f51 --- /dev/null +++ b/internal/osutil/lstat_ok.go @@ -0,0 +1,15 @@ +// Copyright (C) 2015 The Syncthing Authors. +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this file, +// You can obtain one at http://mozilla.org/MPL/2.0/. + +// +build !linux,!android + +package osutil + +import "os" + +func Lstat(name string) (fi os.FileInfo, err error) { + return os.Lstat(name) +} diff --git a/internal/scanner/walk.go b/internal/scanner/walk.go index e11a1193c..5bfae552d 100644 --- a/internal/scanner/walk.go +++ b/internal/scanner/walk.go @@ -17,6 +17,7 @@ import ( "github.com/syncthing/protocol" "github.com/syncthing/syncthing/internal/ignore" + "github.com/syncthing/syncthing/internal/osutil" "github.com/syncthing/syncthing/internal/symlinks" "golang.org/x/text/unicode/norm" ) @@ -193,7 +194,7 @@ func (w *Walker) walkAndHashFiles(fchan chan protocol.FileInfo) filepath.WalkFun // We will attempt to normalize it. normalizedPath := filepath.Join(w.Dir, normalizedRn) - if _, err := os.Lstat(normalizedPath); os.IsNotExist(err) { + if _, err := osutil.Lstat(normalizedPath); os.IsNotExist(err) { // Nothing exists with the normalized filename. Good. if err = os.Rename(p, normalizedPath); err != nil { l.Infof(`Error normalizing UTF8 encoding of file "%s": %v`, rn, err) @@ -356,7 +357,7 @@ func (w *Walker) walkAndHashFiles(fchan chan protocol.FileInfo) filepath.WalkFun } func checkDir(dir string) error { - if info, err := os.Lstat(dir); err != nil { + if info, err := osutil.Lstat(dir); err != nil { return err } else if !info.IsDir() { return errors.New(dir + ": not a directory") diff --git a/internal/symlinks/symlink_windows.go b/internal/symlinks/symlink_windows.go index 491217d0a..c41830664 100644 --- a/internal/symlinks/symlink_windows.go +++ b/internal/symlinks/symlink_windows.go @@ -60,7 +60,7 @@ func init() { return } - stat, err := os.Lstat(path) + stat, err := osutil.Lstat(path) if err != nil || stat.Mode()&os.ModeSymlink == 0 { return } diff --git a/internal/versioner/external.go b/internal/versioner/external.go index 343862107..027137ca1 100644 --- a/internal/versioner/external.go +++ b/internal/versioner/external.go @@ -12,6 +12,8 @@ import ( "os/exec" "path/filepath" "strings" + + "github.com/syncthing/syncthing/internal/osutil" ) func init() { @@ -43,7 +45,7 @@ func NewExternal(folderID, folderPath string, params map[string]string) Versione // Move away the named file to a version archive. If this function returns // nil, the named file does not exist any more (has been archived). func (v External) Archive(filePath string) error { - _, err := os.Lstat(filePath) + _, err := osutil.Lstat(filePath) if os.IsNotExist(err) { if debug { l.Debugln("not archiving nonexistent file", filePath) @@ -82,7 +84,7 @@ func (v External) Archive(filePath string) error { } // return error if the file was not removed - if _, err = os.Lstat(filePath); os.IsNotExist(err) { + if _, err = osutil.Lstat(filePath); os.IsNotExist(err) { return nil } return errors.New("Versioner: file was not removed by external script") diff --git a/internal/versioner/simple.go b/internal/versioner/simple.go index f621fef3b..d179bee43 100644 --- a/internal/versioner/simple.go +++ b/internal/versioner/simple.go @@ -46,7 +46,7 @@ func NewSimple(folderID, folderPath string, params map[string]string) Versioner // Move away the named file to a version archive. If this function returns // nil, the named file does not exist any more (has been archived). func (v Simple) Archive(filePath string) error { - fileInfo, err := os.Lstat(filePath) + fileInfo, err := osutil.Lstat(filePath) if os.IsNotExist(err) { if debug { l.Debugln("not archiving nonexistent file", filePath) diff --git a/internal/versioner/staggered.go b/internal/versioner/staggered.go index c2b78b081..cf122e6a8 100644 --- a/internal/versioner/staggered.go +++ b/internal/versioner/staggered.go @@ -210,7 +210,7 @@ func (v Staggered) expire(versions []string) { var prevAge int64 firstFile := true for _, file := range versions { - fi, err := os.Lstat(file) + fi, err := osutil.Lstat(file) if err != nil { l.Warnln("versioner:", err) continue @@ -281,7 +281,7 @@ func (v Staggered) Archive(filePath string) error { v.mutex.Lock() defer v.mutex.Unlock() - _, err := os.Lstat(filePath) + _, err := osutil.Lstat(filePath) if os.IsNotExist(err) { if debug { l.Debugln("not archiving nonexistent file", filePath)