github.com/ph/moby@v1.13.1/pkg/fsutils/fsutils_linux.go (about) 1 // +build linux 2 3 package fsutils 4 5 import ( 6 "fmt" 7 "io/ioutil" 8 "os" 9 "syscall" 10 "unsafe" 11 ) 12 13 func locateDummyIfEmpty(path string) (string, error) { 14 children, err := ioutil.ReadDir(path) 15 if err != nil { 16 return "", err 17 } 18 if len(children) != 0 { 19 return "", nil 20 } 21 dummyFile, err := ioutil.TempFile(path, "fsutils-dummy") 22 if err != nil { 23 return "", err 24 } 25 name := dummyFile.Name() 26 if err = dummyFile.Close(); err != nil { 27 return name, err 28 } 29 return name, nil 30 } 31 32 // SupportsDType returns whether the filesystem mounted on path supports d_type 33 func SupportsDType(path string) (bool, error) { 34 // locate dummy so that we have at least one dirent 35 dummy, err := locateDummyIfEmpty(path) 36 if err != nil { 37 return false, err 38 } 39 if dummy != "" { 40 defer os.Remove(dummy) 41 } 42 43 visited := 0 44 supportsDType := true 45 fn := func(ent *syscall.Dirent) bool { 46 visited++ 47 if ent.Type == syscall.DT_UNKNOWN { 48 supportsDType = false 49 // stop iteration 50 return true 51 } 52 // continue iteration 53 return false 54 } 55 if err = iterateReadDir(path, fn); err != nil { 56 return false, err 57 } 58 if visited == 0 { 59 return false, fmt.Errorf("did not hit any dirent during iteration %s", path) 60 } 61 return supportsDType, nil 62 } 63 64 func iterateReadDir(path string, fn func(*syscall.Dirent) bool) error { 65 d, err := os.Open(path) 66 if err != nil { 67 return err 68 } 69 defer d.Close() 70 fd := int(d.Fd()) 71 buf := make([]byte, 4096) 72 for { 73 nbytes, err := syscall.ReadDirent(fd, buf) 74 if err != nil { 75 return err 76 } 77 if nbytes == 0 { 78 break 79 } 80 for off := 0; off < nbytes; { 81 ent := (*syscall.Dirent)(unsafe.Pointer(&buf[off])) 82 if stop := fn(ent); stop { 83 return nil 84 } 85 off += int(ent.Reclen) 86 } 87 } 88 return nil 89 }