vfs: store root dir

so we don't need to pass it over and over
This commit is contained in:
Nicola Murino 2020-01-19 13:58:55 +01:00
parent a4834f4a83
commit d75f56b914
12 changed files with 65 additions and 57 deletions

View file

@ -425,13 +425,13 @@ SFTPGo uses multipart uploads and parallel downloads for storing and retrieving
Some SFTP commands doesn't work over S3: Some SFTP commands doesn't work over S3:
- `symlink` and `chtimes` will fail - `symlink` and `chtimes` will fail
- `chown`, `chmod` are silently ignored - `chown` and `chmod` are silently ignored
- upload resume is not supported - upload resume is not supported
- upload mode `atomic` is ignored since S3 uploads are already atomic - upload mode `atomic` is ignored since S3 uploads are already atomic
Other notes: Other notes:
- `rename` is a two steps operation: server-side copy and then deletion. So it is not atomic as for local filesystem - `rename` is a two steps operation: server-side copy and then deletion. So it is not atomic as for local filesystem.
- We don't support renaming non empty directories since we should rename all the contents too and this could take long time: think about directories with thousands of files, for each file we should do an AWS API call. - We don't support renaming non empty directories since we should rename all the contents too and this could take long time: think about directories with thousands of files, for each file we should do an AWS API call.
- For server side encryption you have to configure the mapped bucket to automatically encrypt objects. - For server side encryption you have to configure the mapped bucket to automatically encrypt objects.
- A local home directory is still required to store temporary files. - A local home directory is still required to store temporary files.

View file

@ -114,7 +114,7 @@ func (u *User) GetFilesystem(connectionID string) (vfs.Fs, error) {
if u.FsConfig.Provider == 1 { if u.FsConfig.Provider == 1 {
return vfs.NewS3Fs(connectionID, u.GetHomeDir(), u.FsConfig.S3Config) return vfs.NewS3Fs(connectionID, u.GetHomeDir(), u.FsConfig.S3Config)
} }
return vfs.NewOsFs(connectionID), nil return vfs.NewOsFs(connectionID, u.GetHomeDir()), nil
} }
// GetPermissionsForPath returns the permissions for the given path. // GetPermissionsForPath returns the permissions for the given path.

View file

