Centralizes docs on Ino, specifically zero (#1560)

Signed-off-by: Adrian Cole <adrian@tetrate.io>
This commit is contained in:
Crypt Keeper
2023-07-07 08:33:50 +08:00
committed by GitHub
parent 0ec3c852d6
commit 6a9088b46b
16 changed files with 109 additions and 27 deletions

View File

@@ -7,16 +7,38 @@ import (
"time"
)
// Dirent is an entry read from a directory.
// Ino is the file serial number, or zero if unknown.
//
// The inode is used for a file equivalence, like os.SameFile, so any constant
// value will interfere that.
//
// When zero is returned by File.Readdir, certain callers will fan-out to
// File.Stat to retrieve a non-zero value. Callers using this for darwin's
// definition of `getdirentries` conflate zero `d_fileno` with a deleted file
// and skip the entry. See /RATIONALE.md for more on this.
type Ino = uint64
// FileType is fs.FileMode masked on fs.ModeType. For example, zero is a
// regular file, fs.ModeDir is a directory and fs.ModeIrregular is unknown.
//
// Note: This is defined by Linux, not POSIX.
type FileType = fs.FileMode
// Dirent is an entry read from a directory via File.Readdir.
//
// # Notes
//
// - This extends `dirent` defined in POSIX with some fields defined by
// Linux. See https://man7.org/linux/man-pages/man3/readdir.3.html and
// https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/dirent.h.html
// - This has a subset of fields defined in Stat_t. Notably, there is no
// field corresponding to Stat_t.Dev because that value will be constant
// for all files in a directory. To get the Dev value, call File.Stat on
// the directory File.Readdir was called on.
type Dirent struct {
// Ino is the file serial number, or zero if not available.
Ino uint64
// Ino is the file serial number, or zero if not available. See Ino for
// more details including impact returning a zero value.
Ino Ino
// Name is the base name of the directory entry. Empty is invalid.
Name string

View File

@@ -55,7 +55,7 @@ type File interface {
//
// - Implementations should cache this result.
// - This combined with Dev can implement os.SameFile.
Ino() (uint64, syscall.Errno)
Ino() (Ino, syscall.Errno)
// IsDir returns true if this file is a directory or an error there was an
// error retrieving this information.

View File

@@ -13,8 +13,9 @@ type Stat_t struct {
// Dev is the device ID of device containing the file.
Dev uint64
// Ino is the file serial number.
Ino uint64
// Ino is the file serial number, or zero if not available. See Ino for
// more details including impact returning a zero value.
Ino Ino
// Uid is the user ID that owns the file, or zero if unsupported.
// For example, this is unsupported on some virtual filesystems or windows.

View File

@@ -97,7 +97,7 @@ func (UnimplementedFile) Dev() (uint64, syscall.Errno) {
}
// Ino implements File.Ino
func (UnimplementedFile) Ino() (uint64, syscall.Errno) {
func (UnimplementedFile) Ino() (Ino, syscall.Errno) {
return 0, 0
}

View File

@@ -139,7 +139,8 @@ func synthesizeDotEntries(f *FileEntry) ([]fsapi.Dirent, syscall.Errno) {
}
result := [2]fsapi.Dirent{}
result[0] = fsapi.Dirent{Name: ".", Ino: dotIno, Type: fs.ModeDir}
// See /RATIONALE.md for why we don't attempt to get an inode for ".."
// See /RATIONALE.md for why we don't attempt to get an inode for ".." and
// why in wasi-libc this won't fan-out either.
result[1] = fsapi.Dirent{Name: "..", Ino: 0, Type: fs.ModeDir}
return result[:], 0
}

View File

@@ -27,7 +27,7 @@ func (r *lazyDir) Dev() (uint64, syscall.Errno) {
}
// Ino implements the same method as documented on fsapi.File
func (r *lazyDir) Ino() (uint64, syscall.Errno) {
func (r *lazyDir) Ino() (fsapi.Ino, syscall.Errno) {
if f, ok := r.file(); !ok {
return 0, syscall.EBADF
} else {

View File

@@ -124,7 +124,7 @@ type cachedStat struct {
dev uint64
// dev is the same as fsapi.Stat_t Ino.
ino uint64
ino fsapi.Ino
// isDir is fsapi.Stat_t Mode masked with fs.ModeDir
isDir bool
@@ -132,7 +132,7 @@ type cachedStat struct {
// cachedStat returns the cacheable parts of fsapi.Stat_t or an error if they
// couldn't be retrieved.
func (f *fsFile) cachedStat() (dev, ino uint64, isDir bool, errno syscall.Errno) {
func (f *fsFile) cachedStat() (dev uint64, ino fsapi.Ino, isDir bool, errno syscall.Errno) {
if f.cachedSt == nil {
if _, errno = f.Stat(); errno != 0 {
return
@@ -148,7 +148,7 @@ func (f *fsFile) Dev() (uint64, syscall.Errno) {
}
// Ino implements the same method as documented on fsapi.File
func (f *fsFile) Ino() (uint64, syscall.Errno) {
func (f *fsFile) Ino() (fsapi.Ino, syscall.Errno) {
_, ino, _, errno := f.cachedStat()
return ino, errno
}
@@ -435,7 +435,7 @@ func readdir(f readdirFile, path string, n int) (dirents []fsapi.Dirent, errno s
dirents = make([]fsapi.Dirent, 0, len(fis))
// linux/darwin won't have to fan out to lstat, but windows will.
var ino uint64
var ino fsapi.Ino
for fi := range fis {
t := fis[fi]
if ino, errno = inoFromFileInfo(path, t); errno != 0 {

View File

@@ -151,7 +151,7 @@ func TestFileIno(t *testing.T) {
tests := []struct {
name string
fs fs.FS
expectedIno uint64
expectedIno fsapi.Ino
}{
{name: "os.DirFS", fs: dirFS, expectedIno: st.Ino},
{name: "embed.api.FS", fs: embedFS},

View File

@@ -44,7 +44,7 @@ type osFile struct {
// cachedStat returns the cacheable parts of fsapi.Stat_t or an error if they
// couldn't be retrieved.
func (f *osFile) cachedStat() (dev, ino uint64, isDir bool, errno syscall.Errno) {
func (f *osFile) cachedStat() (dev uint64, ino fsapi.Ino, isDir bool, errno syscall.Errno) {
if f.cachedSt == nil {
if _, errno = f.Stat(); errno != 0 {
return
@@ -60,7 +60,7 @@ func (f *osFile) Dev() (uint64, syscall.Errno) {
}
// Ino implements the same method as documented on fsapi.File
func (f *osFile) Ino() (uint64, syscall.Errno) {
func (f *osFile) Ino() (fsapi.Ino, syscall.Errno) {
_, ino, _, errno := f.cachedStat()
return ino, errno
}

View File

@@ -76,7 +76,7 @@ func (r *readFile) Dev() (uint64, syscall.Errno) {
}
// Ino implements the same method as documented on fsapi.File.
func (r *readFile) Ino() (uint64, syscall.Errno) {
func (r *readFile) Ino() (fsapi.Ino, syscall.Errno) {
return r.f.Ino()
}

View File

@@ -31,7 +31,7 @@ func statFile(f fs.File) (fsapi.Stat_t, syscall.Errno) {
return defaultStatFile(f)
}
func inoFromFileInfo(_ string, t fs.FileInfo) (ino uint64, err syscall.Errno) {
func inoFromFileInfo(_ string, t fs.FileInfo) (ino fsapi.Ino, err syscall.Errno) {
if d, ok := t.Sys().(*syscall.Stat_t); ok {
ino = d.Ino
}

View File

@@ -34,7 +34,7 @@ func statFile(f fs.File) (fsapi.Stat_t, syscall.Errno) {
return defaultStatFile(f)
}
func inoFromFileInfo(_ string, t fs.FileInfo) (ino uint64, err syscall.Errno) {
func inoFromFileInfo(_ string, t fs.FileInfo) (ino fsapi.Ino, err syscall.Errno) {
if d, ok := t.Sys().(*syscall.Stat_t); ok {
ino = d.Ino
}

View File

@@ -33,7 +33,7 @@ func statFile(f fs.File) (fsapi.Stat_t, syscall.Errno) {
return defaultStatFile(f)
}
func inoFromFileInfo(_ string, t fs.FileInfo) (ino uint64, err syscall.Errno) {
func inoFromFileInfo(_ string, t fs.FileInfo) (ino fsapi.Ino, err syscall.Errno) {
return
}

View File

@@ -72,7 +72,7 @@ func statFile(f fs.File) (fsapi.Stat_t, syscall.Errno) {
}
// inoFromFileInfo uses stat to get the inode information of the file.
func inoFromFileInfo(filePath string, t fs.FileInfo) (ino uint64, errno syscall.Errno) {
func inoFromFileInfo(filePath string, t fs.FileInfo) (ino fsapi.Ino, errno syscall.Errno) {
if filePath == "" {
// This is a fs.File backed implementation which doesn't have access to
// the original file path.