fusego/fuseutil/dirent.go

106 lines
3.0 KiB
Go

// Copyright 2015 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package fuseutil
import (
"syscall"
"unsafe"
"github.com/jacobsa/fuse/fuseops"
)
type DirentType uint32
const (
DT_Unknown DirentType = 0
DT_Socket DirentType = syscall.DT_SOCK
DT_Link DirentType = syscall.DT_LNK
DT_File DirentType = syscall.DT_REG
DT_Block DirentType = syscall.DT_BLK
DT_Directory DirentType = syscall.DT_DIR
DT_Char DirentType = syscall.DT_CHR
DT_FIFO DirentType = syscall.DT_FIFO
)
// A struct representing an entry within a directory file, describing a child.
// See notes on fuseops.ReadDirOp and on WriteDirent for details.
type Dirent struct {
// The (opaque) offset within the directory file of the entry following this
// one. See notes on fuseops.ReadDirOp.Offset for details.
Offset fuseops.DirOffset
// The inode of the child file or directory, and its name within the parent.
Inode fuseops.InodeID
Name string
// The type of the child. The zero value (DT_Unknown) is legal, but means
// that the kernel will need to call GetAttr when the type is needed.
Type DirentType
}
// Write the supplied directory entry intto the given buffer in the format
// expected in fuseops.ReadFileOp.Data, returning the number of bytes written.
// Return zero if the entry would not fit.
func WriteDirent(buf []byte, d Dirent) (n int) {
// We want to write bytes with the layout of fuse_dirent
// (http://goo.gl/BmFxob) in host order. The struct must be aligned according
// to FUSE_DIRENT_ALIGN (http://goo.gl/UziWvH), which dictates 8-byte
// alignment.
type fuse_dirent struct {
ino uint64
off uint64
namelen uint32
type_ uint32
name [0]byte
}
const direntAlignment = 8
const direntSize = 8 + 8 + 4 + 4
// Compute the number of bytes of padding we'll need to maintain alignment
// for the next entry.
var padLen int
if len(d.Name)%direntAlignment != 0 {
padLen = direntAlignment - (len(d.Name) % direntAlignment)
}
// Do we have enough room?
totalLen := direntSize + len(d.Name) + padLen
if totalLen > len(buf) {
return n
}
// Write the header.
de := fuse_dirent{
ino: uint64(d.Inode),
off: uint64(d.Offset),
namelen: uint32(len(d.Name)),
type_: uint32(d.Type),
}
n += copy(buf[n:], (*[direntSize]byte)(unsafe.Pointer(&de))[:])
// Write the name afterward.
n += copy(buf[n:], d.Name)
// Add any necessary padding.
if padLen != 0 {
var padding [direntAlignment]byte
n += copy(buf[n:], padding[:padLen])
}
return n
}