lib/std/sys/unix.rad 3.6 KiB raw
1
//! Unix-specific system calls and utilities.
2
use std::intrinsics;
3
4
/// File access modes.
5
pub record OpenFlags(i64);
6
7
/// Open file for reading only.
8
pub const O_RDONLY: OpenFlags = OpenFlags(0);
9
10
/// Open file for writing only.
11
pub const O_WRONLY: OpenFlags = OpenFlags(1);
12
13
/// Open file for reading and writing.
14
pub const O_RDWR: OpenFlags = OpenFlags(2);
15
16
/// Create file if it doesn't exist.
17
pub const O_CREAT: OpenFlags = OpenFlags(64);
18
19
/// Truncate file to zero length.
20
pub const O_TRUNC: OpenFlags = OpenFlags(512);
21
22
/// Standard file descriptor for stdin.
23
pub const STDIN: i64 = 0;
24
25
/// Standard file descriptor for stdout.
26
pub const STDOUT: i64 = 1;
27
28
/// Standard file descriptor for stderr.
29
pub const STDERR: i64 = 2;
30
31
/// Special value representing current working directory for `openat()`.
32
const AT_FDCWD: i64 = -100;
33
34
/// Opens a file at the given path and returns a file descriptor.
35
/// Returns a negative value on error.
36
pub fn open(path: *[u8], flags: OpenFlags) -> i64 {
37
    return intrinsics::ecall(56, AT_FDCWD, path.ptr as i64, *flags, 0);
38
}
39
40
/// Opens a file at the given path with mode, returns a file descriptor.
41
pub fn openOpts(path: *[u8], flags: OpenFlags, mode: i64) -> i64 {
42
    return intrinsics::ecall(56, AT_FDCWD, path.ptr as i64, *flags, mode);
43
}
44
45
/// Reads from a file descriptor into the provided buffer.
46
/// Returns the number of bytes read, or a negative value on error.
47
pub fn read(fd: i64, buf: *mut [u8]) -> i64 {
48
    return intrinsics::ecall(63, fd, buf.ptr as i64, buf.len as i64, 0);
49
}
50
51
/// Reads from a file descriptor until EOF or buffer is full.
52
/// Returns the total number of bytes read, or a negative value on error.
53
pub fn readToEnd(fd: i64, buf: *mut [u8]) -> i64 {
54
    let mut total: u32 = 0;
55
    while total < buf.len {
56
        let chunk = &mut buf[total..];
57
        let n = read(fd, chunk);
58
59
        if n < 0 {
60
            return n;
61
        }
62
        if n == 0 {
63
            break;
64
        }
65
        total += n as u32;
66
    }
67
    return total as i64;
68
}
69
70
/// Writes to a file descriptor from the provided buffer.
71
/// Returns the number of bytes written, or a negative value on error.
72
pub fn write(fd: i64, buf: *[u8]) -> i64 {
73
    return intrinsics::ecall(64, fd, buf.ptr as i64, buf.len as i64, 0);
74
}
75
76
/// Closes a file descriptor.
77
/// Returns `0` on success, or a negative value on error.
78
pub fn close(fd: i64) -> i64 {
79
    return intrinsics::ecall(57, fd, 0, 0, 0);
80
}
81
82
/// Reads the entire contents of a file at the given path into the provided buffer.
83
/// Returns a slice containing the data read, or `nil` on error.
84
pub fn readFile(path: *[u8], buf: *mut [u8]) -> ?*[u8] {
85
    let fd = open(path, O_RDONLY);
86
    if fd < 0 {
87
        return nil;
88
    }
89
    let n = readToEnd(fd, buf);
90
91
    if close(fd) < 0 {
92
        return nil;
93
    }
94
    if n < 0 {
95
        return nil;
96
    }
97
    return &buf[..n as u32];
98
}
99
100
/// Exit the current process with the given status code.
101
pub fn exit(status: i64) {
102
    intrinsics::ecall(93, status, 0, 0, 0);
103
}
104
105
/// Writes the entire contents of a buffer to a file at the given path.
106
/// Creates the file if it doesn't exist, truncates if it does.
107
/// Returns `true` on success.
108
pub fn writeFile(path: *[u8], data: *[u8]) -> bool {
109
    let flags = OpenFlags(*O_WRONLY | *O_CREAT | *O_TRUNC);
110
    let fd = openOpts(path, flags, 420); // 0644 in octal.
111
    if fd < 0 {
112
        return false;
113
    }
114
    let mut written: u32 = 0;
115
    while written < data.len {
116
        let chunk = &data[written..];
117
        let n = write(fd, chunk);
118
        if n <= 0 {
119
            close(fd);
120
            return false;
121
        }
122
        written += n as u32;
123
    }
124
    close(fd);
125
126
    return true;
127
}