Landin library reference source

compiler/tests/fixtures/runtime/posix-files/main.ldn

1--  platform/posix's files: a descriptor is a handle, a failure is the
2--  errno as an atom, and a path is a host string, terminated beneath the
3--  caller.  The program makes a scratch directory, opens a file in it
4--  relative to the directory's own descriptor, writes and reads it back,
5--  asks its status, and removes both.  Each failure is the errno POSIX
6--  names for it, the same atom on Linux, Darwin and FreeBSD: a missing
7--  name, an exclusive create of a taken one, a file used as a directory, a
8--  directory opened for writing, a closed descriptor, a path holding a NUL
9--  and one longer than PATH_MAX.  The program writes each atom's number
10--  on this system, so a failing lane shows what it met.
11import core/text
12import platform/posix
13
14top: []u8 = "posix-files-scratch"
15inner: []u8 = "posix-files-scratch/data"
16
17--  Write LINE to standard output.
18say: (line: []u8) -> none =
19    _ = posix.write(posix.standard_output, line) else 0
20end say
21
22--  Write NAME, `=` and the number PROBLEM has on this system.
23said: (name: []u8, problem: posix.errno) -> none =
24    mut line: [32]u8 = zeroed
25    mut used: usize = 0
26    for byte in name do
27        line[used] = byte
28        inc used
29    end for
30    line[used] = 61
31    inc used
32    used = text.write_u32(line[0..<32], used,
33                          u32(posix.number(problem))) else used
34    line[used] = 10
35    say(line[0..<used + 1])
36end said
37
38--  Remove what an earlier run may have left.
39clear: () -> none =
40    posix.unlink_at(posix.working_directory, text.host_over(inner)) else (p)
41        _ = p
42    end
43    posix.remove_directory_at(posix.working_directory,
44                              text.host_over(top)) else (p)
45        _ = p
46    end
47end clear
48
49--  Whether opening PATH with OPTIONS, relative to AT, fails with WANTED.
50refused: (at: posix.descriptor, path: text.host_string,
51          options: posix.open_options, wanted: posix.errno, name: []u8)
52         -> (yes: bool) =
53    yes = false
54    opened: posix.descriptor = posix.open_at(at, path, options, 0o644)
55      else (problem)
56        said(name, problem)
57        yes = problem == wanted
58        return
59    end
60    posix.close(opened) else (p)
61        _ = p
62    end
63end refused
64
65public main: () -> (code: i32) =
66    clear()
67    code = 1
68    posix.make_directory_at(posix.working_directory, text.host_over(top),
69                            0o755) else (problem)
70        said("mkdir", problem)
71        return
72    end
73    code = 2
74    folder: posix.descriptor =
75        posix.open_at(posix.working_directory, text.host_over(top),
76                      (access: posix.read_only, create: false,
77                       exclusive: false, truncate: false, append: false,
78                       directory: true), 0) else (problem)
79        said("folder", problem)
80        return
81    end
82
83    --  A file made relative to the directory's descriptor, written and
84    --  read back through a second descriptor.
85    code = 3
86    written: posix.descriptor =
87        posix.open_at(folder, text.host_over("data"), posix.writing,
88                      0o644) else (problem)
89        said("create", problem)
90        return
91    end
92    count: usize = posix.write(written, "posix\n") else (problem)
93        said("write", problem)
94        return
95    end
96    return when count <> 6
97    posix.close(written) else (problem)
98        said("close", problem)
99        return
100    end
101    code = 4
102    reading: posix.descriptor =
103        posix.open_at(posix.working_directory, text.host_over(inner),
104                      posix.reading, 0) else (problem)
105        said("open", problem)
106        return
107    end
108    mut buffer: [16]u8 = zeroed
109    got: usize = posix.read(reading, buffer[0..<16]) else (problem)
110        said("read", problem)
111        return
112    end
113    return when got <> 6 or buffer[0] <> 112 or buffer[5] <> 10
114    ended: usize = posix.read(reading, buffer[0..<16]) else (problem)
115        said("eof", problem)
116        return
117    end
118    return when ended <> 0
119    posix.close(reading) else (problem)
120        said("close", problem)
121        return
122    end
123
124    --  Its status: a regular file of six bytes, the same file by either
125    --  path, inside a directory.
126    code = 5
127    file: posix.status =
128        posix.status_at(folder, text.host_over("data"), false) else (problem)
129        said("stat", problem)
130        return
131    end
132    again: posix.status =
133        posix.status_at(posix.working_directory, text.host_over(inner),
134                        true) else (problem)
135        said("stat", problem)
136        return
137    end
138    holder: posix.status =
139        posix.status_at(posix.working_directory, text.host_over(top),
140                        true) else (problem)
141        said("stat", problem)
142        return
143    end
144    return when file.kind <> posix.regular or file.size <> 6
145      or file.device <> again.device or file.inode <> again.inode
146      or holder.kind <> posix.directory or holder.inode == file.inode
147
148    --  The failure oracles.
149    code = 6
150    return when not refused(folder, text.host_over("absent"), posix.reading,
151                            posix.enoent, "absent")
152    code = 7
153    return when not refused(folder, text.host_over("data"),
154                            (access: posix.write_only, create: true,
155                             exclusive: true, truncate: false,
156                             append: false, directory: false),
157                            posix.eexist, "exclusive")
158    code = 8
159    return when not refused(folder, text.host_over("data/below"),
160                            posix.reading, posix.enotdir, "through")
161    code = 9
162    return when not refused(posix.working_directory, text.host_over(top),
163                            posix.writing, posix.eisdir, "directory")
164    code = 10
165    return when not refused(posix.working_directory,
166                            text.host_over("posix\x00files"), posix.reading,
167                            posix.einval, "nul")
168    code = 11
169    long: [5000]u8 = [5000 of 97]
170    return when not refused(posix.working_directory,
171                            text.host_over(long[0..<5000]), posix.reading,
172                            posix.enametoolong, "long")
173    code = 12
174    _ = posix.read(reading, buffer[0..<16]) else (problem)
175        said("closed", problem)
176        return when problem <> posix.ebadf
177        0
178    end
179
180    code = 13
181    posix.close(folder) else (problem)
182        said("close", problem)
183        return
184    end
185    posix.unlink_at(posix.working_directory, text.host_over(inner))
186      else (problem)
187        said("unlink", problem)
188        return
189    end
190    posix.remove_directory_at(posix.working_directory, text.host_over(top))
191      else (problem)
192        said("rmdir", problem)
193        return
194    end
195    code = 42
196end main