lib/scanner: Use fs.Filesystem for all operations

One more step on the path of the great refactoring. Touches rwfolder a
little bit since it uses the Lstat from fs as well, but mostly this is
just on the scanner as rwfolder is scheduled for a later refactor.

There are a couple of usages of fs.DefaultFilesystem that will in the
end become a filesystem injected from the top, but that comes later.

GitHub-Pull-Request: https://github.com/syncthing/syncthing/pull/4070
LGTM: AudriusButkevicius, imsodin
This commit is contained in:
Jakob Borg
2017-04-01 09:04:11 +00:00
committed by Simon Frei
parent bdb56d91b9
commit 4253f22680
13 changed files with 191 additions and 103 deletions

View File

@@ -32,7 +32,7 @@ func (f *BasicFilesystem) Mkdir(name string, perm FileMode) error {
}
func (f *BasicFilesystem) Lstat(name string) (FileInfo, error) {
fi, err := os.Lstat(name)
fi, err := underlyingLstat(name)
if err != nil {
return nil, err
}
@@ -71,11 +71,32 @@ func (f *BasicFilesystem) DirNames(name string) ([]string, error) {
}
func (f *BasicFilesystem) Open(name string) (File, error) {
return os.Open(name)
fd, err := os.Open(name)
if err != nil {
return nil, err
}
return fsFile{fd}, err
}
func (f *BasicFilesystem) Create(name string) (File, error) {
return os.Create(name)
fd, err := os.Create(name)
if err != nil {
return nil, err
}
return fsFile{fd}, err
}
// fsFile implements the fs.File interface on top of an os.File
type fsFile struct {
*os.File
}
func (f fsFile) Stat() (FileInfo, error) {
info, err := f.File.Stat()
if err != nil {
return nil, err
}
return fsFileInfo{info}, nil
}
// fsFileInfo implements the fs.FileInfo interface on top of an os.FileInfo.

View File

@@ -7,8 +7,9 @@
package fs
import (
"errors"
"io"
"os"
"path/filepath"
"time"
)
@@ -37,6 +38,7 @@ type File interface {
io.WriterAt
io.Closer
Truncate(size int64) error
Stat() (FileInfo, error)
}
// The FileInfo interface is almost the same as os.FileInfo, but with the
@@ -57,12 +59,20 @@ type FileInfo interface {
// FileMode is similar to os.FileMode
type FileMode uint32
// ModePerm is the equivalent of os.ModePerm
const ModePerm = FileMode(os.ModePerm)
// DefaultFilesystem is the fallback to use when nothing explicitly has
// been passed.
var DefaultFilesystem Filesystem = new(BasicFilesystem)
var DefaultFilesystem Filesystem = NewBasicFilesystem()
// SkipDir is used as a return value from WalkFuncs to indicate that
// the directory named in the call is to be skipped. It is not returned
// as an error by any function.
var errSkipDir = errors.New("skip this directory")
var SkipDir = errSkipDir // silences the lint warning...
var SkipDir = filepath.SkipDir
// IsExist is the equivalent of os.IsExist
var IsExist = os.IsExist
// IsNotExist is the equivalent of os.IsNotExist
var IsNotExist = os.IsNotExist

29
lib/fs/lstat_broken.go Normal file
View File

@@ -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 https://mozilla.org/MPL/2.0/.
// +build linux android
package fs
import (
"os"
"syscall"
"time"
)
// Lstat is like os.Lstat, except lobotomized for Android. See
// https://forum.syncthing.net/t/2395
func underlyingLstat(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
}

15
lib/fs/lstat_regular.go Normal file
View File

@@ -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 https://mozilla.org/MPL/2.0/.
// +build !linux,!android
package fs
import "os"
func underlyingLstat(name string) (fi os.FileInfo, err error) {
return os.Lstat(name)
}

View File

@@ -27,12 +27,14 @@ var osChtimes = os.Chtimes
// of what shenanigans the underlying filesystem gets up to. A nil MtimeFS
// just does the underlying operations with no additions.
type MtimeFS struct {
Filesystem
db database
}
func NewMtimeFS(db database) *MtimeFS {
func NewMtimeFS(underlying Filesystem, db database) *MtimeFS {
return &MtimeFS{
db: db,
Filesystem: underlying,
db: db,
}
}
@@ -56,12 +58,8 @@ func (f *MtimeFS) Chtimes(name string, atime, mtime time.Time) error {
return nil
}
func (f *MtimeFS) Lstat(name string) (os.FileInfo, error) {
if f == nil {
return osutil.Lstat(name)
}
info, err := osutil.Lstat(name)
func (f *MtimeFS) Lstat(name string) (FileInfo, error) {
info, err := f.Filesystem.Lstat(name)
if err != nil {
return nil, err
}
@@ -113,7 +111,7 @@ func (f *MtimeFS) load(name string) (real, virtual time.Time) {
// The mtimeFileInfo is an os.FileInfo that lies about the ModTime().
type mtimeFileInfo struct {
os.FileInfo
FileInfo
mtime time.Time
}

View File

@@ -25,7 +25,7 @@ func TestMtimeFS(t *testing.T) {
// a random time with nanosecond precision
testTime := time.Unix(1234567890, 123456789)
mtimefs := NewMtimeFS(make(mapStore))
mtimefs := NewMtimeFS(DefaultFilesystem, make(mapStore))
// Do one Chtimes call that will go through to the normal filesystem
osChtimes = os.Chtimes