fs.ha (4748B)
1 // SPDX-License-Identifier: MPL-2.0 2 // (c) Hare authors <https://harelang.org> 3 4 use errors; 5 use fs; 6 use rt; 7 use types::c; 8 9 export type setxattr_flag = enum int { 10 NONE = 0, 11 XATTR_CREATE = 0x1, 12 XATTR_REPLACE = 0x2, 13 }; 14 15 @init fn init_cwd() void = { 16 static let cwd_fs = os_filesystem { ... }; 17 cwd = static_dirfdopen(rt::AT_FDCWD, &cwd_fs); 18 }; 19 20 // Returns the current working directory. The return value is statically 21 // allocated and must be duplicated (see [[strings::dup]]) before calling getcwd 22 // again. 23 export fn getcwd() str = c::tostr(rt::getcwd() as *const u8: *const c::char)!; 24 25 // Change the current working directory. 26 export fn chdir(target: (*fs::fs | str)) (void | fs::error) = { 27 const path: str = match (target) { 28 case let fs: *fs::fs => 29 assert(fs.open == &fs_open); 30 let fs = fs: *os_filesystem; 31 match (rt::fchdir(fs.dirfd)) { 32 case let err: rt::errno => 33 return errno_to_fs(err); 34 case void => 35 return; 36 }; 37 case let s: str => 38 yield s; 39 }; 40 match (rt::chdir(path)) { 41 case let err: rt::errno => 42 return errno_to_fs(err); 43 case void => void; 44 }; 45 }; 46 47 // Changes the root directory of the process. Generally requires the caller to 48 // have root or otherwise elevated permissions. 49 // 50 // This function is not appropriate for sandboxing. 51 export fn chroot(target: str) (void | fs::error) = { 52 match (rt::chroot(target)) { 53 case let err: rt::errno => 54 return errno_to_fs(err); 55 case void => void; 56 }; 57 }; 58 59 // Makes a FIFO node. This function is only available on Unix systems. 60 export fn mkfifo(path: str, mode: fs::mode) (void | fs::error) = { 61 match (rt::mknodat(rt::AT_FDCWD, path, 62 mode: rt::mode_t | rt::S_IFIFO, 0)) { 63 case let err: rt::errno => 64 return errno_to_fs(err); 65 case void => void; 66 }; 67 }; 68 69 // Makes a block device node. This function is only available on Unix-like 70 // systems. 71 export fn mkblk( 72 path: str, 73 mode: fs::mode, 74 major: uint, 75 minor: uint, 76 ) (void | fs::error) = { 77 match (rt::mknodat(rt::AT_FDCWD, path, 78 mode: rt::mode_t | rt::S_IFBLK, 79 rt::mkdev(major: u32, minor: u32))) { 80 case let err: rt::errno => 81 return errno_to_fs(err); 82 case void => void; 83 }; 84 }; 85 86 // Makes a character device node. This function is only available on Unix-like 87 // systems. 88 export fn mkchr( 89 path: str, 90 mode: fs::mode, 91 major: uint, 92 minor: uint, 93 ) (void | fs::error) = { 94 match (rt::mknodat(rt::AT_FDCWD, path, mode: rt::mode_t | rt::S_IFCHR, 95 rt::mkdev(major: u32, minor: u32))) { 96 case let err: rt::errno => 97 return errno_to_fs(err); 98 case void => void; 99 }; 100 }; 101 102 // Makes a regular file. This function is only available on Unix-like systems. 103 // This function should only be used if you have a special reason; most of the 104 // time you should use [[create]] instead. 105 export fn mkfile(path: str, mode: fs::mode) (void | fs::error) = { 106 match (rt::mknodat(rt::AT_FDCWD, path, 107 mode: rt::mode_t | rt::S_IFREG, 0)) { 108 case let err: rt::errno => 109 return errors::errno(err); 110 case void => void; 111 }; 112 }; 113 114 // Access modes for [[access]]. 115 export type amode = enum int { 116 F_OK = rt::F_OK, 117 R_OK = rt::R_OK, 118 W_OK = rt::W_OK, 119 X_OK = rt::X_OK, 120 }; 121 122 // Returns true if the given mode of access is permissible. The use of this 123 // function is discouraged as it can allow for a race condition to occur betwen 124 // testing for the desired access mode and actually using the file should the 125 // permissions of the file change between these operations. It is recommended 126 // instead to attempt to use the file directly and to handle any errors that 127 // should occur at that time. 128 export fn access(path: str, mode: amode) (bool | fs::error) = { 129 match (rt::access(path, mode)) { 130 case let b: bool => 131 return b; 132 case let err: rt::errno => 133 return errno_to_fs(err); 134 }; 135 }; 136 137 // Sets an extended file attribute. 138 export fn setxattr( 139 path: str, 140 name: str, 141 value: []u8, 142 flags: setxattr_flag = setxattr_flag::NONE, 143 ) (void | fs::error) = { 144 match (rt::setxattr(path, name, value, flags)) { 145 case let err: rt::errno => 146 return errno_to_fs(err); 147 case void => 148 return void; 149 }; 150 }; 151 152 // Gets an extended file attribute. 153 // The caller is responsible for freeing the returned slice. 154 export fn getxattr(path: str, name: str) ([]u8 | fs::error) = { 155 let empty: []u8 = []; 156 let attr_size = match (rt::getxattr(path, name, empty)) { 157 case let err: rt::errno => 158 return errno_to_fs(err); 159 case let s: u64 => 160 yield s; 161 }; 162 163 let buf: []u8 = alloc([0...], attr_size)!; 164 match (rt::getxattr(path, name, buf)) { 165 case let err: rt::errno => 166 return errno_to_fs(err); 167 case let s: u64 => 168 return buf; 169 }; 170 }; 171 172 // Removes an extended file attribute. 173 export fn removexattr(path: str, name: str) (void | fs::error) = { 174 match (rt::removexattr(path, name)) { 175 case let err: rt::errno => 176 return errno_to_fs(err); 177 case void => 178 return void; 179 }; 180 };