summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--hostmux/mux.c127
1 files changed, 86 insertions, 41 deletions
diff --git a/hostmux/mux.c b/hostmux/mux.c
index b942d658..8dc11fc2 100644
--- a/hostmux/mux.c
+++ b/hostmux/mux.c
@@ -58,6 +58,16 @@ netfs_attempt_lookup (struct iouser *user, struct node *dir,
if (dir->nn->name)
err = ENOTDIR;
+ else if (strcmp (name, ".") == 0)
+ /* Current directory -- just add an additional reference to DIR and
+ return it. */
+ {
+ netfs_nref (dir);
+ *node = dir;
+ err = 0;
+ }
+ else if (strcmp (name, "..") == 0)
+ err = EAGAIN;
else
err = lookup_host (dir->nn->mux, name, node);
@@ -84,30 +94,48 @@ netfs_get_dirents (struct iouser *cred, struct node *dir,
size_t size = 0; /* Total size of our return block. */
struct hostmux_name *first_name, *nm;
+ /* Add the length of a directory entry for NAME to SIZE and return true,
+ unless it would overflow MAX_DATA_LEN or NUM_ENTRIES, in which case
+ return false. */
+ int bump_size (const char *name)
+ {
+ if (num_entries == -1 || count < num_entries)
+ {
+ size_t new_size = size + DIRENT_LEN (strlen (name));
+ if (max_data_len > 0 && new_size > max_data_len)
+ return 0;
+ size = new_size;
+ count++;
+ return 1;
+ }
+ else
+ return 0;
+ }
+
if (dir->nn->name)
return ENOTDIR;
rwlock_reader_lock (&dir->nn->mux->names_lock);
/* Find the first entry. */
- for (first_name = dir->nn->mux->names;
- first_name && first_entry > 0;
+ for (first_name = dir->nn->mux->names, count = 0;
+ first_name && first_entry > count;
first_name = first_name->next)
if (first_name->node)
- first_entry--;
+ count++;
+
+ count = 0;
+
+ /* Make space for the `.' and `..' entries. */
+ if (first_entry == 0)
+ bump_size (".");
+ if (first_entry <= 1)
+ bump_size ("..");
/* See how much space we need for the result. */
- for (nm = first_name, count = 0;
- nm && (num_entries == -1 || count < num_entries);
- nm = nm->next)
- if (nm->node)
- {
- size_t new_size = size + DIRENT_LEN (strlen (nm->name));
- if (max_data_len > 0 && new_size > max_data_len)
- break;
- size = new_size;
- count++;
- }
+ for (nm = first_name; nm; nm = nm->next)
+ if (nm->node && !bump_size (nm->name))
+ break;
/* Allocate it. */
err = vm_allocate (mach_task_self (), (vm_address_t *) data, size, 1);
@@ -116,37 +144,54 @@ netfs_get_dirents (struct iouser *cred, struct node *dir,
{
char *p = *data;
+ int add_dir_entry (const char *name, ino_t fileno, int type)
+ {
+ if (num_entries == -1 || count < num_entries)
+ {
+ struct dirent hdr;
+ size_t name_len = strlen (name);
+ size_t sz = DIRENT_LEN (name_len);
+
+ if (sz > size)
+ return 0;
+ else
+ size -= sz;
+
+ hdr.d_fileno = fileno;
+ hdr.d_reclen = sz;
+ hdr.d_type = type;
+ hdr.d_namlen = name_len;
+
+ memcpy (p, &hdr, DIRENT_NAME_OFFS);
+ strcpy (p + DIRENT_NAME_OFFS, name);
+ p += sz;
+
+ count++;
+
+ return 1;
+ }
+ else
+ return 0;
+ }
+
*data_len = size;
*data_entries = count;
- /* See how much space we need for the result. */
- for (nm = first_name, count = 0;
- nm && (num_entries == -1 || count < num_entries);
- nm = nm->next)
- if (nm->node)
- {
- struct dirent hdr;
- size_t name_len = strlen (nm->name);
- size_t sz = DIRENT_LEN (name_len);
-
- if (sz > size)
- break;
- else
- size -= sz;
-
- hdr.d_fileno = nm->fileno;
- hdr.d_reclen = sz;
- hdr.d_type =
- (strcmp (nm->canon, nm->name) == 0 ? DT_REG : DT_LNK);
- hdr.d_namlen = name_len;
-
- memcpy (p, &hdr, DIRENT_NAME_OFFS);
- strcpy (p + DIRENT_NAME_OFFS, nm->name);
- p += sz;
-
- count++;
- }
+ count = 0;
+
+ /* Add `.' and `..' entries. */
+ if (first_entry == 0)
+ add_dir_entry (".", 2, DT_DIR);
+ if (first_entry <= 1)
+ add_dir_entry ("..", 2, DT_DIR);
+ /* Fill in the real directory entries. */
+ for (nm = first_name; nm; nm = nm->next)
+ if (nm->node
+ && !add_dir_entry (nm->name, nm->fileno,
+ strcmp (nm->canon, nm->name) == 0
+ ? DT_REG : DT_LNK))
+ break;
}
rwlock_reader_unlock (&dir->nn->mux->names_lock);