Skip to content

Commit 0f89140

Browse files
committed
Further improve cocmd interpreter
1 parent 0cee831 commit 0f89140

File tree

14 files changed

+278
-181
lines changed

14 files changed

+278
-181
lines changed

libc/calls/calls.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -129,8 +129,9 @@ int linkat(int, const char *, int, const char *, int);
129129
int madvise(void *, uint64_t, int);
130130
int memfd_create(const char *, unsigned int);
131131
int mincore(void *, size_t, unsigned char *);
132-
int mkdir(const char *, uint32_t);
133-
int mkdirat(int, const char *, uint32_t);
132+
int mkdir(const char *, unsigned);
133+
int mkdirat(int, const char *, unsigned);
134+
int makedirs(const char *, unsigned);
134135
int mkfifo(const char *, uint32_t);
135136
int mkfifoat(int, const char *, uint32_t);
136137
int mknod(const char *, uint32_t, uint64_t);

libc/calls/clock_nanosleep.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,10 +75,10 @@
7575
* @return 0 on success, or errno on error
7676
* @raise EINTR when a signal got delivered while we were waiting
7777
* @raise ENOTSUP if `clock` is known but we can't use it here
78+
* @raise EFAULT if `req` or null or bad memory was passed
7879
* @raise EINVAL if `clock` is unknown to current platform
7980
* @raise EINVAL if `flags` has an unrecognized value
8081
* @raise EINVAL if `req->tv_nsec ∉ [0,1000000000)`
81-
* @raise EFAULT if bad memory was passed
8282
* @raise ENOSYS on bare metal
8383
* @returnserrno
8484
* @norestart

libc/stdio/makedirs.c renamed to libc/calls/makedirs.c

Lines changed: 59 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -17,58 +17,75 @@
1717
│ PERFORMANCE OF THIS SOFTWARE. │
1818
╚─────────────────────────────────────────────────────────────────────────────*/
1919
#include "libc/calls/calls.h"
20+
#include "libc/calls/struct/stat.h"
2021
#include "libc/errno.h"
21-
#include "libc/fmt/conv.h"
22-
#include "libc/mem/mem.h"
22+
#include "libc/str/path.h"
2323
#include "libc/str/str.h"
24-
25-
static char *DirName(const char *path) {
26-
char *dirp;
27-
if (!(path = strdup(path))) return 0;
28-
dirp = strdup(dirname(path));
29-
free(path);
30-
return dirp;
31-
}
32-
33-
static int MakeDirs(const char *path, unsigned mode, int e) {
34-
int rc;
35-
char *dir;
36-
if (!mkdir(path, mode) || errno == EEXIST) {
37-
errno = e;
38-
return 0;
39-
}
40-
if (errno != ENOENT) {
41-
return -1;
42-
}
43-
if (!(dir = DirName(path))) {
44-
return -1;
45-
}
46-
if (strcmp(dir, path)) {
47-
rc = MakeDirs(dir, mode, e);
48-
} else {
49-
rc = -1;
50-
}
51-
free(dir);
52-
if (rc == -1) return -1;
53-
errno = e;
54-
if (!mkdir(path, mode) || errno == EEXIST) {
55-
errno = e;
56-
return 0;
57-
} else {
58-
return -1;
59-
}
60-
}
24+
#include "libc/sysv/consts/s.h"
25+
#include "libc/sysv/errfuns.h"
6126

6227
/**
63-
* Recursively creates directory a.k.a. folder.
28+
* Creates directory and parent components.
6429
*
65-
* This function won't fail if the directory already exists.
30+
* This function is similar to mkdir() except it iteratively creates
31+
* parent directories and it won't fail if the directory already exists.
6632
*
6733
* @param path is a UTF-8 string, preferably relative w/ forward slashes
6834
* @param mode can be, for example, 0755
6935
* @return 0 on success or -1 w/ errno
36+
* @raise EEXIST if named file already exists as non-directory
37+
* @raise ENOTDIR if directory component in `path` existed as non-directory
38+
* @raise ENAMETOOLONG if symlink-resolved `path` length exceeds `PATH_MAX`
39+
* @raise ENAMETOOLONG if component in `path` exists longer than `NAME_MAX`
40+
* @raise EROFS if parent directory is on read-only filesystem
41+
* @raise ENOSPC if file system or parent directory is full
42+
* @raise EACCES if write permission was denied on parent directory
43+
* @raise EACCES if search permission was denied on component in `path`
44+
* @raise ENOENT if `path` is an empty string
45+
* @raise ELOOP if loop was detected resolving components of `path`
46+
* @asyncsignalsafe
7047
* @threadsafe
7148
*/
7249
int makedirs(const char *path, unsigned mode) {
73-
return MakeDirs(path, mode, errno);
50+
int c, e, i, n;
51+
struct stat st;
52+
char buf[PATH_MAX];
53+
54+
e = errno;
55+
n = strlen(path);
56+
if (n >= PATH_MAX) return enametoolong();
57+
memcpy(buf, path, n + 1);
58+
i = n;
59+
60+
// descend
61+
while (i) {
62+
if (!mkdir(buf, mode)) break;
63+
if (errno == EEXIST) {
64+
if (i == n) goto CheckTop;
65+
break;
66+
}
67+
if (errno != ENOENT) return -1;
68+
while (i && _isdirsep(buf[i - 1])) buf[--i] = 0;
69+
while (i && !_isdirsep(buf[i - 1])) buf[--i] = 0;
70+
}
71+
72+
// ascend
73+
for (;;) {
74+
if (mkdir(buf, mode)) {
75+
if (errno != EEXIST) return -1;
76+
if (i == n) goto CheckTop;
77+
}
78+
if (i == n) break;
79+
while (i < n && !_isdirsep((c = path[i]))) buf[i++] = c;
80+
while (i < n && _isdirsep((c = path[i]))) buf[i++] = c;
81+
}
82+
83+
Finish:
84+
errno = e;
85+
return 0;
86+
87+
CheckTop:
88+
if (stat(path, &st)) return -1;
89+
if (S_ISDIR(st.st_mode)) goto Finish;
90+
return eexist();
7491
}

