| 1 | module os |
| 2 | |
| 3 | // stat returns a platform-agnostic Stat struct, containing metadata about the given file/folder path. |
| 4 | // It returns a POSIX error, if it can not do so. |
| 5 | // Note: symlinks are followed, and the resulting Stat for their target will be returned. |
| 6 | // If this is not desired, call lstat/1 instead. |
| 7 | pub fn stat(path string) !Stat { |
| 8 | mut s := C.stat{} |
| 9 | unsafe { |
| 10 | res := C.stat(&char(path.str), &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 similar to stat/1 for normal files/folders. |
| 31 | // Unlike stat/1, however, it will return the stat info for a symlink, instead of its target. |
| 32 | pub fn lstat(path string) !Stat { |
| 33 | mut s := C.stat{} |
| 34 | unsafe { |
| 35 | res := C.lstat(&char(path.str), &s) |
| 36 | if res != 0 { |
| 37 | return error_posix() |
| 38 | } |
| 39 | return Stat{ |
| 40 | dev: s.st_dev |
| 41 | inode: s.st_ino |
| 42 | nlink: s.st_nlink |
| 43 | mode: s.st_mode |
| 44 | uid: s.st_uid |
| 45 | gid: s.st_gid |
| 46 | rdev: s.st_rdev |
| 47 | size: s.st_size |
| 48 | atime: s.st_atime |
| 49 | mtime: s.st_mtime |
| 50 | ctime: s.st_ctime |
| 51 | } |
| 52 | } |
| 53 | } |
| 54 | |
| 55 | // get_filetype returns the FileType from the Stat struct. |
| 56 | pub fn (st Stat) get_filetype() FileType { |
| 57 | match st.mode & u32(C.S_IFMT) { |
| 58 | u32(C.S_IFREG) { |
| 59 | return .regular |
| 60 | } |
| 61 | u32(C.S_IFDIR) { |
| 62 | return .directory |
| 63 | } |
| 64 | u32(C.S_IFCHR) { |
| 65 | return .character_device |
| 66 | } |
| 67 | u32(C.S_IFBLK) { |
| 68 | return .block_device |
| 69 | } |
| 70 | u32(C.S_IFIFO) { |
| 71 | return .fifo |
| 72 | } |
| 73 | u32(C.S_IFLNK) { |
| 74 | return .symbolic_link |
| 75 | } |
| 76 | u32(C.S_IFSOCK) { |
| 77 | return .socket |
| 78 | } |
| 79 | else { |
| 80 | return .unknown |
| 81 | } |
| 82 | } |
| 83 | } |
| 84 | |
| 85 | // get_mode returns the file type and permissions (readable, writable, executable) in owner/group/others format. |
| 86 | pub fn (st Stat) get_mode() FileMode { |
| 87 | return FileMode{ |
| 88 | typ: st.get_filetype() |
| 89 | owner: FilePermission{ |
| 90 | read: (st.mode & u32(C.S_IRUSR)) != 0 |
| 91 | write: (st.mode & u32(C.S_IWUSR)) != 0 |
| 92 | execute: (st.mode & u32(C.S_IXUSR)) != 0 |
| 93 | } |
| 94 | group: FilePermission{ |
| 95 | read: (st.mode & u32(C.S_IRGRP)) != 0 |
| 96 | write: (st.mode & u32(C.S_IWGRP)) != 0 |
| 97 | execute: (st.mode & u32(C.S_IXGRP)) != 0 |
| 98 | } |
| 99 | others: FilePermission{ |
| 100 | read: (st.mode & u32(C.S_IROTH)) != 0 |
| 101 | write: (st.mode & u32(C.S_IWOTH)) != 0 |
| 102 | execute: (st.mode & u32(C.S_IXOTH)) != 0 |
| 103 | } |
| 104 | } |
| 105 | } |
| 106 | |
| 107 | // is_dir returns a `bool` indicating whether the given `path` is a directory. |
| 108 | pub fn is_dir(path string) bool { |
| 109 | attr := stat(path) or { return false } |
| 110 | return attr.get_filetype() == .directory |
| 111 | } |
| 112 | |
| 113 | // is_link returns a boolean indicating whether `path` is a link. |
| 114 | // Warning: `is_link()` is known to cause a TOCTOU vulnerability when used incorrectly |
| 115 | // (for more information: https://github.com/vlang/v/blob/master/vlib/os/README.md). |
| 116 | pub fn is_link(path string) bool { |
| 117 | attr := lstat(path) or { return false } |
| 118 | return attr.get_filetype() == .symbolic_link |
| 119 | } |
| 120 | |
| 121 | // kind_of_existing_path identifies whether path is a file, directory, or link. |
| 122 | fn kind_of_existing_path(path string) PathKind { |
| 123 | mut res := PathKind{} |
| 124 | attr := lstat(path) or { return res } |
| 125 | res.is_file = attr.get_filetype() == .regular |
| 126 | res.is_dir = attr.get_filetype() == .directory |
| 127 | res.is_link = attr.get_filetype() == .symbolic_link |
| 128 | return res |
| 129 | } |
| 130 | |