forked from keybase/kbfs
-
Notifications
You must be signed in to change notification settings - Fork 0
/
file.go
146 lines (120 loc) · 4.66 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
// Copyright 2016 Keybase Inc. All rights reserved.
// Use of this source code is governed by a BSD
// license that can be found in the LICENSE file.
package libdokan
import (
"github.com/keybase/kbfs/dokan"
"github.com/keybase/kbfs/libkbfs"
"golang.org/x/net/context"
)
// File represents KBFS files.
type File struct {
FSO
}
func newFile(folder *Folder, node libkbfs.Node, name string, parent libkbfs.Node) *File {
f := &File{FSO{
name: name,
parent: parent,
folder: folder,
node: node,
}}
f.refcount.Increase()
return f
}
// GetFileInformation for dokan.
func (f *File) GetFileInformation(ctx context.Context, fi *dokan.FileInfo) (a *dokan.Stat, err error) {
f.folder.fs.logEnter(ctx, "File GetFileInformation")
defer func() { f.folder.reportErr(ctx, libkbfs.ReadMode, err) }()
a, err = eiToStat(f.folder.fs.config.KBFSOps().Stat(ctx, f.node))
if a != nil {
f.folder.fs.log.CDebugf(ctx, "File GetFileInformation node=%v => %v", f.node, *a)
} else {
f.folder.fs.log.CDebugf(ctx, "File GetFileInformation node=%v => Error %T %v", f.node, err, err)
}
return a, err
}
// CanDeleteFile - return just nil
// TODO check for permissions here.
func (f *File) CanDeleteFile(ctx context.Context, fi *dokan.FileInfo) error {
f.folder.fs.logEnterf(ctx, "File CanDeleteFile for %q", f.name)
return nil
}
// Cleanup - for dokan, remember to handle deletions.
// If Cleanup is called with non-nil FileInfo that has IsDeleteOnClose()
// no libdokan locks should be held prior to the call.
func (f *File) Cleanup(ctx context.Context, fi *dokan.FileInfo) {
var err error
f.folder.fs.logEnter(ctx, "File Cleanup")
defer func() { f.folder.reportErr(ctx, libkbfs.WriteMode, err) }()
f.folder.fs.log.CDebugf(ctx, "Cleanup %v", *f)
if fi != nil && fi.IsDeleteOnClose() {
// renameAndDeletionLock should be the first lock to be grabbed in libdokan.
f.folder.fs.renameAndDeletionLock.Lock()
defer f.folder.fs.renameAndDeletionLock.Unlock()
f.folder.fs.log.CDebugf(ctx, "Removing (Delete) file in cleanup %s", f.name)
err = f.folder.fs.config.KBFSOps().RemoveEntry(ctx, f.parent, f.name)
}
if f.refcount.Decrease() {
f.folder.fs.log.CDebugf(ctx, "Forgetting file node")
f.folder.forgetNode(ctx, f.node)
// TODO this should not be needed in future.
f.folder.fs.config.KBFSOps().Sync(ctx, f.node)
}
}
// FlushFileBuffers performs a (f)sync.
func (f *File) FlushFileBuffers(ctx context.Context, fi *dokan.FileInfo) (err error) {
f.folder.fs.logEnter(ctx, "File FlushFileBuffers")
defer func() { f.folder.reportErr(ctx, libkbfs.WriteMode, err) }()
return f.folder.fs.config.KBFSOps().Sync(ctx, f.node)
}
// ReadFile for dokan reads.
func (f *File) ReadFile(ctx context.Context, fi *dokan.FileInfo, bs []byte, offset int64) (n int, err error) {
f.folder.fs.logEnter(ctx, "ReadFile")
defer func() { f.folder.reportErr(ctx, libkbfs.ReadMode, err) }()
var nlarge int64
nlarge, err = f.folder.fs.config.KBFSOps().Read(ctx, f.node, bs, offset)
// This is safe since length of slices always fits into an int
return int(nlarge), err
}
// WriteFile for dokan writes.
func (f *File) WriteFile(ctx context.Context, fi *dokan.FileInfo, bs []byte, offset int64) (n int, err error) {
f.folder.fs.logEnter(ctx, "WriteFile")
defer func() { f.folder.reportErr(ctx, libkbfs.WriteMode, err) }()
if offset == -1 {
ei, err := f.folder.fs.config.KBFSOps().Stat(ctx, f.node)
if err != nil {
return 0, err
}
offset = int64(ei.Size)
}
err = f.folder.fs.config.KBFSOps().Write(ctx, f.node, bs, offset)
return len(bs), err
}
// SetEndOfFile for dokan (f)truncates.
func (f *File) SetEndOfFile(ctx context.Context, fi *dokan.FileInfo, length int64) (err error) {
f.folder.fs.logEnter(ctx, "File SetEndOfFile")
defer func() { f.folder.reportErr(ctx, libkbfs.WriteMode, err) }()
return f.folder.fs.config.KBFSOps().Truncate(ctx, f.node, uint64(length))
}
// SetAllocationSize for dokan (f)truncates but does not grow
// file size (it may fallocate, but that is not done at the
// moment).
func (f *File) SetAllocationSize(ctx context.Context, fi *dokan.FileInfo, newSize int64) (err error) {
f.folder.fs.logEnter(ctx, "File SetAllocationSize")
defer func() { f.folder.reportErr(ctx, libkbfs.WriteMode, err) }()
ei, err := f.folder.fs.config.KBFSOps().Stat(ctx, f.node)
if err != nil {
return err
}
// Refuse to grow the file.
if int64(ei.Size) <= newSize {
return nil
}
return f.folder.fs.config.KBFSOps().Truncate(ctx, f.node, uint64(newSize))
}
// SetFileAttributes for Dokan.
func (f *File) SetFileAttributes(ctx context.Context, fi *dokan.FileInfo, fileAttributes dokan.FileAttribute) error {
f.folder.fs.logEnter(ctx, "File SetFileAttributes")
// TODO handle attributes for real.
return nil
}