Use standard POSIX "ustar" format for the scratch disk.
[pintos-anon] / src / filesys / fsutil.c
index 14a45079c7a65d74166b8cd2b720fb6c9b10dfbe..bf2c15466af77514211de9ca9e79b54f677ed905 100644 (file)
@@ -3,6 +3,7 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <ustar.h>
 #include "filesys/directory.h"
 #include "filesys/file.h"
 #include "filesys/filesys.h"
 #include "filesys/directory.h"
 #include "filesys/file.h"
 #include "filesys/filesys.h"
@@ -66,85 +67,103 @@ fsutil_rm (char **argv)
     PANIC ("%s: delete failed\n", file_name);
 }
 
     PANIC ("%s: delete failed\n", file_name);
 }
 
-/* Copies from the "scratch" disk, hdc or hd1:0 to file ARGV[1]
-   in the file system.
-
-   The current sector on the scratch disk must begin with the
-   string "PUT\0" followed by a 32-bit little-endian integer
-   indicating the file size in bytes.  Subsequent sectors hold
-   the file content.
-
-   The first call to this function will read starting at the
-   beginning of the scratch disk.  Later calls advance across the
-   disk.  This disk position is independent of that used for
-   fsutil_get(), so all `put's should precede all `get's. */
+/* Extracts a ustar-format tar archive from the scratch disk, hdc
+   or hd1:0, into the Pintos file system. */
 void
 void
