stat.go

  1package sys
  2
  3import "io/fs"
  4
  5// Inode is the file serial number, or zero if unknown.
  6//
  7// Any constant value will invalidate functions that use this for
  8// equivalence, such as os.SameFile (Stat_t.Ino).
  9//
 10// When zero is returned by a `readdir`, some compilers will attempt to
 11// get a non-zero value with `lstat`. Those using this for darwin's definition
 12// of `getdirentries` conflate zero `d_fileno` with a deleted file, so skip the
 13// entry. See /RATIONALE.md for more on this.
 14type Inode = uint64
 15
 16// ^-- Inode is a type alias to consolidate documentation and aid in reference
 17// searches. While only Stat_t is exposed publicly at the moment, this is used
 18// internally for Dirent and several function return values.
 19
 20// EpochNanos is a timestamp in epoch nanoseconds, or zero if unknown.
 21//
 22// This defines epoch time the same way as Walltime, except this value is
 23// packed into an int64. Common conversions are detailed in the examples.
 24type EpochNanos = int64
 25
 26// Stat_t is similar to syscall.Stat_t, except available on all operating
 27// systems, including Windows.
 28//
 29// # Notes
 30//
 31//   - This is used for WebAssembly ABI emulating the POSIX `stat` system call.
 32//     See https://pubs.opengroup.org/onlinepubs/9699919799/functions/stat.html
 33//   - Fields here are required for WebAssembly ABI including wasip1
 34//     (a.k.a. wasix) and wasi-filesystem (a.k.a. wasip2).
 35//   - This isn't the same as syscall.Stat_t because wazero supports Windows,
 36//     which doesn't have that type. runtime.GOOS that has this already also
 37//     have inconsistent field lengths, which complicates wasm binding.
 38//   - Use NewStat_t to create this from an existing fs.FileInfo.
 39//   - For portability, numeric fields are 64-bit when at least one platform
 40//     defines it that large.
 41type Stat_t struct {
 42	// Dev is the device ID of device containing the file.
 43	Dev uint64
 44
 45	// Ino is the file serial number, or zero if not available. See Inode for
 46	// more details including impact returning a zero value.
 47	Ino Inode
 48
 49	// Mode is the same as Mode on fs.FileInfo containing bits to identify the
 50	// type of the file (fs.ModeType) and its permissions (fs.ModePerm).
 51	Mode fs.FileMode
 52
 53	// Nlink is the number of hard links to the file.
 54	//
 55	// Note: This value is platform-specific and often at least one. Linux will
 56	// return 1+N for a directory, where BSD (like Darwin) return 2+N, which
 57	// includes the dot entry.
 58	Nlink uint64
 59
 60	// Size is the length in bytes for regular files. For symbolic links, this
 61	// is length in bytes of the pathname contained in the symbolic link.
 62	Size int64
 63
 64	// Atim is the last data access timestamp in epoch nanoseconds.
 65	Atim EpochNanos
 66
 67	// Mtim is the last data modification timestamp in epoch nanoseconds.
 68	Mtim EpochNanos
 69
 70	// Ctim is the last file status change timestamp in epoch nanoseconds.
 71	Ctim EpochNanos
 72}
 73
 74// NewStat_t fills a new Stat_t from `info`, including any runtime.GOOS-specific
 75// details from fs.FileInfo `Sys`. When `Sys` is already a *Stat_t, it is
 76// returned as-is.
 77//
 78// # Notes
 79//
 80//   - When already in fs.FileInfo `Sys`, Stat_t must be a pointer.
 81//   - When runtime.GOOS is "windows" Stat_t.Ino will be zero.
 82//   - When fs.FileInfo `Sys` is nil or unknown, some fields not in fs.FileInfo
 83//     are defaulted: Stat_t.Atim and Stat_t.Ctim are set to `ModTime`, and
 84//     are set to ModTime and Stat_t.Nlink is set to 1.
 85func NewStat_t(info fs.FileInfo) Stat_t {
 86	// Note: Pointer, not val, for parity with Go, which sets *syscall.Stat_t
 87	if st, ok := info.Sys().(*Stat_t); ok {
 88		return *st
 89	}
 90	return statFromFileInfo(info)
 91}
 92
 93func defaultStatFromFileInfo(info fs.FileInfo) Stat_t {
 94	st := Stat_t{}
 95	st.Ino = 0
 96	st.Dev = 0
 97	st.Mode = info.Mode()
 98	st.Nlink = 1
 99	st.Size = info.Size()
100	mtim := info.ModTime().UnixNano() // Set all times to the mod time
101	st.Atim = mtim
102	st.Mtim = mtim
103	st.Ctim = mtim
104	return st
105}