197 lines
6.7 KiB
C++
197 lines
6.7 KiB
C++
// 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"
|
|
|
|
#include <strings.h> /* for bzero */
|
|
|
|
//----------------------------------------------------------------------
|
|
// 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;
|
|
hdr = NULL;
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
// 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(void *into, int numBytes)
|
|
{
|
|
int result = ReadAt(into, numBytes, seekPosition);
|
|
seekPosition += result;
|
|
return result;
|
|
}
|
|
|
|
int
|
|
OpenFile::Write(const void *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(void *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(const void *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();
|
|
}
|