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