2023-10-29 15:15:34 +01:00
|
|
|
//go:build linux
|
2016-07-18 00:03:23 +02:00
|
|
|
|
|
|
|
package mount
|
|
|
|
|
|
|
|
import (
|
2019-05-07 14:53:16 +02:00
|
|
|
"context"
|
2024-07-03 12:34:29 +02:00
|
|
|
"os"
|
2022-06-12 12:37:00 +02:00
|
|
|
"syscall"
|
2016-07-18 00:03:23 +02:00
|
|
|
"time"
|
|
|
|
|
|
|
|
"bazil.org/fuse"
|
|
|
|
fusefs "bazil.org/fuse/fs"
|
2019-07-28 19:47:38 +02:00
|
|
|
"github.com/rclone/rclone/fs/log"
|
|
|
|
"github.com/rclone/rclone/vfs"
|
2016-07-18 00:03:23 +02:00
|
|
|
)
|
|
|
|
|
|
|
|
// File represents a file
|
|
|
|
type File struct {
|
2017-10-28 21:01:34 +02:00
|
|
|
*vfs.File
|
2020-07-23 18:17:01 +02:00
|
|
|
fsys *FS
|
2016-07-18 00:03:23 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// Check interface satisfied
|
|
|
|
var _ fusefs.Node = (*File)(nil)
|
|
|
|
|
|
|
|
// Attr fills out the attributes for the file
|
2017-05-09 12:39:33 +02:00
|
|
|
func (f *File) Attr(ctx context.Context, a *fuse.Attr) (err error) {
|
2018-01-12 17:30:54 +01:00
|
|
|
defer log.Trace(f, "")("a=%+v, err=%v", a, &err)
|
2024-07-02 11:26:15 +02:00
|
|
|
a.Valid = time.Duration(f.fsys.opt.AttrTimeout)
|
2017-10-25 11:00:26 +02:00
|
|
|
modTime := f.File.ModTime()
|
|
|
|
Size := uint64(f.File.Size())
|
|
|
|
Blocks := (Size + 511) / 512
|
2017-10-29 12:00:56 +01:00
|
|
|
a.Gid = f.VFS().Opt.GID
|
|
|
|
a.Uid = f.VFS().Opt.UID
|
2024-07-03 12:34:29 +02:00
|
|
|
a.Mode = os.FileMode(f.VFS().Opt.FilePerms)
|
2017-05-02 23:35:07 +02:00
|
|
|
a.Size = Size
|
|
|
|
a.Atime = modTime
|
|
|
|
a.Mtime = modTime
|
|
|
|
a.Ctime = modTime
|
|
|
|
a.Blocks = Blocks
|
2016-07-18 00:03:23 +02:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2017-03-23 20:41:21 +01:00
|
|
|
// Check interface satisfied
|
|
|
|
var _ fusefs.NodeSetattrer = (*File)(nil)
|
|
|
|
|
2017-11-20 20:42:35 +01:00
|
|
|
// Setattr handles attribute changes from FUSE. Currently supports ModTime and Size only
|
2017-05-09 12:39:33 +02:00
|
|
|
func (f *File) Setattr(ctx context.Context, req *fuse.SetattrRequest, resp *fuse.SetattrResponse) (err error) {
|
2018-01-12 17:30:54 +01:00
|
|
|
defer log.Trace(f, "a=%+v", req)("err=%v", &err)
|
2017-11-20 20:42:35 +01:00
|
|
|
if !f.VFS().Opt.NoModTime {
|
|
|
|
if req.Valid.Mtime() {
|
|
|
|
err = f.File.SetModTime(req.Mtime)
|
2018-01-29 21:49:13 +01:00
|
|
|
} else if req.Valid.MtimeNow() {
|
|
|
|
err = f.File.SetModTime(time.Now())
|
2017-11-20 20:42:35 +01:00
|
|
|
}
|
2017-03-23 20:41:21 +01:00
|
|
|
}
|
2017-11-20 20:42:35 +01:00
|
|
|
if req.Valid.Size() {
|
|
|
|
err = f.File.Truncate(int64(req.Size))
|
2017-03-23 20:41:21 +01:00
|
|
|
}
|
2017-05-02 23:35:07 +02:00
|
|
|
return translateError(err)
|
2016-07-18 00:03:23 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// Check interface satisfied
|
|
|
|
var _ fusefs.NodeOpener = (*File)(nil)
|
|
|
|
|
|
|
|
// Open the file for read or write
|
2017-03-02 23:07:01 +01:00
|
|
|
func (f *File) Open(ctx context.Context, req *fuse.OpenRequest, resp *fuse.OpenResponse) (fh fusefs.Handle, err error) {
|
2018-01-12 17:30:54 +01:00
|
|
|
defer log.Trace(f, "flags=%v", req.Flags)("fh=%v, err=%v", &fh, &err)
|
2017-10-30 11:14:39 +01:00
|
|
|
|
|
|
|
// fuse flags are based off syscall flags as are os flags, so
|
|
|
|
// should be compatible
|
2018-03-15 11:27:04 +01:00
|
|
|
handle, err := f.File.Open(int(req.Flags))
|
2017-10-30 11:14:39 +01:00
|
|
|
if err != nil {
|
|
|
|
return nil, translateError(err)
|
|
|
|
}
|
|
|
|
|
2019-09-14 14:11:21 +02:00
|
|
|
// If size unknown then use direct io to read
|
2019-10-06 13:06:26 +02:00
|
|
|
if entry := handle.Node().DirEntry(); entry != nil && entry.Size() < 0 {
|
2019-09-14 14:11:21 +02:00
|
|
|
resp.Flags |= fuse.OpenDirectIO
|
|
|
|
}
|
2024-03-04 12:37:18 +01:00
|
|
|
if f.fsys.opt.DirectIO {
|
|
|
|
resp.Flags |= fuse.OpenDirectIO
|
|
|
|
}
|
2019-09-14 14:11:21 +02:00
|
|
|
|
2017-11-02 19:22:26 +01:00
|
|
|
return &FileHandle{handle}, nil
|
2016-07-18 00:03:23 +02:00
|
|
|
}
|
2017-01-29 12:29:42 +01:00
|
|
|
|
|
|
|
// Check interface satisfied
|
|
|
|
var _ fusefs.NodeFsyncer = (*File)(nil)
|
|
|
|
|
|
|
|
// Fsync the file
|
|
|
|
//
|
|
|
|
// Note that we don't do anything except return OK
|
2017-05-09 12:39:33 +02:00
|
|
|
func (f *File) Fsync(ctx context.Context, req *fuse.FsyncRequest) (err error) {
|
2018-01-12 17:30:54 +01:00
|
|
|
defer log.Trace(f, "")("err=%v", &err)
|
2017-01-29 12:29:42 +01:00
|
|
|
return nil
|
|
|
|
}
|
2018-05-03 10:15:32 +02:00
|
|
|
|
|
|
|
// Getxattr gets an extended attribute by the given name from the
|
|
|
|
// node.
|
|
|
|
//
|
|
|
|
// If there is no xattr by that name, returns fuse.ErrNoXattr.
|
|
|
|
func (f *File) Getxattr(ctx context.Context, req *fuse.GetxattrRequest, resp *fuse.GetxattrResponse) error {
|
2022-06-12 12:37:00 +02:00
|
|
|
return syscall.ENOSYS // we never implement this
|
2018-05-03 10:15:32 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
var _ fusefs.NodeGetxattrer = (*File)(nil)
|
|
|
|
|
|
|
|
// Listxattr lists the extended attributes recorded for the node.
|
|
|
|
func (f *File) Listxattr(ctx context.Context, req *fuse.ListxattrRequest, resp *fuse.ListxattrResponse) error {
|
2022-06-12 12:37:00 +02:00
|
|
|
return syscall.ENOSYS // we never implement this
|
2018-05-03 10:15:32 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
var _ fusefs.NodeListxattrer = (*File)(nil)
|
|
|
|
|
|
|
|
// Setxattr sets an extended attribute with the given name and
|
|
|
|
// value for the node.
|
|
|
|
func (f *File) Setxattr(ctx context.Context, req *fuse.SetxattrRequest) error {
|
2022-06-12 12:37:00 +02:00
|
|
|
return syscall.ENOSYS // we never implement this
|
2018-05-03 10:15:32 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
var _ fusefs.NodeSetxattrer = (*File)(nil)
|
|
|
|
|
|
|
|
// Removexattr removes an extended attribute for the name.
|
|
|
|
//
|
|
|
|
// If there is no xattr by that name, returns fuse.ErrNoXattr.
|
|
|
|
func (f *File) Removexattr(ctx context.Context, req *fuse.RemovexattrRequest) error {
|
2022-06-12 12:37:00 +02:00
|
|
|
return syscall.ENOSYS // we never implement this
|
2018-05-03 10:15:32 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
var _ fusefs.NodeRemovexattrer = (*File)(nil)
|