libc/calls/mkdir.c

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,7 @@
1717
│ PERFORMANCE OF THIS SOFTWARE. │
1818
╚─────────────────────────────────────────────────────────────────────────────*/
1919
#include "libc/calls/calls.h"
20-
#include "libc/dce.h"
21-
#include "libc/nt/files.h"
22-
#include "libc/nt/runtime.h"
23-
#include "libc/str/str.h"
2420
#include "libc/sysv/consts/at.h"
25-
#include "libc/sysv/errfuns.h"
2621

2722
/**
2823
* Creates directory a.k.a. folder.
@@ -36,9 +31,21 @@
3631
* @param path is a UTF-8 string, preferably relative w/ forward slashes
3732
* @param mode can be, for example, 0755
3833
* @return 0 on success or -1 w/ errno
39-
* @error ENAMETOOLONG if >246 characters on NT
34+
* @raise EEXIST if named file already exists
35+
* @raise ENOTDIR if directory component in `path` existed as non-directory
36+
* @raise ENAMETOOLONG if symlink-resolved `path` length exceeds `PATH_MAX`
37+
* @raise ENAMETOOLONG if component in `path` exists longer than `NAME_MAX`
38+
* @raise EROFS if parent directory is on read-only filesystem
39+
* @raise ENOSPC if file system or parent directory is full
40+
* @raise EACCES if write permission was denied on parent directory
41+
* @raise EACCES if search permission was denied on component in `path`
42+
* @raise ENOENT if a component within `path` didn't exist
43+
* @raise ENOENT if `path` is an empty string
44+
* @raise ELOOP if loop was detected resolving components of `path`
45+
* @see makedirs() which is higher-level
46+
* @see mkdirat() for modern call
4047
* @asyncsignalsafe
41-
* @see makedirs()
48+
* @threadsafe
4249
*/
4350
int mkdir(const char *path, unsigned mode) {
4451
return mkdirat(AT_FDCWD, path, mode);

libc/calls/mkdirat.c

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,12 +31,23 @@
3131
/**
3232
* Creates directory a.k.a. folder.
3333
*
34-
* @param dirfd is normally AT_FDCWD but if it's an open directory and
34+
* @param dirfd is normally `AT_FDCWD` but if it's an open directory and
3535
* path is relative, then path becomes relative to dirfd
3636
* @param path is a UTF-8 string, preferably relative w/ forward slashes
37-
* @param mode can be, for example, 0755
38-
* @return 0 on success or -1 w/ errno
39-
* @error EEXIST, ENOTDIR, ENAMETOOLONG, EACCES, ENOENT
37+
* @param mode is permissions bits, which is usually 0755
38+
* @return 0 on success, or -1 w/ errno
39+
* @raise EEXIST if named file already exists
40+
* @raise EBADF if `path` is relative and `dirfd` isn't `AT_FDCWD` or valid
41+
* @raise ENOTDIR if directory component in `path` existed as non-directory
42+
* @raise ENAMETOOLONG if symlink-resolved `path` length exceeds `PATH_MAX`
43+
* @raise ENAMETOOLONG if component in `path` exists longer than `NAME_MAX`
44+
* @raise EROFS if parent directory is on read-only filesystem
45+
* @raise ENOSPC if file system or parent directory is full
46+
* @raise EACCES if write permission was denied on parent directory
47+
* @raise EACCES if search permission was denied on component in `path`
48+
* @raise ENOENT if a component within `path` didn't exist
49+
* @raise ENOENT if `path` is an empty string
50+
* @raise ELOOP if loop was detected resolving components of `path`
4051
* @asyncsignalsafe
4152
* @see makedirs()
4253
*/

0 commit comments

Comments
 (0)