Skip to content

Commit de74e03

Browse files
kjcamannjhunsaker
authored andcommitted
[core] add path_util.h, make hugetlb_path.h use it
This carves out the internal utility functions `walk_path_suffix` and `path_append` from `monad_hugetlbfs_open_dir_fd` so that they can be re-used elsewhere in the project. They are now called `monad_path_open_subdir` (enhanced form of the old `walk_path_suffix`) and `monad_path_append` (old `path_append`). `monad_hugetlbfs_open_dir_fd` is also rewritten to use these, and `monad_path_open_subdir` gets a unit test. `monad_path_append` is more robust and more useful than it was before. `monad_path_open_subdir` is used when you want to open a path to a subdirectory underneath some known existing directory hierarchy, but you do not know if the intermediate path components exist or not. You may want to do `mkdir -p` programatically to create them, or even if not, you'll want a better error message than open(2) would give you (just a mysterious ENOENT with no hint about what is wrong). "Known" existing directory is used losely here, since init_dirfd can be the special value AT_FDCWD to use the current working directory, and if `path_suffix` is absolute (contains a leading '/'), it will relative to root in any case -- both of which are the defined POSIX behavior of openat(2). `monad_path_open_subdir` is reused outside of the hugetblfs path calculation in a later event SDK commit.
1 parent 1c4dc6a commit de74e03

File tree

8 files changed

+359
-135
lines changed

8 files changed

+359
-135
lines changed

category/core/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,8 @@ add_library(
9999
"monad_exception.cpp"
100100
"monad_exception.hpp"
101101
"nibble.h"
102+
"path_util.c"
103+
"path_util.h"
102104
"result.hpp"
103105
"size_of.hpp"
104106
"small_prng.hpp"

category/core/mem/hugetlb_path.c

Lines changed: 39 additions & 132 deletions
Original file line numberDiff line numberDiff line change
@@ -16,19 +16,17 @@
1616
#include <category/core/cleanup.h> // NOLINT(misc-include-cleaner)
1717
#include <category/core/format_err.h>
1818
#include <category/core/mem/hugetlb_path.h>
19+
#include <category/core/path_util.h>
1920
#include <category/core/srcloc.h>
2021

2122
#include <hugetlbfs.h>
2223

2324
#include <errno.h>
25+
#include <stddef.h>
26+
#include <string.h>
27+
2428
#include <fcntl.h>
25-
#include <limits.h>
2629
#include <linux/limits.h>
27-
#include <stdlib.h>
28-
#include <string.h>
29-
#include <sys/stat.h>
30-
#include <sys/types.h>
31-
#include <unistd.h>
3230

3331
thread_local char g_error_buf[PATH_MAX];
3432

@@ -39,122 +37,27 @@ thread_local char g_error_buf[PATH_MAX];
3937
&MONAD_SOURCE_LOCATION_CURRENT(), \
4038
__VA_ARGS__)
4139

