1// See the file LICENSE for copyright and licensing information. 2 3// Derived from FUSE's fuse_kernel.h, which carries this notice: 4/* 5 This file defines the kernel interface of FUSE 6 Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu> 7 8 9 This -- and only this -- header file may also be distributed under 10 the terms of the BSD Licence as follows: 11 12 Copyright (C) 2001-2007 Miklos Szeredi. All rights reserved. 13 14 Redistribution and use in source and binary forms, with or without 15 modification, are permitted provided that the following conditions 16 are met: 17 1. Redistributions of source code must retain the above copyright 18 notice, this list of conditions and the following disclaimer. 19 2. Redistributions in binary form must reproduce the above copyright 20 notice, this list of conditions and the following disclaimer in the 21 documentation and/or other materials provided with the distribution. 22 23 THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND 24 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE 27 FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 SUCH DAMAGE. 34*/ 35 36package fuse 37 38import ( 39 "fmt" 40 "syscall" 41 "unsafe" 42) 43 44// The FUSE version implemented by the package. 45const ( 46 protoVersionMinMajor = 7 47 protoVersionMinMinor = 8 48 protoVersionMaxMajor = 7 49 protoVersionMaxMinor = 12 50) 51 52const ( 53 rootID = 1 54) 55 56type kstatfs struct { 57 Blocks uint64 58 Bfree uint64 59 Bavail uint64 60 Files uint64 61 Ffree uint64 62 Bsize uint32 63 Namelen uint32 64 Frsize uint32 65 _ uint32 66 Spare [6]uint32 67} 68 69type fileLock struct { 70 Start uint64 71 End uint64 72 Type uint32 73 Pid uint32 74} 75 76// GetattrFlags are bit flags that can be seen in GetattrRequest. 77type GetattrFlags uint32 78 79const ( 80 // Indicates the handle is valid. 81 GetattrFh GetattrFlags = 1 << 0 82) 83 84var getattrFlagsNames = []flagName{ 85 {uint32(GetattrFh), "GetattrFh"}, 86} 87 88func (fl GetattrFlags) String() string { 89 return flagString(uint32(fl), getattrFlagsNames) 90} 91 92// The SetattrValid are bit flags describing which fields in the SetattrRequest 93// are included in the change. 94type SetattrValid uint32 95 96const ( 97 SetattrMode SetattrValid = 1 << 0 98 SetattrUid SetattrValid = 1 << 1 99 SetattrGid SetattrValid = 1 << 2 100 SetattrSize SetattrValid = 1 << 3 101 SetattrAtime SetattrValid = 1 << 4 102 SetattrMtime SetattrValid = 1 << 5 103 SetattrHandle SetattrValid = 1 << 6 104 105 // Linux only(?) 106 SetattrAtimeNow SetattrValid = 1 << 7 107 SetattrMtimeNow SetattrValid = 1 << 8 108 SetattrLockOwner SetattrValid = 1 << 9 // http://www.mail-archive.com/git-commits-head@vger.kernel.org/msg27852.html 109 110 // OS X only 111 SetattrCrtime SetattrValid = 1 << 28 112 SetattrChgtime SetattrValid = 1 << 29 113 SetattrBkuptime SetattrValid = 1 << 30 114 SetattrFlags SetattrValid = 1 << 31 115) 116 117func (fl SetattrValid) Mode() bool { return fl&SetattrMode != 0 } 118func (fl SetattrValid) Uid() bool { return fl&SetattrUid != 0 } 119func (fl SetattrValid) Gid() bool { return fl&SetattrGid != 0 } 120func (fl SetattrValid) Size() bool { return fl&SetattrSize != 0 } 121func (fl SetattrValid) Atime() bool { return fl&SetattrAtime != 0 } 122func (fl SetattrValid) Mtime() bool { return fl&SetattrMtime != 0 } 123func (fl SetattrValid) Handle() bool { return fl&SetattrHandle != 0 } 124func (fl SetattrValid) AtimeNow() bool { return fl&SetattrAtimeNow != 0 } 125func (fl SetattrValid) MtimeNow() bool { return fl&SetattrMtimeNow != 0 } 126func (fl SetattrValid) LockOwner() bool { return fl&SetattrLockOwner != 0 } 127func (fl SetattrValid) Crtime() bool { return fl&SetattrCrtime != 0 } 128func (fl SetattrValid) Chgtime() bool { return fl&SetattrChgtime != 0 } 129func (fl SetattrValid) Bkuptime() bool { return fl&SetattrBkuptime != 0 } 130func (fl SetattrValid) Flags() bool { return fl&SetattrFlags != 0 } 131 132func (fl SetattrValid) String() string { 133 return flagString(uint32(fl), setattrValidNames) 134} 135 136var setattrValidNames = []flagName{ 137 {uint32(SetattrMode), "SetattrMode"}, 138 {uint32(SetattrUid), "SetattrUid"}, 139 {uint32(SetattrGid), "SetattrGid"}, 140 {uint32(SetattrSize), "SetattrSize"}, 141 {uint32(SetattrAtime), "SetattrAtime"}, 142 {uint32(SetattrMtime), "SetattrMtime"}, 143 {uint32(SetattrHandle), "SetattrHandle"}, 144 {uint32(SetattrAtimeNow), "SetattrAtimeNow"}, 145 {uint32(SetattrMtimeNow), "SetattrMtimeNow"}, 146 {uint32(SetattrLockOwner), "SetattrLockOwner"}, 147 {uint32(SetattrCrtime), "SetattrCrtime"}, 148 {uint32(SetattrChgtime), "SetattrChgtime"}, 149 {uint32(SetattrBkuptime), "SetattrBkuptime"}, 150 {uint32(SetattrFlags), "SetattrFlags"}, 151} 152 153// Flags that can be seen in OpenRequest.Flags. 154const ( 155 // Access modes. These are not 1-bit flags, but alternatives where 156 // only one can be chosen. See the IsReadOnly etc convenience 157 // methods. 158 OpenReadOnly OpenFlags = syscall.O_RDONLY 159 OpenWriteOnly OpenFlags = syscall.O_WRONLY 160 OpenReadWrite OpenFlags = syscall.O_RDWR 161 162 // File was opened in append-only mode, all writes will go to end 163 // of file. OS X does not provide this information. 164 OpenAppend OpenFlags = syscall.O_APPEND 165 OpenCreate OpenFlags = syscall.O_CREAT 166 OpenDirectory OpenFlags = syscall.O_DIRECTORY 167 OpenExclusive OpenFlags = syscall.O_EXCL 168 OpenNonblock OpenFlags = syscall.O_NONBLOCK 169 OpenSync OpenFlags = syscall.O_SYNC 170 OpenTruncate OpenFlags = syscall.O_TRUNC 171) 172 173// OpenAccessModeMask is a bitmask that separates the access mode 174// from the other flags in OpenFlags. 175const OpenAccessModeMask OpenFlags = syscall.O_ACCMODE 176 177// OpenFlags are the O_FOO flags passed to open/create/etc calls. For 178// example, os.O_WRONLY | os.O_APPEND. 179type OpenFlags uint32 180 181func (fl OpenFlags) String() string { 182 // O_RDONLY, O_RWONLY, O_RDWR are not flags 183 s := accModeName(fl & OpenAccessModeMask) 184 flags := uint32(fl &^ OpenAccessModeMask) 185 if flags != 0 { 186 s = s + "+" + flagString(flags, openFlagNames) 187 } 188 return s 189} 190 191// Return true if OpenReadOnly is set. 192func (fl OpenFlags) IsReadOnly() bool { 193 return fl&OpenAccessModeMask == OpenReadOnly 194} 195 196// Return true if OpenWriteOnly is set. 197func (fl OpenFlags) IsWriteOnly() bool { 198 return fl&OpenAccessModeMask == OpenWriteOnly 199} 200 201// Return true if OpenReadWrite is set. 202func (fl OpenFlags) IsReadWrite() bool { 203 return fl&OpenAccessModeMask == OpenReadWrite 204} 205 206func accModeName(flags OpenFlags) string { 207 switch flags { 208 case OpenReadOnly: 209 return "OpenReadOnly" 210 case OpenWriteOnly: 211 return "OpenWriteOnly" 212 case OpenReadWrite: 213 return "OpenReadWrite" 214 default: 215 return "" 216 } 217} 218 219var openFlagNames = []flagName{ 220 {uint32(OpenAppend), "OpenAppend"}, 221 {uint32(OpenCreate), "OpenCreate"}, 222 {uint32(OpenDirectory), "OpenDirectory"}, 223 {uint32(OpenExclusive), "OpenExclusive"}, 224 {uint32(OpenNonblock), "OpenNonblock"}, 225 {uint32(OpenSync), "OpenSync"}, 226 {uint32(OpenTruncate), "OpenTruncate"}, 227} 228 229// The OpenResponseFlags are returned in the OpenResponse. 230type OpenResponseFlags uint32 231 232const ( 233 OpenDirectIO OpenResponseFlags = 1 << 0 // bypass page cache for this open file 234 OpenKeepCache OpenResponseFlags = 1 << 1 // don't invalidate the data cache on open 235 OpenNonSeekable OpenResponseFlags = 1 << 2 // mark the file as non-seekable (not supported on OS X or FreeBSD) 236 237 OpenPurgeAttr OpenResponseFlags = 1 << 30 // OS X 238 OpenPurgeUBC OpenResponseFlags = 1 << 31 // OS X 239) 240 241func (fl OpenResponseFlags) String() string { 242 return flagString(uint32(fl), openResponseFlagNames) 243} 244 245var openResponseFlagNames = []flagName{ 246 {uint32(OpenDirectIO), "OpenDirectIO"}, 247 {uint32(OpenKeepCache), "OpenKeepCache"}, 248 {uint32(OpenNonSeekable), "OpenNonSeekable"}, 249 {uint32(OpenPurgeAttr), "OpenPurgeAttr"}, 250 {uint32(OpenPurgeUBC), "OpenPurgeUBC"}, 251} 252 253// The InitFlags are used in the Init exchange. 254type InitFlags uint32 255 256const ( 257 InitAsyncRead InitFlags = 1 << 0 258 InitPosixLocks InitFlags = 1 << 1 259 InitFileOps InitFlags = 1 << 2 260 InitAtomicTrunc InitFlags = 1 << 3 261 InitExportSupport InitFlags = 1 << 4 262 InitBigWrites InitFlags = 1 << 5 263 // Do not mask file access modes with umask. Not supported on OS X. 264 InitDontMask InitFlags = 1 << 6 265 InitSpliceWrite InitFlags = 1 << 7 266 InitSpliceMove InitFlags = 1 << 8 267 InitSpliceRead InitFlags = 1 << 9 268 InitFlockLocks InitFlags = 1 << 10 269 InitHasIoctlDir InitFlags = 1 << 11 270 InitAutoInvalData InitFlags = 1 << 12 271 InitDoReaddirplus InitFlags = 1 << 13 272 InitReaddirplusAuto InitFlags = 1 << 14 273 InitAsyncDIO InitFlags = 1 << 15 274 InitWritebackCache InitFlags = 1 << 16 275 InitNoOpenSupport InitFlags = 1 << 17 276 277 InitCaseSensitive InitFlags = 1 << 29 // OS X only 278 InitVolRename InitFlags = 1 << 30 // OS X only 279 InitXtimes InitFlags = 1 << 31 // OS X only 280) 281 282type flagName struct { 283 bit uint32 284 name string 285} 286 287var initFlagNames = []flagName{ 288 {uint32(InitAsyncRead), "InitAsyncRead"}, 289 {uint32(InitPosixLocks), "InitPosixLocks"}, 290 {uint32(InitFileOps), "InitFileOps"}, 291 {uint32(InitAtomicTrunc), "InitAtomicTrunc"}, 292 {uint32(InitExportSupport), "InitExportSupport"}, 293 {uint32(InitBigWrites), "InitBigWrites"}, 294 {uint32(InitDontMask), "InitDontMask"}, 295 {uint32(InitSpliceWrite), "InitSpliceWrite"}, 296 {uint32(InitSpliceMove), "InitSpliceMove"}, 297 {uint32(InitSpliceRead), "InitSpliceRead"}, 298 {uint32(InitFlockLocks), "InitFlockLocks"}, 299 {uint32(InitHasIoctlDir), "InitHasIoctlDir"}, 300 {uint32(InitAutoInvalData), "InitAutoInvalData"}, 301 {uint32(InitDoReaddirplus), "InitDoReaddirplus"}, 302 {uint32(InitReaddirplusAuto), "InitReaddirplusAuto"}, 303 {uint32(InitAsyncDIO), "InitAsyncDIO"}, 304 {uint32(InitWritebackCache), "InitWritebackCache"}, 305 {uint32(InitNoOpenSupport), "InitNoOpenSupport"}, 306 307 {uint32(InitCaseSensitive), "InitCaseSensitive"}, 308 {uint32(InitVolRename), "InitVolRename"}, 309 {uint32(InitXtimes), "InitXtimes"}, 310} 311 312func (fl InitFlags) String() string { 313 return flagString(uint32(fl), initFlagNames) 314} 315 316func flagString(f uint32, names []flagName) string { 317 var s string 318 319 if f == 0 { 320 return "0" 321 } 322 323 for _, n := range names { 324 if f&n.bit != 0 { 325 s += "+" + n.name 326 f &^= n.bit 327 } 328 } 329 if f != 0 { 330 s += fmt.Sprintf("%+#x", f) 331 } 332 return s[1:] 333} 334 335// The ReleaseFlags are used in the Release exchange. 336type ReleaseFlags uint32 337 338const ( 339 ReleaseFlush ReleaseFlags = 1 << 0 340) 341 342func (fl ReleaseFlags) String() string { 343 return flagString(uint32(fl), releaseFlagNames) 344} 345 346var releaseFlagNames = []flagName{ 347 {uint32(ReleaseFlush), "ReleaseFlush"}, 348} 349 350// Opcodes 351const ( 352 opLookup = 1 353 opForget = 2 // no reply 354 opGetattr = 3 355 opSetattr = 4 356 opReadlink = 5 357 opSymlink = 6 358 opMknod = 8 359 opMkdir = 9 360 opUnlink = 10 361 opRmdir = 11 362 opRename = 12 363 opLink = 13 364 opOpen = 14 365 opRead = 15 366 opWrite = 16 367 opStatfs = 17 368 opRelease = 18 369 opFsync = 20 370 opSetxattr = 21 371 opGetxattr = 22 372 opListxattr = 23 373 opRemovexattr = 24 374 opFlush = 25 375 opInit = 26 376 opOpendir = 27 377 opReaddir = 28 378 opReleasedir = 29 379 opFsyncdir = 30 380 opGetlk = 31 381 opSetlk = 32 382 opSetlkw = 33 383 opAccess = 34 384 opCreate = 35 385 opInterrupt = 36 386 opBmap = 37 387 opDestroy = 38 388 opIoctl = 39 // Linux? 389 opPoll = 40 // Linux? 390 391 // OS X 392 opSetvolname = 61 393 opGetxtimes = 62 394 opExchange = 63 395) 396 397type entryOut struct { 398 Nodeid uint64 // Inode ID 399 Generation uint64 // Inode generation 400 EntryValid uint64 // Cache timeout for the name 401 AttrValid uint64 // Cache timeout for the attributes 402 EntryValidNsec uint32 403 AttrValidNsec uint32 404 Attr attr 405} 406 407func entryOutSize(p Protocol) uintptr { 408 switch { 409 case p.LT(Protocol{7, 9}): 410 return unsafe.Offsetof(entryOut{}.Attr) + unsafe.Offsetof(entryOut{}.Attr.Blksize) 411 default: 412 return unsafe.Sizeof(entryOut{}) 413 } 414} 415 416type forgetIn struct { 417 Nlookup uint64 418} 419 420type getattrIn struct { 421 GetattrFlags uint32 422 _ uint32 423 Fh uint64 424} 425 426type attrOut struct { 427 AttrValid uint64 // Cache timeout for the attributes 428 AttrValidNsec uint32 429 _ uint32 430 Attr attr 431} 432 433func attrOutSize(p Protocol) uintptr { 434 switch { 435 case p.LT(Protocol{7, 9}): 436 return unsafe.Offsetof(attrOut{}.Attr) + unsafe.Offsetof(attrOut{}.Attr.Blksize) 437 default: 438 return unsafe.Sizeof(attrOut{}) 439 } 440} 441 442// OS X 443type getxtimesOut struct { 444 Bkuptime uint64 445 Crtime uint64 446 BkuptimeNsec uint32 447 CrtimeNsec uint32 448} 449 450type mknodIn struct { 451 Mode uint32 452 Rdev uint32 453 Umask uint32 454 _ uint32 455 // "filename\x00" follows. 456} 457 458func mknodInSize(p Protocol) uintptr { 459 switch { 460 case p.LT(Protocol{7, 12}): 461 return unsafe.Offsetof(mknodIn{}.Umask) 462 default: 463 return unsafe.Sizeof(mknodIn{}) 464 } 465} 466 467type mkdirIn struct { 468 Mode uint32 469 Umask uint32 470 // filename follows 471} 472 473func mkdirInSize(p Protocol) uintptr { 474 switch { 475 case p.LT(Protocol{7, 12}): 476 return unsafe.Offsetof(mkdirIn{}.Umask) + 4 477 default: 478 return unsafe.Sizeof(mkdirIn{}) 479 } 480} 481 482type renameIn struct { 483 Newdir uint64 484 // "oldname\x00newname\x00" follows 485} 486 487// OS X 488type exchangeIn struct { 489 Olddir uint64 490 Newdir uint64 491 Options uint64 492 // "oldname\x00newname\x00" follows 493} 494 495type linkIn struct { 496 Oldnodeid uint64 497} 498 499type setattrInCommon struct { 500 Valid uint32 501 _ uint32 502 Fh uint64 503 Size uint64 504 LockOwner uint64 // unused on OS X? 505 Atime uint64 506 Mtime uint64 507 Unused2 uint64 508 AtimeNsec uint32 509 MtimeNsec uint32 510 Unused3 uint32 511 Mode uint32 512 Unused4 uint32 513 Uid uint32 514 Gid uint32 515 Unused5 uint32 516} 517 518type openIn struct { 519 Flags uint32 520 Unused uint32 521} 522 523type openOut struct { 524 Fh uint64 525 OpenFlags uint32 526 _ uint32 527} 528 529type createIn struct { 530 Flags uint32 531 Mode uint32 532 Umask uint32 533 _ uint32 534} 535 536func createInSize(p Protocol) uintptr { 537 switch { 538 case p.LT(Protocol{7, 12}): 539 return unsafe.Offsetof(createIn{}.Umask) 540 default: 541 return unsafe.Sizeof(createIn{}) 542 } 543} 544 545type releaseIn struct { 546 Fh uint64 547 Flags uint32 548 ReleaseFlags uint32 549 LockOwner uint32 550} 551 552type flushIn struct { 553 Fh uint64 554 FlushFlags uint32 555 _ uint32 556 LockOwner uint64 557} 558 559type readIn struct { 560 Fh uint64 561 Offset uint64 562 Size uint32 563 ReadFlags uint32 564 LockOwner uint64 565 Flags uint32 566 _ uint32 567} 568 569func readInSize(p Protocol) uintptr { 570 switch { 571 case p.LT(Protocol{7, 9}): 572 return unsafe.Offsetof(readIn{}.ReadFlags) + 4 573 default: 574 return unsafe.Sizeof(readIn{}) 575 } 576} 577 578// The ReadFlags are passed in ReadRequest. 579type ReadFlags uint32 580 581const ( 582 // LockOwner field is valid. 583 ReadLockOwner ReadFlags = 1 << 1 584) 585 586var readFlagNames = []flagName{ 587 {uint32(ReadLockOwner), "ReadLockOwner"}, 588} 589 590func (fl ReadFlags) String() string { 591 return flagString(uint32(fl), readFlagNames) 592} 593 594type writeIn struct { 595 Fh uint64 596 Offset uint64 597 Size uint32 598 WriteFlags uint32 599 LockOwner uint64 600 Flags uint32 601 _ uint32 602} 603 604func writeInSize(p Protocol) uintptr { 605 switch { 606 case p.LT(Protocol{7, 9}): 607 return unsafe.Offsetof(writeIn{}.LockOwner) 608 default: 609 return unsafe.Sizeof(writeIn{}) 610 } 611} 612 613type writeOut struct { 614 Size uint32 615 _ uint32 616} 617 618// The WriteFlags are passed in WriteRequest. 619type WriteFlags uint32 620 621const ( 622 WriteCache WriteFlags = 1 << 0 623 // LockOwner field is valid. 624 WriteLockOwner WriteFlags = 1 << 1 625) 626 627var writeFlagNames = []flagName{ 628 {uint32(WriteCache), "WriteCache"}, 629 {uint32(WriteLockOwner), "WriteLockOwner"}, 630} 631 632func (fl WriteFlags) String() string { 633 return flagString(uint32(fl), writeFlagNames) 634} 635 636type statfsOut struct { 637 St kstatfs 638} 639 640type fsyncIn struct { 641 Fh uint64 642 FsyncFlags uint32 643 _ uint32 644} 645 646type setxattrInCommon struct { 647 Size uint32 648 Flags uint32 649} 650 651func (setxattrInCommon) position() uint32 { 652 return 0 653} 654 655type getxattrInCommon struct { 656 Size uint32 657 _ uint32 658} 659 660func (getxattrInCommon) position() uint32 { 661 return 0 662} 663 664type getxattrOut struct { 665 Size uint32 666 _ uint32 667} 668 669type lkIn struct { 670 Fh uint64 671 Owner uint64 672 Lk fileLock 673 LkFlags uint32 674 _ uint32 675} 676 677func lkInSize(p Protocol) uintptr { 678 switch { 679 case p.LT(Protocol{7, 9}): 680 return unsafe.Offsetof(lkIn{}.LkFlags) 681 default: 682 return unsafe.Sizeof(lkIn{}) 683 } 684} 685 686type lkOut struct { 687 Lk fileLock 688} 689 690type accessIn struct { 691 Mask uint32 692 _ uint32 693} 694 695type initIn struct { 696 Major uint32 697 Minor uint32 698 MaxReadahead uint32 699 Flags uint32 700} 701 702const initInSize = int(unsafe.Sizeof(initIn{})) 703 704type initOut struct { 705 Major uint32 706 Minor uint32 707 MaxReadahead uint32 708 Flags uint32 709 Unused uint32 710 MaxWrite uint32 711} 712 713type interruptIn struct { 714 Unique uint64 715} 716 717type bmapIn struct { 718 Block uint64 719 BlockSize uint32 720 _ uint32 721} 722 723type bmapOut struct { 724 Block uint64 725} 726 727type inHeader struct { 728 Len uint32 729 Opcode uint32 730 Unique uint64 731 Nodeid uint64 732 Uid uint32 733 Gid uint32 734 Pid uint32 735 _ uint32 736} 737 738const inHeaderSize = int(unsafe.Sizeof(inHeader{})) 739 740type outHeader struct { 741 Len uint32 742 Error int32 743 Unique uint64 744} 745 746type dirent struct { 747 Ino uint64 748 Off uint64 749 Namelen uint32 750 Type uint32 751 Name [0]byte 752} 753 754const direntSize = 8 + 8 + 4 + 4 755 756const ( 757 notifyCodePoll int32 = 1 758 notifyCodeInvalInode int32 = 2 759 notifyCodeInvalEntry int32 = 3 760) 761 762type notifyInvalInodeOut struct { 763 Ino uint64 764 Off int64 765 Len int64 766} 767 768type notifyInvalEntryOut struct { 769 Parent uint64 770 Namelen uint32 771 _ uint32 772} 773