Repository navigation
Expand file tree
/
Copy pathfs.oak
More file actions
166 lines (148 loc) · 4.1 KB
/
Copy pathfs.oak
File metadata and controls
166 lines (148 loc) · 4.1 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
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
// libfs offers ergonomic filesystem APIs to Oak programs.
//
// It wraps the basic built-in filesystem functions to provide more ergonomic,
// safer, and efficient implementations of basic filesystem tasks like reading
// files and walking a directory tree.
//
// Most functions in libfs are implemented in both synchronous and asynchronous
// variants. Sync variants of functions block, and return the value
// immediately for ease of use. For better performance, we can pass a callback
// to the function to invoke its asynchronous variant. In that case, the
// function will not block; instead, the callback will be called some time
// later with the return value.
// ReadBufSize is the size of the buffer used to read a file in streaming
// file-read operations in libfs. This may be changed to alter the behavior of
// libfs, but it will affect the behavior of libfs globally in your program.
ReadBufSize := 4096
fn readFileSync(path) {
evt := open(path, :readonly)
if evt.type {
:error -> ?
_ -> {
fd := evt.fd
fn sub(file, offset) {
evt := read(fd, offset, ReadBufSize)
if evt.type {
:error -> {
close(fd)
?
}
_ -> if len(evt.data) {
ReadBufSize -> sub(
file << evt.data
offset + ReadBufSize
)
_ -> {
close(fd)
file << evt.data
}
}
}
}
sub('', 0)
}
}
}
fn readFileAsync(path, withFile) with open(path, :readonly) fn(evt) if evt.type {
:error -> withFile(?)
_ -> {
fd := evt.fd
fn sub(file, offset) with read(fd, offset, ReadBufSize) fn(evt) if evt.type {
:error -> with close(fd) fn {
withFile(?)
}
_ -> if len(evt.data) {
ReadBufSize -> sub(
file << evt.data
offset + ReadBufSize
)
_ -> with close(fd) fn {
withFile(file << evt.data)
}
}
}
sub('', 0)
}
}
// readFile reads the entire contents of a file at `path` and returns the file
// contents as a string if successful, or ? on error.
fn readFile(path, withFile) if withFile {
? -> readFileSync(path)
_ -> readFileAsync(path, withFile)
}
fn writeFileSyncWithFlag(path, file, flag) {
evt := open(path, flag)
if evt.type {
:error -> ?
_ -> {
fd := evt.fd
{
evt := write(fd, 0, file)
close(fd)
if evt.type {
:error -> ?
_ -> true
}
}
}
}
}
fn writeFileAsyncWithFlag(path, file, flag, withEnd) with open(path, flag) fn(evt) if evt.type {
:error -> withEnd(?)
_ -> with write(fd := evt.fd, 0, file) fn(evt) if evt.type {
:error -> with close(fd) fn {
withEnd(?)
}
_ -> with close(fd) fn {
withEnd(true)
}
}
}
// writeFile writes all data in `file` to a file at `path`, and returns true on
// success and ? on error. If the file does not exist, it will be created. If
// it exists, it will be truncated.
fn writeFile(path, file, withEnd) if withEnd {
? -> writeFileSyncWithFlag(path, file, :truncate)
_ -> writeFileAsyncWithFlag(path, file, :truncate, withEnd)
}
// appendFile appends all data in `file` to the end of the file at `path`, and
// returns true on success and ? on error. If the file does not exist, it will
// be created.
fn appendFile(path, file, withEnd) if withEnd {
? -> writeFileSyncWithFlag(path, file, :append)
_ -> writeFileAsyncWithFlag(path, file, :append, withEnd)
}
fn statFileSync(path) {
evt := stat(path)
if evt.type {
:error -> ?
_ -> evt.data
}
}
fn statFileAsync(path, withStat) with stat(path) fn(evt) if evt.type {
:error -> withStat(?)
_ -> withStat(evt.data)
}
// statFile returns the result of stat() if successful, and ? otherwise.
fn statFile(path, withStat) if withStat {
? -> statFileSync(path)
_ -> statFileAsync(path, withStat)
}
fn listFilesSync(path) {
evt := ls(path)
if evt.type {
:error -> ?
_ -> evt.data
}
}
fn listFilesAsync(path, withFiles) with ls(path) fn(evt) if evt.type {
:error -> withFiles(?)
_ -> withFiles(evt.data)
}
// listFiles returns a list of files and directories in a directory at `path`.
// If the directory does not exist or is not a directory, or if the read
// failed, it returns ?.
fn listFiles(path, withFiles) if withFiles {
? -> listFilesSync(path)
_ -> listFilesAsync(path, withFiles)
}