Esempio n. 1
0
func (k *LinuxKernel) Getdents(dirfd co.Fd, buf co.Obuf, count uint64) uint64 {
	dirPath, err := posix.PathFromFd(int(dirfd))
	if err != nil {
		return UINT64_MAX // FIXME
	}
	dents, err := ioutil.ReadDir(dirPath)
	if err != nil {
		return UINT64_MAX // FIXME
	}
	// figure out our offset
	// TODO: maybe figure out how a real kernel does this
	in := k.U.StrucAt(buf.Addr)
	var offset, read uint64
	// TODO: DRY? :(
	var ent interface{}
	if k.U.Bits() == 64 {
		ent = &Dirent64{}
	} else {
		ent = &Dirent{}
	}
	for {
		tmp := ent.(*Dirent64)
		if err := in.Unpack(ent); err != nil {
			break
		}
		size, _ := struc.Sizeof(ent)
		if read+uint64(size) > count {
			break
		}
		if tmp.Off > 0 {
			offset = tmp.Off
		}
		if tmp.Len == 0 {
			break
		}
	}
	if offset >= uint64(len(dents)) {
		return 0
	}
	dents = dents[offset:]
	written := 0
	for i, f := range dents {
		// TODO: syscall.Stat_t portability?
		inode := f.Sys().(*syscall.Stat_t).Ino
		// figure out file mode
		mode := f.Mode()
		fileType := DT_REG
		if f.IsDir() {
			fileType = DT_DIR
		} else if mode&os.ModeNamedPipe > 0 {
			fileType = DT_FIFO
		} else if mode&os.ModeSymlink > 0 {
			fileType = DT_LNK
		} else if mode&os.ModeDevice > 0 {
			if mode&os.ModeCharDevice > 0 {
				fileType = DT_CHR
			} else {
				fileType = DT_BLK
			}
		} else if mode&os.ModeSocket > 0 {
			fileType = DT_SOCK
		}
		// TODO: does inode get truncated? I guess there's getdents64
		var ent interface{}
		if k.U.Bits() == 64 {
			ent = &Dirent64{inode, uint64(i), 0, f.Name() + "\x00", fileType}
		} else {
			ent = &Dirent{inode, uint64(i), 0, f.Name() + "\x00", fileType}
		}
		size, _ := struc.Sizeof(ent)
		if uint64(written+size) > count {
			break
		}
		if k.U.Bits() == 64 {
			ent.(*Dirent64).Len = size
		} else {
			ent.(*Dirent).Len = size
		}
		written += size
		if err := buf.Pack(ent); err != nil {
			return UINT64_MAX // FIXME
		}
	}
	return uint64(written)
}
Esempio n. 2
0
func (k *LinuxKernel) getdents(dirfd co.Fd, buf co.Obuf, count uint64, bits uint) uint64 {
	dir, ok := k.Files[dirfd]
	if !ok {
		return UINT64_MAX // FIXME
	}
	dents := dir.Dirents
	if dents == nil {
		dent, err := os.Lstat(path.Join(dir.Path, ".."))
		if err == nil {
			dents = append(dents, fileInfoProxy{dent, ".."})
		}
		dent, err = os.Lstat(dir.Path)
		if err == nil {
			dents = append(dents, fileInfoProxy{dent, "."})
		}
		contents, err := ioutil.ReadDir(dir.Path)
		if err != nil {
			return UINT64_MAX // FIXME
		}
		dents = append(dents, contents...)
		dir.Dirents = dents
	}
	if dir.Offset >= uint64(len(dents)) {
		return 0
	}
	dents = dents[dir.Offset:]
	written := 0
	offset := dir.Offset
	out := buf.Struc()
	for i, f := range dents {
		// TODO: syscall.Stat_t portability?
		inode := f.Sys().(*syscall.Stat_t).Ino
		// figure out file mode
		mode := f.Mode()
		fileType := DT_REG
		if f.IsDir() {
			fileType = DT_DIR
		} else if mode&os.ModeNamedPipe > 0 {
			fileType = DT_FIFO
		} else if mode&os.ModeSymlink > 0 {
			fileType = DT_LNK
		} else if mode&os.ModeDevice > 0 {
			if mode&os.ModeCharDevice > 0 {
				fileType = DT_CHR
			} else {
				fileType = DT_BLK
			}
		} else if mode&os.ModeSocket > 0 {
			fileType = DT_SOCK
		}
		// TODO: does inode get truncated? guess it depends on guest LFS support
		var ent interface{}
		if bits == 64 {
			ent = &Dirent64{inode, dir.Offset + uint64(i), 0, fileType, f.Name() + "\x00"}
		} else {
			ent = &Dirent{inode, dir.Offset + uint64(i), 0, f.Name() + "\x00", fileType}
		}
		size, _ := struc.Sizeof(ent)
		if uint64(written+size) > count {
			break
		}
		offset++
		if bits == 64 {
			ent.(*Dirent64).Len = size
		} else {
			ent.(*Dirent).Len = size
		}
		written += size
		if err := out.Pack(ent); err != nil {
			return UINT64_MAX // FIXME
		}
	}
	dir.Offset = offset
	return uint64(written)
}