/*Computes the size of the given directory*/ error_t node_get_size (node_t * dir, OFFSET_T * off) { error_t err = 0; /*The final size */ size_t size = 0; /*The number of directory entries */ /*int count = 0; */ /*The the node in the directory entries list from which we start counting */ /*node_dirent_t * dirent_start = NULL; */ /*The currently analyzed dirent */ node_dirent_t *dirent_current = NULL; /*The pointer to the beginning of the list of dirents */ node_dirent_t *dirent_list = NULL; /*The first entry we have to analyze */ /*int first_entry = 2; */ /*Takes into consideration the name of the current dirent */ void bump_size (const char *name) { /*Increment the current size by the size of the current dirent */ size += DIRENT_LEN (strlen (name)); /*Count the current dirent */ /*++count; */ } /*bump_size */
static error_t _get_node_size (struct node *dir, OFFSET_T *off) { size_t size = 0; error_t err; int count = 0; node_dirent_t *dirent_start, *dirent_current; node_dirent_t *dirent_list = NULL; int first_entry = 2; int bump_size (const char *name) { size_t new_size = size + DIRENT_LEN (strlen (name)); size = new_size; count ++; return 1; }
/* Fetch a directory */ error_t netfs_get_dirents (struct iouser *cred, struct node *dir, int first_entry, int max_entries, char **data, mach_msg_type_number_t *data_len, vm_size_t max_data_len, int *data_entries) { error_t err = procfs_refresh_node (dir); struct procfs_dir_entry *dir_entry; if (! err) { if (dir->nn->dir) { if (! procfs_dir_refresh (dir->nn->dir, dir == dir->nn->fs->root)) { for (dir_entry = dir->nn->dir->ordered; first_entry > 0 && dir_entry; first_entry--, dir_entry = dir_entry->ordered_next); if (! dir_entry ) max_entries = 0; if (max_entries != 0) { size_t size = 0; char *p; int count = 0; if (max_data_len == 0) size = DIRENTS_CHUNK_SIZE; else if (max_data_len > DIRENTS_CHUNK_SIZE) size = DIRENTS_CHUNK_SIZE; else size = max_data_len; *data = mmap (0, size, PROT_READ|PROT_WRITE, MAP_ANON, 0, 0); err = ((void *) *data == (void *) -1) ? errno : 0; if (! err) { p = *data; /* This gets all the actual entries present. */ while ((max_entries == -1 || count < max_entries) && dir_entry) { struct dirent hdr; size_t name_len = strlen (dir_entry->name); size_t sz = DIRENT_LEN (name_len); int entry_type = IFTODT (dir_entry->stat.st_mode); if ((p - *data) + sz > size) { if (max_data_len > 0) break; else /* The Buffer Size must be increased. */ { vm_address_t extension = (vm_address_t)(*data + size); err = vm_allocate (mach_task_self (), &extension, DIRENTS_CHUNK_SIZE, 0); if (err) break; size += DIRENTS_CHUNK_SIZE; } } hdr.d_namlen = name_len; hdr.d_fileno = dir_entry->stat.st_ino; hdr.d_reclen = sz; hdr.d_type = entry_type; memcpy (p, &hdr, DIRENT_NAME_OFFS); strcpy (p + DIRENT_NAME_OFFS, dir_entry->name); p += sz; count++; dir_entry = dir_entry->ordered_next; } if (err) munmap (*data, size); else { vm_address_t alloc_end = (vm_address_t)(*data + size); vm_address_t real_end = round_page (p); if (alloc_end > real_end) munmap ((caddr_t) real_end, alloc_end - real_end); *data_len = p - *data; *data_entries = count; } } } else { *data_len = 0; *data_entries = 0; } } } else return ENOTDIR; } procfs_dir_entries_remove (dir->nn->dir); return err; }
/*Reads the directory entries from `node`, which must be locked*/ error_t node_entries_get (node_t * node, node_dirent_t ** dirents) { error_t err = 0; /*The list of dirents */ struct dirent **dirent_list, **dirent; /*The head of the list of dirents */ node_dirent_t *node_dirent_list = NULL; /*The size of the array of pointers to dirent */ size_t dirent_data_size; /*The array of dirents */ char *dirent_data; /*Obtain the directory entries for the given node */ err = dir_entries_get (node->nn->port, &dirent_data, &dirent_data_size, &dirent_list); if (err) { return err; } /*The new entry in the list */ node_dirent_t *node_dirent_new; /*The new dirent */ struct dirent *dirent_new; /*LOG_MSG("node_entries_get: Getting entries for %p", node); */ /*The name of the current dirent */ char *name; /*The length of the current name */ size_t name_len; /*The size of the current dirent */ size_t size; /*Go through all elements of the list of pointers to dirent */ for (dirent = dirent_list; *dirent; ++dirent) { /*obtain the name of the current dirent */ name = &((*dirent)->d_name[0]); /*If the current dirent is either '.' or '..', skip it */ if ((strcmp (name, ".") == 0) || (strcmp (name, "..") == 0)) continue; /*obtain the length of the current name */ name_len = strlen (name); /*obtain the length of the current dirent */ size = DIRENT_LEN (name_len); /*create a new list element */ node_dirent_new = malloc (sizeof (node_dirent_t)); if (!node_dirent_new) { err = ENOMEM; break; } /*create a new dirent */ dirent_new = malloc (size); if (!dirent_new) { free (node_dirent_new); err = ENOMEM; break; } /*fill the dirent with information */ dirent_new->d_ino = (*dirent)->d_ino; dirent_new->d_type = (*dirent)->d_type; dirent_new->d_reclen = size; strcpy ((char *) dirent_new + DIRENT_NAME_OFFS, name); /*add the dirent to the list */ node_dirent_new->dirent = dirent_new; node_dirent_new->next = node_dirent_list; node_dirent_list = node_dirent_new; } /*If something went wrong in the loop */ if (err) /*free the list of dirents */ node_entries_free (node_dirent_list); else /*store the list of dirents in the second parameter */ *dirents = node_dirent_list; /*Free the list of pointers to dirent */ free (dirent_list); /*Free the results of listing the dirents */ munmap (dirent_data, dirent_data_size); /*Return the result of operations */ return err; } /*node_entries_get */
/* Fetch a directory, as for netfs_get_dirents. */ static error_t get_dirents (struct ftpfs_dir *dir, int first_entry, int max_entries, char **data, mach_msg_type_number_t *data_len, vm_size_t max_data_len, int *data_entries) { struct ftpfs_dir_entry *e; error_t err = 0; if (! dir) return ENOTDIR; e = dir->ordered; /* Find the first entry. */ while (first_entry-- > 0) if (! e) { max_entries = 0; break; } else e = e->ordered_next; if (max_entries != 0) { size_t size = (max_data_len == 0 || max_data_len > DIRENTS_CHUNK_SIZE ? DIRENTS_CHUNK_SIZE : max_data_len); *data = mmap (0, size, PROT_READ|PROT_WRITE, MAP_ANON, 0, 0); err = ((void *) *data == (void *) -1) ? errno : 0; if (! err) { char *p = *data; int count = 0; /* See how much space we need for the result. */ while ((max_entries == -1 || count < max_entries) && e) { struct dirent hdr; size_t name_len = strlen (e->name); size_t sz = DIRENT_LEN (name_len); int entry_type = e->stat_timestamp ? IFTODT (e->stat.st_mode) : DT_UNKNOWN; if ((p - *data) + sz > size) { if (max_data_len > 0) break; else /* Try to grow our return buffer. */ { vm_address_t extension = (vm_address_t)(*data + size); err = vm_allocate (mach_task_self (), &extension, DIRENTS_CHUNK_SIZE, 0); if (err) break; size += DIRENTS_CHUNK_SIZE; } } hdr.d_namlen = name_len; hdr.d_fileno = e->stat.st_ino; hdr.d_reclen = sz; hdr.d_type = entry_type; memcpy (p, &hdr, DIRENT_NAME_OFFS); strcpy (p + DIRENT_NAME_OFFS, e->name); p += sz; count++; e = e->ordered_next; } if (err) munmap (*data, size); else { vm_address_t alloc_end = (vm_address_t)(*data + size); vm_address_t real_end = round_page (p); if (alloc_end > real_end) munmap ((caddr_t) real_end, alloc_end - real_end); *data_len = p - *data; *data_entries = count; } } } else { *data_len = 0; *data_entries = 0; } return err; }
/* Implement the netfs_get_directs callback as described in <hurd/netfs.h>. */ error_t netfs_get_dirents (struct iouser *cred, struct node *dir, int first_entry, int num_entries, char **data, mach_msg_type_number_t *data_len, vm_size_t max_data_len, int *data_entries) { error_t err; int count; 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; pthread_rwlock_rdlock (&dir->nn->mux->names_lock); /* Find the first entry. */ for (first_name = dir->nn->mux->names, count = 2; first_name && first_entry > count; first_name = first_name->next) if (first_name->node) 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; nm; nm = nm->next) if (nm->node && !bump_size (nm->name)) break; /* Allocate it. */ *data = mmap (0, size, PROT_READ|PROT_WRITE, MAP_ANON, 0, 0); err = ((void *) *data == (void *) -1) ? errno : 0; if (! err) /* Copy out the result. */ { 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; 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; }
error_t netfs_get_dirents (struct iouser *cred, struct node *dir, int first_entry, int max_entries, char **data, mach_msg_type_number_t *data_len, vm_size_t max_data_len, int *data_entries) { error_t err; int count = 0; char *data_p; size_t size = (max_data_len == 0 || max_data_len > DIRENTS_CHUNK_SIZE ? DIRENTS_CHUNK_SIZE : max_data_len); debug (""); int add_dirent (const char * name, ino_t ino, int type) { /*If the required number of dirents has not been listed yet*/ if((max_entries == -1) || (count < max_entries)) { struct dirent hdr; size_t name_len = strlen(name); size_t sz = DIRENT_LEN(name_len); /*If there is no room for this dirent*/ if ((data_p - *data) + sz > size) { if (max_data_len > 0) return 1; else /* Try to grow our return buffer. */ { error_t err; vm_address_t extension = (vm_address_t)(*data + size); err = vm_allocate (mach_task_self (), &extension, DIRENTS_CHUNK_SIZE, 0); if (err) { munmap (*data, size); return 1; } size += DIRENTS_CHUNK_SIZE; } } /*setup the dirent*/ hdr.d_ino = ino; hdr.d_reclen = sz; hdr.d_type = type; hdr.d_namlen = name_len; memcpy(data_p, &hdr, DIRENT_NAME_OFFS); strcpy(data_p + DIRENT_NAME_OFFS, name); data_p += sz; /*count the new dirent*/ ++count; } return 0; } int add_each_dev (struct vether_device *dev) { struct lnode *ln = (struct lnode *) dev; add_dirent (ln->vdev.name, ln->st.st_ino, DT_CHR); return 0; } if (dir != netfs_root_node) return ENOTDIR; *data = mmap (0, size, PROT_READ | PROT_WRITE, MAP_ANON, 0, 0); err = ((void *) *data == (void *) -1) ? errno : 0; if (!err) { data_p = *data; if (first_entry < 2 + get_dev_num ()) { add_dirent (".", 2, DT_DIR); add_dirent ("..", 2, DT_DIR); foreach_dev_do (add_each_dev); } vm_address_t alloc_end = (vm_address_t)(*data + size); vm_address_t real_end = round_page (data_p); if (alloc_end > real_end) munmap ((caddr_t) real_end, alloc_end - real_end); *data_entries = count; debug ("first_entry is %d, count is %d", first_entry, count); *data_len = data_p - *data; } return err; }