 320dd70935
			
		
	
	320dd70935
	
	
	
		
			
			No need to have a util package under a package... er, package. We should move most of this functionality to continuity. Signed-off-by: Stephen J Day <stephen.day@docker.com>
		
			
				
	
	
		
			88 lines
		
	
	
		
			1.6 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			88 lines
		
	
	
		
			1.6 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| // +build linux
 | |
| 
 | |
| package fs
 | |
| 
 | |
| 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
 | |
| }
 |