module os // stat returns a platform-agnostic Stat struct comparable to what is // available in other programming languages and fails with the POSIX // error if the stat call fails. In Windows, there is no lstat so // information on a link cannot be provided. // C._wstat64() can be used on 32- and 64-bit Windows per // https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/stat-functions?view=msvc-170 pub fn stat(path string) !Stat { mut s := C.__stat64{} unsafe { res := C._wstat64(path.to_wide(), &s) if res != 0 { return error_posix() } return Stat{ dev: s.st_dev inode: s.st_ino nlink: s.st_nlink mode: s.st_mode uid: s.st_uid gid: s.st_gid rdev: s.st_rdev size: s.st_size atime: s.st_atime mtime: s.st_mtime ctime: s.st_ctime } } } // lstat is the same as stat() for Windows @[inline] pub fn lstat(path string) !Stat { return stat(path) } // get_filetype returns the FileType from the Stat struct pub fn (st Stat) get_filetype() FileType { match st.mode & u32(C.S_IFMT) { u32(C.S_IFDIR) { return .directory } else { return .regular } } } // get_mode returns the file type and permissions (readable, writable, executable) // in owner/group/others format, however, they will all be the same for Windows pub fn (st Stat) get_mode() FileMode { return FileMode{ typ: st.get_filetype() owner: FilePermission{ read: (st.mode & u32(C.S_IREAD)) != 0 write: (st.mode & u32(C.S_IWRITE)) != 0 execute: (st.mode & u32(C.S_IEXEC)) != 0 } group: FilePermission{ read: (st.mode & u32(C.S_IREAD)) != 0 write: (st.mode & u32(C.S_IWRITE)) != 0 execute: (st.mode & u32(C.S_IEXEC)) != 0 } others: FilePermission{ read: (st.mode & u32(C.S_IREAD)) != 0 write: (st.mode & u32(C.S_IWRITE)) != 0 execute: (st.mode & u32(C.S_IEXEC)) != 0 } } } // is_dir returns a `bool` indicating whether the given `path` is a directory. pub fn is_dir(path string) bool { w_path := path.replace('/', '\\') attr := C.GetFileAttributesW(w_path.to_wide()) if attr == u32(C.INVALID_FILE_ATTRIBUTES) { return false } if int(attr) & C.FILE_ATTRIBUTE_DIRECTORY != 0 { return true } return false } // is_link returns a boolean indicating whether `path` is a link. // Warning: `is_link()` is known to cause a TOCTOU vulnerability when used incorrectly // (for more information: https://github.com/vlang/v/blob/master/vlib/os/README.md) pub fn is_link(path string) bool { path_ := path.replace('/', '\\') attr := C.GetFileAttributesW(path_.to_wide()) return int(attr) != int(C.INVALID_FILE_ATTRIBUTES) && (attr & 0x400) != 0 } // kind_of_existing_path identifies whether path is a file, directory, or link fn kind_of_existing_path(path string) PathKind { mut res := PathKind{} attr := C.GetFileAttributesW(path.to_wide()) if attr != u32(C.INVALID_FILE_ATTRIBUTES) { if (int(attr) & C.FILE_ATTRIBUTE_NORMAL) != 0 { res.is_file = true } if (int(attr) & C.FILE_ATTRIBUTE_DIRECTORY) != 0 { res.is_dir = true } if (int(attr) & 0x400) != 0 { res.is_link = true } } return res }