github.com/olivere/camlistore@v0.0.0-20140121221811-1b7ac2da0199/third_party/code.google.com/p/rsc/fuse/fuse.go (about)

     1  // +build linux darwin
     2  
     3  // Copyright 2011 The Go Authors.  All rights reserved.
     4  // Use of this source code is governed by a BSD-style
     5  // license that can be found in the LICENSE file.
     6  
     7  // Adapted from Plan 9 from User Space's src/cmd/9pfuse/fuse.c,
     8  // which carries this notice:
     9  //
    10  // The files in this directory are subject to the following license.
    11  //
    12  // The author of this software is Russ Cox.
    13  //
    14  //         Copyright (c) 2006 Russ Cox
    15  //
    16  // Permission to use, copy, modify, and distribute this software for any
    17  // purpose without fee is hereby granted, provided that this entire notice
    18  // is included in all copies of any software which is or includes a copy
    19  // or modification of this software and in all copies of the supporting
    20  // documentation for such software.
    21  //
    22  // THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
    23  // WARRANTY.  IN PARTICULAR, THE AUTHOR MAKES NO REPRESENTATION OR WARRANTY
    24  // OF ANY KIND CONCERNING THE MERCHANTABILITY OF THIS SOFTWARE OR ITS
    25  // FITNESS FOR ANY PARTICULAR PURPOSE.
    26  
    27  // Package fuse enables writing FUSE file systems on FreeBSD, Linux, and OS X.
    28  //
    29  // On OS X, it requires OSXFUSE (http://osxfuse.github.com/).
    30  //
    31  // There are two approaches to writing a FUSE file system.  The first is to speak
    32  // the low-level message protocol, reading from a Conn using ReadRequest and
    33  // writing using the various Respond methods.  This approach is closest to
    34  // the actual interaction with the kernel and can be the simplest one in contexts
    35  // such as protocol translators.
    36  //
    37  // Servers of synthesized file systems tend to share common bookkeeping
    38  // abstracted away by the second approach, which is to call the Conn's
    39  // Serve method to serve the FUSE protocol using
    40  // an implementation of the service methods in the interfaces
    41  // FS (file system), Node (file or directory), and Handle (opened file or directory).
    42  // There are a daunting number of such methods that can be written,
    43  // but few are required.
    44  // The specific methods are described in the documentation for those interfaces.
    45  //
    46  // The hellofs subdirectory contains a simple illustration of the ServeFS approach.
    47  //
    48  // Service Methods
    49  //
    50  // The required and optional methods for the FS, Node, and Handle interfaces
    51  // have the general form
    52  //
    53  //	Op(req *OpRequest, resp *OpResponse, intr Intr) Error
    54  //
    55  // where Op is the name of a FUSE operation.  Op reads request parameters
    56  // from req and writes results to resp.  An operation whose only result is
    57  // the error result omits the resp parameter.  Multiple goroutines may call
    58  // service methods simultaneously; the methods being called are responsible
    59  // for appropriate synchronization.
    60  //
    61  // Interrupted Operations
    62  //
    63  // In some file systems, some operations
    64  // may take an undetermined amount of time.  For example, a Read waiting for
    65  // a network message or a matching Write might wait indefinitely.  If the request
    66  // is cancelled and no longer needed, the package will close intr, a chan struct{}.
    67  // Blocking operations should select on a receive from intr and attempt to
    68  // abort the operation early if the receive succeeds (meaning the channel is closed).
    69  // To indicate that the operation failed because it was aborted, return fuse.EINTR.
    70  //
    71  // If an operation does not block for an indefinite amount of time, the intr parameter
    72  // can be ignored.
    73  //
    74  // Authentication
    75  //
    76  // All requests types embed a Header, meaning that the method can inspect
    77  // req.Pid, req.Uid, and req.Gid as necessary to implement permission checking.
    78  // Alternately, XXX.
    79  //
    80  // Mount Options
    81  //
    82  // XXX
    83  //
    84  package fuse
    85  
    86  // BUG(rsc): The mount code for FreeBSD has not been written yet.
    87  
    88  import (
    89  	"bytes"
    90  	"errors"
    91  	"fmt"
    92  	"io"
    93  	"log"
    94  	"os"
    95  	"runtime"
    96  	"sync"
    97  	"syscall"
    98  	"time"
    99  	"unsafe"
   100  )
   101  
   102  // A Conn represents a connection to a mounted FUSE file system.
   103  type Conn struct {
   104  	fd  int
   105  	buf []byte
   106  	wio sync.Mutex
   107  
   108  	serveConn
   109  }
   110  
   111  // Mount mounts a new FUSE connection on the named directory
   112  // and returns a connection for reading and writing FUSE messages.
   113  func Mount(dir string) (*Conn, error) {
   114  	// TODO(rsc): mount options (...string?)
   115  	fd, errstr := mount(dir)
   116  	if errstr != "" {
   117  		return nil, errors.New(errstr)
   118  	}
   119  
   120  	return &Conn{fd: fd}, nil
   121  }
   122  
   123  // A Request represents a single FUSE request received from the kernel.
   124  // Use a type switch to determine the specific kind.
   125  // A request of unrecognized type will have concrete type *Header.
   126  type Request interface {
   127  	// Hdr returns the Header associated with this request.
   128  	Hdr() *Header
   129  
   130  	// RespondError responds to the request with the given error.
   131  	RespondError(Error)
   132  
   133  	String() string
   134  
   135  	// handle returns the HandleID for the request, or 0.
   136  	handle() HandleID
   137  }
   138  
   139  // A RequestID identifies an active FUSE request.
   140  type RequestID uint64
   141  
   142  // A NodeID is a number identifying a directory or file.
   143  // It must be unique among IDs returned in LookupResponses
   144  // that have not yet been forgotten by ForgetRequests.
   145  type NodeID uint64
   146  
   147  // A HandleID is a number identifying an open directory or file.
   148  // It only needs to be unique while the directory or file is open.
   149  type HandleID uint64
   150  
   151  // The RootID identifies the root directory of a FUSE file system.
   152  const RootID NodeID = rootID
   153  
   154  // A Header describes the basic information sent in every request.
   155  type Header struct {
   156  	Conn *Conn     // connection this request was received on
   157  	ID   RequestID // unique ID for request
   158  	Node NodeID    // file or directory the request is about
   159  	Uid  uint32    // user ID of process making request
   160  	Gid  uint32    // group ID of process making request
   161  	Pid  uint32    // process ID of process making request
   162  }
   163  
   164  func (h *Header) String() string {
   165  	return fmt.Sprintf("ID=%#x Node=%#x Uid=%d Gid=%d Pid=%d", h.ID, h.Node, h.Uid, h.Gid, h.Pid)
   166  }
   167  
   168  func (h *Header) Hdr() *Header {
   169  	return h
   170  }
   171  
   172  func (h *Header) handle() HandleID {
   173  	return 0
   174  }
   175  
   176  // An Error is a FUSE error.
   177  type Error interface {
   178  	errno() int32
   179  }
   180  
   181  const (
   182  	// ENOSYS indicates that the call is not supported.
   183  	ENOSYS = Errno(syscall.ENOSYS)
   184  
   185  	// ESTALE is used by Serve to respond to violations of the FUSE protocol.
   186  	ESTALE = Errno(syscall.ESTALE)
   187  
   188  	ENOENT = Errno(syscall.ENOENT)
   189  	EIO    = Errno(syscall.EIO)
   190  	EPERM  = Errno(syscall.EPERM)
   191  )
   192  
   193  type errno int
   194  
   195  func (e errno) errno() int32 {
   196  	return int32(e)
   197  }
   198  
   199  // Errno implements Error using a syscall.Errno.
   200  type Errno syscall.Errno
   201  
   202  func (e Errno) errno() int32 {
   203  	return int32(e)
   204  }
   205  
   206  func (e Errno) String() string {
   207  	return syscall.Errno(e).Error()
   208  }
   209  
   210  func (h *Header) RespondError(err Error) {
   211  	// FUSE uses negative errors!
   212  	// TODO: File bug report against OSXFUSE: positive error causes kernel panic.
   213  	out := &outHeader{Error: -err.errno(), Unique: uint64(h.ID)}
   214  	h.Conn.respond(out, unsafe.Sizeof(*out))
   215  }
   216  
   217  var maxWrite = syscall.Getpagesize()
   218  var bufSize = 4096 + maxWrite
   219  
   220  // a message represents the bytes of a single FUSE message
   221  type message struct {
   222  	conn *Conn
   223  	buf  []byte    // all bytes
   224  	hdr  *inHeader // header
   225  	off  int       // offset for reading additional fields
   226  }
   227  
   228  func newMessage(c *Conn) *message {
   229  	m := &message{conn: c, buf: make([]byte, bufSize)}
   230  	m.hdr = (*inHeader)(unsafe.Pointer(&m.buf[0]))
   231  	return m
   232  }
   233  
   234  func (m *message) len() uintptr {
   235  	return uintptr(len(m.buf) - m.off)
   236  }
   237  
   238  func (m *message) data() unsafe.Pointer {
   239  	var p unsafe.Pointer
   240  	if m.off < len(m.buf) {
   241  		p = unsafe.Pointer(&m.buf[m.off])
   242  	}
   243  	return p
   244  }
   245  
   246  func (m *message) bytes() []byte {
   247  	return m.buf[m.off:]
   248  }
   249  
   250  func (m *message) Header() Header {
   251  	h := m.hdr
   252  	return Header{Conn: m.conn, ID: RequestID(h.Unique), Node: NodeID(h.Nodeid), Uid: h.Uid, Gid: h.Gid, Pid: h.Pid}
   253  }
   254  
   255  // fileMode returns a Go os.FileMode from a Unix mode.
   256  func fileMode(unixMode uint32) os.FileMode {
   257  	mode := os.FileMode(unixMode & 0777)
   258  	switch unixMode & syscall.S_IFMT {
   259  	case syscall.S_IFREG:
   260  		// nothing
   261  	case syscall.S_IFDIR:
   262  		mode |= os.ModeDir
   263  	case syscall.S_IFCHR:
   264  		mode |= os.ModeCharDevice | os.ModeDevice
   265  	case syscall.S_IFBLK:
   266  		mode |= os.ModeDevice
   267  	case syscall.S_IFIFO:
   268  		mode |= os.ModeNamedPipe
   269  	case syscall.S_IFLNK:
   270  		mode |= os.ModeSymlink
   271  	case syscall.S_IFSOCK:
   272  		mode |= os.ModeSocket
   273  	default:
   274  		// no idea
   275  		mode |= os.ModeDevice
   276  	}
   277  	if unixMode&syscall.S_ISUID != 0 {
   278  		mode |= os.ModeSetuid
   279  	}
   280  	if unixMode&syscall.S_ISGID != 0 {
   281  		mode |= os.ModeSetgid
   282  	}
   283  	return mode
   284  }
   285  
   286  func (c *Conn) ReadRequest() (Request, error) {
   287  	// TODO: Some kind of buffer reuse.
   288  	m := newMessage(c)
   289  	n, err := syscall.Read(c.fd, m.buf)
   290  	if err != nil && err != syscall.ENODEV {
   291  		return nil, err
   292  	}
   293  	if n <= 0 {
   294  		return nil, io.EOF
   295  	}
   296  	m.buf = m.buf[:n]
   297  
   298  	if n < inHeaderSize {
   299  		return nil, errors.New("fuse: message too short")
   300  	}
   301  
   302  	// FreeBSD FUSE sends a short length in the header
   303  	// for FUSE_INIT even though the actual read length is correct.
   304  	if n == inHeaderSize+initInSize && m.hdr.Opcode == opInit && m.hdr.Len < uint32(n) {
   305  		m.hdr.Len = uint32(n)
   306  	}
   307  
   308  	// OSXFUSE sometimes sends the wrong m.hdr.Len in a FUSE_WRITE message.
   309  	if m.hdr.Len < uint32(n) && m.hdr.Len >= uint32(unsafe.Sizeof(writeIn{})) && m.hdr.Opcode == opWrite {
   310  		m.hdr.Len = uint32(n)
   311  	}
   312  
   313  	if m.hdr.Len != uint32(n) {
   314  		return nil, fmt.Errorf("fuse: read %d opcode %d but expected %d", n, m.hdr.Opcode, m.hdr.Len)
   315  	}
   316  
   317  	m.off = inHeaderSize
   318  
   319  	// Convert to data structures.
   320  	// Do not trust kernel to hand us well-formed data.
   321  	var req Request
   322  	switch m.hdr.Opcode {
   323  	default:
   324  		println("No opcode", m.hdr.Opcode)
   325  		goto unrecognized
   326  
   327  	case opLookup:
   328  		buf := m.bytes()
   329  		n := len(buf)
   330  		if n == 0 || buf[n-1] != '\x00' {
   331  			goto corrupt
   332  		}
   333  		req = &LookupRequest{
   334  			Header: m.Header(),
   335  			Name:   string(buf[:n-1]),
   336  		}
   337  
   338  	case opForget:
   339  		in := (*forgetIn)(m.data())
   340  		if m.len() < unsafe.Sizeof(*in) {
   341  			goto corrupt
   342  		}
   343  		req = &ForgetRequest{
   344  			Header: m.Header(),
   345  			N:      in.Nlookup,
   346  		}
   347  
   348  	case opGetattr:
   349  		req = &GetattrRequest{
   350  			Header: m.Header(),
   351  		}
   352  
   353  	case opSetattr:
   354  		in := (*setattrIn)(m.data())
   355  		if m.len() < unsafe.Sizeof(*in) {
   356  			goto corrupt
   357  		}
   358  		req = &SetattrRequest{
   359  			Header:   m.Header(),
   360  			Valid:    SetattrValid(in.Valid),
   361  			Handle:   HandleID(in.Fh),
   362  			Size:     in.Size,
   363  			Atime:    time.Unix(int64(in.Atime), int64(in.AtimeNsec)),
   364  			Mtime:    time.Unix(int64(in.Mtime), int64(in.MtimeNsec)),
   365  			Mode:     fileMode(in.Mode),
   366  			Uid:      in.Uid,
   367  			Gid:      in.Gid,
   368  			Bkuptime: in.BkupTime(),
   369  			Chgtime:  in.Chgtime(),
   370  			Flags:    in.Flags(),
   371  		}
   372  
   373  	case opReadlink:
   374  		if len(m.bytes()) > 0 {
   375  			goto corrupt
   376  		}
   377  		req = &ReadlinkRequest{
   378  			Header: m.Header(),
   379  		}
   380  
   381  	case opSymlink:
   382  		// m.bytes() is "newName\0target\0"
   383  		names := m.bytes()
   384  		if len(names) == 0 || names[len(names)-1] != 0 {
   385  			goto corrupt
   386  		}
   387  		i := bytes.IndexByte(names, '\x00')
   388  		if i < 0 {
   389  			goto corrupt
   390  		}
   391  		newName, target := names[0:i], names[i+1:len(names)-1]
   392  		req = &SymlinkRequest{
   393  			Header:  m.Header(),
   394  			NewName: string(newName),
   395  			Target:  string(target),
   396  		}
   397  
   398  	case opLink:
   399  		in := (*linkIn)(m.data())
   400  		if m.len() < unsafe.Sizeof(*in) {
   401  			goto corrupt
   402  		}
   403  		newName := m.bytes()[unsafe.Sizeof(*in):]
   404  		if len(newName) < 2 || newName[len(newName)-1] != 0 {
   405  			goto corrupt
   406  		}
   407  		newName = newName[:len(newName)-1]
   408  		req = &LinkRequest{
   409  			Header:  m.Header(),
   410  			OldNode: NodeID(in.Oldnodeid),
   411  			NewName: string(newName),
   412  		}
   413  
   414  	case opMknod:
   415  		in := (*mknodIn)(m.data())
   416  		if m.len() < unsafe.Sizeof(*in) {
   417  			goto corrupt
   418  		}
   419  		name := m.bytes()[unsafe.Sizeof(*in):]
   420  		if len(name) < 2 || name[len(name)-1] != '\x00' {
   421  			goto corrupt
   422  		}
   423  		name = name[:len(name)-1]
   424  		req = &MknodRequest{
   425  			Header: m.Header(),
   426  			Mode:   fileMode(in.Mode),
   427  			Rdev:   in.Rdev,
   428  			Name:   string(name),
   429  		}
   430  
   431  	case opMkdir:
   432  		in := (*mkdirIn)(m.data())
   433  		if m.len() < unsafe.Sizeof(*in) {
   434  			goto corrupt
   435  		}
   436  		name := m.bytes()[unsafe.Sizeof(*in):]
   437  		i := bytes.IndexByte(name, '\x00')
   438  		if i < 0 {
   439  			goto corrupt
   440  		}
   441  		req = &MkdirRequest{
   442  			Header: m.Header(),
   443  			Name:   string(name[:i]),
   444  			Mode:   fileMode(in.Mode) | os.ModeDir,
   445  		}
   446  
   447  	case opUnlink, opRmdir:
   448  		buf := m.bytes()
   449  		n := len(buf)
   450  		if n == 0 || buf[n-1] != '\x00' {
   451  			goto corrupt
   452  		}
   453  		req = &RemoveRequest{
   454  			Header: m.Header(),
   455  			Name:   string(buf[:n-1]),
   456  			Dir:    m.hdr.Opcode == opRmdir,
   457  		}
   458  
   459  	case opRename:
   460  		in := (*renameIn)(m.data())
   461  		if m.len() < unsafe.Sizeof(*in) {
   462  			goto corrupt
   463  		}
   464  		newDirNodeID := NodeID(in.Newdir)
   465  		oldNew := m.bytes()[unsafe.Sizeof(*in):]
   466  		// oldNew should be "old\x00new\x00"
   467  		if len(oldNew) < 4 {
   468  			goto corrupt
   469  		}
   470  		if oldNew[len(oldNew)-1] != '\x00' {
   471  			goto corrupt
   472  		}
   473  		i := bytes.IndexByte(oldNew, '\x00')
   474  		if i < 0 {
   475  			goto corrupt
   476  		}
   477  		oldName, newName := string(oldNew[:i]), string(oldNew[i+1:len(oldNew)-1])
   478  		// log.Printf("RENAME: newDirNode = %d; old = %q, new = %q", newDirNodeID, oldName, newName)
   479  		req = &RenameRequest{
   480  			Header:  m.Header(),
   481  			NewDir:  newDirNodeID,
   482  			OldName: oldName,
   483  			NewName: newName,
   484  		}
   485  
   486  	case opOpendir, opOpen:
   487  		in := (*openIn)(m.data())
   488  		if m.len() < unsafe.Sizeof(*in) {
   489  			goto corrupt
   490  		}
   491  		req = &OpenRequest{
   492  			Header: m.Header(),
   493  			Dir:    m.hdr.Opcode == opOpendir,
   494  			Flags:  in.Flags,
   495  			Mode:   fileMode(in.Mode),
   496  		}
   497  
   498  	case opRead, opReaddir:
   499  		in := (*readIn)(m.data())
   500  		if m.len() < unsafe.Sizeof(*in) {
   501  			goto corrupt
   502  		}
   503  		req = &ReadRequest{
   504  			Header: m.Header(),
   505  			Dir:    m.hdr.Opcode == opReaddir,
   506  			Handle: HandleID(in.Fh),
   507  			Offset: int64(in.Offset),
   508  			Size:   int(in.Size),
   509  		}
   510  
   511  	case opWrite:
   512  		in := (*writeIn)(m.data())
   513  		if m.len() < unsafe.Sizeof(*in) {
   514  			goto corrupt
   515  		}
   516  		r := &WriteRequest{
   517  			Header: m.Header(),
   518  			Handle: HandleID(in.Fh),
   519  			Offset: int64(in.Offset),
   520  			Flags:  WriteFlags(in.WriteFlags),
   521  		}
   522  		buf := m.bytes()[unsafe.Sizeof(*in):]
   523  		if uint32(len(buf)) < in.Size {
   524  			goto corrupt
   525  		}
   526  		r.Data = buf
   527  		req = r
   528  
   529  	case opStatfs:
   530  		req = &StatfsRequest{
   531  			Header: m.Header(),
   532  		}
   533  
   534  	case opRelease, opReleasedir:
   535  		in := (*releaseIn)(m.data())
   536  		if m.len() < unsafe.Sizeof(*in) {
   537  			goto corrupt
   538  		}
   539  		req = &ReleaseRequest{
   540  			Header:       m.Header(),
   541  			Dir:          m.hdr.Opcode == opReleasedir,
   542  			Handle:       HandleID(in.Fh),
   543  			Flags:        in.Flags,
   544  			ReleaseFlags: ReleaseFlags(in.ReleaseFlags),
   545  			LockOwner:    in.LockOwner,
   546  		}
   547  
   548  	case opFsync:
   549  		in := (*fsyncIn)(m.data())
   550  		if m.len() < unsafe.Sizeof(*in) {
   551  			goto corrupt
   552  		}
   553  		req = &FsyncRequest{
   554  			Header: m.Header(),
   555  			Handle: HandleID(in.Fh),
   556  			Flags:  in.FsyncFlags,
   557  		}
   558  
   559  	case opSetxattr:
   560  		var size uint32
   561  		var r *SetxattrRequest
   562  		if runtime.GOOS == "darwin" {
   563  			in := (*setxattrInOSX)(m.data())
   564  			if m.len() < unsafe.Sizeof(*in) {
   565  				goto corrupt
   566  			}
   567  			r = &SetxattrRequest{
   568  				Flags:    in.Flags,
   569  				Position: in.Position,
   570  			}
   571  			size = in.Size
   572  			m.off += int(unsafe.Sizeof(*in))
   573  		} else {
   574  			in := (*setxattrIn)(m.data())
   575  			if m.len() < unsafe.Sizeof(*in) {
   576  				goto corrupt
   577  			}
   578  			r = &SetxattrRequest{}
   579  			size = in.Size
   580  			m.off += int(unsafe.Sizeof(*in))
   581  		}
   582  		r.Header = m.Header()
   583  		name := m.bytes()
   584  		i := bytes.IndexByte(name, '\x00')
   585  		if i < 0 {
   586  			goto corrupt
   587  		}
   588  		r.Name = string(name[:i])
   589  		r.Xattr = name[i+1:]
   590  		if uint32(len(r.Xattr)) < size {
   591  			goto corrupt
   592  		}
   593  		r.Xattr = r.Xattr[:size]
   594  		req = r
   595  
   596  	case opGetxattr:
   597  		var r *GetxattrRequest
   598  		nameOff := 8
   599  		if runtime.GOOS == "darwin" {
   600  			in := (*getxattrInOSX)(m.data())
   601  			if m.len() < unsafe.Sizeof(*in) {
   602  				goto corrupt
   603  			}
   604  			nameOff += 8
   605  			r = &GetxattrRequest{
   606  				Header:   m.Header(),
   607  				Size:     in.Size,
   608  				Position: in.Position,
   609  			}
   610  		} else {
   611  			in := (*getxattrIn)(m.data())
   612  			if m.len() < unsafe.Sizeof(*in) {
   613  				goto corrupt
   614  			}
   615  			r = &GetxattrRequest{
   616  				Header: m.Header(),
   617  				Size:   in.Size,
   618  			}
   619  		}
   620  		r.Header = m.Header()
   621  		name := m.bytes()[nameOff:]
   622  		i := bytes.IndexByte(name, 0)
   623  		if i < 0 {
   624  			goto corrupt
   625  		}
   626  		r.Name = string(name[:i])
   627  		req = r
   628  
   629  	case opListxattr:
   630  		if runtime.GOOS == "darwin" {
   631  			in := (*getxattrInOSX)(m.data())
   632  			if m.len() < unsafe.Sizeof(*in) {
   633  				goto corrupt
   634  			}
   635  			req = &ListxattrRequest{
   636  				Header:   m.Header(),
   637  				Size:     in.Size,
   638  				Position: in.Position,
   639  			}
   640  		} else {
   641  			in := (*getxattrIn)(m.data())
   642  			if m.len() < unsafe.Sizeof(*in) {
   643  				goto corrupt
   644  			}
   645  			req = &ListxattrRequest{
   646  				Header: m.Header(),
   647  				Size:   in.Size,
   648  			}
   649  		}
   650  
   651  	case opRemovexattr:
   652  		buf := m.bytes()
   653  		n := len(buf)
   654  		if n == 0 || buf[n-1] != '\x00' {
   655  			goto corrupt
   656  		}
   657  		req = &RemovexattrRequest{
   658  			Header: m.Header(),
   659  			Name:   string(buf[:n-1]),
   660  		}
   661  
   662  	case opFlush:
   663  		in := (*flushIn)(m.data())
   664  		if m.len() < unsafe.Sizeof(*in) {
   665  			goto corrupt
   666  		}
   667  		req = &FlushRequest{
   668  			Header:    m.Header(),
   669  			Handle:    HandleID(in.Fh),
   670  			Flags:     in.FlushFlags,
   671  			LockOwner: in.LockOwner,
   672  		}
   673  
   674  	case opInit:
   675  		in := (*initIn)(m.data())
   676  		if m.len() < unsafe.Sizeof(*in) {
   677  			goto corrupt
   678  		}
   679  		req = &InitRequest{
   680  			Header:       m.Header(),
   681  			Major:        in.Major,
   682  			Minor:        in.Minor,
   683  			MaxReadahead: in.MaxReadahead,
   684  			Flags:        InitFlags(in.Flags),
   685  		}
   686  
   687  	case opFsyncdir:
   688  		// TODO(bradfitz): not really tested. I see this rarely on OS X,
   689  		// generally when a Finder window is open showing a directory
   690  		// and then the filesystem is unmounted. But I should write proper
   691  		// tests for it before I remove this comment.
   692  		in := (*fsyncIn)(m.data())
   693  		if m.len() < unsafe.Sizeof(*in) {
   694  			goto corrupt
   695  		}
   696  		req = &FsyncRequest{
   697  			Dir:    true,
   698  			Header: m.Header(),
   699  			Handle: HandleID(in.Fh),
   700  			Flags:  in.FsyncFlags,
   701  		}
   702  
   703  	case opGetlk:
   704  		panic("opGetlk")
   705  	case opSetlk:
   706  		panic("opSetlk")
   707  	case opSetlkw:
   708  		panic("opSetlkw")
   709  
   710  	case opAccess:
   711  		in := (*accessIn)(m.data())
   712  		if m.len() < unsafe.Sizeof(*in) {
   713  			goto corrupt
   714  		}
   715  		req = &AccessRequest{
   716  			Header: m.Header(),
   717  			Mask:   in.Mask,
   718  		}
   719  
   720  	case opCreate:
   721  		in := (*openIn)(m.data())
   722  		if m.len() < unsafe.Sizeof(*in) {
   723  			goto corrupt
   724  		}
   725  		name := m.bytes()[unsafe.Sizeof(*in):]
   726  		i := bytes.IndexByte(name, '\x00')
   727  		if i < 0 {
   728  			goto corrupt
   729  		}
   730  		req = &CreateRequest{
   731  			Header: m.Header(),
   732  			Flags:  in.Flags,
   733  			Mode:   fileMode(in.Mode),
   734  			Name:   string(name[:i]),
   735  		}
   736  
   737  	case opInterrupt:
   738  		in := (*interruptIn)(m.data())
   739  		if m.len() < unsafe.Sizeof(*in) {
   740  			goto corrupt
   741  		}
   742  		req = &InterruptRequest{
   743  			Header: m.Header(),
   744  			Unique: in.Unique,
   745  		}
   746  
   747  	case opBmap:
   748  		panic("opBmap")
   749  
   750  	case opDestroy:
   751  		req = &DestroyRequest{
   752  			Header: m.Header(),
   753  		}
   754  
   755  	// OS X
   756  	case opSetvolname:
   757  		panic("opSetvolname")
   758  	case opGetxtimes:
   759  		panic("opGetxtimes")
   760  	case opExchange:
   761  		panic("opExchange")
   762  	}
   763  
   764  	return req, nil
   765  
   766  corrupt:
   767  	println("malformed message")
   768  	return nil, fmt.Errorf("fuse: malformed message")
   769  
   770  unrecognized:
   771  	// Unrecognized message.
   772  	// Assume higher-level code will send a "no idea what you mean" error.
   773  	h := m.Header()
   774  	return &h, nil
   775  }
   776  
   777  func (c *Conn) respond(out *outHeader, n uintptr) {
   778  	c.wio.Lock()
   779  	defer c.wio.Unlock()
   780  	out.Len = uint32(n)
   781  	msg := (*[1 << 30]byte)(unsafe.Pointer(out))[:n]
   782  	nn, err := syscall.Write(c.fd, msg)
   783  	if nn != len(msg) || err != nil {
   784  		log.Printf("RESPOND WRITE: %d %v", nn, err)
   785  		log.Printf("with stack: %s", stack())
   786  	}
   787  }
   788  
   789  func (c *Conn) respondData(out *outHeader, n uintptr, data []byte) {
   790  	c.wio.Lock()
   791  	defer c.wio.Unlock()
   792  	// TODO: use writev
   793  	out.Len = uint32(n + uintptr(len(data)))
   794  	msg := make([]byte, out.Len)
   795  	copy(msg, (*[1 << 30]byte)(unsafe.Pointer(out))[:n])
   796  	copy(msg[n:], data)
   797  	syscall.Write(c.fd, msg)
   798  }
   799  
   800  // An InitRequest is the first request sent on a FUSE file system.
   801  type InitRequest struct {
   802  	Header
   803  	Major        uint32
   804  	Minor        uint32
   805  	MaxReadahead uint32
   806  	Flags        InitFlags
   807  }
   808  
   809  func (r *InitRequest) String() string {
   810  	return fmt.Sprintf("Init [%s] %d.%d ra=%d fl=%v", &r.Header, r.Major, r.Minor, r.MaxReadahead, r.Flags)
   811  }
   812  
   813  // An InitResponse is the response to an InitRequest.
   814  type InitResponse struct {
   815  	MaxReadahead uint32
   816  	Flags        InitFlags
   817  	MaxWrite     uint32
   818  }
   819  
   820  func (r *InitResponse) String() string {
   821  	return fmt.Sprintf("Init %+v", *r)
   822  }
   823  
   824  // Respond replies to the request with the given response.
   825  func (r *InitRequest) Respond(resp *InitResponse) {
   826  	out := &initOut{
   827  		outHeader:    outHeader{Unique: uint64(r.ID)},
   828  		Major:        kernelVersion,
   829  		Minor:        kernelMinorVersion,
   830  		MaxReadahead: resp.MaxReadahead,
   831  		Flags:        uint32(resp.Flags),
   832  		MaxWrite:     resp.MaxWrite,
   833  	}
   834  	r.Conn.respond(&out.outHeader, unsafe.Sizeof(*out))
   835  }
   836  
   837  // A StatfsRequest requests information about the mounted file system.
   838  type StatfsRequest struct {
   839  	Header
   840  }
   841  
   842  func (r *StatfsRequest) String() string {
   843  	return fmt.Sprintf("Statfs [%s]\n", &r.Header)
   844  }
   845  
   846  // Respond replies to the request with the given response.
   847  func (r *StatfsRequest) Respond(resp *StatfsResponse) {
   848  	out := &statfsOut{
   849  		outHeader: outHeader{Unique: uint64(r.ID)},
   850  		St: kstatfs{
   851  			Blocks:  resp.Blocks,
   852  			Bfree:   resp.Bfree,
   853  			Bavail:  resp.Bavail,
   854  			Files:   resp.Files,
   855  			Bsize:   resp.Bsize,
   856  			Namelen: resp.Namelen,
   857  			Frsize:  resp.Frsize,
   858  		},
   859  	}
   860  	r.Conn.respond(&out.outHeader, unsafe.Sizeof(*out))
   861  }
   862  
   863  // A StatfsResponse is the response to a StatfsRequest.
   864  type StatfsResponse struct {
   865  	Blocks  uint64 // Total data blocks in file system.
   866  	Bfree   uint64 // Free blocks in file system.
   867  	Bavail  uint64 // Free blocks in file system if you're not root.
   868  	Files   uint64 // Total files in file system.
   869  	Ffree   uint64 // Free files in file system.
   870  	Bsize   uint32 // Block size
   871  	Namelen uint32 // Maximum file name length?
   872  	Frsize  uint32 // ?
   873  }
   874  
   875  func (r *StatfsResponse) String() string {
   876  	return fmt.Sprintf("Statfs %+v", *r)
   877  }
   878  
   879  // An AccessRequest asks whether the file can be accessed
   880  // for the purpose specified by the mask.
   881  type AccessRequest struct {
   882  	Header
   883  	Mask uint32
   884  }
   885  
   886  func (r *AccessRequest) String() string {
   887  	return fmt.Sprintf("Access [%s] mask=%#x", &r.Header, r.Mask)
   888  }
   889  
   890  // Respond replies to the request indicating that access is allowed.
   891  // To deny access, use RespondError.
   892  func (r *AccessRequest) Respond() {
   893  	out := &outHeader{Unique: uint64(r.ID)}
   894  	r.Conn.respond(out, unsafe.Sizeof(*out))
   895  }
   896  
   897  // An Attr is the metadata for a single file or directory.
   898  type Attr struct {
   899  	Inode  uint64      // inode number
   900  	Size   uint64      // size in bytes
   901  	Blocks uint64      // size in blocks
   902  	Atime  time.Time   // time of last access
   903  	Mtime  time.Time   // time of last modification
   904  	Ctime  time.Time   // time of last inode change
   905  	Crtime time.Time   // time of creation (OS X only)
   906  	Mode   os.FileMode // file mode
   907  	Nlink  uint32      // number of links
   908  	Uid    uint32      // owner uid
   909  	Gid    uint32      // group gid
   910  	Rdev   uint32      // device numbers
   911  	Flags  uint32      // chflags(2) flags (OS X only)
   912  }
   913  
   914  func unix(t time.Time) (sec uint64, nsec uint32) {
   915  	nano := t.UnixNano()
   916  	sec = uint64(nano / 1e9)
   917  	nsec = uint32(nano % 1e9)
   918  	return
   919  }
   920  
   921  func (a *Attr) attr() (out attr) {
   922  	out.Ino = a.Inode
   923  	out.Size = a.Size
   924  	out.Blocks = a.Blocks
   925  	out.Atime, out.AtimeNsec = unix(a.Atime)
   926  	out.Mtime, out.MtimeNsec = unix(a.Mtime)
   927  	out.Ctime, out.CtimeNsec = unix(a.Ctime)
   928  	out.SetCrtime(unix(a.Crtime))
   929  	out.Mode = uint32(a.Mode) & 0777
   930  	switch {
   931  	default:
   932  		out.Mode |= syscall.S_IFREG
   933  	case a.Mode&os.ModeDir != 0:
   934  		out.Mode |= syscall.S_IFDIR
   935  	case a.Mode&os.ModeDevice != 0:
   936  		if a.Mode&os.ModeCharDevice != 0 {
   937  			out.Mode |= syscall.S_IFCHR
   938  		} else {
   939  			out.Mode |= syscall.S_IFBLK
   940  		}
   941  	case a.Mode&os.ModeNamedPipe != 0:
   942  		out.Mode |= syscall.S_IFIFO
   943  	case a.Mode&os.ModeSymlink != 0:
   944  		out.Mode |= syscall.S_IFLNK
   945  	case a.Mode&os.ModeSocket != 0:
   946  		out.Mode |= syscall.S_IFSOCK
   947  	}
   948  	if a.Mode&os.ModeSetuid != 0 {
   949  		out.Mode |= syscall.S_ISUID
   950  	}
   951  	if a.Mode&os.ModeSetgid != 0 {
   952  		out.Mode |= syscall.S_ISGID
   953  	}
   954  	out.Nlink = a.Nlink
   955  	if out.Nlink < 1 {
   956  		out.Nlink = 1
   957  	}
   958  	out.Uid = a.Uid
   959  	out.Gid = a.Gid
   960  	out.Rdev = a.Rdev
   961  	out.SetFlags(a.Flags)
   962  
   963  	return
   964  }
   965  
   966  // A GetattrRequest asks for the metadata for the file denoted by r.Node.
   967  type GetattrRequest struct {
   968  	Header
   969  }
   970  
   971  func (r *GetattrRequest) String() string {
   972  	return fmt.Sprintf("Getattr [%s]", &r.Header)
   973  }
   974  
   975  // Respond replies to the request with the given response.
   976  func (r *GetattrRequest) Respond(resp *GetattrResponse) {
   977  	out := &attrOut{
   978  		outHeader:     outHeader{Unique: uint64(r.ID)},
   979  		AttrValid:     uint64(resp.AttrValid / time.Second),
   980  		AttrValidNsec: uint32(resp.AttrValid % time.Second / time.Nanosecond),
   981  		Attr:          resp.Attr.attr(),
   982  	}
   983  	r.Conn.respond(&out.outHeader, unsafe.Sizeof(*out))
   984  }
   985  
   986  // A GetattrResponse is the response to a GetattrRequest.
   987  type GetattrResponse struct {
   988  	AttrValid time.Duration // how long Attr can be cached
   989  	Attr      Attr          // file attributes
   990  }
   991  
   992  func (r *GetattrResponse) String() string {
   993  	return fmt.Sprintf("Getattr %+v", *r)
   994  }
   995  
   996  // A GetxattrRequest asks for the extended attributes associated with r.Node.
   997  type GetxattrRequest struct {
   998  	Header
   999  	Size     uint32 // maximum size to return
  1000  	Position uint32 // offset within extended attributes
  1001  	Name     string // Name of the attribute being requested
  1002  }
  1003  
  1004  func (r *GetxattrRequest) String() string {
  1005  	return fmt.Sprintf("Getxattr [%s] %d @%d", &r.Header, r.Size, r.Position)
  1006  }
  1007  
  1008  // Respond replies to the request with the given response.
  1009  func (r *GetxattrRequest) Respond(resp *GetxattrResponse) {
  1010  	hdr := outHeader{Unique: uint64(r.ID)}
  1011  	if r.Size == 0 {
  1012  		out := &getxattrOut{
  1013  			outHeader: hdr,
  1014  			Size:      uint32(len(resp.Xattr)),
  1015  		}
  1016  		r.Conn.respond(&out.outHeader, unsafe.Sizeof(*out))
  1017  	} else {
  1018  		r.Conn.respondData(&hdr, unsafe.Sizeof(hdr), resp.Xattr)
  1019  	}
  1020  }
  1021  
  1022  // A GetxattrResponse is the response to a GetxattrRequest.
  1023  type GetxattrResponse struct {
  1024  	Xattr []byte
  1025  }
  1026  
  1027  func (r *GetxattrResponse) String() string {
  1028  	return fmt.Sprintf("Getxattr %x", r.Xattr)
  1029  }
  1030  
  1031  // A ListxattrRequest asks to list the extended attributes associated with r.Node.
  1032  type ListxattrRequest struct {
  1033  	Header
  1034  	Size     uint32 // maximum size to return
  1035  	Position uint32 // offset within attribute list
  1036  }
  1037  
  1038  func (r *ListxattrRequest) String() string {
  1039  	return fmt.Sprintf("Listxattr [%s] %d @%d", &r.Header, r.Size, r.Position)
  1040  }
  1041  
  1042  // Respond replies to the request with the given response.
  1043  func (r *ListxattrRequest) Respond(resp *ListxattrResponse) {
  1044  	hdr := outHeader{Unique: uint64(r.ID)}
  1045  	if r.Size == 0 {
  1046  		out := &getxattrOut{
  1047  			outHeader: hdr,
  1048  			Size:      resp.Size,
  1049  		}
  1050  		r.Conn.respond(&out.outHeader, unsafe.Sizeof(*out))
  1051  	} else {
  1052  		r.Conn.respondData(&hdr, unsafe.Sizeof(hdr), resp.Xattr)
  1053  	}
  1054  }
  1055  
  1056  // A ListxattrResponse is the response to a ListxattrRequest.
  1057  type ListxattrResponse struct {
  1058  	Size  uint32
  1059  	Xattr []byte
  1060  }
  1061  
  1062  // SetattrNames initializes the ListxattrResponse with the list of
  1063  // attribute names.
  1064  func (l *ListxattrResponse) SetAttrNames(req *ListxattrRequest, to []string) {
  1065  	var buf bytes.Buffer
  1066  	for _, b := range to {
  1067  		buf.WriteString(b)
  1068  		buf.WriteByte(0)
  1069  	}
  1070  	l.Size = uint32(buf.Len())
  1071  	l.Xattr = buf.Bytes()
  1072  	if len(l.Xattr) > int(req.Size) {
  1073  		l.Xattr = l.Xattr[:req.Size]
  1074  	}
  1075  }
  1076  
  1077  func (r *ListxattrResponse) String() string {
  1078  	return fmt.Sprintf("Listxattr %x", r.Xattr)
  1079  }
  1080  
  1081  // A RemovexattrRequest asks to remove an extended attribute associated with r.Node.
  1082  type RemovexattrRequest struct {
  1083  	Header
  1084  	Name string // name of extended attribute
  1085  }
  1086  
  1087  func (r *RemovexattrRequest) String() string {
  1088  	return fmt.Sprintf("Removexattr [%s] %q", &r.Header, r.Name)
  1089  }
  1090  
  1091  // Respond replies to the request, indicating that the attribute was removed.
  1092  func (r *RemovexattrRequest) Respond() {
  1093  	out := &outHeader{Unique: uint64(r.ID)}
  1094  	r.Conn.respond(out, unsafe.Sizeof(*out))
  1095  }
  1096  
  1097  // A SetxattrRequest asks to set an extended attribute associated with a file.
  1098  type SetxattrRequest struct {
  1099  	Header
  1100  	Flags    uint32
  1101  	Position uint32 // OS X only
  1102  	Name     string
  1103  	Xattr    []byte
  1104  }
  1105  
  1106  func (r *SetxattrRequest) String() string {
  1107  	return fmt.Sprintf("Setxattr [%s] %q %x fl=%v @%#x", &r.Header, r.Name, r.Xattr, r.Flags, r.Position)
  1108  }
  1109  
  1110  // Respond replies to the request, indicating that the extended attribute was set.
  1111  func (r *SetxattrRequest) Respond() {
  1112  	out := &outHeader{Unique: uint64(r.ID)}
  1113  	r.Conn.respond(out, unsafe.Sizeof(*out))
  1114  }
  1115  
  1116  // A LookupRequest asks to look up the given name in the directory named by r.Node.
  1117  type LookupRequest struct {
  1118  	Header
  1119  	Name string
  1120  }
  1121  
  1122  func (r *LookupRequest) String() string {
  1123  	return fmt.Sprintf("Lookup [%s] %q", &r.Header, r.Name)
  1124  }
  1125  
  1126  // Respond replies to the request with the given response.
  1127  func (r *LookupRequest) Respond(resp *LookupResponse) {
  1128  	out := &entryOut{
  1129  		outHeader:      outHeader{Unique: uint64(r.ID)},
  1130  		Nodeid:         uint64(resp.Node),
  1131  		Generation:     resp.Generation,
  1132  		EntryValid:     uint64(resp.EntryValid / time.Second),
  1133  		EntryValidNsec: uint32(resp.EntryValid % time.Second / time.Nanosecond),
  1134  		AttrValid:      uint64(resp.AttrValid / time.Second),
  1135  		AttrValidNsec:  uint32(resp.AttrValid % time.Second / time.Nanosecond),
  1136  		Attr:           resp.Attr.attr(),
  1137  	}
  1138  	r.Conn.respond(&out.outHeader, unsafe.Sizeof(*out))
  1139  }
  1140  
  1141  // A LookupResponse is the response to a LookupRequest.
  1142  type LookupResponse struct {
  1143  	Node       NodeID
  1144  	Generation uint64
  1145  	EntryValid time.Duration
  1146  	AttrValid  time.Duration
  1147  	Attr       Attr
  1148  }
  1149  
  1150  func (r *LookupResponse) String() string {
  1151  	return fmt.Sprintf("Lookup %+v", *r)
  1152  }
  1153  
  1154  // An OpenRequest asks to open a file or directory
  1155  type OpenRequest struct {
  1156  	Header
  1157  	Dir   bool // is this Opendir?
  1158  	Flags uint32
  1159  	Mode  os.FileMode
  1160  }
  1161  
  1162  func (r *OpenRequest) String() string {
  1163  	return fmt.Sprintf("Open [%s] dir=%v fl=%v mode=%v", &r.Header, r.Dir, r.Flags, r.Mode)
  1164  }
  1165  
  1166  // Respond replies to the request with the given response.
  1167  func (r *OpenRequest) Respond(resp *OpenResponse) {
  1168  	out := &openOut{
  1169  		outHeader: outHeader{Unique: uint64(r.ID)},
  1170  		Fh:        uint64(resp.Handle),
  1171  		OpenFlags: uint32(resp.Flags),
  1172  	}
  1173  	r.Conn.respond(&out.outHeader, unsafe.Sizeof(*out))
  1174  }
  1175  
  1176  // A OpenResponse is the response to a OpenRequest.
  1177  type OpenResponse struct {
  1178  	Handle HandleID
  1179  	Flags  OpenFlags
  1180  }
  1181  
  1182  func (r *OpenResponse) String() string {
  1183  	return fmt.Sprintf("Open %+v", *r)
  1184  }
  1185  
  1186  // A CreateRequest asks to create and open a file (not a directory).
  1187  type CreateRequest struct {
  1188  	Header
  1189  	Name  string
  1190  	Flags uint32
  1191  	Mode  os.FileMode
  1192  }
  1193  
  1194  func (r *CreateRequest) String() string {
  1195  	return fmt.Sprintf("Create [%s] %q fl=%v mode=%v", &r.Header, r.Name, r.Flags, r.Mode)
  1196  }
  1197  
  1198  // Respond replies to the request with the given response.
  1199  func (r *CreateRequest) Respond(resp *CreateResponse) {
  1200  	out := &createOut{
  1201  		outHeader: outHeader{Unique: uint64(r.ID)},
  1202  
  1203  		Nodeid:         uint64(resp.Node),
  1204  		Generation:     resp.Generation,
  1205  		EntryValid:     uint64(resp.EntryValid / time.Second),
  1206  		EntryValidNsec: uint32(resp.EntryValid % time.Second / time.Nanosecond),
  1207  		AttrValid:      uint64(resp.AttrValid / time.Second),
  1208  		AttrValidNsec:  uint32(resp.AttrValid % time.Second / time.Nanosecond),
  1209  		Attr:           resp.Attr.attr(),
  1210  
  1211  		Fh:        uint64(resp.Handle),
  1212  		OpenFlags: uint32(resp.Flags),
  1213  	}
  1214  	r.Conn.respond(&out.outHeader, unsafe.Sizeof(*out))
  1215  }
  1216  
  1217  // A CreateResponse is the response to a CreateRequest.
  1218  // It describes the created node and opened handle.
  1219  type CreateResponse struct {
  1220  	LookupResponse
  1221  	OpenResponse
  1222  }
  1223  
  1224  func (r *CreateResponse) String() string {
  1225  	return fmt.Sprintf("Create %+v", *r)
  1226  }
  1227  
  1228  // A MkdirRequest asks to create (but not open) a directory.
  1229  type MkdirRequest struct {
  1230  	Header
  1231  	Name string
  1232  	Mode os.FileMode
  1233  }
  1234  
  1235  func (r *MkdirRequest) String() string {
  1236  	return fmt.Sprintf("Mkdir [%s] %q mode=%v", &r.Header, r.Name, r.Mode)
  1237  }
  1238  
  1239  // Respond replies to the request with the given response.
  1240  func (r *MkdirRequest) Respond(resp *MkdirResponse) {
  1241  	out := &entryOut{
  1242  		outHeader:      outHeader{Unique: uint64(r.ID)},
  1243  		Nodeid:         uint64(resp.Node),
  1244  		Generation:     resp.Generation,
  1245  		EntryValid:     uint64(resp.EntryValid / time.Second),
  1246  		EntryValidNsec: uint32(resp.EntryValid % time.Second / time.Nanosecond),
  1247  		AttrValid:      uint64(resp.AttrValid / time.Second),
  1248  		AttrValidNsec:  uint32(resp.AttrValid % time.Second / time.Nanosecond),
  1249  		Attr:           resp.Attr.attr(),
  1250  	}
  1251  	r.Conn.respond(&out.outHeader, unsafe.Sizeof(*out))
  1252  }
  1253  
  1254  // A MkdirResponse is the response to a MkdirRequest.
  1255  type MkdirResponse struct {
  1256  	LookupResponse
  1257  }
  1258  
  1259  func (r *MkdirResponse) String() string {
  1260  	return fmt.Sprintf("Mkdir %+v", *r)
  1261  }
  1262  
  1263  // A ReadRequest asks to read from an open file.
  1264  type ReadRequest struct {
  1265  	Header
  1266  	Dir    bool // is this Readdir?
  1267  	Handle HandleID
  1268  	Offset int64
  1269  	Size   int
  1270  }
  1271  
  1272  func (r *ReadRequest) handle() HandleID {
  1273  	return r.Handle
  1274  }
  1275  
  1276  func (r *ReadRequest) String() string {
  1277  	return fmt.Sprintf("Read [%s] %#x %d @%#x dir=%v", &r.Header, r.Handle, r.Size, r.Offset, r.Dir)
  1278  }
  1279  
  1280  // Respond replies to the request with the given response.
  1281  func (r *ReadRequest) Respond(resp *ReadResponse) {
  1282  	out := &outHeader{Unique: uint64(r.ID)}
  1283  	r.Conn.respondData(out, unsafe.Sizeof(*out), resp.Data)
  1284  }
  1285  
  1286  // A ReadResponse is the response to a ReadRequest.
  1287  type ReadResponse struct {
  1288  	Data []byte
  1289  }
  1290  
  1291  func (r *ReadResponse) String() string {
  1292  	return fmt.Sprintf("Read %x", r.Data)
  1293  }
  1294  
  1295  // A ReleaseRequest asks to release (close) an open file handle.
  1296  type ReleaseRequest struct {
  1297  	Header
  1298  	Dir          bool // is this Releasedir?
  1299  	Handle       HandleID
  1300  	Flags        uint32 // flags from OpenRequest
  1301  	ReleaseFlags ReleaseFlags
  1302  	LockOwner    uint32
  1303  }
  1304  
  1305  func (r *ReleaseRequest) handle() HandleID {
  1306  	return r.Handle
  1307  }
  1308  
  1309  func (r *ReleaseRequest) String() string {
  1310  	return fmt.Sprintf("Release [%s] %#x fl=%v rfl=%v owner=%#x", &r.Header, r.Handle, r.Flags, r.ReleaseFlags, r.LockOwner)
  1311  }
  1312  
  1313  // Respond replies to the request, indicating that the handle has been released.
  1314  func (r *ReleaseRequest) Respond() {
  1315  	out := &outHeader{Unique: uint64(r.ID)}
  1316  	r.Conn.respond(out, unsafe.Sizeof(*out))
  1317  }
  1318  
  1319  // A DestroyRequest is sent by the kernel when unmounting the file system.
  1320  // No more requests will be received after this one, but it should still be
  1321  // responded to.
  1322  type DestroyRequest struct {
  1323  	Header
  1324  }
  1325  
  1326  func (r *DestroyRequest) String() string {
  1327  	return fmt.Sprintf("Destroy [%s]", &r.Header)
  1328  }
  1329  
  1330  // Respond replies to the request.
  1331  func (r *DestroyRequest) Respond() {
  1332  	out := &outHeader{Unique: uint64(r.ID)}
  1333  	r.Conn.respond(out, unsafe.Sizeof(*out))
  1334  }
  1335  
  1336  // A ForgetRequest is sent by the kernel when forgetting about r.Node
  1337  // as returned by r.N lookup requests.
  1338  type ForgetRequest struct {
  1339  	Header
  1340  	N uint64
  1341  }
  1342  
  1343  func (r *ForgetRequest) String() string {
  1344  	return fmt.Sprintf("Forget [%s] %d", &r.Header, r.N)
  1345  }
  1346  
  1347  // Respond replies to the request, indicating that the forgetfulness has been recorded.
  1348  func (r *ForgetRequest) Respond() {
  1349  	// Don't reply to forget messages.
  1350  }
  1351  
  1352  // A Dirent represents a single directory entry.
  1353  type Dirent struct {
  1354  	Inode uint64 // inode this entry names
  1355  	Type  uint32 // ?
  1356  	Name  string // name of entry
  1357  }
  1358  
  1359  // AppendDirent appends the encoded form of a directory entry to data
  1360  // and returns the resulting slice.
  1361  func AppendDirent(data []byte, dir Dirent) []byte {
  1362  	de := dirent{
  1363  		Ino:     dir.Inode,
  1364  		Namelen: uint32(len(dir.Name)),
  1365  		Type:    dir.Type,
  1366  	}
  1367  	de.Off = uint64(len(data) + direntSize + (len(dir.Name)+7)&^7)
  1368  	data = append(data, (*[direntSize]byte)(unsafe.Pointer(&de))[:]...)
  1369  	data = append(data, dir.Name...)
  1370  	n := direntSize + uintptr(len(dir.Name))
  1371  	if n%8 != 0 {
  1372  		var pad [8]byte
  1373  		data = append(data, pad[:8-n%8]...)
  1374  	}
  1375  	return data
  1376  }
  1377  
  1378  // A WriteRequest asks to write to an open file.
  1379  type WriteRequest struct {
  1380  	Header
  1381  	Handle HandleID
  1382  	Offset int64
  1383  	Data   []byte
  1384  	Flags  WriteFlags
  1385  }
  1386  
  1387  func (r *WriteRequest) String() string {
  1388  	return fmt.Sprintf("Write [%s] %#x %d @%d fl=%v", &r.Header, r.Handle, len(r.Data), r.Offset, r.Flags)
  1389  }
  1390  
  1391  // Respond replies to the request with the given response.
  1392  func (r *WriteRequest) Respond(resp *WriteResponse) {
  1393  	out := &writeOut{
  1394  		outHeader: outHeader{Unique: uint64(r.ID)},
  1395  		Size:      uint32(resp.Size),
  1396  	}
  1397  	r.Conn.respond(&out.outHeader, unsafe.Sizeof(*out))
  1398  }
  1399  
  1400  func (r *WriteRequest) handle() HandleID {
  1401  	return r.Handle
  1402  }
  1403  
  1404  // A WriteResponse replies to a write indicating how many bytes were written.
  1405  type WriteResponse struct {
  1406  	Size int
  1407  }
  1408  
  1409  func (r *WriteResponse) String() string {
  1410  	return fmt.Sprintf("Write %+v", *r)
  1411  }
  1412  
  1413  // A SetattrRequest asks to change one or more attributes associated with a file,
  1414  // as indicated by Valid.
  1415  type SetattrRequest struct {
  1416  	Header
  1417  	Valid  SetattrValid
  1418  	Handle HandleID
  1419  	Size   uint64
  1420  	Atime  time.Time
  1421  	Mtime  time.Time
  1422  	Mode   os.FileMode
  1423  	Uid    uint32
  1424  	Gid    uint32
  1425  
  1426  	// OS X only
  1427  	Bkuptime time.Time
  1428  	Chgtime  time.Time
  1429  	Crtime   time.Time
  1430  	Flags    uint32 // see chflags(2)
  1431  }
  1432  
  1433  func (r *SetattrRequest) String() string {
  1434  	var buf bytes.Buffer
  1435  	fmt.Fprintf(&buf, "Setattr [%s]", &r.Header)
  1436  	if r.Valid.Mode() {
  1437  		fmt.Fprintf(&buf, " mode=%v", r.Mode)
  1438  	}
  1439  	if r.Valid.Uid() {
  1440  		fmt.Fprintf(&buf, " uid=%d", r.Uid)
  1441  	}
  1442  	if r.Valid.Gid() {
  1443  		fmt.Fprintf(&buf, " gid=%d", r.Gid)
  1444  	}
  1445  	if r.Valid.Size() {
  1446  		fmt.Fprintf(&buf, " size=%d", r.Size)
  1447  	}
  1448  	if r.Valid.Atime() {
  1449  		fmt.Fprintf(&buf, " atime=%v", r.Atime)
  1450  	}
  1451  	if r.Valid.Mtime() {
  1452  		fmt.Fprintf(&buf, " mtime=%v", r.Mtime)
  1453  	}
  1454  	if r.Valid.Handle() {
  1455  		fmt.Fprintf(&buf, " handle=%#x", r.Handle)
  1456  	} else {
  1457  		fmt.Fprintf(&buf, " handle=INVALID-%#x", r.Handle)
  1458  	}
  1459  	if r.Valid.Crtime() {
  1460  		fmt.Fprintf(&buf, " crtime=%v", r.Crtime)
  1461  	}
  1462  	if r.Valid.Chgtime() {
  1463  		fmt.Fprintf(&buf, " chgtime=%v", r.Chgtime)
  1464  	}
  1465  	if r.Valid.Bkuptime() {
  1466  		fmt.Fprintf(&buf, " bkuptime=%v", r.Bkuptime)
  1467  	}
  1468  	if r.Valid.Flags() {
  1469  		fmt.Fprintf(&buf, " flags=%#x", r.Flags)
  1470  	}
  1471  	return buf.String()
  1472  }
  1473  
  1474  func (r *SetattrRequest) handle() HandleID {
  1475  	if r.Valid.Handle() {
  1476  		return r.Handle
  1477  	}
  1478  	return 0
  1479  }
  1480  
  1481  // Respond replies to the request with the given response,
  1482  // giving the updated attributes.
  1483  func (r *SetattrRequest) Respond(resp *SetattrResponse) {
  1484  	out := &attrOut{
  1485  		outHeader:     outHeader{Unique: uint64(r.ID)},
  1486  		AttrValid:     uint64(resp.AttrValid / time.Second),
  1487  		AttrValidNsec: uint32(resp.AttrValid % time.Second / time.Nanosecond),
  1488  		Attr:          resp.Attr.attr(),
  1489  	}
  1490  	r.Conn.respond(&out.outHeader, unsafe.Sizeof(*out))
  1491  }
  1492  
  1493  // A SetattrResponse is the response to a SetattrRequest.
  1494  type SetattrResponse struct {
  1495  	AttrValid time.Duration // how long Attr can be cached
  1496  	Attr      Attr          // file attributes
  1497  }
  1498  
  1499  func (r *SetattrResponse) String() string {
  1500  	return fmt.Sprintf("Setattr %+v", *r)
  1501  }
  1502  
  1503  // A FlushRequest asks for the current state of an open file to be flushed
  1504  // to storage, as when a file descriptor is being closed.  A single opened Handle
  1505  // may receive multiple FlushRequests over its lifetime.
  1506  type FlushRequest struct {
  1507  	Header
  1508  	Handle    HandleID
  1509  	Flags     uint32
  1510  	LockOwner uint64
  1511  }
  1512  
  1513  func (r *FlushRequest) String() string {
  1514  	return fmt.Sprintf("Flush [%s] %#x fl=%#x lk=%#x", &r.Header, r.Handle, r.Flags, r.LockOwner)
  1515  }
  1516  
  1517  func (r *FlushRequest) handle() HandleID {
  1518  	return r.Handle
  1519  }
  1520  
  1521  // Respond replies to the request, indicating that the flush succeeded.
  1522  func (r *FlushRequest) Respond() {
  1523  	out := &outHeader{Unique: uint64(r.ID)}
  1524  	r.Conn.respond(out, unsafe.Sizeof(*out))
  1525  }
  1526  
  1527  // A RemoveRequest asks to remove a file or directory.
  1528  type RemoveRequest struct {
  1529  	Header
  1530  	Name string // name of extended attribute
  1531  	Dir  bool   // is this rmdir?
  1532  }
  1533  
  1534  func (r *RemoveRequest) String() string {
  1535  	return fmt.Sprintf("Remove [%s] %q dir=%v", &r.Header, r.Name, r.Dir)
  1536  }
  1537  
  1538  // Respond replies to the request, indicating that the file was removed.
  1539  func (r *RemoveRequest) Respond() {
  1540  	out := &outHeader{Unique: uint64(r.ID)}
  1541  	r.Conn.respond(out, unsafe.Sizeof(*out))
  1542  }
  1543  
  1544  // A SymlinkRequest is a request to create a symlink making NewName point to Target.
  1545  type SymlinkRequest struct {
  1546  	Header
  1547  	NewName, Target string
  1548  }
  1549  
  1550  func (r *SymlinkRequest) String() string {
  1551  	return fmt.Sprintf("Symlink [%s] from %q to target %q", &r.Header, r.NewName, r.Target)
  1552  }
  1553  
  1554  func (r *SymlinkRequest) handle() HandleID {
  1555  	return 0
  1556  }
  1557  
  1558  // Respond replies to the request, indicating that the symlink was created.
  1559  func (r *SymlinkRequest) Respond(resp *SymlinkResponse) {
  1560  	out := &entryOut{
  1561  		outHeader:      outHeader{Unique: uint64(r.ID)},
  1562  		Nodeid:         uint64(resp.Node),
  1563  		Generation:     resp.Generation,
  1564  		EntryValid:     uint64(resp.EntryValid / time.Second),
  1565  		EntryValidNsec: uint32(resp.EntryValid % time.Second / time.Nanosecond),
  1566  		AttrValid:      uint64(resp.AttrValid / time.Second),
  1567  		AttrValidNsec:  uint32(resp.AttrValid % time.Second / time.Nanosecond),
  1568  		Attr:           resp.Attr.attr(),
  1569  	}
  1570  	r.Conn.respond(&out.outHeader, unsafe.Sizeof(*out))
  1571  }
  1572  
  1573  // A SymlinkResponse is the response to a SymlinkRequest.
  1574  type SymlinkResponse struct {
  1575  	LookupResponse
  1576  }
  1577  
  1578  // A ReadlinkRequest is a request to read a symlink's target.
  1579  type ReadlinkRequest struct {
  1580  	Header
  1581  }
  1582  
  1583  func (r *ReadlinkRequest) String() string {
  1584  	return fmt.Sprintf("Readlink [%s]", &r.Header)
  1585  }
  1586  
  1587  func (r *ReadlinkRequest) handle() HandleID {
  1588  	return 0
  1589  }
  1590  
  1591  func (r *ReadlinkRequest) Respond(target string) {
  1592  	out := &outHeader{Unique: uint64(r.ID)}
  1593  	r.Conn.respondData(out, unsafe.Sizeof(*out), []byte(target))
  1594  }
  1595  
  1596  // A LinkRequest is a request to create a hard link.
  1597  type LinkRequest struct {
  1598  	Header
  1599  	OldNode NodeID
  1600  	NewName string
  1601  }
  1602  
  1603  func (r *LinkRequest) Respond(resp *LookupResponse) {
  1604  	out := &entryOut{
  1605  		outHeader:      outHeader{Unique: uint64(r.ID)},
  1606  		Nodeid:         uint64(resp.Node),
  1607  		Generation:     resp.Generation,
  1608  		EntryValid:     uint64(resp.EntryValid / time.Second),
  1609  		EntryValidNsec: uint32(resp.EntryValid % time.Second / time.Nanosecond),
  1610  		AttrValid:      uint64(resp.AttrValid / time.Second),
  1611  		AttrValidNsec:  uint32(resp.AttrValid % time.Second / time.Nanosecond),
  1612  		Attr:           resp.Attr.attr(),
  1613  	}
  1614  	r.Conn.respond(&out.outHeader, unsafe.Sizeof(*out))
  1615  }
  1616  
  1617  // A RenameRequest is a request to rename a file.
  1618  type RenameRequest struct {
  1619  	Header
  1620  	NewDir           NodeID
  1621  	OldName, NewName string
  1622  }
  1623  
  1624  func (r *RenameRequest) handle() HandleID {
  1625  	return 0
  1626  }
  1627  
  1628  func (r *RenameRequest) String() string {
  1629  	return fmt.Sprintf("Rename [%s] from %q to dirnode %d %q", &r.Header, r.OldName, r.NewDir, r.NewName)
  1630  }
  1631  
  1632  func (r *RenameRequest) Respond() {
  1633  	out := &outHeader{Unique: uint64(r.ID)}
  1634  	r.Conn.respond(out, unsafe.Sizeof(*out))
  1635  }
  1636  
  1637  type MknodRequest struct {
  1638  	Header
  1639  	Name string
  1640  	Mode os.FileMode
  1641  	Rdev uint32
  1642  }
  1643  
  1644  func (r *MknodRequest) String() string {
  1645  	return fmt.Sprintf("Mknod [%s] Name %q mode %v rdev %d", &r.Header, r.Name, r.Mode, r.Rdev)
  1646  }
  1647  
  1648  func (r *MknodRequest) Respond(resp *LookupResponse) {
  1649  	out := &entryOut{
  1650  		outHeader:      outHeader{Unique: uint64(r.ID)},
  1651  		Nodeid:         uint64(resp.Node),
  1652  		Generation:     resp.Generation,
  1653  		EntryValid:     uint64(resp.EntryValid / time.Second),
  1654  		EntryValidNsec: uint32(resp.EntryValid % time.Second / time.Nanosecond),
  1655  		AttrValid:      uint64(resp.AttrValid / time.Second),
  1656  		AttrValidNsec:  uint32(resp.AttrValid % time.Second / time.Nanosecond),
  1657  		Attr:           resp.Attr.attr(),
  1658  	}
  1659  	r.Conn.respond(&out.outHeader, unsafe.Sizeof(*out))
  1660  }
  1661  
  1662  type FsyncRequest struct {
  1663  	Header
  1664  	Handle HandleID
  1665  	Flags  uint32
  1666  	Dir    bool // if opFsyncDir
  1667  }
  1668  
  1669  func (r *FsyncRequest) String() string {
  1670  	return fmt.Sprintf("Fsync [%s] Handle %v Flags %v", &r.Header, r.Handle, r.Flags)
  1671  }
  1672  
  1673  func (r *FsyncRequest) Respond() {
  1674  	out := &outHeader{Unique: uint64(r.ID)}
  1675  	r.Conn.respond(out, unsafe.Sizeof(*out))
  1676  }
  1677  
  1678  type InterruptRequest struct {
  1679  	Header
  1680  	Unique uint64
  1681  }
  1682  
  1683  /*{
  1684  
  1685  // A XXXRequest xxx.
  1686  type XXXRequest struct {
  1687  	Header
  1688  	xxx
  1689  }
  1690  
  1691  func (r *XXXRequest) String() string {
  1692  	return fmt.Sprintf("XXX [%s] xxx", &r.Header)
  1693  }
  1694  
  1695  func (r *XXXRequest) handle() HandleID {
  1696  	return r.Handle
  1697  }
  1698  
  1699  // Respond replies to the request with the given response.
  1700  func (r *XXXRequest) Respond(resp *XXXResponse) {
  1701  	out := &xxxOut{
  1702  		outHeader: outHeader{Unique: uint64(r.ID)},
  1703  		xxx,
  1704  	}
  1705  	r.Conn.respond(&out.outHeader, unsafe.Sizeof(*out))
  1706  }
  1707  
  1708  // A XXXResponse is the response to a XXXRequest.
  1709  type XXXResponse struct {
  1710  	xxx
  1711  }
  1712  
  1713  func (r *XXXResponse) String() string {
  1714  	return fmt.Sprintf("XXX %+v", *r)
  1715  }
  1716  
  1717   }
  1718  */