1 #include "filesys/directory.h"
5 #include "filesys/filesys.h"
6 #include "filesys/inode.h"
7 #include "threads/malloc.h"
12 struct inode *inode; /* Backing store. */
15 /* A single directory entry. */
18 disk_sector_t inode_sector; /* Sector number of header. */
19 char name[NAME_MAX + 1]; /* Null terminated file name. */
20 bool in_use; /* In use or free? */
23 /* Creates a directory with space for ENTRY_CNT entries in the
24 given SECTOR. Returns true if successful, false on failure. */
26 dir_create (disk_sector_t sector, size_t entry_cnt)
28 return inode_create (sector, entry_cnt * sizeof (struct dir_entry));
31 /* Opens the directory in the given INODE, of which it takes
32 ownership, and sets *DIRP to the new directory or a null
33 pointer on failure. Return true if successful, false on
36 dir_open (struct inode *inode, struct dir **dirp)
38 struct dir *dir = NULL;
40 ASSERT (dirp != NULL);
44 dir = malloc (sizeof *dir);
55 /* Opens the root directory and sets *DIRP to it or to a null
56 pointer on failure. Return true if successful, false on
59 dir_open_root (struct dir **dirp)
61 return dir_open (inode_open (ROOT_DIR_SECTOR), dirp);
64 /* Destroys DIR and frees associated resources. */
66 dir_close (struct dir *dir)
70 inode_close (dir->inode);
75 /* Searches DIR for a file with the given NAME.
76 If successful, returns true, sets *EP to the directory entry
77 if EP is non-null, and sets *OFSP to the byte offset of the
78 directory entry if OFSP is non-null.
79 otherwise, returns false and ignores EP and OFSP. */
81 lookup (const struct dir *dir, const char *name,
82 struct dir_entry *ep, off_t *ofsp)
88 ASSERT (name != NULL);
90 for (ofs = 0; inode_read_at (dir->inode, &e, sizeof e, ofs) == sizeof e;
92 if (e.in_use && !strcmp (name, e.name))
103 /* Searches DIR for a file with the given NAME
104 and returns true if one exists, false otherwise.
105 On success, sets *INODE to an inode for the file, otherwise to
106 a null pointer. The caller must close *INODE. */
108 dir_lookup (const struct dir *dir, const char *name,
109 struct inode **inode)
113 ASSERT (dir != NULL);
114 ASSERT (name != NULL);
116 if (lookup (dir, name, &e, NULL))
117 *inode = inode_open (e.inode_sector);
121 return *inode != NULL;
124 /* Adds a file named NAME to DIR, which must not already contain a
125 file by that name. The file's inode is in sector
127 Returns true if successful, false on failure.
128 Fails if NAME is invalid (i.e. too long) or a disk or memory
131 dir_add (struct dir *dir, const char *name, disk_sector_t inode_sector)
135 bool success = false;
137 ASSERT (dir != NULL);
138 ASSERT (name != NULL);
140 /* Check NAME for validity. */
141 if (*name == '\0' || strlen (name) > NAME_MAX)
144 /* Check that NAME is not in use. */
145 if (lookup (dir, name, NULL, NULL))
148 /* Set OFS to offset of free slot.
149 If there are no free slots, then it will be set to the
152 inode_read_at() will only return a short read at end of file.
153 Otherwise, we'd need to verify that we didn't get a short
154 read due to something intermittent such as low memory. */
155 for (ofs = 0; inode_read_at (dir->inode, &e, sizeof e, ofs) == sizeof e;
162 strlcpy (e.name, name, sizeof e.name);
163 e.inode_sector = inode_sector;
164 success = inode_write_at (dir->inode, &e, sizeof e, ofs) == sizeof e;
170 /* Removes any entry for NAME in DIR.
171 Returns true if successful, false on failure,
172 which occurs only if there is no file with the given NAME. */
174 dir_remove (struct dir *dir, const char *name)
177 struct inode *inode = NULL;
178 bool success = false;
181 ASSERT (dir != NULL);
182 ASSERT (name != NULL);
184 /* Find directory entry. */
185 if (!lookup (dir, name, &e, &ofs))
189 inode = inode_open (e.inode_sector);
193 /* Erase directory entry. */
195 if (inode_write_at (dir->inode, &e, sizeof e, ofs) != sizeof e)
199 inode_remove (inode);
207 /* Prints the names of the files in DIR to the system console. */
209 dir_list (const struct dir *dir)
214 for (ofs = 0; inode_read_at (dir->inode, &e, sizeof e, ofs) == sizeof e;
217 printf ("%s\n", e.name);