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