42-
static int
43-
path_append(char **dst, char const *src, size_t *size, bool prepend_sep)
44-
{
45-
if (*dst == nullptr) {
46-
return 0;
47-
}
48-
if (prepend_sep) {
49-
if (*size == 0) {
50-
return FORMAT_ERRC(ERANGE, "path buffer overflow");
51-
}
52-
**dst = '/';
53-
*dst += 1;
54-
*size -= 1;
55-
}
56-
size_t const n = strlcpy(*dst, src, *size);
57-
if (n >= *size) {
58-
*dst += *size;
59-
*size = 0;
60-
return FORMAT_ERRC(ERANGE, "path buffer overflow");
61-
}
62-
*dst += n;
63-
*size -= n;
64-
return 0;
65-
}
66-
67-
static int walk_path_suffix(
68-
char const *path_suffix, bool create_dirs, mode_t mode, int *curfd,
69-
char const *const namebuf_start, char *namebuf, size_t namebuf_size)
70-
{
71-
// NOLINTBEGIN(clang-analyzer-unix.Malloc)
72-
int rc = 0;
73-
char *dir_name;
74-
char *tokctx;
75-
76-
char *const path_components [[gnu::cleanup(cleanup_free)]] =
77-
strdup(path_suffix);
78-
if (path_components == nullptr) {
79-
return FORMAT_ERRC(errno, "strdup of `%s` failed", path_suffix);
80-
}
81-
82-
for (dir_name = strtok_r(path_components, "/", &tokctx); dir_name;
83-
dir_name = strtok_r(nullptr, "/", &tokctx)) {
84-
// This loop iterates over the path components in a path string; each
85-
// path component is the name of a directory.
86-
//
87-
// Within this loop, `dir_name` refers to the next path component and
88-
// `*curfd` is an open file descriptor to the parent directory of
89-
// `dir_name`; the "walk" involves:
90-
//
91-
// - creating a directory named `dir_name` if it doesn't exist and
92-
// we're allowed to create directories
93-
//
94-
// - opening a file descriptor to `dir_name` as the new `*curfd`
95-
// with O_DIRECTORY (thereby checking if it is a directory in
96-
// case we got EEXIST but it is some other type of file)
97-
//
98-
// - appending the `dir_name` to `namebuf`
99-
//
100-
// When we're done, `*curfd` is an open file descriptor to the last
101-
// directory in the path; if we fail early for any reason, the error
102-
// will indicate what path component is responsible for the error,
103-
// e.g., in `/a/b/c/d` if `c` exists but is not a directory we'll get
104-
// ENOTDIR with the error string indicating that it occured for path
105-
// component `c` at `/a/b`
106-
int nextfd;
107-
int lastfd;
108-
if (create_dirs && mkdirat(*curfd, dir_name, mode) == -1 &&
109-
errno != EEXIST) {
110-
rc = FORMAT_ERRC(
111-
errno,
112-
"mkdir of `%s` at path `%s` failed",
113-
dir_name,
114-
namebuf_start ? namebuf_start : "<unknown>");
115-
goto Error;
116-
}
117-
nextfd = openat(*curfd, dir_name, O_DIRECTORY | O_PATH);
118-
if (nextfd == -1) {
119-
rc = FORMAT_ERRC(
120-
errno,
121-
"openat of `%s` at path `%s` failed",
122-
dir_name,
123-
namebuf_start ? namebuf_start : "<unknown>");
124-
goto Error;
125-
}
126-
lastfd = *curfd;
127-
*curfd = nextfd;
128-
(void)close(lastfd);
129-
rc = path_append(
130-
&namebuf, dir_name, &namebuf_size, /*prepend_sep*/ true);
131-
}
132-
return rc;
133-
134-
Error:
135-
(void)close(*curfd);
136-
*curfd = -1;
137-
return rc;
138-
// NOLINTEND(clang-analyzer-unix.Malloc)
139-
}
140-
14140
int monad_hugetlbfs_open_dir_fd(
14241
struct monad_hugetlbfs_resolve_params const *params, int *dirfd,
143-
char *namebuf, size_t namebuf_size)
42+
char *pathbuf, size_t pathbuf_size)
14443
{
145-
int rc;
14644
size_t resolve_size;
14745
char const *hugetlbfs_mount_path;
148-
char const *const namebuf_start = namebuf;
149-
int curfd;
46+
char local_pathbuf[PATH_MAX];
47+
#ifdef O_PATH
48+
constexpr int OPEN_FLAGS = O_DIRECTORY | O_PATH;
49+
#else
50+
constexpr int OPEN_FLAGS = O_DIRECTORY;
51+
#endif
15052

15153
if (params == nullptr) {
15254
return FORMAT_ERRC(EFAULT, "params cannot be nullptr");
15355
}
154-
if (dirfd != nullptr) {
155-
// Ensure the caller doesn't accidentally close something (i.e., stdin)
156-
// if they unconditionally close upon failure
157-
*dirfd = -1;
56+
if (pathbuf == nullptr) {
57+
// Even if the user doesn't want the full absolute path, we need it
58+
// locally for better error reporting
59+
pathbuf = local_pathbuf;
60+
pathbuf_size = sizeof local_pathbuf;
15861
}
15962
if (params->page_size == 0) {
16063
long default_size = gethugepagesize();
@@ -171,31 +74,35 @@ int monad_hugetlbfs_open_dir_fd(
17174
return FORMAT_ERRC(
17275
ENODEV, "no mounted hugetlbfs is accessible to this user");
17376
}
174-
rc = path_append(
175-
&namebuf, hugetlbfs_mount_path, &namebuf_size, /*prepend_sep*/ false);
176-
if (rc) {
177-
return rc;
77+
size_t const mount_path_len =
78+
strlcpy(pathbuf, hugetlbfs_mount_path, pathbuf_size);
79+
if (mount_path_len >= pathbuf_size) {
80+
return FORMAT_ERRC(
81+
ENAMETOOLONG, "pathbuf cannot hold %s", hugetlbfs_mount_path);
17882
}
179-
curfd = open(hugetlbfs_mount_path, O_DIRECTORY | O_PATH);
180-
if (curfd == -1) {
83+
int mountfd [[gnu::cleanup(cleanup_close)]] =
84+
open(hugetlbfs_mount_path, OPEN_FLAGS);
85+
if (mountfd == -1) {
18186
return FORMAT_ERRC(
18287
errno, "open of hugetlbfs mount `%s` failed", hugetlbfs_mount_path);
18388
}
184-
rc = walk_path_suffix(
89+
int const rc = monad_path_open_subdir(
90+
mountfd,
18591
params->path_suffix,
186-
params->create_dirs,
187-
params->dir_create_mode,
188-
&curfd,
189-
namebuf_start,
190-
namebuf,
191-
namebuf_size);
192-
if (dirfd) {
193-
*dirfd = curfd;
194-
}
195-
else {
196-
(void)close(curfd);
92+
params->create_dirs ? params->dir_create_mode : MONAD_PATH_NO_CREATE,
93+
dirfd,
94+
pathbuf + mount_path_len,
95+
pathbuf_size - mount_path_len);
96+
if (rc != 0) {
97+
return FORMAT_ERRC(
98+
rc,
99+
"monad_path_open_subdir of `%s` underneath `%s` failed at last "
100+
"path component of `%s`",
101+
params->path_suffix,
102+
hugetlbfs_mount_path,
103+
pathbuf);
197104
}
198-
return rc;
105+
return 0;
199106
}
200107

201108
char const *monad_hugetlbfs_get_last_error()

category/core/mem/hugetlb_path.h

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313
// You should have received a copy of the GNU General Public License
1414
// along with this program. If not, see <http://www.gnu.org/licenses/>.
1515

16+
#pragma once
17+
1618
/**
1719
* @file
1820
*
@@ -44,10 +46,10 @@ struct monad_hugetlbfs_resolve_params
4446
/// hugetlbfs filesystem; the mount point of the filesystem will be used if
4547
/// path_suffix is nullptr. If desired, the subdirectory will be created if it
4648
/// does not exist. This also formats the full name of the absolute path to
47-
/// the subdirectory into namebuf, if it is not nullptr.
49+
/// the subdirectory into pathbuf, if it is not nullptr.
4850
int monad_hugetlbfs_open_dir_fd(
49-
struct monad_hugetlbfs_resolve_params const *, int *dirfd, char *namebuf,
50-
size_t namebuf_size);
51+
struct monad_hugetlbfs_resolve_params const *, int *dirfd, char *pathbuf,
52+
size_t pathbuf_size);
5153

5254
/// Return the last error that occurred on this thread
5355
char const *monad_hugetlbfs_get_last_error();

0 commit comments

Comments
 (0)