1// See the file LICENSE for copyright and licensing information.
2
3// Adapted from Plan 9 from User Space's src/cmd/9pfuse/fuse.c,
4// which carries this notice:
5//
6// The files in this directory are subject to the following license.
7//
8// The author of this software is Russ Cox.
9//
10//         Copyright (c) 2006 Russ Cox
11//
12// Permission to use, copy, modify, and distribute this software for any
13// purpose without fee is hereby granted, provided that this entire notice
14// is included in all copies of any software which is or includes a copy
15// or modification of this software and in all copies of the supporting
16// documentation for such software.
17//
18// THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
19// WARRANTY.  IN PARTICULAR, THE AUTHOR MAKES NO REPRESENTATION OR WARRANTY
20// OF ANY KIND CONCERNING THE MERCHANTABILITY OF THIS SOFTWARE OR ITS
21// FITNESS FOR ANY PARTICULAR PURPOSE.
22
23// Package fuse enables writing FUSE file systems on Linux and FreeBSD.
24//
25// There are two approaches to writing a FUSE file system.  The first is to speak
26// the low-level message protocol, reading from a Conn using ReadRequest and
27// writing using the various Respond methods.  This approach is closest to
28// the actual interaction with the kernel and can be the simplest one in contexts
29// such as protocol translators.
30//
31// Servers of synthesized file systems tend to share common
32// bookkeeping abstracted away by the second approach, which is to
33// call fs.Serve to serve the FUSE protocol using an implementation of
34// the service methods in the interfaces FS* (file system), Node* (file
35// or directory), and Handle* (opened file or directory).
36// There are a daunting number of such methods that can be written,
37// but few are required.
38// The specific methods are described in the documentation for those interfaces.
39//
40// The hellofs subdirectory contains a simple illustration of the fs.Serve approach.
41//
42// Service Methods
43//
44// The required and optional methods for the FS, Node, and Handle interfaces
45// have the general form
46//
47//	Op(ctx context.Context, req *OpRequest, resp *OpResponse) error
48//
49// where Op is the name of a FUSE operation. Op reads request
50// parameters from req and writes results to resp. An operation whose
51// only result is the error result omits the resp parameter.
52//
53// Multiple goroutines may call service methods simultaneously; the
54// methods being called are responsible for appropriate
55// synchronization.
56//
57// The operation must not hold on to the request or response,
58// including any []byte fields such as WriteRequest.Data or
59// SetxattrRequest.Xattr.
60//
61// Errors
62//
63// Operations can return errors. The FUSE interface can only
64// communicate POSIX errno error numbers to file system clients, the
65// message is not visible to file system clients. The returned error
66// can implement ErrorNumber to control the errno returned. Without
67// ErrorNumber, a generic errno (EIO) is returned.
68//
69// Error messages will be visible in the debug log as part of the
70// response.
71//
72// Interrupted Operations
73//
74// In some file systems, some operations
75// may take an undetermined amount of time.  For example, a Read waiting for
76// a network message or a matching Write might wait indefinitely.  If the request
77// is cancelled and no longer needed, the context will be cancelled.
78// Blocking operations should select on a receive from ctx.Done() and attempt to
79// abort the operation early if the receive succeeds (meaning the channel is closed).
80// To indicate that the operation failed because it was aborted, return syscall.EINTR.
81//
82// If an operation does not block for an indefinite amount of time, supporting
83// cancellation is not necessary.
84//
85// Authentication
86//
87// All requests types embed a Header, meaning that the method can
88// inspect req.Pid, req.Uid, and req.Gid as necessary to implement
89// permission checking. The kernel FUSE layer normally prevents other
90// users from accessing the FUSE file system (to change this, see
91// AllowOther), but does not enforce access modes (to change this, see
92// DefaultPermissions).
93//
94// Mount Options
95//
96// Behavior and metadata of the mounted file system can be changed by
97// passing MountOption values to Mount.
98//
99package fuse // import "bazil.org/fuse"
100
101import (
102	"bytes"
103	"encoding/json"
104	"errors"
105	"fmt"
106	"io"
107	"os"
108	"strings"
109	"sync"
110	"syscall"
111	"time"
112	"unsafe"
113)
114
115// A Conn represents a connection to a mounted FUSE file system.
116type Conn struct {
117	// Always closed, mount is ready when Mount returns.
118	//
119	// Deprecated: Not used, OS X remnant.
120	Ready <-chan struct{}
121
122	// Use error returned from Mount.
123	//
124	// Deprecated: Not used, OS X remnant.
125	MountError error
126
127	// File handle for kernel communication. Only safe to access if
128	// rio or wio is held.
129	dev *os.File
130	wio sync.RWMutex
131	rio sync.RWMutex
132
133	// Protocol version negotiated with initRequest/initResponse.
134	proto Protocol
135	// Feature flags negotiated with initRequest/initResponse.
136	flags InitFlags
137}
138
139// MountpointDoesNotExistError is an error returned when the
140// mountpoint does not exist.
141type MountpointDoesNotExistError struct {
142	Path string
143}
144
145var _ error = (*MountpointDoesNotExistError)(nil)
146
147func (e *MountpointDoesNotExistError) Error() string {
148	return fmt.Sprintf("mountpoint does not exist: %v", e.Path)
149}
150
151// Mount mounts a new FUSE connection on the named directory
152// and returns a connection for reading and writing FUSE messages.
153//
154// After a successful return, caller must call Close to free
155// resources.
156func Mount(dir string, options ...MountOption) (*Conn, error) {
157	conf := mountConfig{
158		options: make(map[string]string),
159	}
160	for _, option := range options {
161		if err := option(&conf); err != nil {
162			return nil, err
163		}
164	}
165
166	ready := make(chan struct{})
167	close(ready)
168	c := &Conn{
169		Ready: ready,
170	}
171	f, err := mount(dir, &conf)
172	if err != nil {
173		return nil, err
174	}
175	c.dev = f
176
177	if err := initMount(c, &conf); err != nil {
178		c.Close()
179		_ = Unmount(dir)
180		return nil, err
181	}
182
183	return c, nil
184}
185
186type OldVersionError struct {
187	Kernel     Protocol
188	LibraryMin Protocol
189}
190
191func (e *OldVersionError) Error() string {
192	return fmt.Sprintf("kernel FUSE version is too old: %v < %v", e.Kernel, e.LibraryMin)
193}
194
195var (
196	ErrClosedWithoutInit = errors.New("fuse connection closed without init")
197)
198
199func initMount(c *Conn, conf *mountConfig) error {
200	req, err := c.ReadRequest()
201	if err != nil {
202		if err == io.EOF {
203			return ErrClosedWithoutInit
204		}
205		return err
206	}
207	r, ok := req.(*initRequest)
208	if !ok {
209		return fmt.Errorf("missing init, got: %T", req)
210	}
211
212	min := Protocol{protoVersionMinMajor, protoVersionMinMinor}
213	if r.Kernel.LT(min) {
214		req.RespondError(Errno(syscall.EPROTO))
215		c.Close()
216		return &OldVersionError{
217			Kernel:     r.Kernel,
218			LibraryMin: min,
219		}
220	}
221
222	proto := Protocol{protoVersionMaxMajor, protoVersionMaxMinor}
223	if r.Kernel.LT(proto) {
224		// Kernel doesn't support the latest version we have.
225		proto = r.Kernel
226	}
227	c.proto = proto
228
229	c.flags = r.Flags & (InitBigWrites | conf.initFlags)
230	s := &initResponse{
231		Library:             proto,
232		MaxReadahead:        conf.maxReadahead,
233		Flags:               c.flags,
234		MaxBackground:       conf.maxBackground,
235		CongestionThreshold: conf.congestionThreshold,
236		MaxWrite:            maxWrite,
237	}
238	r.Respond(s)
239	return nil
240}
241
242// A Request represents a single FUSE request received from the kernel.
243// Use a type switch to determine the specific kind.
244// A request of unrecognized type will have concrete type *Header.
245type Request interface {
246	// Hdr returns the Header associated with this request.
247	Hdr() *Header
248
249	// RespondError responds to the request with the given error.
250	RespondError(error)
251
252	String() string
253}
254
255// A RequestID identifies an active FUSE request.
256type RequestID uint64
257
258func (r RequestID) String() string {
259	return fmt.Sprintf("%#x", uint64(r))
260}
261
262// A NodeID is a number identifying a directory or file.
263// It must be unique among IDs returned in LookupResponses
264// that have not yet been forgotten by ForgetRequests.
265type NodeID uint64
266
267func (n NodeID) String() string {
268	return fmt.Sprintf("%#x", uint64(n))
269}
270
271// A HandleID is a number identifying an open directory or file.
272// It only needs to be unique while the directory or file is open.
273type HandleID uint64
274
275func (h HandleID) String() string {
276	return fmt.Sprintf("%#x", uint64(h))
277}
278
279// The RootID identifies the root directory of a FUSE file system.
280const RootID NodeID = rootID
281
282// A Header describes the basic information sent in every request.
283type Header struct {
284	Conn *Conn     `json:"-"` // connection this request was received on
285	ID   RequestID // unique ID for request
286	Node NodeID    // file or directory the request is about
287	Uid  uint32    // user ID of process making request
288	Gid  uint32    // group ID of process making request
289	Pid  uint32    // process ID of process making request
290
291	// for returning to reqPool
292	msg *message
293}
294
295func (h *Header) String() string {
296	return fmt.Sprintf("ID=%v Node=%v Uid=%d Gid=%d Pid=%d", h.ID, h.Node, h.Uid, h.Gid, h.Pid)
297}
298
299func (h *Header) Hdr() *Header {
300	return h
301}
302
303func (h *Header) noResponse() {
304	putMessage(h.msg)
305}
306
307func (h *Header) respond(msg []byte) {
308	out := (*outHeader)(unsafe.Pointer(&msg[0]))
309	out.Unique = uint64(h.ID)
310	h.Conn.respond(msg)
311	putMessage(h.msg)
312}
313
314// An ErrorNumber is an error with a specific error number.
315//
316// Operations may return an error value that implements ErrorNumber to
317// control what specific error number (errno) to return.
318type ErrorNumber interface {
319	// Errno returns the the error number (errno) for this error.
320	Errno() Errno
321}
322
323// Deprecated: Return a syscall.Errno directly. See ToErrno for exact
324// rules.
325const (
326	// ENOSYS indicates that the call is not supported.
327	ENOSYS = Errno(syscall.ENOSYS)
328
329	// ESTALE is used by Serve to respond to violations of the FUSE protocol.
330	ESTALE = Errno(syscall.ESTALE)
331
332	ENOENT = Errno(syscall.ENOENT)
333	EIO    = Errno(syscall.EIO)
334	EPERM  = Errno(syscall.EPERM)
335
336	// EINTR indicates request was interrupted by an InterruptRequest.
337	// See also fs.Intr.
338	EINTR = Errno(syscall.EINTR)
339
340	ERANGE  = Errno(syscall.ERANGE)
341	ENOTSUP = Errno(syscall.ENOTSUP)
342	EEXIST  = Errno(syscall.EEXIST)
343)
344
345// DefaultErrno is the errno used when error returned does not
346// implement ErrorNumber.
347const DefaultErrno = EIO
348
349var errnoNames = map[Errno]string{
350	ENOSYS:                      "ENOSYS",
351	ESTALE:                      "ESTALE",
352	ENOENT:                      "ENOENT",
353	EIO:                         "EIO",
354	EPERM:                       "EPERM",
355	EINTR:                       "EINTR",
356	EEXIST:                      "EEXIST",
357	Errno(syscall.ENAMETOOLONG): "ENAMETOOLONG",
358}
359
360// Errno implements Error and ErrorNumber using a syscall.Errno.
361type Errno syscall.Errno
362
363var _ ErrorNumber = Errno(0)
364var _ error = Errno(0)
365
366func (e Errno) Errno() Errno {
367	return e
368}
369
370func (e Errno) String() string {
371	return syscall.Errno(e).Error()
372}
373
374func (e Errno) Error() string {
375	return syscall.Errno(e).Error()
376}
377
378// ErrnoName returns the short non-numeric identifier for this errno.
379// For example, "EIO".
380func (e Errno) ErrnoName() string {
381	s := errnoNames[e]
382	if s == "" {
383		s = fmt.Sprint(e.Errno())
384	}
385	return s
386}
387
388func (e Errno) MarshalText() ([]byte, error) {
389	s := e.ErrnoName()
390	return []byte(s), nil
391}
392
393// ToErrno converts arbitrary errors to Errno.
394//
395// If the underlying type of err is syscall.Errno, it is used
396// directly. No unwrapping is done, to prevent wrong errors from
397// leaking via e.g. *os.PathError.
398//
399// If err unwraps to implement ErrorNumber, that is used.
400//
401// Finally, returns DefaultErrno.
402func ToErrno(err error) Errno {
403	if err, ok := err.(syscall.Errno); ok {
404		return Errno(err)
405	}
406	var errnum ErrorNumber
407	if errors.As(err, &errnum) {
408		return Errno(errnum.Errno())
409	}
410	return DefaultErrno
411}
412
413func (h *Header) RespondError(err error) {
414	errno := ToErrno(err)
415	// FUSE uses negative errors!
416	buf := newBuffer(0)
417	hOut := (*outHeader)(unsafe.Pointer(&buf[0]))
418	hOut.Error = -int32(errno)
419	h.respond(buf)
420}
421
422// All requests read from the kernel, without data, are shorter than
423// this.
424var maxRequestSize = syscall.Getpagesize()
425var bufSize = maxRequestSize + maxWrite
426
427// reqPool is a pool of messages.
428//
429// Lifetime of a logical message is from getMessage to putMessage.
430// getMessage is called by ReadRequest. putMessage is called by
431// Conn.ReadRequest, Request.Respond, or Request.RespondError.
432//
433// Messages in the pool are guaranteed to have conn and off zeroed,
434// buf allocated and len==bufSize, and hdr set.
435var reqPool = sync.Pool{
436	New: allocMessage,
437}
438
439func allocMessage() interface{} {
440	m := &message{buf: make([]byte, bufSize)}
441	m.hdr = (*inHeader)(unsafe.Pointer(&m.buf[0]))
442	return m
443}
444
445func getMessage(c *Conn) *message {
446	m := reqPool.Get().(*message)
447	m.conn = c
448	return m
449}
450
451func putMessage(m *message) {
452	m.buf = m.buf[:bufSize]
453	m.conn = nil
454	m.off = 0
455	reqPool.Put(m)
456}
457
458// a message represents the bytes of a single FUSE message
459type message struct {
460	conn *Conn
461	buf  []byte    // all bytes
462	hdr  *inHeader // header
463	off  int       // offset for reading additional fields
464}
465
466func (m *message) len() uintptr {
467	return uintptr(len(m.buf) - m.off)
468}
469
470func (m *message) data() unsafe.Pointer {
471	var p unsafe.Pointer
472	if m.off < len(m.buf) {
473		p = unsafe.Pointer(&m.buf[m.off])
474	}
475	return p
476}
477
478func (m *message) bytes() []byte {
479	return m.buf[m.off:]
480}
481
482func (m *message) Header() Header {
483	h := m.hdr
484	return Header{
485		Conn: m.conn,
486		ID:   RequestID(h.Unique),
487		Node: NodeID(h.Nodeid),
488		Uid:  h.Uid,
489		Gid:  h.Gid,
490		Pid:  h.Pid,
491
492		msg: m,
493	}
494}
495
496// fileMode returns a Go os.FileMode from a Unix mode.
497func fileMode(unixMode uint32) os.FileMode {
498	mode := os.FileMode(unixMode & 0o777)
499	switch unixMode & syscall.S_IFMT {
500	case syscall.S_IFREG:
501		// nothing
502	case syscall.S_IFDIR:
503		mode |= os.ModeDir
504	case syscall.S_IFCHR:
505		mode |= os.ModeCharDevice | os.ModeDevice
506	case syscall.S_IFBLK:
507		mode |= os.ModeDevice
508	case syscall.S_IFIFO:
509		mode |= os.ModeNamedPipe
510	case syscall.S_IFLNK:
511		mode |= os.ModeSymlink
512	case syscall.S_IFSOCK:
513		mode |= os.ModeSocket
514	case 0:
515		// apparently there's plenty of times when the FUSE request
516		// does not contain the file type
517		mode |= os.ModeIrregular
518	default:
519		// not just unavailable in the kernel codepath; known to
520		// kernel but unrecognized by us
521		Debug(fmt.Sprintf("unrecognized file mode type: %04o", unixMode))
522		mode |= os.ModeIrregular
523	}
524	if unixMode&syscall.S_ISUID != 0 {
525		mode |= os.ModeSetuid
526	}
527	if unixMode&syscall.S_ISGID != 0 {
528		mode |= os.ModeSetgid
529	}
530	return mode
531}
532
533type noOpcode struct {
534	Opcode uint32
535}
536
537func (m noOpcode) String() string {
538	return fmt.Sprintf("No opcode %v", m.Opcode)
539}
540
541type malformedMessage struct {
542}
543
544func (malformedMessage) String() string {
545	return "malformed message"
546}
547
548// Close closes the FUSE connection.
549func (c *Conn) Close() error {
550	c.wio.Lock()
551	defer c.wio.Unlock()
552	c.rio.Lock()
553	defer c.rio.Unlock()
554	return c.dev.Close()
555}
556
557// caller must hold wio or rio
558func (c *Conn) fd() int {
559	return int(c.dev.Fd())
560}
561
562func (c *Conn) Protocol() Protocol {
563	return c.proto
564}
565
566// Features reports the feature flags negotiated between the kernel and
567// the FUSE library. See MountOption for how to influence features
568// activated.
569func (c *Conn) Features() InitFlags {
570	return c.flags
571}
572
573// ReadRequest returns the next FUSE request from the kernel.
574//
575// Caller must call either Request.Respond or Request.RespondError in
576// a reasonable time. Caller must not retain Request after that call.
577func (c *Conn) ReadRequest() (Request, error) {
578	m := getMessage(c)
579	c.rio.RLock()
580	n, err := syscall.Read(c.fd(), m.buf)
581	c.rio.RUnlock()
582	if err != nil && err != syscall.ENODEV {
583		putMessage(m)
584		return nil, err
585	}
586	if n <= 0 {
587		putMessage(m)
588		return nil, io.EOF
589	}
590	m.buf = m.buf[:n]
591
592	if n < inHeaderSize {
593		putMessage(m)
594		return nil, errors.New("fuse: message too short")
595	}
596
597	// FreeBSD FUSE sends a short length in the header
598	// for FUSE_INIT even though the actual read length is correct.
599	if n == inHeaderSize+initInSize && m.hdr.Opcode == opInit && m.hdr.Len < uint32(n) {
600		m.hdr.Len = uint32(n)
601	}
602
603	if m.hdr.Len != uint32(n) {
604		// prepare error message before returning m to pool
605		err := fmt.Errorf("fuse: read %d opcode %d but expected %d", n, m.hdr.Opcode, m.hdr.Len)
606		putMessage(m)
607		return nil, err
608	}
609
610	m.off = inHeaderSize
611
612	// Convert to data structures.
613	// Do not trust kernel to hand us well-formed data.
614	var req Request
615	switch m.hdr.Opcode {
616	default:
617		Debug(noOpcode{Opcode: m.hdr.Opcode})
618		goto unrecognized
619
620	case opLookup:
621		buf := m.bytes()
622		n := len(buf)
623		if n == 0 || buf[n-1] != '\x00' {
624			goto corrupt
625		}
626		req = &LookupRequest{
627			Header: m.Header(),
628			Name:   string(buf[:n-1]),
629		}
630
631	case opForget:
632		in := (*forgetIn)(m.data())
633		if m.len() < unsafe.Sizeof(*in) {
634			goto corrupt
635		}
636		req = &ForgetRequest{
637			Header: m.Header(),
638			N:      in.Nlookup,
639		}
640
641	case opGetattr:
642		switch {
643		case c.proto.LT(Protocol{7, 9}):
644			req = &GetattrRequest{
645				Header: m.Header(),
646			}
647
648		default:
649			in := (*getattrIn)(m.data())
650			if m.len() < unsafe.Sizeof(*in) {
651				goto corrupt
652			}
653			req = &GetattrRequest{
654				Header: m.Header(),
655				Flags:  GetattrFlags(in.GetattrFlags),
656				Handle: HandleID(in.Fh),
657			}
658		}
659
660	case opSetattr:
661		in := (*setattrIn)(m.data())
662		if m.len() < unsafe.Sizeof(*in) {
663			goto corrupt
664		}
665		req = &SetattrRequest{
666			Header: m.Header(),
667			Valid:  SetattrValid(in.Valid),
668			Handle: HandleID(in.Fh),
669			Size:   in.Size,
670			Atime:  time.Unix(int64(in.Atime), int64(in.AtimeNsec)),
671			Mtime:  time.Unix(int64(in.Mtime), int64(in.MtimeNsec)),
672			Mode:   fileMode(in.Mode),
673			Uid:    in.Uid,
674			Gid:    in.Gid,
675		}
676
677	case opReadlink:
678		if len(m.bytes()) > 0 {
679			goto corrupt
680		}
681		req = &ReadlinkRequest{
682			Header: m.Header(),
683		}
684
685	case opSymlink:
686		// m.bytes() is "newName\0target\0"
687		names := m.bytes()
688		if len(names) == 0 || names[len(names)-1] != 0 {
689			goto corrupt
690		}
691		i := bytes.IndexByte(names, '\x00')
692		if i < 0 {
693			goto corrupt
694		}
695		newName, target := names[0:i], names[i+1:len(names)-1]
696		req = &SymlinkRequest{
697			Header:  m.Header(),
698			NewName: string(newName),
699			Target:  string(target),
700		}
701
702	case opLink:
703		in := (*linkIn)(m.data())
704		if m.len() < unsafe.Sizeof(*in) {
705			goto corrupt
706		}
707		newName := m.bytes()[unsafe.Sizeof(*in):]
708		if len(newName) < 2 || newName[len(newName)-1] != 0 {
709			goto corrupt
710		}
711		newName = newName[:len(newName)-1]
712		req = &LinkRequest{
713			Header:  m.Header(),
714			OldNode: NodeID(in.Oldnodeid),
715			NewName: string(newName),
716		}
717
718	case opMknod:
719		size := mknodInSize(c.proto)
720		if m.len() < size {
721			goto corrupt
722		}
723		in := (*mknodIn)(m.data())
724		name := m.bytes()[size:]
725		if len(name) < 2 || name[len(name)-1] != '\x00' {
726			goto corrupt
727		}
728		name = name[:len(name)-1]
729		r := &MknodRequest{
730			Header: m.Header(),
731			Mode:   fileMode(in.Mode),
732			Rdev:   in.Rdev,
733			Name:   string(name),
734		}
735		if c.proto.GE(Protocol{7, 12}) {
736			r.Umask = fileMode(in.Umask) & os.ModePerm
737		}
738		req = r
739
740	case opMkdir:
741		size := mkdirInSize(c.proto)
742		if m.len() < size {
743			goto corrupt
744		}
745		in := (*mkdirIn)(m.data())
746		name := m.bytes()[size:]
747		i := bytes.IndexByte(name, '\x00')
748		if i < 0 {
749			goto corrupt
750		}
751		r := &MkdirRequest{
752			Header: m.Header(),
753			Name:   string(name[:i]),
754			// observed on Linux: mkdirIn.Mode & syscall.S_IFMT == 0,
755			// and this causes fileMode to go into it's "no idea"
756			// code branch; enforce type to directory
757			Mode: fileMode((in.Mode &^ syscall.S_IFMT) | syscall.S_IFDIR),
758		}
759		if c.proto.GE(Protocol{7, 12}) {
760			r.Umask = fileMode(in.Umask) & os.ModePerm
761		}
762		req = r
763
764	case opUnlink, opRmdir:
765		buf := m.bytes()
766		n := len(buf)
767		if n == 0 || buf[n-1] != '\x00' {
768			goto corrupt
769		}
770		req = &RemoveRequest{
771			Header: m.Header(),
772			Name:   string(buf[:n-1]),
773			Dir:    m.hdr.Opcode == opRmdir,
774		}
775
776	case opRename:
777		in := (*renameIn)(m.data())
778		if m.len() < unsafe.Sizeof(*in) {
779			goto corrupt
780		}
781		newDirNodeID := NodeID(in.Newdir)
782		oldNew := m.bytes()[unsafe.Sizeof(*in):]
783		// oldNew should be "old\x00new\x00"
784		if len(oldNew) < 4 {
785			goto corrupt
786		}
787		if oldNew[len(oldNew)-1] != '\x00' {
788			goto corrupt
789		}
790		i := bytes.IndexByte(oldNew, '\x00')
791		if i < 0 {
792			goto corrupt
793		}
794		oldName, newName := string(oldNew[:i]), string(oldNew[i+1:len(oldNew)-1])
795		req = &RenameRequest{
796			Header:  m.Header(),
797			NewDir:  newDirNodeID,
798			OldName: oldName,
799			NewName: newName,
800		}
801
802	case opOpendir, opOpen:
803		in := (*openIn)(m.data())
804		if m.len() < unsafe.Sizeof(*in) {
805			goto corrupt
806		}
807		req = &OpenRequest{
808			Header: m.Header(),
809			Dir:    m.hdr.Opcode == opOpendir,
810			Flags:  openFlags(in.Flags),
811		}
812
813	case opRead, opReaddir:
814		in := (*readIn)(m.data())
815		if m.len() < readInSize(c.proto) {
816			goto corrupt
817		}
818		r := &ReadRequest{
819			Header: m.Header(),
820			Dir:    m.hdr.Opcode == opReaddir,
821			Handle: HandleID(in.Fh),
822			Offset: int64(in.Offset),
823			Size:   int(in.Size),
824		}
825		if c.proto.GE(Protocol{7, 9}) {
826			r.Flags = ReadFlags(in.ReadFlags)
827			r.LockOwner = LockOwner(in.LockOwner)
828			r.FileFlags = openFlags(in.Flags)
829		}
830		req = r
831
832	case opWrite:
833		in := (*writeIn)(m.data())
834		if m.len() < writeInSize(c.proto) {
835			goto corrupt
836		}
837		r := &WriteRequest{
838			Header: m.Header(),
839			Handle: HandleID(in.Fh),
840			Offset: int64(in.Offset),
841			Flags:  WriteFlags(in.WriteFlags),
842		}
843		if c.proto.GE(Protocol{7, 9}) {
844			r.LockOwner = LockOwner(in.LockOwner)
845			r.FileFlags = openFlags(in.Flags)
846		}
847		buf := m.bytes()[writeInSize(c.proto):]
848		if uint32(len(buf)) < in.Size {
849			goto corrupt
850		}
851		r.Data = buf
852		req = r
853
854	case opStatfs:
855		req = &StatfsRequest{
856			Header: m.Header(),
857		}
858
859	case opRelease, opReleasedir:
860		in := (*releaseIn)(m.data())
861		if m.len() < unsafe.Sizeof(*in) {
862			goto corrupt
863		}
864		req = &ReleaseRequest{
865			Header:       m.Header(),
866			Dir:          m.hdr.Opcode == opReleasedir,
867			Handle:       HandleID(in.Fh),
868			Flags:        openFlags(in.Flags),
869			ReleaseFlags: ReleaseFlags(in.ReleaseFlags),
870			LockOwner:    LockOwner(in.LockOwner),
871		}
872
873	case opFsync, opFsyncdir:
874		in := (*fsyncIn)(m.data())
875		if m.len() < unsafe.Sizeof(*in) {
876			goto corrupt
877		}
878		req = &FsyncRequest{
879			Dir:    m.hdr.Opcode == opFsyncdir,
880			Header: m.Header(),
881			Handle: HandleID(in.Fh),
882			Flags:  in.FsyncFlags,
883		}
884
885	case opSetxattr:
886		in := (*setxattrIn)(m.data())
887		if m.len() < unsafe.Sizeof(*in) {
888			goto corrupt
889		}
890		m.off += int(unsafe.Sizeof(*in))
891		name := m.bytes()
892		i := bytes.IndexByte(name, '\x00')
893		if i < 0 {
894			goto corrupt
895		}
896		xattr := name[i+1:]
897		if uint32(len(xattr)) < in.Size {
898			goto corrupt
899		}
900		xattr = xattr[:in.Size]
901		req = &SetxattrRequest{
902			Header: m.Header(),
903			Flags:  in.Flags,
904			Name:   string(name[:i]),
905			Xattr:  xattr,
906		}
907
908	case opGetxattr:
909		in := (*getxattrIn)(m.data())
910		if m.len() < unsafe.Sizeof(*in) {
911			goto corrupt
912		}
913		name := m.bytes()[unsafe.Sizeof(*in):]
914		i := bytes.IndexByte(name, '\x00')
915		if i < 0 {
916			goto corrupt
917		}
918		req = &GetxattrRequest{
919			Header: m.Header(),
920			Name:   string(name[:i]),
921			Size:   in.Size,
922		}
923
924	case opListxattr:
925		in := (*getxattrIn)(m.data())
926		if m.len() < unsafe.Sizeof(*in) {
927			goto corrupt
928		}
929		req = &ListxattrRequest{
930			Header: m.Header(),
931			Size:   in.Size,
932		}
933
934	case opRemovexattr:
935		buf := m.bytes()
936		n := len(buf)
937		if n == 0 || buf[n-1] != '\x00' {
938			goto corrupt
939		}
940		req = &RemovexattrRequest{
941			Header: m.Header(),
942			Name:   string(buf[:n-1]),
943		}
944
945	case opFlush:
946		in := (*flushIn)(m.data())
947		if m.len() < unsafe.Sizeof(*in) {
948			goto corrupt
949		}
950		req = &FlushRequest{
951			Header:    m.Header(),
952			Handle:    HandleID(in.Fh),
953			LockOwner: LockOwner(in.LockOwner),
954		}
955
956	case opInit:
957		in := (*initIn)(m.data())
958		if m.len() < unsafe.Sizeof(*in) {
959			goto corrupt
960		}
961		req = &initRequest{
962			Header:       m.Header(),
963			Kernel:       Protocol{in.Major, in.Minor},
964			MaxReadahead: in.MaxReadahead,
965			Flags:        InitFlags(in.Flags),
966		}
967
968	case opAccess:
969		in := (*accessIn)(m.data())
970		if m.len() < unsafe.Sizeof(*in) {
971			goto corrupt
972		}
973		req = &AccessRequest{
974			Header: m.Header(),
975			Mask:   in.Mask,
976		}
977
978	case opCreate:
979		size := createInSize(c.proto)
980		if m.len() < size {
981			goto corrupt
982		}
983		in := (*createIn)(m.data())
984		name := m.bytes()[size:]
985		i := bytes.IndexByte(name, '\x00')
986		if i < 0 {
987			goto corrupt
988		}
989		r := &CreateRequest{
990			Header: m.Header(),
991			Flags:  openFlags(in.Flags),
992			Mode:   fileMode(in.Mode),
993			Name:   string(name[:i]),
994		}
995		if c.proto.GE(Protocol{7, 12}) {
996			r.Umask = fileMode(in.Umask) & os.ModePerm
997		}
998		req = r
999
1000	case opInterrupt:
1001		in := (*interruptIn)(m.data())
1002		if m.len() < unsafe.Sizeof(*in) {
1003			goto corrupt
1004		}
1005		req = &InterruptRequest{
1006			Header: m.Header(),
1007			IntrID: RequestID(in.Unique),
1008		}
1009
1010	case opBmap:
1011		// bmap asks to map a byte offset within a file to a single
1012		// uint64. On Linux, it triggers only with blkdev fuse mounts,
1013		// that claim to be backed by an actual block device. FreeBSD
1014		// seems to send it for just any fuse mount, whether there's a
1015		// block device involved or not.
1016		goto unrecognized
1017
1018	case opDestroy:
1019		req = &DestroyRequest{
1020			Header: m.Header(),
1021		}
1022
1023	case opNotifyReply:
1024		req = &NotifyReply{
1025			Header: m.Header(),
1026			msg:    m,
1027		}
1028
1029	case opPoll:
1030		in := (*pollIn)(m.data())
1031		if m.len() < unsafe.Sizeof(*in) {
1032			goto corrupt
1033		}
1034		req = &PollRequest{
1035			Header: m.Header(),
1036			Handle: HandleID(in.Fh),
1037			kh:     in.Kh,
1038			Flags:  PollFlags(in.Flags),
1039			Events: PollEvents(in.Events),
1040		}
1041
1042	case opBatchForget:
1043		in := (*batchForgetIn)(m.data())
1044		if m.len() < unsafe.Sizeof(*in) {
1045			goto corrupt
1046		}
1047		m.off += int(unsafe.Sizeof(*in))
1048		items := make([]BatchForgetItem, 0, in.Count)
1049		for count := in.Count; count > 0; count-- {
1050			one := (*forgetOne)(m.data())
1051			if m.len() < unsafe.Sizeof(*one) {
1052				goto corrupt
1053			}
1054			m.off += int(unsafe.Sizeof(*one))
1055			items = append(items, BatchForgetItem{
1056				NodeID: NodeID(one.NodeID),
1057				N:      one.Nlookup,
1058			})
1059		}
1060		req = &BatchForgetRequest{
1061			Header: m.Header(),
1062			Forget: items,
1063		}
1064
1065	case opSetlk, opSetlkw:
1066		in := (*lkIn)(m.data())
1067		if m.len() < unsafe.Sizeof(*in) {
1068			goto corrupt
1069		}
1070		tmp := &LockRequest{
1071			Header:    m.Header(),
1072			Handle:    HandleID(in.Fh),
1073			LockOwner: LockOwner(in.Owner),
1074			Lock: FileLock{
1075				Start: in.Lk.Start,
1076				End:   in.Lk.End,
1077				Type:  LockType(in.Lk.Type),
1078				PID:   int32(in.Lk.PID),
1079			},
1080			LockFlags: LockFlags(in.LkFlags),
1081		}
1082		switch {
1083		case tmp.Lock.Type == LockUnlock:
1084			req = (*UnlockRequest)(tmp)
1085		case m.hdr.Opcode == opSetlkw:
1086			req = (*LockWaitRequest)(tmp)
1087		default:
1088			req = tmp
1089		}
1090
1091	case opGetlk:
1092		in := (*lkIn)(m.data())
1093		if m.len() < unsafe.Sizeof(*in) {
1094			goto corrupt
1095		}
1096		req = &QueryLockRequest{
1097			Header:    m.Header(),
1098			Handle:    HandleID(in.Fh),
1099			LockOwner: LockOwner(in.Owner),
1100			Lock: FileLock{
1101				Start: in.Lk.Start,
1102				End:   in.Lk.End,
1103				Type:  LockType(in.Lk.Type),
1104				// fuse.h claims this field is a uint32, but then the
1105				// spec talks about -1 as a value, and using int as
1106				// the C definition is pretty common. Make our API use
1107				// a signed integer.
1108				PID: int32(in.Lk.PID),
1109			},
1110			LockFlags: LockFlags(in.LkFlags),
1111		}
1112	}
1113
1114	return req, nil
1115
1116corrupt:
1117	Debug(malformedMessage{})
1118	putMessage(m)
1119	return nil, fmt.Errorf("fuse: malformed message")
1120
1121unrecognized:
1122	// Unrecognized message.
1123	// Assume higher-level code will send a "no idea what you mean" error.
1124	req = &UnrecognizedRequest{
1125		Header: m.Header(),
1126		Opcode: m.hdr.Opcode,
1127	}
1128	return req, nil
1129}
1130
1131type bugShortKernelWrite struct {
1132	Written int64
1133	Length  int64
1134	Error   string
1135	Stack   string
1136}
1137
1138func (b bugShortKernelWrite) String() string {
1139	return fmt.Sprintf("short kernel write: written=%d/%d error=%q stack=\n%s", b.Written, b.Length, b.Error, b.Stack)
1140}
1141
1142type bugKernelWriteError struct {
1143	Error string
1144	Stack string
1145}
1146
1147func (b bugKernelWriteError) String() string {
1148	return fmt.Sprintf("kernel write error: error=%q stack=\n%s", b.Error, b.Stack)
1149}
1150
1151// safe to call even with nil error
1152func errorString(err error) string {
1153	if err == nil {
1154		return ""
1155	}
1156	return err.Error()
1157}
1158
1159func (c *Conn) writeToKernel(msg []byte) error {
1160	out := (*outHeader)(unsafe.Pointer(&msg[0]))
1161	out.Len = uint32(len(msg))
1162
1163	c.wio.RLock()
1164	defer c.wio.RUnlock()
1165	nn, err := syscall.Write(c.fd(), msg)
1166	if err == nil && nn != len(msg) {
1167		Debug(bugShortKernelWrite{
1168			Written: int64(nn),
1169			Length:  int64(len(msg)),
1170			Error:   errorString(err),
1171			Stack:   stack(),
1172		})
1173	}
1174	return err
1175}
1176
1177func (c *Conn) respond(msg []byte) {
1178	if err := c.writeToKernel(msg); err != nil {
1179		Debug(bugKernelWriteError{
1180			Error: errorString(err),
1181			Stack: stack(),
1182		})
1183	}
1184}
1185
1186type notCachedError struct{}
1187
1188func (notCachedError) Error() string {
1189	return "node not cached"
1190}
1191
1192var _ ErrorNumber = notCachedError{}
1193
1194func (notCachedError) Errno() Errno {
1195	// Behave just like if the original syscall.ENOENT had been passed
1196	// straight through.
1197	return ENOENT
1198}
1199
1200var (
1201	ErrNotCached = notCachedError{}
1202)
1203
1204// sendNotify sends a notification to kernel.
1205//
1206// A returned ENOENT is translated to a friendlier error.
1207func (c *Conn) sendNotify(msg []byte) error {
1208	switch err := c.writeToKernel(msg); err {
1209	case syscall.ENOENT:
1210		return ErrNotCached
1211	default:
1212		return err
1213	}
1214}
1215
1216// InvalidateNode invalidates the kernel cache of the attributes and a
1217// range of the data of a node.
1218//
1219// Giving offset 0 and size -1 means all data. To invalidate just the
1220// attributes, give offset 0 and size 0.
1221//
1222// Returns ErrNotCached if the kernel is not currently caching the
1223// node.
1224func (c *Conn) InvalidateNode(nodeID NodeID, off int64, size int64) error {
1225	buf := newBuffer(unsafe.Sizeof(notifyInvalInodeOut{}))
1226	h := (*outHeader)(unsafe.Pointer(&buf[0]))
1227	// h.Unique is 0
1228	h.Error = notifyCodeInvalInode
1229	out := (*notifyInvalInodeOut)(buf.alloc(unsafe.Sizeof(notifyInvalInodeOut{})))
1230	out.Ino = uint64(nodeID)
1231	out.Off = off
1232	out.Len = size
1233	return c.sendNotify(buf)
1234}
1235
1236// InvalidateEntry invalidates the kernel cache of the directory entry
1237// identified by parent directory node ID and entry basename.
1238//
1239// Kernel may or may not cache directory listings. To invalidate
1240// those, use InvalidateNode to invalidate all of the data for a
1241// directory. (As of 2015-06, Linux FUSE does not cache directory
1242// listings.)
1243//
1244// Returns ErrNotCached if the kernel is not currently caching the
1245// node.
1246func (c *Conn) InvalidateEntry(parent NodeID, name string) error {
1247	const maxUint32 = ^uint32(0)
1248	if uint64(len(name)) > uint64(maxUint32) {
1249		// very unlikely, but we don't want to silently truncate
1250		return syscall.ENAMETOOLONG
1251	}
1252	buf := newBuffer(unsafe.Sizeof(notifyInvalEntryOut{}) + uintptr(len(name)) + 1)
1253	h := (*outHeader)(unsafe.Pointer(&buf[0]))
1254	// h.Unique is 0
1255	h.Error = notifyCodeInvalEntry
1256	out := (*notifyInvalEntryOut)(buf.alloc(unsafe.Sizeof(notifyInvalEntryOut{})))
1257	out.Parent = uint64(parent)
1258	out.Namelen = uint32(len(name))
1259	buf = append(buf, name...)
1260	buf = append(buf, '\x00')
1261	return c.sendNotify(buf)
1262}
1263
1264func (c *Conn) NotifyStore(nodeID NodeID, offset uint64, data []byte) error {
1265	buf := newBuffer(unsafe.Sizeof(notifyStoreOut{}) + uintptr(len(data)))
1266	h := (*outHeader)(unsafe.Pointer(&buf[0]))
1267	// h.Unique is 0
1268	h.Error = notifyCodeStore
1269	out := (*notifyStoreOut)(buf.alloc(unsafe.Sizeof(notifyStoreOut{})))
1270	out.Nodeid = uint64(nodeID)
1271	out.Offset = offset
1272	out.Size = uint32(len(data))
1273	buf = append(buf, data...)
1274	return c.sendNotify(buf)
1275}
1276
1277type NotifyRetrieval struct {
1278	// we may want fields later, so don't let callers know it's the
1279	// empty struct
1280	_ struct{}
1281}
1282
1283func (n *NotifyRetrieval) Finish(r *NotifyReply) []byte {
1284	m := r.msg
1285	defer putMessage(m)
1286	in := (*notifyRetrieveIn)(m.data())
1287	if m.len() < unsafe.Sizeof(*in) {
1288		Debug(malformedMessage{})
1289		return nil
1290	}
1291	m.off += int(unsafe.Sizeof(*in))
1292	buf := m.bytes()
1293	if uint32(len(buf)) < in.Size {
1294		Debug(malformedMessage{})
1295		return nil
1296	}
1297
1298	data := make([]byte, in.Size)
1299	copy(data, buf)
1300	return data
1301}
1302
1303func (c *Conn) NotifyRetrieve(notificationID RequestID, nodeID NodeID, offset uint64, size uint32) (*NotifyRetrieval, error) {
1304	// notificationID may collide with kernel-chosen requestIDs, it's
1305	// up to the caller to branch based on the opCode.
1306
1307	buf := newBuffer(unsafe.Sizeof(notifyRetrieveOut{}))
1308	h := (*outHeader)(unsafe.Pointer(&buf[0]))
1309	// h.Unique is 0
1310	h.Error = notifyCodeRetrieve
1311	out := (*notifyRetrieveOut)(buf.alloc(unsafe.Sizeof(notifyRetrieveOut{})))
1312	out.NotifyUnique = uint64(notificationID)
1313	out.Nodeid = uint64(nodeID)
1314	out.Offset = offset
1315	// kernel constrains size to maxWrite for us
1316	out.Size = size
1317	if err := c.sendNotify(buf); err != nil {
1318		return nil, err
1319	}
1320	r := &NotifyRetrieval{}
1321	return r, nil
1322}
1323
1324// NotifyPollWakeup sends a notification to the kernel to wake up all
1325// clients waiting on this node. Wakeup is a value from a PollRequest
1326// for a Handle or a Node currently alive (Forget has not been called
1327// on it).
1328func (c *Conn) NotifyPollWakeup(wakeup PollWakeup) error {
1329	if wakeup.kh == 0 {
1330		// likely somebody ignored the comma-ok return
1331		return nil
1332	}
1333	buf := newBuffer(unsafe.Sizeof(notifyPollWakeupOut{}))
1334	h := (*outHeader)(unsafe.Pointer(&buf[0]))
1335	// h.Unique is 0
1336	h.Error = notifyCodePoll
1337	out := (*notifyPollWakeupOut)(buf.alloc(unsafe.Sizeof(notifyPollWakeupOut{})))
1338	out.Kh = wakeup.kh
1339	return c.sendNotify(buf)
1340}
1341
1342// LockOwner is a file-local opaque identifier assigned by the kernel
1343// to identify the owner of a particular lock.
1344type LockOwner uint64
1345
1346func (o LockOwner) String() string {
1347	if o == 0 {
1348		return "0"
1349	}
1350	return fmt.Sprintf("%016x", uint64(o))
1351}
1352
1353// An initRequest is the first request sent on a FUSE file system.
1354type initRequest struct {
1355	Header `json:"-"`
1356	Kernel Protocol
1357	// Maximum readahead in bytes that the kernel plans to use.
1358	MaxReadahead uint32
1359	Flags        InitFlags
1360}
1361
1362var _ Request = (*initRequest)(nil)
1363
1364func (r *initRequest) String() string {
1365	return fmt.Sprintf("Init [%v] %v ra=%d fl=%v", &r.Header, r.Kernel, r.MaxReadahead, r.Flags)
1366}
1367
1368type UnrecognizedRequest struct {
1369	Header `json:"-"`
1370	Opcode uint32
1371}
1372
1373var _ Request = (*UnrecognizedRequest)(nil)
1374
1375func (r *UnrecognizedRequest) String() string {
1376	return fmt.Sprintf("Unrecognized [%v] opcode=%d", &r.Header, r.Opcode)
1377}
1378
1379// An initResponse is the response to an initRequest.
1380type initResponse struct {
1381	Library Protocol
1382	// Maximum readahead in bytes that the kernel can use. Ignored if
1383	// greater than initRequest.MaxReadahead.
1384	MaxReadahead uint32
1385	Flags        InitFlags
1386	// Maximum number of outstanding background requests
1387	MaxBackground uint16
1388	// Number of background requests at which congestion starts
1389	CongestionThreshold uint16
1390	// Maximum size of a single write operation.
1391	// Linux enforces a minimum of 4 KiB.
1392	MaxWrite uint32
1393}
1394
1395func (r *initResponse) String() string {
1396	return fmt.Sprintf("Init %v ra=%d fl=%v maxbg=%d cg=%d w=%d", r.Library, r.MaxReadahead, r.Flags, r.MaxBackground, r.CongestionThreshold, r.MaxWrite)
1397}
1398
1399// Respond replies to the request with the given response.
1400func (r *initRequest) Respond(resp *initResponse) {
1401	buf := newBuffer(unsafe.Sizeof(initOut{}))
1402	out := (*initOut)(buf.alloc(unsafe.Sizeof(initOut{})))
1403	out.Major = resp.Library.Major
1404	out.Minor = resp.Library.Minor
1405	out.MaxReadahead = resp.MaxReadahead
1406	out.Flags = uint32(resp.Flags)
1407	out.MaxBackground = resp.MaxBackground
1408	out.CongestionThreshold = resp.CongestionThreshold
1409	out.MaxWrite = resp.MaxWrite
1410
1411	// MaxWrite larger than our receive buffer would just lead to
1412	// errors on large writes.
1413	if out.MaxWrite > maxWrite {
1414		out.MaxWrite = maxWrite
1415	}
1416	r.respond(buf)
1417}
1418
1419// A StatfsRequest requests information about the mounted file system.
1420type StatfsRequest struct {
1421	Header `json:"-"`
1422}
1423
1424var _ Request = (*StatfsRequest)(nil)
1425
1426func (r *StatfsRequest) String() string {
1427	return fmt.Sprintf("Statfs [%s]", &r.Header)
1428}
1429
1430// Respond replies to the request with the given response.
1431func (r *StatfsRequest) Respond(resp *StatfsResponse) {
1432	buf := newBuffer(unsafe.Sizeof(statfsOut{}))
1433	out := (*statfsOut)(buf.alloc(unsafe.Sizeof(statfsOut{})))
1434	out.St = kstatfs{
1435		Blocks:  resp.Blocks,
1436		Bfree:   resp.Bfree,
1437		Bavail:  resp.Bavail,
1438		Files:   resp.Files,
1439		Ffree:   resp.Ffree,
1440		Bsize:   resp.Bsize,
1441		Namelen: resp.Namelen,
1442		Frsize:  resp.Frsize,
1443	}
1444	r.respond(buf)
1445}
1446
1447// A StatfsResponse is the response to a StatfsRequest.
1448type StatfsResponse struct {
1449	Blocks  uint64 // Total data blocks in file system.
1450	Bfree   uint64 // Free blocks in file system.
1451	Bavail  uint64 // Free blocks in file system if you're not root.
1452	Files   uint64 // Total files in file system.
1453	Ffree   uint64 // Free files in file system.
1454	Bsize   uint32 // Block size
1455	Namelen uint32 // Maximum file name length?
1456	Frsize  uint32 // Fragment size, smallest addressable data size in the file system.
1457}
1458
1459func (r *StatfsResponse) String() string {
1460	return fmt.Sprintf("Statfs blocks=%d/%d/%d files=%d/%d bsize=%d frsize=%d namelen=%d",
1461		r.Bavail, r.Bfree, r.Blocks,
1462		r.Ffree, r.Files,
1463		r.Bsize,
1464		r.Frsize,
1465		r.Namelen,
1466	)
1467}
1468
1469// An AccessRequest asks whether the file can be accessed
1470// for the purpose specified by the mask.
1471type AccessRequest struct {
1472	Header `json:"-"`
1473	Mask   uint32
1474}
1475
1476var _ Request = (*AccessRequest)(nil)
1477
1478func (r *AccessRequest) String() string {
1479	return fmt.Sprintf("Access [%s] mask=%#x", &r.Header, r.Mask)
1480}
1481
1482// Respond replies to the request indicating that access is allowed.
1483// To deny access, use RespondError.
1484func (r *AccessRequest) Respond() {
1485	buf := newBuffer(0)
1486	r.respond(buf)
1487}
1488
1489// An Attr is the metadata for a single file or directory.
1490type Attr struct {
1491	Valid time.Duration // how long Attr can be cached
1492
1493	Inode     uint64      // inode number
1494	Size      uint64      // size in bytes
1495	Blocks    uint64      // size in 512-byte units
1496	Atime     time.Time   // time of last access
1497	Mtime     time.Time   // time of last modification
1498	Ctime     time.Time   // time of last inode change
1499	Mode      os.FileMode // file mode
1500	Nlink     uint32      // number of links (usually 1)
1501	Uid       uint32      // owner uid
1502	Gid       uint32      // group gid
1503	Rdev      uint32      // device numbers
1504	BlockSize uint32      // preferred blocksize for filesystem I/O
1505
1506	// Deprecated: Not used, OS X remnant.
1507	Crtime time.Time
1508	// Deprecated: Not used, OS X remnant.
1509	Flags uint32
1510}
1511
1512func (a Attr) String() string {
1513	return fmt.Sprintf("valid=%v ino=%v size=%d mode=%v", a.Valid, a.Inode, a.Size, a.Mode)
1514}
1515
1516func unixTime(t time.Time) (sec uint64, nsec uint32) {
1517	nano := t.UnixNano()
1518	sec = uint64(nano / 1e9)
1519	nsec = uint32(nano % 1e9)
1520	return
1521}
1522
1523func (a *Attr) attr(out *attr, proto Protocol) {
1524	out.Ino = a.Inode
1525	out.Size = a.Size
1526	out.Blocks = a.Blocks
1527	out.Atime, out.AtimeNsec = unixTime(a.Atime)
1528	out.Mtime, out.MtimeNsec = unixTime(a.Mtime)
1529	out.Ctime, out.CtimeNsec = unixTime(a.Ctime)
1530	out.Mode = uint32(a.Mode) & 0o777
1531	switch {
1532	default:
1533		out.Mode |= syscall.S_IFREG
1534	case a.Mode&os.ModeDir != 0:
1535		out.Mode |= syscall.S_IFDIR
1536	case a.Mode&os.ModeDevice != 0:
1537		if a.Mode&os.ModeCharDevice != 0 {
1538			out.Mode |= syscall.S_IFCHR
1539		} else {
1540			out.Mode |= syscall.S_IFBLK
1541		}
1542	case a.Mode&os.ModeNamedPipe != 0:
1543		out.Mode |= syscall.S_IFIFO
1544	case a.Mode&os.ModeSymlink != 0:
1545		out.Mode |= syscall.S_IFLNK
1546	case a.Mode&os.ModeSocket != 0:
1547		out.Mode |= syscall.S_IFSOCK
1548	}
1549	if a.Mode&os.ModeSetuid != 0 {
1550		out.Mode |= syscall.S_ISUID
1551	}
1552	if a.Mode&os.ModeSetgid != 0 {
1553		out.Mode |= syscall.S_ISGID
1554	}
1555	out.Nlink = a.Nlink
1556	out.Uid = a.Uid
1557	out.Gid = a.Gid
1558	out.Rdev = a.Rdev
1559	if proto.GE(Protocol{7, 9}) {
1560		out.Blksize = a.BlockSize
1561	}
1562}
1563
1564// A GetattrRequest asks for the metadata for the file denoted by r.Node.
1565type GetattrRequest struct {
1566	Header `json:"-"`
1567	Flags  GetattrFlags
1568	Handle HandleID
1569}
1570
1571var _ Request = (*GetattrRequest)(nil)
1572
1573func (r *GetattrRequest) String() string {
1574	return fmt.Sprintf("Getattr [%s] %v fl=%v", &r.Header, r.Handle, r.Flags)
1575}
1576
1577// Respond replies to the request with the given response.
1578func (r *GetattrRequest) Respond(resp *GetattrResponse) {
1579	size := attrOutSize(r.Header.Conn.proto)
1580	buf := newBuffer(size)
1581	out := (*attrOut)(buf.alloc(size))
1582	out.AttrValid = uint64(resp.Attr.Valid / time.Second)
1583	out.AttrValidNsec = uint32(resp.Attr.Valid % time.Second / time.Nanosecond)
1584	resp.Attr.attr(&out.Attr, r.Header.Conn.proto)
1585	r.respond(buf)
1586}
1587
1588// A GetattrResponse is the response to a GetattrRequest.
1589type GetattrResponse struct {
1590	Attr Attr // file attributes
1591}
1592
1593func (r *GetattrResponse) String() string {
1594	return fmt.Sprintf("Getattr %v", r.Attr)
1595}
1596
1597// A GetxattrRequest asks for the extended attributes associated with r.Node.
1598type GetxattrRequest struct {
1599	Header `json:"-"`
1600
1601	// Maximum size to return.
1602	Size uint32
1603
1604	// Name of the attribute requested.
1605	Name string
1606
1607	// Deprecated: Not used, OS X remnant.
1608	Position uint32
1609}
1610
1611var _ Request = (*GetxattrRequest)(nil)
1612
1613func (r *GetxattrRequest) String() string {
1614	return fmt.Sprintf("Getxattr [%s] %q %d", &r.Header, r.Name, r.Size)
1615}
1616
1617// Respond replies to the request with the given response.
1618func (r *GetxattrRequest) Respond(resp *GetxattrResponse) {
1619	if r.Size == 0 {
1620		buf := newBuffer(unsafe.Sizeof(getxattrOut{}))
1621		out := (*getxattrOut)(buf.alloc(unsafe.Sizeof(getxattrOut{})))
1622		out.Size = uint32(len(resp.Xattr))
1623		r.respond(buf)
1624	} else {
1625		buf := newBuffer(uintptr(len(resp.Xattr)))
1626		buf = append(buf, resp.Xattr...)
1627		r.respond(buf)
1628	}
1629}
1630
1631// A GetxattrResponse is the response to a GetxattrRequest.
1632type GetxattrResponse struct {
1633	Xattr []byte
1634}
1635
1636func (r *GetxattrResponse) String() string {
1637	return fmt.Sprintf("Getxattr %q", r.Xattr)
1638}
1639
1640// A ListxattrRequest asks to list the extended attributes associated with r.Node.
1641type ListxattrRequest struct {
1642	Header `json:"-"`
1643	Size   uint32 // maximum size to return
1644
1645	// Deprecated: Not used, OS X remnant.
1646	Position uint32
1647}
1648
1649var _ Request = (*ListxattrRequest)(nil)
1650
1651func (r *ListxattrRequest) String() string {
1652	return fmt.Sprintf("Listxattr [%s] %d", &r.Header, r.Size)
1653}
1654
1655// Respond replies to the request with the given response.
1656func (r *ListxattrRequest) Respond(resp *ListxattrResponse) {
1657	if r.Size == 0 {
1658		buf := newBuffer(unsafe.Sizeof(getxattrOut{}))
1659		out := (*getxattrOut)(buf.alloc(unsafe.Sizeof(getxattrOut{})))
1660		out.Size = uint32(len(resp.Xattr))
1661		r.respond(buf)
1662	} else {
1663		buf := newBuffer(uintptr(len(resp.Xattr)))
1664		buf = append(buf, resp.Xattr...)
1665		r.respond(buf)
1666	}
1667}
1668
1669// A ListxattrResponse is the response to a ListxattrRequest.
1670type ListxattrResponse struct {
1671	Xattr []byte
1672}
1673
1674func (r *ListxattrResponse) String() string {
1675	return fmt.Sprintf("Listxattr %q", r.Xattr)
1676}
1677
1678// Append adds an extended attribute name to the response.
1679func (r *ListxattrResponse) Append(names ...string) {
1680	for _, name := range names {
1681		r.Xattr = append(r.Xattr, name...)
1682		r.Xattr = append(r.Xattr, '\x00')
1683	}
1684}
1685
1686// A RemovexattrRequest asks to remove an extended attribute associated with r.Node.
1687type RemovexattrRequest struct {
1688	Header `json:"-"`
1689	Name   string // name of extended attribute
1690}
1691
1692var _ Request = (*RemovexattrRequest)(nil)
1693
1694func (r *RemovexattrRequest) String() string {
1695	return fmt.Sprintf("Removexattr [%s] %q", &r.Header, r.Name)
1696}
1697
1698// Respond replies to the request, indicating that the attribute was removed.
1699func (r *RemovexattrRequest) Respond() {
1700	buf := newBuffer(0)
1701	r.respond(buf)
1702}
1703
1704// A SetxattrRequest asks to set an extended attribute associated with a file.
1705type SetxattrRequest struct {
1706	Header `json:"-"`
1707
1708	// Flags can make the request fail if attribute does/not already
1709	// exist. Unfortunately, the constants are platform-specific and
1710	// not exposed by Go1.2. Look for XATTR_CREATE, XATTR_REPLACE.
1711	//
1712	// TODO improve this later
1713	//
1714	// TODO XATTR_CREATE and exist -> EEXIST
1715	//
1716	// TODO XATTR_REPLACE and not exist -> ENODATA
1717	Flags uint32
1718
1719	// Deprecated: Not used, OS X remnant.
1720	Position uint32
1721
1722	Name  string
1723	Xattr []byte
1724}
1725
1726var _ Request = (*SetxattrRequest)(nil)
1727
1728func trunc(b []byte, max int) ([]byte, string) {
1729	if len(b) > max {
1730		return b[:max], "..."
1731	}
1732	return b, ""
1733}
1734
1735func (r *SetxattrRequest) String() string {
1736	xattr, tail := trunc(r.Xattr, 16)
1737	return fmt.Sprintf("Setxattr [%s] %q %q%s fl=%v", &r.Header, r.Name, xattr, tail, r.Flags)
1738}
1739
1740// Respond replies to the request, indicating that the extended attribute was set.
1741func (r *SetxattrRequest) Respond() {
1742	buf := newBuffer(0)
1743	r.respond(buf)
1744}
1745
1746// A LookupRequest asks to look up the given name in the directory named by r.Node.
1747type LookupRequest struct {
1748	Header `json:"-"`
1749	Name   string
1750}
1751
1752var _ Request = (*LookupRequest)(nil)
1753
1754func (r *LookupRequest) String() string {
1755	return fmt.Sprintf("Lookup [%s] %q", &r.Header, r.Name)
1756}
1757
1758// Respond replies to the request with the given response.
1759func (r *LookupRequest) Respond(resp *LookupResponse) {
1760	size := entryOutSize(r.Header.Conn.proto)
1761	buf := newBuffer(size)
1762	out := (*entryOut)(buf.alloc(size))
1763	out.Nodeid = uint64(resp.Node)
1764	out.Generation = resp.Generation
1765	out.EntryValid = uint64(resp.EntryValid / time.Second)
1766	out.EntryValidNsec = uint32(resp.EntryValid % time.Second / time.Nanosecond)
1767	out.AttrValid = uint64(resp.Attr.Valid / time.Second)
1768	out.AttrValidNsec = uint32(resp.Attr.Valid % time.Second / time.Nanosecond)
1769	resp.Attr.attr(&out.Attr, r.Header.Conn.proto)
1770	r.respond(buf)
1771}
1772
1773// A LookupResponse is the response to a LookupRequest.
1774type LookupResponse struct {
1775	Node       NodeID
1776	Generation uint64
1777	EntryValid time.Duration
1778	Attr       Attr
1779}
1780
1781func (r *LookupResponse) string() string {
1782	return fmt.Sprintf("%v gen=%d valid=%v attr={%v}", r.Node, r.Generation, r.EntryValid, r.Attr)
1783}
1784
1785func (r *LookupResponse) String() string {
1786	return fmt.Sprintf("Lookup %s", r.string())
1787}
1788
1789// An OpenRequest asks to open a file or directory
1790type OpenRequest struct {
1791	Header `json:"-"`
1792	Dir    bool // is this Opendir?
1793	Flags  OpenFlags
1794}
1795
1796var _ Request = (*OpenRequest)(nil)
1797
1798func (r *OpenRequest) String() string {
1799	return fmt.Sprintf("Open [%s] dir=%v fl=%v", &r.Header, r.Dir, r.Flags)
1800}
1801
1802// Respond replies to the request with the given response.
1803func (r *OpenRequest) Respond(resp *OpenResponse) {
1804	buf := newBuffer(unsafe.Sizeof(openOut{}))
1805	out := (*openOut)(buf.alloc(unsafe.Sizeof(openOut{})))
1806	out.Fh = uint64(resp.Handle)
1807	out.OpenFlags = uint32(resp.Flags)
1808	r.respond(buf)
1809}
1810
1811// A OpenResponse is the response to a OpenRequest.
1812type OpenResponse struct {
1813	Handle HandleID
1814	Flags  OpenResponseFlags
1815}
1816
1817func (r *OpenResponse) string() string {
1818	return fmt.Sprintf("%v fl=%v", r.Handle, r.Flags)
1819}
1820
1821func (r *OpenResponse) String() string {
1822	return fmt.Sprintf("Open %s", r.string())
1823}
1824
1825// A CreateRequest asks to create and open a file (not a directory).
1826type CreateRequest struct {
1827	Header `json:"-"`
1828	Name   string
1829	Flags  OpenFlags
1830	Mode   os.FileMode
1831	// Umask of the request.
1832	Umask os.FileMode
1833}
1834
1835var _ Request = (*CreateRequest)(nil)
1836
1837func (r *CreateRequest) String() string {
1838	return fmt.Sprintf("Create [%s] %q fl=%v mode=%v umask=%v", &r.Header, r.Name, r.Flags, r.Mode, r.Umask)
1839}
1840
1841// Respond replies to the request with the given response.
1842func (r *CreateRequest) Respond(resp *CreateResponse) {
1843	eSize := entryOutSize(r.Header.Conn.proto)
1844	buf := newBuffer(eSize + unsafe.Sizeof(openOut{}))
1845
1846	e := (*entryOut)(buf.alloc(eSize))
1847	e.Nodeid = uint64(resp.Node)
1848	e.Generation = resp.Generation
1849	e.EntryValid = uint64(resp.EntryValid / time.Second)
1850	e.EntryValidNsec = uint32(resp.EntryValid % time.Second / time.Nanosecond)
1851	e.AttrValid = uint64(resp.Attr.Valid / time.Second)
1852	e.AttrValidNsec = uint32(resp.Attr.Valid % time.Second / time.Nanosecond)
1853	resp.Attr.attr(&e.Attr, r.Header.Conn.proto)
1854
1855	o := (*openOut)(buf.alloc(unsafe.Sizeof(openOut{})))
1856	o.Fh = uint64(resp.Handle)
1857	o.OpenFlags = uint32(resp.Flags)
1858
1859	r.respond(buf)
1860}
1861
1862// A CreateResponse is the response to a CreateRequest.
1863// It describes the created node and opened handle.
1864type CreateResponse struct {
1865	LookupResponse
1866	OpenResponse
1867}
1868
1869func (r *CreateResponse) String() string {
1870	return fmt.Sprintf("Create {%s} {%s}", r.LookupResponse.string(), r.OpenResponse.string())
1871}
1872
1873// A MkdirRequest asks to create (but not open) a directory.
1874type MkdirRequest struct {
1875	Header `json:"-"`
1876	Name   string
1877	Mode   os.FileMode
1878	// Umask of the request.
1879	Umask os.FileMode
1880}
1881
1882var _ Request = (*MkdirRequest)(nil)
1883
1884func (r *MkdirRequest) String() string {
1885	return fmt.Sprintf("Mkdir [%s] %q mode=%v umask=%v", &r.Header, r.Name, r.Mode, r.Umask)
1886}
1887
1888// Respond replies to the request with the given response.
1889func (r *MkdirRequest) Respond(resp *MkdirResponse) {
1890	size := entryOutSize(r.Header.Conn.proto)
1891	buf := newBuffer(size)
1892	out := (*entryOut)(buf.alloc(size))
1893	out.Nodeid = uint64(resp.Node)
1894	out.Generation = resp.Generation
1895	out.EntryValid = uint64(resp.EntryValid / time.Second)
1896	out.EntryValidNsec = uint32(resp.EntryValid % time.Second / time.Nanosecond)
1897	out.AttrValid = uint64(resp.Attr.Valid / time.Second)
1898	out.AttrValidNsec = uint32(resp.Attr.Valid % time.Second / time.Nanosecond)
1899	resp.Attr.attr(&out.Attr, r.Header.Conn.proto)
1900	r.respond(buf)
1901}
1902
1903// A MkdirResponse is the response to a MkdirRequest.
1904type MkdirResponse struct {
1905	LookupResponse
1906}
1907
1908func (r *MkdirResponse) String() string {
1909	return fmt.Sprintf("Mkdir %v", r.LookupResponse.string())
1910}
1911
1912// A ReadRequest asks to read from an open file.
1913type ReadRequest struct {
1914	Header    `json:"-"`
1915	Dir       bool // is this Readdir?
1916	Handle    HandleID
1917	Offset    int64
1918	Size      int
1919	Flags     ReadFlags
1920	LockOwner LockOwner
1921	FileFlags OpenFlags
1922}
1923
1924var _ Request = (*ReadRequest)(nil)
1925
1926func (r *ReadRequest) String() string {
1927	return fmt.Sprintf("Read [%s] %v %d @%#x dir=%v fl=%v owner=%v ffl=%v", &r.Header, r.Handle, r.Size, r.Offset, r.Dir, r.Flags, r.LockOwner, r.FileFlags)
1928}
1929
1930// Respond replies to the request with the given response.
1931func (r *ReadRequest) Respond(resp *ReadResponse) {
1932	buf := newBuffer(uintptr(len(resp.Data)))
1933	buf = append(buf, resp.Data...)
1934	r.respond(buf)
1935}
1936
1937// A ReadResponse is the response to a ReadRequest.
1938type ReadResponse struct {
1939	Data []byte
1940}
1941
1942func (r *ReadResponse) String() string {
1943	return fmt.Sprintf("Read %d", len(r.Data))
1944}
1945
1946type jsonReadResponse struct {
1947	Len uint64
1948}
1949
1950func (r *ReadResponse) MarshalJSON() ([]byte, error) {
1951	j := jsonReadResponse{
1952		Len: uint64(len(r.Data)),
1953	}
1954	return json.Marshal(j)
1955}
1956
1957// A ReleaseRequest asks to release (close) an open file handle.
1958type ReleaseRequest struct {
1959	Header       `json:"-"`
1960	Dir          bool // is this Releasedir?
1961	Handle       HandleID
1962	Flags        OpenFlags // flags from OpenRequest
1963	ReleaseFlags ReleaseFlags
1964	LockOwner    LockOwner
1965}
1966
1967var _ Request = (*ReleaseRequest)(nil)
1968
1969func (r *ReleaseRequest) String() string {
1970	return fmt.Sprintf("Release [%s] %v fl=%v rfl=%v owner=%v", &r.Header, r.Handle, r.Flags, r.ReleaseFlags, r.LockOwner)
1971}
1972
1973// Respond replies to the request, indicating that the handle has been released.
1974func (r *ReleaseRequest) Respond() {
1975	buf := newBuffer(0)
1976	r.respond(buf)
1977}
1978
1979// A DestroyRequest is sent by the kernel when unmounting the file system.
1980// No more requests will be received after this one, but it should still be
1981// responded to.
1982type DestroyRequest struct {
1983	Header `json:"-"`
1984}
1985
1986var _ Request = (*DestroyRequest)(nil)
1987
1988func (r *DestroyRequest) String() string {
1989	return fmt.Sprintf("Destroy [%s]", &r.Header)
1990}
1991
1992// Respond replies to the request.
1993func (r *DestroyRequest) Respond() {
1994	buf := newBuffer(0)
1995	r.respond(buf)
1996}
1997
1998// A ForgetRequest is sent by the kernel when forgetting about r.Node
1999// as returned by r.N lookup requests.
2000type ForgetRequest struct {
2001	Header `json:"-"`
2002	N      uint64
2003}
2004
2005var _ Request = (*ForgetRequest)(nil)
2006
2007func (r *ForgetRequest) String() string {
2008	return fmt.Sprintf("Forget [%s] %d", &r.Header, r.N)
2009}
2010
2011// Respond replies to the request, indicating that the forgetfulness has been recorded.
2012func (r *ForgetRequest) Respond() {
2013	// Don't reply to forget messages.
2014	r.noResponse()
2015}
2016
2017type BatchForgetItem struct {
2018	NodeID NodeID
2019	N      uint64
2020}
2021
2022type BatchForgetRequest struct {
2023	Header `json:"-"`
2024	Forget []BatchForgetItem
2025}
2026
2027var _ Request = (*BatchForgetRequest)(nil)
2028
2029func (r *BatchForgetRequest) String() string {
2030	b := new(strings.Builder)
2031	fmt.Fprintf(b, "BatchForget [%s]", &r.Header)
2032	if len(r.Forget) == 0 {
2033		b.WriteString(" empty")
2034	} else {
2035		for _, item := range r.Forget {
2036			fmt.Fprintf(b, " %dx%d", item.NodeID, item.N)
2037		}
2038	}
2039	return b.String()
2040}
2041
2042// Respond replies to the request, indicating that the forgetfulness has been recorded.
2043func (r *BatchForgetRequest) Respond() {
2044	// Don't reply to forget messages.
2045	r.noResponse()
2046}
2047
2048// A Dirent represents a single directory entry.
2049type Dirent struct {
2050	// Inode this entry names.
2051	Inode uint64
2052
2053	// Type of the entry, for example DT_File.
2054	//
2055	// Setting this is optional. The zero value (DT_Unknown) means
2056	// callers will just need to do a Getattr when the type is
2057	// needed. Providing a type can speed up operations
2058	// significantly.
2059	Type DirentType
2060
2061	// Name of the entry
2062	Name string
2063}
2064
2065// Type of an entry in a directory listing.
2066type DirentType uint32
2067
2068const (
2069	// These don't quite match os.FileMode; especially there's an
2070	// explicit unknown, instead of zero value meaning file. They
2071	// are also not quite syscall.DT_*; nothing says the FUSE
2072	// protocol follows those, and even if they were, we don't
2073	// want each fs to fiddle with syscall.
2074
2075	// The shift by 12 is hardcoded in the FUSE userspace
2076	// low-level C library, so it's safe here.
2077
2078	DT_Unknown DirentType = 0
2079	DT_Socket  DirentType = syscall.S_IFSOCK >> 12
2080	DT_Link    DirentType = syscall.S_IFLNK >> 12
2081	DT_File    DirentType = syscall.S_IFREG >> 12
2082	DT_Block   DirentType = syscall.S_IFBLK >> 12
2083	DT_Dir     DirentType = syscall.S_IFDIR >> 12
2084	DT_Char    DirentType = syscall.S_IFCHR >> 12
2085	DT_FIFO    DirentType = syscall.S_IFIFO >> 12
2086)
2087
2088func (t DirentType) String() string {
2089	switch t {
2090	case DT_Unknown:
2091		return "unknown"
2092	case DT_Socket:
2093		return "socket"
2094	case DT_Link:
2095		return "link"
2096	case DT_File:
2097		return "file"
2098	case DT_Block:
2099		return "block"
2100	case DT_Dir:
2101		return "dir"
2102	case DT_Char:
2103		return "char"
2104	case DT_FIFO:
2105		return "fifo"
2106	}
2107	return "invalid"
2108}
2109
2110// AppendDirent appends the encoded form of a directory entry to data
2111// and returns the resulting slice.
2112func AppendDirent(data []byte, dir Dirent) []byte {
2113	de := dirent{
2114		Ino:     dir.Inode,
2115		Namelen: uint32(len(dir.Name)),
2116		Type:    uint32(dir.Type),
2117	}
2118	de.Off = uint64(len(data) + direntSize + (len(dir.Name)+7)&^7)
2119	data = append(data, (*[direntSize]byte)(unsafe.Pointer(&de))[:]...)
2120	data = append(data, dir.Name...)
2121	n := direntSize + uintptr(len(dir.Name))
2122	if n%8 != 0 {
2123		var pad [8]byte
2124		data = append(data, pad[:8-n%8]...)
2125	}
2126	return data
2127}
2128
2129// A WriteRequest asks to write to an open file.
2130type WriteRequest struct {
2131	Header
2132	Handle    HandleID
2133	Offset    int64
2134	Data      []byte
2135	Flags     WriteFlags
2136	LockOwner LockOwner
2137	FileFlags OpenFlags
2138}
2139
2140var _ Request = (*WriteRequest)(nil)
2141
2142func (r *WriteRequest) String() string {
2143	return fmt.Sprintf("Write [%s] %v %d @%d fl=%v owner=%v ffl=%v", &r.Header, r.Handle, len(r.Data), r.Offset, r.Flags, r.LockOwner, r.FileFlags)
2144}
2145
2146type jsonWriteRequest struct {
2147	Handle HandleID
2148	Offset int64
2149	Len    uint64
2150	Flags  WriteFlags
2151}
2152
2153func (r *WriteRequest) MarshalJSON() ([]byte, error) {
2154	j := jsonWriteRequest{
2155		Handle: r.Handle,
2156		Offset: r.Offset,
2157		Len:    uint64(len(r.Data)),
2158		Flags:  r.Flags,
2159	}
2160	return json.Marshal(j)
2161}
2162
2163// Respond replies to the request with the given response.
2164func (r *WriteRequest) Respond(resp *WriteResponse) {
2165	buf := newBuffer(unsafe.Sizeof(writeOut{}))
2166	out := (*writeOut)(buf.alloc(unsafe.Sizeof(writeOut{})))
2167	out.Size = uint32(resp.Size)
2168	r.respond(buf)
2169}
2170
2171// A WriteResponse replies to a write indicating how many bytes were written.
2172type WriteResponse struct {
2173	Size int
2174}
2175
2176func (r *WriteResponse) String() string {
2177	return fmt.Sprintf("Write %d", r.Size)
2178}
2179
2180// A SetattrRequest asks to change one or more attributes associated with a file,
2181// as indicated by Valid.
2182type SetattrRequest struct {
2183	Header `json:"-"`
2184	Valid  SetattrValid
2185	Handle HandleID
2186	Size   uint64
2187	Atime  time.Time
2188	Mtime  time.Time
2189	// Mode is the file mode to set (when valid).
2190	//
2191	// The type of the node (as in os.ModeType, os.ModeDir etc) is not
2192	// guaranteed to be sent by the kernel, in which case
2193	// os.ModeIrregular will be set.
2194	Mode os.FileMode
2195	Uid  uint32
2196	Gid  uint32
2197
2198	// Deprecated: Not used, OS X remnant.
2199	Bkuptime time.Time
2200	// Deprecated: Not used, OS X remnant.
2201	Chgtime time.Time
2202	// Deprecated: Not used, OS X remnant.
2203	Crtime time.Time
2204	// Deprecated: Not used, OS X remnant.
2205	Flags uint32
2206}
2207
2208var _ Request = (*SetattrRequest)(nil)
2209
2210func (r *SetattrRequest) String() string {
2211	var buf bytes.Buffer
2212	fmt.Fprintf(&buf, "Setattr [%s]", &r.Header)
2213	if r.Valid.Mode() {
2214		fmt.Fprintf(&buf, " mode=%v", r.Mode)
2215	}
2216	if r.Valid.Uid() {
2217		fmt.Fprintf(&buf, " uid=%d", r.Uid)
2218	}
2219	if r.Valid.Gid() {
2220		fmt.Fprintf(&buf, " gid=%d", r.Gid)
2221	}
2222	if r.Valid.Size() {
2223		fmt.Fprintf(&buf, " size=%d", r.Size)
2224	}
2225	if r.Valid.Atime() {
2226		fmt.Fprintf(&buf, " atime=%v", r.Atime)
2227	}
2228	if r.Valid.AtimeNow() {
2229		fmt.Fprintf(&buf, " atime=now")
2230	}
2231	if r.Valid.Mtime() {
2232		fmt.Fprintf(&buf, " mtime=%v", r.Mtime)
2233	}
2234	if r.Valid.MtimeNow() {
2235		fmt.Fprintf(&buf, " mtime=now")
2236	}
2237	if r.Valid.Handle() {
2238		fmt.Fprintf(&buf, " handle=%v", r.Handle)
2239	} else {
2240		fmt.Fprintf(&buf, " handle=INVALID-%v", r.Handle)
2241	}
2242	if r.Valid.LockOwner() {
2243		fmt.Fprintf(&buf, " lockowner")
2244	}
2245	return buf.String()
2246}
2247
2248// Respond replies to the request with the given response,
2249// giving the updated attributes.
2250func (r *SetattrRequest) Respond(resp *SetattrResponse) {
2251	size := attrOutSize(r.Header.Conn.proto)
2252	buf := newBuffer(size)
2253	out := (*attrOut)(buf.alloc(size))
2254	out.AttrValid = uint64(resp.Attr.Valid / time.Second)
2255	out.AttrValidNsec = uint32(resp.Attr.Valid % time.Second / time.Nanosecond)
2256	resp.Attr.attr(&out.Attr, r.Header.Conn.proto)
2257	r.respond(buf)
2258}
2259
2260// A SetattrResponse is the response to a SetattrRequest.
2261type SetattrResponse struct {
2262	Attr Attr // file attributes
2263}
2264
2265func (r *SetattrResponse) String() string {
2266	return fmt.Sprintf("Setattr %v", r.Attr)
2267}
2268
2269// A FlushRequest asks for the current state of an open file to be flushed
2270// to storage, as when a file descriptor is being closed.  A single opened Handle
2271// may receive multiple FlushRequests over its lifetime.
2272type FlushRequest struct {
2273	Header `json:"-"`
2274	Handle HandleID
2275	// Deprecated: Unused since 2006.
2276	Flags     uint32
2277	LockOwner LockOwner
2278}
2279
2280var _ Request = (*FlushRequest)(nil)
2281
2282func (r *FlushRequest) String() string {
2283	return fmt.Sprintf("Flush [%s] %v fl=%#x owner=%v", &r.Header, r.Handle, r.Flags, r.LockOwner)
2284}
2285
2286// Respond replies to the request, indicating that the flush succeeded.
2287func (r *FlushRequest) Respond() {
2288	buf := newBuffer(0)
2289	r.respond(buf)
2290}
2291
2292// A RemoveRequest asks to remove a file or directory from the
2293// directory r.Node.
2294type RemoveRequest struct {
2295	Header `json:"-"`
2296	Name   string // name of the entry to remove
2297	Dir    bool   // is this rmdir?
2298}
2299
2300var _ Request = (*RemoveRequest)(nil)
2301
2302func (r *RemoveRequest) String() string {
2303	return fmt.Sprintf("Remove [%s] %q dir=%v", &r.Header, r.Name, r.Dir)
2304}
2305
2306// Respond replies to the request, indicating that the file was removed.
2307func (r *RemoveRequest) Respond() {
2308	buf := newBuffer(0)
2309	r.respond(buf)
2310}
2311
2312// A SymlinkRequest is a request to create a symlink making NewName point to Target.
2313type SymlinkRequest struct {
2314	Header          `json:"-"`
2315	NewName, Target string
2316}
2317
2318var _ Request = (*SymlinkRequest)(nil)
2319
2320func (r *SymlinkRequest) String() string {
2321	return fmt.Sprintf("Symlink [%s] from %q to target %q", &r.Header, r.NewName, r.Target)
2322}
2323
2324// Respond replies to the request, indicating that the symlink was created.
2325func (r *SymlinkRequest) Respond(resp *SymlinkResponse) {
2326	size := entryOutSize(r.Header.Conn.proto)
2327	buf := newBuffer(size)
2328	out := (*entryOut)(buf.alloc(size))
2329	out.Nodeid = uint64(resp.Node)
2330	out.Generation = resp.Generation
2331	out.EntryValid = uint64(resp.EntryValid / time.Second)
2332	out.EntryValidNsec = uint32(resp.EntryValid % time.Second / time.Nanosecond)
2333	out.AttrValid = uint64(resp.Attr.Valid / time.Second)
2334	out.AttrValidNsec = uint32(resp.Attr.Valid % time.Second / time.Nanosecond)
2335	resp.Attr.attr(&out.Attr, r.Header.Conn.proto)
2336	r.respond(buf)
2337}
2338
2339// A SymlinkResponse is the response to a SymlinkRequest.
2340type SymlinkResponse struct {
2341	LookupResponse
2342}
2343
2344func (r *SymlinkResponse) String() string {
2345	return fmt.Sprintf("Symlink %v", r.LookupResponse.string())
2346}
2347
2348// A ReadlinkRequest is a request to read a symlink's target.
2349type ReadlinkRequest struct {
2350	Header `json:"-"`
2351}
2352
2353var _ Request = (*ReadlinkRequest)(nil)
2354
2355func (r *ReadlinkRequest) String() string {
2356	return fmt.Sprintf("Readlink [%s]", &r.Header)
2357}
2358
2359func (r *ReadlinkRequest) Respond(target string) {
2360	buf := newBuffer(uintptr(len(target)))
2361	buf = append(buf, target...)
2362	r.respond(buf)
2363}
2364
2365// A LinkRequest is a request to create a hard link.
2366type LinkRequest struct {
2367	Header  `json:"-"`
2368	OldNode NodeID
2369	NewName string
2370}
2371
2372var _ Request = (*LinkRequest)(nil)
2373
2374func (r *LinkRequest) String() string {
2375	return fmt.Sprintf("Link [%s] node %d to %q", &r.Header, r.OldNode, r.NewName)
2376}
2377
2378func (r *LinkRequest) Respond(resp *LookupResponse) {
2379	size := entryOutSize(r.Header.Conn.proto)
2380	buf := newBuffer(size)
2381	out := (*entryOut)(buf.alloc(size))
2382	out.Nodeid = uint64(resp.Node)
2383	out.Generation = resp.Generation
2384	out.EntryValid = uint64(resp.EntryValid / time.Second)
2385	out.EntryValidNsec = uint32(resp.EntryValid % time.Second / time.Nanosecond)
2386	out.AttrValid = uint64(resp.Attr.Valid / time.Second)
2387	out.AttrValidNsec = uint32(resp.Attr.Valid % time.Second / time.Nanosecond)
2388	resp.Attr.attr(&out.Attr, r.Header.Conn.proto)
2389	r.respond(buf)
2390}
2391
2392// A RenameRequest is a request to rename a file.
2393type RenameRequest struct {
2394	Header           `json:"-"`
2395	NewDir           NodeID
2396	OldName, NewName string
2397}
2398
2399var _ Request = (*RenameRequest)(nil)
2400
2401func (r *RenameRequest) String() string {
2402	return fmt.Sprintf("Rename [%s] from %q to dirnode %v %q", &r.Header, r.OldName, r.NewDir, r.NewName)
2403}
2404
2405func (r *RenameRequest) Respond() {
2406	buf := newBuffer(0)
2407	r.respond(buf)
2408}
2409
2410type MknodRequest struct {
2411	Header `json:"-"`
2412	Name   string
2413	Mode   os.FileMode
2414	Rdev   uint32
2415	// Umask of the request.
2416	Umask os.FileMode
2417}
2418
2419var _ Request = (*MknodRequest)(nil)
2420
2421func (r *MknodRequest) String() string {
2422	return fmt.Sprintf("Mknod [%s] Name %q mode=%v umask=%v rdev=%d", &r.Header, r.Name, r.Mode, r.Umask, r.Rdev)
2423}
2424
2425func (r *MknodRequest) Respond(resp *LookupResponse) {
2426	size := entryOutSize(r.Header.Conn.proto)
2427	buf := newBuffer(size)
2428	out := (*entryOut)(buf.alloc(size))
2429	out.Nodeid = uint64(resp.Node)
2430	out.Generation = resp.Generation
2431	out.EntryValid = uint64(resp.EntryValid / time.Second)
2432	out.EntryValidNsec = uint32(resp.EntryValid % time.Second / time.Nanosecond)
2433	out.AttrValid = uint64(resp.Attr.Valid / time.Second)
2434	out.AttrValidNsec = uint32(resp.Attr.Valid % time.Second / time.Nanosecond)
2435	resp.Attr.attr(&out.Attr, r.Header.Conn.proto)
2436	r.respond(buf)
2437}
2438
2439type FsyncRequest struct {
2440	Header `json:"-"`
2441	Handle HandleID
2442	// TODO bit 1 is datasync, not well documented upstream
2443	Flags uint32
2444	Dir   bool
2445}
2446
2447var _ Request = (*FsyncRequest)(nil)
2448
2449func (r *FsyncRequest) String() string {
2450	return fmt.Sprintf("Fsync [%s] Handle %v Flags %v", &r.Header, r.Handle, r.Flags)
2451}
2452
2453func (r *FsyncRequest) Respond() {
2454	buf := newBuffer(0)
2455	r.respond(buf)
2456}
2457
2458// An InterruptRequest is a request to interrupt another pending request. The
2459// response to that request should return an error status of EINTR.
2460type InterruptRequest struct {
2461	Header `json:"-"`
2462	IntrID RequestID // ID of the request to be interrupt.
2463}
2464
2465var _ Request = (*InterruptRequest)(nil)
2466
2467func (r *InterruptRequest) Respond() {
2468	// nothing to do here
2469	r.noResponse()
2470}
2471
2472func (r *InterruptRequest) String() string {
2473	return fmt.Sprintf("Interrupt [%s] ID %v", &r.Header, r.IntrID)
2474}
2475
2476// Deprecated: Not used, OS X remnant.
2477type ExchangeDataRequest struct {
2478	Header           `json:"-"`
2479	OldDir, NewDir   NodeID
2480	OldName, NewName string
2481}
2482
2483var _ Request = (*ExchangeDataRequest)(nil)
2484
2485func (r *ExchangeDataRequest) String() string {
2486	// TODO options
2487	return fmt.Sprintf("ExchangeData [%s] %v %q and %v %q", &r.Header, r.OldDir, r.OldName, r.NewDir, r.NewName)
2488}
2489
2490func (r *ExchangeDataRequest) Respond() {
2491	buf := newBuffer(0)
2492	r.respond(buf)
2493}
2494
2495// NotifyReply is a response to an earlier notification. It behaves
2496// like a Request, but is not really a request expecting a response.
2497type NotifyReply struct {
2498	Header `json:"-"`
2499	msg    *message
2500}
2501
2502var _ Request = (*NotifyReply)(nil)
2503
2504func (r *NotifyReply) String() string {
2505	return fmt.Sprintf("NotifyReply [%s]", &r.Header)
2506}
2507
2508type PollRequest struct {
2509	Header `json:"-"`
2510	Handle HandleID
2511	kh     uint64
2512	Flags  PollFlags
2513	// Events is a bitmap of events of interest.
2514	//
2515	// This field is only set for FUSE protocol 7.21 and later.
2516	Events PollEvents
2517}
2518
2519var _ Request = (*PollRequest)(nil)
2520
2521func (r *PollRequest) String() string {
2522	return fmt.Sprintf("Poll [%s] %v kh=%v fl=%v ev=%v", &r.Header, r.Handle, r.kh, r.Flags, r.Events)
2523}
2524
2525type PollWakeup struct {
2526	kh uint64
2527}
2528
2529func (p PollWakeup) String() string {
2530	return fmt.Sprintf("PollWakeup{kh=%d}", p.kh)
2531}
2532
2533// Wakeup returns information that can be used later to wake up file
2534// system clients polling a Handle or a Node.
2535//
2536// ok is false if wakeups are not requested for this poll.
2537//
2538// Do not retain PollWakeup past the lifetime of the Handle or Node.
2539func (r *PollRequest) Wakeup() (_ PollWakeup, ok bool) {
2540	if r.Flags&PollScheduleNotify == 0 {
2541		return PollWakeup{}, false
2542	}
2543	p := PollWakeup{
2544		kh: r.kh,
2545	}
2546	return p, true
2547}
2548
2549func (r *PollRequest) Respond(resp *PollResponse) {
2550	buf := newBuffer(unsafe.Sizeof(pollOut{}))
2551	out := (*pollOut)(buf.alloc(unsafe.Sizeof(pollOut{})))
2552	out.REvents = uint32(resp.REvents)
2553	r.respond(buf)
2554}
2555
2556type PollResponse struct {
2557	REvents PollEvents
2558}
2559
2560func (r *PollResponse) String() string {
2561	return fmt.Sprintf("Poll revents=%v", r.REvents)
2562}
2563
2564type FileLock struct {
2565	Start uint64
2566	End   uint64
2567	Type  LockType
2568	PID   int32
2569}
2570
2571// LockRequest asks to try acquire a byte range lock on a node. The
2572// response should be immediate, do not wait to obtain lock.
2573//
2574// Unlocking can be
2575//
2576//     - explicit with UnlockRequest
2577//     - for flock: implicit on final close (ReleaseRequest.ReleaseFlags
2578//       has ReleaseFlockUnlock set)
2579//     - for POSIX locks: implicit on any close (FlushRequest)
2580//     - for Open File Description locks: implicit on final close
2581//       (no LockOwner observed as of 2020-04)
2582//
2583// See LockFlags to know which kind of a lock is being requested. (As
2584// of 2020-04, Open File Descriptor locks are indistinguishable from
2585// POSIX. This means programs using those locks will likely misbehave
2586// when closing FDs on FUSE-based distributed filesystems, as the
2587// filesystem has no better knowledge than to follow POSIX locking
2588// rules and release the global lock too early.)
2589//
2590// Most of the other differences between flock (BSD) and POSIX (fcntl
2591// F_SETLK) locks are relevant only to the caller, not the filesystem.
2592// FUSE always sees ranges, and treats flock whole-file locks as
2593// requests for the maximum byte range. Filesystems should do the
2594// same, as this provides a forwards compatibility path to
2595// Linux-native Open file description locks.
2596//
2597// To enable locking events in FUSE, pass LockingFlock() and/or
2598// LockingPOSIX() to Mount.
2599//
2600// See also LockWaitRequest.
2601type LockRequest struct {
2602	Header
2603	Handle HandleID
2604	// LockOwner is a unique identifier for the originating client, to
2605	// identify locks.
2606	LockOwner LockOwner
2607	Lock      FileLock
2608	LockFlags LockFlags
2609}
2610
2611var _ Request = (*LockRequest)(nil)
2612
2613func (r *LockRequest) String() string {
2614	return fmt.Sprintf("Lock [%s] %v owner=%v range=%d..%d type=%v pid=%v fl=%v", &r.Header, r.Handle, r.LockOwner, r.Lock.Start, r.Lock.End, r.Lock.Type, r.Lock.PID, r.LockFlags)
2615}
2616
2617func (r *LockRequest) Respond() {
2618	buf := newBuffer(0)
2619	r.respond(buf)
2620}
2621
2622// LockWaitRequest asks to acquire a byte range lock on a node,
2623// delaying response until lock can be obtained (or the request is
2624// interrupted).
2625//
2626// See LockRequest. LockWaitRequest can be converted to a LockRequest.
2627type LockWaitRequest LockRequest
2628
2629var _ LockRequest = LockRequest(LockWaitRequest{})
2630
2631var _ Request = (*LockWaitRequest)(nil)
2632
2633func (r *LockWaitRequest) String() string {
2634	return fmt.Sprintf("LockWait [%s] %v owner=%v range=%d..%d type=%v pid=%v fl=%v", &r.Header, r.Handle, r.LockOwner, r.Lock.Start, r.Lock.End, r.Lock.Type, r.Lock.PID, r.LockFlags)
2635}
2636
2637func (r *LockWaitRequest) Respond() {
2638	buf := newBuffer(0)
2639	r.respond(buf)
2640}
2641
2642// UnlockRequest asks to release a lock on a byte range on a node.
2643//
2644// UnlockRequests always have Lock.Type == LockUnlock.
2645//
2646// See LockRequest. UnlockRequest can be converted to a LockRequest.
2647type UnlockRequest LockRequest
2648
2649var _ LockRequest = LockRequest(UnlockRequest{})
2650
2651var _ Request = (*UnlockRequest)(nil)
2652
2653func (r *UnlockRequest) String() string {
2654	return fmt.Sprintf("Unlock [%s] %v owner=%v range=%d..%d type=%v pid=%v fl=%v", &r.Header, r.Handle, r.LockOwner, r.Lock.Start, r.Lock.End, r.Lock.Type, r.Lock.PID, r.LockFlags)
2655}
2656
2657func (r *UnlockRequest) Respond() {
2658	buf := newBuffer(0)
2659	r.respond(buf)
2660}
2661
2662// QueryLockRequest queries the lock status.
2663//
2664// If the lock could be placed, set response Lock.Type to
2665// unix.F_UNLCK.
2666//
2667// If there are conflicting locks, the response should describe one of
2668// them. For Open File Description locks, set PID to -1. (This is
2669// probably also the sane behavior for locks held by remote parties.)
2670type QueryLockRequest struct {
2671	Header
2672	Handle    HandleID
2673	LockOwner LockOwner
2674	Lock      FileLock
2675	LockFlags LockFlags
2676}
2677
2678var _ Request = (*QueryLockRequest)(nil)
2679
2680func (r *QueryLockRequest) String() string {
2681	return fmt.Sprintf("QueryLock [%s] %v owner=%v range=%d..%d type=%v pid=%v fl=%v", &r.Header, r.Handle, r.LockOwner, r.Lock.Start, r.Lock.End, r.Lock.Type, r.Lock.PID, r.LockFlags)
2682}
2683
2684// Respond replies to the request with the given response.
2685func (r *QueryLockRequest) Respond(resp *QueryLockResponse) {
2686	buf := newBuffer(unsafe.Sizeof(lkOut{}))
2687	out := (*lkOut)(buf.alloc(unsafe.Sizeof(lkOut{})))
2688	out.Lk = fileLock{
2689		Start: resp.Lock.Start,
2690		End:   resp.Lock.End,
2691		Type:  uint32(resp.Lock.Type),
2692		PID:   uint32(resp.Lock.PID),
2693	}
2694	r.respond(buf)
2695}
2696
2697type QueryLockResponse struct {
2698	Lock FileLock
2699}
2700
2701func (r *QueryLockResponse) String() string {
2702	return fmt.Sprintf("QueryLock range=%d..%d type=%v pid=%v", r.Lock.Start, r.Lock.End, r.Lock.Type, r.Lock.PID)
2703}
2704