[PATCH 031/112] fs: implement fdopendir and rewinddir

Ahmad Fatoum a.fatoum at pengutronix.de
Wed Jan 3 10:11:51 PST 2024


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 at pengutronix.de>
---
 fs/fs.c          | 55 ++++++++++++++++++++++++++++++++++++++++++++++--
 include/dirent.h |  3 +++
 2 files changed, 56 insertions(+), 2 deletions(-)

diff --git a/fs/fs.c b/fs/fs.c
index 96ca0f110393..ca1bcef1adf0 100644
--- a/fs/fs.c
+++ b/fs/fs.c
@@ -2643,6 +2643,20 @@ int open(const char *pathname, int flags, ...)
 }
 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 @@ DIR *opendir(const char *pathname)
 }
 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 6e77058d2903..4f7ff2a5f91f 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 */
-- 
2.39.2




More information about the barebox mailing list