1 Star 0 Fork 0

huangsg / rsc

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
fuse.go 41.35 KB
一键复制 编辑 原始数据 按行查看 历史
huangsg 提交于 2020-03-01 20:37 . 初始化代码
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650
// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Adapted from Plan 9 from User Space's src/cmd/9pfuse/fuse.c,
// which carries this notice:
//
// The files in this directory are subject to the following license.
//
// The author of this software is Russ Cox.
//
// Copyright (c) 2006 Russ Cox
//
// Permission to use, copy, modify, and distribute this software for any
// purpose without fee is hereby granted, provided that this entire notice
// is included in all copies of any software which is or includes a copy
// or modification of this software and in all copies of the supporting
// documentation for such software.
//
// THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
// WARRANTY. IN PARTICULAR, THE AUTHOR MAKES NO REPRESENTATION OR WARRANTY
// OF ANY KIND CONCERNING THE MERCHANTABILITY OF THIS SOFTWARE OR ITS
// FITNESS FOR ANY PARTICULAR PURPOSE.
// Package fuse enables writing FUSE file systems on FreeBSD, Linux, and OS X.
//
// On OS X, it requires OSXFUSE (http://osxfuse.github.com/).
//
// There are two approaches to writing a FUSE file system. The first is to speak
// the low-level message protocol, reading from a Conn using ReadRequest and
// writing using the various Respond methods. This approach is closest to
// the actual interaction with the kernel and can be the simplest one in contexts
// such as protocol translators.
//
// Servers of synthesized file systems tend to share common bookkeeping
// abstracted away by the second approach, which is to call the Conn's
// Serve method to serve the FUSE protocol using
// an implementation of the service methods in the interfaces
// FS (file system), Node (file or directory), and Handle (opened file or directory).
// There are a daunting number of such methods that can be written,
// but few are required.
// The specific methods are described in the documentation for those interfaces.
//
// The hellofs subdirectory contains a simple illustration of the ServeFS approach.
//
// Service Methods
//
// The required and optional methods for the FS, Node, and Handle interfaces
// have the general form
//
// Op(req *OpRequest, resp *OpResponse, intr Intr) Error
//
// where Op is the name of a FUSE operation. Op reads request parameters
// from req and writes results to resp. An operation whose only result is
// the error result omits the resp parameter. Multiple goroutines may call
// service methods simultaneously; the methods being called are responsible
// for appropriate synchronization.
//
// Interrupted Operations
//
// In some file systems, some operations
// may take an undetermined amount of time. For example, a Read waiting for
// a network message or a matching Write might wait indefinitely. If the request
// is cancelled and no longer needed, the package will close intr, a chan struct{}.
// Blocking operations should select on a receive from intr and attempt to
// abort the operation early if the receive succeeds (meaning the channel is closed).
// To indicate that the operation failed because it was aborted, return fuse.EINTR.
//
// If an operation does not block for an indefinite amount of time, the intr parameter
// can be ignored.
//
// Authentication
//
// All requests types embed a Header, meaning that the method can inspect
// req.Pid, req.Uid, and req.Gid as necessary to implement permission checking.
// Alternately, XXX.
//
// Mount Options
//
// XXX
//
package fuse
// BUG(rsc): The mount code for FreeBSD has not been written yet.
import (
"bytes"
"errors"
"fmt"
"io"
"log"
"os"
"runtime"
"sync"
"syscall"
"time"
"unsafe"
)
// A Conn represents a connection to a mounted FUSE file system.
type Conn struct {
fd int
buf []byte
wio sync.Mutex
serveConn
}
// Mount mounts a new FUSE connection on the named directory
// and returns a connection for reading and writing FUSE messages.
func Mount(dir string) (*Conn, error) {
// TODO(rsc): mount options (...string?)
fd, errstr := mount(dir)
if errstr != "" {
return nil, errors.New(errstr)
}
return &Conn{fd: fd}, nil
}
// A Request represents a single FUSE request received from the kernel.
// Use a type switch to determine the specific kind.
// A request of unrecognized type will have concrete type *Header.
type Request interface {
// Hdr returns the Header associated with this request.
Hdr() *Header
// RespondError responds to the request with the given error.
RespondError(Error)
String() string
// handle returns the HandleID for the request, or 0.
handle() HandleID
}
// A RequestID identifies an active FUSE request.
type RequestID uint64
// A NodeID is a number identifying a directory or file.
// It must be unique among IDs returned in LookupResponses
// that have not yet been forgotten by ForgetRequests.
type NodeID uint64
// A HandleID is a number identifying an open directory or file.
// It only needs to be unique while the directory or file is open.
type HandleID uint64
// The RootID identifies the root directory of a FUSE file system.
const RootID NodeID = rootID
// A Header describes the basic information sent in every request.
type Header struct {
Conn *Conn // connection this request was received on
ID RequestID // unique ID for request
Node NodeID // file or directory the request is about
Uid uint32 // user ID of process making request
Gid uint32 // group ID of process making request
Pid uint32 // process ID of process making request
}
func (h *Header) String() string {
return fmt.Sprintf("ID=%#x Node=%#x Uid=%d Gid=%d Pid=%d", h.ID, h.Node, h.Uid, h.Gid, h.Pid)
}
func (h *Header) Hdr() *Header {
return h
}
func (h *Header) handle() HandleID {
return 0
}
// An Error is a FUSE error.
type Error interface {
errno() int32
}
const (
// ENOSYS indicates that the call is not supported.
ENOSYS = Errno(syscall.ENOSYS)
// ESTALE is used by Serve to respond to violations of the FUSE protocol.
ESTALE = Errno(syscall.ESTALE)
ENOENT = Errno(syscall.ENOENT)
EIO = Errno(syscall.EIO)
EPERM = Errno(syscall.EPERM)
)
type errno int
func (e errno) errno() int32 {
return int32(e)
}
// Errno implements Error using a syscall.Errno.
type Errno syscall.Errno
func (e Errno) errno() int32 {
return int32(e)
}
func (e Errno) String() string {
return syscall.Errno(e).Error()
}
func (h *Header) RespondError(err Error) {
// FUSE uses negative errors!
// TODO: File bug report against OSXFUSE: positive error causes kernel panic.
out := &outHeader{Error: -err.errno(), Unique: uint64(h.ID)}
h.Conn.respond(out, unsafe.Sizeof(*out))
}
var maxWrite = syscall.Getpagesize()
var bufSize = 4096 + maxWrite
// a message represents the bytes of a single FUSE message
type message struct {
conn *Conn
buf []byte // all bytes
hdr *inHeader // header
off int // offset for reading additional fields
}
func newMessage(c *Conn) *message {
m := &message{conn: c, buf: make([]byte, bufSize)}
m.hdr = (*inHeader)(unsafe.Pointer(&m.buf[0]))
return m
}
func (m *message) len() uintptr {
return uintptr(len(m.buf) - m.off)
}
func (m *message) data() unsafe.Pointer {
var p unsafe.Pointer
if m.off < len(m.buf) {
p = unsafe.Pointer(&m.buf[m.off])
}
return p
}
func (m *message) bytes() []byte {
return m.buf[m.off:]
}
func (m *message) Header() Header {
h := m.hdr
return Header{Conn: m.conn, ID: RequestID(h.Unique), Node: NodeID(h.Nodeid), Uid: h.Uid, Gid: h.Gid, Pid: h.Pid}
}
// fileMode returns a Go os.FileMode from a Unix mode.
func fileMode(unixMode uint32) os.FileMode {
mode := os.FileMode(unixMode & 0777)
switch unixMode & syscall.S_IFMT {
case syscall.S_IFREG:
// nothing
case syscall.S_IFDIR:
mode |= os.ModeDir
case syscall.S_IFCHR:
mode |= os.ModeCharDevice | os.ModeDevice
case syscall.S_IFBLK:
mode |= os.ModeDevice
case syscall.S_IFIFO:
mode |= os.ModeNamedPipe
case syscall.S_IFLNK:
mode |= os.ModeSymlink
case syscall.S_IFSOCK:
mode |= os.ModeSocket
default:
// no idea
mode |= os.ModeDevice
}
if unixMode&syscall.S_ISUID != 0 {
mode |= os.ModeSetuid
}
if unixMode&syscall.S_ISGID != 0 {
mode |= os.ModeSetgid
}
return mode
}
func (c *Conn) ReadRequest() (Request, error) {
// TODO: Some kind of buffer reuse.
m := newMessage(c)
n, err := syscall.Read(c.fd, m.buf)
if err != nil && err != syscall.ENODEV {
return nil, err
}
if n <= 0 {
return nil, io.EOF
}
m.buf = m.buf[:n]
if n < inHeaderSize {
return nil, errors.New("fuse: message too short")
}
// FreeBSD FUSE sends a short length in the header
// for FUSE_INIT even though the actual read length is correct.
if n == inHeaderSize+initInSize && m.hdr.Opcode == opInit && m.hdr.Len < uint32(n) {
m.hdr.Len = uint32(n)
}
// OSXFUSE sometimes sends the wrong m.hdr.Len in a FUSE_WRITE message.
if m.hdr.Len < uint32(n) && m.hdr.Len >= uint32(unsafe.Sizeof(writeIn{})) && m.hdr.Opcode == opWrite {
m.hdr.Len = uint32(n)
}
if m.hdr.Len != uint32(n) {
return nil, fmt.Errorf("fuse: read %d opcode %d but expected %d", n, m.hdr.Opcode, m.hdr.Len)
}
m.off = inHeaderSize
// Convert to data structures.
// Do not trust kernel to hand us well-formed data.
var req Request
switch m.hdr.Opcode {
default:
println("No opcode", m.hdr.Opcode)
goto unrecognized
case opLookup:
buf := m.bytes()
n := len(buf)
if n == 0 || buf[n-1] != '\x00' {
goto corrupt
}
req = &LookupRequest{
Header: m.Header(),
Name: string(buf[:n-1]),
}
case opForget:
in := (*forgetIn)(m.data())
if m.len() < unsafe.Sizeof(*in) {
goto corrupt
}
req = &ForgetRequest{
Header: m.Header(),
N: in.Nlookup,
}
case opGetattr:
req = &GetattrRequest{
Header: m.Header(),
}
case opSetattr:
in := (*setattrIn)(m.data())
if m.len() < unsafe.Sizeof(*in) {
goto corrupt
}
req = &SetattrRequest{
Header: m.Header(),
Valid: SetattrValid(in.Valid),
Handle: HandleID(in.Fh),
Size: in.Size,
Atime: time.Unix(int64(in.Atime), int64(in.AtimeNsec)),
Mtime: time.Unix(int64(in.Mtime), int64(in.MtimeNsec)),
Mode: fileMode(in.Mode),
Uid: in.Uid,
Gid: in.Gid,
Bkuptime: in.BkupTime(),
Chgtime: in.Chgtime(),
Flags: in.Flags(),
}
case opReadlink:
if len(m.bytes()) > 0 {
goto corrupt
}
req = &ReadlinkRequest{
Header: m.Header(),
}
case opSymlink:
// m.bytes() is "newName\0target\0"
names := m.bytes()
if len(names) == 0 || names[len(names)-1] != 0 {
goto corrupt
}
i := bytes.IndexByte(names, '\x00')
if i < 0 {
goto corrupt
}
newName, target := names[0:i], names[i+1:len(names)-1]
req = &SymlinkRequest{
Header: m.Header(),
NewName: string(newName),
Target: string(target),
}
case opLink:
in := (*linkIn)(m.data())
if m.len() < unsafe.Sizeof(*in) {
goto corrupt
}
newName := m.bytes()[unsafe.Sizeof(*in):]
if len(newName) < 2 || newName[len(newName)-1] != 0 {
goto corrupt
}
newName = newName[:len(newName)-1]
req = &LinkRequest{
Header: m.Header(),
OldNode: NodeID(in.Oldnodeid),
NewName: string(newName),
}
case opMknod:
in := (*mknodIn)(m.data())
if m.len() < unsafe.Sizeof(*in) {
goto corrupt
}
name := m.bytes()[unsafe.Sizeof(*in):]
if len(name) < 2 || name[len(name)-1] != '\x00' {
goto corrupt
}
name = name[:len(name)-1]
req = &MknodRequest{
Header: m.Header(),
Mode: fileMode(in.Mode),
Rdev: in.Rdev,
Name: string(name),
}
case opMkdir:
in := (*mkdirIn)(m.data())
if m.len() < unsafe.Sizeof(*in) {
goto corrupt
}
name := m.bytes()[unsafe.Sizeof(*in):]
i := bytes.IndexByte(name, '\x00')
if i < 0 {
goto corrupt
}
req = &MkdirRequest{
Header: m.Header(),
Name: string(name[:i]),
Mode: fileMode(in.Mode) | os.ModeDir,
}
case opUnlink, opRmdir:
buf := m.bytes()
n := len(buf)
if n == 0 || buf[n-1] != '\x00' {
goto corrupt
}
req = &RemoveRequest{
Header: m.Header(),
Name: string(buf[:n-1]),
Dir: m.hdr.Opcode == opRmdir,
}
case opRename:
in := (*renameIn)(m.data())
if m.len() < unsafe.Sizeof(*in) {
goto corrupt
}
newDirNodeID := NodeID(in.Newdir)
oldNew := m.bytes()[unsafe.Sizeof(*in):]
// oldNew should be "old\x00new\x00"
if len(oldNew) < 4 {
goto corrupt
}
if oldNew[len(oldNew)-1] != '\x00' {
goto corrupt
}
i := bytes.IndexByte(oldNew, '\x00')
if i < 0 {
goto corrupt
}
oldName, newName := string(oldNew[:i]), string(oldNew[i+1:len(oldNew)-1])
// log.Printf("RENAME: newDirNode = %d; old = %q, new = %q", newDirNodeID, oldName, newName)
req = &RenameRequest{
Header: m.Header(),
NewDir: newDirNodeID,
OldName: oldName,
NewName: newName,
}
case opOpendir, opOpen:
in := (*openIn)(m.data())
if m.len() < unsafe.Sizeof(*in) {
goto corrupt
}
req = &OpenRequest{
Header: m.Header(),
Dir: m.hdr.Opcode == opOpendir,
Flags: in.Flags,
Mode: fileMode(in.Mode),
}
case opRead, opReaddir:
in := (*readIn)(m.data())
if m.len() < unsafe.Sizeof(*in) {
goto corrupt
}
req = &ReadRequest{
Header: m.Header(),
Dir: m.hdr.Opcode == opReaddir,
Handle: HandleID(in.Fh),
Offset: int64(in.Offset),
Size: int(in.Size),
}
case opWrite:
in := (*writeIn)(m.data())
if m.len() < unsafe.Sizeof(*in) {
goto corrupt
}
r := &WriteRequest{
Header: m.Header(),
Handle: HandleID(in.Fh),
Offset: int64(in.Offset),
Flags: WriteFlags(in.WriteFlags),
}
buf := m.bytes()[unsafe.Sizeof(*in):]
if uint32(len(buf)) < in.Size {
goto corrupt
}
r.Data = buf
req = r
case opStatfs:
req = &StatfsRequest{
Header: m.Header(),
}
case opRelease, opReleasedir:
in := (*releaseIn)(m.data())
if m.len() < unsafe.Sizeof(*in) {
goto corrupt
}
req = &ReleaseRequest{
Header: m.Header(),
Dir: m.hdr.Opcode == opReleasedir,
Handle: HandleID(in.Fh),
Flags: in.Flags,
ReleaseFlags: ReleaseFlags(in.ReleaseFlags),
LockOwner: in.LockOwner,
}
case opFsync:
in := (*fsyncIn)(m.data())
if m.len() < unsafe.Sizeof(*in) {
goto corrupt
}
req = &FsyncRequest{
Header: m.Header(),
Handle: HandleID(in.Fh),
Flags: in.FsyncFlags,
}
case opSetxattr:
var size uint32
var r *SetxattrRequest
if runtime.GOOS == "darwin" {
in := (*setxattrInOSX)(m.data())
if m.len() < unsafe.Sizeof(*in) {
goto corrupt
}
r = &SetxattrRequest{
Flags: in.Flags,
Position: in.Position,
}
size = in.Size
m.off += int(unsafe.Sizeof(*in))
} else {
in := (*setxattrIn)(m.data())
if m.len() < unsafe.Sizeof(*in) {
goto corrupt
}
r = &SetxattrRequest{}
size = in.Size
m.off += int(unsafe.Sizeof(*in))
}
r.Header = m.Header()
name := m.bytes()
i := bytes.IndexByte(name, '\x00')
if i < 0 {
goto corrupt
}
r.Name = string(name[:i])
r.Xattr = name[i+1:]
if uint32(len(r.Xattr)) < size {
goto corrupt
}
r.Xattr = r.Xattr[:size]
req = r
case opGetxattr:
if runtime.GOOS == "darwin" {
in := (*getxattrInOSX)(m.data())
if m.len() < unsafe.Sizeof(*in) {
goto corrupt
}
req = &GetxattrRequest{
Header: m.Header(),
Size: in.Size,
Position: in.Position,
}
} else {
in := (*getxattrIn)(m.data())
if m.len() < unsafe.Sizeof(*in) {
goto corrupt
}
req = &GetxattrRequest{
Header: m.Header(),
Size: in.Size,
}
}
case opListxattr:
if runtime.GOOS == "darwin" {
in := (*getxattrInOSX)(m.data())
if m.len() < unsafe.Sizeof(*in) {
goto corrupt
}
req = &ListxattrRequest{
Header: m.Header(),
Size: in.Size,
Position: in.Position,
}
} else {
in := (*getxattrIn)(m.data())
if m.len() < unsafe.Sizeof(*in) {
goto corrupt
}
req = &ListxattrRequest{
Header: m.Header(),
Size: in.Size,
}
}
case opRemovexattr:
buf := m.bytes()
n := len(buf)
if n == 0 || buf[n-1] != '\x00' {
goto corrupt
}
req = &RemovexattrRequest{
Header: m.Header(),
Name: string(buf[:n-1]),
}
case opFlush:
in := (*flushIn)(m.data())
if m.len() < unsafe.Sizeof(*in) {
goto corrupt
}
req = &FlushRequest{
Header: m.Header(),
Handle: HandleID(in.Fh),
Flags: in.FlushFlags,
LockOwner: in.LockOwner,
}
case opInit:
in := (*initIn)(m.data())
if m.len() < unsafe.Sizeof(*in) {
goto corrupt
}
req = &InitRequest{
Header: m.Header(),
Major: in.Major,
Minor: in.Minor,
MaxReadahead: in.MaxReadahead,
Flags: InitFlags(in.Flags),
}
case opFsyncdir:
panic("opFsyncdir")
case opGetlk:
panic("opGetlk")
case opSetlk:
panic("opSetlk")
case opSetlkw:
panic("opSetlkw")
case opAccess:
in := (*accessIn)(m.data())
if m.len() < unsafe.Sizeof(*in) {
goto corrupt
}
req = &AccessRequest{
Header: m.Header(),
Mask: in.Mask,
}
case opCreate:
in := (*openIn)(m.data())
if m.len() < unsafe.Sizeof(*in) {
goto corrupt
}
name := m.bytes()[unsafe.Sizeof(*in):]
i := bytes.IndexByte(name, '\x00')
if i < 0 {
goto corrupt
}
req = &CreateRequest{
Header: m.Header(),
Flags: in.Flags,
Mode: fileMode(in.Mode),
Name: string(name[:i]),
}
case opInterrupt:
panic("opInterrupt")
case opBmap:
panic("opBmap")
case opDestroy:
req = &DestroyRequest{
Header: m.Header(),
}
// OS X
case opSetvolname:
panic("opSetvolname")
case opGetxtimes:
panic("opGetxtimes")
case opExchange:
panic("opExchange")
}
return req, nil
corrupt:
println("malformed message")
return nil, fmt.Errorf("fuse: malformed message")
unrecognized:
// Unrecognized message.
// Assume higher-level code will send a "no idea what you mean" error.
h := m.Header()
return &h, nil
}
func (c *Conn) respond(out *outHeader, n uintptr) {
c.wio.Lock()
defer c.wio.Unlock()
out.Len = uint32(n)
msg := (*[1 << 30]byte)(unsafe.Pointer(out))[:n]
nn, err := syscall.Write(c.fd, msg)
if nn != len(msg) || err != nil {
log.Printf("RESPOND WRITE: %d %v", nn, err)
log.Printf("with stack: %s", stack())
}
}
func (c *Conn) respondData(out *outHeader, n uintptr, data []byte) {
c.wio.Lock()
defer c.wio.Unlock()
// TODO: use writev
out.Len = uint32(n + uintptr(len(data)))
msg := make([]byte, out.Len)
copy(msg, (*[1 << 30]byte)(unsafe.Pointer(out))[:n])
copy(msg[n:], data)
syscall.Write(c.fd, msg)
}
// An InitRequest is the first request sent on a FUSE file system.
type InitRequest struct {
Header
Major uint32
Minor uint32
MaxReadahead uint32
Flags InitFlags
}
func (r *InitRequest) String() string {
return fmt.Sprintf("Init [%s] %d.%d ra=%d fl=%v", &r.Header, r.Major, r.Minor, r.MaxReadahead, r.Flags)
}
// An InitResponse is the response to an InitRequest.
type InitResponse struct {
MaxReadahead uint32
Flags InitFlags
MaxWrite uint32
}
func (r *InitResponse) String() string {
return fmt.Sprintf("Init %+v", *r)
}
// Respond replies to the request with the given response.
func (r *InitRequest) Respond(resp *InitResponse) {
out := &initOut{
outHeader: outHeader{Unique: uint64(r.ID)},
Major: kernelVersion,
Minor: kernelMinorVersion,
MaxReadahead: resp.MaxReadahead,
Flags: uint32(resp.Flags),
MaxWrite: resp.MaxWrite,
}
r.Conn.respond(&out.outHeader, unsafe.Sizeof(*out))
}
// A StatfsRequest requests information about the mounted file system.
type StatfsRequest struct {
Header
}
func (r *StatfsRequest) String() string {
return fmt.Sprintf("Statfs [%s]\n", &r.Header)
}
// Respond replies to the request with the given response.
func (r *StatfsRequest) Respond(resp *StatfsResponse) {
out := &statfsOut{
outHeader: outHeader{Unique: uint64(r.ID)},
St: kstatfs{
Blocks: resp.Blocks,
Bfree: resp.Bfree,
Bavail: resp.Bavail,
Files: resp.Files,
Bsize: resp.Bsize,
Namelen: resp.Namelen,
Frsize: resp.Frsize,
},
}
r.Conn.respond(&out.outHeader, unsafe.Sizeof(*out))
}
// A StatfsResponse is the response to a StatfsRequest.
type StatfsResponse struct {
Blocks uint64 // Total data blocks in file system.
Bfree uint64 // Free blocks in file system.
Bavail uint64 // Free blocks in file system if you're not root.
Files uint64 // Total files in file system.
Ffree uint64 // Free files in file system.
Bsize uint32 // Block size
Namelen uint32 // Maximum file name length?
Frsize uint32 // ?
}
func (r *StatfsResponse) String() string {
return fmt.Sprintf("Statfs %+v", *r)
}
// An AccessRequest asks whether the file can be accessed
// for the purpose specified by the mask.
type AccessRequest struct {
Header
Mask uint32
}
func (r *AccessRequest) String() string {
return fmt.Sprintf("Access [%s] mask=%#x", &r.Header, r.Mask)
}
// Respond replies to the request indicating that access is allowed.
// To deny access, use RespondError.
func (r *AccessRequest) Respond() {
out := &outHeader{Unique: uint64(r.ID)}
r.Conn.respond(out, unsafe.Sizeof(*out))
}
// An Attr is the metadata for a single file or directory.
type Attr struct {
Inode uint64 // inode number
Size uint64 // size in bytes
Blocks uint64 // size in blocks
Atime time.Time // time of last access
Mtime time.Time // time of last modification
Ctime time.Time // time of last inode change
Crtime time.Time // time of creation (OS X only)
Mode os.FileMode // file mode
Nlink uint32 // number of links
Uid uint32 // owner uid
Gid uint32 // group gid
Rdev uint32 // device numbers
Flags uint32 // chflags(2) flags (OS X only)
}
func unix(t time.Time) (sec uint64, nsec uint32) {
nano := t.UnixNano()
sec = uint64(nano / 1e9)
nsec = uint32(nano % 1e9)
return
}
func (a *Attr) attr() (out attr) {
out.Ino = a.Inode
out.Size = a.Size
out.Blocks = a.Blocks
out.Atime, out.AtimeNsec = unix(a.Atime)
out.Mtime, out.MtimeNsec = unix(a.Mtime)
out.Ctime, out.CtimeNsec = unix(a.Ctime)
out.SetCrtime(unix(a.Crtime))
out.Mode = uint32(a.Mode) & 0777
switch {
default:
out.Mode |= syscall.S_IFREG
case a.Mode&os.ModeDir != 0:
out.Mode |= syscall.S_IFDIR
case a.Mode&os.ModeDevice != 0:
if a.Mode&os.ModeCharDevice != 0 {
out.Mode |= syscall.S_IFCHR
} else {
out.Mode |= syscall.S_IFBLK
}
case a.Mode&os.ModeNamedPipe != 0:
out.Mode |= syscall.S_IFIFO
case a.Mode&os.ModeSymlink != 0:
out.Mode |= syscall.S_IFLNK
case a.Mode&os.ModeSocket != 0:
out.Mode |= syscall.S_IFSOCK
}
if a.Mode&os.ModeSetuid != 0 {
out.Mode |= syscall.S_ISUID
}
if a.Mode&os.ModeSetgid != 0 {
out.Mode |= syscall.S_ISGID
}
out.Nlink = a.Nlink
if out.Nlink < 1 {
out.Nlink = 1
}
out.Uid = a.Uid
out.Gid = a.Gid
out.Rdev = a.Rdev
out.SetFlags(a.Flags)
return
}
// A GetattrRequest asks for the metadata for the file denoted by r.Node.
type GetattrRequest struct {
Header
}
func (r *GetattrRequest) String() string {
return fmt.Sprintf("Getattr [%s]", &r.Header)
}
// Respond replies to the request with the given response.
func (r *GetattrRequest) Respond(resp *GetattrResponse) {
out := &attrOut{
outHeader: outHeader{Unique: uint64(r.ID)},
AttrValid: uint64(resp.AttrValid / time.Second),
AttrValidNsec: uint32(resp.AttrValid % time.Second / time.Nanosecond),
Attr: resp.Attr.attr(),
}
r.Conn.respond(&out.outHeader, unsafe.Sizeof(*out))
}
// A GetattrResponse is the response to a GetattrRequest.
type GetattrResponse struct {
AttrValid time.Duration // how long Attr can be cached
Attr Attr // file attributes
}
func (r *GetattrResponse) String() string {
return fmt.Sprintf("Getattr %+v", *r)
}
// A GetxattrRequest asks for the extended attributes associated with r.Node.
type GetxattrRequest struct {
Header
Size uint32 // maximum size to return
Position uint32 // offset within extended attributes
}
func (r *GetxattrRequest) String() string {
return fmt.Sprintf("Getxattr [%s] %d @%d", &r.Header, r.Size, r.Position)
}
// Respond replies to the request with the given response.
func (r *GetxattrRequest) Respond(resp *GetxattrResponse) {
out := &getxattrOut{
outHeader: outHeader{Unique: uint64(r.ID)},
Size: uint32(len(resp.Xattr)),
}
r.Conn.respondData(&out.outHeader, unsafe.Sizeof(*out), resp.Xattr)
}
// A GetxattrResponse is the response to a GetxattrRequest.
type GetxattrResponse struct {
Xattr []byte
}
func (r *GetxattrResponse) String() string {
return fmt.Sprintf("Getxattr %x", r.Xattr)
}
// A ListxattrRequest asks to list the extended attributes associated with r.Node.
type ListxattrRequest struct {
Header
Size uint32 // maximum size to return
Position uint32 // offset within attribute list
}
func (r *ListxattrRequest) String() string {
return fmt.Sprintf("Listxattr [%s] %d @%d", &r.Header, r.Size, r.Position)
}
// Respond replies to the request with the given response.
func (r *ListxattrRequest) Respond(resp *ListxattrResponse) {
out := &getxattrOut{
outHeader: outHeader{Unique: uint64(r.ID)},
Size: uint32(len(resp.Xattr)),
}
r.Conn.respondData(&out.outHeader, unsafe.Sizeof(*out), resp.Xattr)
}
// A ListxattrResponse is the response to a ListxattrRequest.
type ListxattrResponse struct {
Xattr []byte
}
func (r *ListxattrResponse) String() string {
return fmt.Sprintf("Listxattr %x", r.Xattr)
}
// A RemovexattrRequest asks to remove an extended attribute associated with r.Node.
type RemovexattrRequest struct {
Header
Name string // name of extended attribute
}
func (r *RemovexattrRequest) String() string {
return fmt.Sprintf("Removexattr [%s] %q", &r.Header, r.Name)
}
// Respond replies to the request, indicating that the attribute was removed.
func (r *RemovexattrRequest) Respond() {
out := &outHeader{Unique: uint64(r.ID)}
r.Conn.respond(out, unsafe.Sizeof(*out))
}
// A SetxattrRequest asks to set an extended attribute associated with a file.
type SetxattrRequest struct {
Header
Flags uint32
Position uint32 // OS X only
Name string
Xattr []byte
}
func (r *SetxattrRequest) String() string {
return fmt.Sprintf("Setxattr [%s] %q %x fl=%v @%#x", &r.Header, r.Name, r.Xattr, r.Flags, r.Position)
}
// Respond replies to the request, indicating that the extended attribute was set.
func (r *SetxattrRequest) Respond() {
out := &outHeader{Unique: uint64(r.ID)}
r.Conn.respond(out, unsafe.Sizeof(*out))
}
// A LookupRequest asks to look up the given name in the directory named by r.Node.
type LookupRequest struct {
Header
Name string
}
func (r *LookupRequest) String() string {
return fmt.Sprintf("Lookup [%s] %q", &r.Header, r.Name)
}
// Respond replies to the request with the given response.
func (r *LookupRequest) Respond(resp *LookupResponse) {
out := &entryOut{
outHeader: outHeader{Unique: uint64(r.ID)},
Nodeid: uint64(resp.Node),
Generation: resp.Generation,
EntryValid: uint64(resp.EntryValid / time.Second),
EntryValidNsec: uint32(resp.EntryValid % time.Second / time.Nanosecond),
AttrValid: uint64(resp.AttrValid / time.Second),
AttrValidNsec: uint32(resp.AttrValid % time.Second / time.Nanosecond),
Attr: resp.Attr.attr(),
}
r.Conn.respond(&out.outHeader, unsafe.Sizeof(*out))
}
// A LookupResponse is the response to a LookupRequest.
type LookupResponse struct {
Node NodeID
Generation uint64
EntryValid time.Duration
AttrValid time.Duration
Attr Attr
}
func (r *LookupResponse) String() string {
return fmt.Sprintf("Lookup %+v", *r)
}
// An OpenRequest asks to open a file or directory
type OpenRequest struct {
Header
Dir bool // is this Opendir?
Flags uint32
Mode os.FileMode
}
func (r *OpenRequest) String() string {
return fmt.Sprintf("Open [%s] dir=%v fl=%v mode=%v", &r.Header, r.Dir, r.Flags, r.Mode)
}
// Respond replies to the request with the given response.
func (r *OpenRequest) Respond(resp *OpenResponse) {
out := &openOut{
outHeader: outHeader{Unique: uint64(r.ID)},
Fh: uint64(resp.Handle),
OpenFlags: uint32(resp.Flags),
}
r.Conn.respond(&out.outHeader, unsafe.Sizeof(*out))
}
// A OpenResponse is the response to a OpenRequest.
type OpenResponse struct {
Handle HandleID
Flags OpenFlags
}
func (r *OpenResponse) String() string {
return fmt.Sprintf("Open %+v", *r)
}
// A CreateRequest asks to create and open a file (not a directory).
type CreateRequest struct {
Header
Name string
Flags uint32
Mode os.FileMode
}
func (r *CreateRequest) String() string {
return fmt.Sprintf("Create [%s] %q fl=%v mode=%v", &r.Header, r.Name, r.Flags, r.Mode)
}
// Respond replies to the request with the given response.
func (r *CreateRequest) Respond(resp *CreateResponse) {
out := &createOut{
outHeader: outHeader{Unique: uint64(r.ID)},
Nodeid: uint64(resp.Node),
Generation: resp.Generation,
EntryValid: uint64(resp.EntryValid / time.Second),
EntryValidNsec: uint32(resp.EntryValid % time.Second / time.Nanosecond),
AttrValid: uint64(resp.AttrValid / time.Second),
AttrValidNsec: uint32(resp.AttrValid % time.Second / time.Nanosecond),
Attr: resp.Attr.attr(),
Fh: uint64(resp.Handle),
OpenFlags: uint32(resp.Flags),
}
r.Conn.respond(&out.outHeader, unsafe.Sizeof(*out))
}
// A CreateResponse is the response to a CreateRequest.
// It describes the created node and opened handle.
type CreateResponse struct {
LookupResponse
OpenResponse
}
func (r *CreateResponse) String() string {
return fmt.Sprintf("Create %+v", *r)
}
// A MkdirRequest asks to create (but not open) a directory.
type MkdirRequest struct {
Header
Name string
Mode os.FileMode
}
func (r *MkdirRequest) String() string {
return fmt.Sprintf("Mkdir [%s] %q mode=%v", &r.Header, r.Name, r.Mode)
}
// Respond replies to the request with the given response.
func (r *MkdirRequest) Respond(resp *MkdirResponse) {
out := &entryOut{
outHeader: outHeader{Unique: uint64(r.ID)},
Nodeid: uint64(resp.Node),
Generation: resp.Generation,
EntryValid: uint64(resp.EntryValid / time.Second),
EntryValidNsec: uint32(resp.EntryValid % time.Second / time.Nanosecond),
AttrValid: uint64(resp.AttrValid / time.Second),
AttrValidNsec: uint32(resp.AttrValid % time.Second / time.Nanosecond),
Attr: resp.Attr.attr(),
}
r.Conn.respond(&out.outHeader, unsafe.Sizeof(*out))
}
// A MkdirResponse is the response to a MkdirRequest.
type MkdirResponse struct {
LookupResponse
}
func (r *MkdirResponse) String() string {
return fmt.Sprintf("Mkdir %+v", *r)
}
// A ReadRequest asks to read from an open file.
type ReadRequest struct {
Header
Dir bool // is this Readdir?
Handle HandleID
Offset int64
Size int
}
func (r *ReadRequest) handle() HandleID {
return r.Handle
}
func (r *ReadRequest) String() string {
return fmt.Sprintf("Read [%s] %#x %d @%#x dir=%v", &r.Header, r.Handle, r.Size, r.Offset, r.Dir)
}
// Respond replies to the request with the given response.
func (r *ReadRequest) Respond(resp *ReadResponse) {
out := &outHeader{Unique: uint64(r.ID)}
r.Conn.respondData(out, unsafe.Sizeof(*out), resp.Data)
}
// A ReadResponse is the response to a ReadRequest.
type ReadResponse struct {
Data []byte
}
func (r *ReadResponse) String() string {
return fmt.Sprintf("Read %x", r.Data)
}
// A ReleaseRequest asks to release (close) an open file handle.
type ReleaseRequest struct {
Header
Dir bool // is this Releasedir?
Handle HandleID
Flags uint32 // flags from OpenRequest
ReleaseFlags ReleaseFlags
LockOwner uint32
}
func (r *ReleaseRequest) handle() HandleID {
return r.Handle
}
func (r *ReleaseRequest) String() string {
return fmt.Sprintf("Release [%s] %#x fl=%v rfl=%v owner=%#x", &r.Header, r.Handle, r.Flags, r.ReleaseFlags, r.LockOwner)
}
// Respond replies to the request, indicating that the handle has been released.
func (r *ReleaseRequest) Respond() {
out := &outHeader{Unique: uint64(r.ID)}
r.Conn.respond(out, unsafe.Sizeof(*out))
}
// A DestroyRequest is sent by the kernel when unmounting the file system.
// No more requests will be received after this one, but it should still be
// responded to.
type DestroyRequest struct {
Header
}
func (r *DestroyRequest) String() string {
return fmt.Sprintf("Destroy [%s]", &r.Header)
}
// Respond replies to the request.
func (r *DestroyRequest) Respond() {
out := &outHeader{Unique: uint64(r.ID)}
r.Conn.respond(out, unsafe.Sizeof(*out))
}
// A ForgetRequest is sent by the kernel when forgetting about r.Node
// as returned by r.N lookup requests.
type ForgetRequest struct {
Header
N uint64
}
func (r *ForgetRequest) String() string {
return fmt.Sprintf("Forget [%s] %d", &r.Header, r.N)
}
// Respond replies to the request, indicating that the forgetfulness has been recorded.
func (r *ForgetRequest) Respond() {
// Don't reply to forget messages.
}
// A Dirent represents a single directory entry.
type Dirent struct {
Inode uint64 // inode this entry names
Type uint32 // ?
Name string // name of entry
}
// AppendDirent appends the encoded form of a directory entry to data
// and returns the resulting slice.
func AppendDirent(data []byte, dir Dirent) []byte {
de := dirent{
Ino: dir.Inode,
Namelen: uint32(len(dir.Name)),
Type: dir.Type,
}
de.Off = uint64(len(data) + direntSize + (len(dir.Name)+7)&^7)
data = append(data, (*[direntSize]byte)(unsafe.Pointer(&de))[:]...)
data = append(data, dir.Name...)
n := direntSize + uintptr(len(dir.Name))
if n%8 != 0 {
var pad [8]byte
data = append(data, pad[:8-n%8]...)
}
return data
}
// A WriteRequest asks to write to an open file.
type WriteRequest struct {
Header
Handle HandleID
Offset int64
Data []byte
Flags WriteFlags
}
func (r *WriteRequest) String() string {
return fmt.Sprintf("Write [%s] %#x %d @%d fl=%v", &r.Header, r.Handle, len(r.Data), r.Offset, r.Flags)
}
// Respond replies to the request with the given response.
func (r *WriteRequest) Respond(resp *WriteResponse) {
out := &writeOut{
outHeader: outHeader{Unique: uint64(r.ID)},
Size: uint32(resp.Size),
}
r.Conn.respond(&out.outHeader, unsafe.Sizeof(*out))
}
func (r *WriteRequest) handle() HandleID {
return r.Handle
}
// A WriteResponse replies to a write indicating how many bytes were written.
type WriteResponse struct {
Size int
}
func (r *WriteResponse) String() string {
return fmt.Sprintf("Write %+v", *r)
}
// A SetattrRequest asks to change one or more attributes associated with a file,
// as indicated by Valid.
type SetattrRequest struct {
Header
Valid SetattrValid
Handle HandleID
Size uint64
Atime time.Time
Mtime time.Time
Mode os.FileMode
Uid uint32
Gid uint32
// OS X only
Bkuptime time.Time
Chgtime time.Time
Crtime time.Time
Flags uint32 // see chflags(2)
}
func (r *SetattrRequest) String() string {
var buf bytes.Buffer
fmt.Fprintf(&buf, "Setattr [%s]", &r.Header)
if r.Valid.Mode() {
fmt.Fprintf(&buf, " mode=%v", r.Mode)
}
if r.Valid.Uid() {
fmt.Fprintf(&buf, " uid=%d", r.Uid)
}
if r.Valid.Gid() {
fmt.Fprintf(&buf, " gid=%d", r.Gid)
}
if r.Valid.Size() {
fmt.Fprintf(&buf, " size=%d", r.Size)
}
if r.Valid.Atime() {
fmt.Fprintf(&buf, " atime=%v", r.Atime)
}
if r.Valid.Mtime() {
fmt.Fprintf(&buf, " mtime=%v", r.Mtime)
}
if r.Valid.Handle() {
fmt.Fprintf(&buf, " handle=%#x", r.Handle)
} else {
fmt.Fprintf(&buf, " handle=INVALID-%#x", r.Handle)
}
if r.Valid.Crtime() {
fmt.Fprintf(&buf, " crtime=%v", r.Crtime)
}
if r.Valid.Chgtime() {
fmt.Fprintf(&buf, " chgtime=%v", r.Chgtime)
}
if r.Valid.Bkuptime() {
fmt.Fprintf(&buf, " bkuptime=%v", r.Bkuptime)
}
if r.Valid.Flags() {
fmt.Fprintf(&buf, " flags=%#x", r.Flags)
}
return buf.String()
}
func (r *SetattrRequest) handle() HandleID {
if r.Valid.Handle() {
return r.Handle
}
return 0
}
// Respond replies to the request with the given response,
// giving the updated attributes.
func (r *SetattrRequest) Respond(resp *SetattrResponse) {
out := &attrOut{
outHeader: outHeader{Unique: uint64(r.ID)},
AttrValid: uint64(resp.AttrValid / time.Second),
AttrValidNsec: uint32(resp.AttrValid % time.Second / time.Nanosecond),
Attr: resp.Attr.attr(),
}
r.Conn.respond(&out.outHeader, unsafe.Sizeof(*out))
}
// A SetattrResponse is the response to a SetattrRequest.
type SetattrResponse struct {
AttrValid time.Duration // how long Attr can be cached
Attr Attr // file attributes
}
func (r *SetattrResponse) String() string {
return fmt.Sprintf("Setattr %+v", *r)
}
// A FlushRequest asks for the current state of an open file to be flushed
// to storage, as when a file descriptor is being closed. A single opened Handle
// may receive multiple FlushRequests over its lifetime.
type FlushRequest struct {
Header
Handle HandleID
Flags uint32
LockOwner uint64
}
func (r *FlushRequest) String() string {
return fmt.Sprintf("Flush [%s] %#x fl=%#x lk=%#x", &r.Header, r.Handle, r.Flags, r.LockOwner)
}
func (r *FlushRequest) handle() HandleID {
return r.Handle
}
// Respond replies to the request, indicating that the flush succeeded.
func (r *FlushRequest) Respond() {
out := &outHeader{Unique: uint64(r.ID)}
r.Conn.respond(out, unsafe.Sizeof(*out))
}
// A RemoveRequest asks to remove a file or directory.
type RemoveRequest struct {
Header
Name string // name of extended attribute
Dir bool // is this rmdir?
}
func (r *RemoveRequest) String() string {
return fmt.Sprintf("Remove [%s] %q dir=%v", &r.Header, r.Name, r.Dir)
}
// Respond replies to the request, indicating that the file was removed.
func (r *RemoveRequest) Respond() {
out := &outHeader{Unique: uint64(r.ID)}
r.Conn.respond(out, unsafe.Sizeof(*out))
}
// A SymlinkRequest is a request to create a symlink making NewName point to Target.
type SymlinkRequest struct {
Header
NewName, Target string
}
func (r *SymlinkRequest) String() string {
return fmt.Sprintf("Symlink [%s] from %q to target %q", &r.Header, r.NewName, r.Target)
}
func (r *SymlinkRequest) handle() HandleID {
return 0
}
// Respond replies to the request, indicating that the symlink was created.
func (r *SymlinkRequest) Respond(resp *SymlinkResponse) {
out := &entryOut{
outHeader: outHeader{Unique: uint64(r.ID)},
Nodeid: uint64(resp.Node),
Generation: resp.Generation,
EntryValid: uint64(resp.EntryValid / time.Second),
EntryValidNsec: uint32(resp.EntryValid % time.Second / time.Nanosecond),
AttrValid: uint64(resp.AttrValid / time.Second),
AttrValidNsec: uint32(resp.AttrValid % time.Second / time.Nanosecond),
Attr: resp.Attr.attr(),
}
r.Conn.respond(&out.outHeader, unsafe.Sizeof(*out))
}
// A SymlinkResponse is the response to a SymlinkRequest.
type SymlinkResponse struct {
LookupResponse
}
// A ReadlinkRequest is a request to read a symlink's target.
type ReadlinkRequest struct {
Header
}
func (r *ReadlinkRequest) String() string {
return fmt.Sprintf("Readlink [%s]", &r.Header)
}
func (r *ReadlinkRequest) handle() HandleID {
return 0
}
func (r *ReadlinkRequest) Respond(target string) {
out := &outHeader{Unique: uint64(r.ID)}
r.Conn.respondData(out, unsafe.Sizeof(*out), []byte(target))
}
// A LinkRequest is a request to create a hard link.
type LinkRequest struct {
Header
OldNode NodeID
NewName string
}
func (r *LinkRequest) Respond(resp *LookupResponse) {
out := &entryOut{
outHeader: outHeader{Unique: uint64(r.ID)},
Nodeid: uint64(resp.Node),
Generation: resp.Generation,
EntryValid: uint64(resp.EntryValid / time.Second),
EntryValidNsec: uint32(resp.EntryValid % time.Second / time.Nanosecond),
AttrValid: uint64(resp.AttrValid / time.Second),
AttrValidNsec: uint32(resp.AttrValid % time.Second / time.Nanosecond),
Attr: resp.Attr.attr(),
}
r.Conn.respond(&out.outHeader, unsafe.Sizeof(*out))
}
// A RenameRequest is a request to rename a file.
type RenameRequest struct {
Header
NewDir NodeID
OldName, NewName string
}
func (r *RenameRequest) handle() HandleID {
return 0
}
func (r *RenameRequest) String() string {
return fmt.Sprintf("Rename [%s] from %q to dirnode %d %q", &r.Header, r.OldName, r.NewDir, r.NewName)
}
func (r *RenameRequest) Respond() {
out := &outHeader{Unique: uint64(r.ID)}
r.Conn.respond(out, unsafe.Sizeof(*out))
}
type MknodRequest struct {
Header
Name string
Mode os.FileMode
Rdev uint32
}
func (r *MknodRequest) String() string {
return fmt.Sprintf("Mknod [%s] Name %q mode %v rdev %d", &r.Header, r.Name, r.Mode, r.Rdev)
}
func (r *MknodRequest) Respond(resp *LookupResponse) {
out := &entryOut{
outHeader: outHeader{Unique: uint64(r.ID)},
Nodeid: uint64(resp.Node),
Generation: resp.Generation,
EntryValid: uint64(resp.EntryValid / time.Second),
EntryValidNsec: uint32(resp.EntryValid % time.Second / time.Nanosecond),
AttrValid: uint64(resp.AttrValid / time.Second),
AttrValidNsec: uint32(resp.AttrValid % time.Second / time.Nanosecond),
Attr: resp.Attr.attr(),
}
r.Conn.respond(&out.outHeader, unsafe.Sizeof(*out))
}
type FsyncRequest struct {
Header
Handle HandleID
Flags uint32
}
func (r *FsyncRequest) String() string {
return fmt.Sprintf("Fsync [%s] Handle %v Flags %v", &r.Header, r.Handle, r.Flags)
}
func (r *FsyncRequest) Respond() {
out := &outHeader{Unique: uint64(r.ID)}
r.Conn.respond(out, unsafe.Sizeof(*out))
}
/*{
// A XXXRequest xxx.
type XXXRequest struct {
Header
xxx
}
func (r *XXXRequest) String() string {
return fmt.Sprintf("XXX [%s] xxx", &r.Header)
}
func (r *XXXRequest) handle() HandleID {
return r.Handle
}
// Respond replies to the request with the given response.
func (r *XXXRequest) Respond(resp *XXXResponse) {
out := &xxxOut{
outHeader: outHeader{Unique: uint64(r.ID)},
xxx,
}
r.Conn.respond(&out.outHeader, unsafe.Sizeof(*out))
}
// A XXXResponse is the response to a XXXRequest.
type XXXResponse struct {
xxx
}
func (r *XXXResponse) String() string {
return fmt.Sprintf("XXX %+v", *r)
}
}
*/
Go
1
https://gitee.com/hsg4ok_admin/rsc.git
git@gitee.com:hsg4ok_admin/rsc.git
hsg4ok_admin
rsc
rsc
v0.0.1

搜索帮助