Make tests public. Rewrite most tests. Add tests.
[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   struct dir *dir;
50   disk_sector_t inode_sector = 0;
51   bool success = (dir_open_root (&dir)
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;
71   struct inode *inode = NULL;
72
73   if (dir_open_root (&dir))
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 = NULL;
88   bool success = (dir_open_root (&dir)
89                   && dir_remove (dir, name));
90   dir_close (dir); 
91
92   return success;
93 }
94
95 /* Prints a list of files in the filesystem to the system
96    console.
97    Returns true if successful, false on failure,
98    which occurs only if an internal memory allocation fails. */
99 bool
100 filesys_list (void) 
101 {
102   struct dir *dir = NULL;
103   bool success = dir_open_root (&dir);
104   if (success)
105     dir_list (dir);
106   dir_close (dir);
107
108   return success;
109 }
110 \f
111 static void must_succeed_function (int, bool) NO_INLINE;
112 #define MUST_SUCCEED(EXPR) must_succeed_function (__LINE__, EXPR)
113
114 /* Performs basic sanity checks on the filesystem.
115    The filesystem should not contain a file named `foo' when
116    called. */
117 void
118 filesys_self_test (void)
119 {
120   static const char s[] = "This is a test string.";
121   static const char zeros[sizeof s] = {0};
122   struct file *file;
123   char s2[sizeof s];
124   int i;
125
126   filesys_remove ("foo");
127   for (i = 0; i < 2; i++) 
128     {
129       /* Create file and check that it contains zeros
130          throughout the created length. */
131       MUST_SUCCEED (filesys_create ("foo", sizeof s));
132       MUST_SUCCEED ((file = filesys_open ("foo")) != NULL);
133       MUST_SUCCEED (file_read (file, s2, sizeof s2) == sizeof s2);
134       MUST_SUCCEED (memcmp (s2, zeros, sizeof s) == 0);
135       MUST_SUCCEED (file_tell (file) == sizeof s);
136       MUST_SUCCEED (file_length (file) == sizeof s);
137       file_close (file);
138
139       /* Reopen file and write to it. */
140       MUST_SUCCEED ((file = filesys_open ("foo")) != NULL);
141       MUST_SUCCEED (file_write (file, s, sizeof s) == sizeof s);
142       MUST_SUCCEED (file_tell (file) == sizeof s);
143       MUST_SUCCEED (file_length (file) == sizeof s);
144       file_close (file);
145
146       /* Reopen file and verify that it reads back correctly.
147          Delete file while open to check proper semantics. */
148       MUST_SUCCEED ((file = filesys_open ("foo")) != NULL);
149       MUST_SUCCEED (filesys_remove ("foo"));
150       MUST_SUCCEED (filesys_open ("foo") == NULL);
151       MUST_SUCCEED (file_read (file, s2, sizeof s) == sizeof s);
152       MUST_SUCCEED (memcmp (s, s2, sizeof s) == 0);
153       MUST_SUCCEED (file_tell (file) == sizeof s);
154       MUST_SUCCEED (file_length (file) == sizeof s);
155       file_close (file);
156     }
157   
158   printf ("filesys: self test ok\n");
159 }
160
161 /* If SUCCESS is false, panics with an error complaining about
162    LINE_NO. */
163 static void 
164 must_succeed_function (int line_no, bool success) 
165 {
166   if (!success)
167     PANIC ("filesys_self_test: operation failed on line %d", line_no);
168 }
169 \f
170 /* Formats the filesystem. */
171 static void
172 do_format (void)
173 {
174   printf ("Formatting filesystem...");
175   free_map_create ();
176   if (!dir_create (ROOT_DIR_SECTOR, 16))
177     PANIC ("root directory creation failed");
178   free_map_close ();
179   printf ("done.\n");
180 }