projects/linux·blob 542fed2e · refs

115 lines · 2.0 KiB

1/* SPDX-License-Identifier: LGPL-2.1 OR MIT */
2/*
3 * Directory access for NOLIBC
4 * Copyright (C) 2025 Thomas Weißschuh <[email protected]>
5 */
6
7/* make sure to include all global symbols */
8#include "nolibc.h"
9
10#ifndef _NOLIBC_DIRENT_H
11#define _NOLIBC_DIRENT_H
12
13#include "compiler.h"
14#include "stdint.h"
15#include "types.h"
16#include "fcntl.h"
17
18#include <linux/limits.h>
19
20struct dirent {
21 ino_t d_ino;
22 char d_name[NAME_MAX + 1];
23};
24
25/* See comment of FILE in stdio.h */
26typedef struct {
27 char dummy[1];
28} DIR;
29
30static __attribute__((unused))
31DIR *fdopendir(int fd)
32{
33 struct stat buf;
34 int ret;
35
36 if (fd < 0) {
37 SET_ERRNO(EBADF);
38 return NULL;
39 }
40
41 ret = fstat(fd, &buf);
42 if (ret < 0)
43 return NULL;
44
45 if (!S_ISDIR(buf.st_mode)) {
46 SET_ERRNO(ENOTDIR);
47 return NULL;
48 }
49
50 return (DIR *)(intptr_t)~fd;
51}
52
53static __attribute__((unused))
54DIR *opendir(const char *name)
55{
56 int fd;
57
58 fd = open(name, O_RDONLY | O_DIRECTORY);
59 if (fd == -1)
60 return NULL;
61
62 return (DIR *)(intptr_t)~fd;
63}
64
65static __attribute__((unused))
66int closedir(DIR *dirp)
67{
68 intptr_t i = (intptr_t)dirp;
69
70 if (i >= 0) {
71 SET_ERRNO(EBADF);
72 return -1;
73 }
74 return close(~i);
75}
76
77static __attribute__((unused))
78int readdir_r(DIR *dirp, struct dirent *entry, struct dirent **result)
79{
80 char buf[sizeof(struct linux_dirent64) + NAME_MAX + 1] __nolibc_aligned_as(struct linux_dirent64);
81 struct linux_dirent64 *ldir = (void *)buf;
82 intptr_t i = (intptr_t)dirp;
83 int fd, ret;
84 off_t off;
85
86 if (i >= 0)
87 return EBADF;
88
89 fd = ~i;
90
91 ret = _sys_getdents64(fd, ldir, sizeof(buf));
92 if (ret < 0)
93 return -ret;
94 if (ret == 0) {
95 *result = NULL;
96 return 0;
97 }
98
99 /*
100 * getdents64() returns as many entries as fit the buffer.
101 * readdir() can only return one entry at a time.
102 * Make sure the non-returned ones are not skipped.
103 */
104 off = _sys_lseek(fd, ldir->d_off, SEEK_SET);
105 if (off < 0)
106 return -off;
107
108 entry->d_ino = ldir->d_ino;
109 /* the destination should always be big enough */
110 strlcpy(entry->d_name, ldir->d_name, sizeof(entry->d_name));
111 *result = entry;
112 return 0;
113}
114
115#endif /* _NOLIBC_DIRENT_H */