init: init nachos hw01, should pass jenkins os_group_20_hw job but fail on os_group_20_ta job
This commit is contained in:
196
code/filesys/directory.cc
Normal file
196
code/filesys/directory.cc
Normal file
@@ -0,0 +1,196 @@
|
||||
// directory.cc
|
||||
// Routines to manage a directory of file names.
|
||||
//
|
||||
// The directory is a table of fixed length entries; each
|
||||
// entry represents a single file, and contains the file name,
|
||||
// and the location of the file header on disk. The fixed size
|
||||
// of each directory entry means that we have the restriction
|
||||
// of a fixed maximum size for file names.
|
||||
//
|
||||
// The constructor initializes an empty directory of a certain size;
|
||||
// we use ReadFrom/WriteBack to fetch the contents of the directory
|
||||
// from disk, and to write back any modifications back to disk.
|
||||
//
|
||||
// Also, this implementation has the restriction that the size
|
||||
// of the directory cannot expand. In other words, once all the
|
||||
// entries in the directory are used, no more files can be created.
|
||||
//
|
||||
// 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 "utility.h"
|
||||
#include "filehdr.h"
|
||||
#include "directory.h"
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// Directory::Directory
|
||||
// Initialize a directory; initially, the directory is completely
|
||||
// empty. If the disk is being formatted, an empty directory
|
||||
// is all we need, but otherwise, we need to call FetchFrom in order
|
||||
// to initialize it from disk.
|
||||
//
|
||||
// "size" is the number of entries in the directory
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
Directory::Directory(int size)
|
||||
{
|
||||
table = new DirectoryEntry[size];
|
||||
tableSize = size;
|
||||
for (int i = 0; i < tableSize; i++)
|
||||
table[i].inUse = FALSE;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// Directory::~Directory
|
||||
// De-allocate directory data structure.
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
Directory::~Directory()
|
||||
{
|
||||
delete [] table;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// Directory::FetchFrom
|
||||
// Read the contents of the directory from disk.
|
||||
//
|
||||
// "file" -- file containing the directory contents
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
void
|
||||
Directory::FetchFrom(OpenFile *file)
|
||||
{
|
||||
(void) file->ReadAt((char *)table, tableSize * sizeof(DirectoryEntry), 0);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// Directory::WriteBack
|
||||
// Write any modifications to the directory back to disk
|
||||
//
|
||||
// "file" -- file to contain the new directory contents
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
void
|
||||
Directory::WriteBack(OpenFile *file)
|
||||
{
|
||||
(void) file->WriteAt((char *)table, tableSize * sizeof(DirectoryEntry), 0);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// Directory::FindIndex
|
||||
// Look up file name in directory, and return its location in the table of
|
||||
// directory entries. Return -1 if the name isn't in the directory.
|
||||
//
|
||||
// "name" -- the file name to look up
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
int
|
||||
Directory::FindIndex(char *name)
|
||||
{
|
||||
for (int i = 0; i < tableSize; i++)
|
||||
if (table[i].inUse && !strncmp(table[i].name, name, FileNameMaxLen))
|
||||
return i;
|
||||
return -1; // name not in directory
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// Directory::Find
|
||||
// Look up file name in directory, and return the disk sector number
|
||||
// where the file's header is stored. Return -1 if the name isn't
|
||||
// in the directory.
|
||||
//
|
||||
// "name" -- the file name to look up
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
int
|
||||
Directory::Find(char *name)
|
||||
{
|
||||
int i = FindIndex(name);
|
||||
|
||||
if (i != -1)
|
||||
return table[i].sector;
|
||||
return -1;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// Directory::Add
|
||||
// Add a file into the directory. Return TRUE if successful;
|
||||
// return FALSE if the file name is already in the directory, or if
|
||||
// the directory is completely full, and has no more space for
|
||||
// additional file names.
|
||||
//
|
||||
// "name" -- the name of the file being added
|
||||
// "newSector" -- the disk sector containing the added file's header
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
bool
|
||||
Directory::Add(char *name, int newSector)
|
||||
{
|
||||
if (FindIndex(name) != -1)
|
||||
return FALSE;
|
||||
|
||||
for (int i = 0; i < tableSize; i++)
|
||||
if (!table[i].inUse) {
|
||||
table[i].inUse = TRUE;
|
||||
strncpy(table[i].name, name, FileNameMaxLen);
|
||||
table[i].sector = newSector;
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE; // no space. Fix when we have extensible files.
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// Directory::Remove
|
||||
// Remove a file name from the directory. Return TRUE if successful;
|
||||
// return FALSE if the file isn't in the directory.
|
||||
//
|
||||
// "name" -- the file name to be removed
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
bool
|
||||
Directory::Remove(char *name)
|
||||
{
|
||||
int i = FindIndex(name);
|
||||
|
||||
if (i == -1)
|
||||
return FALSE; // name not in directory
|
||||
table[i].inUse = FALSE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// Directory::List
|
||||
// List all the file names in the directory.
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
void
|
||||
Directory::List()
|
||||
{
|
||||
for (int i = 0; i < tableSize; i++)
|
||||
if (table[i].inUse)
|
||||
printf("%s\n", table[i].name);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// Directory::Print
|
||||
// List all the file names in the directory, their FileHeader locations,
|
||||
// and the contents of each file. For debugging.
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
void
|
||||
Directory::Print()
|
||||
{
|
||||
FileHeader *hdr = new FileHeader;
|
||||
|
||||
printf("Directory contents:\n");
|
||||
for (int i = 0; i < tableSize; i++)
|
||||
if (table[i].inUse) {
|
||||
printf("Name: %s, Sector: %d\n", table[i].name, table[i].sector);
|
||||
hdr->FetchFrom(table[i].sector);
|
||||
hdr->Print();
|
||||
}
|
||||
printf("\n");
|
||||
delete hdr;
|
||||
}
|
||||
83
code/filesys/directory.h
Normal file
83
code/filesys/directory.h
Normal file
@@ -0,0 +1,83 @@
|
||||
// directory.h
|
||||
// Data structures to manage a UNIX-like directory of file names.
|
||||
//
|
||||
// A directory is a table of pairs: <file name, sector #>,
|
||||
// giving the name of each file in the directory, and
|
||||
// where to find its file header (the data structure describing
|
||||
// where to find the file's data blocks) on disk.
|
||||
//
|
||||
// We assume mutual exclusion is provided by the caller.
|
||||
//
|
||||
// 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"
|
||||
|
||||
#ifndef DIRECTORY_H
|
||||
#define DIRECTORY_H
|
||||
|
||||
#include "openfile.h"
|
||||
|
||||
#define FileNameMaxLen 9 // for simplicity, we assume
|
||||
// file names are <= 9 characters long
|
||||
|
||||
// The following class defines a "directory entry", representing a file
|
||||
// in the directory. Each entry gives the name of the file, and where
|
||||
// the file's header is to be found on disk.
|
||||
//
|
||||
// Internal data structures kept public so that Directory operations can
|
||||
// access them directly.
|
||||
|
||||
class DirectoryEntry {
|
||||
public:
|
||||
bool inUse; // Is this directory entry in use?
|
||||
int sector; // Location on disk to find the
|
||||
// FileHeader for this file
|
||||
char name[FileNameMaxLen + 1]; // Text name for file, with +1 for
|
||||
// the trailing '\0'
|
||||
};
|
||||
|
||||
// The following class defines a UNIX-like "directory". Each entry in
|
||||
// the directory describes a file, and where to find it on disk.
|
||||
//
|
||||
// The directory data structure can be stored in memory, or on disk.
|
||||
// When it is on disk, it is stored as a regular Nachos file.
|
||||
//
|
||||
// The constructor initializes a directory structure in memory; the
|
||||
// FetchFrom/WriteBack operations shuffle the directory information
|
||||
// from/to disk.
|
||||
|
||||
class Directory {
|
||||
public:
|
||||
Directory(int size); // Initialize an empty directory
|
||||
// with space for "size" files
|
||||
~Directory(); // De-allocate the directory
|
||||
|
||||
void FetchFrom(OpenFile *file); // Init directory contents from disk
|
||||
void WriteBack(OpenFile *file); // Write modifications to
|
||||
// directory contents back to disk
|
||||
|
||||
int Find(char *name); // Find the sector number of the
|
||||
// FileHeader for file: "name"
|
||||
|
||||
bool Add(char *name, int newSector); // Add a file name into the directory
|
||||
|
||||
bool Remove(char *name); // Remove a file from the directory
|
||||
|
||||
void List(); // Print the names of all the files
|
||||
// in the directory
|
||||
void Print(); // Verbose print of the contents
|
||||
// of the directory -- all the file
|
||||
// names and their contents.
|
||||
|
||||
private:
|
||||
int tableSize; // Number of directory entries
|
||||
DirectoryEntry *table; // Table of pairs:
|
||||
// <file name, file header location>
|
||||
|
||||
int FindIndex(char *name); // Find the index into the directory
|
||||
// table corresponding to "name"
|
||||
};
|
||||
|
||||
#endif // DIRECTORY_H
|
||||
156
code/filesys/filehdr.cc
Normal file
156
code/filesys/filehdr.cc
Normal file
@@ -0,0 +1,156 @@
|
||||
// filehdr.cc
|
||||
// Routines for managing the disk file header (in UNIX, this
|
||||
// would be called the i-node).
|
||||
//
|
||||
// The file header is used to locate where on disk the
|
||||
// file's data is stored. We implement this as a fixed size
|
||||
// table of pointers -- each entry in the table points to the
|
||||
// disk sector containing that portion of the file data
|
||||
// (in other words, there are no indirect or doubly indirect
|
||||
// blocks). The table size is chosen so that the file header
|
||||
// will be just big enough to fit in one disk sector,
|
||||
//
|
||||
// Unlike in a real system, we do not keep track of file permissions,
|
||||
// ownership, last modification date, etc., in the file header.
|
||||
//
|
||||
// A file header can be initialized in two ways:
|
||||
// for a new file, by modifying the in-memory data structure
|
||||
// to point to the newly allocated data blocks
|
||||
// for a file already on disk, by reading the file header from 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 "filehdr.h"
|
||||
#include "debug.h"
|
||||
#include "synchdisk.h"
|
||||
#include "main.h"
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// FileHeader::Allocate
|
||||
// Initialize a fresh file header for a newly created file.
|
||||
// Allocate data blocks for the file out of the map of free disk blocks.
|
||||
// Return FALSE if there are not enough free blocks to accomodate
|
||||
// the new file.
|
||||
//
|
||||
// "freeMap" is the bit map of free disk sectors
|
||||
// "fileSize" is the bit map of free disk sectors
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
bool
|
||||
FileHeader::Allocate(PersistentBitmap *freeMap, int fileSize)
|
||||
{
|
||||
numBytes = fileSize;
|
||||
numSectors = divRoundUp(fileSize, SectorSize);
|
||||
if (freeMap->NumClear() < numSectors)
|
||||
return FALSE; // not enough space
|
||||
|
||||
for (int i = 0; i < numSectors; i++) {
|
||||
dataSectors[i] = freeMap->FindAndSet();
|
||||
// since we checked that there was enough free space,
|
||||
// we expect this to succeed
|
||||
ASSERT(dataSectors[i] >= 0);
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// FileHeader::Deallocate
|
||||
// De-allocate all the space allocated for data blocks for this file.
|
||||
//
|
||||
// "freeMap" is the bit map of free disk sectors
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
void
|
||||
FileHeader::Deallocate(PersistentBitmap *freeMap)
|
||||
{
|
||||
for (int i = 0; i < numSectors; i++) {
|
||||
ASSERT(freeMap->Test((int) dataSectors[i])); // ought to be marked!
|
||||
freeMap->Clear((int) dataSectors[i]);
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// FileHeader::FetchFrom
|
||||
// Fetch contents of file header from disk.
|
||||
//
|
||||
// "sector" is the disk sector containing the file header
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
void
|
||||
FileHeader::FetchFrom(int sector)
|
||||
{
|
||||
kernel->synchDisk->ReadSector(sector, (char *)this);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// FileHeader::WriteBack
|
||||
// Write the modified contents of the file header back to disk.
|
||||
//
|
||||
// "sector" is the disk sector to contain the file header
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
void
|
||||
FileHeader::WriteBack(int sector)
|
||||
{
|
||||
kernel->synchDisk->WriteSector(sector, (char *)this);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// FileHeader::ByteToSector
|
||||
// Return which disk sector is storing a particular byte within the file.
|
||||
// This is essentially a translation from a virtual address (the
|
||||
// offset in the file) to a physical address (the sector where the
|
||||
// data at the offset is stored).
|
||||
//
|
||||
// "offset" is the location within the file of the byte in question
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
int
|
||||
FileHeader::ByteToSector(int offset)
|
||||
{
|
||||
return(dataSectors[offset / SectorSize]);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// FileHeader::FileLength
|
||||
// Return the number of bytes in the file.
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
int
|
||||
FileHeader::FileLength()
|
||||
{
|
||||
return numBytes;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// FileHeader::Print
|
||||
// Print the contents of the file header, and the contents of all
|
||||
// the data blocks pointed to by the file header.
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
void
|
||||
FileHeader::Print()
|
||||
{
|
||||
int i, j, k;
|
||||
char *data = new char[SectorSize];
|
||||
|
||||
printf("FileHeader contents. File size: %d. File blocks:\n", numBytes);
|
||||
for (i = 0; i < numSectors; i++)
|
||||
printf("%d ", dataSectors[i]);
|
||||
printf("\nFile contents:\n");
|
||||
for (i = k = 0; i < numSectors; i++) {
|
||||
kernel->synchDisk->ReadSector(dataSectors[i], data);
|
||||
for (j = 0; (j < SectorSize) && (k < numBytes); j++, k++) {
|
||||
if ('\040' <= data[j] && data[j] <= '\176') // isprint(data[j])
|
||||
printf("%c", data[j]);
|
||||
else
|
||||
printf("\\%x", (unsigned char)data[j]);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
delete [] data;
|
||||
}
|
||||
66
code/filesys/filehdr.h
Normal file
66
code/filesys/filehdr.h
Normal file
@@ -0,0 +1,66 @@
|
||||
// filehdr.h
|
||||
// Data structures for managing a disk file header.
|
||||
//
|
||||
// A file header describes where on disk to find the data in a file,
|
||||
// along with other information about the file (for instance, its
|
||||
// length, owner, etc.)
|
||||
//
|
||||
// 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"
|
||||
|
||||
#ifndef FILEHDR_H
|
||||
#define FILEHDR_H
|
||||
|
||||
#include "disk.h"
|
||||
#include "pbitmap.h"
|
||||
|
||||
#define NumDirect ((SectorSize - 2 * sizeof(int)) / sizeof(int))
|
||||
#define MaxFileSize (NumDirect * SectorSize)
|
||||
|
||||
// The following class defines the Nachos "file header" (in UNIX terms,
|
||||
// the "i-node"), describing where on disk to find all of the data in the file.
|
||||
// The file header is organized as a simple table of pointers to
|
||||
// data blocks.
|
||||
//
|
||||
// The file header data structure can be stored in memory or on disk.
|
||||
// When it is on disk, it is stored in a single sector -- this means
|
||||
// that we assume the size of this data structure to be the same
|
||||
// as one disk sector. Without indirect addressing, this
|
||||
// limits the maximum file length to just under 4K bytes.
|
||||
//
|
||||
// There is no constructor; rather the file header can be initialized
|
||||
// by allocating blocks for the file (if it is a new file), or by
|
||||
// reading it from disk.
|
||||
|
||||
class FileHeader {
|
||||
public:
|
||||
bool Allocate(PersistentBitmap *bitMap, int fileSize);// Initialize a file header,
|
||||
// including allocating space
|
||||
// on disk for the file data
|
||||
void Deallocate(PersistentBitmap *bitMap); // De-allocate this file's
|
||||
// data blocks
|
||||
|
||||
void FetchFrom(int sectorNumber); // Initialize file header from disk
|
||||
void WriteBack(int sectorNumber); // Write modifications to file header
|
||||
// back to disk
|
||||
|
||||
int ByteToSector(int offset); // Convert a byte offset into the file
|
||||
// to the disk sector containing
|
||||
// the byte
|
||||
|
||||
int FileLength(); // Return the length of the file
|
||||
// in bytes
|
||||
|
||||
void Print(); // Print the contents of the file.
|
||||
|
||||
private:
|
||||
int numBytes; // Number of bytes in the file
|
||||
int numSectors; // Number of data sectors in the file
|
||||
int dataSectors[NumDirect]; // Disk sector numbers for each data
|
||||
// block in the file
|
||||
};
|
||||
|
||||
#endif // FILEHDR_H
|
||||
340
code/filesys/filesys.cc
Normal file
340
code/filesys/filesys.cc
Normal file
@@ -0,0 +1,340 @@
|
||||
// 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.
|
||||
#ifndef FILESYS_STUB
|
||||
|
||||
#include "copyright.h"
|
||||
#include "debug.h"
|
||||
#include "disk.h"
|
||||
#include "pbitmap.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 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(dbgFile, "Initializing the file system.");
|
||||
if (format) {
|
||||
PersistentBitmap *freeMap = new PersistentBitmap(NumSectors);
|
||||
Directory *directory = new Directory(NumDirEntries);
|
||||
FileHeader *mapHdr = new FileHeader;
|
||||
FileHeader *dirHdr = new FileHeader;
|
||||
|
||||
DEBUG(dbgFile, "Formatting the file system.");
|
||||
|
||||
// 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(dbgFile, "Writing headers back to disk.");
|
||||
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(dbgFile, "Writing bitmap and directory back to disk.");
|
||||
freeMap->WriteBack(freeMapFile); // flush changes to disk
|
||||
directory->WriteBack(directoryFile);
|
||||
|
||||
if (debug->IsEnabled('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(char *name, int initialSize)
|
||||
{
|
||||
Directory *directory;
|
||||
PersistentBitmap *freeMap;
|
||||
FileHeader *hdr;
|
||||
int sector;
|
||||
bool success;
|
||||
|
||||
DEBUG(dbgFile, "Creating file " << name << " size " << initialSize);
|
||||
|
||||
directory = new Directory(NumDirEntries);
|
||||
directory->FetchFrom(directoryFile);
|
||||
|
||||
if (directory->Find(name) != -1)
|
||||
success = FALSE; // file is already in directory
|
||||
else {
|
||||
freeMap = new PersistentBitmap(freeMapFile,NumSectors);
|
||||
sector = freeMap->FindAndSet(); // 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(char *name)
|
||||
{
|
||||
Directory *directory = new Directory(NumDirEntries);
|
||||
OpenFile *openFile = NULL;
|
||||
int sector;
|
||||
|
||||
DEBUG(dbgFile, "Opening file" << 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(char *name)
|
||||
{
|
||||
Directory *directory;
|
||||
PersistentBitmap *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 PersistentBitmap(freeMapFile,NumSectors);
|
||||
|
||||
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;
|
||||
PersistentBitmap *freeMap = new PersistentBitmap(freeMapFile,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->Print();
|
||||
|
||||
directory->FetchFrom(directoryFile);
|
||||
directory->Print();
|
||||
|
||||
delete bitHdr;
|
||||
delete dirHdr;
|
||||
delete freeMap;
|
||||
delete directory;
|
||||
}
|
||||
|
||||
#endif // FILESYS_STUB
|
||||
98
code/filesys/filesys.h
Normal file
98
code/filesys/filesys.h
Normal file
@@ -0,0 +1,98 @@
|
||||
// filesys.h
|
||||
// Data structures to represent the Nachos file system.
|
||||
//
|
||||
// A file system is a set of files stored on disk, organized
|
||||
// into directories. Operations on the file system have to
|
||||
// do with "naming" -- creating, opening, and deleting files,
|
||||
// given a textual file name. Operations on an individual
|
||||
// "open" file (read, write, close) are to be found in the OpenFile
|
||||
// class (openfile.h).
|
||||
//
|
||||
// We define two separate implementations of the file system.
|
||||
// The "STUB" version just re-defines the Nachos file system
|
||||
// operations as operations on the native UNIX file system on the machine
|
||||
// running the Nachos simulation.
|
||||
//
|
||||
// The other version is a "real" file system, built on top of
|
||||
// a disk simulator. The disk is simulated using the native UNIX
|
||||
// file system (in a file named "DISK").
|
||||
//
|
||||
// In the "real" implementation, there are two key data structures used
|
||||
// in the file system. There is a single "root" directory, listing
|
||||
// all of the files in the file system; unlike UNIX, the baseline
|
||||
// system does not provide a hierarchical directory structure.
|
||||
// In addition, there is a bitmap for allocating
|
||||
// disk sectors. Both the root directory and the bitmap are themselves
|
||||
// stored as files in the Nachos file system -- this causes an interesting
|
||||
// bootstrap problem when the simulated disk is initialized.
|
||||
//
|
||||
// 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.
|
||||
|
||||
#ifndef FS_H
|
||||
#define FS_H
|
||||
|
||||
#include "copyright.h"
|
||||
#include "sysdep.h"
|
||||
#include "openfile.h"
|
||||
|
||||
#ifdef FILESYS_STUB // Temporarily implement file system calls as
|
||||
// calls to UNIX, until the real file system
|
||||
// implementation is available
|
||||
class FileSystem {
|
||||
public:
|
||||
FileSystem() { for (int i = 0; i < 20; i++) fileDescriptorTable[i] = NULL; }
|
||||
|
||||
bool Create(char *name) {
|
||||
int fileDescriptor = OpenForWrite(name);
|
||||
|
||||
if (fileDescriptor == -1) return FALSE;
|
||||
Close(fileDescriptor);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
OpenFile* Open(char *name) {
|
||||
int fileDescriptor = OpenForReadWrite(name, FALSE);
|
||||
|
||||
if (fileDescriptor == -1) return NULL;
|
||||
return new OpenFile(fileDescriptor);
|
||||
}
|
||||
|
||||
bool Remove(char *name) { return Unlink(name) == 0; }
|
||||
|
||||
OpenFile *fileDescriptorTable[20];
|
||||
|
||||
};
|
||||
|
||||
#else // FILESYS
|
||||
class FileSystem {
|
||||
public:
|
||||
FileSystem(bool format); // Initialize the file system.
|
||||
// Must be called *after* "synchDisk"
|
||||
// has been initialized.
|
||||
// If "format", there is nothing on
|
||||
// the disk, so initialize the directory
|
||||
// and the bitmap of free blocks.
|
||||
|
||||
bool Create(char *name, int initialSize);
|
||||
// Create a file (UNIX creat)
|
||||
|
||||
OpenFile* Open(char *name); // Open a file (UNIX open)
|
||||
|
||||
bool Remove(char *name); // Delete a file (UNIX unlink)
|
||||
|
||||
void List(); // List all the files in the file system
|
||||
|
||||
void Print(); // List all the files and their contents
|
||||
|
||||
private:
|
||||
OpenFile* freeMapFile; // Bit map of free disk blocks,
|
||||
// represented as a file
|
||||
OpenFile* directoryFile; // "Root" directory -- list of
|
||||
// file names, represented as a file
|
||||
};
|
||||
|
||||
#endif // FILESYS
|
||||
|
||||
#endif // FS_H
|
||||
196
code/filesys/openfile.cc
Normal file
196
code/filesys/openfile.cc
Normal file
@@ -0,0 +1,196 @@
|
||||
// openfile.cc
|
||||
// Routines to manage an open Nachos file. As in UNIX, a
|
||||
// file must be open before we can read or write to it.
|
||||
// Once we're all done, we can close it (in Nachos, by deleting
|
||||
// the OpenFile data structure).
|
||||
//
|
||||
// Also as in UNIX, for convenience, we keep the file header in
|
||||
// memory while the file is open.
|
||||
//
|
||||
// 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.
|
||||
#ifndef FILESYS_STUB
|
||||
|
||||
#include "copyright.h"
|
||||
#include "main.h"
|
||||
#include "filehdr.h"
|
||||
#include "openfile.h"
|
||||
#include "synchdisk.h"
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// OpenFile::OpenFile
|
||||
// Open a Nachos file for reading and writing. Bring the file header
|
||||
// into memory while the file is open.
|
||||
//
|
||||
// "sector" -- the location on disk of the file header for this file
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
OpenFile::OpenFile(int sector)
|
||||
{
|
||||
hdr = new FileHeader;
|
||||
hdr->FetchFrom(sector);
|
||||
seekPosition = 0;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// OpenFile::~OpenFile
|
||||
// Close a Nachos file, de-allocating any in-memory data structures.
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
OpenFile::~OpenFile()
|
||||
{
|
||||
delete hdr;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// OpenFile::Seek
|
||||
// Change the current location within the open file -- the point at
|
||||
// which the next Read or Write will start from.
|
||||
//
|
||||
// "position" -- the location within the file for the next Read/Write
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
void
|
||||
OpenFile::Seek(int position)
|
||||
{
|
||||
seekPosition = position;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// OpenFile::Read/Write
|
||||
// Read/write a portion of a file, starting from seekPosition.
|
||||
// Return the number of bytes actually written or read, and as a
|
||||
// side effect, increment the current position within the file.
|
||||
//
|
||||
// Implemented using the more primitive ReadAt/WriteAt.
|
||||
//
|
||||
// "into" -- the buffer to contain the data to be read from disk
|
||||
// "from" -- the buffer containing the data to be written to disk
|
||||
// "numBytes" -- the number of bytes to transfer
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
int
|
||||
OpenFile::Read(char *into, int numBytes)
|
||||
{
|
||||
int result = ReadAt(into, numBytes, seekPosition);
|
||||
seekPosition += result;
|
||||
return result;
|
||||
}
|
||||
|
||||
int
|
||||
OpenFile::Write(char *into, int numBytes)
|
||||
{
|
||||
int result = WriteAt(into, numBytes, seekPosition);
|
||||
seekPosition += result;
|
||||
return result;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// OpenFile::ReadAt/WriteAt
|
||||
// Read/write a portion of a file, starting at "position".
|
||||
// Return the number of bytes actually written or read, but has
|
||||
// no side effects (except that Write modifies the file, of course).
|
||||
//
|
||||
// There is no guarantee the request starts or ends on an even disk sector
|
||||
// boundary; however the disk only knows how to read/write a whole disk
|
||||
// sector at a time. Thus:
|
||||
//
|
||||
// For ReadAt:
|
||||
// We read in all of the full or partial sectors that are part of the
|
||||
// request, but we only copy the part we are interested in.
|
||||
// For WriteAt:
|
||||
// We must first read in any sectors that will be partially written,
|
||||
// so that we don't overwrite the unmodified portion. We then copy
|
||||
// in the data that will be modified, and write back all the full
|
||||
// or partial sectors that are part of the request.
|
||||
//
|
||||
// "into" -- the buffer to contain the data to be read from disk
|
||||
// "from" -- the buffer containing the data to be written to disk
|
||||
// "numBytes" -- the number of bytes to transfer
|
||||
// "position" -- the offset within the file of the first byte to be
|
||||
// read/written
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
int
|
||||
OpenFile::ReadAt(char *into, int numBytes, int position)
|
||||
{
|
||||
int fileLength = hdr->FileLength();
|
||||
int i, firstSector, lastSector, numSectors;
|
||||
char *buf;
|
||||
|
||||
if ((numBytes <= 0) || (position >= fileLength))
|
||||
return 0; // check request
|
||||
if ((position + numBytes) > fileLength)
|
||||
numBytes = fileLength - position;
|
||||
DEBUG(dbgFile, "Reading " << numBytes << " bytes at " << position << " from file of length " << fileLength);
|
||||
|
||||
firstSector = divRoundDown(position, SectorSize);
|
||||
lastSector = divRoundDown(position + numBytes - 1, SectorSize);
|
||||
numSectors = 1 + lastSector - firstSector;
|
||||
|
||||
// read in all the full and partial sectors that we need
|
||||
buf = new char[numSectors * SectorSize];
|
||||
for (i = firstSector; i <= lastSector; i++)
|
||||
kernel->synchDisk->ReadSector(hdr->ByteToSector(i * SectorSize),
|
||||
&buf[(i - firstSector) * SectorSize]);
|
||||
|
||||
// copy the part we want
|
||||
bcopy(&buf[position - (firstSector * SectorSize)], into, numBytes);
|
||||
delete [] buf;
|
||||
return numBytes;
|
||||
}
|
||||
|
||||
int
|
||||
OpenFile::WriteAt(char *from, int numBytes, int position)
|
||||
{
|
||||
int fileLength = hdr->FileLength();
|
||||
int i, firstSector, lastSector, numSectors;
|
||||
bool firstAligned, lastAligned;
|
||||
char *buf;
|
||||
|
||||
if ((numBytes <= 0) || (position >= fileLength))
|
||||
return 0; // check request
|
||||
if ((position + numBytes) > fileLength)
|
||||
numBytes = fileLength - position;
|
||||
DEBUG(dbgFile, "Writing " << numBytes << " bytes at " << position << " from file of length " << fileLength);
|
||||
|
||||
firstSector = divRoundDown(position, SectorSize);
|
||||
lastSector = divRoundDown(position + numBytes - 1, SectorSize);
|
||||
numSectors = 1 + lastSector - firstSector;
|
||||
|
||||
buf = new char[numSectors * SectorSize];
|
||||
|
||||
firstAligned = (position == (firstSector * SectorSize));
|
||||
lastAligned = ((position + numBytes) == ((lastSector + 1) * SectorSize));
|
||||
|
||||
// read in first and last sector, if they are to be partially modified
|
||||
if (!firstAligned)
|
||||
ReadAt(buf, SectorSize, firstSector * SectorSize);
|
||||
if (!lastAligned && ((firstSector != lastSector) || firstAligned))
|
||||
ReadAt(&buf[(lastSector - firstSector) * SectorSize],
|
||||
SectorSize, lastSector * SectorSize);
|
||||
|
||||
// copy in the bytes we want to change
|
||||
bcopy(from, &buf[position - (firstSector * SectorSize)], numBytes);
|
||||
|
||||
// write modified sectors back
|
||||
for (i = firstSector; i <= lastSector; i++)
|
||||
kernel->synchDisk->WriteSector(hdr->ByteToSector(i * SectorSize),
|
||||
&buf[(i - firstSector) * SectorSize]);
|
||||
delete [] buf;
|
||||
return numBytes;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// OpenFile::Length
|
||||
// Return the number of bytes in the file.
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
int
|
||||
OpenFile::Length()
|
||||
{
|
||||
return hdr->FileLength();
|
||||
}
|
||||
|
||||
#endif //FILESYS_STUB
|
||||
97
code/filesys/openfile.h
Normal file
97
code/filesys/openfile.h
Normal file
@@ -0,0 +1,97 @@
|
||||
// openfile.h
|
||||
// Data structures for opening, closing, reading and writing to
|
||||
// individual files. The operations supported are similar to
|
||||
// the UNIX ones -- type 'man open' to the UNIX prompt.
|
||||
//
|
||||
// There are two implementations. One is a "STUB" that directly
|
||||
// turns the file operations into the underlying UNIX operations.
|
||||
// (cf. comment in filesys.h).
|
||||
//
|
||||
// The other is the "real" implementation, that turns these
|
||||
// operations into read and write disk sector requests.
|
||||
// In this baseline implementation of the file system, we don't
|
||||
// worry about concurrent accesses to the file system
|
||||
// by different threads.
|
||||
//
|
||||
// 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.
|
||||
|
||||
#ifndef OPENFILE_H
|
||||
#define OPENFILE_H
|
||||
|
||||
#include "copyright.h"
|
||||
#include "utility.h"
|
||||
#include "sysdep.h"
|
||||
|
||||
#ifdef FILESYS_STUB // Temporarily implement calls to
|
||||
// Nachos file system as calls to UNIX!
|
||||
// See definitions listed under #else
|
||||
class OpenFile {
|
||||
public:
|
||||
OpenFile(int f) { file = f; currentOffset = 0; } // open the file
|
||||
~OpenFile() { Close(file); } // close the file
|
||||
|
||||
int ReadAt(char *into, int numBytes, int position) {
|
||||
Lseek(file, position, 0);
|
||||
return ReadPartial(file, into, numBytes);
|
||||
}
|
||||
int WriteAt(char *from, int numBytes, int position) {
|
||||
Lseek(file, position, 0);
|
||||
WriteFile(file, from, numBytes);
|
||||
return numBytes;
|
||||
}
|
||||
int Read(char *into, int numBytes) {
|
||||
int numRead = ReadAt(into, numBytes, currentOffset);
|
||||
currentOffset += numRead;
|
||||
return numRead;
|
||||
}
|
||||
int Write(char *from, int numBytes) {
|
||||
int numWritten = WriteAt(from, numBytes, currentOffset);
|
||||
currentOffset += numWritten;
|
||||
return numWritten;
|
||||
}
|
||||
|
||||
int Length() { Lseek(file, 0, 2); return Tell(file); }
|
||||
|
||||
private:
|
||||
int file;
|
||||
int currentOffset;
|
||||
};
|
||||
|
||||
#else // FILESYS
|
||||
class FileHeader;
|
||||
|
||||
class OpenFile {
|
||||
public:
|
||||
OpenFile(int sector); // Open a file whose header is located
|
||||
// at "sector" on the disk
|
||||
~OpenFile(); // Close the file
|
||||
|
||||
void Seek(int position); // Set the position from which to
|
||||
// start reading/writing -- UNIX lseek
|
||||
|
||||
int Read(char *into, int numBytes); // Read/write bytes from the file,
|
||||
// starting at the implicit position.
|
||||
// Return the # actually read/written,
|
||||
// and increment position in file.
|
||||
int Write(char *from, int numBytes);
|
||||
|
||||
int ReadAt(char *into, int numBytes, int position);
|
||||
// Read/write bytes from the file,
|
||||
// bypassing the implicit position.
|
||||
int WriteAt(char *from, int numBytes, int position);
|
||||
|
||||
int Length(); // Return the number of bytes in the
|
||||
// file (this interface is simpler
|
||||
// than the UNIX idiom -- lseek to
|
||||
// end of file, tell, lseek back
|
||||
|
||||
private:
|
||||
FileHeader *hdr; // Header for this file
|
||||
int seekPosition; // Current position within the file
|
||||
};
|
||||
|
||||
#endif // FILESYS
|
||||
|
||||
#endif // OPENFILE_H
|
||||
79
code/filesys/pbitmap.cc
Normal file
79
code/filesys/pbitmap.cc
Normal file
@@ -0,0 +1,79 @@
|
||||
// pbitmap.c
|
||||
// Routines to manage a persistent bitmap -- a bitmap that is
|
||||
// stored on disk.
|
||||
//
|
||||
// Copyright (c) 1992,1993,1995 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 "pbitmap.h"
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// PersistentBitmap::PersistentBitmap(int)
|
||||
// Initialize a bitmap with "numItems" bits, so that every bit is clear.
|
||||
// it can be added somewhere on a list.
|
||||
//
|
||||
// "numItems" is the number of bits in the bitmap.
|
||||
//
|
||||
// This constructor does not initialize the bitmap from a disk file
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
PersistentBitmap::PersistentBitmap(int numItems):Bitmap(numItems)
|
||||
{
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// PersistentBitmap::PersistentBitmap(OpenFile*,int)
|
||||
// Initialize a persistent bitmap with "numItems" bits,
|
||||
// so that every bit is clear.
|
||||
//
|
||||
// "numItems" is the number of bits in the bitmap.
|
||||
// "file" refers to an open file containing the bitmap (written
|
||||
// by a previous call to PersistentBitmap::WriteBack
|
||||
//
|
||||
// This constructor initializes the bitmap from a disk file
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
PersistentBitmap::PersistentBitmap(OpenFile *file, int numItems):Bitmap(numItems)
|
||||
{
|
||||
// map has already been initialized by the BitMap constructor,
|
||||
// but we will just overwrite that with the contents of the
|
||||
// map found in the file
|
||||
file->ReadAt((char *)map, numWords * sizeof(unsigned), 0);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// PersistentBitmap::~PersistentBitmap
|
||||
// De-allocate a persistent bitmap.
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
PersistentBitmap::~PersistentBitmap()
|
||||
{
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// PersistentBitmap::FetchFrom
|
||||
// Initialize the contents of a persistent bitmap from a Nachos file.
|
||||
//
|
||||
// "file" is the place to read the bitmap from
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
void
|
||||
PersistentBitmap::FetchFrom(OpenFile *file)
|
||||
{
|
||||
file->ReadAt((char *)map, numWords * sizeof(unsigned), 0);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// PersistentBitmap::WriteBack
|
||||
// Store the contents of a persistent bitmap to a Nachos file.
|
||||
//
|
||||
// "file" is the place to write the bitmap to
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
void
|
||||
PersistentBitmap::WriteBack(OpenFile *file)
|
||||
{
|
||||
file->WriteAt((char *)map, numWords * sizeof(unsigned), 0);
|
||||
}
|
||||
35
code/filesys/pbitmap.h
Normal file
35
code/filesys/pbitmap.h
Normal file
@@ -0,0 +1,35 @@
|
||||
// pbitmap.h
|
||||
// Data structures defining a "persistent" bitmap -- a bitmap
|
||||
// that can be stored and fetched off of disk
|
||||
//
|
||||
// A persistent bitmap can either be initialized from the disk
|
||||
// when it is created, or it can be initialized later using
|
||||
// the FetchFrom method
|
||||
//
|
||||
// Copyright (c) 1992,1993,1995 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.
|
||||
|
||||
#ifndef PBITMAP_H
|
||||
#define PBITMAP_H
|
||||
|
||||
#include "copyright.h"
|
||||
#include "bitmap.h"
|
||||
#include "openfile.h"
|
||||
|
||||
// The following class defines a persistent bitmap. It inherits all
|
||||
// the behavior of a bitmap (see bitmap.h), adding the ability to
|
||||
// be read from and stored to the disk.
|
||||
|
||||
class PersistentBitmap : public Bitmap {
|
||||
public:
|
||||
PersistentBitmap(OpenFile *file,int numItems); //initialize bitmap from disk
|
||||
PersistentBitmap(int numItems); // or don't...
|
||||
|
||||
~PersistentBitmap(); // deallocate bitmap
|
||||
|
||||
void FetchFrom(OpenFile *file); // read bitmap from the disk
|
||||
void WriteBack(OpenFile *file); // write bitmap contents to disk
|
||||
};
|
||||
|
||||
#endif // PBITMAP_H
|
||||
94
code/filesys/synchdisk.cc
Normal file
94
code/filesys/synchdisk.cc
Normal file
@@ -0,0 +1,94 @@
|
||||
// synchdisk.cc
|
||||
// Routines to synchronously access the disk. The physical disk
|
||||
// is an asynchronous device (disk requests return immediately, and
|
||||
// an interrupt happens later on). This is a layer on top of
|
||||
// the disk providing a synchronous interface (requests wait until
|
||||
// the request completes).
|
||||
//
|
||||
// Use a semaphore to synchronize the interrupt handlers with the
|
||||
// pending requests. And, because the physical disk can only
|
||||
// handle one operation at a time, use a lock to enforce mutual
|
||||
// exclusion.
|
||||
//
|
||||
// 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 "synchdisk.h"
|
||||
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// SynchDisk::SynchDisk
|
||||
// Initialize the synchronous interface to the physical disk, in turn
|
||||
// initializing the physical disk.
|
||||
//
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
SynchDisk::SynchDisk()
|
||||
{
|
||||
semaphore = new Semaphore("synch disk", 0);
|
||||
lock = new Lock("synch disk lock");
|
||||
disk = new Disk(this);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// SynchDisk::~SynchDisk
|
||||
// De-allocate data structures needed for the synchronous disk
|
||||
// abstraction.
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
SynchDisk::~SynchDisk()
|
||||
{
|
||||
delete disk;
|
||||
delete lock;
|
||||
delete semaphore;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// SynchDisk::ReadSector
|
||||
// Read the contents of a disk sector into a buffer. Return only
|
||||
// after the data has been read.
|
||||
//
|
||||
// "sectorNumber" -- the disk sector to read
|
||||
// "data" -- the buffer to hold the contents of the disk sector
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
void
|
||||
SynchDisk::ReadSector(int sectorNumber, char* data)
|
||||
{
|
||||
lock->Acquire(); // only one disk I/O at a time
|
||||
disk->ReadRequest(sectorNumber, data);
|
||||
semaphore->P(); // wait for interrupt
|
||||
lock->Release();
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// SynchDisk::WriteSector
|
||||
// Write the contents of a buffer into a disk sector. Return only
|
||||
// after the data has been written.
|
||||
//
|
||||
// "sectorNumber" -- the disk sector to be written
|
||||
// "data" -- the new contents of the disk sector
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
void
|
||||
SynchDisk::WriteSector(int sectorNumber, char* data)
|
||||
{
|
||||
lock->Acquire(); // only one disk I/O at a time
|
||||
disk->WriteRequest(sectorNumber, data);
|
||||
semaphore->P(); // wait for interrupt
|
||||
lock->Release();
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// SynchDisk::CallBack
|
||||
// Disk interrupt handler. Wake up any thread waiting for the disk
|
||||
// request to finish.
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
void
|
||||
SynchDisk::CallBack()
|
||||
{
|
||||
semaphore->V();
|
||||
}
|
||||
55
code/filesys/synchdisk.h
Normal file
55
code/filesys/synchdisk.h
Normal file
@@ -0,0 +1,55 @@
|
||||
// synchdisk.h
|
||||
// Data structures to export a synchronous interface to the raw
|
||||
// disk device.
|
||||
//
|
||||
// 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"
|
||||
|
||||
#ifndef SYNCHDISK_H
|
||||
#define SYNCHDISK_H
|
||||
|
||||
#include "disk.h"
|
||||
#include "synch.h"
|
||||
#include "callback.h"
|
||||
|
||||
// The following class defines a "synchronous" disk abstraction.
|
||||
// As with other I/O devices, the raw physical disk is an asynchronous device --
|
||||
// requests to read or write portions of the disk return immediately,
|
||||
// and an interrupt occurs later to signal that the operation completed.
|
||||
// (Also, the physical characteristics of the disk device assume that
|
||||
// only one operation can be requested at a time).
|
||||
//
|
||||
// This class provides the abstraction that for any individual thread
|
||||
// making a request, it waits around until the operation finishes before
|
||||
// returning.
|
||||
|
||||
class SynchDisk : public CallBackObj {
|
||||
public:
|
||||
SynchDisk(); // Initialize a synchronous disk,
|
||||
// by initializing the raw Disk.
|
||||
~SynchDisk(); // De-allocate the synch disk data
|
||||
|
||||
void ReadSector(int sectorNumber, char* data);
|
||||
// Read/write a disk sector, returning
|
||||
// only once the data is actually read
|
||||
// or written. These call
|
||||
// Disk::ReadRequest/WriteRequest and
|
||||
// then wait until the request is done.
|
||||
void WriteSector(int sectorNumber, char* data);
|
||||
|
||||
void CallBack(); // Called by the disk device interrupt
|
||||
// handler, to signal that the
|
||||
// current disk operation is complete.
|
||||
|
||||
private:
|
||||
Disk *disk; // Raw disk device
|
||||
Semaphore *semaphore; // To synchronize requesting thread
|
||||
// with the interrupt handler
|
||||
Lock *lock; // Only one read/write request
|
||||
// can be sent to the disk at a time
|
||||
};
|
||||
|
||||
#endif // SYNCHDISK_H
|
||||
Reference in New Issue
Block a user