summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAhmad Fatoum <a.fatoum@pengutronix.de>2024-03-04 19:59:16 +0100
committerSascha Hauer <s.hauer@pengutronix.de>2024-03-05 16:28:05 +0100
commit8c5a89504ae58e5ca53acac97d5649496ff6b7ac (patch)
tree2985583cb01b0fc949660b30783b233926f465ad
parent8208b020c4d22b3fd02c32be4d1503a0dab8327f (diff)
downloadbarebox-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.c55
-rw-r--r--include/dirent.h3
2 files changed, 56 insertions, 2 deletions
diff --git a/fs/fs.c b/fs/fs.c
index 96ca0f1103..ca1bcef1ad 100644
--- a/fs/fs.c
+++ b/fs/fs.c
@@ -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 */