github.com/flavio/docker@v0.1.3-0.20170117145210-f63d1a6eec47/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 err = dummyFile.Close() 27 return name, err 28 } 29 30 // SupportsDType returns whether the filesystem mounted on path supports d_type 31 func SupportsDType(path string) (bool, error) { 32 // locate dummy so that we have at least one dirent 33 dummy, err := locateDummyIfEmpty(path) 34 if err != nil { 35 return false, err 36 } 37 if dummy != "" { 38 defer os.Remove(dummy) 39 } 40 41 visited := 0 42 supportsDType := true 43 fn := func(ent *syscall.Dirent) bool { 44 visited++ 45 if ent.Type == syscall.DT_UNKNOWN { 46 supportsDType = false 47 // stop iteration 48 return true 49 } 50 // continue iteration 51 return false 52 } 53 if err = iterateReadDir(path, fn); err != nil { 54 return false, err 55 } 56 if visited == 0 { 57 return false, fmt.Errorf("did not hit any dirent during iteration %s", path) 58 } 59 return supportsDType, nil 60 } 61 62 func iterateReadDir(path string, fn func(*syscall.Dirent) bool) error { 63 d, err := os.Open(path) 64 if err != nil { 65 return err 66 } 67 defer d.Close() 68 fd := int(d.Fd()) 69 buf := make([]byte, 4096) 70 for { 71 nbytes, err := syscall.ReadDirent(fd, buf) 72 if err != nil { 73 return err 74 } 75 if nbytes == 0 { 76 break 77 } 78 for off := 0; off < nbytes; { 79 ent := (*syscall.Dirent)(unsafe.Pointer(&buf[off])) 80 if stop := fn(ent); stop { 81 return nil 82 } 83 off += int(ent.Reclen) 84 } 85 } 86 return nil 87 }