Use standard POSIX "ustar" format for the scratch disk.
[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 "devices/disk.h"
11 #include "threads/malloc.h"
12 #include "threads/palloc.h"
13 #include "threads/vaddr.h"
14
15 /* List files in the root directory. */
16 void
17 fsutil_ls (char **argv UNUSED) 
18 {
19   struct dir *dir;
20   char name[NAME_MAX + 1];
21   
22   printf ("Files in the root directory:\n");
23   dir = dir_open_root ();
24   if (dir == NULL)
25     PANIC ("root dir open failed");
26   while (dir_readdir (dir, name))
27     printf ("%s\n", name);
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 disk, hdc
71    or hd1:0, into the Pintos file system. */
72 void
73 fsutil_extract (char **argv UNUSED) 
74 {
75   static disk_sector_t sector = 0;
76
77   struct disk *src;
78   void *header, *data;
79
80   /* Allocate buffers. */
81   header = malloc (DISK_SECTOR_SIZE);
82   data = malloc (DISK_SECTOR_SIZE);
83   if (header == NULL || data == NULL)
84     PANIC ("couldn't allocate buffers");
85
86   /* Open source disk. */
87   src = disk_get (1, 0);
88   if (src == NULL)
89     PANIC ("couldn't open scratch disk (hdc or hd1:0)");
90
91   printf ("Extracting ustar archive from scratch disk into file system...\n");
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       disk_read (src, sector++, header);
102       error = ustar_parse_header (header, &file_name, &type, &size);
103       if (error != NULL)
104         PANIC ("bad ustar header in sector %"PRDSNu" (%s)", sector - 1, error);
105
106       if (type == USTAR_EOF)
107         {
108           /* End of archive. */
109           break;
110         }
111       else if (type == USTAR_DIRECTORY)
112         printf ("ignoring directory %s\n", file_name);
113       else if (type == USTAR_REGULAR)
114         {
115           struct file *dst;
116
117           printf ("Putting '%s' into the file system...\n", file_name);
118
119           /* Create destination file. */
120           if (!filesys_create (file_name, size))
121             PANIC ("%s: create failed", file_name);
122           dst = filesys_open (file_name);
123           if (dst == NULL)
124             PANIC ("%s: open failed", file_name);
125
126           /* Do copy. */
127           while (size > 0)
128             {
129               int chunk_size = (size > DISK_SECTOR_SIZE
130                                 ? DISK_SECTOR_SIZE
131                                 : size);
132               disk_read (src, sector++, data);
133               if (file_write (dst, data, chunk_size) != chunk_size)
134                 PANIC ("%s: write failed with %d bytes unwritten",
135                        file_name, size);
136               size -= chunk_size;
137             }
138
139           /* Finish up. */
140           file_close (dst);
141         }
142     }
143
144   /* Erase the ustar header from the start of the disk, so that
145      the extraction operation is idempotent.  We erase two blocks
146      because two blocks of zeros are the ustar end-of-archive
147      marker. */
148   printf ("Erasing ustar archive...\n");
149   memset (header, 0, DISK_SECTOR_SIZE);
150   disk_write (src, 0, header);
151   disk_write (src, 1, header);
152
153   free (data);
154   free (header);
155 }
156
157 /* Copies file FILE_NAME from the file system to the scratch
158    disk, in ustar format.
159
160    The first call to this function will write starting at the
161    beginning of the scratch disk.  Later calls advance across the
162    disk.  This position is independent of that used for
163    fsutil_extract(), so `extract' should precede all
164    `append's. */
165 void
166 fsutil_append (char **argv)
167 {
168   static disk_sector_t sector = 0;
169
170   const char *file_name = argv[1];
171   void *buffer;
172   struct file *src;
173   struct disk *dst;
174   off_t size;
175
176   printf ("Appending '%s' to ustar archive on scratch disk...\n", file_name);
177
178   /* Allocate buffer. */
179   buffer = malloc (DISK_SECTOR_SIZE);
180   if (buffer == NULL)
181     PANIC ("couldn't allocate buffer");
182
183   /* Open source file. */
184   src = filesys_open (file_name);
185   if (src == NULL)
186     PANIC ("%s: open failed", file_name);
187   size = file_length (src);
188
189   /* Open target disk. */
190   dst = disk_get (1, 0);
191   if (dst == NULL)
192     PANIC ("couldn't open target disk (hdc or hd1:0)");
193   
194   /* Write ustar header to first sector. */
195   if (!ustar_make_header (file_name, USTAR_REGULAR, size, buffer))
196     PANIC ("%s: name too long for ustar format", file_name);
197   disk_write (dst, sector++, buffer);
198
199   /* Do copy. */
200   while (size > 0) 
201     {
202       int chunk_size = size > DISK_SECTOR_SIZE ? DISK_SECTOR_SIZE : size;
203       if (sector >= disk_size (dst))
204         PANIC ("%s: out of space on scratch disk", file_name);
205       if (file_read (src, buffer, chunk_size) != chunk_size)
206         PANIC ("%s: read failed with %"PROTd" bytes unread", file_name, size);
207       memset (buffer + chunk_size, 0, DISK_SECTOR_SIZE - chunk_size);
208       disk_write (dst, sector++, buffer);
209       size -= chunk_size;
210     }
211
212   /* Write ustar end-of-archive marker, which is two consecutive
213      sectors full of zeros.  Don't advance our position past
214      them, though, in case we have more files to append. */
215   memset (buffer, 0, DISK_SECTOR_SIZE);
216   disk_write (dst, sector, buffer);
217   disk_write (dst, sector, buffer + 1);
218
219   /* Finish up. */
220   file_close (src);
221   free (buffer);
222 }