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