123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687 |
- // +build linux
- package fsutils
- import (
- "fmt"
- "io/ioutil"
- "os"
- "syscall"
- "unsafe"
- )
- func locateDummyIfEmpty(path string) (string, error) {
- children, err := ioutil.ReadDir(path)
- if err != nil {
- return "", err
- }
- if len(children) != 0 {
- return "", nil
- }
- dummyFile, err := ioutil.TempFile(path, "fsutils-dummy")
- if err != nil {
- return "", err
- }
- name := dummyFile.Name()
- err = dummyFile.Close()
- return name, err
- }
- // SupportsDType returns whether the filesystem mounted on path supports d_type
- func SupportsDType(path string) (bool, error) {
- // locate dummy so that we have at least one dirent
- dummy, err := locateDummyIfEmpty(path)
- if err != nil {
- return false, err
- }
- if dummy != "" {
- defer os.Remove(dummy)
- }
- visited := 0
- supportsDType := true
- fn := func(ent *syscall.Dirent) bool {
- visited++
- if ent.Type == syscall.DT_UNKNOWN {
- supportsDType = false
- // stop iteration
- return true
- }
- // continue iteration
- return false
- }
- if err = iterateReadDir(path, fn); err != nil {
- return false, err
- }
- if visited == 0 {
- return false, fmt.Errorf("did not hit any dirent during iteration %s", path)
- }
- return supportsDType, nil
- }
- func iterateReadDir(path string, fn func(*syscall.Dirent) bool) error {
- d, err := os.Open(path)
- if err != nil {
- return err
- }
- defer d.Close()
- fd := int(d.Fd())
- buf := make([]byte, 4096)
- for {
- nbytes, err := syscall.ReadDirent(fd, buf)
- if err != nil {
- return err
- }
- if nbytes == 0 {
- break
- }
- for off := 0; off < nbytes; {
- ent := (*syscall.Dirent)(unsafe.Pointer(&buf[off]))
- if stop := fn(ent); stop {
- return nil
- }
- off += int(ent.Reclen)
- }
- }
- return nil
- }
|