github.com/weaveworks/common@v0.0.0-20230728070032-dd9e68f319d5/fs/readdircount_linux_amd64.go (about) 1 // +build linux,amd64 2 3 package fs 4 5 import ( 6 "fmt" 7 "os" 8 "unsafe" 9 10 "syscall" 11 ) 12 13 func countDirEntries(buf []byte, n int) int { 14 count := 0 15 buf = buf[:n] 16 for len(buf) > 0 { 17 // see man page getdents(2) for struct linux_dirent64 18 reclenOffset := unsafe.Offsetof(syscall.Dirent{}.Reclen) 19 reclen := *(*uint16)(unsafe.Pointer(&buf[reclenOffset])) 20 21 inoOffset := unsafe.Offsetof(syscall.Dirent{}.Ino) 22 ino := *(*uint64)(unsafe.Pointer(&buf[inoOffset])) 23 24 if int(reclen) > len(buf) { 25 return count 26 } 27 buf = buf[reclen:] 28 if ino == 0 { 29 continue 30 } 31 count++ 32 } 33 return count 34 } 35 36 // ReadDirCount is similar to ReadDirNames() and then counting with len() but 37 // it is optimized to avoid parsing the entries 38 func (realFS) ReadDirCount(dir string) (int, error) { 39 buf := make([]byte, 4096) 40 fh, err := os.Open(dir) 41 if err != nil { 42 return 0, err 43 } 44 defer fh.Close() 45 46 openFilesCount := 0 47 for { 48 n, err := syscall.ReadDirent(int(fh.Fd()), buf) 49 if err != nil { 50 return 0, fmt.Errorf("ReadDirent() failed: %v", err) 51 } 52 if n == 0 { 53 break 54 } 55 56 openFilesCount += countDirEntries(buf, n) 57 } 58 59 // "." and ".." don't count as files to be counted 60 nDotFiles := 2 61 return openFilesCount - nDotFiles, err 62 }