mirror of
https://github.com/rclone/rclone.git
synced 2024-11-26 02:14:42 +01:00
sftp, local: refactor to stop storing os.FileInfo in preparation for serialization
This commit is contained in:
parent
e7d04fc103
commit
dc56ad9816
@ -66,11 +66,13 @@ type Fs struct {
|
|||||||
|
|
||||||
// Object represents a local filesystem object
|
// Object represents a local filesystem object
|
||||||
type Object struct {
|
type Object struct {
|
||||||
fs *Fs // The Fs this object is part of
|
fs *Fs // The Fs this object is part of
|
||||||
remote string // The remote path - properly UTF-8 encoded - for rclone
|
remote string // The remote path - properly UTF-8 encoded - for rclone
|
||||||
path string // The local path - may not be properly UTF-8 encoded - for OS
|
path string // The local path - may not be properly UTF-8 encoded - for OS
|
||||||
info os.FileInfo // Interface for file info (always present)
|
size int64 // file metadata - always present
|
||||||
hashes map[fs.HashType]string // Hashes
|
mode os.FileMode
|
||||||
|
modTime time.Time
|
||||||
|
hashes map[fs.HashType]string // Hashes
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------
|
// ------------------------------------------------------------
|
||||||
@ -159,7 +161,7 @@ func (f *Fs) newObject(remote, dstPath string) *Object {
|
|||||||
func (f *Fs) newObjectWithInfo(remote, dstPath string, info os.FileInfo) (fs.Object, error) {
|
func (f *Fs) newObjectWithInfo(remote, dstPath string, info os.FileInfo) (fs.Object, error) {
|
||||||
o := f.newObject(remote, dstPath)
|
o := f.newObject(remote, dstPath)
|
||||||
if info != nil {
|
if info != nil {
|
||||||
o.info = info
|
o.setMetadata(info)
|
||||||
} else {
|
} else {
|
||||||
err := o.lstat()
|
err := o.lstat()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -169,7 +171,7 @@ func (f *Fs) newObjectWithInfo(remote, dstPath string, info os.FileInfo) (fs.Obj
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if o.info.Mode().IsDir() {
|
if o.mode.IsDir() {
|
||||||
return nil, errors.Wrapf(fs.ErrorNotAFile, "%q", remote)
|
return nil, errors.Wrapf(fs.ErrorNotAFile, "%q", remote)
|
||||||
}
|
}
|
||||||
return o, nil
|
return o, nil
|
||||||
@ -451,7 +453,7 @@ func (f *Fs) Move(src fs.Object, remote string) (fs.Object, error) {
|
|||||||
// OK
|
// OK
|
||||||
} else if err != nil {
|
} else if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
} else if !dstObj.info.Mode().IsRegular() {
|
} else if !dstObj.mode.IsRegular() {
|
||||||
// It isn't a file
|
// It isn't a file
|
||||||
return nil, errors.New("can't move file onto non-file")
|
return nil, errors.New("can't move file onto non-file")
|
||||||
}
|
}
|
||||||
@ -539,14 +541,14 @@ func (o *Object) Remote() string {
|
|||||||
// Hash returns the requested hash of a file as a lowercase hex string
|
// Hash returns the requested hash of a file as a lowercase hex string
|
||||||
func (o *Object) Hash(r fs.HashType) (string, error) {
|
func (o *Object) Hash(r fs.HashType) (string, error) {
|
||||||
// Check that the underlying file hasn't changed
|
// Check that the underlying file hasn't changed
|
||||||
oldtime := o.info.ModTime()
|
oldtime := o.modTime
|
||||||
oldsize := o.info.Size()
|
oldsize := o.size
|
||||||
err := o.lstat()
|
err := o.lstat()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", errors.Wrap(err, "hash: failed to stat")
|
return "", errors.Wrap(err, "hash: failed to stat")
|
||||||
}
|
}
|
||||||
|
|
||||||
if !o.info.ModTime().Equal(oldtime) || oldsize != o.info.Size() {
|
if !o.modTime.Equal(oldtime) || oldsize != o.size {
|
||||||
o.hashes = nil
|
o.hashes = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -570,12 +572,12 @@ func (o *Object) Hash(r fs.HashType) (string, error) {
|
|||||||
|
|
||||||
// Size returns the size of an object in bytes
|
// Size returns the size of an object in bytes
|
||||||
func (o *Object) Size() int64 {
|
func (o *Object) Size() int64 {
|
||||||
return o.info.Size()
|
return o.size
|
||||||
}
|
}
|
||||||
|
|
||||||
// ModTime returns the modification time of the object
|
// ModTime returns the modification time of the object
|
||||||
func (o *Object) ModTime() time.Time {
|
func (o *Object) ModTime() time.Time {
|
||||||
return o.info.ModTime()
|
return o.modTime
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetModTime sets the modification time of the local fs object
|
// SetModTime sets the modification time of the local fs object
|
||||||
@ -597,7 +599,7 @@ func (o *Object) Storable() bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mode := o.info.Mode()
|
mode := o.mode
|
||||||
// On windows a file with os.ModeSymlink represents a file with reparse points
|
// On windows a file with os.ModeSymlink represents a file with reparse points
|
||||||
if runtime.GOOS == "windows" && (mode&os.ModeSymlink) != 0 {
|
if runtime.GOOS == "windows" && (mode&os.ModeSymlink) != 0 {
|
||||||
fs.Debugf(o, "Clearing symlink bit to allow a file with reparse points to be copied")
|
fs.Debugf(o, "Clearing symlink bit to allow a file with reparse points to be copied")
|
||||||
@ -744,10 +746,19 @@ func (o *Object) Update(in io.Reader, src fs.ObjectInfo, options ...fs.OpenOptio
|
|||||||
return o.lstat()
|
return o.lstat()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// setMetadata sets the file info from the os.FileInfo passed in
|
||||||
|
func (o *Object) setMetadata(info os.FileInfo) {
|
||||||
|
o.size = info.Size()
|
||||||
|
o.modTime = info.ModTime()
|
||||||
|
o.mode = info.Mode()
|
||||||
|
}
|
||||||
|
|
||||||
// Stat a Object into info
|
// Stat a Object into info
|
||||||
func (o *Object) lstat() error {
|
func (o *Object) lstat() error {
|
||||||
info, err := o.fs.lstat(o.path)
|
info, err := o.fs.lstat(o.path)
|
||||||
o.info = info
|
if err == nil {
|
||||||
|
o.setMetadata(info)
|
||||||
|
}
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
27
sftp/sftp.go
27
sftp/sftp.go
@ -66,9 +66,11 @@ type Fs struct {
|
|||||||
|
|
||||||
// Object is a remote SFTP file that has been stat'd (so it exists, but is not necessarily open for reading)
|
// Object is a remote SFTP file that has been stat'd (so it exists, but is not necessarily open for reading)
|
||||||
type Object struct {
|
type Object struct {
|
||||||
fs *Fs
|
fs *Fs
|
||||||
remote string
|
remote string
|
||||||
info os.FileInfo
|
size int64 // size of the object
|
||||||
|
modTime time.Time // modification time of the object
|
||||||
|
mode os.FileMode // mode bits from the file
|
||||||
}
|
}
|
||||||
|
|
||||||
// ObjectReader holds the sftp.File interface to a remote SFTP file opened for reading
|
// ObjectReader holds the sftp.File interface to a remote SFTP file opened for reading
|
||||||
@ -270,8 +272,8 @@ func (f *Fs) List(dir string) (entries fs.DirEntries, err error) {
|
|||||||
o := &Object{
|
o := &Object{
|
||||||
fs: f,
|
fs: f,
|
||||||
remote: remote,
|
remote: remote,
|
||||||
info: info,
|
|
||||||
}
|
}
|
||||||
|
o.setMetadata(info)
|
||||||
entries = append(entries, o)
|
entries = append(entries, o)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -439,12 +441,12 @@ func (o *Object) Hash(r fs.HashType) (string, error) {
|
|||||||
|
|
||||||
// Size returns the size in bytes of the remote sftp file
|
// Size returns the size in bytes of the remote sftp file
|
||||||
func (o *Object) Size() int64 {
|
func (o *Object) Size() int64 {
|
||||||
return o.info.Size()
|
return o.size
|
||||||
}
|
}
|
||||||
|
|
||||||
// ModTime returns the modification time of the remote sftp file
|
// ModTime returns the modification time of the remote sftp file
|
||||||
func (o *Object) ModTime() time.Time {
|
func (o *Object) ModTime() time.Time {
|
||||||
return o.info.ModTime()
|
return o.modTime
|
||||||
}
|
}
|
||||||
|
|
||||||
// path returns the native path of the object
|
// path returns the native path of the object
|
||||||
@ -452,7 +454,14 @@ func (o *Object) path() string {
|
|||||||
return path.Join(o.fs.root, o.remote)
|
return path.Join(o.fs.root, o.remote)
|
||||||
}
|
}
|
||||||
|
|
||||||
// stat updates the info field in the Object
|
// setMetadata updates the info in the object from the stat result passed in
|
||||||
|
func (o *Object) setMetadata(info os.FileInfo) {
|
||||||
|
o.modTime = info.ModTime()
|
||||||
|
o.size = info.Size()
|
||||||
|
o.mode = info.Mode()
|
||||||
|
}
|
||||||
|
|
||||||
|
// stat updates the info in the Object
|
||||||
func (o *Object) stat() error {
|
func (o *Object) stat() error {
|
||||||
info, err := o.fs.sftpClient.Stat(o.path())
|
info, err := o.fs.sftpClient.Stat(o.path())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -464,7 +473,7 @@ func (o *Object) stat() error {
|
|||||||
if info.IsDir() {
|
if info.IsDir() {
|
||||||
return errors.Wrapf(fs.ErrorNotAFile, "%q", o.remote)
|
return errors.Wrapf(fs.ErrorNotAFile, "%q", o.remote)
|
||||||
}
|
}
|
||||||
o.info = info
|
o.setMetadata(info)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -485,7 +494,7 @@ func (o *Object) SetModTime(modTime time.Time) error {
|
|||||||
|
|
||||||
// Storable returns whether the remote sftp file is a regular file (not a directory, symbolic link, block device, character device, named pipe, etc)
|
// Storable returns whether the remote sftp file is a regular file (not a directory, symbolic link, block device, character device, named pipe, etc)
|
||||||
func (o *Object) Storable() bool {
|
func (o *Object) Storable() bool {
|
||||||
return o.info.Mode().IsRegular()
|
return o.mode.IsRegular()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read from a remote sftp file object reader
|
// Read from a remote sftp file object reader
|
||||||
|
Loading…
Reference in New Issue
Block a user