-#include "fsutil.h"
-#include <stdbool.h>
-#include "debug.h"
-#include "filesys.h"
-#include "file.h"
-#include "lib.h"
-#include "mmu.h"
-#include "palloc.h"
-
-char *fsutil_copy_arg;
-char *fsutil_print_file;
-char *fsutil_remove_file;
-bool fsutil_list_files;
-bool fsutil_dump_filesys;
-
-static void
-copy (const char *filename, off_t size)
+#include "filesys/fsutil.h"
+#include <debug.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 "threads/malloc.h"
+#include "threads/palloc.h"
+#include "threads/vaddr.h"
+
+/* List files in the root directory. */
+void
+fsutil_ls (char **argv UNUSED)
{
- struct disk *src;
- struct file dst;
- disk_sector_t sector;
- void *buffer;
+ struct dir *dir;
+ char name[NAME_MAX + 1];
+
+ printf ("Files in the root directory:\n");
+ dir = dir_open_root ();
+ if (dir == NULL)
+ PANIC ("root dir open failed");
+ while (dir_readdir (dir, name))
+ printf ("%s\n", name);
+ printf ("End of listing.\n");
+}
- /* Open source disk. */
- src = disk_get (1, 0);
- if (src == NULL)
- PANIC ("couldn't open source disk (hdc or hd1:0)");
- if (size > (off_t) disk_size (src) * DISK_SECTOR_SIZE)
- PANIC ("source disk is too small for %Ld-byte file",
- (unsigned long long) size);
+/* Prints the contents of file ARGV[1] to the system console as
+ hex and ASCII. */
+void
+fsutil_cat (char **argv)
+{
+ const char *file_name = argv[1];
- /* Create destination file. */
- if (!filesys_create (filename, size))
- PANIC ("%s: create failed", filename);
- if (!filesys_open (filename, &dst))
- PANIC ("%s: open failed", filename);
+ struct file *file;
+ char *buffer;
- /* Do copy. */
- buffer = palloc_get (PAL_ASSERT);
- sector = 0;
- while (size > 0)
+ printf ("Printing '%s' to the console...\n", file_name);
+ file = filesys_open (file_name);
+ if (file == NULL)
+ PANIC ("%s: open failed", file_name);
+ buffer = palloc_get_page (PAL_ASSERT);
+ 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 %Ld bytes unwritten",
- filename, (unsigned long long) size);
- size -= chunk_size;
+ off_t pos = file_tell (file);
+ off_t n = file_read (file, buffer, PGSIZE);
+ if (n == 0)
+ break;
+
+ hex_dump (pos, buffer, n, true);
}
- palloc_free (buffer);
+ palloc_free_page (buffer);
+ file_close (file);
+}
- file_close (&dst);
+/* Deletes file ARGV[1]. */
+void
+fsutil_rm (char **argv)
+{
+ const char *file_name = argv[1];
+
+ printf ("Deleting '%s'...\n", file_name);
+ if (!filesys_remove (file_name))
+ PANIC ("%s: delete failed\n", file_name);
}
+/* Extracts a ustar-format tar archive from the scratch block
+ device into the Pintos file system. */
void
-fsutil_run (void)
+fsutil_extract (char **argv UNUSED)
{
- if (fsutil_copy_arg != NULL)
- {
- char *save;
- char *filename = strtok_r (fsutil_copy_arg, ":", &save);
- char *size = strtok_r (NULL, "", &save);
+ static block_sector_t sector = 0;
- if (filename == NULL || size == NULL)
- PANIC ("bad format for -cp option; use -u for usage");
+ struct block *src;
+ void *header, *data;
- copy (filename, atoi (size));
- }
+ /* Allocate buffers. */
+ header = malloc (BLOCK_SECTOR_SIZE);
+ data = malloc (BLOCK_SECTOR_SIZE);
+ if (header == NULL || data == NULL)
+ PANIC ("couldn't allocate buffers");
- if (fsutil_print_file != NULL)
- fsutil_print (fsutil_print_file);
+ /* Open source block device. */
+ src = block_get_role (BLOCK_SCRATCH);
+ if (src == NULL)
+ PANIC ("couldn't open scratch device");
+
+ printf ("Extracting ustar archive from scratch device "
+ "into file system...\n");
- if (fsutil_remove_file != NULL)
+ for (;;)
{
- if (filesys_remove (fsutil_remove_file))
- printk ("%s: removed\n", fsutil_remove_file);
- else
- PANIC ("%s: remove failed\n", fsutil_remove_file);
+ 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);
+ }
}
- if (fsutil_list_files)
- filesys_list ();
+ /* 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);
- if (fsutil_dump_filesys)
- filesys_dump ();
+ free (data);
+ free (header);
}
+/* 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 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_print (const char *filename)
+fsutil_append (char **argv)
{
- struct file file;
- char *buffer;
+ static block_sector_t sector = 0;
- if (!filesys_open (filename, &file))
- PANIC ("%s: open failed", filename);
- buffer = palloc_get (PAL_ASSERT);
- for (;;)
- {
- off_t n = file_read (&file, buffer, PGSIZE);
- if (n == 0)
- break;
+ const char *file_name = argv[1];
+ void *buffer;
+ struct file *src;
+ struct block *dst;
+ off_t size;
- hex_dump (buffer, n, true);
+ printf ("Appending '%s' to ustar archive on scratch device...\n", file_name);
+
+ /* Allocate buffer. */
+ buffer = malloc (BLOCK_SECTOR_SIZE);
+ if (buffer == NULL)
+ PANIC ("couldn't allocate buffer");
+
+ /* Open source file. */
+ src = filesys_open (file_name);
+ if (src == NULL)
+ PANIC ("%s: open failed", file_name);
+ size = file_length (src);
+
+ /* Open target block device. */
+ dst = block_get_role (BLOCK_SCRATCH);
+ if (dst == NULL)
+ 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 > 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", file_name, size);
+ memset (buffer + chunk_size, 0, BLOCK_SECTOR_SIZE - chunk_size);
+ block_write (dst, sector++, buffer);
+ size -= chunk_size;
}
- palloc_free (buffer);
- file_close (&file);
+
+ /* 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);
}