github.com/nicocha30/gvisor-ligolo@v0.0.0-20230726075806-989fa2c0a413/pkg/p9/p9.go (about) 1 // Copyright 2018 The gVisor Authors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 // Package p9 is a 9P2000.L implementation. 16 package p9 17 18 import ( 19 "fmt" 20 "math" 21 "os" 22 "strings" 23 "syscall" 24 25 "golang.org/x/sys/unix" 26 "github.com/nicocha30/gvisor-ligolo/pkg/abi/linux" 27 "github.com/nicocha30/gvisor-ligolo/pkg/atomicbitops" 28 ) 29 30 // OpenFlags is the mode passed to Open and Create operations. 31 // 32 // These correspond to bits sent over the wire. 33 type OpenFlags uint32 34 35 const ( 36 // ReadOnly is a Tlopen and Tlcreate flag indicating read-only mode. 37 ReadOnly OpenFlags = 0 38 39 // WriteOnly is a Tlopen and Tlcreate flag indicating write-only mode. 40 WriteOnly OpenFlags = 1 41 42 // ReadWrite is a Tlopen flag indicates read-write mode. 43 ReadWrite OpenFlags = 2 44 45 // OpenFlagsModeMask is a mask of valid OpenFlags mode bits. 46 OpenFlagsModeMask OpenFlags = 3 47 48 // OpenTruncate is a Tlopen flag indicating that the opened file should be 49 // truncated. 50 OpenTruncate OpenFlags = 01000 51 ) 52 53 // SocketType is the socket type passed in Connect and Bind operations. 54 // 55 // These correspond to bits sent over the wire. 56 type SocketType uint32 57 58 const ( 59 // StreamSocket indicates SOCK_STREAM mode. 60 StreamSocket SocketType = 0 61 62 // DgramSocket indicates SOCK_DGRAM mode. 63 DgramSocket SocketType = 1 64 65 // SeqpacketSocket indicates SOCK_SEQPACKET mode. 66 SeqpacketSocket SocketType = 2 67 68 // AnonymousSocket is only valid for Connect calls, and indicates that 69 // the caller will accept any socket type. 70 AnonymousSocket SocketType = 3 71 ) 72 73 // ToLinux maps the SocketType to a Linux socket type. 74 func (st SocketType) ToLinux() (linux.SockType, bool) { 75 switch st { 76 case StreamSocket: 77 return linux.SOCK_STREAM, true 78 case DgramSocket: 79 return linux.SOCK_DGRAM, true 80 case SeqpacketSocket: 81 return linux.SOCK_SEQPACKET, true 82 default: 83 return 0, false 84 } 85 } 86 87 // SocketTypeFromLinux maps a Linux socket type to a SocketType. 88 func SocketTypeFromLinux(st linux.SockType) (SocketType, bool) { 89 switch st { 90 case linux.SOCK_STREAM: 91 return StreamSocket, true 92 case linux.SOCK_DGRAM: 93 return DgramSocket, true 94 case linux.SOCK_SEQPACKET: 95 return SeqpacketSocket, true 96 default: 97 return 0, false 98 } 99 } 100 101 // OSFlags converts a p9.OpenFlags to an int compatible with open(2). 102 func (o OpenFlags) OSFlags() int { 103 // "flags contains Linux open(2) flags bits" - 9P2000.L 104 return int(o) 105 } 106 107 // String implements fmt.Stringer. 108 func (o OpenFlags) String() string { 109 var buf strings.Builder 110 switch mode := o & OpenFlagsModeMask; mode { 111 case ReadOnly: 112 buf.WriteString("ReadOnly") 113 case WriteOnly: 114 buf.WriteString("WriteOnly") 115 case ReadWrite: 116 buf.WriteString("ReadWrite") 117 default: 118 fmt.Fprintf(&buf, "%#o", mode) 119 } 120 otherFlags := o &^ OpenFlagsModeMask 121 if otherFlags&OpenTruncate != 0 { 122 buf.WriteString("|OpenTruncate") 123 otherFlags &^= OpenTruncate 124 } 125 if otherFlags != 0 { 126 fmt.Fprintf(&buf, "|%#o", otherFlags) 127 } 128 return buf.String() 129 } 130 131 // Tag is a message tag. 132 type Tag uint16 133 134 // FID is a file identifier. 135 type FID uint64 136 137 // FileMode are flags corresponding to file modes. 138 // 139 // These correspond to bits sent over the wire. 140 // These also correspond to mode_t bits. 141 type FileMode uint32 142 143 const ( 144 // FileModeMask is a mask of all the file mode bits of FileMode. 145 FileModeMask FileMode = 0170000 146 147 // ModeSocket is an (unused) mode bit for a socket. 148 ModeSocket FileMode = 0140000 149 150 // ModeSymlink is a mode bit for a symlink. 151 ModeSymlink FileMode = 0120000 152 153 // ModeRegular is a mode bit for regular files. 154 ModeRegular FileMode = 0100000 155 156 // ModeBlockDevice is a mode bit for block devices. 157 ModeBlockDevice FileMode = 060000 158 159 // ModeDirectory is a mode bit for directories. 160 ModeDirectory FileMode = 040000 161 162 // ModeCharacterDevice is a mode bit for a character device. 163 ModeCharacterDevice FileMode = 020000 164 165 // ModeNamedPipe is a mode bit for a named pipe. 166 ModeNamedPipe FileMode = 010000 167 168 // Read is a mode bit indicating read permission. 169 Read FileMode = 04 170 171 // Write is a mode bit indicating write permission. 172 Write FileMode = 02 173 174 // Exec is a mode bit indicating exec permission. 175 Exec FileMode = 01 176 177 // AllPermissions is a mask with rwx bits set for user, group and others. 178 AllPermissions FileMode = 0777 179 180 // Sticky is a mode bit indicating sticky directories. 181 Sticky FileMode = 01000 182 183 // SetGID is the set group ID bit. 184 SetGID FileMode = 02000 185 186 // SetUID is the set user ID bit. 187 SetUID FileMode = 04000 188 189 // permissionsMask is the mask to apply to FileModes for permissions. It 190 // includes rwx bits for user, group, and others, as well as the sticky 191 // bit, setuid bit, and setgid bit. 192 permissionsMask FileMode = 07777 193 ) 194 195 // QIDType is the most significant byte of the FileMode word, to be used as the 196 // Type field of p9.QID. 197 func (m FileMode) QIDType() QIDType { 198 switch { 199 case m.IsDir(): 200 return TypeDir 201 case m.IsSocket(), m.IsNamedPipe(), m.IsCharacterDevice(): 202 // Best approximation. 203 return TypeAppendOnly 204 case m.IsSymlink(): 205 return TypeSymlink 206 default: 207 return TypeRegular 208 } 209 } 210 211 // FileType returns the file mode without the permission bits. 212 func (m FileMode) FileType() FileMode { 213 return m & FileModeMask 214 } 215 216 // Permissions returns just the permission bits of the mode. 217 func (m FileMode) Permissions() FileMode { 218 return m & permissionsMask 219 } 220 221 // Writable returns the mode with write bits added. 222 func (m FileMode) Writable() FileMode { 223 return m | 0222 224 } 225 226 // IsReadable returns true if m represents a file that can be read. 227 func (m FileMode) IsReadable() bool { 228 return m&0444 != 0 229 } 230 231 // IsWritable returns true if m represents a file that can be written to. 232 func (m FileMode) IsWritable() bool { 233 return m&0222 != 0 234 } 235 236 // IsExecutable returns true if m represents a file that can be executed. 237 func (m FileMode) IsExecutable() bool { 238 return m&0111 != 0 239 } 240 241 // IsRegular returns true if m is a regular file. 242 func (m FileMode) IsRegular() bool { 243 return m&FileModeMask == ModeRegular 244 } 245 246 // IsDir returns true if m represents a directory. 247 func (m FileMode) IsDir() bool { 248 return m&FileModeMask == ModeDirectory 249 } 250 251 // IsNamedPipe returns true if m represents a named pipe. 252 func (m FileMode) IsNamedPipe() bool { 253 return m&FileModeMask == ModeNamedPipe 254 } 255 256 // IsCharacterDevice returns true if m represents a character device. 257 func (m FileMode) IsCharacterDevice() bool { 258 return m&FileModeMask == ModeCharacterDevice 259 } 260 261 // IsBlockDevice returns true if m represents a character device. 262 func (m FileMode) IsBlockDevice() bool { 263 return m&FileModeMask == ModeBlockDevice 264 } 265 266 // IsSocket returns true if m represents a socket. 267 func (m FileMode) IsSocket() bool { 268 return m&FileModeMask == ModeSocket 269 } 270 271 // IsSymlink returns true if m represents a symlink. 272 func (m FileMode) IsSymlink() bool { 273 return m&FileModeMask == ModeSymlink 274 } 275 276 // ModeFromOS returns a FileMode from an os.FileMode. 277 func ModeFromOS(mode os.FileMode) FileMode { 278 m := FileMode(mode.Perm()) 279 switch { 280 case mode.IsDir(): 281 m |= ModeDirectory 282 case mode&os.ModeSymlink != 0: 283 m |= ModeSymlink 284 case mode&os.ModeSocket != 0: 285 m |= ModeSocket 286 case mode&os.ModeNamedPipe != 0: 287 m |= ModeNamedPipe 288 case mode&os.ModeCharDevice != 0: 289 m |= ModeCharacterDevice 290 case mode&os.ModeDevice != 0: 291 m |= ModeBlockDevice 292 default: 293 m |= ModeRegular 294 } 295 return m 296 } 297 298 // OSMode converts a p9.FileMode to an os.FileMode. 299 func (m FileMode) OSMode() os.FileMode { 300 var osMode os.FileMode 301 osMode |= os.FileMode(m.Permissions()) 302 switch { 303 case m.IsDir(): 304 osMode |= os.ModeDir 305 case m.IsSymlink(): 306 osMode |= os.ModeSymlink 307 case m.IsSocket(): 308 osMode |= os.ModeSocket 309 case m.IsNamedPipe(): 310 osMode |= os.ModeNamedPipe 311 case m.IsCharacterDevice(): 312 osMode |= os.ModeCharDevice | os.ModeDevice 313 case m.IsBlockDevice(): 314 osMode |= os.ModeDevice 315 } 316 return osMode 317 } 318 319 // UID represents a user ID. 320 type UID uint32 321 322 // Ok returns true if uid is not NoUID. 323 func (uid UID) Ok() bool { 324 return uid != NoUID 325 } 326 327 // GID represents a group ID. 328 type GID uint32 329 330 // Ok returns true if gid is not NoGID. 331 func (gid GID) Ok() bool { 332 return gid != NoGID 333 } 334 335 const ( 336 // NoTag is a sentinel used to indicate no valid tag. 337 NoTag Tag = math.MaxUint16 338 339 // NoFID is a sentinel used to indicate no valid FID. 340 NoFID FID = math.MaxUint32 341 342 // NoUID is a sentinel used to indicate no valid UID. 343 NoUID UID = math.MaxUint32 344 345 // NoGID is a sentinel used to indicate no valid GID. 346 NoGID GID = math.MaxUint32 347 ) 348 349 // MsgType is a type identifier. 350 type MsgType uint8 351 352 // MsgType declarations. 353 const ( 354 MsgTlerror MsgType = 6 355 MsgRlerror MsgType = 7 356 MsgTstatfs MsgType = 8 357 MsgRstatfs MsgType = 9 358 MsgTlopen MsgType = 12 359 MsgRlopen MsgType = 13 360 MsgTlcreate MsgType = 14 361 MsgRlcreate MsgType = 15 362 MsgTsymlink MsgType = 16 363 MsgRsymlink MsgType = 17 364 MsgTmknod MsgType = 18 365 MsgRmknod MsgType = 19 366 MsgTrename MsgType = 20 367 MsgRrename MsgType = 21 368 MsgTreadlink MsgType = 22 369 MsgRreadlink MsgType = 23 370 MsgTgetattr MsgType = 24 371 MsgRgetattr MsgType = 25 372 MsgTsetattr MsgType = 26 373 MsgRsetattr MsgType = 27 374 MsgTlistxattr MsgType = 28 375 MsgRlistxattr MsgType = 29 376 MsgTxattrwalk MsgType = 30 377 MsgRxattrwalk MsgType = 31 378 MsgTxattrcreate MsgType = 32 379 MsgRxattrcreate MsgType = 33 380 MsgTgetxattr MsgType = 34 381 MsgRgetxattr MsgType = 35 382 MsgTsetxattr MsgType = 36 383 MsgRsetxattr MsgType = 37 384 MsgTremovexattr MsgType = 38 385 MsgRremovexattr MsgType = 39 386 MsgTreaddir MsgType = 40 387 MsgRreaddir MsgType = 41 388 MsgTfsync MsgType = 50 389 MsgRfsync MsgType = 51 390 MsgTlink MsgType = 70 391 MsgRlink MsgType = 71 392 MsgTmkdir MsgType = 72 393 MsgRmkdir MsgType = 73 394 MsgTrenameat MsgType = 74 395 MsgRrenameat MsgType = 75 396 MsgTunlinkat MsgType = 76 397 MsgRunlinkat MsgType = 77 398 MsgTversion MsgType = 100 399 MsgRversion MsgType = 101 400 MsgTauth MsgType = 102 401 MsgRauth MsgType = 103 402 MsgTattach MsgType = 104 403 MsgRattach MsgType = 105 404 MsgTflush MsgType = 108 405 MsgRflush MsgType = 109 406 MsgTwalk MsgType = 110 407 MsgRwalk MsgType = 111 408 MsgTread MsgType = 116 409 MsgRread MsgType = 117 410 MsgTwrite MsgType = 118 411 MsgRwrite MsgType = 119 412 MsgTclunk MsgType = 120 413 MsgRclunk MsgType = 121 414 MsgTremove MsgType = 122 415 MsgRremove MsgType = 123 416 MsgTflushf MsgType = 124 417 MsgRflushf MsgType = 125 418 MsgTwalkgetattr MsgType = 126 419 MsgRwalkgetattr MsgType = 127 420 MsgTucreate MsgType = 128 421 MsgRucreate MsgType = 129 422 MsgTumkdir MsgType = 130 423 MsgRumkdir MsgType = 131 424 MsgTumknod MsgType = 132 425 MsgRumknod MsgType = 133 426 MsgTusymlink MsgType = 134 427 MsgRusymlink MsgType = 135 428 MsgTlconnect MsgType = 136 429 MsgRlconnect MsgType = 137 430 MsgTallocate MsgType = 138 431 MsgRallocate MsgType = 139 432 MsgTsetattrclunk MsgType = 140 433 MsgRsetattrclunk MsgType = 141 434 MsgTmultigetattr MsgType = 142 435 MsgRmultigetattr MsgType = 143 436 MsgTbind MsgType = 144 437 MsgRbind MsgType = 145 438 MsgTchannel MsgType = 250 439 MsgRchannel MsgType = 251 440 ) 441 442 // QIDType represents the file type for QIDs. 443 // 444 // QIDType corresponds to the high 8 bits of a Plan 9 file mode. 445 type QIDType uint8 446 447 const ( 448 // TypeDir represents a directory type. 449 TypeDir QIDType = 0x80 450 451 // TypeAppendOnly represents an append only file. 452 TypeAppendOnly QIDType = 0x40 453 454 // TypeExclusive represents an exclusive-use file. 455 TypeExclusive QIDType = 0x20 456 457 // TypeMount represents a mounted channel. 458 TypeMount QIDType = 0x10 459 460 // TypeAuth represents an authentication file. 461 TypeAuth QIDType = 0x08 462 463 // TypeTemporary represents a temporary file. 464 TypeTemporary QIDType = 0x04 465 466 // TypeSymlink represents a symlink. 467 TypeSymlink QIDType = 0x02 468 469 // TypeLink represents a hard link. 470 TypeLink QIDType = 0x01 471 472 // TypeRegular represents a regular file. 473 TypeRegular QIDType = 0x00 474 ) 475 476 // QID is a unique file identifier. 477 // 478 // This may be embedded in other requests and responses. 479 type QID struct { 480 // Type is the highest order byte of the file mode. 481 Type QIDType 482 483 // Version is an arbitrary server version number. 484 Version uint32 485 486 // Path is a unique server identifier for this path (e.g. inode). 487 Path uint64 488 } 489 490 // String implements fmt.Stringer. 491 func (q QID) String() string { 492 return fmt.Sprintf("QID{Type: %d, Version: %d, Path: %d}", q.Type, q.Version, q.Path) 493 } 494 495 // decode implements encoder.decode. 496 func (q *QID) decode(b *buffer) { 497 q.Type = b.ReadQIDType() 498 q.Version = b.Read32() 499 q.Path = b.Read64() 500 } 501 502 // encode implements encoder.encode. 503 func (q *QID) encode(b *buffer) { 504 b.WriteQIDType(q.Type) 505 b.Write32(q.Version) 506 b.Write64(q.Path) 507 } 508 509 // QIDGenerator is a simple generator for QIDs that atomically increments Path 510 // values. 511 type QIDGenerator struct { 512 // uids is an ever increasing value that can be atomically incremented 513 // to provide unique Path values for QIDs. 514 uids atomicbitops.Uint64 515 } 516 517 // Get returns a new 9P unique ID with a unique Path given a QID type. 518 // 519 // While the 9P spec allows Version to be incremented every time the file is 520 // modified, we currently do not use the Version member for anything. Hence, 521 // it is set to 0. 522 func (q *QIDGenerator) Get(t QIDType) QID { 523 return QID{ 524 Type: t, 525 Version: 0, 526 Path: q.uids.Add(1), 527 } 528 } 529 530 // FSStat is used by statfs. 531 type FSStat struct { 532 // Type is the filesystem type. 533 Type uint32 534 535 // BlockSize is the blocksize. 536 BlockSize uint32 537 538 // Blocks is the number of blocks. 539 Blocks uint64 540 541 // BlocksFree is the number of free blocks. 542 BlocksFree uint64 543 544 // BlocksAvailable is the number of blocks *available*. 545 BlocksAvailable uint64 546 547 // Files is the number of files available. 548 Files uint64 549 550 // FilesFree is the number of free file nodes. 551 FilesFree uint64 552 553 // FSID is the filesystem ID. 554 FSID uint64 555 556 // NameLength is the maximum name length. 557 NameLength uint32 558 } 559 560 // decode implements encoder.decode. 561 func (f *FSStat) decode(b *buffer) { 562 f.Type = b.Read32() 563 f.BlockSize = b.Read32() 564 f.Blocks = b.Read64() 565 f.BlocksFree = b.Read64() 566 f.BlocksAvailable = b.Read64() 567 f.Files = b.Read64() 568 f.FilesFree = b.Read64() 569 f.FSID = b.Read64() 570 f.NameLength = b.Read32() 571 } 572 573 // encode implements encoder.encode. 574 func (f *FSStat) encode(b *buffer) { 575 b.Write32(f.Type) 576 b.Write32(f.BlockSize) 577 b.Write64(f.Blocks) 578 b.Write64(f.BlocksFree) 579 b.Write64(f.BlocksAvailable) 580 b.Write64(f.Files) 581 b.Write64(f.FilesFree) 582 b.Write64(f.FSID) 583 b.Write32(f.NameLength) 584 } 585 586 // AttrMask is a mask of attributes for getattr. 587 type AttrMask struct { 588 Mode bool 589 NLink bool 590 UID bool 591 GID bool 592 RDev bool 593 ATime bool 594 MTime bool 595 CTime bool 596 INo bool 597 Size bool 598 Blocks bool 599 BTime bool 600 Gen bool 601 DataVersion bool 602 } 603 604 // Contains returns true if a contains all of the attributes masked as b. 605 func (a AttrMask) Contains(b AttrMask) bool { 606 if b.Mode && !a.Mode { 607 return false 608 } 609 if b.NLink && !a.NLink { 610 return false 611 } 612 if b.UID && !a.UID { 613 return false 614 } 615 if b.GID && !a.GID { 616 return false 617 } 618 if b.RDev && !a.RDev { 619 return false 620 } 621 if b.ATime && !a.ATime { 622 return false 623 } 624 if b.MTime && !a.MTime { 625 return false 626 } 627 if b.CTime && !a.CTime { 628 return false 629 } 630 if b.INo && !a.INo { 631 return false 632 } 633 if b.Size && !a.Size { 634 return false 635 } 636 if b.Blocks && !a.Blocks { 637 return false 638 } 639 if b.BTime && !a.BTime { 640 return false 641 } 642 if b.Gen && !a.Gen { 643 return false 644 } 645 if b.DataVersion && !a.DataVersion { 646 return false 647 } 648 return true 649 } 650 651 // Empty returns true if no fields are masked. 652 func (a AttrMask) Empty() bool { 653 return !a.Mode && !a.NLink && !a.UID && !a.GID && !a.RDev && !a.ATime && !a.MTime && !a.CTime && !a.INo && !a.Size && !a.Blocks && !a.BTime && !a.Gen && !a.DataVersion 654 } 655 656 // AttrMaskAll returns an AttrMask with all fields masked. 657 func AttrMaskAll() AttrMask { 658 return AttrMask{ 659 Mode: true, 660 NLink: true, 661 UID: true, 662 GID: true, 663 RDev: true, 664 ATime: true, 665 MTime: true, 666 CTime: true, 667 INo: true, 668 Size: true, 669 Blocks: true, 670 BTime: true, 671 Gen: true, 672 DataVersion: true, 673 } 674 } 675 676 // String implements fmt.Stringer. 677 func (a AttrMask) String() string { 678 var masks []string 679 if a.Mode { 680 masks = append(masks, "Mode") 681 } 682 if a.NLink { 683 masks = append(masks, "NLink") 684 } 685 if a.UID { 686 masks = append(masks, "UID") 687 } 688 if a.GID { 689 masks = append(masks, "GID") 690 } 691 if a.RDev { 692 masks = append(masks, "RDev") 693 } 694 if a.ATime { 695 masks = append(masks, "ATime") 696 } 697 if a.MTime { 698 masks = append(masks, "MTime") 699 } 700 if a.CTime { 701 masks = append(masks, "CTime") 702 } 703 if a.INo { 704 masks = append(masks, "INo") 705 } 706 if a.Size { 707 masks = append(masks, "Size") 708 } 709 if a.Blocks { 710 masks = append(masks, "Blocks") 711 } 712 if a.BTime { 713 masks = append(masks, "BTime") 714 } 715 if a.Gen { 716 masks = append(masks, "Gen") 717 } 718 if a.DataVersion { 719 masks = append(masks, "DataVersion") 720 } 721 return fmt.Sprintf("AttrMask{with: %s}", strings.Join(masks, " ")) 722 } 723 724 // decode implements encoder.decode. 725 func (a *AttrMask) decode(b *buffer) { 726 mask := b.Read64() 727 a.Mode = mask&0x00000001 != 0 728 a.NLink = mask&0x00000002 != 0 729 a.UID = mask&0x00000004 != 0 730 a.GID = mask&0x00000008 != 0 731 a.RDev = mask&0x00000010 != 0 732 a.ATime = mask&0x00000020 != 0 733 a.MTime = mask&0x00000040 != 0 734 a.CTime = mask&0x00000080 != 0 735 a.INo = mask&0x00000100 != 0 736 a.Size = mask&0x00000200 != 0 737 a.Blocks = mask&0x00000400 != 0 738 a.BTime = mask&0x00000800 != 0 739 a.Gen = mask&0x00001000 != 0 740 a.DataVersion = mask&0x00002000 != 0 741 } 742 743 // encode implements encoder.encode. 744 func (a *AttrMask) encode(b *buffer) { 745 var mask uint64 746 if a.Mode { 747 mask |= 0x00000001 748 } 749 if a.NLink { 750 mask |= 0x00000002 751 } 752 if a.UID { 753 mask |= 0x00000004 754 } 755 if a.GID { 756 mask |= 0x00000008 757 } 758 if a.RDev { 759 mask |= 0x00000010 760 } 761 if a.ATime { 762 mask |= 0x00000020 763 } 764 if a.MTime { 765 mask |= 0x00000040 766 } 767 if a.CTime { 768 mask |= 0x00000080 769 } 770 if a.INo { 771 mask |= 0x00000100 772 } 773 if a.Size { 774 mask |= 0x00000200 775 } 776 if a.Blocks { 777 mask |= 0x00000400 778 } 779 if a.BTime { 780 mask |= 0x00000800 781 } 782 if a.Gen { 783 mask |= 0x00001000 784 } 785 if a.DataVersion { 786 mask |= 0x00002000 787 } 788 b.Write64(mask) 789 } 790 791 // Attr is a set of attributes for getattr. 792 type Attr struct { 793 Mode FileMode 794 UID UID 795 GID GID 796 NLink uint64 797 RDev uint64 798 Size uint64 799 BlockSize uint64 800 Blocks uint64 801 ATimeSeconds uint64 802 ATimeNanoSeconds uint64 803 MTimeSeconds uint64 804 MTimeNanoSeconds uint64 805 CTimeSeconds uint64 806 CTimeNanoSeconds uint64 807 BTimeSeconds uint64 808 BTimeNanoSeconds uint64 809 Gen uint64 810 DataVersion uint64 811 } 812 813 // String implements fmt.Stringer. 814 func (a Attr) String() string { 815 return fmt.Sprintf("Attr{Mode: 0o%o, UID: %d, GID: %d, NLink: %d, RDev: %d, Size: %d, BlockSize: %d, Blocks: %d, ATime: {Sec: %d, NanoSec: %d}, MTime: {Sec: %d, NanoSec: %d}, CTime: {Sec: %d, NanoSec: %d}, BTime: {Sec: %d, NanoSec: %d}, Gen: %d, DataVersion: %d}", 816 a.Mode, a.UID, a.GID, a.NLink, a.RDev, a.Size, a.BlockSize, a.Blocks, a.ATimeSeconds, a.ATimeNanoSeconds, a.MTimeSeconds, a.MTimeNanoSeconds, a.CTimeSeconds, a.CTimeNanoSeconds, a.BTimeSeconds, a.BTimeNanoSeconds, a.Gen, a.DataVersion) 817 } 818 819 // encode implements encoder.encode. 820 func (a *Attr) encode(b *buffer) { 821 b.WriteFileMode(a.Mode) 822 b.WriteUID(a.UID) 823 b.WriteGID(a.GID) 824 b.Write64(a.NLink) 825 b.Write64(a.RDev) 826 b.Write64(a.Size) 827 b.Write64(a.BlockSize) 828 b.Write64(a.Blocks) 829 b.Write64(a.ATimeSeconds) 830 b.Write64(a.ATimeNanoSeconds) 831 b.Write64(a.MTimeSeconds) 832 b.Write64(a.MTimeNanoSeconds) 833 b.Write64(a.CTimeSeconds) 834 b.Write64(a.CTimeNanoSeconds) 835 b.Write64(a.BTimeSeconds) 836 b.Write64(a.BTimeNanoSeconds) 837 b.Write64(a.Gen) 838 b.Write64(a.DataVersion) 839 } 840 841 // decode implements encoder.decode. 842 func (a *Attr) decode(b *buffer) { 843 a.Mode = b.ReadFileMode() 844 a.UID = b.ReadUID() 845 a.GID = b.ReadGID() 846 a.NLink = b.Read64() 847 a.RDev = b.Read64() 848 a.Size = b.Read64() 849 a.BlockSize = b.Read64() 850 a.Blocks = b.Read64() 851 a.ATimeSeconds = b.Read64() 852 a.ATimeNanoSeconds = b.Read64() 853 a.MTimeSeconds = b.Read64() 854 a.MTimeNanoSeconds = b.Read64() 855 a.CTimeSeconds = b.Read64() 856 a.CTimeNanoSeconds = b.Read64() 857 a.BTimeSeconds = b.Read64() 858 a.BTimeNanoSeconds = b.Read64() 859 a.Gen = b.Read64() 860 a.DataVersion = b.Read64() 861 } 862 863 // StatToAttr converts a Linux syscall stat structure to an Attr. 864 func StatToAttr(s *syscall.Stat_t, req AttrMask) (Attr, AttrMask) { 865 attr := Attr{ 866 UID: NoUID, 867 GID: NoGID, 868 } 869 if req.Mode { 870 // p9.FileMode corresponds to Linux mode_t. 871 attr.Mode = FileMode(s.Mode) 872 } 873 if req.NLink { 874 attr.NLink = uint64(s.Nlink) 875 } 876 if req.UID { 877 attr.UID = UID(s.Uid) 878 } 879 if req.GID { 880 attr.GID = GID(s.Gid) 881 } 882 if req.RDev { 883 attr.RDev = s.Dev 884 } 885 if req.ATime { 886 attr.ATimeSeconds = uint64(s.Atim.Sec) 887 attr.ATimeNanoSeconds = uint64(s.Atim.Nsec) 888 } 889 if req.MTime { 890 attr.MTimeSeconds = uint64(s.Mtim.Sec) 891 attr.MTimeNanoSeconds = uint64(s.Mtim.Nsec) 892 } 893 if req.CTime { 894 attr.CTimeSeconds = uint64(s.Ctim.Sec) 895 attr.CTimeNanoSeconds = uint64(s.Ctim.Nsec) 896 } 897 if req.Size { 898 attr.Size = uint64(s.Size) 899 } 900 if req.Blocks { 901 attr.BlockSize = uint64(s.Blksize) 902 attr.Blocks = uint64(s.Blocks) 903 } 904 905 // Use the req field because we already have it. 906 req.BTime = false 907 req.Gen = false 908 req.DataVersion = false 909 910 return attr, req 911 } 912 913 // SetAttrMask specifies a valid mask for setattr. 914 type SetAttrMask struct { 915 Permissions bool 916 UID bool 917 GID bool 918 Size bool 919 ATime bool 920 MTime bool 921 CTime bool 922 ATimeNotSystemTime bool 923 MTimeNotSystemTime bool 924 } 925 926 // IsSubsetOf returns whether s is a subset of m. 927 func (s SetAttrMask) IsSubsetOf(m SetAttrMask) bool { 928 sb := s.bitmask() 929 sm := m.bitmask() 930 return sm|sb == sm 931 } 932 933 // String implements fmt.Stringer. 934 func (s SetAttrMask) String() string { 935 var masks []string 936 if s.Permissions { 937 masks = append(masks, "Permissions") 938 } 939 if s.UID { 940 masks = append(masks, "UID") 941 } 942 if s.GID { 943 masks = append(masks, "GID") 944 } 945 if s.Size { 946 masks = append(masks, "Size") 947 } 948 if s.ATime { 949 masks = append(masks, "ATime") 950 } 951 if s.MTime { 952 masks = append(masks, "MTime") 953 } 954 if s.CTime { 955 masks = append(masks, "CTime") 956 } 957 if s.ATimeNotSystemTime { 958 masks = append(masks, "ATimeNotSystemTime") 959 } 960 if s.MTimeNotSystemTime { 961 masks = append(masks, "MTimeNotSystemTime") 962 } 963 return fmt.Sprintf("SetAttrMask{with: %s}", strings.Join(masks, " ")) 964 } 965 966 // Empty returns true if no fields are masked. 967 func (s SetAttrMask) Empty() bool { 968 return !s.Permissions && !s.UID && !s.GID && !s.Size && !s.ATime && !s.MTime && !s.CTime && !s.ATimeNotSystemTime && !s.MTimeNotSystemTime 969 } 970 971 // decode implements encoder.decode. 972 func (s *SetAttrMask) decode(b *buffer) { 973 mask := b.Read32() 974 s.Permissions = mask&0x00000001 != 0 975 s.UID = mask&0x00000002 != 0 976 s.GID = mask&0x00000004 != 0 977 s.Size = mask&0x00000008 != 0 978 s.ATime = mask&0x00000010 != 0 979 s.MTime = mask&0x00000020 != 0 980 s.CTime = mask&0x00000040 != 0 981 s.ATimeNotSystemTime = mask&0x00000080 != 0 982 s.MTimeNotSystemTime = mask&0x00000100 != 0 983 } 984 985 func (s SetAttrMask) bitmask() uint32 { 986 var mask uint32 987 if s.Permissions { 988 mask |= 0x00000001 989 } 990 if s.UID { 991 mask |= 0x00000002 992 } 993 if s.GID { 994 mask |= 0x00000004 995 } 996 if s.Size { 997 mask |= 0x00000008 998 } 999 if s.ATime { 1000 mask |= 0x00000010 1001 } 1002 if s.MTime { 1003 mask |= 0x00000020 1004 } 1005 if s.CTime { 1006 mask |= 0x00000040 1007 } 1008 if s.ATimeNotSystemTime { 1009 mask |= 0x00000080 1010 } 1011 if s.MTimeNotSystemTime { 1012 mask |= 0x00000100 1013 } 1014 return mask 1015 } 1016 1017 // encode implements encoder.encode. 1018 func (s *SetAttrMask) encode(b *buffer) { 1019 b.Write32(s.bitmask()) 1020 } 1021 1022 // SetAttr specifies a set of attributes for a setattr. 1023 type SetAttr struct { 1024 Permissions FileMode 1025 UID UID 1026 GID GID 1027 Size uint64 1028 ATimeSeconds uint64 1029 ATimeNanoSeconds uint64 1030 MTimeSeconds uint64 1031 MTimeNanoSeconds uint64 1032 } 1033 1034 // String implements fmt.Stringer. 1035 func (s SetAttr) String() string { 1036 return fmt.Sprintf("SetAttr{Permissions: 0o%o, UID: %d, GID: %d, Size: %d, ATime: {Sec: %d, NanoSec: %d}, MTime: {Sec: %d, NanoSec: %d}}", s.Permissions, s.UID, s.GID, s.Size, s.ATimeSeconds, s.ATimeNanoSeconds, s.MTimeSeconds, s.MTimeNanoSeconds) 1037 } 1038 1039 // decode implements encoder.decode. 1040 func (s *SetAttr) decode(b *buffer) { 1041 s.Permissions = b.ReadPermissions() 1042 s.UID = b.ReadUID() 1043 s.GID = b.ReadGID() 1044 s.Size = b.Read64() 1045 s.ATimeSeconds = b.Read64() 1046 s.ATimeNanoSeconds = b.Read64() 1047 s.MTimeSeconds = b.Read64() 1048 s.MTimeNanoSeconds = b.Read64() 1049 } 1050 1051 // encode implements encoder.encode. 1052 func (s *SetAttr) encode(b *buffer) { 1053 b.WritePermissions(s.Permissions) 1054 b.WriteUID(s.UID) 1055 b.WriteGID(s.GID) 1056 b.Write64(s.Size) 1057 b.Write64(s.ATimeSeconds) 1058 b.Write64(s.ATimeNanoSeconds) 1059 b.Write64(s.MTimeSeconds) 1060 b.Write64(s.MTimeNanoSeconds) 1061 } 1062 1063 // Apply applies this to the given Attr. 1064 func (a *Attr) Apply(mask SetAttrMask, attr SetAttr) { 1065 if mask.Permissions { 1066 a.Mode = a.Mode&^permissionsMask | (attr.Permissions & permissionsMask) 1067 } 1068 if mask.UID { 1069 a.UID = attr.UID 1070 } 1071 if mask.GID { 1072 a.GID = attr.GID 1073 } 1074 if mask.Size { 1075 a.Size = attr.Size 1076 } 1077 if mask.ATime { 1078 a.ATimeSeconds = attr.ATimeSeconds 1079 a.ATimeNanoSeconds = attr.ATimeNanoSeconds 1080 } 1081 if mask.MTime { 1082 a.MTimeSeconds = attr.MTimeSeconds 1083 a.MTimeNanoSeconds = attr.MTimeNanoSeconds 1084 } 1085 } 1086 1087 // DirentSizeStatic is the number of bytes required to encode a p9.Dirent 1088 // with an empty name. In other words, it is the static part of its size. 1089 const DirentSizeStatic = 24 1090 1091 // Dirent is used for readdir. 1092 type Dirent struct { 1093 // QID is the entry QID. 1094 QID QID 1095 1096 // Offset is the offset in the directory. 1097 // 1098 // This will be communicated back the original caller. 1099 Offset uint64 1100 1101 // Type is the 9P type. 1102 Type QIDType 1103 1104 // Name is the name of the entry (i.e. basename). 1105 Name string 1106 } 1107 1108 // String implements fmt.Stringer. 1109 func (d Dirent) String() string { 1110 return fmt.Sprintf("Dirent{QID: %d, Offset: %d, Type: 0x%X, Name: %s}", d.QID, d.Offset, d.Type, d.Name) 1111 } 1112 1113 // decode implements encoder.decode. 1114 func (d *Dirent) decode(b *buffer) { 1115 d.QID.decode(b) 1116 d.Offset = b.Read64() 1117 d.Type = b.ReadQIDType() 1118 d.Name = b.ReadString() 1119 } 1120 1121 // encode implements encoder.encode. 1122 func (d *Dirent) encode(b *buffer) { 1123 d.QID.encode(b) 1124 b.Write64(d.Offset) 1125 b.WriteQIDType(d.Type) 1126 b.WriteString(d.Name) 1127 } 1128 1129 // AllocateMode are possible modes to p9.File.Allocate(). 1130 type AllocateMode struct { 1131 KeepSize bool 1132 PunchHole bool 1133 NoHideStale bool 1134 CollapseRange bool 1135 ZeroRange bool 1136 InsertRange bool 1137 Unshare bool 1138 } 1139 1140 // ToAllocateMode returns an AllocateMode from a fallocate(2) mode. 1141 func ToAllocateMode(mode uint64) AllocateMode { 1142 return AllocateMode{ 1143 KeepSize: mode&unix.FALLOC_FL_KEEP_SIZE != 0, 1144 PunchHole: mode&unix.FALLOC_FL_PUNCH_HOLE != 0, 1145 NoHideStale: mode&unix.FALLOC_FL_NO_HIDE_STALE != 0, 1146 CollapseRange: mode&unix.FALLOC_FL_COLLAPSE_RANGE != 0, 1147 ZeroRange: mode&unix.FALLOC_FL_ZERO_RANGE != 0, 1148 InsertRange: mode&unix.FALLOC_FL_INSERT_RANGE != 0, 1149 Unshare: mode&unix.FALLOC_FL_UNSHARE_RANGE != 0, 1150 } 1151 } 1152 1153 // ToLinux converts to a value compatible with fallocate(2)'s mode. 1154 func (a *AllocateMode) ToLinux() uint32 { 1155 rv := uint32(0) 1156 if a.KeepSize { 1157 rv |= unix.FALLOC_FL_KEEP_SIZE 1158 } 1159 if a.PunchHole { 1160 rv |= unix.FALLOC_FL_PUNCH_HOLE 1161 } 1162 if a.NoHideStale { 1163 rv |= unix.FALLOC_FL_NO_HIDE_STALE 1164 } 1165 if a.CollapseRange { 1166 rv |= unix.FALLOC_FL_COLLAPSE_RANGE 1167 } 1168 if a.ZeroRange { 1169 rv |= unix.FALLOC_FL_ZERO_RANGE 1170 } 1171 if a.InsertRange { 1172 rv |= unix.FALLOC_FL_INSERT_RANGE 1173 } 1174 if a.Unshare { 1175 rv |= unix.FALLOC_FL_UNSHARE_RANGE 1176 } 1177 return rv 1178 } 1179 1180 // decode implements encoder.decode. 1181 func (a *AllocateMode) decode(b *buffer) { 1182 mask := b.Read32() 1183 a.KeepSize = mask&0x01 != 0 1184 a.PunchHole = mask&0x02 != 0 1185 a.NoHideStale = mask&0x04 != 0 1186 a.CollapseRange = mask&0x08 != 0 1187 a.ZeroRange = mask&0x10 != 0 1188 a.InsertRange = mask&0x20 != 0 1189 a.Unshare = mask&0x40 != 0 1190 } 1191 1192 // encode implements encoder.encode. 1193 func (a *AllocateMode) encode(b *buffer) { 1194 mask := uint32(0) 1195 if a.KeepSize { 1196 mask |= 0x01 1197 } 1198 if a.PunchHole { 1199 mask |= 0x02 1200 } 1201 if a.NoHideStale { 1202 mask |= 0x04 1203 } 1204 if a.CollapseRange { 1205 mask |= 0x08 1206 } 1207 if a.ZeroRange { 1208 mask |= 0x10 1209 } 1210 if a.InsertRange { 1211 mask |= 0x20 1212 } 1213 if a.Unshare { 1214 mask |= 0x40 1215 } 1216 b.Write32(mask) 1217 } 1218 1219 // FullStat is used in the result of a MultiGetAttr call. 1220 type FullStat struct { 1221 QID QID 1222 Valid AttrMask 1223 Attr Attr 1224 } 1225 1226 // String implements fmt.Stringer. 1227 func (f *FullStat) String() string { 1228 return fmt.Sprintf("FullStat{QID: %v, Valid: %v, Attr: %v}", f.QID, f.Valid, f.Attr) 1229 } 1230 1231 // decode implements encoder.decode. 1232 func (f *FullStat) decode(b *buffer) { 1233 f.QID.decode(b) 1234 f.Valid.decode(b) 1235 f.Attr.decode(b) 1236 } 1237 1238 // encode implements encoder.encode. 1239 func (f *FullStat) encode(b *buffer) { 1240 f.QID.encode(b) 1241 f.Valid.encode(b) 1242 f.Attr.encode(b) 1243 }