Repository navigation
Expand file tree
/
Copy pathmodule.ae
More file actions
142 lines (131 loc) · 4.79 KB
/
Copy pathmodule.ae
File metadata and controls
142 lines (131 loc) · 4.79 KB
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
// std.file - File Operations (alias for std.fs)
//
// This is a convenience module that re-exports file functions from std.fs.
// The implementations are in std/fs/aether_fs.c.
//
// API shape:
// - Raw externs end in `_raw` and return ptr/int in the old C-style
// convention. Use them only for low-level access.
// - Aether-native wrappers (below) use Go-style `(value, err)` tuple
// returns and are the idiomatic way to call file operations.
exports(
file_open_raw, file_close_raw, file_read_all_raw, file_write_raw,
file_exists, file_delete_raw, file_size_raw, file_fd_raw,
open, close, read_all, read, write, delete, size, fd
)
// Raw ptr/int externs (escape hatch).
extern file_open_raw(path: string, mode: string) -> ptr
extern file_close_raw(file: ptr) -> int
extern file_read_all_raw(file: ptr) -> string @heap
extern file_write_raw(file: ptr, data: string, length: int) -> int
extern file_exists(path: string) -> int
extern file_delete_raw(path: string) -> int
// Size in bytes, as `long` (#1021): the old int surface wrapped files
// >= 2 GiB to a negative value. Returns -1 on stat failure.
extern file_size_raw(path: string) -> long
extern file_fd_raw(file: ptr) -> int
// string_concat used to duplicate borrowed strings across free boundaries.
extern string_concat(a: string, b: string) -> string @heap
extern string_length(str: string) -> int
extern fs_error_message(path: string, fallback: string) -> string
// Open a file. Returns (handle, "") on success, (null, error) on failure.
open(path: string, mode: string) -> {
handle = file_open_raw(path, mode)
if handle == null {
return null, "cannot open file"
}
return handle, ""
}
// Close a handle `open` gave, and free it. Returns "" on success, or the
// reason: a write the close flushes can fail, and the data is then not on
// disk (#3179).
close(handle: ptr) -> string {
if handle == null {
return "null handle"
}
if file_close_raw(handle) < 0 {
return "close failed: buffered data was not written"
}
return ""
}
// Read the whole of an open handle, from its start. Returns (text, "") on
// success, ("", error) on failure; the handle stays open (#3179).
read_all(handle: ptr) -> {
if handle == null {
return "", "null handle"
}
text = file_read_all_raw(handle)
if text == null {
return "", "read failed"
}
return text, ""
}
// Read the entire contents of a file at `path`. Opens, reads, closes.
// Returns (content, "") on success, ("", error) on failure.
// This is the convenience form most callers want.
read(path: string) -> {
handle = file_open_raw(path, "r")
if handle == 0 {
return "", "cannot open file"
}
content = file_read_all_raw(handle)
if content == 0 {
file_close_raw(handle)
return "", "cannot read file"
}
content_copy = string_concat(content, "")
file_close_raw(handle)
return content_copy, ""
}
// Write `content` to a file at `path`. Opens in write mode, writes, closes.
// Returns "" on success, error string on failure.
write(path: string, content: string) -> {
handle = file_open_raw(path, "w")
if handle == 0 {
return fs_error_message(path, "cannot open file for writing")
}
length = string_length(content)
ok = file_write_raw(handle, content, length)
if ok == 0 {
err = fs_error_message(path, "write failed")
file_close_raw(handle)
return err
}
closed = file_close_raw(handle)
if closed < 0 {
return fs_error_message(path, "close failed: buffered data was not written")
}
return ""
}
// Delete the file at `path`. Returns "" on success, error on failure.
delete(path: string) -> {
ok = file_delete_raw(path)
if ok == 0 {
return "cannot delete file"
}
return ""
}
// Return the size of the file at `path` in bytes, as `long` (#1021 —
// files >= 2 GiB used to wrap negative through the old int surface).
// Returns (size, "") on success, (0, error) on failure.
//
// The success arm returns FIRST: the first `return` statement pins the
// inferred tuple slot types, so the `long`-typed arm must come before
// the int-literal error arm or the size slot narrows back to int.
size(path: string) -> {
s = file_size_raw(path)
if s >= 0 {
return s, ""
}
return 0, "cannot stat file"
}
// The OS-level file descriptor inside an open handle, or -1 on a
// null handle (#1003). Exists for capability plumbing: open through
// the stdlib, then narrow the descriptor with
// capsicum.rights_limit(file.fd(handle), ...) before capsicum.enter().
// The fd is owned by the handle — do not close it directly; it is
// released by close, which also frees the handle itself, so
// never call fd() on a handle that has been closed.
fd(handle: ptr) -> int {
return file_fd_raw(handle)
}