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  }