-fsutil_put (char **argv
+fsutil_extract (char **argv UNUSED
 {
   static disk_sector_t sector = 0;
 
 {
   static disk_sector_t sector = 0;
 
-  const char *file_name = argv[1];
   struct disk *src;
   struct disk *src;
-  struct file *dst;
-  off_t size;
-  void *buffer;
+  void *header, *data;
 
 
-  printf ("Putting '%s' into the file system...\n", file_name);
+  /* Allocate buffers. */
+  header = malloc (DISK_SECTOR_SIZE);
+  data = malloc (DISK_SECTOR_SIZE);
+  if (header == NULL || data == NULL)
+    PANIC ("couldn't allocate buffers");
 
 
-  /* Allocate buffer. */
-  buffer = malloc (DISK_SECTOR_SIZE);
-  if (buffer == NULL)
-    PANIC ("couldn't allocate buffer");
-
-  /* Open source disk and read file size. */
+  /* Open source disk. */
   src = disk_get (1, 0);
   if (src == NULL)
   src = disk_get (1, 0);
   if (src == NULL)
-    PANIC ("couldn't open source disk (hdc or hd1:0)");
-
-  /* Read file size. */
-  disk_read (src, sector++, buffer);
-  if (memcmp (buffer, "PUT", 4))
-    PANIC ("%s: missing PUT signature on scratch disk", file_name);
-  size = ((int32_t *) buffer)[1];
-  if (size < 0)
-    PANIC ("%s: invalid file size %d", file_name, size);
-  
-  /* Create destination file. */
-  if (!filesys_create (file_name, size))
-    PANIC ("%s: create failed", file_name);
-  dst = filesys_open (file_name);
-  if (dst == NULL)
-    PANIC ("%s: open failed", file_name);
+    PANIC ("couldn't open scratch disk (hdc or hd1:0)");
 
 
-  /* Do copy. */
-  while (size > 0)
+  printf ("Extracting ustar archive from scratch disk into file system...\n");
+
+  for (;;)
     {
     {
-      int chunk_size = size > DISK_SECTOR_SIZE ? DISK_SECTOR_SIZE : size;
-      disk_read (src, sector++, buffer);
-      if (file_write (dst, buffer, chunk_size) != chunk_size)
-        PANIC ("%s: write failed with %"PROTd" bytes unwritten",
-               file_name, size);
-      size -= chunk_size;
+      const char *file_name;
+      const char *error;
+      enum ustar_type type;
+      int size;
+
+      /* Read and parse ustar header. */
+      disk_read (src, sector++, header);
+      error = ustar_parse_header (header, &file_name, &type, &size);
+      if (error != NULL)
+        PANIC ("bad ustar header in sector %"PRDSNu" (%s)", sector - 1, error);
+
+      if (type == USTAR_EOF)
+        {
+          /* End of archive. */
+          break;
+        }
+      else if (type == USTAR_DIRECTORY)
+        printf ("ignoring directory %s\n", file_name);
+      else if (type == USTAR_REGULAR)
+        {
+          struct file *dst;
+
+          printf ("Putting '%s' into the file system...\n", file_name);
+
+          /* Create destination file. */
+          if (!filesys_create (file_name, size))
+            PANIC ("%s: create failed", file_name);
+          dst = filesys_open (file_name);
+          if (dst == NULL)
+            PANIC ("%s: open failed", file_name);
+
+          /* Do copy. */
+          while (size > 0)
+            {
+              int chunk_size = (size > DISK_SECTOR_SIZE
+                                ? DISK_SECTOR_SIZE
+                                : size);
+              disk_read (src, sector++, data);
+              if (file_write (dst, data, chunk_size) != chunk_size)
+                PANIC ("%s: write failed with %d bytes unwritten",
+                       file_name, size);
+              size -= chunk_size;
+            }
+
+          /* Finish up. */
+          file_close (dst);
+        }
     }
 
     }
 
-  /* Finish up. */
-  file_close (dst);
-  free (buffer);
+  /* Erase the ustar header from the start of the disk, so that
+     the extraction operation is idempotent.  We erase two blocks
+     because two blocks of zeros are the ustar end-of-archive
+     marker. */
+  printf ("Erasing ustar archive...\n");
+  memset (header, 0, DISK_SECTOR_SIZE);
+  disk_write (src, 0, header);
+  disk_write (src, 1, header);
+
+  free (data);
+  free (header);
 }
 
 }
 
-/* Copies file FILE_NAME from the file system to the scratch disk.
-
-   The current sector on the scratch disk will receive "GET\0"
-   followed by the file's size in bytes as a 32-bit,
-   little-endian integer.  Subsequent sectors receive the file's
-   data.
+/* Copies file FILE_NAME from the file system to the scratch
+   disk, in ustar format.
 
    The first call to this function will write starting at the
    beginning of the scratch disk.  Later calls advance across the
 
    The first call to this function will write starting at the
    beginning of the scratch disk.  Later calls advance across the
-   disk.  This disk position is independent of that used for
-   fsutil_put(), so all `put's should precede all `get's. */
+   disk.  This position is independent of that used for
+   fsutil_extract(), so `extract' should precede all
+   `append's. */
 void
 void
-fsutil_get (char **argv)
+fsutil_append (char **argv)
 {
   static disk_sector_t sector = 0;
 
 {
   static disk_sector_t sector = 0;
 
@@ -154,7 +173,7 @@ fsutil_get (char **argv)
   struct disk *dst;
   off_t size;
 
   struct disk *dst;
   off_t size;
 
-  printf ("Getting '%s' from the file system...\n", file_name);
+  printf ("Appending '%s' to ustar archive on scratch disk...\n", file_name);
 
   /* Allocate buffer. */
   buffer = malloc (DISK_SECTOR_SIZE);
 
   /* Allocate buffer. */
   buffer = malloc (DISK_SECTOR_SIZE);
@@ -172,12 +191,11 @@ fsutil_get (char **argv)
   if (dst == NULL)
     PANIC ("couldn't open target disk (hdc or hd1:0)");
   
   if (dst == NULL)
     PANIC ("couldn't open target disk (hdc or hd1:0)");
   
-  /* Write size to sector 0. */
-  memset (buffer, 0, DISK_SECTOR_SIZE);
-  memcpy (buffer, "GET", 4);
-  ((int32_t *) buffer)[1] = size;
+  /* Write ustar header to first sector. */
+  if (!ustar_make_header (file_name, USTAR_REGULAR, size, buffer))
+    PANIC ("%s: name too long for ustar format", file_name);
   disk_write (dst, sector++, buffer);
   disk_write (dst, sector++, buffer);
-  
+
   /* Do copy. */
   while (size > 0) 
     {
   /* Do copy. */
   while (size > 0) 
     {
@@ -191,6 +209,13 @@ fsutil_get (char **argv)
       size -= chunk_size;
     }
 
       size -= chunk_size;
     }
 
+  /* Write ustar end-of-archive marker, which is two consecutive
+     sectors full of zeros.  Don't advance our position past
+     them, though, in case we have more files to append. */
+  memset (buffer, 0, DISK_SECTOR_SIZE);
+  disk_write (dst, sector, buffer);
+  disk_write (dst, sector, buffer + 1);
+
   /* Finish up. */
   file_close (src);
   free (buffer);
   /* Finish up. */
   file_close (src);
   free (buffer);