X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=src%2Ffilesys%2Fdirectory.c;h=5f7dd9ed002ee0bf16582c5a65b80306a8c1832c;hb=615bf3b3d2a8573ed6fb9ddc0055745e163ac999;hp=b08e7eeba3f65947e0ffe51b097e0d7aa166d24c;hpb=3a24478801bbb7d7f2fe791686b679acadefed5f;p=pintos-anon diff --git a/src/filesys/directory.c b/src/filesys/directory.c index b08e7ee..5f7dd9e 100644 --- a/src/filesys/directory.c +++ b/src/filesys/directory.c @@ -1,206 +1,218 @@ #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. */ }; /* A single directory entry. */ struct dir_entry { - bool in_use; /* In use or free? */ - char name[NAME_MAX + 1]; /* Null terminated file name. */ disk_sector_t inode_sector; /* Sector number of header. */ + char name[NAME_MAX + 1]; /* Null terminated file name. */ + 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. */ -struct dir * -dir_create (size_t entry_cnt) +/* Creates a directory with space for ENTRY_CNT entries in the + given SECTOR. Returns true if successful, false on failure. */ +bool +dir_create (disk_sector_t sector, size_t entry_cnt) { - struct dir *d = malloc (sizeof *d); - if (d != NULL) - { - d->entry_cnt = entry_cnt; - d->entries = calloc (1, sizeof *d->entries * entry_cnt); - if (d->entries != NULL) - return d; - free (d); - } - return NULL; + return inode_create (sector, entry_cnt * sizeof (struct dir_entry)); } -/* Returns the size, in bytes, of a directory with ENTRY_CNT - entries. */ -size_t -dir_size (size_t entry_cnt) +/* Opens the directory in the given INODE, of which it takes + ownership, and sets *DIRP to the new directory or a null + pointer on failure. Return true if successful, false on + failure. */ +bool +dir_open (struct inode *inode, struct dir **dirp) { - return entry_cnt * sizeof (struct dir_entry); -} + struct dir *dir = NULL; + + ASSERT (dirp != NULL); -/* Destroys D and frees associated resources. */ -void -dir_destroy (struct dir *d) -{ - if (d != NULL) + if (inode != NULL) { - free (d->entries); - free (d); + dir = malloc (sizeof *dir); + if (dir != NULL) + dir->inode = inode; } + + *dirp = dir; + if (dir == NULL) + inode_close (inode); + return dir != NULL; } -/* Reads D from FILE. - D must have already been initialized, to the correct number of - entries, with dir_init(). */ -void -dir_read (struct dir *d, struct file *file) +/* Opens the root directory and sets *DIRP to it or to a null + pointer on failure. Return true if successful, false on + failure. */ +bool +dir_open_root (struct dir **dirp) { - 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); + return dir_open (inode_open (ROOT_DIR_SECTOR), dirp); } -/* Writes D to FILE. - D must have already been initialized, to the correct number of - entries, with dir_init(). */ +/* Destroys DIR and frees associated resources. */ void -dir_write (struct dir *d, struct file *file) +dir_close (struct dir *dir) { - file_write_at (file, d->entries, dir_size (d->entry_cnt), 0); + if (dir != NULL) + { + inode_close (dir->inode); + free (dir); + } } -/* 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, disk_sector_t inode_sector) { - size_t i; + struct dir_entry e; + off_t ofs; + bool success = false; - ASSERT (d != NULL); + ASSERT (dir != NULL); ASSERT (name != NULL); - ASSERT (lookup (d, name) == NULL); + /* 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. */ +/* Prints the names of the files in DIR to the system console. */ void -dir_dump (const struct dir *d) +dir_list (const struct dir *dir) { - struct dir_entry *e; + struct dir_entry e; + size_t ofs; - 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"); - } + for (ofs = 0; inode_read_at (dir->inode, &e, sizeof e, ofs) == sizeof e; + ofs += sizeof e) + if (e.in_use) + printf ("%s\n", e.name); }