1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348
|
// SPDX-License-Identifier: MPL-2.0
// (c) Hare authors <https://harelang.org>
use encoding::utf8;
use errors;
use io;
use strings;
use time;
// An entry of a particular type was sought, but is something else in practice.
// For example, opening a file with [[iter]].
export type wrongtype = !void;
// Returned from [[rename]] if this rename is not possible due to technical
// constraints, such as if it would cause a file to move between filesystems. In
// this situation, other operations (such as copy & remove) may succeed if
// attempted.
export type cannotrename = !void;
// All possible fs error types.
export type error = !(
errors::noentry |
errors::noaccess |
errors::exists |
errors::busy |
errors::invalid |
errors::unsupported |
utf8::invalid |
wrongtype |
cannotrename |
io::error);
// Returns a human-friendly representation of an error.
export fn strerror(err: error) const str = {
match (err) {
case wrongtype =>
return "Wrong entry type for requested operation";
case cannotrename =>
return "Unable to perform rename operation (try move instead)";
case errors::noentry =>
return "File or directory not found";
case errors::noaccess =>
return "Permission denied";
case errors::exists =>
return "File or directory exists";
case errors::invalid =>
return "Invalid argument";
case errors::busy =>
return "Device is busy";
case errors::unsupported =>
return "Operation not supported";
case let err: utf8::invalid =>
return utf8::strerror(err);
case let err: io::error =>
return io::strerror(err);
};
};
// File mode information. These bits do not necessarily reflect the underlying
// operating system's mode representation, though they were chosen to be
// consistent with typical Unix file permissions. All implementations shall
// support at least USER_RW, DIR, and REG.
export type mode = enum uint {
// Read, write, and execute permissions for the file owner
USER_RWX = 0o700,
// Read and write permissions for the file owner
USER_RW = 0o600,
// Read and execute permissions for the file owner
USER_RX = 0o500,
// Read permissions for the file owner
USER_R = 0o400,
// Write permissions for the file owner
USER_W = 0o200,
// Execute permissions for the file owner
USER_X = 0o100,
// Read, write, and execute permissions for group members
GROUP_RWX = 0o070,
// Read and write permissions for group members
GROUP_RW = 0o060,
// Read and execute permissions for group members
GROUP_RX = 0o050,
// Read permissions for group members
GROUP_R = 0o040,
// Write permissions for group members
GROUP_W = 0o020,
// Execute permissions for group members
GROUP_X = 0o010,
// Read, write, and execute permissions for other users
OTHER_RWX = 0o007,
// Read and write permissions for other users
OTHER_RW = 0o006,
// Read and execute permissions for other users
OTHER_RX = 0o005,
// Read permissions for other users
OTHER_R = 0o004,
// Write permissions for other users
OTHER_W = 0o002,
// Execute permissions for other users
OTHER_X = 0o001,
// Entry has the set-uid bit set
SETUID = 0o4000,
// Entry has the set-gid bit set
SETGID = 0o2000,
// Entry has the sticky bit set
STICKY = 0o1000,
// Entry is of an unknown type
UNKNOWN = 0,
// Entry is a FIFO (named pipe)
FIFO = 0o010000,
// Entry is a directory
DIR = 0o040000,
// Entry is a character device
CHR = 0o020000,
// Entry is a block device
BLK = 0o060000,
// Entry is a regular file
REG = 0o100000,
// Entry is a symbolic link
LINK = 0o120000,
// Entry is a Unix socket
SOCK = 0o140000,
};
// A mask defining what items are populated in the stat structure.
export type stat_mask = enum uint {
UID = 1 << 0,
GID = 1 << 1,
SIZE = 1 << 2,
INODE = 1 << 3,
ATIME = 1 << 4,
MTIME = 1 << 5,
CTIME = 1 << 6,
};
// Information about a file or directory. The mask field defines what other
// fields are set; mode is always set.
export type filestat = struct {
mask: stat_mask,
mode: mode,
uid: uint,
gid: uint,
sz: size,
inode: u64,
atime: time::instant,
mtime: time::instant,
ctime: time::instant,
};
// An entry in a directory. This may be borrowed from the filesystem's internal
// state. If you want to keep this around beyond one call to [[next]], use
// [[dirent_dup]].
export type dirent = struct {
// The name of this entry. Not fully qualified: for example,
// "foo/bar/baz.txt" would store "baz.txt" here.
name: str,
// The type of this entry. The permission bits may be unset.
ftype: mode,
};
// Duplicates a [[dirent]] object. Call [[dirent_finish]] to get rid of it
// later.
export fn dirent_dup(e: *dirent) (dirent | nomem) = {
let new = *e;
new.name = strings::dup(e.name)?;
return new;
};
// Frees memory associated with a [[dirent]] object which was duplicated with
// [[dirent_dup]].
export fn dirent_finish(e: *dirent) void = free(e.name);
// Flags to use for opening a file. Not all operating systems support all flags;
// at a minimum, RDONLY, WRONLY, RDWR, CREATE, and TRUNC will be supported.
// Note that NOCTTY and CLOEXEC are on by default, and the CTTY/NOCLOEXEC flags
// respectively disable them.
export type flag = enum int {
RDONLY = 0,
WRONLY = 1,
RDWR = 2,
CREATE = 0o100,
EXCL = 0o200,
CTTY = 0o400,
TRUNC = 0o1000,
APPEND = 0o2000,
NONBLOCK = 0o4000,
DSYNC = 0o10000,
SYNC = 0o4010000,
RSYNC = 0o4010000,
DIRECTORY = 0o200000,
NOFOLLOW = 0o400000,
NOATIME = 0o1000000,
NOCLOEXEC = 0o2000000,
PATH = 0o10000000,
TMPFILE = 0o20200000,
};
export type closefunc = fn(fs: *fs) void;
export type removefunc = fn(fs: *fs, path: str) (void | error);
export type renamefunc = fn(fs: *fs, oldpath: str, newpath: str) (void | error);
export type iterfunc = fn(fs: *fs, path: str) (*iterator | error);
export type statfunc = fn(fs: *fs, path: str) (filestat | error);
export type fstatfunc = fn(fs: *fs, file: io::file) (filestat | error);
export type mkdirfunc = fn(fs: *fs, path: str, mode: mode) (void | error);
export type rmdirfunc = fn(fs: *fs, path: str) (void | error);
export type chmodfunc = fn(fs: *fs, path: str, mode: mode) (void | error);
export type fchmodfunc = fn(fd: io::file, mode: mode) (void | error);
export type chownfunc = fn(fs: *fs, path: str, uid: uint, gid: uint) (void | error);
export type fchownfunc = fn(fd: io::file, uid: uint, gid: uint) (void | error);
export type chtimesfunc = fn(fs: *fs, path: str, atime: (time::instant | void),
mtime: (time::instant | void)) (void | error);
export type fchtimesfunc = fn(fd: io::file, atime: (time::instant | void),
mtime: (time::instant | void)) (void | error);
export type resolvefunc = fn(fs: *fs, path: str) str;
export type readlinkfunc = fn(fs: *fs, path: str) (str | error);
export type linkfunc = fn(fs: *fs, old: str, new: str) (void | error);
export type symlinkfunc = fn(fs: *fs, target: str, path: str) (void | error);
export type openfunc = fn(
fs: *fs,
path: str,
flags: flag,
) (io::handle | error);
export type openfilefunc = fn(
fs: *fs,
path: str,
flags: flag,
) (io::file | error);
export type createfunc = fn(
fs: *fs,
path: str,
mode: mode,
flags: flag,
) (io::handle | error);
export type createfilefunc = fn(
fs: *fs,
path: str,
mode: mode,
flags: flag,
) (io::file | error);
// An abstract implementation of a filesystem, which provides common filesystem
// operations such as file creation and deletion, but which may be backed by any
// underlying storage system. See [[os::cwd]] for access to the host filesystem.
//
// To create a custom filesystem implementation, embed this type as the first
// member of a struct with user-specific data and fill out these fields as
// appropriate.
export type fs = struct {
// Frees resources associated with this filesystem.
close: nullable *closefunc,
// Opens a file.
open: nullable *openfunc,
// Opens a file as an [[io::file]].
openfile: nullable *openfilefunc,
// Creates a new file.
create: nullable *createfunc,
// Creates a new file as an [[io::file]].
createfile: nullable *createfilefunc,
// Removes a file.
remove: nullable *removefunc,
// Renames a file.
rename: nullable *renamefunc,
// Returns an iterator for a path, which yields the contents of a
// directory. Pass empty string to yield from the root.
//
// The iterator must return all entries without error. If an error would
// occur, it should be identified here and returned upfront.
iter: nullable *iterfunc,
// Obtains information about a file or directory. If the target is a
// symbolic link, information is returned about the link, not its
// target.
stat: nullable *statfunc,
// Obtains information about an [[io::file]].
fstat: nullable *fstatfunc,
// Returns the path referred to by a symbolic link. The caller will free
// the return value.
readlink: nullable *readlinkfunc,
// Creates a directory.
mkdir: nullable *mkdirfunc,
// Removes a directory. The target directory must be empty.
rmdir: nullable *rmdirfunc,
// Changes mode flags on a file or directory.
chmod: nullable *chmodfunc,
// Changes mode flags on a [[io::file]].
fchmod: nullable *fchmodfunc,
// Changes ownership of a file.
chown: nullable *chownfunc,
// Changes ownership of a [[io::file]].
fchown: nullable *fchownfunc,
// Changes access and modification time of a file.
chtimes: nullable *chtimesfunc,
// Changes access and modification time of an [[io::file]].
fchtimes: nullable *fchtimesfunc,
// Resolves a path to its absolute, normalized value. If the fs
// implementation does not provide this, [resolve] presumes that
// relative paths are rooted (i.e. "foo" == "/foo").
resolve: nullable *resolvefunc,
// Creates a new (hard) link.
link: nullable *linkfunc,
// Creates a new symbolic link.
symlink: nullable *symlinkfunc,
};
// A function which returns the next directory from an [[iterator]].
export type nextfunc = fn(iter: *iterator) (dirent | done | error);
// A function which frees state associated with an [[iterator]].
export type finishfunc = fn(iter: *iterator) void;
// A directory iterator. To implement a directory iterator for a filesystem,
// subtype this struct to store any necessary state and populate the pointers
// with your implementation.
export type iterator = struct {
// Returns the next member of the directory, or done if there are none
// remaining.
next: *nextfunc,
// Frees resources associated with the iterator.
finish: nullable *finishfunc,
};
|