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