hare

[hare] The Hare programming language
git clone https://git.torresjrjr.com/hare.git
Log | Files | Refs | README | LICENSE

+linux.ha (3805B)


      1 // License: MPL-2.0
      2 // (c) 2022 Alexey Yerin <yyp@disroot.org>
      3 // (c) 2021-2022 Drew DeVault <sir@cmpwn.com>
      4 // (c) 2021 Eyal Sawady <ecs@d2evs.net>
      5 // (c) 2022 Jon Eskin <eskinjp@gmail.com>
      6 use crypto::random;
      7 use encoding::hex;
      8 use errors;
      9 use fmt;
     10 use fs;
     11 use io;
     12 use os;
     13 use path;
     14 use strio;
     15 
     16 fn get_tmpdir() str = os::tryenv("TMPDIR", "/tmp");
     17 
     18 // Creates an unnamed temporary file. The file may or may not have a name; not
     19 // all systems support the creation of temporary inodes which are not linked to
     20 // any directory. If it is necessary to create a real file, it will be removed
     21 // when the stream is closed.
     22 //
     23 // The I/O mode must be either [[io::mode::WRITE]] or [[io::mode::RDWR]].
     24 //
     25 // Only one variadic argument may be provided, if at all, to specify the mode of
     26 // the new file. The default is 0o644.
     27 export fn file(
     28 	iomode: io::mode,
     29 	mode: fs::mode...
     30 ) (io::file | fs::error) = {
     31 	assert(iomode == io::mode::WRITE || iomode == io::mode::RDWR);
     32 	assert(len(mode) == 0 || len(mode) == 1);
     33 	let fmode = if (len(mode) != 0) mode[0] else 0o644: fs::mode;
     34 	let oflags = fs::flags::TMPFILE | fs::flags::EXCL;
     35 	if (iomode == io::mode::RDWR) {
     36 		oflags |= fs::flags::RDWR;
     37 	} else {
     38 		oflags |= fs::flags::WRONLY;
     39 	};
     40 	// TODO: Add a custom "close" function which removes the named file
     41 	match (os::create(get_tmpdir(), fmode, oflags)) {
     42 	case let err: fs::error =>
     43 		let file = named(os::cwd, get_tmpdir(), iomode, mode...)?;
     44 		free(file.1);
     45 		return file.0;
     46 	case let f: io::file =>
     47 		return f;
     48 	};
     49 };
     50 
     51 // Creates a named temporary file in the given directory of the given
     52 // filesystem. The caller is responsible for closing and removing the file when
     53 // they're done with it. The name is statically allocated, and will be
     54 // overwritten on subsequent calls.
     55 //
     56 // The I/O mode must be either [[io::mode::WRITE]] or [[io::mode::RDWR]].
     57 //
     58 // Only one variadic argument may be provided, if at all, to specify the mode of
     59 // the new file. The default is 0o644.
     60 export fn named(
     61 	fs: *fs::fs,
     62 	path: str,
     63 	iomode: io::mode,
     64 	mode: fs::mode...
     65 ) ((io::file, str) | fs::error) = {
     66 	assert(iomode == io::mode::WRITE || iomode == io::mode::RDWR);
     67 	assert(len(mode) == 0 || len(mode) == 1);
     68 
     69 	let fmode = if (len(mode) != 0) mode[0] else 0o644: fs::mode;
     70 	let oflags = fs::flags::EXCL;
     71 	if (iomode == io::mode::RDWR) {
     72 		oflags |= fs::flags::RDWR;
     73 	} else {
     74 		oflags |= fs::flags::WRONLY;
     75 	};
     76 
     77 	static let pathbuf = path::buffer { ... };
     78 	static let namebuf: [32]u8 = [0...];
     79 	for (true) {
     80 		let rand: [size(u64)]u8 = [0...];
     81 		random::buffer(rand);
     82 
     83 		const id = *(&rand[0]: *u64);
     84 		const name = fmt::bsprintf(namebuf, "temp.{}", id);
     85 		const path = path::set(&pathbuf, path, name)!;
     86 
     87 		match (fs::create_file(fs, path, fmode, oflags)) {
     88 		case errors::exists =>
     89 			continue;
     90 		case let err: fs::error =>
     91 			return err;
     92 		case let f: io::file =>
     93 			return (f, path);
     94 		};
     95 	};
     96 	abort(); // Unreachable
     97 };
     98 
     99 // Creates a temporary directory. This function only guarantees that the
    100 // directory will have a unique name and be placed in the system temp directory,
    101 // but not that it will be removed automatically; the caller must remove it when
    102 // they're done using it via [[os::rmdir]] or [[os::rmdirall]].
    103 //
    104 // The return value is statically allocated and will be overwritten on
    105 // subsequent calls.
    106 export fn dir() str = {
    107 	const buf: [8]u8 = [0...], name: [16]u8 = [0...];
    108 	random::buffer(buf[..]);
    109 
    110 	const sink = strio::fixed(name);
    111 	let enc = hex::newencoder(&sink);
    112 	io::write(&enc, buf) as size;
    113 	const name = strio::string(&sink);
    114 
    115 	static let buf = path::buffer { ... };
    116 	path::set(&buf, get_tmpdir(), name)!;
    117 	const path = path::string(&buf);
    118 	match (os::mkdir(path, 0o755)) {
    119 	case let err: fs::error => abort("Could not create temp directory");
    120 	case void => void;
    121 	};
    122 	return path;
    123 };