forked from hanwen/go-fuse
-
Notifications
You must be signed in to change notification settings - Fork 0
/
dir.go
118 lines (98 loc) · 2.74 KB
/
dir.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
// Copyright 2016 the Go-FUSE Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package nodefs
import (
"log"
"sync"
"github.com/gavriva/go-fuse/fuse"
)
type connectorDir struct {
node Node
rawFS fuse.RawFileSystem
// Protect stream and lastOffset. These are written in case
// there is a seek on the directory.
mu sync.Mutex
stream []fuse.DirEntry
// lastOffset stores the last offset for a readdir. This lets
// readdir pick up changes to the directory made after opening
// it.
lastOffset uint64
}
func (d *connectorDir) ReadDir(input *fuse.ReadIn, out *fuse.DirEntryList) (code fuse.Status) {
d.mu.Lock()
defer d.mu.Unlock()
if d.stream == nil {
return fuse.OK
}
// rewinddir() should be as if reopening directory.
// TODO - test this.
if d.lastOffset > 0 && input.Offset == 0 {
d.stream, code = d.node.OpenDir((*fuse.Context)(&input.Context))
if !code.Ok() {
return code
}
}
if input.Offset > uint64(len(d.stream)) {
// This shouldn't happen, but let's not crash.
return fuse.EINVAL
}
todo := d.stream[input.Offset:]
for _, e := range todo {
if e.Name == "" {
log.Printf("got empty directory entry, mode %o.", e.Mode)
continue
}
ok, off := out.AddDirEntry(e)
d.lastOffset = off
if !ok {
break
}
}
return fuse.OK
}
func (d *connectorDir) ReadDirPlus(input *fuse.ReadIn, out *fuse.DirEntryList) (code fuse.Status) {
d.mu.Lock()
defer d.mu.Unlock()
if d.stream == nil {
return fuse.OK
}
// rewinddir() should be as if reopening directory.
if d.lastOffset > 0 && input.Offset == 0 {
d.stream, code = d.node.OpenDir((*fuse.Context)(&input.Context))
if !code.Ok() {
return code
}
}
if input.Offset > uint64(len(d.stream)) {
// This shouldn't happen, but let's not crash.
return fuse.EINVAL
}
todo := d.stream[input.Offset:]
for _, e := range todo {
if e.Name == "" {
log.Printf("got empty directory entry, mode %o.", e.Mode)
continue
}
// we have to be sure entry will fit if we try to add
// it, or we'll mess up the lookup counts.
entryDest, off := out.AddDirLookupEntry(e)
if entryDest == nil {
break
}
entryDest.Ino = uint64(fuse.FUSE_UNKNOWN_INO)
// No need to fill attributes for . and ..
if e.Name == "." || e.Name == ".." {
continue
}
// Clear entryDest before use it, some fields can be corrupted if does not set all fields in rawFS.Lookup
*entryDest = fuse.EntryOut{}
d.rawFS.Lookup(&input.InHeader, e.Name, entryDest)
d.lastOffset = off
}
return fuse.OK
}
type rawDir interface {
ReadDir(out *fuse.DirEntryList, input *fuse.ReadIn, c *fuse.Context) fuse.Status
ReadDirPlus(out *fuse.DirEntryList, input *fuse.ReadIn, c *fuse.Context) fuse.Status
}