Пример #1
0
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
}
Пример #2
0
// Return all the entries at the directory dirPath.
func readDir(dirPath string) (entries []string, err error) {
	buf := make([]byte, readDirentBufSize)
	d, err := os.Open(dirPath)
	if err != nil {
		// File is really not found.
		if os.IsNotExist(err) {
			return nil, errFileNotFound
		}

		// File path cannot be verified since one of the parents is a file.
		if strings.Contains(err.Error(), "not a directory") {
			return nil, errFileNotFound
		}
		return nil, err
	}
	defer d.Close()

	fd := int(d.Fd())
	for {
		nbuf, err := syscall.ReadDirent(fd, buf)
		if err != nil {
			return nil, err
		}
		if nbuf <= 0 {
			break
		}
		var tmpEntries []string
		if tmpEntries, err = parseDirents(dirPath, buf[:nbuf]); err != nil {
			return nil, err
		}
		entries = append(entries, tmpEntries...)
	}
	return
}
Пример #3
0
func Readdir(f *os.File, n int) (dirents []*Dirent, err error) {
	d := new(dirInfo)
	d.buf = make([]byte, 4096)

	if n <= 0 {
		n = 100
	}

	fd := int(f.Fd())
	dirents = make([]*Dirent, 0, n) // Empty with room to grow.
	for {
		// Refill the buffer if necessary
		if d.bufp >= d.nbuf {
			d.bufp = 0
			var errno error
			d.nbuf, errno = syscall.ReadDirent(fd, d.buf)
			if errno != nil {
				return dirents, os.NewSyscallError("readdirent", errno)
			}
			if d.nbuf <= 0 {
				break // EOF
			}
		}

		// Drain the buffer
		var nb int
		nb, _, dirents = ParseDirent(d.buf[d.bufp:d.nbuf], -1, dirents)
		d.bufp += nb
	}
	return dirents, nil
}
Пример #4
0
// Read through the directory calling ParseDir() to write to the DirentBuf
// specified by 'db'
// Returns error EOF when the directory has been walked; returns "readdirent"
// error if unable to perform a ReadDirent() syscall
// It's a modified version of (os) readdirnames() in Go's standard library
func ReadDir(fd int, n int64, db *[]syscall.Dirent) error {
	d := new(dirInfo)
	d.buf = make([]byte, 4096)

	size := n
	if size <= 0 {
		size = 100
		n = -1
	}

	for n != 0 {
		// Refill the buffer if necessary
		if d.bufp >= d.nbuf {
			d.bufp = 0
			var errno error
			d.nbuf, errno = general.FixCount(syscall.ReadDirent(fd, d.buf))
			if errno != nil {
				return os.NewSyscallError("readdirent", errno)
			}
			if d.nbuf <= 0 {
				break // EOF
			}
		}

		// Drain the buffer
		var nb, nc int
		nb, nc = ParseDir(d.buf[d.bufp:d.nbuf], n, db)
		d.bufp += nb
		n -= int64(nc)
	}
	if n >= 0 {
		return io.EOF
	}
	return nil
}
Пример #5
0
func ext۰syscall۰ReadDirent(fr *Frame, args []Value) Value {
	// func ReadDirent(fd int, buf []byte) (n int, err error)
	fd := args[0].(int)
	p := args[1].([]Value)
	b := make([]byte, len(p))
	n, err := syscall.ReadDirent(fd, b)
	for i := 0; i < n; i++ {
		p[i] = b[i]
	}
	return tuple{n, wrapError(err)}
}
Пример #6
0
// PathSupportsOverlay checks whether the given path is compatible with OverlayFS.
// This method also calls SupportsOverlay().
//
// It returns an instance of ErrOverlayUnsupported if OverlayFS is not supported
// or any other error if determining overlay support failed.
func PathSupportsOverlay(path string) error {
	if err := SupportsOverlay(); err != nil {
		// don't wrap since SupportsOverlay already returns ErrOverlayUnsupported
		return err
	}

	var data syscall.Statfs_t
	if err := syscall.Statfs(path, &data); err != nil {
		return errwrap.Wrap(fmt.Errorf("cannot statfs %q", path), err)
	}

	switch data.Type {
	case FsMagicAUFS:
		return ErrOverlayUnsupported("unsupported filesystem: aufs")
	case FsMagicZFS:
		return ErrOverlayUnsupported("unsupported filesystem: zfs")
	}

	dir, err := os.OpenFile(path, syscall.O_RDONLY|syscall.O_DIRECTORY, 0755)
	if err != nil {
		return errwrap.Wrap(fmt.Errorf("cannot open %q", dir), err)
	}
	defer dir.Close()

	buf := make([]byte, 4096)
	// ReadDirent forwards to the raw syscall getdents(3),
	// passing the buffer size.
	n, err := syscall.ReadDirent(int(dir.Fd()), buf)
	if err != nil {
		return errwrap.Wrap(fmt.Errorf("cannot read directory %q", dir), err)
	}

	offset := 0
	for offset < n {
		// offset overflow cannot happen, because Reclen
		// is being maintained by getdents(3), considering the buffer size.
		dirent := (*syscall.Dirent)(unsafe.Pointer(&buf[offset]))
		offset += int(dirent.Reclen)

		if dirent.Ino == 0 { // File absent in directory.
			continue
		}

		if dirent.Type == syscall.DT_UNKNOWN {
			return ErrOverlayUnsupported("unsupported filesystem: missing d_type support")
		}
	}

	return nil
}
Пример #7
0
func readDir(dirName string, fn func(dirName, entName string, typ os.FileMode) error) error {
	fd, err := syscall.Open(dirName, 0, 0)
	if err != nil {
		return err
	}
	defer syscall.Close(fd)

	// The buffer must be at least a block long.
	buf := make([]byte, blockSize) // stack-allocated; doesn't escape
	bufp := 0                      // starting read position in buf
	nbuf := 0                      // end valid data in buf
	for {
		if bufp >= nbuf {
			bufp = 0
			nbuf, err = syscall.ReadDirent(fd, buf)
			if err != nil {
				return os.NewSyscallError("readdirent", err)
			}
			if nbuf <= 0 {
				return nil
			}
		}
		consumed, name, typ := parseDirEnt(buf[bufp:nbuf])
		bufp += consumed
		if name == "" || name == "." || name == ".." {
			continue
		}
		// Fallback for filesystems (like old XFS) that don't
		// support Dirent.Type and have DT_UNKNOWN (0) there
		// instead.
		if typ == unknownFileMode {
			fi, err := os.Lstat(dirName + "/" + name)
			if err != nil {
				// It got deleted in the meantime.
				if os.IsNotExist(err) {
					continue
				}
				return err
			}
			typ = fi.Mode() & os.ModeType
		}
		if err := fn(dirName, name, typ); err != nil {
			return err
		}
	}
}
Пример #8
0
func readDir(dir string) []string {
	fd, err := syscall.Open(dir, syscall.O_CLOEXEC, 0644)

	if err != nil {
		return []string{}
	}

	defer syscall.Close(fd)

	var size = 100
	var n = -1

	var nbuf int
	var bufp int

	var buf = make([]byte, 4096)
	var names = make([]string, 0, size)

	for n != 0 {
		if bufp >= nbuf {
			bufp = 0

			var errno error

			nbuf, errno = fixCount(syscall.ReadDirent(fd, buf))

			if errno != nil {
				return names
			}

			if nbuf <= 0 {
				break
			}
		}

		var nb, nc int
		nb, nc, names = syscall.ParseDirent(buf[bufp:nbuf], n, names)
		bufp += nb
		n -= nc
	}

	return names
}
Пример #9
0
// readdirnames is a hacked-apart version of the Go stdlib code, exposing inode
// numbers further up the stack when reading directory contents. Unlike
// os.Readdirnames, which returns a list of filenames, this function returns a
// list of {filename,inode} pairs.
func readdirnames(dirname string) (names []nameIno, err error) {
	var (
		size = 100
		buf  = make([]byte, 4096)
		nbuf int
		bufp int
		nb   int
	)

	f, err := os.Open(dirname)
	if err != nil {
		return nil, err
	}
	defer f.Close()

	names = make([]nameIno, 0, size) // Empty with room to grow.
	for {
		// Refill the buffer if necessary
		if bufp >= nbuf {
			bufp = 0
			nbuf, err = syscall.ReadDirent(int(f.Fd()), buf) // getdents on linux
			if nbuf < 0 {
				nbuf = 0
			}
			if err != nil {
				return nil, os.NewSyscallError("readdirent", err)
			}
			if nbuf <= 0 {
				break // EOF
			}
		}

		// Drain the buffer
		nb, names = parseDirent(buf[bufp:nbuf], names)
		bufp += nb
	}

	sl := nameInoSlice(names)
	sort.Sort(sl)
	return sl, nil
}
Пример #10
0
func (f *File) readdirnames(n int) (names []string, err error) {
	// If this file has no dirinfo, create one.
	if f.dirinfo == nil {
		f.dirinfo = new(dirInfo)
		// The buffer must be at least a block long.
		f.dirinfo.buf = make([]byte, blockSize)
	}
	d := f.dirinfo

	size := n
	if size <= 0 {
		size = 100
		n = -1
	}

	names = make([]string, 0, size) // Empty with room to grow.
	for n != 0 {
		// Refill the buffer if necessary
		if d.bufp >= d.nbuf {
			d.bufp = 0
			var errno error
			d.nbuf, errno = syscall.ReadDirent(f.fd, d.buf)
			if errno != nil {
				return names, NewSyscallError("readdirent", errno)
			}
			if d.nbuf <= 0 {
				break // EOF
			}
		}

		// Drain the buffer
		var nb, nc int
		nb, nc, names = syscall.ParseDirent(d.buf[d.bufp:d.nbuf], n, names)
		d.bufp += nb
		n -= nc
	}
	if n >= 0 && len(names) == 0 {
		return names, io.EOF
	}
	return names, nil
}
Пример #11
0
// IsEmptyDir check if directory empty or not
func IsEmptyDir(path string) bool {
	if path == "" {
		return false
	}

	path = PATH.Clean(path)

	fd, err := syscall.Open(path, syscall.O_RDONLY, 0)

	if err != nil {
		return false
	}

	defer syscall.Close(fd)

	n, err := syscall.ReadDirent(fd, make([]byte, 4096))

	if n == 0x30 || err != nil {
		return true
	}

	return false
}
Пример #12
0
// This test is inspired on xfstest, t_dir_offset2.c
func TestReaddirPlusSeek(t *testing.T) {
	tc := NewTestCase(t)
	defer tc.Cleanup()

	var names []string
	for i := 0; i < 20; i++ {
		names = append(names, fmt.Sprintf("abcd%d", i))
	}

	for _, n := range names {
		if err := os.MkdirAll(filepath.Join(tc.origSubdir, n), 0755); err != nil {
			t.Fatalf("Mkdir failed: %v", err)
		}
	}

	fd, err := syscall.Open(tc.mountSubdir, syscall.O_RDONLY, 0755)
	if err != nil {
		t.Fatalf("Open(%q): %v", tc.mountSubdir, err)
	}
	defer syscall.Close(int(fd))

	// store offsets
	type entryOff struct {
		ino uint64
		off int64
	}
	previous := map[int]entryOff{}
	var bufdata [1024]byte
	for {
		buf := bufdata[:]
		n, err := syscall.ReadDirent(fd, buf)
		if err != nil {
			t.Fatalf("ReadDirent: %v", err)
		}
		if n == 0 {
			break
		}

		buf = buf[:n]
		for _, d := range parseDirents(buf) {
			if d.name == "." || d.name == ".." {
				continue
			}
			i := len(previous)
			previous[i] = entryOff{d.ino, d.off}
		}
	}

	for i := len(previous) - 1; i >= 0; i-- {
		var off int64
		if i > 0 {
			off = previous[i-1].off
		}

		if _, err := syscall.Seek(fd, off, 0); err != nil {
			t.Fatalf("Seek %v", err)
		}

		buf := bufdata[:]
		n, err := syscall.ReadDirent(fd, buf)
		if err != nil {
			t.Fatalf("readdir after seek %d: %v", i, err)
		}
		if n == 0 {
			t.Fatalf("no dirent after seek to %d", i)
		}

		ds := parseDirents(buf[:n])
		if ds[0].ino != previous[i].ino {
			t.Errorf("got ino %d, want %d", ds[0].ino, previous[i].ino)
		}
	}

	// Delete has a forget as side-effect: make sure we get the lookup counts correct.
	for _, n := range names {
		full := filepath.Join(tc.mountSubdir, n)
		if err := syscall.Rmdir(full); err != nil {
			t.Fatalf("Rmdir(%q): %v", n, err)
		}
	}
}
Пример #13
0
func Walk(_path string, _filter Filter, _collector Collector, _errors Errors) {

	var _cursor *cursor
	var _error Error
	var _errno int

	_cursor, _error = open(nil, _path)
	if _error != nil {
		_errors(_error)
	}

	for _cursor != nil {

		if !_cursor.filtered {
			_cursor.recurse, _cursor.collect = _filter(_cursor.entity)
			_cursor.filtered = true
		}

		if _cursor.collect {
			_entity := new(Entity)
			*_entity = *_cursor.entity
			if _entity.Descriptor >= 0 {
				_entity.Descriptor, _errno = syscall.Dup(_entity.Descriptor)
			} else {
				_errno = 0
			}
			if _errno == 0 {
				_collector(_entity)
			} else {
				_errors(newError("dup", _cursor.entity.Path, _cursor.entity.Descriptor, _errno))
			}
			_cursor.collect = false
		}

		if _cursor.recurse && _cursor.entity.IsDirectory() && _cursor.entity.IsOpen() {

			if _cursor.dirent == nil {
				_cursor.dirent = new(dirent)
				_cursor.dirent.nameBuffer = make([]string, 0, _nameBufferSize)
				_cursor.dirent.dataBuffer = make([]byte, _dataBufferSize)
			}

			if _nameBufferLen := len(_cursor.dirent.nameBuffer); _nameBufferLen > 0 {
				_childName := _cursor.dirent.nameBuffer[_nameBufferLen-1]
				_cursor.dirent.nameBuffer[_nameBufferLen-1] = ""
				_cursor.dirent.nameBuffer = _cursor.dirent.nameBuffer[:_nameBufferLen-1]
				var _childCursor, _error = open(_cursor, _childName)
				if _error == nil {
					_cursor = _childCursor
				} else {
					_errors(_error)
				}
				continue
			}

			if !_cursor.dirent.dataEnded && (_cursor.dirent.dataOffset == _cursor.dirent.dataLimit) {
				_cursor.dirent.dataOffset = 0
				_cursor.dirent.dataLimit, _errno = syscall.ReadDirent(_cursor.entity.Descriptor, _cursor.dirent.dataBuffer[:])
				if _errno == 0 {
					if _cursor.dirent.dataLimit == 0 {
						_cursor.dirent.dataEnded = true
					}
				} else {
					_errors(newError("readdirent", _cursor.entity.Path, _cursor.entity.Descriptor, _errno))
					_cursor.dirent.dataLimit = 0
					_cursor.dirent.dataEnded = true
				}
			}

			if !_cursor.dirent.dataEnded {
				_dataParsed, _, _nameBuffer := syscall.ParseDirent(_cursor.dirent.dataBuffer[_cursor.dirent.dataOffset:_cursor.dirent.dataLimit], cap(_cursor.dirent.nameBuffer), _cursor.dirent.nameBuffer)
				if _dataParsed == 0 {
					_errors(newError("parsedirent", _cursor.entity.Path, _cursor.entity.Descriptor, syscall.EINVAL))
					_cursor.dirent.dataLimit = 0
					_cursor.dirent.dataOffset = 0
					_cursor.dirent.dataEnded = true
				} else {
					_cursor.dirent.dataOffset += _dataParsed
					_cursor.dirent.nameBuffer = _nameBuffer
					continue
				}
			}
		}

		if _cursor.entity.IsOpen() {
			_cursor.entity.Close()
		}

		_cursor = _cursor.parent
	}
}