github.com/scaleoutsean/fusego@v0.0.0-20220224074057-4a6429e46bb8/fuseutil/dirent.go (about)

     1  // Copyright 2015 Google Inc. All Rights Reserved.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package fuseutil
    16  
    17  import (
    18  	"syscall"
    19  	"unsafe"
    20  
    21  	"github.com/scaleoutsean/fusego/fuseops"
    22  )
    23  
    24  type DirentType uint32
    25  
    26  const (
    27  	DT_Unknown   DirentType = 0
    28  	DT_Socket    DirentType = syscall.DT_SOCK
    29  	DT_Link      DirentType = syscall.DT_LNK
    30  	DT_File      DirentType = syscall.DT_REG
    31  	DT_Block     DirentType = syscall.DT_BLK
    32  	DT_Directory DirentType = syscall.DT_DIR
    33  	DT_Char      DirentType = syscall.DT_CHR
    34  	DT_FIFO      DirentType = syscall.DT_FIFO
    35  )
    36  
    37  // A struct representing an entry within a directory file, describing a child.
    38  // See notes on fuseops.ReadDirOp and on WriteDirent for details.
    39  type Dirent struct {
    40  	// The (opaque) offset within the directory file of the entry following this
    41  	// one. See notes on fuseops.ReadDirOp.Offset for details.
    42  	Offset fuseops.DirOffset
    43  
    44  	// The inode of the child file or directory, and its name within the parent.
    45  	Inode fuseops.InodeID
    46  	Name  string
    47  
    48  	// The type of the child. The zero value (DT_Unknown) is legal, but means
    49  	// that the kernel will need to call GetAttr when the type is needed.
    50  	Type DirentType
    51  }
    52  
    53  // Write the supplied directory entry intto the given buffer in the format
    54  // expected in fuseops.ReadFileOp.Data, returning the number of bytes written.
    55  // Return zero if the entry would not fit.
    56  func WriteDirent(buf []byte, d Dirent) (n int) {
    57  	// We want to write bytes with the layout of fuse_dirent
    58  	// (http://goo.gl/BmFxob) in host order. The struct must be aligned according
    59  	// to FUSE_DIRENT_ALIGN (http://goo.gl/UziWvH), which dictates 8-byte
    60  	// alignment.
    61  	type fuse_dirent struct {
    62  		ino     uint64
    63  		off     uint64
    64  		namelen uint32
    65  		type_   uint32
    66  		name    [0]byte
    67  	}
    68  
    69  	const direntAlignment = 8
    70  	const direntSize = 8 + 8 + 4 + 4
    71  
    72  	// Compute the number of bytes of padding we'll need to maintain alignment
    73  	// for the next entry.
    74  	var padLen int
    75  	if len(d.Name)%direntAlignment != 0 {
    76  		padLen = direntAlignment - (len(d.Name) % direntAlignment)
    77  	}
    78  
    79  	// Do we have enough room?
    80  	totalLen := direntSize + len(d.Name) + padLen
    81  	if totalLen > len(buf) {
    82  		return n
    83  	}
    84  
    85  	// Write the header.
    86  	de := fuse_dirent{
    87  		ino:     uint64(d.Inode),
    88  		off:     uint64(d.Offset),
    89  		namelen: uint32(len(d.Name)),
    90  		type_:   uint32(d.Type),
    91  	}
    92  
    93  	n += copy(buf[n:], (*[direntSize]byte)(unsafe.Pointer(&de))[:])
    94  
    95  	// Write the name afterward.
    96  	n += copy(buf[n:], d.Name)
    97  
    98  	// Add any necessary padding.
    99  	if padLen != 0 {
   100  		var padding [direntAlignment]byte
   101  		n += copy(buf[n:], padding[:padLen])
   102  	}
   103  
   104  	return n
   105  }