@ -40,7 +40,7 @@ func doQuotaScan(user dataprovider.User) error {
logger.Warn(logSender, "", "unable scan quota for user %#v error creating filesystem: %v", user.Username, err) logger.Warn(logSender, "", "unable scan quota for user %#v error creating filesystem: %v", user.Username, err)
return err return err
} }
numFiles, size, err := fs.ScanDirContents(user.HomeDir) numFiles, size, err := fs.ScanRootDirContents()
if err != nil { if err != nil {
logger.Warn(logSender, "", "error scanning user home dir %#v: %v", user.HomeDir, err) logger.Warn(logSender, "", "error scanning user home dir %#v: %v", user.HomeDir, err)
} else { } else {

View file

@ -51,7 +51,7 @@ func (c Connection) Fileread(request *sftp.Request) (io.ReaderAt, error) {
return nil, sftp.ErrSSHFxPermissionDenied return nil, sftp.ErrSSHFxPermissionDenied
} }
p, err := c.fs.ResolvePath(request.Filepath, c.User.GetHomeDir()) p, err := c.fs.ResolvePath(request.Filepath)
if err != nil { if err != nil {
return nil, vfs.GetSFTPError(c.fs, err) return nil, vfs.GetSFTPError(c.fs, err)
} }
@ -97,7 +97,7 @@ func (c Connection) Fileread(request *sftp.Request) (io.ReaderAt, error) {
// Filewrite handles the write actions for a file on the system. // Filewrite handles the write actions for a file on the system.
func (c Connection) Filewrite(request *sftp.Request) (io.WriterAt, error) { func (c Connection) Filewrite(request *sftp.Request) (io.WriterAt, error) {
updateConnectionActivity(c.ID) updateConnectionActivity(c.ID)
p, err := c.fs.ResolvePath(request.Filepath, c.User.GetHomeDir()) p, err := c.fs.ResolvePath(request.Filepath)
if err != nil { if err != nil {
return nil, vfs.GetSFTPError(c.fs, err) return nil, vfs.GetSFTPError(c.fs, err)
} }
@ -138,7 +138,7 @@ func (c Connection) Filewrite(request *sftp.Request) (io.WriterAt, error) {
func (c Connection) Filecmd(request *sftp.Request) error { func (c Connection) Filecmd(request *sftp.Request) error {
updateConnectionActivity(c.ID) updateConnectionActivity(c.ID)
p, err := c.fs.ResolvePath(request.Filepath, c.User.GetHomeDir()) p, err := c.fs.ResolvePath(request.Filepath)
if err != nil { if err != nil {
return vfs.GetSFTPError(c.fs, err) return vfs.GetSFTPError(c.fs, err)
} }
@ -194,7 +194,7 @@ func (c Connection) Filecmd(request *sftp.Request) error {
// a directory as well as perform file/folder stat calls. // a directory as well as perform file/folder stat calls.
func (c Connection) Filelist(request *sftp.Request) (sftp.ListerAt, error) { func (c Connection) Filelist(request *sftp.Request) (sftp.ListerAt, error) {
updateConnectionActivity(c.ID) updateConnectionActivity(c.ID)
p, err := c.fs.ResolvePath(request.Filepath, c.User.GetHomeDir()) p, err := c.fs.ResolvePath(request.Filepath)
if err != nil { if err != nil {
return nil, vfs.GetSFTPError(c.fs, err) return nil, vfs.GetSFTPError(c.fs, err)
} }
@ -238,7 +238,7 @@ func (c Connection) getSFTPCmdTargetPath(requestTarget string) (string, error) {
// location for the server. If it is not, return an error // location for the server. If it is not, return an error
if len(requestTarget) > 0 { if len(requestTarget) > 0 {
var err error var err error
target, err = c.fs.ResolvePath(requestTarget, c.User.GetHomeDir()) target, err = c.fs.ResolvePath(requestTarget)
if err != nil { if err != nil {
return target, vfs.GetSFTPError(c.fs, err) return target, vfs.GetSFTPError(c.fs, err)
} }

View file

@ -65,7 +65,7 @@ func (c *MockChannel) Stderr() io.ReadWriter {
// MockOsFs mockable OsFs // MockOsFs mockable OsFs
type MockOsFs struct { type MockOsFs struct {
vfs.OsFs vfs.Fs
err error err error
statErr error statErr error
isAtomicUploadSupported bool isAtomicUploadSupported bool
@ -110,8 +110,9 @@ func (fs MockOsFs) Rename(source, target string) error {
return os.Rename(source, target) return os.Rename(source, target)
} }
func newMockOsFs(err, statErr error, atomicUpload bool) vfs.Fs { func newMockOsFs(err, statErr error, atomicUpload bool, connectionID, rootDir string) vfs.Fs {
return &MockOsFs{ return &MockOsFs{
Fs: vfs.NewOsFs(connectionID, rootDir),
err: err, err: err,
statErr: statErr, statErr: statErr,
isAtomicUploadSupported: atomicUpload, isAtomicUploadSupported: atomicUpload,
@ -366,7 +367,7 @@ func TestTransferCancelFn(t *testing.T) {
func TestMockFsErrors(t *testing.T) { func TestMockFsErrors(t *testing.T) {
errFake := errors.New("fake error") errFake := errors.New("fake error")
fs := newMockOsFs(errFake, errFake, false) fs := newMockOsFs(errFake, errFake, false, "123", os.TempDir())
u := dataprovider.User{} u := dataprovider.User{}
u.Username = "test" u.Username = "test"
u.Permissions = make(map[string][]string) u.Permissions = make(map[string][]string)
@ -402,7 +403,7 @@ func TestUploadFiles(t *testing.T) {
oldUploadMode := uploadMode oldUploadMode := uploadMode
uploadMode = uploadModeAtomic uploadMode = uploadModeAtomic
c := Connection{ c := Connection{
fs: vfs.NewOsFs("123"), fs: vfs.NewOsFs("123", os.TempDir()),
} }
var flags sftp.FileOpenFlags var flags sftp.FileOpenFlags
flags.Write = true flags.Write = true
@ -434,13 +435,13 @@ func TestWithInvalidHome(t *testing.T) {
if err == nil { if err == nil {
t.Errorf("login a user with an invalid home_dir must fail") t.Errorf("login a user with an invalid home_dir must fail")
} }
u.HomeDir = os.TempDir()
fs, _ := u.GetFilesystem("123") fs, _ := u.GetFilesystem("123")
c := Connection{ c := Connection{
User: u, User: u,
fs: fs, fs: fs,
} }
u.HomeDir = os.TempDir() _, err = c.fs.ResolvePath("../upper_path")
_, err = c.fs.ResolvePath("../upper_path", u.GetHomeDir())
if err == nil { if err == nil {
t.Errorf("tested path is not a home subdir") t.Errorf("tested path is not a home subdir")
} }
@ -469,7 +470,7 @@ func TestSFTPCmdTargetPath(t *testing.T) {
func TestGetSFTPErrorFromOSError(t *testing.T) { func TestGetSFTPErrorFromOSError(t *testing.T) {
err := os.ErrNotExist err := os.ErrNotExist
fs := vfs.NewOsFs("") fs := vfs.NewOsFs("", os.TempDir())
err = vfs.GetSFTPError(fs, err) err = vfs.GetSFTPError(fs, err)
if err != sftp.ErrSSHFxNoSuchFile { if err != sftp.ErrSSHFxNoSuchFile {
t.Errorf("unexpected error: %v", err) t.Errorf("unexpected error: %v", err)
@ -644,6 +645,8 @@ func TestSSHCommandErrors(t *testing.T) {
cmd.connection.User.HomeDir = os.TempDir() cmd.connection.User.HomeDir = os.TempDir()
cmd.connection.User.QuotaFiles = 1 cmd.connection.User.QuotaFiles = 1
cmd.connection.User.UsedQuotaFiles = 2 cmd.connection.User.UsedQuotaFiles = 2
fs, _ = cmd.connection.User.GetFilesystem("123")
cmd.connection.fs = fs
err = cmd.handle() err = cmd.handle()
if err != errQuotaExceeded { if err != errQuotaExceeded {
t.Errorf("unexpected error: %v", err) t.Errorf("unexpected error: %v", err)
@ -1175,7 +1178,7 @@ func TestSCPCommandHandleErrors(t *testing.T) {
func TestSCPErrorsMockFs(t *testing.T) { func TestSCPErrorsMockFs(t *testing.T) {
errFake := errors.New("fake error") errFake := errors.New("fake error")
fs := newMockOsFs(errFake, errFake, false) fs := newMockOsFs(errFake, errFake, false, "123", os.TempDir())
u := dataprovider.User{} u := dataprovider.User{}
u.Username = "test" u.Username = "test"
u.Permissions = make(map[string][]string) u.Permissions = make(map[string][]string)
@ -1214,7 +1217,7 @@ func TestSCPErrorsMockFs(t *testing.T) {
if err != errFake { if err != errFake {
t.Errorf("unexpected error: %v", err) t.Errorf("unexpected error: %v", err)
} }
scpCommand.sshCommand.connection.fs = newMockOsFs(errFake, nil, true) scpCommand.sshCommand.connection.fs = newMockOsFs(errFake, nil, true, "123", os.TempDir())
err = scpCommand.handleUpload(filepath.Base(testfile), 0) err = scpCommand.handleUpload(filepath.Base(testfile), 0)
if err != errFake { if err != errFake {
t.Errorf("unexpected error: %v", err) t.Errorf("unexpected error: %v", err)
@ -1239,7 +1242,7 @@ func TestSCPRecursiveDownloadErrors(t *testing.T) {
connection := Connection{ connection := Connection{
channel: &mockSSHChannel, channel: &mockSSHChannel,
netConn: client, netConn: client,
fs: vfs.NewOsFs("123"), fs: vfs.NewOsFs("123", os.TempDir()),
} }
scpCommand := scpCommand{ scpCommand := scpCommand{
sshCommand: sshCommand{ sshCommand: sshCommand{

View file

@ -116,7 +116,7 @@ func (c *scpCommand) handleRecursiveUpload() error {
func (c *scpCommand) handleCreateDir(dirPath string) error { func (c *scpCommand) handleCreateDir(dirPath string) error {
updateConnectionActivity(c.connection.ID) updateConnectionActivity(c.connection.ID)
p, err := c.connection.fs.ResolvePath(dirPath, c.connection.User.GetHomeDir()) p, err := c.connection.fs.ResolvePath(dirPath)
if err != nil { if err != nil {
c.connection.Log(logger.LevelWarn, logSenderSCP, "error creating dir: %#v, invalid file path, err: %v", dirPath, err) c.connection.Log(logger.LevelWarn, logSenderSCP, "error creating dir: %#v, invalid file path, err: %v", dirPath, err)
c.sendErrorMessage(err.Error()) c.sendErrorMessage(err.Error())
@ -228,7 +228,7 @@ func (c *scpCommand) handleUpload(uploadFilePath string, sizeToRead int64) error
updateConnectionActivity(c.connection.ID) updateConnectionActivity(c.connection.ID)
p, err := c.connection.fs.ResolvePath(uploadFilePath, c.connection.User.GetHomeDir()) p, err := c.connection.fs.ResolvePath(uploadFilePath)
if err != nil { if err != nil {
c.connection.Log(logger.LevelWarn, logSenderSCP, "error uploading file: %#v, err: %v", uploadFilePath, err) c.connection.Log(logger.LevelWarn, logSenderSCP, "error uploading file: %#v, err: %v", uploadFilePath, err)
c.sendErrorMessage(err.Error()) c.sendErrorMessage(err.Error())
@ -422,7 +422,7 @@ func (c *scpCommand) handleDownload(filePath string) error {
updateConnectionActivity(c.connection.ID) updateConnectionActivity(c.connection.ID)
p, err := c.connection.fs.ResolvePath(filePath, c.connection.User.GetHomeDir()) p, err := c.connection.fs.ResolvePath(filePath)
if err != nil { if err != nil {
err := fmt.Errorf("Invalid file path") err := fmt.Errorf("Invalid file path")
c.connection.Log(logger.LevelWarn, logSenderSCP, "error downloading file: %#v, invalid file path", filePath) c.connection.Log(logger.LevelWarn, logSenderSCP, "error downloading file: %#v, invalid file path", filePath)
@ -674,7 +674,7 @@ func (c *scpCommand) getFileUploadDestPath(scpDestPath, fileName string) string
// but if scpDestPath is an existing directory then we put the uploaded file // but if scpDestPath is an existing directory then we put the uploaded file
// inside that directory this is as scp command works, for example: // inside that directory this is as scp command works, for example:
// scp fileName.txt user@127.0.0.1:/existing_dir // scp fileName.txt user@127.0.0.1:/existing_dir
if p, err := c.connection.fs.ResolvePath(scpDestPath, c.connection.User.GetHomeDir()); err == nil { if p, err := c.connection.fs.ResolvePath(scpDestPath); err == nil {
if stat, err := c.connection.fs.Stat(p); err == nil { if stat, err := c.connection.fs.Stat(p); err == nil {
if stat.IsDir() { if stat.IsDir() {
return path.Join(scpDestPath, fileName) return path.Join(scpDestPath, fileName)

View file

@ -286,7 +286,7 @@ func (c Configuration) AcceptInboundConnection(conn net.Conn, config *ssh.Server
fs: fs, fs: fs,
} }
connection.fs.CheckRootPath(user.GetHomeDir(), user.Username, user.GetUID(), user.GetGID()) connection.fs.CheckRootPath(user.Username, user.GetUID(), user.GetGID())
connection.Log(logger.LevelInfo, logSender, "User id: %d, logged in with: %#v, username: %#v, home_dir: %#v remote addr: %#v", connection.Log(logger.LevelInfo, logSender, "User id: %d, logged in with: %#v, username: %#v, home_dir: %#v remote addr: %#v",
user.ID, loginType, user.Username, user.HomeDir, remoteAddr.String()) user.ID, loginType, user.Username, user.HomeDir, remoteAddr.String())

View file

@ -1515,6 +1515,7 @@ func TestQuotaDisabledError(t *testing.T) {
func TestMaxSessions(t *testing.T) { func TestMaxSessions(t *testing.T) {
usePubKey := false usePubKey := false
u := getTestUser(usePubKey) u := getTestUser(usePubKey)
u.Username += "1"
u.MaxSessions = 1 u.MaxSessions = 1
user, _, err := httpd.AddUser(u, http.StatusOK) user, _, err := httpd.AddUser(u, http.StatusOK)
if err != nil { if err != nil {
@ -2904,7 +2905,7 @@ func TestRootDirCommands(t *testing.T) {
func TestRelativePaths(t *testing.T) { func TestRelativePaths(t *testing.T) {
user := getTestUser(true) user := getTestUser(true)
path := filepath.Join(user.HomeDir, "/") path := filepath.Join(user.HomeDir, "/")
fs := vfs.NewOsFs("") fs := vfs.NewOsFs("", user.GetHomeDir())
rel := fs.GetRelativePath(path, user.GetHomeDir()) rel := fs.GetRelativePath(path, user.GetHomeDir())
if rel != "/" { if rel != "/" {
t.Errorf("Unexpected relative path: %v", rel) t.Errorf("Unexpected relative path: %v", rel)

View file

@ -130,7 +130,7 @@ func (c *sshCommand) handleHashCommands() error {
response = fmt.Sprintf("%x -\n", h.Sum(nil)) response = fmt.Sprintf("%x -\n", h.Sum(nil))
} else { } else {
sshPath := c.getDestPath() sshPath := c.getDestPath()
fsPath, err := c.connection.fs.ResolvePath(sshPath, c.connection.User.GetHomeDir()) fsPath, err := c.connection.fs.ResolvePath(sshPath)
if err != nil { if err != nil {
return c.sendErrorResponse(err) return c.sendErrorResponse(err)
} }
@ -296,7 +296,7 @@ func (c *sshCommand) getSystemCommand() (systemCommand, error) {
if len(c.args) > 0 { if len(c.args) > 0 {
var err error var err error
sshPath := c.getDestPath() sshPath := c.getDestPath()
path, err = c.connection.fs.ResolvePath(sshPath, c.connection.User.GetHomeDir()) path, err = c.connection.fs.ResolvePath(sshPath)
if err != nil { if err != nil {
return command, err return command, err
} }
@ -339,7 +339,7 @@ func (c *sshCommand) rescanHomeDir() error {
var numFiles int var numFiles int
var size int64 var size int64
if AddQuotaScan(c.connection.User.Username) { if AddQuotaScan(c.connection.User.Username) {
numFiles, size, err = c.connection.fs.ScanDirContents(c.connection.User.HomeDir) numFiles, size, err = c.connection.fs.ScanRootDirContents()
if err != nil { if err != nil {
c.connection.Log(logger.LevelWarn, logSenderSSH, "error scanning user home dir %#v: %v", c.connection.User.HomeDir, err) c.connection.Log(logger.LevelWarn, logSenderSSH, "error scanning user home dir %#v: %v", c.connection.User.HomeDir, err)
} else { } else {
@ -397,7 +397,7 @@ func (c *sshCommand) sendExitStatus(err error) {
if err == nil && c.command != "scp" { if err == nil && c.command != "scp" {
realPath := c.getDestPath() realPath := c.getDestPath()
if len(realPath) > 0 { if len(realPath) > 0 {
p, err := c.connection.fs.ResolvePath(realPath, c.connection.User.GetHomeDir()) p, err := c.connection.fs.ResolvePath(realPath)
if err == nil { if err == nil {
realPath = p realPath = p
} }

View file

@ -22,13 +22,16 @@ const (
type OsFs struct { type OsFs struct {
name string name string
connectionID string connectionID string
rootDir string
} }
// NewOsFs returns an OsFs object that allows to interact with local Os filesystem // NewOsFs returns an OsFs object that allows to interact with local Os filesystem
func NewOsFs(connectionID string) Fs { func NewOsFs(connectionID, rootDir string) Fs {
return &OsFs{ return &OsFs{
name: osFsName, name: osFsName,
connectionID: connectionID} connectionID: connectionID,
rootDir: rootDir,
}
} }
// Name returns the name for the Fs implementation // Name returns the name for the Fs implementation
@ -133,28 +136,28 @@ func (OsFs) IsPermission(err error) bool {
return os.IsPermission(err) return os.IsPermission(err)
} }
// CheckRootPath creates the specified root directory if it does not exists // CheckRootPath creates the root directory if it does not exists
func (fs OsFs) CheckRootPath(rootPath, username string, uid int, gid int) bool { func (fs OsFs) CheckRootPath(username string, uid int, gid int) bool {
var err error var err error
if _, err = fs.Stat(rootPath); fs.IsNotExist(err) { if _, err = fs.Stat(fs.rootDir); fs.IsNotExist(err) {
err = os.MkdirAll(rootPath, 0777) err = os.MkdirAll(fs.rootDir, 0777)
fsLog(fs, logger.LevelDebug, "root directory %#v for user %#v does not exist, try to create, mkdir error: %v", fsLog(fs, logger.LevelDebug, "root directory %#v for user %#v does not exist, try to create, mkdir error: %v",
rootPath, username, err) fs.rootDir, username, err)
if err == nil { if err == nil {
SetPathPermissions(fs, rootPath, uid, gid) SetPathPermissions(fs, fs.rootDir, uid, gid)
} }
} }
return (err == nil) return (err == nil)
} }
// ScanDirContents returns the number of files contained in a directory and // ScanRootDirContents returns the number of files contained in a directory and
// their size // their size
func (fs OsFs) ScanDirContents(dirPath string) (int, int64, error) { func (fs OsFs) ScanRootDirContents() (int, int64, error) {
numFiles := 0 numFiles := 0
size := int64(0) size := int64(0)
isDir, err := IsDirectory(fs, dirPath) isDir, err := IsDirectory(fs, fs.rootDir)
if err == nil && isDir { if err == nil && isDir {
err = filepath.Walk(dirPath, func(path string, info os.FileInfo, err error) error { err = filepath.Walk(fs.rootDir, func(path string, info os.FileInfo, err error) error {
if err != nil { if err != nil {
return err return err
} }
@ -194,27 +197,27 @@ func (OsFs) Join(elem ...string) string {
} }
// ResolvePath returns the matching filesystem path for the specified sftp path // ResolvePath returns the matching filesystem path for the specified sftp path
func (fs OsFs) ResolvePath(sftpPath, rootPath string) (string, error) { func (fs OsFs) ResolvePath(sftpPath string) (string, error) {
if !filepath.IsAbs(rootPath) { if !filepath.IsAbs(fs.rootDir) {
return "", fmt.Errorf("Invalid root path: %v", rootPath) return "", fmt.Errorf("Invalid root path: %v", fs.rootDir)
} }
r := filepath.Clean(filepath.Join(rootPath, sftpPath)) r := filepath.Clean(filepath.Join(fs.rootDir, sftpPath))
p, err := filepath.EvalSymlinks(r) p, err := filepath.EvalSymlinks(r)
if err != nil && !os.IsNotExist(err) { if err != nil && !os.IsNotExist(err) {
return "", err return "", err
} else if os.IsNotExist(err) { } else if os.IsNotExist(err) {
// The requested path doesn't exist, so at this point we need to iterate up the // The requested path doesn't exist, so at this point we need to iterate up the
// path chain until we hit a directory that _does_ exist and can be validated. // path chain until we hit a directory that _does_ exist and can be validated.
_, err = fs.findFirstExistingDir(r, rootPath) _, err = fs.findFirstExistingDir(r, fs.rootDir)
if err != nil { if err != nil {
fsLog(fs, logger.LevelWarn, "error resolving not existent path: %#v", err) fsLog(fs, logger.LevelWarn, "error resolving not existent path: %#v", err)
} }
return r, err return r, err
} }
err = fs.isSubDir(p, rootPath) err = fs.isSubDir(p, fs.rootDir)
if err != nil { if err != nil {
fsLog(fs, logger.LevelWarn, "Invalid path resolution, dir: %#v outside user home: %#v err: %v", p, rootPath, err) fsLog(fs, logger.LevelWarn, "Invalid path resolution, dir: %#v outside user home: %#v err: %v", p, fs.rootDir, err)
} }
return r, err return r, err
} }

View file

@ -372,10 +372,10 @@ func (S3Fs) IsPermission(err error) bool {
} }
// CheckRootPath creates the specified root directory if it does not exists // CheckRootPath creates the specified root directory if it does not exists
func (fs S3Fs) CheckRootPath(rootPath, username string, uid int, gid int) bool { func (fs S3Fs) CheckRootPath(username string, uid int, gid int) bool {
// we need a local directory for temporary files // we need a local directory for temporary files
osFs := NewOsFs(fs.ConnectionID()) osFs := NewOsFs(fs.ConnectionID(), fs.localTempDir)
osFs.CheckRootPath(fs.localTempDir, username, uid, gid) osFs.CheckRootPath(username, uid, gid)
err := fs.checkIfBucketExists() err := fs.checkIfBucketExists()
if err == nil { if err == nil {
return true return true
@ -394,9 +394,9 @@ func (fs S3Fs) CheckRootPath(rootPath, username string, uid int, gid int) bool {
return err == nil return err == nil
} }
// ScanDirContents returns the number of files contained in the bucket, // ScanRootDirContents returns the number of files contained in the bucket,
// and their size // and their size
func (fs S3Fs) ScanDirContents(dirPath string) (int, int64, error) { func (fs S3Fs) ScanRootDirContents() (int, int64, error) {
numFiles := 0 numFiles := 0
size := int64(0) size := int64(0)
ctx, cancelFn := context.WithDeadline(context.Background(), time.Now().Add(fs.ctxLongTimeout)) ctx, cancelFn := context.WithDeadline(context.Background(), time.Now().Add(fs.ctxLongTimeout))
@ -440,7 +440,7 @@ func (S3Fs) Join(elem ...string) string {
} }
// ResolvePath returns the matching filesystem path for the specified sftp path // ResolvePath returns the matching filesystem path for the specified sftp path
func (fs S3Fs) ResolvePath(sftpPath, rootPath string) (string, error) { func (fs S3Fs) ResolvePath(sftpPath string) (string, error) {
return sftpPath, nil return sftpPath, nil
} }

View file

@ -1,3 +1,4 @@
// Package vfs provides local and remote filesystems support
package vfs package vfs
import ( import (
@ -29,11 +30,11 @@ type Fs interface {
ReadDir(dirname string) ([]os.FileInfo, error) ReadDir(dirname string) ([]os.FileInfo, error)
IsUploadResumeSupported() bool IsUploadResumeSupported() bool
IsAtomicUploadSupported() bool IsAtomicUploadSupported() bool
CheckRootPath(rootPath, username string, uid int, gid int) bool CheckRootPath(username string, uid int, gid int) bool
ResolvePath(sftpPath, rootPath string) (string, error) ResolvePath(sftpPath string) (string, error)
IsNotExist(err error) bool IsNotExist(err error) bool
IsPermission(err error) bool IsPermission(err error) bool
ScanDirContents(dirPath string) (int, int64, error) ScanRootDirContents() (int, int64, error)
GetAtomicUploadPath(name string) string GetAtomicUploadPath(name string) string
GetRelativePath(name, rootPath string) string GetRelativePath(name, rootPath string) string
Join(elem ...string) string Join(elem ...string) string