github.com/charlievieth/fastwalk@v1.0.3/internal/dirent/dirent.go (about) 1 //go:build aix || dragonfly || freebsd || (js && wasm) || wasip1 || linux || netbsd || openbsd || solaris 2 3 package dirent 4 5 import ( 6 "os" 7 "runtime" 8 "syscall" 9 "unsafe" 10 ) 11 12 // readInt returns the size-bytes unsigned integer in native byte order at offset off. 13 func readInt(b []byte, off, size uintptr) (u uint64, ok bool) { 14 if len(b) < int(off+size) { 15 return 0, false 16 } 17 if isBigEndian { 18 return readIntBE(b[off:], size), true 19 } 20 return readIntLE(b[off:], size), true 21 } 22 23 func readIntBE(b []byte, size uintptr) uint64 { 24 switch size { 25 case 1: 26 return uint64(b[0]) 27 case 2: 28 _ = b[1] // bounds check hint to compiler; see golang.org/issue/14808 29 return uint64(b[1]) | uint64(b[0])<<8 30 case 4: 31 _ = b[3] // bounds check hint to compiler; see golang.org/issue/14808 32 return uint64(b[3]) | uint64(b[2])<<8 | uint64(b[1])<<16 | uint64(b[0])<<24 33 case 8: 34 _ = b[7] // bounds check hint to compiler; see golang.org/issue/14808 35 return uint64(b[7]) | uint64(b[6])<<8 | uint64(b[5])<<16 | uint64(b[4])<<24 | 36 uint64(b[3])<<32 | uint64(b[2])<<40 | uint64(b[1])<<48 | uint64(b[0])<<56 37 default: 38 panic("syscall: readInt with unsupported size") 39 } 40 } 41 42 func readIntLE(b []byte, size uintptr) uint64 { 43 switch size { 44 case 1: 45 return uint64(b[0]) 46 case 2: 47 _ = b[1] // bounds check hint to compiler; see golang.org/issue/14808 48 return uint64(b[0]) | uint64(b[1])<<8 49 case 4: 50 _ = b[3] // bounds check hint to compiler; see golang.org/issue/14808 51 return uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24 52 case 8: 53 _ = b[7] // bounds check hint to compiler; see golang.org/issue/14808 54 return uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24 | 55 uint64(b[4])<<32 | uint64(b[5])<<40 | uint64(b[6])<<48 | uint64(b[7])<<56 56 default: 57 panic("syscall: readInt with unsupported size") 58 } 59 } 60 61 const InvalidMode = os.FileMode(1<<32 - 1) 62 63 func Parse(buf []byte) (consumed int, name string, typ os.FileMode) { 64 65 reclen, ok := direntReclen(buf) 66 if !ok || reclen > uint64(len(buf)) { 67 // WARN: this is a hard error because we consumed 0 bytes 68 // and not stopping here could lead to an infinite loop. 69 return 0, "", InvalidMode 70 } 71 consumed = int(reclen) 72 rec := buf[:reclen] 73 74 ino, ok := direntIno(rec) 75 if !ok { 76 return consumed, "", InvalidMode 77 } 78 // When building to wasip1, the host runtime might be running on Windows 79 // or might expose a remote file system which does not have the concept 80 // of inodes. Therefore, we cannot make the assumption that it is safe 81 // to skip entries with zero inodes. 82 if ino == 0 && runtime.GOOS != "wasip1" { 83 return consumed, "", InvalidMode 84 } 85 86 typ = direntType(buf) 87 88 const namoff = uint64(unsafe.Offsetof(syscall.Dirent{}.Name)) 89 namlen, ok := direntNamlen(rec) 90 if !ok || namoff+namlen > uint64(len(rec)) { 91 return consumed, "", InvalidMode 92 } 93 namebuf := rec[namoff : namoff+namlen] 94 for i, c := range namebuf { 95 if c == 0 { 96 namebuf = namebuf[:i] 97 break 98 } 99 } 100 // Check for useless names before allocating a string. 101 if string(namebuf) == "." { 102 name = "." 103 } else if string(namebuf) == ".." { 104 name = ".." 105 } else { 106 name = string(namebuf) 107 } 108 return consumed, name, typ 109 }