Landin library reference source

platform/libc/libc.ldn

1--  The C library, declared as ordinary extern(c) imports, raw: the
2--  system's own interface on Darwin and FreeBSD, and C's on Linux.  On
3--  Darwin and FreeBSD, whose C library is their system interface,
4--  platform/posix reaches the operating system only through these
5--  declarations; on Linux it makes platform/linux's system calls, and this
6--  module serves a program linked with --link=libc.  Its scope is the
7--  systems with a C library, Linux, Darwin and FreeBSD.  Every declaration
8--  here is bodyless, so a program that names none of them needs no C
9--  library, and a static Linux program that names one is refused before it
10--  links (D280).  Facts that differ between systems are selected by
11--  `compiler.os`, record layouts by the C ABI as well, and the native C
12--  headers of each system check them: the `stat` record in
13--  abi/core-io-file-identity, the rest in the hosted runtime and ABI
14--  fixtures.
15
16compiler.assert(compiler.os == linux or compiler.os == darwin
17                or compiler.os == freebsd)
18
19--- Open the file at the NUL-terminated `path` and return its descriptor, or
20--- -1 with the reason in errno.  `flags` is `o_rdonly` or `o_wronly`, or'd
21--- with `o_creat` and `o_trunc`; with `o_creat` the one variadic argument
22--- is the new file's permission bits as an `i32`, which the process umask
23--- filters.
24public extern(c) open: (path: ptr u8, flags: i32, ...) -> (descriptor: i32)
25
26--- Read at most `length` bytes from `descriptor` into `data`.  The count
27--- read, zero at end of file, or -1 with the reason in errno.  EINTR means
28--- nothing was transferred.
29public extern(c) read: (descriptor: i32, data: ptr mut u8, length: usize)
30                       -> (count: isize)
31
32--- Write at most `length` bytes from `data` to `descriptor`.  The count
33--- accepted, which may be short, or -1 with the reason in errno.  EINTR
34--- means nothing was transferred.
35public extern(c) write: (descriptor: i32, data: ptr u8, length: usize)
36                        -> (count: isize)
37
38--- Open `path`, relative to the directory open as `directory` (or
39--- `at_fdcwd`), as `open` does: the new descriptor, or -1 with the reason
40--- in errno.  With `o_creat` the one variadic argument is the permission
41--- bits as an `i32`.
42public extern(c) openat: (directory: i32, path: ptr u8, flags: i32, ...)
43                         -> (descriptor: i32)
44
45--- Close `descriptor`: 0, or -1 with the reason in errno.  The descriptor
46--- may be released even when this fails, so a failed close is never
47--- retried.
48public extern(c) close: (descriptor: i32) -> (status: i32)
49
50--- The number of bytes before the first NUL at `text`.
51public extern(c) strlen: (text: ptr u8) -> (length: usize)
52
53--- What `malloc` returns when it cannot allocate: C's null pointer.
54public no_allocation: atom
55
56--- A `malloc` result: a block, or `no_allocation`.
57public allocation: type = no_allocation | ptr mut u8
58
59--- Allocate `size` bytes aligned for any C object, or `no_allocation`.
60--- `malloc(0)` may return either; a caller that needs a distinct block for
61--- an empty request asks for a nonzero size.
62public extern(c) malloc: (size: usize) -> (block: allocation)
63
64--- Give a block from `malloc` back to the C library.
65public extern(c) free: (block: ptr mut u8) -> none
66
67fixed if compiler.os == linux then
68    --- The calling thread's errno cell, `__errno_location` on Linux and
69    --- `__error` on Darwin and FreeBSD.  Read it immediately after the
70    --- failing call, before any other call that may set it.
71    public extern(c) link(symbol: "__errno_location") errno_cell:
72        () -> (cell: ptr mut i32)
73else
74    --- The calling thread's errno cell, `__errno_location` on Linux and
75    --- `__error` on Darwin and FreeBSD.  Read it immediately after the
76    --- failing call, before any other call that may set it.
77    public extern(c) link(symbol: "__error") errno_cell:
78        () -> (cell: ptr mut i32)
79end if
80
81--- errno: the operation is not permitted.  The same on every hosted
82--- system.
83public eperm: i32 = 1
84--- errno: no such file or directory.
85public enoent: i32 = 2
86--- errno: interrupted by a signal before anything was transferred.
87public eintr: i32 = 4
88--- errno: permission denied.
89public eacces: i32 = 13
90--- errno: a path component is not a directory.
91public enotdir: i32 = 20
92--- errno: the file system is read-only.
93public erofs: i32 = 30
94
95--- `open` flag: read only.  The same on every hosted system.
96public o_rdonly: i32 = 0
97--- `open` flag: write only.  The same on every hosted system.
98public o_wronly: i32 = 1
99--- `open` flag: read and write.  The same on every hosted system.
100public o_rdwr: i32 = 2
101
102fixed if compiler.os == linux then
103    --- `open` flag: create the file if it does not exist.  Linux keeps one
104    --- value on every architecture; Darwin and FreeBSD share the BSD one.
105    public o_creat: i32 = 64
106    --- `open` flag: truncate an existing regular file to length zero.
107    public o_trunc: i32 = 512
108    --- `open` flag: with `o_creat`, fail with EEXIST if the name is taken.
109    public o_excl: i32 = 128
110    --- `open` flag: every write goes to the end of the file.
111    public o_append: i32 = 1024
112    --- `mmap` flag: the mapping is backed by no file and starts zeroed.
113    public map_anonymous: i32 = 32
114    --- `poll`'s count of records, C's `nfds_t`.
115    public poll_count: type = u64
116else
117    --- `open` flag: create the file if it does not exist.  Linux keeps one
118    --- value on every architecture; Darwin and FreeBSD share the BSD one.
119    public o_creat: i32 = 512
120    --- `open` flag: truncate an existing regular file to length zero.
121    public o_trunc: i32 = 1024
122    --- `open` flag: with `o_creat`, fail with EEXIST if the name is taken.
123    public o_excl: i32 = 2048
124    --- `open` flag: every write goes to the end of the file.
125    public o_append: i32 = 8
126    --- `mmap` flag: the mapping is backed by no file and starts zeroed.
127    public map_anonymous: i32 = 4096
128    --- `poll`'s count of records, C's `nfds_t`.
129    public poll_count: type = u32
130end if
131
132--- `mmap` protection: the pages may be read.  The same on every hosted
133--- system.
134public prot_read: i32 = 1
135--- `mmap` protection: the pages may be written.
136public prot_write: i32 = 2
137--- `mmap` flag: the mapping is private to this process.
138public map_private: i32 = 2
139
140--- Map `length` bytes, at a place of the system's choosing when `address`
141--- is zero: the mapping's address, or `map_failed` with the reason in
142--- errno.  With `map_anonymous` the descriptor is -1 and the offset zero.
143public extern(c) mmap: (address: usize, length: usize, protection: i32,
144                        flags: i32, descriptor: i32, offset: i64)
145                       -> (result: usize)
146
147--- What `mmap` returns when it fails: C's `MAP_FAILED`, all bits set.
148public map_failed: usize = 0 -% 1
149
150--- Unmap the `length` bytes at `address`: 0, or -1 with the reason in
151--- errno.
152public extern(c) munmap: (address: usize, length: usize) -> (status: i32)
153
154--- The size of a page in bytes, 16 KiB on Darwin arm64 and 4 KiB on the
155--- others.
156public extern(c) getpagesize: () -> (bytes: i32)
157
158--- End the process with `status` at once: no `atexit` handler runs and no
159--- C stream is flushed.
160public extern(c) _exit: (status: i32) -> noreturn
161
162--- One record `poll` reads and fills, C's `struct pollfd`: the descriptor
163--- to watch, the events asked about and the events that happened.  A
164--- negative descriptor is ignored.  The same on every hosted system.
165public poll_record: type = struct
166    descriptor: i32
167    events: i16
168    returned: i16
169end poll_record
170
171--- Wait until one of the `count` records at `records` has an event, or
172--- `timeout` milliseconds pass, waiting indefinitely when it is negative:
173--- the number of records with an event, zero when the time passed first,
174--- or -1 with the reason in errno.
175public extern(c) poll: (records: ptr mut poll_record, count: poll_count,
176                        timeout: i32) -> (result: i32)
177
178--- C's `struct timespec`: whole seconds and the nanoseconds after them.
179public timespec: type = struct
180    seconds: i64
181    nanoseconds: i64
182end timespec
183
184--  Full records rather than guessed opaque storage, selected by hosted
185--  system and C ABI.  Darwin arm64 uses the ordinary stat symbol with its
186--  64-bit inode ABI.
187
188fixed if compiler.os == freebsd then
189    --- `sizeof (struct stat)` in the native C headers.
190    public file_status_size: usize = 224
191    --- C's `struct stat`, as `stat` fills it on this system.
192    public file_status: type = struct
193        device: u64
194        inode: u64
195        links: u64
196        mode: u16
197        bsdflags: i16
198        uid: u32
199        gid: u32
200        padding: i32
201        special_device: u64
202        accessed: timespec
203        modified: timespec
204        changed: timespec
205        born: timespec
206        bytes: i64
207        blocks: i64
208        block_size: i32
209        flags: u32
210        generation: u64
211        revision: u64
212        spare: [9]u64
213    end file_status
214elsif compiler.c_sysv_lp64 then
215    --- `sizeof (struct stat)` in the native C headers.
216    public file_status_size: usize = 144
217    --- C's `struct stat`, as `stat` fills it on this system.
218    public file_status: type = struct
219        device: u64
220        inode: u64
221        links: u64
222        mode: u32
223        uid: u32
224        gid: u32
225        padding: i32
226        special_device: u64
227        bytes: i64
228        block_size: i64
229        blocks: i64
230        accessed: timespec
231        modified: timespec
232        changed: timespec
233        reserved: [3]i64
234    end file_status
235elsif compiler.c_aapcs64_lp64 or compiler.c_riscv_lp64d then
236    --- `sizeof (struct stat)` in the native C headers.
237    public file_status_size: usize = 128
238    --- C's `struct stat`, as `stat` fills it on this system.
239    public file_status: type = struct
240        device: u64
241        inode: u64
242        mode: u32
243        links: u32
244        uid: u32
245        gid: u32
246        special_device: u64
247        padding1: u64
248        bytes: i64
249        block_size: i32
250        padding2: i32
251        blocks: i64
252        accessed: timespec
253        modified: timespec
254        changed: timespec
255        reserved: [2]u32
256    end file_status
257else
258    --- `sizeof (struct stat)` in the native C headers.
259    public file_status_size: usize = 144
260    --- C's `struct stat`, as `stat` fills it on this system. C declares
261    --- `dev_t` as `int32_t` here, but a device number is a bit pattern, not
262    --- a quantity, and devfs's may have the sign bit set, so both device
263    --- fields are unsigned and widening them never traps.
264    public file_status: type = struct
265        device: u32
266        mode: u16
267        links: u16
268        inode: u64
269        uid: u32
270        gid: u32
271        special_device: u32
272        accessed: timespec
273        modified: timespec
274        changed: timespec
275        created: timespec
276        bytes: i64
277        blocks: i64
278        block_size: i32
279        flags: u32
280        generation: u32
281        spare: i32
282        reserved: [2]i64
283    end file_status
284end if
285
286--- Fill `result` with the status of the file `path` names, following
287--- symbolic links: 0, or -1 with the reason in errno.
288public extern(c) stat: (path: ptr u8, result: ptr mut file_status)
289                       -> (status: i32)
290
291--- Fill `result` with the status of `path`, relative to the directory
292--- open as `directory`: 0, or -1 with the reason in errno.  With
293--- `at_symlink_nofollow` in `flags` a symbolic link is reported itself.
294public extern(c) fstatat: (directory: i32, path: ptr u8,
295                           result: ptr mut file_status, flags: i32)
296                          -> (status: i32)
297
298--- errno: the name already exists.  The same on every hosted system.
299public eexist: i32 = 17
300
301--- A `struct dirent`'s `d_type`: the entry's type is not known, and a
302--- status call relative to the directory tells it.  The values are the
303--- same on every hosted system.
304public dt_unknown: u8 = 0
305--- `d_type`: a directory.
306public dt_dir: u8 = 4
307--- `d_type`: a regular file.
308public dt_reg: u8 = 8
309--- `d_type`: a symbolic link.
310public dt_lnk: u8 = 10
311
312--- A `stat` mode's file-type bits, and the types among them.  The same on
313--- every hosted system.
314public s_ifmt: u32 = 0o170000
315--- `stat` mode: a directory.
316public s_ifdir: u32 = 0o040000
317--- `stat` mode: a regular file.
318public s_ifreg: u32 = 0o100000
319--- `stat` mode: a symbolic link.
320public s_iflnk: u32 = 0o120000
321
322fixed if compiler.os == linux then
323    fixed if compiler.arch == arm64 then
324        --- `open` flag: fail with ENOTDIR unless the path names a
325        --- directory.  Linux's arm64 keeps a value of its own.
326        public o_directory: i32 = 16384
327    else
328        --- `open` flag: fail with ENOTDIR unless the path names a
329        --- directory.  Linux's arm64 keeps a value of its own.
330        public o_directory: i32 = 65536
331    end if
332    --- `fstatat` flag: report a symbolic link itself.
333    public at_symlink_nofollow: i32 = 256
334
335    --- C's `struct dirent` as `readdir` returns it.  glibc gives no name
336    --- length: the name ends at its NUL.
337    public directory_record: type = struct
338        inode: u64
339        offset: i64
340        record_length: u16
341        kind: u8
342        name: [256]u8
343    end directory_record
344
345    --- The directory descriptor that makes an `*at` call's relative path
346    --- relative to the working directory.
347    public at_fdcwd: i32 = -100
348    --- `unlinkat` flag: remove an empty directory rather than a file.
349    public at_removedir: i32 = 512
350
351    --- Make the directory `path`, relative to `directory` (or `at_fdcwd`),
352    --- with the permission bits `mode`, which the process umask filters:
353    --- 0, or -1 with the reason in errno.
354    public extern(c) mkdirat: (directory: i32, path: ptr u8, mode: u32)
355                              -> (status: i32)
356elsif compiler.os == darwin then
357    --- `open` flag: fail with ENOTDIR unless the path names a directory.
358    --- Linux's arm64 keeps a value of its own.
359    public o_directory: i32 = 1048576
360    --- `fstatat` flag: report a symbolic link itself.
361    public at_symlink_nofollow: i32 = 32
362
363    --- C's `struct dirent` as `readdir` returns it, with the 64-bit
364    --- inode every arm64 Darwin has.
365    public directory_record: type = struct
366        inode: u64
367        seek_offset: u64
368        record_length: u16
369        name_length: u16
370        kind: u8
371        name: [1024]u8
372    end directory_record
373
374    --- The directory descriptor that makes an `*at` call's relative path
375    --- relative to the working directory.
376    public at_fdcwd: i32 = -2
377    --- `unlinkat` flag: remove an empty directory rather than a file.
378    public at_removedir: i32 = 128
379
380    --- Make the directory `path`, relative to `directory` (or `at_fdcwd`),
381    --- with the permission bits `mode`, which the process umask filters:
382    --- 0, or -1 with the reason in errno.
383    public extern(c) mkdirat: (directory: i32, path: ptr u8, mode: u16)
384                              -> (status: i32)
385else
386    --- `open` flag: fail with ENOTDIR unless the path names a directory.
387    --- Linux's arm64 keeps a value of its own.
388    public o_directory: i32 = 131072
389    --- `fstatat` flag: report a symbolic link itself.
390    public at_symlink_nofollow: i32 = 512
391
392    --- C's `struct dirent` as `readdir` returns it, in the layout
393    --- FreeBSD 12 gave it with 64-bit inodes.
394    public directory_record: type = struct
395        inode: u64
396        offset: i64
397        record_length: u16
398        kind: u8
399        padding0: u8
400        name_length: u16
401        padding1: u16
402        name: [256]u8
403    end directory_record
404
405    --- The directory descriptor that makes an `*at` call's relative path
406    --- relative to the working directory.
407    public at_fdcwd: i32 = -100
408    --- `unlinkat` flag: remove an empty directory rather than a file.
409    public at_removedir: i32 = 2048
410
411    --- Make the directory `path`, relative to `directory` (or `at_fdcwd`),
412    --- with the permission bits `mode`, which the process umask filters:
413    --- 0, or -1 with the reason in errno.
414    public extern(c) mkdirat: (directory: i32, path: ptr u8, mode: u16)
415                              -> (status: i32)
416end if
417
418--- What `fdopendir` gives when it cannot open a directory stream, and
419--- `readdir` at the end or on a failure: C's null pointer.
420public no_directory: atom
421
422--- An `fdopendir` result: a directory stream, `DIR *`, or `no_directory`.
423public directory_stream: type = no_directory | ptr mut u8
424
425--- A `readdir` result: the next record, or `no_directory`.
426public directory_entry: type = no_directory | ptr directory_record
427
428--- A directory stream over the directory open as `descriptor`, which the
429--- stream then owns and `closedir` closes, or `no_directory` with the
430--- reason in errno.
431public extern(c) fdopendir: (descriptor: i32) -> (stream: directory_stream)
432
433--- The stream's next record, good until the next `readdir` or `closedir`
434--- on it, or `no_directory` at the end and on a failure, which errno tells
435--- apart when the caller zeroed it first.  Records include `.` and `..`.
436public extern(c) readdir: (stream: ptr mut u8) -> (record: directory_entry)
437
438--- Close a directory stream and its descriptor: 0, or -1 with the reason
439--- in errno.  The stream is released either way.
440public extern(c) closedir: (stream: ptr mut u8) -> (status: i32)
441
442--- Remove the name `path`, relative to `directory` (or `at_fdcwd`): a
443--- file with `flags` zero, an empty directory with `at_removedir`.  0, or
444--- -1 with the reason in errno.
445public extern(c) unlinkat: (directory: i32, path: ptr u8, flags: i32)
446                           -> (status: i32)