X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?p=pintos-anon;a=blobdiff_plain;f=src%2Ffilesys%2Fdirectory.c;h=030c1c9b0dbaf9b3a41a4decaadd7c76793b1d63;hp=ec6ecd98715d30ba99acff1449e15b0d440c92ea;hb=a03618133f7df0954802a470a4bee7674f7aed45;hpb=993c1d9f4452e2edd851f3175dfdf317f18bdb9f diff --git a/src/filesys/directory.c b/src/filesys/directory.c index ec6ecd9..030c1c9 100644 --- a/src/filesys/directory.c +++ b/src/filesys/directory.c @@ -1,206 +1,236 @@ #include "filesys/directory.h" #include #include -#include "filesys/file.h" -#include "filesys/fsutil.h" +#include +#include "filesys/filesys.h" +#include "filesys/inode.h" #include "threads/malloc.h" /* A directory. */ struct dir { - size_t entry_cnt; /* Number of entries. */ - struct dir_entry *entries; /* Array of entries. */ + struct inode *inode; /* Backing store. */ + off_t pos; /* Current position. */ }; /* A single directory entry. */ struct dir_entry { - bool in_use; /* In use or free? */ + block_sector_t inode_sector; /* Sector number of header. */ char name[NAME_MAX + 1]; /* Null terminated file name. */ - disk_sector_t inode_sector; /* Sector number of header. */ + bool in_use; /* In use or free? */ }; -/* Returns a new directory that holds ENTRY_CNT entries, if - successful, or a null pointer if memory is unavailable. */ +/* Creates a directory with space for ENTRY_CNT entries in the + given SECTOR. Returns true if successful, false on failure. */ +bool +dir_create (block_sector_t sector, size_t entry_cnt) +{ + return inode_create (sector, entry_cnt * sizeof (struct dir_entry)); +} + +/* Opens and returns the directory for the given INODE, of which + it takes ownership. Returns a null pointer on failure. */ struct dir * -dir_create (size_t entry_cnt) +dir_open (struct inode *inode) { - struct dir *d = malloc (sizeof *d); - if (d != NULL) + struct dir *dir = calloc (1, sizeof *dir); + if (inode != NULL && dir != NULL) { - d->entry_cnt = entry_cnt; - d->entries = calloc (1, sizeof *d->entries * entry_cnt); - if (d->entries != NULL) - return d; - free (d); + dir->inode = inode; + dir->pos = 0; + return dir; + } + else + { + inode_close (inode); + free (dir); + return NULL; } - return NULL; } -/* Returns the size, in bytes, of a directory with ENTRY_CNT - entries. */ -size_t -dir_size (size_t entry_cnt) +/* Opens the root directory and returns a directory for it. + Return true if successful, false on failure. */ +struct dir * +dir_open_root (void) { - return entry_cnt * sizeof (struct dir_entry); + return dir_open (inode_open (ROOT_DIR_SECTOR)); } -/* Destroys D and frees associated resources. */ -void -dir_destroy (struct dir *d) +/* Opens and returns a new directory for the same inode as DIR. + Returns a null pointer on failure. */ +struct dir * +dir_reopen (struct dir *dir) { - if (d != NULL) - { - free (d->entries); - free (d); - } + return dir_open (inode_reopen (dir->inode)); } -/* Reads D from FILE. - D must have already been initialized, to the correct number of - entries, with dir_init(). */ +/* Destroys DIR and frees associated resources. */ void -dir_read (struct dir *d, struct file *file) +dir_close (struct dir *dir) { - ASSERT (d != NULL); - ASSERT (file != NULL); - ASSERT (file_length (file) >= (off_t) dir_size (d->entry_cnt)); - - file_read_at (file, d->entries, dir_size (d->entry_cnt), 0); + if (dir != NULL) + { + inode_close (dir->inode); + free (dir); + } } -/* Writes D to FILE. - D must have already been initialized, to the correct number of - entries, with dir_init(). */ -void -dir_write (struct dir *d, struct file *file) +/* Returns the inode encapsulated by DIR. */ +struct inode * +dir_get_inode (struct dir *dir) { - file_write_at (file, d->entries, dir_size (d->entry_cnt), 0); + return dir->inode; } -/* Searches D for a file named NAME. - If successful, returns the file's entry; - otherwise, returns a null pointer. */ -static struct dir_entry * -lookup (const struct dir *d, const char *name) +/* Searches DIR for a file with the given NAME. + If successful, returns true, sets *EP to the directory entry + if EP is non-null, and sets *OFSP to the byte offset of the + directory entry if OFSP is non-null. + otherwise, returns false and ignores EP and OFSP. */ +static bool +lookup (const struct dir *dir, const char *name, + struct dir_entry *ep, off_t *ofsp) { - size_t i; + struct dir_entry e; + size_t ofs; - ASSERT (d != NULL); + ASSERT (dir != NULL); ASSERT (name != NULL); - if (strlen (name) > NAME_MAX) - return NULL; - - for (i = 0; i < d->entry_cnt; i++) - { - struct dir_entry *e = &d->entries[i]; - if (e->in_use && !strcmp (name, e->name)) - return e; - } - return NULL; + for (ofs = 0; inode_read_at (dir->inode, &e, sizeof e, ofs) == sizeof e; + ofs += sizeof e) + if (e.in_use && !strcmp (name, e.name)) + { + if (ep != NULL) + *ep = e; + if (ofsp != NULL) + *ofsp = ofs; + return true; + } + return false; } -/* Searches D for a file named NAME +/* Searches DIR for a file with the given NAME and returns true if one exists, false otherwise. - If INODE_SECTOR is nonnull, then on success *INODE_SECTOR - is set to the sector that contains the file's inode. */ + On success, sets *INODE to an inode for the file, otherwise to + a null pointer. The caller must close *INODE. */ bool -dir_lookup (const struct dir *d, const char *name, - disk_sector_t *inode_sector) +dir_lookup (const struct dir *dir, const char *name, + struct inode **inode) { - const struct dir_entry *e; + struct dir_entry e; - ASSERT (d != NULL); + ASSERT (dir != NULL); ASSERT (name != NULL); - - e = lookup (d, name); - if (e != NULL) - { - if (inode_sector != NULL) - *inode_sector = e->inode_sector; - return true; - } + + if (lookup (dir, name, &e, NULL)) + *inode = inode_open (e.inode_sector); else - return false; + *inode = NULL; + + return *inode != NULL; } -/* Adds a file named NAME to D, which must not already contain a +/* Adds a file named NAME to DIR, which must not already contain a file by that name. The file's inode is in sector INODE_SECTOR. Returns true if successful, false on failure. - Fails if NAME is invalid (i.e. too long) or if D has no free - directory entries. */ + Fails if NAME is invalid (i.e. too long) or a disk or memory + error occurs. */ bool -dir_add (struct dir *d, const char *name, disk_sector_t inode_sector) +dir_add (struct dir *dir, const char *name, block_sector_t inode_sector) { - size_t i; - - ASSERT (d != NULL); + struct dir_entry e; + off_t ofs; + bool success = false; + + ASSERT (dir != NULL); ASSERT (name != NULL); - ASSERT (lookup (d, name) == NULL); - if (strlen (name) > NAME_MAX) + /* Check NAME for validity. */ + if (*name == '\0' || strlen (name) > NAME_MAX) return false; - for (i = 0; i < d->entry_cnt; i++) - { - struct dir_entry *e = &d->entries[i]; - if (!e->in_use) - { - e->in_use = true; - strlcpy (e->name, name, sizeof e->name); - e->inode_sector = inode_sector; - return true; - } - } - return false; + /* Check that NAME is not in use. */ + if (lookup (dir, name, NULL, NULL)) + goto done; + + /* Set OFS to offset of free slot. + If there are no free slots, then it will be set to the + current end-of-file. + + inode_read_at() will only return a short read at end of file. + Otherwise, we'd need to verify that we didn't get a short + read due to something intermittent such as low memory. */ + for (ofs = 0; inode_read_at (dir->inode, &e, sizeof e, ofs) == sizeof e; + ofs += sizeof e) + if (!e.in_use) + break; + + /* Write slot. */ + e.in_use = true; + strlcpy (e.name, name, sizeof e.name); + e.inode_sector = inode_sector; + success = inode_write_at (dir->inode, &e, sizeof e, ofs) == sizeof e; + + done: + return success; } -/* Removes any entry for NAME in D. +/* Removes any entry for NAME in DIR. Returns true if successful, false on failure, which occurs only if there is no file with the given NAME. */ bool -dir_remove (struct dir *d, const char *name) +dir_remove (struct dir *dir, const char *name) { - struct dir_entry *e; + struct dir_entry e; + struct inode *inode = NULL; + bool success = false; + off_t ofs; - ASSERT (d != NULL); + ASSERT (dir != NULL); ASSERT (name != NULL); - e = lookup (d, name); - if (e != NULL) - { - e->in_use = false; - return true; - } - else - return false; -} + /* Find directory entry. */ + if (!lookup (dir, name, &e, &ofs)) + goto done; -/* Prints the names of the files in D to the system console. */ -void -dir_list (const struct dir *d) -{ - struct dir_entry *e; - - for (e = d->entries; e < d->entries + d->entry_cnt; e++) - if (e->in_use) - printf ("%s\n", e->name); + /* Open inode. */ + inode = inode_open (e.inode_sector); + if (inode == NULL) + goto done; + + /* Erase directory entry. */ + e.in_use = false; + if (inode_write_at (dir->inode, &e, sizeof e, ofs) != sizeof e) + goto done; + + /* Remove inode. */ + inode_remove (inode); + success = true; + + done: + inode_close (inode); + return success; } -/* Dumps the contents of D, including its files' names and their - contents, to the system console. */ -void -dir_dump (const struct dir *d) +/* Reads the next directory entry in DIR and stores the name in + NAME. Returns true if successful, false if the directory + contains no more entries. */ +bool +dir_readdir (struct dir *dir, char name[NAME_MAX + 1]) { - struct dir_entry *e; - - for (e = d->entries; e < d->entries + d->entry_cnt; e++) - if (e->in_use) - { - printf ("Contents of %s:\n", e->name); - fsutil_print (e->name); - printf ("\n"); - } + struct dir_entry e; + + while (inode_read_at (dir->inode, &e, sizeof e, dir->pos) == sizeof e) + { + dir->pos += sizeof e; + if (e.in_use) + { + strlcpy (name, e.name, NAME_MAX + 1); + return true; + } + } + return false; }