| 1 | module os |
| 2 | |
| 3 | // stat returns metadata for the given file/folder. |
| 4 | // It will return a POSIX error message, if it can not do so. |
| 5 | // C._wstat64() can be used on 32- and 64-bit Windows per |
| 6 | // https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/stat-functions?view=msvc-170 |
| 7 | pub fn stat(path string) !Stat { |
| 8 | mut s := C.__stat64{} |
| 9 | unsafe { |
| 10 | res := C._wstat64(path.to_wide(), &s) |
| 11 | if res != 0 { |
| 12 | return error_posix() |
| 13 | } |
| 14 | return Stat{ |
| 15 | dev: s.st_dev |
| 16 | inode: s.st_ino |
| 17 | nlink: s.st_nlink |
| 18 | mode: s.st_mode |
| 19 | uid: s.st_uid |
| 20 | gid: s.st_gid |
| 21 | rdev: s.st_rdev |
| 22 | size: s.st_size |
| 23 | atime: s.st_atime |
| 24 | mtime: s.st_mtime |
| 25 | ctime: s.st_ctime |
| 26 | } |
| 27 | } |
| 28 | } |
| 29 | |
| 30 | // lstat is the same as stat() for Windows. |
| 31 | @[inline] |
| 32 | pub fn lstat(path string) !Stat { |
| 33 | return stat(path) |
| 34 | } |
| 35 | |
| 36 | // get_filetype returns the FileType from the Stat struct. |
| 37 | pub fn (st Stat) get_filetype() FileType { |
| 38 | match st.mode & u32(C.S_IFMT) { |
| 39 | u32(C.S_IFDIR) { |
| 40 | return .directory |
| 41 | } |
| 42 | else { |
| 43 | return .regular |
| 44 | } |
| 45 | } |
| 46 | } |
| 47 | |
| 48 | // get_mode returns the file type and permissions (readable, writable, executable) in owner/group/others format. |
| 49 | // Note: they will all be the same for Windows. |
| 50 | pub fn (st Stat) get_mode() FileMode { |
| 51 | return FileMode{ |
| 52 | typ: st.get_filetype() |
| 53 | owner: FilePermission{ |
| 54 | read: (st.mode & u32(C.S_IREAD)) != 0 |
| 55 | write: (st.mode & u32(C.S_IWRITE)) != 0 |
| 56 | execute: (st.mode & u32(C.S_IEXEC)) != 0 |
| 57 | } |
| 58 | group: FilePermission{ |
| 59 | read: (st.mode & u32(C.S_IREAD)) != 0 |
| 60 | write: (st.mode & u32(C.S_IWRITE)) != 0 |
| 61 | execute: (st.mode & u32(C.S_IEXEC)) != 0 |
| 62 | } |
| 63 | others: FilePermission{ |
| 64 | read: (st.mode & u32(C.S_IREAD)) != 0 |
| 65 | write: (st.mode & u32(C.S_IWRITE)) != 0 |
| 66 | execute: (st.mode & u32(C.S_IEXEC)) != 0 |
| 67 | } |
| 68 | } |
| 69 | } |
| 70 | |
| 71 | // is_dir returns a `bool` indicating whether the given `path` is a directory. |
| 72 | pub fn is_dir(path string) bool { |
| 73 | w_path := path.replace('/', '\\') |
| 74 | attr := C.GetFileAttributesW(w_path.to_wide()) |
| 75 | if attr == u32(C.INVALID_FILE_ATTRIBUTES) { |
| 76 | return false |
| 77 | } |
| 78 | if int(attr) & C.FILE_ATTRIBUTE_DIRECTORY != 0 { |
| 79 | return true |
| 80 | } |
| 81 | return false |
| 82 | } |
| 83 | |
| 84 | // is_link returns a boolean indicating whether `path` is a link. |
| 85 | // Warning: `is_link()` is known to cause a TOCTOU vulnerability when used incorrectly |
| 86 | // (for more information: https://github.com/vlang/v/blob/master/vlib/os/README.md) |
| 87 | pub fn is_link(path string) bool { |
| 88 | path_ := path.replace('/', '\\') |
| 89 | attr := C.GetFileAttributesW(path_.to_wide()) |
| 90 | return int(attr) != int(C.INVALID_FILE_ATTRIBUTES) && (attr & 0x400) != 0 |
| 91 | } |
| 92 | |
| 93 | // kind_of_existing_path identifies whether path is a file, directory, or link. |
| 94 | fn kind_of_existing_path(path string) PathKind { |
| 95 | mut res := PathKind{} |
| 96 | attr := C.GetFileAttributesW(path.to_wide()) |
| 97 | if attr != u32(C.INVALID_FILE_ATTRIBUTES) { |
| 98 | if (int(attr) & C.FILE_ATTRIBUTE_NORMAL) != 0 { |
| 99 | res.is_file = true |
| 100 | } |
| 101 | if (int(attr) & C.FILE_ATTRIBUTE_DIRECTORY) != 0 { |
| 102 | res.is_dir = true |
| 103 | } |
| 104 | if (int(attr) & 0x400) != 0 { |
| 105 | res.is_link = true |
| 106 | } |
| 107 | } |
| 108 | return res |
| 109 | } |
| 110 | |