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