Fsutil_ls must close the directory after reading it
[pintos-anon] / src / filesys / fsutil.c
1 #include "filesys/fsutil.h"
2 #include <debug.h>
3 #include <stdio.h>
4 #include <stdlib.h>
5 #include <string.h>
6 #include <ustar.h>
7 #include "filesys/directory.h"
8 #include "filesys/file.h"
9 #include "filesys/filesys.h"
10 #include "threads/malloc.h"
11 #include "threads/palloc.h"
12 #include "threads/vaddr.h"
13
14 /* List files in the root directory. */
15 void
16 fsutil_ls (char **argv UNUSED) 
17 {
18   struct dir *dir;
19   char name[NAME_MAX + 1];
20   
21   printf ("Files in the root directory:\n");
22   dir = dir_open_root ();
23   if (dir == NULL)
24     PANIC ("root dir open failed");
25   while (dir_readdir (dir, name))
26     printf ("%s\n", name);
27   dir_close (dir);
28   printf ("End of listing.\n");
29 }
30
31 /* Prints the contents of file ARGV[1] to the system console as
32    hex and ASCII. */
33 void
34 fsutil_cat (char **argv)
35 {
36   const char *file_name = argv[1];
37   
38   struct file *file;
39   char *buffer;
40
41   printf ("Printing '%s' to the console...\n", file_name);
42   file = filesys_open (file_name);
43   if (file == NULL)
44     PANIC ("%s: open failed", file_name);
45   buffer = palloc_get_page (PAL_ASSERT);
46   for (;;) 
47     {
48       off_t pos = file_tell (file);
49       off_t n = file_read (file, buffer, PGSIZE);
50       if (n == 0)
51         break;
52
53       hex_dump (pos, buffer, n, true); 
54     }
55   palloc_free_page (buffer);
56   file_close (file);
57 }
58
59 /* Deletes file ARGV[1]. */
60 void
61 fsutil_rm (char **argv) 
62 {
63   const char *file_name = argv[1];
64   
65   printf ("Deleting '%s'...\n", file_name);
66   if (!filesys_remove (file_name))
67     PANIC ("%s: delete failed\n", file_name);
68 }
69
70 /* Extracts a ustar-format tar archive from the scratch block
71    device into the Pintos file system. */
72 void
73 fsutil_extract (char **argv UNUSED) 
74 {
75   static block_sector_t sector = 0;
76
77   struct block *src;
78   void *header, *data;
79
80   /* Allocate buffers. */
81   header = malloc (BLOCK_SECTOR_SIZE);
82   data = malloc (BLOCK_SECTOR_SIZE);
83   if (header == NULL || data == NULL)
84     PANIC ("couldn't allocate buffers");
85
86   /* Open source block device. */
87   src = block_get_role (BLOCK_SCRATCH);
88   if (src == NULL)
89     PANIC ("couldn't open scratch device");
90
91   printf ("Extracting ustar archive from scratch device "
92           "into file system...\n");
93
94   for (;;)
95     {
96       const char *file_name;
97       const char *error;
98       enum ustar_type type;
99       int size;
100
101       /* Read and parse ustar header. */
102       block_read (src, sector++, header);
103       error = ustar_parse_header (header, &file_name, &type, &size);
104       if (error != NULL)
105         PANIC ("bad ustar header in sector %"PRDSNu" (%s)", sector - 1, error);
106
107       if (type == USTAR_EOF)
108         {
109           /* End of archive. */
110           break;
111         }
112       else if (type == USTAR_DIRECTORY)
113         printf ("ignoring directory %s\n", file_name);
114       else if (type == USTAR_REGULAR)
115         {
116           struct file *dst;
117
118           printf ("Putting '%s' into the file system...\n", file_name);
119
120           /* Create destination file. */
121           if (!filesys_create (file_name, size))
122             PANIC ("%s: create failed", file_name);
123           dst = filesys_open (file_name);
124           if (dst == NULL)
125             PANIC ("%s: open failed", file_name);
126
127           /* Do copy. */
128           while (size > 0)
129             {
130               int chunk_size = (size > BLOCK_SECTOR_SIZE
131                                 ? BLOCK_SECTOR_SIZE
132                                 : size);
133               block_read (src, sector++, data);
134               if (file_write (dst, data, chunk_size) != chunk_size)
135                 PANIC ("%s: write failed with %d bytes unwritten",
136                        file_name, size);
137               size -= chunk_size;
138             }
139
140           /* Finish up. */
141           file_close (dst);
142         }
143     }
144
145   /* Erase the ustar header from the start of the block device,
146      so that the extraction operation is idempotent.  We erase
147      two blocks because two blocks of zeros are the ustar
148      end-of-archive marker. */
149   printf ("Erasing ustar archive...\n");
150   memset (header, 0, BLOCK_SECTOR_SIZE);
151   block_write (src, 0, header);
152   block_write (src, 1, header);
153
154   free (data);
155   free (header);
156 }
157
158 /* Copies file FILE_NAME from the file system to the scratch
159    device, in ustar format.
160
161    The first call to this function will write starting at the
162    beginning of the scratch device.  Later calls advance across
163    the device.  This position is independent of that used for
164    fsutil_extract(), so `extract' should precede all
165    `append's. */
166 void
167 fsutil_append (char **argv)
168 {
169   static block_sector_t sector = 0;
170
171   const char *file_name = argv[1];
172   void *buffer;
173   struct file *src;
174   struct block *dst;
175   off_t size;
176
177   printf ("Appending '%s' to ustar archive on scratch device...\n", file_name);
178
179   /* Allocate buffer. */
180   buffer = malloc (BLOCK_SECTOR_SIZE);
181   if (buffer == NULL)
182     PANIC ("couldn't allocate buffer");
183
184   /* Open source file. */
185   src = filesys_open (file_name);
186   if (src == NULL)
187     PANIC ("%s: open failed", file_name);
188   size = file_length (src);
189
190   /* Open target block device. */
191   dst = block_get_role (BLOCK_SCRATCH);
192   if (dst == NULL)
193     PANIC ("couldn't open scratch device");
194   
195   /* Write ustar header to first sector. */
196   if (!ustar_make_header (file_name, USTAR_REGULAR, size, buffer))
197     PANIC ("%s: name too long for ustar format", file_name);
198   block_write (dst, sector++, buffer);
199
200   /* Do copy. */
201   while (size > 0) 
202     {
203       int chunk_size = size > BLOCK_SECTOR_SIZE ? BLOCK_SECTOR_SIZE : size;
204       if (sector >= block_size (dst))
205         PANIC ("%s: out of space on scratch device", file_name);
206       if (file_read (src, buffer, chunk_size) != chunk_size)
207         PANIC ("%s: read failed with %"PROTd" bytes unread", file_name, size);
208       memset (buffer + chunk_size, 0, BLOCK_SECTOR_SIZE - chunk_size);
209       block_write (dst, sector++, buffer);
210       size -= chunk_size;
211     }
212
213   /* Write ustar end-of-archive marker, which is two consecutive
214      sectors full of zeros.  Don't advance our position past
215      them, though, in case we have more files to append. */
216   memset (buffer, 0, BLOCK_SECTOR_SIZE);
217   block_write (dst, sector, buffer);
218   block_write (dst, sector, buffer + 1);
219
220   /* Finish up. */
221   file_close (src);
222   free (buffer);
223 }