Wording improvements, from "Valentin I. Spitkovsky"
[pintos.git] / src / filesys / directory.c
blob0d265d5da78b7be2ca705a5a9b7eeacfbcd5dfd2
1 #include "filesys/directory.h"
2 #include <stdio.h>
3 #include <string.h>
4 #include <list.h>
5 #include "filesys/filesys.h"
6 #include "filesys/inode.h"
7 #include "threads/malloc.h"
9 /* A directory. */
10 struct dir
12 struct inode *inode; /* Backing store. */
13 off_t pos; /* Current position. */
16 /* A single directory entry. */
17 struct dir_entry
19 disk_sector_t inode_sector; /* Sector number of header. */
20 char name[NAME_MAX + 1]; /* Null terminated file name. */
21 bool in_use; /* In use or free? */
24 /* Creates a directory with space for ENTRY_CNT entries in the
25 given SECTOR. Returns true if successful, false on failure. */
26 bool
27 dir_create (disk_sector_t sector, size_t entry_cnt)
29 return inode_create (sector, entry_cnt * sizeof (struct dir_entry));
32 /* Opens and returns the directory for the given INODE, of which
33 it takes ownership. Returns a null pointer on failure. */
34 struct dir *
35 dir_open (struct inode *inode)
37 struct dir *dir = calloc (1, sizeof *dir);
38 if (inode != NULL && dir != NULL)
40 dir->inode = inode;
41 dir->pos = 0;
42 return dir;
44 else
46 inode_close (inode);
47 free (dir);
48 return NULL;
52 /* Opens the root directory and returns a directory for it.
53 Return true if successful, false on failure. */
54 struct dir *
55 dir_open_root (void)
57 return dir_open (inode_open (ROOT_DIR_SECTOR));
60 /* Opens and returns a new directory for the same inode as DIR.
61 Returns a null pointer on failure. */
62 struct dir *
63 dir_reopen (struct dir *dir)
65 return dir_open (inode_reopen (dir->inode));
68 /* Destroys DIR and frees associated resources. */
69 void
70 dir_close (struct dir *dir)
72 if (dir != NULL)
74 inode_close (dir->inode);
75 free (dir);
79 /* Returns the inode encapsulated by DIR. */
80 struct inode *
81 dir_get_inode (struct dir *dir)
83 return dir->inode;
86 /* Searches DIR for a file with the given NAME.
87 If successful, returns true, sets *EP to the directory entry
88 if EP is non-null, and sets *OFSP to the byte offset of the
89 directory entry if OFSP is non-null.
90 otherwise, returns false and ignores EP and OFSP. */
91 static bool
92 lookup (const struct dir *dir, const char *name,
93 struct dir_entry *ep, off_t *ofsp)
95 struct dir_entry e;
96 size_t ofs;
98 ASSERT (dir != NULL);
99 ASSERT (name != NULL);
101 for (ofs = 0; inode_read_at (dir->inode, &e, sizeof e, ofs) == sizeof e;
102 ofs += sizeof e)
103 if (e.in_use && !strcmp (name, e.name))
105 if (ep != NULL)
106 *ep = e;
107 if (ofsp != NULL)
108 *ofsp = ofs;
109 return true;
111 return false;
114 /* Searches DIR for a file with the given NAME
115 and returns true if one exists, false otherwise.
116 On success, sets *INODE to an inode for the file, otherwise to
117 a null pointer. The caller must close *INODE. */
118 bool
119 dir_lookup (const struct dir *dir, const char *name,
120 struct inode **inode)
122 struct dir_entry e;
124 ASSERT (dir != NULL);
125 ASSERT (name != NULL);
127 if (lookup (dir, name, &e, NULL))
128 *inode = inode_open (e.inode_sector);
129 else
130 *inode = NULL;
132 return *inode != NULL;
135 /* Adds a file named NAME to DIR, which must not already contain a
136 file by that name. The file's inode is in sector
137 INODE_SECTOR.
138 Returns true if successful, false on failure.
139 Fails if NAME is invalid (i.e. too long) or a disk or memory
140 error occurs. */
141 bool
142 dir_add (struct dir *dir, const char *name, disk_sector_t inode_sector)
144 struct dir_entry e;
145 off_t ofs;
146 bool success = false;
148 ASSERT (dir != NULL);
149 ASSERT (name != NULL);
151 /* Check NAME for validity. */
152 if (*name == '\0' || strlen (name) > NAME_MAX)
153 return false;
155 /* Check that NAME is not in use. */
156 if (lookup (dir, name, NULL, NULL))
157 goto done;
159 /* Set OFS to offset of free slot.
160 If there are no free slots, then it will be set to the
161 current end-of-file.
163 inode_read_at() will only return a short read at end of file.
164 Otherwise, we'd need to verify that we didn't get a short
165 read due to something intermittent such as low memory. */
166 for (ofs = 0; inode_read_at (dir->inode, &e, sizeof e, ofs) == sizeof e;
167 ofs += sizeof e)
168 if (!e.in_use)
169 break;
171 /* Write slot. */
172 e.in_use = true;
173 strlcpy (e.name, name, sizeof e.name);
174 e.inode_sector = inode_sector;
175 success = inode_write_at (dir->inode, &e, sizeof e, ofs) == sizeof e;
177 done:
178 return success;
181 /* Removes any entry for NAME in DIR.
182 Returns true if successful, false on failure,
183 which occurs only if there is no file with the given NAME. */
184 bool
185 dir_remove (struct dir *dir, const char *name)
187 struct dir_entry e;
188 struct inode *inode = NULL;
189 bool success = false;
190 off_t ofs;
192 ASSERT (dir != NULL);
193 ASSERT (name != NULL);
195 /* Find directory entry. */
196 if (!lookup (dir, name, &e, &ofs))
197 goto done;
199 /* Open inode. */
200 inode = inode_open (e.inode_sector);
201 if (inode == NULL)
202 goto done;
204 /* Erase directory entry. */
205 e.in_use = false;
206 if (inode_write_at (dir->inode, &e, sizeof e, ofs) != sizeof e)
207 goto done;
209 /* Remove inode. */
210 inode_remove (inode);
211 success = true;
213 done:
214 inode_close (inode);
215 return success;
218 /* Reads the next directory entry in DIR and stores the name in
219 NAME. Returns true if successful, false if the directory
220 contains no more entries. */
221 bool
222 dir_readdir (struct dir *dir, char name[NAME_MAX + 1])
224 struct dir_entry e;
226 while (inode_read_at (dir->inode, &e, sizeof e, dir->pos) == sizeof e)
228 dir->pos += sizeof e;
229 if (e.in_use)
231 strlcpy (name, e.name, NAME_MAX + 1);
232 return true;
235 return false;