# HG changeset patch # User Paul Boddie # Date 1715266004 -7200 # Node ID 21004e509ba51102d7de5326ec01e7c1bcdf746e # Parent 5b77aef76beac37486d5337021df112dae5dcd6b Introduced a metadata channel for accessing directory listing content, along with a directory rewinding operation that makes use of this channel. diff -r 5b77aef76bea -r 21004e509ba5 libfsclient/include/fsclient/client.h --- a/libfsclient/include/fsclient/client.h Mon May 06 01:14:09 2024 +0200 +++ b/libfsclient/include/fsclient/client.h Thu May 09 16:46:44 2024 +0200 @@ -46,7 +46,7 @@ file_t *client_opendir(const char *name); file_t *client_opendir_using(const char *name, l4_cap_idx_t server); -file_t *client_opendir_at(file_t *file); +file_t *client_opendir_reader(file_t *file); file_t *client_reopen(file_t *file, flags_t flags); long client_pipe(file_t **reader, file_t **writer, flags_t flags); @@ -96,6 +96,7 @@ /* Directory reading operations. */ struct dirent *client_readdir(file_t *file); +void client_rewinddir(file_t *file); /* Notification operations. */ diff -r 5b77aef76bea -r 21004e509ba5 libfsclient/include/fsclient/file.h --- a/libfsclient/include/fsclient/file.h Mon May 06 01:14:09 2024 +0200 +++ b/libfsclient/include/fsclient/file.h Thu May 09 16:46:44 2024 +0200 @@ -35,9 +35,11 @@ EXTERN_C_BEGIN +struct file_t; + /* File access abstraction compatible with notifiable_base_t. */ -typedef struct +typedef struct file_t { /* File object reference. */ @@ -77,6 +79,10 @@ long error; + /* Metadata file object reference. */ + + struct file_t *metadata; + } file_t; diff -r 5b77aef76bea -r 21004e509ba5 libfsclient/lib/src/client.cc --- a/libfsclient/lib/src/client.cc Mon May 06 01:14:09 2024 +0200 +++ b/libfsclient/lib/src/client.cc Thu May 09 16:46:44 2024 +0200 @@ -257,6 +257,9 @@ if (file == NULL) return; + if (file->metadata != NULL) + client_close(file->metadata); + file_flush(file); file_close(file); free(file); @@ -348,33 +351,30 @@ } /* Open a directory listing stream via the given named directory and a named - capability. */ + capability, returning the directory object with a metadata file object + reference to the directory listing stream. */ file_t *client_opendir_using(const char *name, l4_cap_idx_t server) { file_t *file = client_open_using(name, O_DIRECTORY, server); - if (file == NULL) - return NULL; - /* Return the directory structure itself for error handling. */ if (!client_opened(file)) return file; - file_t *reader = client_opendir_at(file); + file->metadata = client_opendir_reader(file); - /* Release the directory and return the reader even if an error occurs. */ + /* Return the directory even if an error occurs. */ - client_close(file); - return reader; + return file; } /* Open a directory listing stream via the given directory. */ -file_t *client_opendir_at(file_t *file) +file_t *client_opendir_reader(file_t *file) { file_t *reader = (file_t *) malloc(sizeof(file_t)); @@ -640,8 +640,11 @@ struct dirent *client_readdir(file_t *file) { + if ((file == NULL) || (file->metadata == NULL)) + return NULL; + char buffer[DIRENT_CORE_SIZE]; - offset_t nread = client_read(file, buffer, DIRENT_CORE_SIZE); + offset_t nread = client_read(file->metadata, buffer, DIRENT_CORE_SIZE); /* Stop if no new structure can be successfully read. */ @@ -666,7 +669,7 @@ char *current = entry + DIRENT_CORE_SIZE; - nread = client_read(file, current, remaining); + nread = client_read(file->metadata, current, remaining); /* Stop if no complete structure can be successfully read. */ @@ -679,6 +682,18 @@ return (struct dirent *) entry; } +/* Rewind directory reading. */ + +void client_rewinddir(file_t *file) +{ + if ((file == NULL) || (file->metadata == NULL)) + return; + + client_close(file->metadata); + + file->metadata = client_opendir_reader(file); +} + /* Read from the filesystem object into the buffer provided. */ diff -r 5b77aef76bea -r 21004e509ba5 libfsclient/lib/src/file.cc --- a/libfsclient/lib/src/file.cc Mon May 06 01:14:09 2024 +0200 +++ b/libfsclient/lib/src/file.cc Thu May 09 16:46:44 2024 +0200 @@ -91,6 +91,7 @@ file->can_block = 0; file->flags = 0; file->error = 0; + file->metadata = NULL; /* Initialise the notifiable section of the structure. */ diff -r 5b77aef76bea -r 21004e509ba5 tests/dstest_file_readdir.cc --- a/tests/dstest_file_readdir.cc Mon May 06 01:14:09 2024 +0200 +++ b/tests/dstest_file_readdir.cc Thu May 09 16:46:44 2024 +0200 @@ -1,7 +1,7 @@ /* * Test directory reading operations. * - * Copyright (C) 2020, 2021, 2022 Paul Boddie + * Copyright (C) 2020, 2021, 2022, 2024 Paul Boddie * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -122,16 +122,36 @@ return 1; } + char *name = NULL; + dirent = client_readdir(reader); if (dirent != NULL) { + name = strdup(dirent->d_name); printf("> %s\n", dirent->d_name); free(dirent); } printf("Entry shown.\n"); + /* Rewind to show the same entry. */ + + char *name2 = NULL; + + client_rewinddir(reader); + + dirent = client_readdir(reader); + + if (dirent != NULL) + { + name2 = strdup(dirent->d_name); + printf("> %s\n", dirent->d_name); + free(dirent); + } + + printf("Entry shown and identical: %s\n", (name != NULL) && (name2 != NULL) && !strcmp(name, name2) ? "True" : "False"); + printf("End of test.\n"); return 0; }