// 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. #include "copyright.h" #include "filehdr.h" #include "openfile.h" #include "system.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('f', "Reading %d bytes at %d, from file of length %d.\n", numBytes, position, 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++) 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('f', "Writing %d bytes at %d, from file of length %d.\n", numBytes, position, 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++) 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(); }