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