342 lines
12 KiB
C++
342 lines
12 KiB
C++
// filesys.cc
|
|
// Routines to manage the overall operation of the file system.
|
|
// Implements routines to map from textual file names to files.
|
|
//
|
|
// Each file in the file system has:
|
|
// A file header, stored in a sector on disk
|
|
// (the size of the file header data structure is arranged
|
|
// to be precisely the size of 1 disk sector)
|
|
// A number of data blocks
|
|
// An entry in the file system directory
|
|
//
|
|
// The file system consists of several data structures:
|
|
// A bitmap of free disk sectors (cf. bitmap.h)
|
|
// A directory of file names and file headers
|
|
//
|
|
// Both the bitmap and the directory are represented as normal
|
|
// files. Their file headers are located in specific sectors
|
|
// (sector 0 and sector 1), so that the file system can find them
|
|
// on bootup.
|
|
//
|
|
// The file system assumes that the bitmap and directory files are
|
|
// kept "open" continuously while Nachos is running.
|
|
//
|
|
// For those operations (such as Create, Remove) that modify the
|
|
// directory and/or bitmap, if the operation succeeds, the changes
|
|
// are written immediately back to disk (the two files are kept
|
|
// open during all this time). If the operation fails, and we have
|
|
// modified part of the directory and/or bitmap, we simply discard
|
|
// the changed version, without writing it back to disk.
|
|
//
|
|
// Our implementation at this point has the following restrictions:
|
|
//
|
|
// there is no synchronization for concurrent accesses
|
|
// files have a fixed size, set when the file is created
|
|
// files cannot be bigger than about 3KB in size
|
|
// there is no hierarchical directory structure, and only a limited
|
|
// number of files can be added to the system
|
|
// there is no attempt to make the system robust to failures
|
|
// (if Nachos exits in the middle of an operation that modifies
|
|
// the file system, it may corrupt the disk)
|
|
//
|
|
// Copyright (c) 1992-1993 The Regents of the University of California.
|
|
// All rights reserved. See copyright.h for copyright notice and limitation
|
|
// of liability and disclaimer of warranty provisions.
|
|
|
|
#include "copyright.h"
|
|
|
|
#include "disk.h"
|
|
#include "bitmap.h"
|
|
#include "directory.h"
|
|
#include "filehdr.h"
|
|
#include "filesys.h"
|
|
|
|
// Sectors containing the file headers for the bitmap of free sectors,
|
|
// and the directory of files. These file headers are placed in well-known
|
|
// sectors, so that they can be located on boot-up.
|
|
#define FreeMapSector 0
|
|
#define DirectorySector 1
|
|
|
|
// Initial file sizes for the bitmap and directory; until the file system
|
|
// supports extensible files, the directory size sets the maximum number
|
|
// of files that can be loaded onto the disk.
|
|
#define BitsInByte 8
|
|
#define FreeMapFileSize (NumSectors / BitsInByte)
|
|
#define NumDirEntries 10
|
|
#define DirectoryFileSize (sizeof(DirectoryEntry) * NumDirEntries)
|
|
|
|
//----------------------------------------------------------------------
|
|
// FileSystem::FileSystem
|
|
// Initialize the file system. If format = TRUE, the disk has
|
|
// nothing on it, and we need to initialize the disk to contain
|
|
// an empty directory, and a bitmap of free sectors (with almost but
|
|
// not all of the sectors marked as free).
|
|
//
|
|
// If format = FALSE, we just have to open the files
|
|
// representing the bitmap and the directory.
|
|
//
|
|
// "format" -- should we initialize the disk?
|
|
//----------------------------------------------------------------------
|
|
|
|
FileSystem::FileSystem(bool format)
|
|
{
|
|
DEBUG('f', "Initializing the file system.\n");
|
|
if (format) {
|
|
BitMap *freeMap = new BitMap(NumSectors);
|
|
Directory *directory = new Directory(NumDirEntries);
|
|
FileHeader *mapHdr = new FileHeader;
|
|
FileHeader *dirHdr = new FileHeader;
|
|
|
|
DEBUG('f', "Formatting the file system.\n");
|
|
|
|
// First, allocate space for FileHeaders for the directory and bitmap
|
|
// (make sure no one else grabs these!)
|
|
freeMap->Mark(FreeMapSector);
|
|
freeMap->Mark(DirectorySector);
|
|
|
|
// Second, allocate space for the data blocks containing the contents
|
|
// of the directory and bitmap files. There better be enough space!
|
|
|
|
ASSERT(mapHdr->Allocate(freeMap, FreeMapFileSize));
|
|
ASSERT(dirHdr->Allocate(freeMap, DirectoryFileSize));
|
|
|
|
// Flush the bitmap and directory FileHeaders back to disk
|
|
// We need to do this before we can "Open" the file, since open
|
|
// reads the file header off of disk (and currently the disk has garbage
|
|
// on it!).
|
|
|
|
DEBUG('f', "Writing headers back to disk.\n");
|
|
mapHdr->WriteBack(FreeMapSector);
|
|
dirHdr->WriteBack(DirectorySector);
|
|
|
|
// OK to open the bitmap and directory files now
|
|
// The file system operations assume these two files are left open
|
|
// while Nachos is running.
|
|
|
|
freeMapFile = new OpenFile(FreeMapSector);
|
|
directoryFile = new OpenFile(DirectorySector);
|
|
|
|
// Once we have the files "open", we can write the initial version
|
|
// of each file back to disk. The directory at this point is completely
|
|
// empty; but the bitmap has been changed to reflect the fact that
|
|
// sectors on the disk have been allocated for the file headers and
|
|
// to hold the file data for the directory and bitmap.
|
|
|
|
DEBUG('f', "Writing bitmap and directory back to disk.\n");
|
|
freeMap->WriteBack(freeMapFile); // flush changes to disk
|
|
directory->WriteBack(directoryFile);
|
|
|
|
if (DebugIsEnabled('f')) {
|
|
freeMap->Print();
|
|
directory->Print();
|
|
|
|
delete freeMap;
|
|
delete directory;
|
|
delete mapHdr;
|
|
delete dirHdr;
|
|
}
|
|
} else {
|
|
// if we are not formatting the disk, just open the files representing
|
|
// the bitmap and directory; these are left open while Nachos is running
|
|
freeMapFile = new OpenFile(FreeMapSector);
|
|
directoryFile = new OpenFile(DirectorySector);
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
// FileSystem::Create
|
|
// Create a file in the Nachos file system (similar to UNIX create).
|
|
// Since we can't increase the size of files dynamically, we have
|
|
// to give Create the initial size of the file.
|
|
//
|
|
// The steps to create a file are:
|
|
// Make sure the file doesn't already exist
|
|
// Allocate a sector for the file header
|
|
// Allocate space on disk for the data blocks for the file
|
|
// Add the name to the directory
|
|
// Store the new file header on disk
|
|
// Flush the changes to the bitmap and the directory back to disk
|
|
//
|
|
// Return TRUE if everything goes ok, otherwise, return FALSE.
|
|
//
|
|
// Create fails if:
|
|
// file is already in directory
|
|
// no free space for file header
|
|
// no free entry for file in directory
|
|
// no free space for data blocks for the file
|
|
//
|
|
// Note that this implementation assumes there is no concurrent access
|
|
// to the file system!
|
|
//
|
|
// "name" -- name of file to be created
|
|
// "initialSize" -- size of file to be created
|
|
//----------------------------------------------------------------------
|
|
|
|
bool
|
|
FileSystem::Create(const char *name, int initialSize)
|
|
{
|
|
Directory *directory;
|
|
BitMap *freeMap;
|
|
FileHeader *hdr;
|
|
int sector;
|
|
bool success;
|
|
|
|
DEBUG('f', "Creating file %s, size %d\n", name, initialSize);
|
|
|
|
directory = new Directory(NumDirEntries);
|
|
directory->FetchFrom(directoryFile);
|
|
|
|
if (directory->Find(name) != -1)
|
|
success = FALSE; // file is already in directory
|
|
else {
|
|
freeMap = new BitMap(NumSectors);
|
|
freeMap->FetchFrom(freeMapFile);
|
|
sector = freeMap->Find(); // find a sector to hold the file header
|
|
if (sector == -1)
|
|
success = FALSE; // no free block for file header
|
|
else if (!directory->Add(name, sector))
|
|
success = FALSE; // no space in directory
|
|
else {
|
|
hdr = new FileHeader;
|
|
if (!hdr->Allocate(freeMap, initialSize))
|
|
success = FALSE; // no space on disk for data
|
|
else {
|
|
success = TRUE;
|
|
// everthing worked, flush all changes back to disk
|
|
hdr->WriteBack(sector);
|
|
directory->WriteBack(directoryFile);
|
|
freeMap->WriteBack(freeMapFile);
|
|
}
|
|
delete hdr;
|
|
}
|
|
delete freeMap;
|
|
}
|
|
delete directory;
|
|
return success;
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
// FileSystem::Open
|
|
// Open a file for reading and writing.
|
|
// To open a file:
|
|
// Find the location of the file's header, using the directory
|
|
// Bring the header into memory
|
|
//
|
|
// "name" -- the text name of the file to be opened
|
|
//----------------------------------------------------------------------
|
|
|
|
OpenFile *
|
|
FileSystem::Open(const char *name)
|
|
{
|
|
Directory *directory = new Directory(NumDirEntries);
|
|
OpenFile *openFile = NULL;
|
|
int sector;
|
|
|
|
DEBUG('f', "Opening file %s\n", name);
|
|
directory->FetchFrom(directoryFile);
|
|
sector = directory->Find(name);
|
|
if (sector >= 0)
|
|
openFile = new OpenFile(sector); // name was found in directory
|
|
delete directory;
|
|
return openFile; // return NULL if not found
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
// FileSystem::Remove
|
|
// Delete a file from the file system. This requires:
|
|
// Remove it from the directory
|
|
// Delete the space for its header
|
|
// Delete the space for its data blocks
|
|
// Write changes to directory, bitmap back to disk
|
|
//
|
|
// Return TRUE if the file was deleted, FALSE if the file wasn't
|
|
// in the file system.
|
|
//
|
|
// "name" -- the text name of the file to be removed
|
|
//----------------------------------------------------------------------
|
|
|
|
bool
|
|
FileSystem::Remove(const char *name)
|
|
{
|
|
Directory *directory;
|
|
BitMap *freeMap;
|
|
FileHeader *fileHdr;
|
|
int sector;
|
|
|
|
directory = new Directory(NumDirEntries);
|
|
directory->FetchFrom(directoryFile);
|
|
sector = directory->Find(name);
|
|
if (sector == -1) {
|
|
delete directory;
|
|
return FALSE; // file not found
|
|
}
|
|
fileHdr = new FileHeader;
|
|
fileHdr->FetchFrom(sector);
|
|
|
|
freeMap = new BitMap(NumSectors);
|
|
freeMap->FetchFrom(freeMapFile);
|
|
|
|
fileHdr->Deallocate(freeMap); // remove data blocks
|
|
freeMap->Clear(sector); // remove header block
|
|
directory->Remove(name);
|
|
|
|
freeMap->WriteBack(freeMapFile); // flush to disk
|
|
directory->WriteBack(directoryFile); // flush to disk
|
|
delete fileHdr;
|
|
delete directory;
|
|
delete freeMap;
|
|
return TRUE;
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
// FileSystem::List
|
|
// List all the files in the file system directory.
|
|
//----------------------------------------------------------------------
|
|
|
|
void
|
|
FileSystem::List()
|
|
{
|
|
Directory *directory = new Directory(NumDirEntries);
|
|
|
|
directory->FetchFrom(directoryFile);
|
|
directory->List();
|
|
delete directory;
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
// FileSystem::Print
|
|
// Print everything about the file system:
|
|
// the contents of the bitmap
|
|
// the contents of the directory
|
|
// for each file in the directory,
|
|
// the contents of the file header
|
|
// the data in the file
|
|
//----------------------------------------------------------------------
|
|
|
|
void
|
|
FileSystem::Print()
|
|
{
|
|
FileHeader *bitHdr = new FileHeader;
|
|
FileHeader *dirHdr = new FileHeader;
|
|
BitMap *freeMap = new BitMap(NumSectors);
|
|
Directory *directory = new Directory(NumDirEntries);
|
|
|
|
printf("Bit map file header:\n");
|
|
bitHdr->FetchFrom(FreeMapSector);
|
|
bitHdr->Print();
|
|
|
|
printf("Directory file header:\n");
|
|
dirHdr->FetchFrom(DirectorySector);
|
|
dirHdr->Print();
|
|
|
|
freeMap->FetchFrom(freeMapFile);
|
|
freeMap->Print();
|
|
|
|
directory->FetchFrom(directoryFile);
|
|
directory->Print();
|
|
|
|
delete bitHdr;
|
|
delete dirHdr;
|
|
delete freeMap;
|
|
delete directory;
|
|
}
|