github.com/hanwen/go-fuse@v1.0.0/fuse/nodefs/dir.go (about) 1 // Copyright 2016 the Go-FUSE Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package nodefs 6 7 import ( 8 "log" 9 "sync" 10 11 "github.com/hanwen/go-fuse/fuse" 12 ) 13 14 type connectorDir struct { 15 node Node 16 inode *Inode 17 rawFS fuse.RawFileSystem 18 19 // Protect stream and lastOffset. These are written in case 20 // there is a seek on the directory. 21 mu sync.Mutex 22 stream []fuse.DirEntry 23 } 24 25 func (d *connectorDir) ReadDir(input *fuse.ReadIn, out *fuse.DirEntryList) (code fuse.Status) { 26 d.mu.Lock() 27 defer d.mu.Unlock() 28 29 // rewinddir() should be as if reopening directory. 30 // TODO - test this. 31 if d.stream == nil || input.Offset == 0 { 32 d.stream, code = d.node.OpenDir(&input.Context) 33 if !code.Ok() { 34 return code 35 } 36 d.stream = append(d.stream, d.inode.getMountDirEntries()...) 37 d.stream = append(d.stream, 38 fuse.DirEntry{Mode: fuse.S_IFDIR, Name: "."}, 39 fuse.DirEntry{Mode: fuse.S_IFDIR, Name: ".."}) 40 } 41 42 if input.Offset > uint64(len(d.stream)) { 43 // This shouldn't happen, but let's not crash. 44 return fuse.EINVAL 45 } 46 47 todo := d.stream[input.Offset:] 48 for _, e := range todo { 49 if e.Name == "" { 50 log.Printf("got empty directory entry, mode %o.", e.Mode) 51 continue 52 } 53 ok := out.AddDirEntry(e) 54 if !ok { 55 break 56 } 57 } 58 return fuse.OK 59 } 60 61 func (d *connectorDir) ReadDirPlus(input *fuse.ReadIn, out *fuse.DirEntryList) (code fuse.Status) { 62 d.mu.Lock() 63 defer d.mu.Unlock() 64 65 // rewinddir() should be as if reopening directory. 66 if d.stream == nil || input.Offset == 0 { 67 d.stream, code = d.node.OpenDir(&input.Context) 68 if !code.Ok() { 69 return code 70 } 71 d.stream = append(d.stream, d.inode.getMountDirEntries()...) 72 d.stream = append(d.stream, 73 fuse.DirEntry{Mode: fuse.S_IFDIR, Name: "."}, 74 fuse.DirEntry{Mode: fuse.S_IFDIR, Name: ".."}) 75 } 76 77 if input.Offset > uint64(len(d.stream)) { 78 // This shouldn't happen, but let's not crash. 79 return fuse.EINVAL 80 } 81 todo := d.stream[input.Offset:] 82 for _, e := range todo { 83 if e.Name == "" { 84 log.Printf("got empty directory entry, mode %o.", e.Mode) 85 continue 86 } 87 88 // we have to be sure entry will fit if we try to add 89 // it, or we'll mess up the lookup counts. 90 entryDest := out.AddDirLookupEntry(e) 91 if entryDest == nil { 92 break 93 } 94 entryDest.Ino = uint64(fuse.FUSE_UNKNOWN_INO) 95 96 // No need to fill attributes for . and .. 97 if e.Name == "." || e.Name == ".." { 98 continue 99 } 100 101 // Clear entryDest before use it, some fields can be corrupted if does not set all fields in rawFS.Lookup 102 *entryDest = fuse.EntryOut{} 103 104 d.rawFS.Lookup(&input.InHeader, e.Name, entryDest) 105 } 106 return fuse.OK 107 } 108 109 type rawDir interface { 110 ReadDir(out *fuse.DirEntryList, input *fuse.ReadIn, c *fuse.Context) fuse.Status 111 ReadDirPlus(out *fuse.DirEntryList, input *fuse.ReadIn, c *fuse.Context) fuse.Status 112 }