improve chtimes handling on open files

This commit is contained in:
Nicola Murino
2021-11-26 19:00:44 +01:00
parent f828c58dca
commit f2480ce5c9
8 changed files with 93 additions and 3 deletions

View File

@@ -291,6 +291,7 @@ type ActiveTransfer interface {
SignalClose() SignalClose()
Truncate(fsPath string, size int64) (int64, error) Truncate(fsPath string, size int64) (int64, error)
GetRealFsPath(fsPath string) string GetRealFsPath(fsPath string) string
SetTimes(fsPath string, atime time.Time, mtime time.Time) bool
} }
// ActiveConnection defines the interface for the current active connections // ActiveConnection defines the interface for the current active connections

View File

@@ -201,6 +201,17 @@ func (c *BaseConnection) getRealFsPath(fsPath string) string {
return fsPath return fsPath
} }
func (c *BaseConnection) setTimes(fsPath string, atime time.Time, mtime time.Time) {
c.RLock()
defer c.RUnlock()
for _, t := range c.activeTransfers {
if t.SetTimes(fsPath, atime, mtime) {
return
}
}
}
func (c *BaseConnection) truncateOpenHandle(fsPath string, size int64) (int64, error) { func (c *BaseConnection) truncateOpenHandle(fsPath string, size int64) (int64, error) {
c.RLock() c.RLock()
defer c.RUnlock() defer c.RUnlock()
@@ -558,6 +569,7 @@ func (c *BaseConnection) handleChtimes(fs vfs.Fs, fsPath, pathForPerms string, a
fsPath, attributes.Atime, attributes.Mtime, err) fsPath, attributes.Atime, attributes.Mtime, err)
return c.GetFsError(fs, err) return c.GetFsError(fs, err)
} }
c.setTimes(fsPath, attributes.Atime, attributes.Mtime)
accessTimeString := attributes.Atime.Format(chtimesFormat) accessTimeString := attributes.Atime.Format(chtimesFormat)
modificationTimeString := attributes.Mtime.Format(chtimesFormat) modificationTimeString := attributes.Mtime.Format(chtimesFormat)
logger.CommandLog(chtimesLogSender, fsPath, "", c.User.Username, "", c.ID, c.protocol, -1, -1, logger.CommandLog(chtimesLogSender, fsPath, "", c.User.Username, "", c.ID, c.protocol, -1, -1,

View File

@@ -321,6 +321,58 @@ func TestSetStat(t *testing.T) {
assert.NoError(t, err) assert.NoError(t, err)
} }
func TestChtimesOpenHandle(t *testing.T) {
localUser, _, err := httpdtest.AddUser(getTestUser(), http.StatusCreated)
assert.NoError(t, err)
sftpUser, _, err := httpdtest.AddUser(getTestSFTPUser(), http.StatusCreated)
assert.NoError(t, err)
u := getCryptFsUser()
u.Username += "_crypt"
cryptFsUser, _, err := httpdtest.AddUser(u, http.StatusCreated)
assert.NoError(t, err)
for _, user := range []dataprovider.User{localUser, sftpUser, cryptFsUser} {
conn, client, err := getSftpClient(user)
if assert.NoError(t, err) {
defer conn.Close()
defer client.Close()
f, err := client.Create(testFileName)
assert.NoError(t, err, "user %v", user.Username)
f1, err := client.Create(testFileName + "1")
assert.NoError(t, err, "user %v", user.Username)
acmodTime := time.Now().Add(36 * time.Hour)
err = client.Chtimes(testFileName, acmodTime, acmodTime)
assert.NoError(t, err, "user %v", user.Username)
_, err = f.Write(testFileContent)
assert.NoError(t, err, "user %v", user.Username)
err = f.Close()
assert.NoError(t, err, "user %v", user.Username)
err = f1.Close()
assert.NoError(t, err, "user %v", user.Username)
info, err := client.Lstat(testFileName)
assert.NoError(t, err, "user %v", user.Username)
diff := math.Abs(info.ModTime().Sub(acmodTime).Seconds())
assert.LessOrEqual(t, diff, float64(1), "user %v", user.Username)
info1, err := client.Lstat(testFileName + "1")
assert.NoError(t, err, "user %v", user.Username)
diff = math.Abs(info1.ModTime().Sub(acmodTime).Seconds())
assert.Greater(t, diff, float64(86400), "user %v", user.Username)
}
}
_, err = httpdtest.RemoveUser(sftpUser, http.StatusOK)
assert.NoError(t, err)
_, err = httpdtest.RemoveUser(localUser, http.StatusOK)
assert.NoError(t, err)
err = os.RemoveAll(localUser.GetHomeDir())
assert.NoError(t, err)
_, err = httpdtest.RemoveUser(cryptFsUser, http.StatusOK)
assert.NoError(t, err)
err = os.RemoveAll(cryptFsUser.GetHomeDir())
assert.NoError(t, err)
}
func TestPermissionErrors(t *testing.T) { func TestPermissionErrors(t *testing.T) {
user, _, err := httpdtest.AddUser(getTestUser(), http.StatusCreated) user, _, err := httpdtest.AddUser(getTestUser(), http.StatusCreated)
assert.NoError(t, err) assert.NoError(t, err)

View File

@@ -38,6 +38,8 @@ type BaseTransfer struct { //nolint:maligned
isNewFile bool isNewFile bool
transferType int transferType int
AbortTransfer int32 AbortTransfer int32
aTime time.Time
mTime time.Time
sync.Mutex sync.Mutex
ErrTransfer error ErrTransfer error
} }
@@ -115,6 +117,15 @@ func (t *BaseTransfer) GetFsPath() string {
return t.fsPath return t.fsPath
} }
func (t *BaseTransfer) SetTimes(fsPath string, atime time.Time, mtime time.Time) bool {
if fsPath == t.GetFsPath() {
t.aTime = atime
t.mTime = mtime
return true
}
return false
}
// GetRealFsPath returns the real transfer filesystem path. // GetRealFsPath returns the real transfer filesystem path.
// If atomic uploads are enabled this differ from fsPath // If atomic uploads are enabled this differ from fsPath
func (t *BaseTransfer) GetRealFsPath(fsPath string) string { func (t *BaseTransfer) GetRealFsPath(fsPath string) string {
@@ -252,6 +263,7 @@ func (t *BaseTransfer) Close() error {
} }
t.Connection.Log(logger.LevelDebug, "uploaded file size %v", fileSize) t.Connection.Log(logger.LevelDebug, "uploaded file size %v", fileSize)
t.updateQuota(numFiles, fileSize) t.updateQuota(numFiles, fileSize)
t.updateTimes()
logger.TransferLog(uploadLogSender, t.fsPath, elapsed, atomic.LoadInt64(&t.BytesReceived), t.Connection.User.Username, logger.TransferLog(uploadLogSender, t.fsPath, elapsed, atomic.LoadInt64(&t.BytesReceived), t.Connection.User.Username,
t.Connection.ID, t.Connection.protocol, t.Connection.localAddr, t.Connection.remoteAddr, t.ftpMode) t.Connection.ID, t.Connection.protocol, t.Connection.localAddr, t.Connection.remoteAddr, t.ftpMode)
ExecuteActionNotification(&t.Connection.User, operationUpload, t.fsPath, t.requestPath, "", "", "", t.Connection.protocol, ExecuteActionNotification(&t.Connection.User, operationUpload, t.fsPath, t.requestPath, "", "", "", t.Connection.protocol,
@@ -266,6 +278,14 @@ func (t *BaseTransfer) Close() error {
return err return err
} }
func (t *BaseTransfer) updateTimes() {
if !t.aTime.IsZero() && !t.mTime.IsZero() {
err := t.Fs.Chtimes(t.fsPath, t.aTime, t.mTime)
t.Connection.Log(logger.LevelDebug, "set times for file %#v, atime: %v, mtime: %v, err: %v",
t.fsPath, t.aTime, t.mTime, err)
}
}
func (t *BaseTransfer) updateQuota(numFiles int, fileSize int64) bool { func (t *BaseTransfer) updateQuota(numFiles int, fileSize int64) bool {
// S3 uploads are atomic, if there is an error nothing is uploaded // S3 uploads are atomic, if there is an error nothing is uploaded
if t.File == nil && t.ErrTransfer != nil { if t.File == nil && t.ErrTransfer != nil {

View File

@@ -84,6 +84,7 @@ Flags:
--s3-acl string --s3-acl string
--s3-bucket string --s3-bucket string
--s3-endpoint string --s3-endpoint string
--s3-force-path-style Force path style bucket URL
--s3-key-prefix string Allows to restrict access to the --s3-key-prefix string Allows to restrict access to the
virtual folder identified by this virtual folder identified by this
prefix and its contents prefix and its contents

View File

@@ -9762,6 +9762,8 @@ func getScpDownloadCommand(localPath, remotePath string, preserveTime, recursive
args = append(args, "2022") args = append(args, "2022")
args = append(args, "-o") args = append(args, "-o")
args = append(args, "StrictHostKeyChecking=no") args = append(args, "StrictHostKeyChecking=no")
args = append(args, "-o")
args = append(args, "HostKeyAlgorithms=+ssh-rsa")
args = append(args, "-i") args = append(args, "-i")
args = append(args, privateKeyPath) args = append(args, privateKeyPath)
args = append(args, remotePath) args = append(args, remotePath)
@@ -9787,6 +9789,8 @@ func getScpUploadCommand(localPath, remotePath string, preserveTime, remoteToRem
args = append(args, "2022") args = append(args, "2022")
args = append(args, "-o") args = append(args, "-o")
args = append(args, "StrictHostKeyChecking=no") args = append(args, "StrictHostKeyChecking=no")
args = append(args, "-o")
args = append(args, "HostKeyAlgorithms=+ssh-rsa")
args = append(args, "-i") args = append(args, "-i")
args = append(args, privateKeyPath) args = append(args, privateKeyPath)
args = append(args, localPath) args = append(args, localPath)

View File

@@ -232,7 +232,7 @@ function deleteAction() {
}, },
{ {
"targets": [2], "targets": [2],
"render": $.fn.dataTable.render.ellipsis(50, true), "render": $.fn.dataTable.render.ellipsis(60, true),
}, },
{ {
"targets": [3], "targets": [3],

View File

@@ -255,11 +255,11 @@
}, },
{ {
"targets": [3], "targets": [3],
"render": $.fn.dataTable.render.ellipsis(30, true), "render": $.fn.dataTable.render.ellipsis(40, true),
}, },
{ {
"targets": [4], "targets": [4],
"render": $.fn.dataTable.render.ellipsis(40, true), "render": $.fn.dataTable.render.ellipsis(70, true),
} }
], ],
"scrollX": false, "scrollX": false,