diff options
author | Ahmad Fatoum <a.fatoum@pengutronix.de> | 2024-03-04 19:59:16 +0100 |
---|---|---|
committer | Sascha Hauer <s.hauer@pengutronix.de> | 2024-03-05 16:28:05 +0100 |
commit | 8c5a89504ae58e5ca53acac97d5649496ff6b7ac (patch) | |
tree | 2985583cb01b0fc949660b30783b233926f465ad | |
parent | 8208b020c4d22b3fd02c32be4d1503a0dab8327f (diff) | |
download | barebox-8c5a89504ae5.tar.gz barebox-8c5a89504ae5.tar.xz |
fs: implement fdopendir and rewinddir
We will be using the incoming O_PATH support to implement the EFI file
system protocol for when barebox acts as EFI loader.
The protocol also requires being able to rewind iteration, so add
support for that too.
Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
Link: https://lore.barebox.org/20240304190038.3486881-32-a.fatoum@pengutronix.de
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
-rw-r--r-- | fs/fs.c | 55 | ||||
-rw-r--r-- | include/dirent.h | 3 |
2 files changed, 56 insertions, 2 deletions
@@ -2643,6 +2643,20 @@ out1: } EXPORT_SYMBOL(open); +static const char *fd_getpath(int fd) +{ + FILE *f; + + if (fd < 0) + return ERR_PTR(errno_set(fd)); + + f = fd_to_file(fd); + if (IS_ERR(f)) + return ERR_CAST(f); + + return f->path; +} + int unlink(const char *pathname) { int ret; @@ -2710,9 +2724,11 @@ EXPORT_SYMBOL(symlink); static void __release_dir(DIR *d) { - struct readdir_entry *entry, *tmp; + while (!list_empty(&d->entries)) { + struct readdir_entry *entry = + list_first_entry(&d->entries, struct readdir_entry, list); - list_for_each_entry_safe(entry, tmp, &d->entries, list) { + list_del(&entry->list); free(entry); } } @@ -2772,6 +2788,7 @@ DIR *opendir(const char *pathname) d = xzalloc(sizeof(*d)); d->path = path; + d->fd = -ENOENT; ret = __opendir(d); if (ret) @@ -2790,6 +2807,27 @@ out: } EXPORT_SYMBOL(opendir); +DIR *fdopendir(int fd) +{ + const char *path; + DIR *dir; + + path = fd_getpath(fd); + if (IS_ERR(path)) + return NULL; + + dir = opendir(path); + if (!dir) + return NULL; + + /* we intentionally don't increment the reference count, + * as POSIX specifies that fd ownership is transferred + */ + dir->fd = fd; + return dir; +} +EXPORT_SYMBOL(fdopendir); + int closedir(DIR *dir) { if (!dir) @@ -2797,12 +2835,25 @@ int closedir(DIR *dir) path_put(&dir->path); __release_dir(dir); + if (dir->fd >= 0) + close(dir->fd); free(dir); return 0; } EXPORT_SYMBOL(closedir); +int rewinddir(DIR *dir) +{ + if (!dir) + return errno_set(-EBADF); + + __release_dir(dir); + + return __opendir(dir); +} +EXPORT_SYMBOL(rewinddir); + int readlink(const char *pathname, char *buf, size_t bufsiz) { int ret; diff --git a/include/dirent.h b/include/dirent.h index 6e77058d29..4f7ff2a5f9 100644 --- a/include/dirent.h +++ b/include/dirent.h @@ -14,13 +14,16 @@ typedef struct dir { struct fs_driver *fsdrv; struct dirent d; void *priv; /* private data for the fs driver */ + int fd; struct path path; struct list_head entries; } DIR; DIR *opendir(const char *pathname); +DIR *fdopendir(int fd); struct dirent *readdir(DIR *dir); int unreaddir(DIR *dir, const struct dirent *d); +int rewinddir(DIR *dir); int closedir(DIR *dir); #endif /* __DIRENT_H */ |