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