forked from nxsre/sshfs-go
/
file.go
158 lines (131 loc) · 3.25 KB
/
file.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
package fs
import (
"bazil.org/fuse"
"bazil.org/fuse/fs"
"context"
"github.com/pkg/sftp"
"github.com/sirupsen/logrus"
"log"
"sync"
"time"
)
// File Node
type File struct {
*Node
create bool
file *sftp.File
writing bool
sync.Mutex
}
var _ fs.Node = (*File)(nil)
// Attr File
func (f *File) Attr(ctx context.Context, a *fuse.Attr) error {
logrus.Debug("handling File.Attr call")
stat, err := f.sftp.Stat(f.Path())
if err != nil {
return err
}
statT, ok := stat.Sys().(*sftp.FileStat)
if ok {
a.Atime = time.Unix(int64(statT.Atime), 0)
}
a.Inode = f.GetInode()
a.Mode = stat.Mode()
a.Size = uint64(stat.Size())
a.Ctime = stat.ModTime()
a.Mtime = stat.ModTime()
return nil
}
var _ fs.NodeSetattrer = (*File)(nil)
// Setattr File
func (f *File) Setattr(ctx context.Context, req *fuse.SetattrRequest, resp *fuse.SetattrResponse) error {
logrus.WithField("req", req).Debug("handling File.Setattr call")
if req.Valid.Size() {
resp.Attr.Size = req.Size
return f.sftp.Truncate(f.Path(), int64(req.Size))
}
return nil
}
var _ fs.NodeOpener = (*File)(nil)
// Open File
func (f *File) Open(ctx context.Context, req *fuse.OpenRequest, resp *fuse.OpenResponse) (fs.Handle, error) {
logrus.WithField("req", req).Debug("handling File.Open call")
// Unsupported flags
if req.Flags&fuse.OpenAppend == fuse.OpenAppend {
return nil, fuse.ENOTSUP
}
file, err := f.sftp.OpenFile(f.Path(), int(req.Flags))
if err != nil {
return nil, err
}
fh := &File{
file: file,
Node: f.Node,
}
fh.Lock()
if req.Flags.IsReadOnly() {
return fh, err
}
if req.Flags.IsWriteOnly() {
resp.Flags = fuse.OpenPurgeAttr
return fh, nil
}
return nil, fuse.ENOTSUP
}
var _ fs.Handle = (*File)(nil)
var _ fs.HandleReader = (*File)(nil)
// Read File
func (f *File) Read(ctx context.Context, req *fuse.ReadRequest, resp *fuse.ReadResponse) error {
logrus.WithField("req", req).Debug("handling File.Read call")
// TODO: 大文件按照 req.Offset 分块读取
if f.file == nil {
var err error
f.file, err = f.sftp.OpenFile(f.Path(), int(req.Flags))
if err != nil {
return err
}
}
f.file.Seek(req.Offset, 0)
resp.Data = make([]byte, req.Size)
f.file.Read(resp.Data)
return nil
}
var _ fs.HandleWriter = (*File)(nil)
// Write File
func (f *File) Write(ctx context.Context, req *fuse.WriteRequest, resp *fuse.WriteResponse) error {
logrus.Debug("handling File.Write call")
var err error
if f.file == nil {
f.file, err = f.sftp.OpenFile(f.Path(), int(req.FileFlags)|int(req.Flags))
if err != nil {
return err
}
}
//stat, err := f.file.Stat()
_, err = f.file.Write(req.Data)
resp.Size = len(req.Data)
return err
}
var _ fs.NodeFsyncer = (*File)(nil)
// Fsync File
func (f *File) Fsync(ctx context.Context, req *fuse.FsyncRequest) error {
logrus.Debug("handling File.Fsync call")
return nil
}
var _ fs.HandleReleaser = (*File)(nil)
// Release File
func (f *File) Release(ctx context.Context, req *fuse.ReleaseRequest) error {
logrus.Debug("handling File.Release call", f.Path())
var err error
if f.file != nil {
err = f.file.Close()
}
f.Unlock()
return err
}
var _ fs.HandleFlusher = (*File)(nil)
// Flush File
func (f *File) Flush(ctx context.Context, req *fuse.FlushRequest) error {
log.Println("Flushing file", f.Path())
return nil
}