39bdff91aa99b5c0f37b7dc4bfb9f8e0af64029d
[pintos-anon] / src / filesys / filesys.c
1 #include "filesys/filesys.h"
2 #include <debug.h>
3 #include <stdio.h>
4 #include <string.h>
5 #include "filesys/file.h"
6 #include "filesys/free-map.h"
7 #include "filesys/inode.h"
8 #include "filesys/directory.h"
9 #include "devices/disk.h"
10
11 /* The disk that contains the filesystem. */
12 struct disk *filesys_disk;
13
14 static void do_format (void);
15
16 /* Initializes the filesystem module.
17    If FORMAT is true, reformats the filesystem. */
18 void
19 filesys_init (bool format) 
20 {
21   filesys_disk = disk_get (0, 1);
22   if (filesys_disk == NULL)
23     PANIC ("hd0:1 (hdb) not present, filesystem initialization failed");
24
25   inode_init ();
26   free_map_init ();
27
28   if (format) 
29     do_format ();
30
31   free_map_open ();
32 }
33
34 /* Shuts down the filesystem module, writing any unwritten data
35    to disk. */
36 void
37 filesys_done (void) 
38 {
39   free_map_close ();
40 }
41 \f
42 /* Creates a file named NAME with the given INITIAL_SIZE.
43    Returns true if successful, false otherwise.
44    Fails if a file named NAME already exists,
45    or if internal memory allocation fails. */
46 bool
47 filesys_create (const char *name, off_t initial_size) 
48 {
49   disk_sector_t inode_sector = 0;
50   struct dir *dir = dir_open_root ();
51   bool success = (dir != NULL
52                   && free_map_allocate (1, &inode_sector)
53                   && inode_create (inode_sector, initial_size)
54                   && dir_add (dir, name, inode_sector));
55   if (!success && inode_sector != 0) 
56     free_map_release (inode_sector, 1);
57   dir_close (dir);
58
59   return success;
60 }
61
62 /* Opens the file with the given NAME.
63    Returns the new file if successful or a null pointer
64    otherwise.
65    Fails if no file named NAME exists,
66    or if an internal memory allocation fails. */
67 struct file *
68 filesys_open (const char *name)
69 {
70   struct dir *dir = dir_open_root ();
71   struct inode *inode = NULL;
72
73   if (dir != NULL)
74     dir_lookup (dir, name, &inode);
75   dir_close (dir);
76
77   return file_open (inode);
78 }
79
80 /* Deletes the file named NAME.
81    Returns true if successful, false on failure.
82    Fails if no file named NAME exists,
83    or if an internal memory allocation fails. */
84 bool
85 filesys_remove (const char *name) 
86 {
87   struct dir *dir = dir_open_root ();
88   bool success = dir != NULL && dir_remove (dir, name);
89   dir_close (dir); 
90
91   return success;
92 }
93
94 /* Prints a list of files in the filesystem to the system
95    console.
96    Returns true if successful, false on failure,
97    which occurs only if an internal memory allocation fails. */
98 bool
99 filesys_list (void) 
100 {
101   struct dir *dir = dir_open_root ();
102   if (dir != NULL) 
103     {
104       dir_list (dir);
105       dir_close (dir);
106       return true;
107     }
108   else
109     return false;
110 }
111 \f
112 static void must_succeed_function (int, bool) NO_INLINE;
113 #define MUST_SUCCEED(EXPR) must_succeed_function (__LINE__, EXPR)
114
115 /* Performs basic sanity checks on the filesystem.
116    The filesystem should not contain a file named `foo' when
117    called. */
118 void
119 filesys_self_test (void)
120 {
121   static const char s[] = "This is a test string.";
122   static const char zeros[sizeof s] = {0};
123   struct file *file;
124   char s2[sizeof s];
125   int i;
126
127   filesys_remove ("foo");
128   for (i = 0; i < 2; i++) 
129     {
130       /* Create file and check that it contains zeros
131          throughout the created length. */
132       MUST_SUCCEED (filesys_create ("foo", sizeof s));
133       MUST_SUCCEED ((file = filesys_open ("foo")) != NULL);
134       MUST_SUCCEED (file_read (file, s2, sizeof s2) == sizeof s2);
135       MUST_SUCCEED (memcmp (s2, zeros, sizeof s) == 0);
136       MUST_SUCCEED (file_tell (file) == sizeof s);
137       MUST_SUCCEED (file_length (file) == sizeof s);
138       file_close (file);
139
140       /* Reopen file and write to it. */
141       MUST_SUCCEED ((file = filesys_open ("foo")) != NULL);
142       MUST_SUCCEED (file_write (file, s, sizeof s) == sizeof s);
143       MUST_SUCCEED (file_tell (file) == sizeof s);
144       MUST_SUCCEED (file_length (file) == sizeof s);
145       file_close (file);
146
147       /* Reopen file and verify that it reads back correctly.
148          Delete file while open to check proper semantics. */
149       MUST_SUCCEED ((file = filesys_open ("foo")) != NULL);
150       MUST_SUCCEED (filesys_remove ("foo"));
151       MUST_SUCCEED (filesys_open ("foo") == NULL);
152       MUST_SUCCEED (file_read (file, s2, sizeof s) == sizeof s);
153       MUST_SUCCEED (memcmp (s, s2, sizeof s) == 0);
154       MUST_SUCCEED (file_tell (file) == sizeof s);
155       MUST_SUCCEED (file_length (file) == sizeof s);
156       file_close (file);
157     }
158   
159   printf ("filesys: self test ok\n");
160 }
161
162 /* If SUCCESS is false, panics with an error complaining about
163    LINE_NO. */
164 static void 
165 must_succeed_function (int line_no, bool success) 
166 {
167   if (!success)
168     PANIC ("filesys_self_test: operation failed on line %d", line_no);
169 }
170 \f
171 /* Formats the filesystem. */
172 static void
173 do_format (void)
174 {
175   printf ("Formatting filesystem...");
176   free_map_create ();
177   if (!dir_create (ROOT_DIR_SECTOR, 16))
178     PANIC ("root directory creation failed");
179   free_map_close ();
180   printf ("done.\n");
181 }