mirror of
https://github.com/rclone/rclone.git
synced 2024-12-23 07:29:35 +01:00
local: add --local-time-type to use mtime/atime/btime/ctime as the time
Fixes #7484
This commit is contained in:
parent
854a36c4ab
commit
ac6ba11d22
@ -36,6 +36,27 @@ const devUnset = 0xdeadbeefcafebabe // a d
|
||||
const linkSuffix = ".rclonelink" // The suffix added to a translated symbolic link
|
||||
const useReadDir = (runtime.GOOS == "windows" || runtime.GOOS == "plan9") // these OSes read FileInfos directly
|
||||
|
||||
// timeType allows the user to choose what exactly ModTime() returns
|
||||
type timeType = fs.Enum[timeTypeChoices]
|
||||
|
||||
const (
|
||||
mTime timeType = iota
|
||||
aTime
|
||||
bTime
|
||||
cTime
|
||||
)
|
||||
|
||||
type timeTypeChoices struct{}
|
||||
|
||||
func (timeTypeChoices) Choices() []string {
|
||||
return []string{
|
||||
mTime: "mtime",
|
||||
aTime: "atime",
|
||||
bTime: "btime",
|
||||
cTime: "ctime",
|
||||
}
|
||||
}
|
||||
|
||||
// Register with Fs
|
||||
func init() {
|
||||
fsi := &fs.RegInfo{
|
||||
@ -213,6 +234,42 @@ when copying to a CIFS mount owned by another user. If this option is
|
||||
enabled, rclone will no longer update the modtime after copying a file.`,
|
||||
Default: false,
|
||||
Advanced: true,
|
||||
}, {
|
||||
Name: "time_type",
|
||||
Help: `Set what kind of time is returned.
|
||||
|
||||
Normally rclone does all operations on the mtime or Modification time.
|
||||
|
||||
If you set this flag then rclone will return the Modified time as whatever
|
||||
you set here. So if you use "rclone lsl --local-time-type ctime" then
|
||||
you will see ctimes in the listing.
|
||||
|
||||
If the OS doesn't support returning the time_type specified then rclone
|
||||
will silently replace it with the modification time which all OSes support.
|
||||
|
||||
- mtime is supported by all OSes
|
||||
- atime is supported on all OSes except: plan9, js
|
||||
- btime is only supported on: Windows, macOS, freebsd, netbsd
|
||||
- ctime is supported on all Oses except: Windows, plan9, js
|
||||
|
||||
Note that setting the time will still set the modified time so this is
|
||||
only useful for reading.
|
||||
`,
|
||||
Default: mTime,
|
||||
Advanced: true,
|
||||
Examples: []fs.OptionExample{{
|
||||
Value: mTime.String(),
|
||||
Help: "The last modification time.",
|
||||
}, {
|
||||
Value: aTime.String(),
|
||||
Help: "The last access time.",
|
||||
}, {
|
||||
Value: bTime.String(),
|
||||
Help: "The creation time.",
|
||||
}, {
|
||||
Value: cTime.String(),
|
||||
Help: "The last status change time.",
|
||||
}},
|
||||
}, {
|
||||
Name: config.ConfigEncoding,
|
||||
Help: config.ConfigEncodingHelp,
|
||||
@ -237,6 +294,7 @@ type Options struct {
|
||||
NoPreAllocate bool `config:"no_preallocate"`
|
||||
NoSparse bool `config:"no_sparse"`
|
||||
NoSetModTime bool `config:"no_set_modtime"`
|
||||
TimeType timeType `config:"time_type"`
|
||||
Enc encoder.MultiEncoder `config:"encoding"`
|
||||
}
|
||||
|
||||
@ -1132,7 +1190,7 @@ func (file *localOpenFile) Read(p []byte) (n int, err error) {
|
||||
if oldsize != fi.Size() {
|
||||
return 0, fserrors.NoLowLevelRetryError(fmt.Errorf("can't copy - source file is being updated (size changed from %d to %d)", oldsize, fi.Size()))
|
||||
}
|
||||
if !oldtime.Equal(fi.ModTime()) {
|
||||
if !oldtime.Equal(readTime(file.o.fs.opt.TimeType, fi)) {
|
||||
return 0, fserrors.NoLowLevelRetryError(fmt.Errorf("can't copy - source file is being updated (mod time changed from %v to %v)", oldtime, fi.ModTime()))
|
||||
}
|
||||
}
|
||||
@ -1428,7 +1486,7 @@ func (o *Object) setMetadata(info os.FileInfo) {
|
||||
}
|
||||
o.fs.objectMetaMu.Lock()
|
||||
o.size = info.Size()
|
||||
o.modTime = info.ModTime()
|
||||
o.modTime = readTime(o.fs.opt.TimeType, info)
|
||||
o.mode = info.Mode()
|
||||
o.fs.objectMetaMu.Unlock()
|
||||
// Read the size of the link.
|
||||
|
@ -5,12 +5,31 @@ package local
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/rclone/rclone/fs"
|
||||
)
|
||||
|
||||
// Read the time specified from the os.FileInfo
|
||||
func readTime(t timeType, fi os.FileInfo) time.Time {
|
||||
stat, ok := fi.Sys().(*syscall.Stat_t)
|
||||
if !ok {
|
||||
fs.Debugf(nil, "didn't return Stat_t as expected")
|
||||
return fi.ModTime()
|
||||
}
|
||||
switch t {
|
||||
case aTime:
|
||||
return time.Unix(stat.Atimespec.Unix())
|
||||
case bTime:
|
||||
return time.Unix(stat.Birthtimespec.Unix())
|
||||
case cTime:
|
||||
return time.Unix(stat.Ctimespec.Unix())
|
||||
}
|
||||
return fi.ModTime()
|
||||
}
|
||||
|
||||
// Read the metadata from the file into metadata where possible
|
||||
func (o *Object) readMetadataFromFile(m *fs.Metadata) (err error) {
|
||||
info, err := o.fs.lstat(o.path)
|
||||
|
@ -5,8 +5,10 @@ package local
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"runtime"
|
||||
"sync"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/rclone/rclone/fs"
|
||||
@ -18,6 +20,22 @@ var (
|
||||
readMetadataFromFileFn func(o *Object, m *fs.Metadata) (err error)
|
||||
)
|
||||
|
||||
// Read the time specified from the os.FileInfo
|
||||
func readTime(t timeType, fi os.FileInfo) time.Time {
|
||||
stat, ok := fi.Sys().(*syscall.Stat_t)
|
||||
if !ok {
|
||||
fs.Debugf(nil, "didn't return Stat_t as expected")
|
||||
return fi.ModTime()
|
||||
}
|
||||
switch t {
|
||||
case aTime:
|
||||
return time.Unix(stat.Atim.Unix())
|
||||
case cTime:
|
||||
return time.Unix(stat.Ctim.Unix())
|
||||
}
|
||||
return fi.ModTime()
|
||||
}
|
||||
|
||||
// Read the metadata from the file into metadata where possible
|
||||
func (o *Object) readMetadataFromFile(m *fs.Metadata) (err error) {
|
||||
statxCheckOnce.Do(func() {
|
||||
|
@ -5,10 +5,17 @@ package local
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/rclone/rclone/fs"
|
||||
)
|
||||
|
||||
// Read the time specified from the os.FileInfo
|
||||
func readTime(t timeType, fi os.FileInfo) time.Time {
|
||||
return fi.ModTime()
|
||||
}
|
||||
|
||||
// Read the metadata from the file into metadata where possible
|
||||
func (o *Object) readMetadataFromFile(m *fs.Metadata) (err error) {
|
||||
info, err := o.fs.lstat(o.path)
|
||||
|
@ -5,12 +5,29 @@ package local
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/rclone/rclone/fs"
|
||||
)
|
||||
|
||||
// Read the time specified from the os.FileInfo
|
||||
func readTime(t timeType, fi os.FileInfo) time.Time {
|
||||
stat, ok := fi.Sys().(*syscall.Stat_t)
|
||||
if !ok {
|
||||
fs.Debugf(nil, "didn't return Stat_t as expected")
|
||||
return fi.ModTime()
|
||||
}
|
||||
switch t {
|
||||
case aTime:
|
||||
return time.Unix(stat.Atim.Unix())
|
||||
case cTime:
|
||||
return time.Unix(stat.Ctim.Unix())
|
||||
}
|
||||
return fi.ModTime()
|
||||
}
|
||||
|
||||
// Read the metadata from the file into metadata where possible
|
||||
func (o *Object) readMetadataFromFile(m *fs.Metadata) (err error) {
|
||||
info, err := o.fs.lstat(o.path)
|
||||
|
@ -5,12 +5,29 @@ package local
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/rclone/rclone/fs"
|
||||
)
|
||||
|
||||
// Read the time specified from the os.FileInfo
|
||||
func readTime(t timeType, fi os.FileInfo) time.Time {
|
||||
stat, ok := fi.Sys().(*syscall.Win32FileAttributeData)
|
||||
if !ok {
|
||||
fs.Debugf(nil, "didn't return Win32FileAttributeData as expected")
|
||||
return fi.ModTime()
|
||||
}
|
||||
switch t {
|
||||
case aTime:
|
||||
return time.Unix(0, stat.LastAccessTime.Nanoseconds())
|
||||
case bTime:
|
||||
return time.Unix(0, stat.CreationTime.Nanoseconds())
|
||||
}
|
||||
return fi.ModTime()
|
||||
}
|
||||
|
||||
// Read the metadata from the file into metadata where possible
|
||||
func (o *Object) readMetadataFromFile(m *fs.Metadata) (err error) {
|
||||
info, err := o.fs.lstat(o.path)
|
||||
|
Loading…
Reference in New Issue
Block a user