From 02e35ee0021a6ba0a504b50f89ca4732dbb67beb Mon Sep 17 00:00:00 2001 From: Nicola Murino Date: Sat, 22 Aug 2020 14:52:17 +0200 Subject: [PATCH] sftpd: add Readlink support --- common/common.go | 1 + common/connection.go | 18 +++++++++++++--- common/connection_test.go | 4 ++-- common/transfer.go | 12 +++++++++++ common/transfer_test.go | 34 +++++++++++++++++++++++++++++-- dataprovider/user.go | 2 +- sftpd/handler.go | 17 ++++++++++++++++ sftpd/internal_test.go | 11 ++++++++++ sftpd/sftpd_test.go | 43 ++++++++++++++++++++++++++++++++++++--- vfs/fileinfo.go | 8 ++++++-- vfs/gcsfs.go | 21 +++++++++++-------- vfs/osfs.go | 14 +++++++++++-- vfs/s3fs.go | 21 +++++++++++-------- vfs/vfs.go | 1 + webdavd/file.go | 2 +- webdavd/internal_test.go | 12 +++++------ 16 files changed, 183 insertions(+), 38 deletions(-) diff --git a/common/common.go b/common/common.go index 3db62dbc..0eccee64 100644 --- a/common/common.go +++ b/common/common.go @@ -146,6 +146,7 @@ type ActiveTransfer interface { GetStartTime() time.Time SignalClose() Truncate(fsPath string, size int64) (int64, error) + GetRealFsPath(fsPath string) string } // ActiveConnection defines the interface for the current active connections diff --git a/common/connection.go b/common/connection.go index 434d2a75..ce03efac 100644 --- a/common/connection.go +++ b/common/connection.go @@ -172,6 +172,18 @@ func (c *BaseConnection) SignalTransfersAbort() error { return nil } +func (c *BaseConnection) getRealFsPath(fsPath string) string { + c.RLock() + defer c.RUnlock() + + for _, t := range c.activeTransfers { + if p := t.GetRealFsPath(fsPath); len(p) > 0 { + return p + } + } + return fsPath +} + func (c *BaseConnection) truncateOpenHandle(fsPath string, size int64) (int64, error) { c.RLock() defer c.RUnlock() @@ -439,7 +451,7 @@ func (c *BaseConnection) SetStat(fsPath, virtualPath string, attributes *StatAtt if !c.User.HasPerm(dataprovider.PermChmod, pathForPerms) { return c.GetPermissionDeniedError() } - if err := c.Fs.Chmod(fsPath, attributes.Mode); err != nil { + if err := c.Fs.Chmod(c.getRealFsPath(fsPath), attributes.Mode); err != nil { c.Log(logger.LevelWarn, "failed to chmod path %#v, mode: %v, err: %+v", fsPath, attributes.Mode.String(), err) return c.GetFsError(err) } @@ -451,7 +463,7 @@ func (c *BaseConnection) SetStat(fsPath, virtualPath string, attributes *StatAtt if !c.User.HasPerm(dataprovider.PermChown, pathForPerms) { return c.GetPermissionDeniedError() } - if err := c.Fs.Chown(fsPath, attributes.UID, attributes.GID); err != nil { + if err := c.Fs.Chown(c.getRealFsPath(fsPath), attributes.UID, attributes.GID); err != nil { c.Log(logger.LevelWarn, "failed to chown path %#v, uid: %v, gid: %v, err: %+v", fsPath, attributes.UID, attributes.GID, err) return c.GetFsError(err) @@ -465,7 +477,7 @@ func (c *BaseConnection) SetStat(fsPath, virtualPath string, attributes *StatAtt return c.GetPermissionDeniedError() } - if err := c.Fs.Chtimes(fsPath, attributes.Atime, attributes.Mtime); err != nil { + if err := c.Fs.Chtimes(c.getRealFsPath(fsPath), attributes.Atime, attributes.Mtime); err != nil { c.Log(logger.LevelWarn, "failed to chtimes for path %#v, access time: %v, modification time: %v, err: %+v", fsPath, attributes.Atime, attributes.Mtime, err) return c.GetFsError(err) diff --git a/common/connection_test.go b/common/connection_test.go index 201ef525..1930a61c 100644 --- a/common/connection_test.go +++ b/common/connection_test.go @@ -605,7 +605,7 @@ func TestSpaceForCrossRename(t *testing.T) { testDir := filepath.Join(os.TempDir(), "dir") err = os.MkdirAll(testDir, os.ModePerm) assert.NoError(t, err) - err = ioutil.WriteFile(filepath.Join(testDir, "afile"), []byte("content"), os.ModePerm) + err = ioutil.WriteFile(filepath.Join(testDir, "afile.txt"), []byte("content"), os.ModePerm) assert.NoError(t, err) err = os.Chmod(testDir, 0001) assert.NoError(t, err) @@ -616,7 +616,7 @@ func TestSpaceForCrossRename(t *testing.T) { assert.NoError(t, err) } - testFile := filepath.Join(os.TempDir(), "afile") + testFile := filepath.Join(os.TempDir(), "afile.txt") err = ioutil.WriteFile(testFile, []byte("test data"), os.ModePerm) assert.NoError(t, err) quotaResult = vfs.QuotaCheckResult{ diff --git a/common/transfer.go b/common/transfer.go index 252a9d40..2c5f5c2b 100644 --- a/common/transfer.go +++ b/common/transfer.go @@ -108,6 +108,18 @@ func (t *BaseTransfer) GetFsPath() string { return t.fsPath } +// GetRealFsPath returns the real transfer filesystem path. +// If atomic uploads are enabled this differ from fsPath +func (t *BaseTransfer) GetRealFsPath(fsPath string) string { + if fsPath == t.GetFsPath() { + if t.File != nil { + return t.File.Name() + } + return t.fsPath + } + return "" +} + // SetCancelFn sets the cancel function for the transfer func (t *BaseTransfer) SetCancelFn(cancelFn func()) { t.cancelFn = cancelFn diff --git a/common/transfer_test.go b/common/transfer_test.go index bec86fc1..08d7d29c 100644 --- a/common/transfer_test.go +++ b/common/transfer_test.go @@ -83,6 +83,36 @@ func TestTransferThrottling(t *testing.T) { assert.NoError(t, err) } +func TestRealPath(t *testing.T) { + testFile := filepath.Join(os.TempDir(), "afile.txt") + fs := vfs.NewOsFs("123", os.TempDir(), nil) + u := dataprovider.User{ + Username: "user", + HomeDir: os.TempDir(), + } + u.Permissions = make(map[string][]string) + u.Permissions["/"] = []string{dataprovider.PermAny} + file, err := os.Create(testFile) + if !assert.NoError(t, err) { + assert.FailNow(t, "unable to open test file") + } + conn := NewBaseConnection(fs.ConnectionID(), ProtocolSFTP, u, fs) + transfer := NewBaseTransfer(file, conn, nil, testFile, "/transfer_test_file", TransferUpload, 0, 0, 0, true, fs) + rPath := transfer.GetRealFsPath(testFile) + assert.Equal(t, testFile, rPath) + rPath = conn.getRealFsPath(testFile) + assert.Equal(t, testFile, rPath) + err = transfer.Close() + assert.NoError(t, err) + err = file.Close() + assert.NoError(t, err) + transfer.File = nil + rPath = transfer.GetRealFsPath(testFile) + assert.Equal(t, testFile, rPath) + rPath = transfer.GetRealFsPath("") + assert.Empty(t, rPath) +} + func TestTruncate(t *testing.T) { testFile := filepath.Join(os.TempDir(), "transfer_test_file") fs := vfs.NewOsFs("123", os.TempDir(), nil) @@ -99,14 +129,14 @@ func TestTruncate(t *testing.T) { _, err = file.Write([]byte("hello")) assert.NoError(t, err) conn := NewBaseConnection(fs.ConnectionID(), ProtocolSFTP, u, fs) - transfer := NewBaseTransfer(file, conn, nil, testFile, "/transfer_test_file", TransferUpload, 0, 0, 100, true, fs) + transfer := NewBaseTransfer(file, conn, nil, testFile, "/transfer_test_file", TransferUpload, 0, 5, 100, false, fs) err = conn.SetStat(testFile, "/transfer_test_file", &StatAttributes{ Size: 2, Flags: StatAttrSize, }) assert.NoError(t, err) - assert.Equal(t, int64(98), transfer.MaxWriteSize) + assert.Equal(t, int64(103), transfer.MaxWriteSize) err = transfer.Close() assert.NoError(t, err) err = file.Close() diff --git a/dataprovider/user.go b/dataprovider/user.go index f068eab3..402bc531 100644 --- a/dataprovider/user.go +++ b/dataprovider/user.go @@ -227,7 +227,7 @@ func (u *User) AddVirtualDirs(list []os.FileInfo, sftpPath string) []os.FileInfo } for _, v := range u.VirtualFolders { if path.Dir(v.VirtualPath) == sftpPath { - fi := vfs.NewFileInfo(v.VirtualPath, true, 0, time.Now()) + fi := vfs.NewFileInfo(v.VirtualPath, true, 0, time.Now(), false) found := false for index, f := range list { if f.Name() == fi.Name() { diff --git a/sftpd/handler.go b/sftpd/handler.go index f9e2c785..9246cfe1 100644 --- a/sftpd/handler.go +++ b/sftpd/handler.go @@ -195,6 +195,23 @@ func (c *Connection) Filelist(request *sftp.Request) (sftp.ListerAt, error) { } return listerAt([]os.FileInfo{s}), nil + case "Readlink": + if !c.User.HasPerm(dataprovider.PermListItems, path.Dir(request.Filepath)) { + return nil, sftp.ErrSSHFxPermissionDenied + } + + s, err := c.Fs.Readlink(p) + if err != nil { + c.Log(logger.LevelWarn, "error running readlink on path %#v: %+v", p, err) + return nil, c.GetFsError(err) + } + + if !c.User.HasPerm(dataprovider.PermListItems, path.Dir(s)) { + return nil, sftp.ErrSSHFxPermissionDenied + } + + return listerAt([]os.FileInfo{vfs.NewFileInfo(s, false, 0, time.Now(), true)}), nil + default: return nil, sftp.ErrSSHFxOpUnsupported } diff --git a/sftpd/internal_test.go b/sftpd/internal_test.go index ff47606e..79019892 100644 --- a/sftpd/internal_test.go +++ b/sftpd/internal_test.go @@ -229,6 +229,17 @@ func TestReadWriteErrors(t *testing.T) { assert.NoError(t, err) } +func TestUnsupportedListOP(t *testing.T) { + fs := vfs.NewOsFs("", os.TempDir(), nil) + conn := common.NewBaseConnection("", common.ProtocolSFTP, dataprovider.User{}, fs) + sftpConn := Connection{ + BaseConnection: conn, + } + request := sftp.NewRequest("Unsupported", "") + _, err := sftpConn.Filelist(request) + assert.EqualError(t, err, sftp.ErrSSHFxOpUnsupported.Error()) +} + func TestTransferCancelFn(t *testing.T) { testfile := "testfile" file, err := os.Create(testfile) diff --git a/sftpd/sftpd_test.go b/sftpd/sftpd_test.go index 716c9d8e..1ccf7d2a 100644 --- a/sftpd/sftpd_test.go +++ b/sftpd/sftpd_test.go @@ -608,8 +608,9 @@ func TestLink(t *testing.T) { assert.NoError(t, err) err = client.Symlink(testFileName, testFileName+".link") assert.NoError(t, err) - _, err = client.ReadLink(testFileName + ".link") - assert.Error(t, err, "readlink is currently not implemented so must fail") + linkName, err := client.ReadLink(testFileName + ".link") + assert.NoError(t, err) + assert.Equal(t, path.Join("/", testFileName), linkName) err = client.Symlink(testFileName, testFileName+".link") assert.Error(t, err, "creating a symlink to an existing one must fail") err = client.Link(testFileName, testFileName+".hlink") @@ -657,7 +658,12 @@ func TestStat(t *testing.T) { assert.Equal(t, newPerm, newFi.Mode().Perm()) } _, err = client.ReadLink(testFileName) - assert.Error(t, err, "readlink is not supported and must fail") + assert.Error(t, err, "readlink on a file must fail") + err = client.Symlink(testFileName, testFileName+".sym") + assert.NoError(t, err) + linkName, err := client.ReadLink(testFileName + ".sym") + assert.NoError(t, err) + assert.Equal(t, path.Join("/", testFileName), linkName) newPerm = os.FileMode(0666) err = client.Chmod(testFileName, newPerm) assert.NoError(t, err) @@ -674,6 +680,21 @@ func TestStat(t *testing.T) { err = f.Close() assert.NoError(t, err) } + f, err = client.OpenFile(testFileName, os.O_WRONLY) + newPerm = os.FileMode(0444) + if assert.NoError(t, err) { + err = f.Chmod(newPerm) + assert.NoError(t, err) + err = f.Close() + assert.NoError(t, err) + } + newFi, err = client.Lstat(testFileName) + if assert.NoError(t, err) { + assert.Equal(t, newPerm, newFi.Mode().Perm()) + } + newPerm = os.FileMode(0666) + err = client.Chmod(testFileName, newPerm) + assert.NoError(t, err) err = os.Remove(testFilePath) assert.NoError(t, err) } @@ -4650,6 +4671,7 @@ func TestPermList(t *testing.T) { u.Permissions["/"] = []string{dataprovider.PermDownload, dataprovider.PermUpload, dataprovider.PermDelete, dataprovider.PermRename, dataprovider.PermCreateDirs, dataprovider.PermCreateSymlinks, dataprovider.PermOverwrite, dataprovider.PermChmod, dataprovider.PermChown, dataprovider.PermChtimes} + u.Permissions["/sub"] = []string{dataprovider.PermCreateSymlinks, dataprovider.PermListItems} user, _, err := httpd.AddUser(u, http.StatusOK) assert.NoError(t, err) client, err := getSftpClient(user, usePubKey) @@ -4659,6 +4681,21 @@ func TestPermList(t *testing.T) { assert.Error(t, err, "read remote dir without permission should not succeed") _, err = client.Stat("test_file") assert.Error(t, err, "stat remote file without permission should not succeed") + _, err = client.ReadLink("test_link") + assert.Error(t, err, "read remote link without permission on source dir should not succeed") + f, err := client.Create(testFileName) + if assert.NoError(t, err) { + _, err = f.Write([]byte("content")) + assert.NoError(t, err) + err = f.Close() + assert.NoError(t, err) + } + err = client.Mkdir("sub") + assert.NoError(t, err) + err = client.Symlink(testFileName, path.Join("/sub", testFileName)) + assert.NoError(t, err) + _, err = client.ReadLink(path.Join("/sub", testFileName)) + assert.Error(t, err, "read remote link without permission on targe dir should not succeed") } _, err = httpd.RemoveUser(user, http.StatusOK) assert.NoError(t, err) diff --git a/vfs/fileinfo.go b/vfs/fileinfo.go index 3cf5bffa..b0692f14 100644 --- a/vfs/fileinfo.go +++ b/vfs/fileinfo.go @@ -21,16 +21,20 @@ type FileInfo struct { } // NewFileInfo creates file info. -func NewFileInfo(name string, isDirectory bool, sizeInBytes int64, modTime time.Time) FileInfo { +func NewFileInfo(name string, isDirectory bool, sizeInBytes int64, modTime time.Time, fullName bool) FileInfo { mode := os.FileMode(0644) contentType := "" if isDirectory { mode = os.FileMode(0755) | os.ModeDir contentType = "inode/directory" } + if !fullName { + // we have always Unix style paths here + name = path.Base(name) + } return FileInfo{ - name: path.Base(name), // we have always Unix style paths here + name: name, sizeInBytes: sizeInBytes, modTime: modTime, mode: mode, diff --git a/vfs/gcsfs.go b/vfs/gcsfs.go index 990979c4..59103cb6 100644 --- a/vfs/gcsfs.go +++ b/vfs/gcsfs.go @@ -86,10 +86,10 @@ func (fs GCSFs) Stat(name string) (os.FileInfo, error) { if err != nil { return result, err } - return NewFileInfo(name, true, 0, time.Now()), nil + return NewFileInfo(name, true, 0, time.Now(), false), nil } if fs.config.KeyPrefix == name+"/" { - return NewFileInfo(name, true, 0, time.Now()), nil + return NewFileInfo(name, true, 0, time.Now(), false), nil } prefix := fs.getPrefixForStat(name) query := &storage.Query{Prefix: prefix, Delimiter: "/"} @@ -108,7 +108,7 @@ func (fs GCSFs) Stat(name string) (os.FileInfo, error) { } if len(attrs.Prefix) > 0 { if fs.isEqual(attrs.Prefix, name) { - result = NewFileInfo(name, true, 0, time.Now()) + result = NewFileInfo(name, true, 0, time.Now(), false) break } } else { @@ -117,7 +117,7 @@ func (fs GCSFs) Stat(name string) (os.FileInfo, error) { } if fs.isEqual(attrs.Name, name) { isDir := strings.HasSuffix(attrs.Name, "/") - result = NewFileInfo(name, isDir, attrs.Size, attrs.Updated) + result = NewFileInfo(name, isDir, attrs.Size, attrs.Updated, false) if !isDir { result.setContentType(attrs.ContentType) } @@ -280,6 +280,11 @@ func (GCSFs) Symlink(source, target string) error { return errors.New("403 symlinks are not supported") } +// Readlink returns the destination of the named symbolic link +func (GCSFs) Readlink(name string) (string, error) { + return "", errors.New("403 readlink is not supported") +} + // Chown changes the numeric uid and gid of the named file. // Silently ignored. func (GCSFs) Chown(name string, uid int, gid int) error { @@ -333,7 +338,7 @@ func (fs GCSFs) ReadDir(dirname string) ([]os.FileInfo, error) { } if len(attrs.Prefix) > 0 { name, _ := fs.resolve(attrs.Prefix, prefix) - result = append(result, NewFileInfo(name, true, 0, time.Now())) + result = append(result, NewFileInfo(name, true, 0, time.Now(), false)) } else { name, isDir := fs.resolve(attrs.Name, prefix) if len(name) == 0 { @@ -342,7 +347,7 @@ func (fs GCSFs) ReadDir(dirname string) ([]os.FileInfo, error) { if !attrs.Deleted.IsZero() { continue } - fi := NewFileInfo(name, isDir, attrs.Size, attrs.Updated) + fi := NewFileInfo(name, isDir, attrs.Size, attrs.Updated, false) if !isDir { fi.setContentType(attrs.ContentType) } @@ -508,13 +513,13 @@ func (fs GCSFs) Walk(root string, walkFn filepath.WalkFunc) error { if len(name) == 0 { continue } - err = walkFn(attrs.Name, NewFileInfo(name, isDir, attrs.Size, attrs.Updated), nil) + err = walkFn(attrs.Name, NewFileInfo(name, isDir, attrs.Size, attrs.Updated, false), nil) if err != nil { break } } - walkFn(root, NewFileInfo(root, true, 0, time.Now()), err) //nolint:errcheck + walkFn(root, NewFileInfo(root, true, 0, time.Now(), false), err) //nolint:errcheck metrics.GCSListObjectsCompleted(err) return err } diff --git a/vfs/osfs.go b/vfs/osfs.go index a58f70ab..d3558561 100644 --- a/vfs/osfs.go +++ b/vfs/osfs.go @@ -56,7 +56,7 @@ func (fs OsFs) Stat(name string) (os.FileInfo, error) { } for _, v := range fs.virtualFolders { if v.MappedPath == name { - info := NewFileInfo(v.VirtualPath, true, fi.Size(), fi.ModTime()) + info := NewFileInfo(v.VirtualPath, true, fi.Size(), fi.ModTime(), false) return info, nil } } @@ -71,7 +71,7 @@ func (fs OsFs) Lstat(name string) (os.FileInfo, error) { } for _, v := range fs.virtualFolders { if v.MappedPath == name { - info := NewFileInfo(v.VirtualPath, true, fi.Size(), fi.ModTime()) + info := NewFileInfo(v.VirtualPath, true, fi.Size(), fi.ModTime(), false) return info, nil } } @@ -116,6 +116,16 @@ func (OsFs) Symlink(source, target string) error { return os.Symlink(source, target) } +// Readlink returns the destination of the named symbolic link +// as absolute virtual path +func (fs OsFs) Readlink(name string) (string, error) { + p, err := os.Readlink(name) + if err != nil { + return p, err + } + return fs.GetRelativePath(p), err +} + // Chown changes the numeric uid and gid of the named file. func (OsFs) Chown(name string, uid int, gid int) error { return os.Chown(name, uid, gid) diff --git a/vfs/s3fs.go b/vfs/s3fs.go index 44a12304..95bbba43 100644 --- a/vfs/s3fs.go +++ b/vfs/s3fs.go @@ -112,10 +112,10 @@ func (fs S3Fs) Stat(name string) (os.FileInfo, error) { if err != nil { return result, err } - return NewFileInfo(name, true, 0, time.Now()), nil + return NewFileInfo(name, true, 0, time.Now(), false), nil } if "/"+fs.config.KeyPrefix == name+"/" { - return NewFileInfo(name, true, 0, time.Now()), nil + return NewFileInfo(name, true, 0, time.Now(), false), nil } prefix := path.Dir(name) if prefix == "/" || prefix == "." { @@ -135,7 +135,7 @@ func (fs S3Fs) Stat(name string) (os.FileInfo, error) { }, func(page *s3.ListObjectsV2Output, lastPage bool) bool { for _, p := range page.CommonPrefixes { if fs.isEqual(p.Prefix, name) { - result = NewFileInfo(name, true, 0, time.Now()) + result = NewFileInfo(name, true, 0, time.Now(), false) return false } } @@ -144,7 +144,7 @@ func (fs S3Fs) Stat(name string) (os.FileInfo, error) { objectSize := *fileObject.Size objectModTime := *fileObject.LastModified isDir := strings.HasSuffix(*fileObject.Key, "/") - result = NewFileInfo(name, isDir, objectSize, objectModTime) + result = NewFileInfo(name, isDir, objectSize, objectModTime, false) return false } } @@ -312,6 +312,11 @@ func (S3Fs) Symlink(source, target string) error { return errors.New("403 symlinks are not supported") } +// Readlink returns the destination of the named symbolic link +func (S3Fs) Readlink(name string) (string, error) { + return "", errors.New("403 readlink is not supported") +} + // Chown changes the numeric uid and gid of the named file. // Silently ignored. func (S3Fs) Chown(name string, uid int, gid int) error { @@ -358,7 +363,7 @@ func (fs S3Fs) ReadDir(dirname string) ([]os.FileInfo, error) { }, func(page *s3.ListObjectsV2Output, lastPage bool) bool { for _, p := range page.CommonPrefixes { name, isDir := fs.resolve(p.Prefix, prefix) - result = append(result, NewFileInfo(name, isDir, 0, time.Now())) + result = append(result, NewFileInfo(name, isDir, 0, time.Now(), false)) } for _, fileObject := range page.Contents { objectSize := *fileObject.Size @@ -367,7 +372,7 @@ func (fs S3Fs) ReadDir(dirname string) ([]os.FileInfo, error) { if len(name) == 0 { continue } - result = append(result, NewFileInfo(name, isDir, objectSize, objectModTime)) + result = append(result, NewFileInfo(name, isDir, objectSize, objectModTime, false)) } return true }) @@ -505,7 +510,7 @@ func (fs S3Fs) Walk(root string, walkFn filepath.WalkFunc) error { if len(name) == 0 { continue } - err := walkFn(fs.Join("/", *fileObject.Key), NewFileInfo(name, isDir, objectSize, objectModTime), nil) + err := walkFn(fs.Join("/", *fileObject.Key), NewFileInfo(name, isDir, objectSize, objectModTime, false), nil) if err != nil { return false } @@ -513,7 +518,7 @@ func (fs S3Fs) Walk(root string, walkFn filepath.WalkFunc) error { return true }) metrics.S3ListObjectsCompleted(err) - walkFn(root, NewFileInfo(root, true, 0, time.Now()), err) //nolint:errcheck + walkFn(root, NewFileInfo(root, true, 0, time.Now(), false), err) //nolint:errcheck return err } diff --git a/vfs/vfs.go b/vfs/vfs.go index df72def4..fbcf7108 100644 --- a/vfs/vfs.go +++ b/vfs/vfs.go @@ -33,6 +33,7 @@ type Fs interface { Chtimes(name string, atime, mtime time.Time) error Truncate(name string, size int64) error ReadDir(dirname string) ([]os.FileInfo, error) + Readlink(name string) (string, error) IsUploadResumeSupported() bool IsAtomicUploadSupported() bool CheckRootPath(username string, uid int, gid int) bool diff --git a/webdavd/file.go b/webdavd/file.go index 69154687..921015f0 100644 --- a/webdavd/file.go +++ b/webdavd/file.go @@ -98,7 +98,7 @@ func (f *webDavFile) Stat() (os.FileInfo, error) { f.Unlock() if f.GetType() == common.TransferUpload && closed && errUpload == nil { info := webDavFileInfo{ - FileInfo: vfs.NewFileInfo(f.GetFsPath(), false, atomic.LoadInt64(&f.BytesReceived), time.Now()), + FileInfo: vfs.NewFileInfo(f.GetFsPath(), false, atomic.LoadInt64(&f.BytesReceived), time.Now(), false), file: f, } return info, nil diff --git a/webdavd/internal_test.go b/webdavd/internal_test.go index 522c1691..f5fb0385 100644 --- a/webdavd/internal_test.go +++ b/webdavd/internal_test.go @@ -79,11 +79,11 @@ func (fs MockOsFs) Rename(source, target string) error { // Walk returns a duplicate path for testing func (fs MockOsFs) Walk(root string, walkFn filepath.WalkFunc) error { if fs.err == errWalkDir { - walkFn("fsdpath", vfs.NewFileInfo("dpath", true, 0, time.Now()), nil) //nolint:errcheck - walkFn("fsdpath", vfs.NewFileInfo("dpath", true, 0, time.Now()), nil) //nolint:errcheck + walkFn("fsdpath", vfs.NewFileInfo("dpath", true, 0, time.Now(), false), nil) //nolint:errcheck + walkFn("fsdpath", vfs.NewFileInfo("dpath", true, 0, time.Now(), false), nil) //nolint:errcheck return nil } - walkFn("fsfpath", vfs.NewFileInfo("fpath", false, 0, time.Now()), nil) //nolint:errcheck + walkFn("fsfpath", vfs.NewFileInfo("fpath", false, 0, time.Now(), false), nil) //nolint:errcheck return fs.err } @@ -317,12 +317,12 @@ func TestFileAccessErrors(t *testing.T) { if assert.Error(t, err) { assert.EqualError(t, err, os.ErrNotExist.Error()) } - info := vfs.NewFileInfo(missingPath, true, 0, time.Now()) + info := vfs.NewFileInfo(missingPath, true, 0, time.Now(), false) _, err = connection.getFile(fsMissingPath, missingPath, info) if assert.Error(t, err) { assert.EqualError(t, err, os.ErrNotExist.Error()) } - info = vfs.NewFileInfo(missingPath, false, 123, time.Now()) + info = vfs.NewFileInfo(missingPath, false, 123, time.Now(), false) _, err = connection.getFile(fsMissingPath, missingPath, info) if assert.Error(t, err) { assert.EqualError(t, err, os.ErrNotExist.Error()) @@ -429,7 +429,7 @@ func TestContentType(t *testing.T) { ctx := context.Background() baseTransfer := common.NewBaseTransfer(nil, connection.BaseConnection, nil, testFilePath, testFile, common.TransferDownload, 0, 0, 0, false, fs) - info := vfs.NewFileInfo(testFilePath, true, 0, time.Now()) + info := vfs.NewFileInfo(testFilePath, true, 0, time.Now(), false) davFile := newWebDavFile(baseTransfer, nil, nil, info) fi, err := davFile.Stat() if assert.NoError(t, err) {