Applied patch set 6 by Ben, derived from Anthony's megapatch, and minor
[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   printf ("End of listing.\n");
28 }
29
30 /* Prints the contents of file ARGV[1] to the system console as
31    hex and ASCII. */
32 void
33 fsutil_cat (char **argv)
34 {
35   const char *file_name = argv[1];
36   
37   struct file *file;
38   char *buffer;
39
40   printf ("Printing '%s' to the console...\n", file_name);
41   file = filesys_open (file_name);
42   if (file == NULL)
43     PANIC ("%s: open failed", file_name);
44   buffer = palloc_get_page (PAL_ASSERT);
45   for (;;) 
46     {
47       off_t pos = file_tell (file);
48       off_t n = file_read (file, buffer, PGSIZE);
49       if (n == 0)
50         break;
51
52       hex_dump (pos, buffer, n, true); 
53     }
54   palloc_free_page (buffer);
55   file_close (file);
56 }
57
58 /* Deletes file ARGV[1]. */
59 void
60 fsutil_rm (char **argv) 
61 {
62   const char *file_name = argv[1];
63   
64   printf ("Deleting '%s'...\n", file_name);
65   if (!filesys_remove (file_name))
66     PANIC ("%s: delete failed\n", file_name);
67 }
68
69 /* Extracts a ustar-format tar archive from the scratch device
70    into the Pintos file system. */
71 void
72 fsutil_extract (char **argv UNUSED)
73 {
74   static block_sector_t sector = 0;
75
76   struct block *src;
77   void *header, *data;
78
79   /* Allocate buffers. */
80   header = malloc (BLOCK_SECTOR_SIZE);
81   data = malloc (BLOCK_SECTOR_SIZE);
82   if (header == NULL || data == NULL)
83     PANIC ("couldn't allocate buffers");
84
85   /* Open source device. */
86   src = block_get_role (BLOCK_SCRATCH);
87   if (src == NULL)
88     PANIC ("couldn't open scratch device");
89
90   printf ("Extracting ustar archive from %s into file system...\n",
91           block_name (src));
92
93   for (;;)
94     {
95       const char *file_name;
96       const char *error;
97       enum ustar_type type;
98       int size;
99
100       /* Read and parse ustar header. */
101       block_read (src, sector++, header);
102       error = ustar_parse_header (header, &file_name, &type, &size);
103       if (error != NULL)
104         PANIC ("%s: bad ustar header in sector %"PRDSNu" (%s)",
105                block_name (src), 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 %"PROTd" 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 device, so that
146      the extraction operation is idempotent.  We erase two blocks
147      because two blocks of zeros are the ustar end-of-archive
148      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 Pintos file system to a 
159    ustar-format tar archive maintained on the scratch device.
160
161    The first call to this function will write starting at the
162    beginning of the scratch device, thus creating a new archive.  
163    Therefore, any `extract' calls must precede all `append's.
164    Later calls advance across the device, appending to the 
165    archive. */
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 ("Getting '%s' from the file system...\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 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: can't get from file system (name too long)", 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 get. */
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 }