github.com/hanwen/go-fuse@v1.0.0/fuse/opcode.go (about) 1 // Copyright 2016 the Go-FUSE Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package fuse 6 7 import ( 8 "bytes" 9 "fmt" 10 "log" 11 "reflect" 12 "runtime" 13 "unsafe" 14 ) 15 16 const ( 17 _OP_LOOKUP = int32(1) 18 _OP_FORGET = int32(2) 19 _OP_GETATTR = int32(3) 20 _OP_SETATTR = int32(4) 21 _OP_READLINK = int32(5) 22 _OP_SYMLINK = int32(6) 23 _OP_MKNOD = int32(8) 24 _OP_MKDIR = int32(9) 25 _OP_UNLINK = int32(10) 26 _OP_RMDIR = int32(11) 27 _OP_RENAME = int32(12) 28 _OP_LINK = int32(13) 29 _OP_OPEN = int32(14) 30 _OP_READ = int32(15) 31 _OP_WRITE = int32(16) 32 _OP_STATFS = int32(17) 33 _OP_RELEASE = int32(18) 34 _OP_FSYNC = int32(20) 35 _OP_SETXATTR = int32(21) 36 _OP_GETXATTR = int32(22) 37 _OP_LISTXATTR = int32(23) 38 _OP_REMOVEXATTR = int32(24) 39 _OP_FLUSH = int32(25) 40 _OP_INIT = int32(26) 41 _OP_OPENDIR = int32(27) 42 _OP_READDIR = int32(28) 43 _OP_RELEASEDIR = int32(29) 44 _OP_FSYNCDIR = int32(30) 45 _OP_GETLK = int32(31) 46 _OP_SETLK = int32(32) 47 _OP_SETLKW = int32(33) 48 _OP_ACCESS = int32(34) 49 _OP_CREATE = int32(35) 50 _OP_INTERRUPT = int32(36) 51 _OP_BMAP = int32(37) 52 _OP_DESTROY = int32(38) 53 _OP_IOCTL = int32(39) 54 _OP_POLL = int32(40) 55 _OP_NOTIFY_REPLY = int32(41) 56 _OP_BATCH_FORGET = int32(42) 57 _OP_FALLOCATE = int32(43) // protocol version 19. 58 _OP_READDIRPLUS = int32(44) // protocol version 21. 59 _OP_RENAME2 = int32(45) // protocol version 23. 60 61 // The following entries don't have to be compatible across Go-FUSE versions. 62 _OP_NOTIFY_INVAL_ENTRY = int32(100) 63 _OP_NOTIFY_INVAL_INODE = int32(101) 64 _OP_NOTIFY_STORE_CACHE = int32(102) 65 _OP_NOTIFY_RETRIEVE_CACHE = int32(103) 66 _OP_NOTIFY_DELETE = int32(104) // protocol version 18 67 68 _OPCODE_COUNT = int32(105) 69 ) 70 71 //////////////////////////////////////////////////////////////// 72 73 func doInit(server *Server, req *request) { 74 input := (*InitIn)(req.inData) 75 if input.Major != _FUSE_KERNEL_VERSION { 76 log.Printf("Major versions does not match. Given %d, want %d\n", input.Major, _FUSE_KERNEL_VERSION) 77 req.status = EIO 78 return 79 } 80 if input.Minor < _MINIMUM_MINOR_VERSION { 81 log.Printf("Minor version is less than we support. Given %d, want at least %d\n", input.Minor, _MINIMUM_MINOR_VERSION) 82 req.status = EIO 83 return 84 } 85 86 server.reqMu.Lock() 87 server.kernelSettings = *input 88 server.kernelSettings.Flags = input.Flags & (CAP_ASYNC_READ | CAP_BIG_WRITES | CAP_FILE_OPS | 89 CAP_AUTO_INVAL_DATA | CAP_READDIRPLUS | CAP_NO_OPEN_SUPPORT | CAP_PARALLEL_DIROPS) 90 91 if server.opts.EnableLocks { 92 server.kernelSettings.Flags |= CAP_FLOCK_LOCKS | CAP_POSIX_LOCKS 93 } 94 95 if input.Minor >= 13 { 96 server.setSplice() 97 } 98 server.reqMu.Unlock() 99 100 out := (*InitOut)(req.outData()) 101 *out = InitOut{ 102 Major: _FUSE_KERNEL_VERSION, 103 Minor: _OUR_MINOR_VERSION, 104 MaxReadAhead: input.MaxReadAhead, 105 Flags: server.kernelSettings.Flags, 106 MaxWrite: uint32(server.opts.MaxWrite), 107 CongestionThreshold: uint16(server.opts.MaxBackground * 3 / 4), 108 MaxBackground: uint16(server.opts.MaxBackground), 109 } 110 111 if server.opts.MaxReadAhead != 0 && uint32(server.opts.MaxReadAhead) < out.MaxReadAhead { 112 out.MaxReadAhead = uint32(server.opts.MaxReadAhead) 113 } 114 if out.Minor > input.Minor { 115 out.Minor = input.Minor 116 } 117 118 if out.Minor <= 22 { 119 tweaked := *req.handler 120 121 // v8-v22 don't have TimeGran and further fields. 122 tweaked.OutputSize = 24 123 req.handler = &tweaked 124 } 125 126 req.status = OK 127 } 128 129 func doOpen(server *Server, req *request) { 130 out := (*OpenOut)(req.outData()) 131 status := server.fileSystem.Open((*OpenIn)(req.inData), out) 132 req.status = status 133 if status != OK { 134 return 135 } 136 } 137 138 func doCreate(server *Server, req *request) { 139 out := (*CreateOut)(req.outData()) 140 status := server.fileSystem.Create((*CreateIn)(req.inData), req.filenames[0], out) 141 req.status = status 142 } 143 144 func doReadDir(server *Server, req *request) { 145 in := (*ReadIn)(req.inData) 146 buf := server.allocOut(req, in.Size) 147 out := NewDirEntryList(buf, uint64(in.Offset)) 148 149 code := server.fileSystem.ReadDir(in, out) 150 req.flatData = out.bytes() 151 req.status = code 152 } 153 154 func doReadDirPlus(server *Server, req *request) { 155 in := (*ReadIn)(req.inData) 156 buf := server.allocOut(req, in.Size) 157 out := NewDirEntryList(buf, uint64(in.Offset)) 158 159 code := server.fileSystem.ReadDirPlus(in, out) 160 req.flatData = out.bytes() 161 req.status = code 162 } 163 164 func doOpenDir(server *Server, req *request) { 165 out := (*OpenOut)(req.outData()) 166 status := server.fileSystem.OpenDir((*OpenIn)(req.inData), out) 167 req.status = status 168 } 169 170 func doSetattr(server *Server, req *request) { 171 out := (*AttrOut)(req.outData()) 172 req.status = server.fileSystem.SetAttr((*SetAttrIn)(req.inData), out) 173 } 174 175 func doWrite(server *Server, req *request) { 176 n, status := server.fileSystem.Write((*WriteIn)(req.inData), req.arg) 177 o := (*WriteOut)(req.outData()) 178 o.Size = n 179 req.status = status 180 } 181 182 func doNotifyReply(server *Server, req *request) { 183 reply := (*NotifyRetrieveIn)(req.inData) 184 server.retrieveMu.Lock() 185 reading := server.retrieveTab[reply.Unique] 186 delete(server.retrieveTab, reply.Unique) 187 server.retrieveMu.Unlock() 188 189 badf := func(format string, argv ...interface{}) { 190 log.Printf("notify reply: "+format, argv...) 191 } 192 193 if reading == nil { 194 badf("unexpected unique - ignoring") 195 return 196 } 197 198 reading.n = 0 199 reading.st = EIO 200 defer close(reading.ready) 201 202 if reading.nodeid != reply.NodeId { 203 badf("inode mismatch: expected %s, got %s", reading.nodeid, reply.NodeId) 204 return 205 } 206 207 if reading.offset != reply.Offset { 208 badf("offset mismatch: expected @%d, got @%d", reading.offset, reply.Offset) 209 return 210 } 211 212 if len(reading.dest) < len(req.arg) { 213 badf("too much data: requested %db, got %db (will use only %db)", len(reading.dest), len(req.arg), len(reading.dest)) 214 } 215 216 reading.n = copy(reading.dest, req.arg) 217 reading.st = OK 218 } 219 220 const _SECURITY_CAPABILITY = "security.capability" 221 const _SECURITY_ACL = "system.posix_acl_access" 222 const _SECURITY_ACL_DEFAULT = "system.posix_acl_default" 223 224 func doGetXAttr(server *Server, req *request) { 225 if server.opts.DisableXAttrs { 226 req.status = ENOSYS 227 return 228 } 229 230 if server.opts.IgnoreSecurityLabels && req.inHeader.Opcode == _OP_GETXATTR { 231 fn := req.filenames[0] 232 if fn == _SECURITY_CAPABILITY || fn == _SECURITY_ACL_DEFAULT || 233 fn == _SECURITY_ACL { 234 req.status = ENOATTR 235 return 236 } 237 } 238 239 input := (*GetXAttrIn)(req.inData) 240 241 if input.Size == 0 { 242 out := (*GetXAttrOut)(req.outData()) 243 switch req.inHeader.Opcode { 244 case _OP_GETXATTR: 245 // TODO(hanwen): double check this. For getxattr, input.Size 246 // field refers to the size of the attribute, so it usually 247 // is not 0. 248 sz, code := server.fileSystem.GetXAttrSize(req.inHeader, req.filenames[0]) 249 if code.Ok() { 250 out.Size = uint32(sz) 251 } 252 req.status = code 253 return 254 case _OP_LISTXATTR: 255 data, code := server.fileSystem.ListXAttr(req.inHeader) 256 if code.Ok() { 257 out.Size = uint32(len(data)) 258 } 259 req.status = code 260 return 261 } 262 } 263 var data []byte 264 switch req.inHeader.Opcode { 265 case _OP_GETXATTR: 266 data, req.status = server.fileSystem.GetXAttrData(req.inHeader, req.filenames[0]) 267 case _OP_LISTXATTR: 268 data, req.status = server.fileSystem.ListXAttr(req.inHeader) 269 default: 270 log.Panicf("xattr opcode %v", req.inHeader.Opcode) 271 req.status = ENOSYS 272 } 273 274 if len(data) > int(input.Size) { 275 req.status = ERANGE 276 } 277 278 if !req.status.Ok() { 279 return 280 } 281 282 req.flatData = data 283 } 284 285 func doGetAttr(server *Server, req *request) { 286 out := (*AttrOut)(req.outData()) 287 s := server.fileSystem.GetAttr((*GetAttrIn)(req.inData), out) 288 req.status = s 289 } 290 291 // doForget - forget one NodeId 292 func doForget(server *Server, req *request) { 293 if !server.opts.RememberInodes { 294 server.fileSystem.Forget(req.inHeader.NodeId, (*ForgetIn)(req.inData).Nlookup) 295 } 296 } 297 298 // doBatchForget - forget a list of NodeIds 299 func doBatchForget(server *Server, req *request) { 300 in := (*_BatchForgetIn)(req.inData) 301 wantBytes := uintptr(in.Count) * unsafe.Sizeof(_ForgetOne{}) 302 if uintptr(len(req.arg)) < wantBytes { 303 // We have no return value to complain, so log an error. 304 log.Printf("Too few bytes for batch forget. Got %d bytes, want %d (%d entries)", 305 len(req.arg), wantBytes, in.Count) 306 } 307 308 h := &reflect.SliceHeader{ 309 Data: uintptr(unsafe.Pointer(&req.arg[0])), 310 Len: int(in.Count), 311 Cap: int(in.Count), 312 } 313 314 forgets := *(*[]_ForgetOne)(unsafe.Pointer(h)) 315 for i, f := range forgets { 316 if server.opts.Debug { 317 log.Printf("doBatchForget: rx %d %d/%d: FORGET i%d {Nlookup=%d}", 318 req.inHeader.Unique, i+1, len(forgets), f.NodeId, f.Nlookup) 319 } 320 if f.NodeId == pollHackInode { 321 continue 322 } 323 server.fileSystem.Forget(f.NodeId, f.Nlookup) 324 } 325 } 326 327 func doReadlink(server *Server, req *request) { 328 req.flatData, req.status = server.fileSystem.Readlink(req.inHeader) 329 } 330 331 func doLookup(server *Server, req *request) { 332 out := (*EntryOut)(req.outData()) 333 s := server.fileSystem.Lookup(req.inHeader, req.filenames[0], out) 334 req.status = s 335 } 336 337 func doMknod(server *Server, req *request) { 338 out := (*EntryOut)(req.outData()) 339 340 req.status = server.fileSystem.Mknod((*MknodIn)(req.inData), req.filenames[0], out) 341 } 342 343 func doMkdir(server *Server, req *request) { 344 out := (*EntryOut)(req.outData()) 345 req.status = server.fileSystem.Mkdir((*MkdirIn)(req.inData), req.filenames[0], out) 346 } 347 348 func doUnlink(server *Server, req *request) { 349 req.status = server.fileSystem.Unlink(req.inHeader, req.filenames[0]) 350 } 351 352 func doRmdir(server *Server, req *request) { 353 req.status = server.fileSystem.Rmdir(req.inHeader, req.filenames[0]) 354 } 355 356 func doLink(server *Server, req *request) { 357 out := (*EntryOut)(req.outData()) 358 req.status = server.fileSystem.Link((*LinkIn)(req.inData), req.filenames[0], out) 359 } 360 361 func doRead(server *Server, req *request) { 362 in := (*ReadIn)(req.inData) 363 buf := server.allocOut(req, in.Size) 364 365 req.readResult, req.status = server.fileSystem.Read(in, buf) 366 if fd, ok := req.readResult.(*readResultFd); ok { 367 req.fdData = fd 368 req.flatData = nil 369 } else if req.readResult != nil && req.status.Ok() { 370 req.flatData, req.status = req.readResult.Bytes(buf) 371 } 372 } 373 374 func doFlush(server *Server, req *request) { 375 req.status = server.fileSystem.Flush((*FlushIn)(req.inData)) 376 } 377 378 func doRelease(server *Server, req *request) { 379 server.fileSystem.Release((*ReleaseIn)(req.inData)) 380 } 381 382 func doFsync(server *Server, req *request) { 383 req.status = server.fileSystem.Fsync((*FsyncIn)(req.inData)) 384 } 385 386 func doReleaseDir(server *Server, req *request) { 387 server.fileSystem.ReleaseDir((*ReleaseIn)(req.inData)) 388 } 389 390 func doFsyncDir(server *Server, req *request) { 391 req.status = server.fileSystem.FsyncDir((*FsyncIn)(req.inData)) 392 } 393 394 func doSetXAttr(server *Server, req *request) { 395 splits := bytes.SplitN(req.arg, []byte{0}, 2) 396 req.status = server.fileSystem.SetXAttr((*SetXAttrIn)(req.inData), string(splits[0]), splits[1]) 397 } 398 399 func doRemoveXAttr(server *Server, req *request) { 400 req.status = server.fileSystem.RemoveXAttr(req.inHeader, req.filenames[0]) 401 } 402 403 func doAccess(server *Server, req *request) { 404 req.status = server.fileSystem.Access((*AccessIn)(req.inData)) 405 } 406 407 func doSymlink(server *Server, req *request) { 408 out := (*EntryOut)(req.outData()) 409 req.status = server.fileSystem.Symlink(req.inHeader, req.filenames[1], req.filenames[0], out) 410 } 411 412 func doRename(server *Server, req *request) { 413 in1 := (*Rename1In)(req.inData) 414 in := RenameIn{ 415 InHeader: in1.InHeader, 416 Newdir: in1.Newdir, 417 } 418 req.status = server.fileSystem.Rename(&in, req.filenames[0], req.filenames[1]) 419 } 420 421 func doRename2(server *Server, req *request) { 422 req.status = server.fileSystem.Rename((*RenameIn)(req.inData), req.filenames[0], req.filenames[1]) 423 } 424 425 func doStatFs(server *Server, req *request) { 426 out := (*StatfsOut)(req.outData()) 427 req.status = server.fileSystem.StatFs(req.inHeader, out) 428 if req.status == ENOSYS && runtime.GOOS == "darwin" { 429 // OSX FUSE requires Statfs to be implemented for the 430 // mount to succeed. 431 *out = StatfsOut{} 432 req.status = OK 433 } 434 } 435 436 func doIoctl(server *Server, req *request) { 437 req.status = ENOSYS 438 } 439 440 func doDestroy(server *Server, req *request) { 441 req.status = OK 442 } 443 444 func doFallocate(server *Server, req *request) { 445 req.status = server.fileSystem.Fallocate((*FallocateIn)(req.inData)) 446 } 447 448 func doGetLk(server *Server, req *request) { 449 req.status = server.fileSystem.GetLk((*LkIn)(req.inData), (*LkOut)(req.outData())) 450 } 451 452 func doSetLk(server *Server, req *request) { 453 req.status = server.fileSystem.SetLk((*LkIn)(req.inData)) 454 } 455 456 func doSetLkw(server *Server, req *request) { 457 req.status = server.fileSystem.SetLkw((*LkIn)(req.inData)) 458 } 459 460 //////////////////////////////////////////////////////////////// 461 462 type operationFunc func(*Server, *request) 463 type castPointerFunc func(unsafe.Pointer) interface{} 464 465 type operationHandler struct { 466 Name string 467 Func operationFunc 468 InputSize uintptr 469 OutputSize uintptr 470 DecodeIn castPointerFunc 471 DecodeOut castPointerFunc 472 FileNames int 473 FileNameOut bool 474 } 475 476 var operationHandlers []*operationHandler 477 478 func operationName(op int32) string { 479 h := getHandler(op) 480 if h == nil { 481 return "unknown" 482 } 483 return h.Name 484 } 485 486 func getHandler(o int32) *operationHandler { 487 if o >= _OPCODE_COUNT { 488 return nil 489 } 490 return operationHandlers[o] 491 } 492 493 func init() { 494 operationHandlers = make([]*operationHandler, _OPCODE_COUNT) 495 for i := range operationHandlers { 496 operationHandlers[i] = &operationHandler{Name: fmt.Sprintf("OPCODE-%d", i)} 497 } 498 499 fileOps := []int32{_OP_READLINK, _OP_NOTIFY_INVAL_ENTRY, _OP_NOTIFY_DELETE} 500 for _, op := range fileOps { 501 operationHandlers[op].FileNameOut = true 502 } 503 504 for op, sz := range map[int32]uintptr{ 505 _OP_FORGET: unsafe.Sizeof(ForgetIn{}), 506 _OP_BATCH_FORGET: unsafe.Sizeof(_BatchForgetIn{}), 507 _OP_GETATTR: unsafe.Sizeof(GetAttrIn{}), 508 _OP_SETATTR: unsafe.Sizeof(SetAttrIn{}), 509 _OP_MKNOD: unsafe.Sizeof(MknodIn{}), 510 _OP_MKDIR: unsafe.Sizeof(MkdirIn{}), 511 _OP_RENAME: unsafe.Sizeof(Rename1In{}), 512 _OP_LINK: unsafe.Sizeof(LinkIn{}), 513 _OP_OPEN: unsafe.Sizeof(OpenIn{}), 514 _OP_READ: unsafe.Sizeof(ReadIn{}), 515 _OP_WRITE: unsafe.Sizeof(WriteIn{}), 516 _OP_RELEASE: unsafe.Sizeof(ReleaseIn{}), 517 _OP_FSYNC: unsafe.Sizeof(FsyncIn{}), 518 _OP_SETXATTR: unsafe.Sizeof(SetXAttrIn{}), 519 _OP_GETXATTR: unsafe.Sizeof(GetXAttrIn{}), 520 _OP_LISTXATTR: unsafe.Sizeof(GetXAttrIn{}), 521 _OP_FLUSH: unsafe.Sizeof(FlushIn{}), 522 _OP_INIT: unsafe.Sizeof(InitIn{}), 523 _OP_OPENDIR: unsafe.Sizeof(OpenIn{}), 524 _OP_READDIR: unsafe.Sizeof(ReadIn{}), 525 _OP_RELEASEDIR: unsafe.Sizeof(ReleaseIn{}), 526 _OP_FSYNCDIR: unsafe.Sizeof(FsyncIn{}), 527 _OP_GETLK: unsafe.Sizeof(LkIn{}), 528 _OP_SETLK: unsafe.Sizeof(LkIn{}), 529 _OP_SETLKW: unsafe.Sizeof(LkIn{}), 530 _OP_ACCESS: unsafe.Sizeof(AccessIn{}), 531 _OP_CREATE: unsafe.Sizeof(CreateIn{}), 532 _OP_INTERRUPT: unsafe.Sizeof(InterruptIn{}), 533 _OP_BMAP: unsafe.Sizeof(_BmapIn{}), 534 _OP_IOCTL: unsafe.Sizeof(_IoctlIn{}), 535 _OP_POLL: unsafe.Sizeof(_PollIn{}), 536 _OP_NOTIFY_REPLY: unsafe.Sizeof(NotifyRetrieveIn{}), 537 _OP_FALLOCATE: unsafe.Sizeof(FallocateIn{}), 538 _OP_READDIRPLUS: unsafe.Sizeof(ReadIn{}), 539 _OP_RENAME2: unsafe.Sizeof(RenameIn{}), 540 } { 541 operationHandlers[op].InputSize = sz 542 } 543 544 for op, sz := range map[int32]uintptr{ 545 _OP_LOOKUP: unsafe.Sizeof(EntryOut{}), 546 _OP_GETATTR: unsafe.Sizeof(AttrOut{}), 547 _OP_SETATTR: unsafe.Sizeof(AttrOut{}), 548 _OP_SYMLINK: unsafe.Sizeof(EntryOut{}), 549 _OP_MKNOD: unsafe.Sizeof(EntryOut{}), 550 _OP_MKDIR: unsafe.Sizeof(EntryOut{}), 551 _OP_LINK: unsafe.Sizeof(EntryOut{}), 552 _OP_OPEN: unsafe.Sizeof(OpenOut{}), 553 _OP_WRITE: unsafe.Sizeof(WriteOut{}), 554 _OP_STATFS: unsafe.Sizeof(StatfsOut{}), 555 _OP_GETXATTR: unsafe.Sizeof(GetXAttrOut{}), 556 _OP_LISTXATTR: unsafe.Sizeof(GetXAttrOut{}), 557 _OP_INIT: unsafe.Sizeof(InitOut{}), 558 _OP_OPENDIR: unsafe.Sizeof(OpenOut{}), 559 _OP_GETLK: unsafe.Sizeof(LkOut{}), 560 _OP_CREATE: unsafe.Sizeof(CreateOut{}), 561 _OP_BMAP: unsafe.Sizeof(_BmapOut{}), 562 _OP_IOCTL: unsafe.Sizeof(_IoctlOut{}), 563 _OP_POLL: unsafe.Sizeof(_PollOut{}), 564 _OP_NOTIFY_INVAL_ENTRY: unsafe.Sizeof(NotifyInvalEntryOut{}), 565 _OP_NOTIFY_INVAL_INODE: unsafe.Sizeof(NotifyInvalInodeOut{}), 566 _OP_NOTIFY_STORE_CACHE: unsafe.Sizeof(NotifyStoreOut{}), 567 _OP_NOTIFY_RETRIEVE_CACHE: unsafe.Sizeof(NotifyRetrieveOut{}), 568 _OP_NOTIFY_DELETE: unsafe.Sizeof(NotifyInvalDeleteOut{}), 569 } { 570 operationHandlers[op].OutputSize = sz 571 } 572 573 for op, v := range map[int32]string{ 574 _OP_LOOKUP: "LOOKUP", 575 _OP_FORGET: "FORGET", 576 _OP_BATCH_FORGET: "BATCH_FORGET", 577 _OP_GETATTR: "GETATTR", 578 _OP_SETATTR: "SETATTR", 579 _OP_READLINK: "READLINK", 580 _OP_SYMLINK: "SYMLINK", 581 _OP_MKNOD: "MKNOD", 582 _OP_MKDIR: "MKDIR", 583 _OP_UNLINK: "UNLINK", 584 _OP_RMDIR: "RMDIR", 585 _OP_RENAME: "RENAME", 586 _OP_LINK: "LINK", 587 _OP_OPEN: "OPEN", 588 _OP_READ: "READ", 589 _OP_WRITE: "WRITE", 590 _OP_STATFS: "STATFS", 591 _OP_RELEASE: "RELEASE", 592 _OP_FSYNC: "FSYNC", 593 _OP_SETXATTR: "SETXATTR", 594 _OP_GETXATTR: "GETXATTR", 595 _OP_LISTXATTR: "LISTXATTR", 596 _OP_REMOVEXATTR: "REMOVEXATTR", 597 _OP_FLUSH: "FLUSH", 598 _OP_INIT: "INIT", 599 _OP_OPENDIR: "OPENDIR", 600 _OP_READDIR: "READDIR", 601 _OP_RELEASEDIR: "RELEASEDIR", 602 _OP_FSYNCDIR: "FSYNCDIR", 603 _OP_GETLK: "GETLK", 604 _OP_SETLK: "SETLK", 605 _OP_SETLKW: "SETLKW", 606 _OP_ACCESS: "ACCESS", 607 _OP_CREATE: "CREATE", 608 _OP_INTERRUPT: "INTERRUPT", 609 _OP_BMAP: "BMAP", 610 _OP_DESTROY: "DESTROY", 611 _OP_IOCTL: "IOCTL", 612 _OP_POLL: "POLL", 613 _OP_NOTIFY_REPLY: "NOTIFY_REPLY", 614 _OP_NOTIFY_INVAL_ENTRY: "NOTIFY_INVAL_ENTRY", 615 _OP_NOTIFY_INVAL_INODE: "NOTIFY_INVAL_INODE", 616 _OP_NOTIFY_STORE_CACHE: "NOTIFY_STORE", 617 _OP_NOTIFY_RETRIEVE_CACHE: "NOTIFY_RETRIEVE", 618 _OP_NOTIFY_DELETE: "NOTIFY_DELETE", 619 _OP_FALLOCATE: "FALLOCATE", 620 _OP_READDIRPLUS: "READDIRPLUS", 621 _OP_RENAME2: "RENAME2", 622 } { 623 operationHandlers[op].Name = v 624 } 625 626 for op, v := range map[int32]operationFunc{ 627 _OP_OPEN: doOpen, 628 _OP_READDIR: doReadDir, 629 _OP_WRITE: doWrite, 630 _OP_OPENDIR: doOpenDir, 631 _OP_CREATE: doCreate, 632 _OP_SETATTR: doSetattr, 633 _OP_GETXATTR: doGetXAttr, 634 _OP_LISTXATTR: doGetXAttr, 635 _OP_GETATTR: doGetAttr, 636 _OP_FORGET: doForget, 637 _OP_BATCH_FORGET: doBatchForget, 638 _OP_READLINK: doReadlink, 639 _OP_INIT: doInit, 640 _OP_LOOKUP: doLookup, 641 _OP_MKNOD: doMknod, 642 _OP_MKDIR: doMkdir, 643 _OP_UNLINK: doUnlink, 644 _OP_RMDIR: doRmdir, 645 _OP_LINK: doLink, 646 _OP_READ: doRead, 647 _OP_FLUSH: doFlush, 648 _OP_RELEASE: doRelease, 649 _OP_FSYNC: doFsync, 650 _OP_RELEASEDIR: doReleaseDir, 651 _OP_FSYNCDIR: doFsyncDir, 652 _OP_SETXATTR: doSetXAttr, 653 _OP_REMOVEXATTR: doRemoveXAttr, 654 _OP_GETLK: doGetLk, 655 _OP_SETLK: doSetLk, 656 _OP_SETLKW: doSetLkw, 657 _OP_ACCESS: doAccess, 658 _OP_SYMLINK: doSymlink, 659 _OP_RENAME: doRename, 660 _OP_STATFS: doStatFs, 661 _OP_IOCTL: doIoctl, 662 _OP_DESTROY: doDestroy, 663 _OP_NOTIFY_REPLY: doNotifyReply, 664 _OP_FALLOCATE: doFallocate, 665 _OP_READDIRPLUS: doReadDirPlus, 666 _OP_RENAME2: doRename2, 667 } { 668 operationHandlers[op].Func = v 669 } 670 671 // Outputs. 672 for op, f := range map[int32]castPointerFunc{ 673 _OP_LOOKUP: func(ptr unsafe.Pointer) interface{} { return (*EntryOut)(ptr) }, 674 _OP_OPEN: func(ptr unsafe.Pointer) interface{} { return (*OpenOut)(ptr) }, 675 _OP_OPENDIR: func(ptr unsafe.Pointer) interface{} { return (*OpenOut)(ptr) }, 676 _OP_GETATTR: func(ptr unsafe.Pointer) interface{} { return (*AttrOut)(ptr) }, 677 _OP_CREATE: func(ptr unsafe.Pointer) interface{} { return (*CreateOut)(ptr) }, 678 _OP_LINK: func(ptr unsafe.Pointer) interface{} { return (*EntryOut)(ptr) }, 679 _OP_SETATTR: func(ptr unsafe.Pointer) interface{} { return (*AttrOut)(ptr) }, 680 _OP_INIT: func(ptr unsafe.Pointer) interface{} { return (*InitOut)(ptr) }, 681 _OP_MKDIR: func(ptr unsafe.Pointer) interface{} { return (*EntryOut)(ptr) }, 682 _OP_NOTIFY_INVAL_ENTRY: func(ptr unsafe.Pointer) interface{} { return (*NotifyInvalEntryOut)(ptr) }, 683 _OP_NOTIFY_INVAL_INODE: func(ptr unsafe.Pointer) interface{} { return (*NotifyInvalInodeOut)(ptr) }, 684 _OP_NOTIFY_STORE_CACHE: func(ptr unsafe.Pointer) interface{} { return (*NotifyStoreOut)(ptr) }, 685 _OP_NOTIFY_RETRIEVE_CACHE: func(ptr unsafe.Pointer) interface{} { return (*NotifyRetrieveOut)(ptr) }, 686 _OP_NOTIFY_DELETE: func(ptr unsafe.Pointer) interface{} { return (*NotifyInvalDeleteOut)(ptr) }, 687 _OP_STATFS: func(ptr unsafe.Pointer) interface{} { return (*StatfsOut)(ptr) }, 688 _OP_SYMLINK: func(ptr unsafe.Pointer) interface{} { return (*EntryOut)(ptr) }, 689 _OP_GETLK: func(ptr unsafe.Pointer) interface{} { return (*LkOut)(ptr) }, 690 } { 691 operationHandlers[op].DecodeOut = f 692 } 693 694 // Inputs. 695 for op, f := range map[int32]castPointerFunc{ 696 _OP_FLUSH: func(ptr unsafe.Pointer) interface{} { return (*FlushIn)(ptr) }, 697 _OP_GETATTR: func(ptr unsafe.Pointer) interface{} { return (*GetAttrIn)(ptr) }, 698 _OP_SETXATTR: func(ptr unsafe.Pointer) interface{} { return (*SetXAttrIn)(ptr) }, 699 _OP_GETXATTR: func(ptr unsafe.Pointer) interface{} { return (*GetXAttrIn)(ptr) }, 700 _OP_LISTXATTR: func(ptr unsafe.Pointer) interface{} { return (*GetXAttrIn)(ptr) }, 701 _OP_SETATTR: func(ptr unsafe.Pointer) interface{} { return (*SetAttrIn)(ptr) }, 702 _OP_INIT: func(ptr unsafe.Pointer) interface{} { return (*InitIn)(ptr) }, 703 _OP_IOCTL: func(ptr unsafe.Pointer) interface{} { return (*_IoctlIn)(ptr) }, 704 _OP_OPEN: func(ptr unsafe.Pointer) interface{} { return (*OpenIn)(ptr) }, 705 _OP_MKNOD: func(ptr unsafe.Pointer) interface{} { return (*MknodIn)(ptr) }, 706 _OP_CREATE: func(ptr unsafe.Pointer) interface{} { return (*CreateIn)(ptr) }, 707 _OP_READ: func(ptr unsafe.Pointer) interface{} { return (*ReadIn)(ptr) }, 708 _OP_READDIR: func(ptr unsafe.Pointer) interface{} { return (*ReadIn)(ptr) }, 709 _OP_ACCESS: func(ptr unsafe.Pointer) interface{} { return (*AccessIn)(ptr) }, 710 _OP_FORGET: func(ptr unsafe.Pointer) interface{} { return (*ForgetIn)(ptr) }, 711 _OP_BATCH_FORGET: func(ptr unsafe.Pointer) interface{} { return (*_BatchForgetIn)(ptr) }, 712 _OP_LINK: func(ptr unsafe.Pointer) interface{} { return (*LinkIn)(ptr) }, 713 _OP_MKDIR: func(ptr unsafe.Pointer) interface{} { return (*MkdirIn)(ptr) }, 714 _OP_RELEASE: func(ptr unsafe.Pointer) interface{} { return (*ReleaseIn)(ptr) }, 715 _OP_RELEASEDIR: func(ptr unsafe.Pointer) interface{} { return (*ReleaseIn)(ptr) }, 716 _OP_FALLOCATE: func(ptr unsafe.Pointer) interface{} { return (*FallocateIn)(ptr) }, 717 _OP_NOTIFY_REPLY: func(ptr unsafe.Pointer) interface{} { return (*NotifyRetrieveIn)(ptr) }, 718 _OP_READDIRPLUS: func(ptr unsafe.Pointer) interface{} { return (*ReadIn)(ptr) }, 719 _OP_RENAME: func(ptr unsafe.Pointer) interface{} { return (*Rename1In)(ptr) }, 720 _OP_GETLK: func(ptr unsafe.Pointer) interface{} { return (*LkIn)(ptr) }, 721 _OP_SETLK: func(ptr unsafe.Pointer) interface{} { return (*LkIn)(ptr) }, 722 _OP_SETLKW: func(ptr unsafe.Pointer) interface{} { return (*LkIn)(ptr) }, 723 _OP_RENAME2: func(ptr unsafe.Pointer) interface{} { return (*RenameIn)(ptr) }, 724 } { 725 operationHandlers[op].DecodeIn = f 726 } 727 728 // File name args. 729 for op, count := range map[int32]int{ 730 _OP_CREATE: 1, 731 _OP_SETXATTR: 1, 732 _OP_GETXATTR: 1, 733 _OP_LINK: 1, 734 _OP_LOOKUP: 1, 735 _OP_MKDIR: 1, 736 _OP_MKNOD: 1, 737 _OP_REMOVEXATTR: 1, 738 _OP_RENAME: 2, 739 _OP_RENAME2: 2, 740 _OP_RMDIR: 1, 741 _OP_SYMLINK: 2, 742 _OP_UNLINK: 1, 743 } { 744 operationHandlers[op].FileNames = count 745 } 746 747 var r request 748 sizeOfOutHeader := unsafe.Sizeof(OutHeader{}) 749 for code, h := range operationHandlers { 750 if h.OutputSize+sizeOfOutHeader > unsafe.Sizeof(r.outBuf) { 751 log.Panicf("request output buffer too small: code %v, sz %d + %d %v", code, h.OutputSize, sizeOfOutHeader, h) 752 } 753 } 754 }