Comments.
[pintos-anon] / src / filesys / directory.c
1 #include "filesys/directory.h"
2 #include <stdio.h>
3 #include <string.h>
4 #include "filesys/file.h"
5 #include "filesys/fsutil.h"
6 #include "threads/malloc.h"
7
8 /* A directory. */
9 struct dir 
10   {
11     size_t entry_cnt;           /* Number of entries. */
12     struct dir_entry *entries;  /* Array of entries. */
13   };
14
15 /* A single directory entry. */
16 struct dir_entry 
17   {
18     bool in_use;                        /* In use or free? */
19     char name[NAME_MAX + 1];            /* Null terminated file name. */
20     disk_sector_t inode_sector;         /* Sector number of header. */
21   };
22
23 /* Returns a new directory that holds ENTRY_CNT entries, if
24    successful, or a null pointer if memory is unavailable. */
25 struct dir *
26 dir_create (size_t entry_cnt) 
27 {
28   struct dir *d = malloc (sizeof *d);
29   if (d != NULL)
30     {
31       d->entry_cnt = entry_cnt;
32       d->entries = calloc (1, sizeof *d->entries * entry_cnt);
33       if (d->entries != NULL)
34         return d;
35       free (d); 
36     }
37   return NULL;
38 }
39
40 /* Returns the size, in bytes, of a directory with ENTRY_CNT
41    entries. */
42 size_t
43 dir_size (size_t entry_cnt) 
44 {
45   return entry_cnt * sizeof (struct dir_entry);
46 }
47
48 /* Destroys D and frees associated resources. */
49 void
50 dir_destroy (struct dir *d) 
51 {
52   if (d != NULL) 
53     {
54       free (d->entries);
55       free (d); 
56     }
57 }
58
59 /* Reads D from FILE.
60    D must have already been initialized, to the correct number of
61    entries, with dir_init(). */
62 void
63 dir_read (struct dir *d, struct file *file) 
64 {
65   ASSERT (d != NULL);
66   ASSERT (file != NULL);
67   ASSERT (file_length (file) >= (off_t) dir_size (d->entry_cnt));
68
69   file_read_at (file, d->entries, dir_size (d->entry_cnt), 0);
70 }
71
72 /* Writes D to FILE.
73    D must have already been initialized, to the correct number of
74    entries, with dir_init(). */
75 void
76 dir_write (struct dir *d, struct file *file) 
77 {
78   file_write_at (file, d->entries, dir_size (d->entry_cnt), 0);
79 }
80
81 /* Searches D for a file named NAME.
82    If successful, returns the file's entry;
83    otherwise, returns a null pointer. */
84 static struct dir_entry *
85 lookup (const struct dir *d, const char *name) 
86 {
87   size_t i;
88   
89   ASSERT (d != NULL);
90   ASSERT (name != NULL);
91
92   if (strlen (name) > NAME_MAX)
93     return NULL;
94
95   for (i = 0; i < d->entry_cnt; i++) 
96     {
97       struct dir_entry *e = &d->entries[i];
98       if (e->in_use && !strcmp (name, e->name))
99         return e;
100     }
101   return NULL;
102 }
103
104 /* Searches D for a file named NAME
105    and returns true if one exists, false otherwise.
106    If INODE_SECTOR is nonnull, then on success *INODE_SECTOR
107    is set to the sector that contains the file's inode. */
108 bool
109 dir_lookup (const struct dir *d, const char *name,
110             disk_sector_t *inode_sector) 
111 {
112   const struct dir_entry *e;
113
114   ASSERT (d != NULL);
115   ASSERT (name != NULL);
116   
117   e = lookup (d, name);
118   if (e != NULL) 
119     {
120       if (inode_sector != NULL)
121         *inode_sector = e->inode_sector;
122       return true;
123     }
124   else
125     return false;
126 }
127
128 /* Adds a file named NAME to D, which must not already contain a
129    file by that name.  The file's inode is in sector
130    INODE_SECTOR.
131    Returns true if successful, false on failure.
132    Fails if NAME is invalid (i.e. too long) or if D has no free
133    directory entries. */
134 bool
135 dir_add (struct dir *d, const char *name, disk_sector_t inode_sector) 
136 {
137   size_t i;
138   
139   ASSERT (d != NULL);
140   ASSERT (name != NULL);
141   ASSERT (lookup (d, name) == NULL);
142
143   if (strlen (name) > NAME_MAX)
144     return false;
145
146   for (i = 0; i < d->entry_cnt; i++)
147     {
148       struct dir_entry *e = &d->entries[i];
149       if (!e->in_use) 
150         {
151           e->in_use = true;
152           strlcpy (e->name, name, sizeof e->name);
153           e->inode_sector = inode_sector;
154           return true;
155         }
156     }
157   return false;
158 }
159
160 /* Removes any entry for NAME in D.
161    Returns true if successful, false on failure,
162    which occurs only if there is no file with the given NAME. */
163 bool
164 dir_remove (struct dir *d, const char *name) 
165 {
166   struct dir_entry *e;
167
168   ASSERT (d != NULL);
169   ASSERT (name != NULL);
170
171   e = lookup (d, name);
172   if (e != NULL) 
173     {
174       e->in_use = false;
175       return true;
176     }
177   else
178     return false;
179 }
180
181 /* Prints the names of the files in D to the system console. */
182 void
183 dir_list (const struct dir *d)
184 {
185   struct dir_entry *e;
186   
187   for (e = d->entries; e < d->entries + d->entry_cnt; e++)
188     if (e->in_use)
189       printf ("%s\n", e->name);
190 }
191
192 /* Dumps the contents of D, including its files' names and their
193    contents, to the system console. */
194 void
195 dir_dump (const struct dir *d) 
196 {
197   struct dir_entry *e;
198   
199   for (e = d->entries; e < d->entries + d->entry_cnt; e++)
200     if (e->in_use) 
201       {
202         printf ("Contents of %s:\n", e->name);
203         fsutil_print (e->name);
204         printf ("\n");
205       }
206 }