X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?p=pintos-anon;a=blobdiff_plain;f=src%2Ffilesys%2Ffsutil.c;h=5f045d64a5ad076f02d686007687d0a93a082f90;hp=67dab6fdc59768fd4587a47f379308f24a525865;hb=bb0485f5561709b2d9a97fdeda9bfa1bd55a20c9;hpb=97dcefb4742e13df9eb22c3aa00bb802bdc55c60 diff --git a/src/filesys/fsutil.c b/src/filesys/fsutil.c index 67dab6f..5f045d6 100644 --- a/src/filesys/fsutil.c +++ b/src/filesys/fsutil.c @@ -1,124 +1,223 @@ -#include "fsutil.h" -#include -#include "debug.h" -#include "filesys.h" -#include "file.h" -#include "lib.h" -#include "mmu.h" -#include "palloc.h" - -/* Filename and file size to use for copy operations, - as "filename:size". */ -char *fsutil_copy_arg; - -/* Name of a file print to print to console. */ -char *fsutil_print_file; - -/* Name of a file to delete. */ -char *fsutil_remove_file; - -/* List all files in the filesystem to the system console? */ -bool fsutil_list_files; - -/* Dump full contents of filesystem to the system console? */ -bool fsutil_dump_filesys; - -/* Copies from the "scratch" disk, hdc or hd1:0, - to a file named FILENAME in the filesystem. - The file will be SIZE bytes in length. */ -static void -copy (const char *filename, off_t size) +#include "filesys/fsutil.h" +#include +#include +#include +#include +#include +#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); + dir_close (dir); + 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 %lld-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 %lld 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); } -/* Executes the filesystem operations described by the variables - declared in fsutil.h. */ +/* 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"); - if (fsutil_remove_file != NULL) + printf ("Extracting ustar archive from scratch device " + "into file system...\n"); + + 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 (); - - if (fsutil_dump_filesys) - filesys_dump (); + /* 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); } -/* Prints the contents of file FILENAME to the system console as - hex and ASCII. */ +/* 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; + + printf ("Appending '%s' to ustar archive on scratch device...\n", file_name); - hex_dump (buffer, n, true); + /* 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); }