#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 "devices/disk.h"
-#include "threads/mmu.h"
#include "threads/malloc.h"
#include "threads/palloc.h"
+#include "threads/vaddr.h"
/* List files in the root directory. */
void
fsutil_ls (char **argv UNUSED)
{
+ struct dir *dir;
+ char name[NAME_MAX + 1];
+
printf ("Files in the root directory:\n");
- filesys_list ();
+ dir = dir_open_root ();
+ if (dir == NULL)
+ PANIC ("root dir open failed");
+ while (dir_readdir (dir, name))
+ printf ("%s\n", name);
+ dir_close (dir);
printf ("End of listing.\n");
}
void
fsutil_cat (char **argv)
{
- const char *filename = argv[1];
+ const char *file_name = argv[1];
struct file *file;
char *buffer;
- printf ("Printing '%s' to the console...\n", filename);
- file = filesys_open (filename);
+ printf ("Printing '%s' to the console...\n", file_name);
+ file = filesys_open (file_name);
if (file == NULL)
- PANIC ("%s: open failed", filename);
+ PANIC ("%s: open failed", file_name);
buffer = palloc_get_page (PAL_ASSERT);
for (;;)
{
void
fsutil_rm (char **argv)
{
- const char *filename = argv[1];
+ const char *file_name = argv[1];
- printf ("Deleting '%s'...\n", filename);
- if (!filesys_remove (filename))
- PANIC ("%s: delete failed\n", filename);
+ printf ("Deleting '%s'...\n", file_name);
+ if (!filesys_remove (file_name))
+ PANIC ("%s: delete failed\n", file_name);
}
-/* Copies from the "scratch" disk, hdc or hd1:0 to file ARGV[1]
- in the filesystem.
-
- 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 block
+ device into the Pintos file system. */
void
-fsutil_put (char **argv)
+fsutil_extract (char **argv UNUSED)
{
- static disk_sector_t sector = 0;
-
- const char *filename = argv[1];
- struct disk *src;
- struct file *dst;
- off_t size;
- void *buffer;
+ static block_sector_t sector = 0;
- printf ("Putting '%s' into the file system...\n", filename);
+ struct block *src;
+ void *header, *data;
- /* Allocate buffer. */
- buffer = malloc (DISK_SECTOR_SIZE);
- if (buffer == NULL)
- PANIC ("couldn't allocate buffer");
+ /* Allocate buffers. */
+ header = malloc (BLOCK_SECTOR_SIZE);
+ data = malloc (BLOCK_SECTOR_SIZE);
+ if (header == NULL || data == NULL)
+ PANIC ("couldn't allocate buffers");
- /* Open source disk and read file size. */
- src = disk_get (1, 0);
+ /* Open source block device. */
+ src = block_get_role (BLOCK_SCRATCH);
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", filename);
- size = ((int32_t *) buffer)[1];
- if (size < 0)
- PANIC ("%s: invalid file size %d", filename, size);
-
- /* Create destination file. */
- if (!filesys_create (filename, size))
- PANIC ("%s: create failed", filename);
- dst = filesys_open (filename);
- if (dst == NULL)
- PANIC ("%s: open failed", filename);
+ PANIC ("couldn't open scratch device");
- /* Do copy. */
- while (size > 0)
+ printf ("Extracting ustar archive from scratch device "
+ "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",
- filename, size);
- size -= chunk_size;
+ const char *file_name;
+ const char *error;
+ enum ustar_type type;
+ int size;
+
+ /* Read and parse ustar header. */
+ block_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 > BLOCK_SECTOR_SIZE
+ ? BLOCK_SECTOR_SIZE
+ : size);
+ block_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 block device,
+ 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, BLOCK_SECTOR_SIZE);
+ block_write (src, 0, header);
+ block_write (src, 1, header);
+
+ free (data);
+ free (header);
}
-/* Copies file FILENAME 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
+ device, in ustar format.
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. */
+ beginning of the scratch device. Later calls advance across
+ the device. This position is independent of that used for
+ fsutil_extract(), so `extract' should precede all
+ `append's. */
void
-fsutil_get (char **argv)
+fsutil_append (char **argv)
{
- static disk_sector_t sector = 0;
+ static block_sector_t sector = 0;
- const char *filename = argv[1];
+ const char *file_name = argv[1];
void *buffer;
struct file *src;
- struct disk *dst;
+ struct block *dst;
off_t size;
- printf ("Getting '%s' from the file system...\n", filename);
+ printf ("Appending '%s' to ustar archive on scratch device...\n", file_name);
/* Allocate buffer. */
- buffer = malloc (DISK_SECTOR_SIZE);
+ buffer = malloc (BLOCK_SECTOR_SIZE);
if (buffer == NULL)
PANIC ("couldn't allocate buffer");
/* Open source file. */
- src = filesys_open (filename);
+ src = filesys_open (file_name);
if (src == NULL)
- PANIC ("%s: open failed", filename);
+ PANIC ("%s: open failed", file_name);
size = file_length (src);
- /* Open target disk. */
- dst = disk_get (1, 0);
+ /* Open target block device. */
+ dst = block_get_role (BLOCK_SCRATCH);
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;
- disk_write (dst, sector++, buffer);
+ PANIC ("couldn't open scratch device");
+ /* 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);
+ block_write (dst, sector++, buffer);
+
/* Do copy. */
while (size > 0)
{
- int chunk_size = size > DISK_SECTOR_SIZE ? DISK_SECTOR_SIZE : size;
- if (sector >= disk_size (dst))
- PANIC ("%s: out of space on scratch disk", filename);
+ int chunk_size = size > BLOCK_SECTOR_SIZE ? BLOCK_SECTOR_SIZE : size;
+ if (sector >= block_size (dst))
+ PANIC ("%s: out of space on scratch device", file_name);
if (file_read (src, buffer, chunk_size) != chunk_size)
- PANIC ("%s: read failed with %"PROTd" bytes unread", filename, size);
- memset (buffer + chunk_size, 0, DISK_SECTOR_SIZE - chunk_size);
- disk_write (dst, sector++, buffer);
+ PANIC ("%s: read failed with %"PROTd" bytes unread", file_name, size);
+ memset (buffer + chunk_size, 0, BLOCK_SECTOR_SIZE - chunk_size);
+ block_write (dst, sector++, buffer);
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, BLOCK_SECTOR_SIZE);
+ block_write (dst, sector, buffer);
+ block_write (dst, sector, buffer + 1);
+
/* Finish up. */
file_close (src);
free (buffer);