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}