// distribution boxbackup-0.10 (svn version: 494)
//
// Copyright (c) 2003 - 2006
// Ben Summers and contributors. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
// 3. All use of this software and associated advertising materials must
// display the following acknowledgment:
// This product includes software developed by Ben Summers.
// 4. The names of the Authors may not be used to endorse or promote
// products derived from this software without specific prior written
// permission.
//
// [Where legally impermissible the Authors do not disclaim liability for
// direct physical injury or death caused solely by defects in the software
// unless it is modified by a third party.]
//
// THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT,
// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
//
//
// --------------------------------------------------------------------------
//
// File
// Name: RaidFileWrite.cpp
// Purpose: Writing RAID like files
// Created: 2003/07/10
//
// --------------------------------------------------------------------------
#include "Box.h"
#include <errno.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <sys/file.h>
#include <stdio.h>
#include <string.h>
#include "Guards.h"
#include "RaidFileWrite.h"
#include "RaidFileController.h"
#include "RaidFileException.h"
#include "RaidFileUtil.h"
#include "Utils.h"
// For DirectoryExists fn
#include "RaidFileRead.h"
#include "MemLeakFindOn.h"
// should be a multiple of 2
#define TRANSFORM_BLOCKS_TO_LOAD 4
// Must have this number of discs in the set
#define TRANSFORM_NUMBER_DISCS_REQUIRED 3
// --------------------------------------------------------------------------
//
// Function
// Name: RaidFileWrite::RaidFileWrite(int, const std::string &)
// Purpose: Construtor, just stores requried details
// Created: 2003/07/10
//
// --------------------------------------------------------------------------
RaidFileWrite::RaidFileWrite(int SetNumber, const std::string &Filename)
: mSetNumber(SetNumber),
mFilename(Filename),
mOSFileHandle(-1) // not valid file handle
{
}
// --------------------------------------------------------------------------
//
// Function
// Name: RaidFileWrite::~RaidFileWrite()
// Purpose: Destructor (will discard written file if not commited)
// Created: 2003/07/10
//
// --------------------------------------------------------------------------
RaidFileWrite::~RaidFileWrite()
{
if(mOSFileHandle != -1)
{
Discard();
}
}
// --------------------------------------------------------------------------
//
// Function
// Name: RaidFileWrite::Open()
// Purpose: Opens the file for writing
// Created: 2003/07/10
//
// --------------------------------------------------------------------------
void RaidFileWrite::Open(bool AllowOverwrite)
{
if(mOSFileHandle != -1)
{
THROW_EXCEPTION(RaidFileException, AlreadyOpen)
}
// Get disc set
RaidFileController &rcontroller(RaidFileController::GetController());
RaidFileDiscSet rdiscSet(rcontroller.GetDiscSet(mSetNumber));
// Check for overwriting? (step 1)
if(!AllowOverwrite)
{
// See if the file exists already -- can't overwrite existing files
RaidFileUtil::ExistType existance = RaidFileUtil::RaidFileExists(rdiscSet, mFilename);
if(existance != RaidFileUtil::NoFile)
{
TRACE2("Trying to overwrite raidfile %d %s\n", mSetNumber, mFilename.c_str());
THROW_EXCEPTION(RaidFileException, CannotOverwriteExistingFile)
}
}
// Get the filename for the write file
std::string writeFilename(RaidFileUtil::MakeWriteFileName(rdiscSet, mFilename));
// Add on a temporary extension
writeFilename += 'X';
// Attempt to open
mOSFileHandle = ::open(writeFilename.c_str(), O_WRONLY | O_CREAT,
S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
if(mOSFileHandle == -1)
{
THROW_EXCEPTION(RaidFileException, ErrorOpeningWriteFile)
}
// Get a lock on the write file
#ifdef HAVE_FLOCK
int errnoBlock = EWOULDBLOCK;
if(::flock(mOSFileHandle, LOCK_EX | LOCK_NB) != 0)
#else
int errnoBlock = EAGAIN;
struct flock desc;
desc.l_type = F_WRLCK;
desc.l_whence = SEEK_SET;
desc.l_start = 0;
desc.l_len = 0;
if(::fcntl(mOSFileHandle, F_SETLK, &desc) != 0)
#endif
{
// Lock was not obtained.
bool wasLocked = (errno == errnoBlock);
// Close the file
::close(mOSFileHandle);
mOSFileHandle = -1;
// Report an exception?
if(wasLocked)
{
THROW_EXCEPTION(RaidFileException, FileIsCurrentlyOpenForWriting)
}
else
{
// Random error occured
THROW_EXCEPTION(RaidFileException, OSError)
}
}
// Truncate it to size zero
if(::ftruncate(mOSFileHandle, 0) != 0)
{
THROW_EXCEPTION(RaidFileException, ErrorOpeningWriteFileOnTruncate)
}
// Done!
}
// --------------------------------------------------------------------------
//
// Function
// Name: RaidFileWrite::Write(const void *, int)
// Purpose: Writes a block of data
// Created: 2003/07/10
//
// --------------------------------------------------------------------------
void RaidFileWrite::Write(const void *pBuffer, int Length)
{
// open?
if(mOSFileHandle == -1)
{
THROW_EXCEPTION(RaidFileException, NotOpen)
}
// Write data
int written = ::write(mOSFileHandle, pBuffer, Length);
if(written != Length)
{
TRACE3("RaidFileWrite::Write: Write failure, Length = %d, written = %d, errno = %d\n", Length, written, errno);
THROW_EXCEPTION(RaidFileException, OSError)
}
}
// --------------------------------------------------------------------------
//
// Function
// Name: RaidFileWrite::GetPosition()
// Purpose: Returns current position in file
// Created: 2003/07/10
//
// --------------------------------------------------------------------------
IOStream::pos_type RaidFileWrite::GetPosition() const
{
// open?
if(mOSFileHandle == -1)
{
THROW_EXCEPTION(RaidFileException, NotOpen)
}
// Use lseek to find the current file position
off_t p = ::lseek(mOSFileHandle, 0, SEEK_CUR);
if(p == -1)
{
THROW_EXCEPTION(RaidFileException, OSError)
}
return p;
}
// --------------------------------------------------------------------------
//
// Function
// Name: RaidFileWrite::Seek(RaidFileWrite::pos_type, bool)
// Purpose: Seeks in the file, relative to current position if Relative is true.
// Created: 2003/07/10
//
// --------------------------------------------------------------------------
void RaidFileWrite::Seek(IOStream::pos_type SeekTo, int SeekType)
{
// open?
if(mOSFileHandle == -1)
{
THROW_EXCEPTION(RaidFileException, NotOpen)
}
// Seek...
if(::lseek(mOSFileHandle, SeekTo, ConvertSeekTypeToOSWhence(SeekType)) == -1)
{
THROW_EXCEPTION(RaidFileException, OSError)
}
}
// --------------------------------------------------------------------------
//
// Function
// Name: RaidFileWrite::Commit(bool)
// Purpose: Closes, and commits the written file
// Created: 2003/07/10
//
// --------------------------------------------------------------------------
void RaidFileWrite::Commit(bool ConvertToRaidNow)
{
// open?
if(mOSFileHandle == -1)
{
THROW_EXCEPTION(RaidFileException, NotOpen)
}
// Rename it into place -- BEFORE it's closed so lock remains
RaidFileController &rcontroller(RaidFileController::GetController());
RaidFileDiscSet rdiscSet(rcontroller.GetDiscSet(mSetNumber));
// Get the filename for the write file
std::string renameTo(RaidFileUtil::MakeWriteFileName(rdiscSet, mFilename));
// And the current name
std::string renameFrom(renameTo + 'X');
if(::rename(renameFrom.c_str(), renameTo.c_str()) != 0)
{
THROW_EXCEPTION(RaidFileException, OSError)
}
// Close file...
if(::close(mOSFileHandle) != 0)
{
THROW_EXCEPTION(RaidFileException, OSError)
}
mOSFileHandle = -1;
// Raid it?
if(ConvertToRaidNow)
{
TransformToRaidStorage();
}
}
// --------------------------------------------------------------------------
//
// Function
// Name: RaidFileWrite::Discard()
// Purpose: Closes, discarding the data written.
// Created: 2003/07/10
//
// --------------------------------------------------------------------------
void RaidFileWrite::Discard()
{
// open?
if(mOSFileHandle == -1)
{
THROW_EXCEPTION(RaidFileException, NotOpen)
}
// Get disc set
RaidFileController &rcontroller(RaidFileController::GetController());
RaidFileDiscSet rdiscSet(rcontroller.GetDiscSet(mSetNumber));
// Get the filename for the write file (temporary)
std::string writeFilename(RaidFileUtil::MakeWriteFileName(rdiscSet, mFilename));
writeFilename += 'X';
// Unlink and close it
if((::unlink(writeFilename.c_str()) != 0)
|| (::close(mOSFileHandle) != 0))
{
THROW_EXCEPTION(RaidFileException, OSError)
}
// reset file handle
mOSFileHandle = -1;
}
// --------------------------------------------------------------------------
//
// Function
// Name: RaidFileWrite::TransformToRaidStorage()
// Purpose: Turns the file into the RAID storage form
// Created: 2003/07/11
//
// --------------------------------------------------------------------------
void RaidFileWrite::TransformToRaidStorage()
{
// open?
if(mOSFileHandle != -1)
{
THROW_EXCEPTION(RaidFileException, WriteFileOpenOnTransform)
}
// Get disc set
RaidFileController &rcontroller(RaidFileController::GetController());
RaidFileDiscSet rdiscSet(rcontroller.GetDiscSet(mSetNumber));
if(rdiscSet.IsNonRaidSet())
{
// Not in RAID mode -- do nothing
return;
}
// Otherwise check that it's the right sized set
if(TRANSFORM_NUMBER_DISCS_REQUIRED != rdiscSet.size())
{
THROW_EXCEPTION(RaidFileException, WrongNumberOfDiscsInSet)
}
unsigned int blockSize = rdiscSet.GetBlockSize();
// Get the filename for the write file (and get the disc set name for the start disc)
int startDisc = 0;
std::string writeFilename(RaidFileUtil::MakeWriteFileName(rdiscSet, mFilename, &startDisc));
// Open it
FileHandleGuard<> writeFile(writeFilename.c_str());
// Get file information for write file
struct stat writeFileStat;
if(::fstat(writeFile, &writeFileStat) != 0)
{
THROW_EXCEPTION(RaidFileException, OSError)
}
// // DEBUG MODE -- check file system size block size is same as block size for files
// // doesn't really apply, as space benefits of using fragment size are worth efficiency,
// // and anyway, it'll be buffered eventually so it won't matter.
// #ifndef NDEBUG
// {
// if(writeFileStat.st_blksize != blockSize)
// {
// TRACE2("TransformToRaidStorage: optimal block size of file = %d, of set = %d, MISMATCH\n",
// writeFileStat.st_blksize, blockSize);
// }
// }
// #endif
// How many blocks is the file? (rounding up)
int writeFileSizeInBlocks = (writeFileStat.st_size + (blockSize - 1)) / blockSize;
// And how big should the buffer be? (round up to multiple of 2, and no bigger than the preset limit)
int bufferSizeBlocks = (writeFileSizeInBlocks + 1) & ~1;
if(bufferSizeBlocks > TRANSFORM_BLOCKS_TO_LOAD) bufferSizeBlocks = TRANSFORM_BLOCKS_TO_LOAD;
// How big should the buffer be?
int bufferSize = (TRANSFORM_BLOCKS_TO_LOAD * blockSize);
// Allocate buffer...
MemoryBlockGuard<char*> buffer(bufferSize);
// Allocate buffer for parity file
MemoryBlockGuard<char*> parityBuffer(blockSize);
// Get filenames of eventual files
std::string stripe1Filename(RaidFileUtil::MakeRaidComponentName(rdiscSet, mFilename, (startDisc + 0) % TRANSFORM_NUMBER_DISCS_REQUIRED));
std::string stripe2Filename(RaidFileUtil::MakeRaidComponentName(rdiscSet, mFilename, (startDisc + 1) % TRANSFORM_NUMBER_DISCS_REQUIRED));
std::string parityFilename(RaidFileUtil::MakeRaidComponentName(rdiscSet, mFilename, (startDisc + 2) % TRANSFORM_NUMBER_DISCS_REQUIRED));
// Make write equivalents
std::string stripe1FilenameW(stripe1Filename + 'P');
std::string stripe2FilenameW(stripe2Filename + 'P');
std::string parityFilenameW(parityFilename + 'P');
// Then open them all for writing (in strict order)
try
{
#if HAVE_DECL_O_EXLOCK
FileHandleGuard<(O_WRONLY | O_CREAT | O_EXCL | O_EXLOCK)> stripe1(stripe1FilenameW.c_str());
FileHandleGuard<(O_WRONLY | O_CREAT | O_EXCL | O_EXLOCK)> stripe2(stripe2FilenameW.c_str());
FileHandleGuard<(O_WRONLY | O_CREAT | O_EXCL | O_EXLOCK)> parity(parityFilenameW.c_str());
#else
FileHandleGuard<(O_WRONLY | O_CREAT | O_EXCL)> stripe1(stripe1FilenameW.c_str());
FileHandleGuard<(O_WRONLY | O_CREAT | O_EXCL)> stripe2(stripe2FilenameW.c_str());
FileHandleGuard<(O_WRONLY | O_CREAT | O_EXCL)> parity(parityFilenameW.c_str());
#endif
// Then... read in data...
int bytesRead = -1;
bool sizeRecordRequired = false;
int blocksDone = 0;
while((bytesRead = ::read(writeFile, buffer, bufferSize)) > 0)
{
// Blocks to do...
int blocksToDo = (bytesRead + (blockSize - 1)) / blockSize;
// Need to add zeros to end?
int blocksRoundUp = (blocksToDo + 1) & ~1;
int zerosEnd = (blocksRoundUp * blockSize);
if(bytesRead != zerosEnd)
{
// Set the end of the blocks to zero
::memset(buffer + bytesRead, 0, zerosEnd - bytesRead);
}
// number of int's to XOR
unsigned int num = blockSize / sizeof(unsigned int);
// Then... calculate and write parity data
for(int b = 0; b < blocksToDo; b += 2)
{
// Calculate int pointers
unsigned int *pstripe1 = (unsigned int *)(buffer + (b * blockSize));
unsigned int *pstripe2 = (unsigned int *)(buffer + ((b+1) * blockSize));
unsigned int *pparity = (unsigned int *)((char*)parityBuffer);
// Do XOR
for(unsigned int n = 0; n < num; ++n)
{
pparity[n] = pstripe1[n] ^ pstripe2[n];
}
// Size of parity to write...
int parityWriteSize = blockSize;
// Adjust if it's the last block
if((blocksDone + (b + 2)) >= writeFileSizeInBlocks)
{
// Yes...
unsigned int bytesInLastTwoBlocks = bytesRead - (b * blockSize);
// Some special cases...
// Zero will never happen... but in the (imaginary) case it does, the file size will be appended
// by the test at the end.
if(bytesInLastTwoBlocks == sizeof(RaidFileRead::FileSizeType)
|| bytesInLastTwoBlocks == blockSize)
{
// Write the entire block, and put the file size at end
sizeRecordRequired = true;
}
else if(bytesInLastTwoBlocks < blockSize)
{
// write only these bits
parityWriteSize = bytesInLastTwoBlocks;
}
else if(bytesInLastTwoBlocks < ((blockSize * 2) - sizeof(RaidFileRead::FileSizeType)))
{
// XOR in the size at the end of the parity block
ASSERT(sizeof(RaidFileRead::FileSizeType) == (2*sizeof(unsigned int)));
ASSERT(sizeof(RaidFileRead::FileSizeType) >= sizeof(off_t));
int sizePos = (blockSize/sizeof(unsigned int)) - 2;
union { RaidFileRead::FileSizeType l; unsigned int i[2]; } sw;
sw.l = box_hton64(writeFileStat.st_size);
pparity[sizePos+0] = pstripe1[sizePos+0] ^ sw.i[0];
pparity[sizePos+1] = pstripe1[sizePos+1] ^ sw.i[1];
}
else
{
// Write the entire block, and put the file size at end
sizeRecordRequired = true;
}
}
// Write block
if(::write(parity, parityBuffer, parityWriteSize) != parityWriteSize)
{
THROW_EXCEPTION(RaidFileException, OSError)
}
}
// Write stripes
char *writeFrom = buffer;
for(int l = 0; l < blocksToDo; ++l)
{
// Write the block
int toWrite = (l == (blocksToDo - 1))
?(bytesRead - ((blocksToDo-1)*blockSize))
:blockSize;
if(::write(((l&1)==0)?stripe1:stripe2, writeFrom, toWrite) != toWrite)
{
THROW_EXCEPTION(RaidFileException, OSError)
}
// Next block
writeFrom += blockSize;
}
// Count of blocks done
blocksDone += blocksToDo;
}
// Error on read?
if(bytesRead == -1)
{
THROW_EXCEPTION(RaidFileException, OSError)
}
// Special case for zero length files
if(writeFileStat.st_size == 0)
{
sizeRecordRequired = true;
}
// Might need to write the file size to the end of the parity file
// if it can't be worked out some other means -- size is required to rebuild the file if one of the stripe files is missing
if(sizeRecordRequired)
{
ASSERT(sizeof(writeFileStat.st_size) <= sizeof(RaidFileRead::FileSizeType));
RaidFileRead::FileSizeType sw = box_hton64(writeFileStat.st_size);
ASSERT((::lseek(parity, 0, SEEK_CUR) % blockSize) == 0);
if(::write(parity, &sw, sizeof(sw)) != sizeof(sw))
{
THROW_EXCEPTION(RaidFileException, OSError)
}
}
// Then close the written files (note in reverse order of opening)
parity.Close();
stripe2.Close();
stripe1.Close();
// Rename them into place
if(::rename(stripe1FilenameW.c_str(), stripe1Filename.c_str()) != 0
|| ::rename(stripe2FilenameW.c_str(), stripe2Filename.c_str()) != 0
|| ::rename(parityFilenameW.c_str(), parityFilename.c_str()) != 0)
{
THROW_EXCEPTION(RaidFileException, OSError)
}
// Close the write file
writeFile.Close();
// Finally delete the write file
if(::unlink(writeFilename.c_str()) != 0)
{
THROW_EXCEPTION(RaidFileException, OSError)
}
}
catch(...)
{
// Unlink all the dodgy files
::unlink(stripe1Filename.c_str());
::unlink(stripe2Filename.c_str());
::unlink(parityFilename.c_str());
::unlink(stripe1FilenameW.c_str());
::unlink(stripe2FilenameW.c_str());
::unlink(parityFilenameW.c_str());
// and send the error on its way
throw;
}
}
// --------------------------------------------------------------------------
//
// Function
// Name: RaidFileWrite::Delete()
// Purpose: Deletes a RAID file
// Created: 2003/07/13
//
// --------------------------------------------------------------------------
void RaidFileWrite::Delete()
{
// Get disc set
RaidFileController &rcontroller(RaidFileController::GetController());
RaidFileDiscSet rdiscSet(rcontroller.GetDiscSet(mSetNumber));
// See if the file exists already -- can't delete files which don't exist
RaidFileUtil::ExistType existance = RaidFileUtil::RaidFileExists(rdiscSet, mFilename);
if(existance == RaidFileUtil::NoFile)
{
THROW_EXCEPTION(RaidFileException, RaidFileDoesntExist)
}
// Get the filename for the write file
std::string writeFilename(RaidFileUtil::MakeWriteFileName(rdiscSet, mFilename));
// Attempt to delete it
bool deletedSomething = false;
if(::unlink(writeFilename.c_str()) == 0)
{
deletedSomething = true;
}
// If we're not running in RAID mode, stop now
if(rdiscSet.size() == 1)
{
return;
}
// Now the other files
std::string stripe1Filename(RaidFileUtil::MakeRaidComponentName(rdiscSet, mFilename, 0 % TRANSFORM_NUMBER_DISCS_REQUIRED));
std::string stripe2Filename(RaidFileUtil::MakeRaidComponentName(rdiscSet, mFilename, 1 % TRANSFORM_NUMBER_DISCS_REQUIRED));
std::string parityFilename(RaidFileUtil::MakeRaidComponentName(rdiscSet, mFilename, 2 % TRANSFORM_NUMBER_DISCS_REQUIRED));
if(::unlink(stripe1Filename.c_str()) == 0)
{
deletedSomething = true;
}
if(::unlink(stripe2Filename.c_str()) == 0)
{
deletedSomething = true;
}
if(::unlink(parityFilename.c_str()) == 0)
{
deletedSomething = true;
}
// Check something happened
if(!deletedSomething)
{
THROW_EXCEPTION(RaidFileException, OSError)
}
}
// --------------------------------------------------------------------------
//
// Function
// Name: RaidFileWrite::CreateDirectory(int, const std::string &, bool, int)
// Purpose: Creates a directory within the raid file directories with the given name.
// Created: 2003/08/20
//
// --------------------------------------------------------------------------
void RaidFileWrite::CreateDirectory(int SetNumber, const std::string &rDirName, bool Recursive, int mode)
{
// Get disc set
RaidFileController &rcontroller(RaidFileController::GetController());
RaidFileDiscSet rdiscSet(rcontroller.GetDiscSet(SetNumber));
// Pass on...
CreateDirectory(rdiscSet, rDirName, Recursive, mode);
}
// --------------------------------------------------------------------------
//
// Function
// Name: RaidFileWrite::CreateDirectory(const RaidFileDiscSet &, const std::string &, bool, int)
// Purpose: Creates a directory within the raid file directories with the given name.
// Created: 2003/08/20
//
// --------------------------------------------------------------------------
void RaidFileWrite::CreateDirectory(const RaidFileDiscSet &rSet, const std::string &rDirName, bool Recursive, int mode)
{
if(Recursive)
{
// split up string
std::vector<std::string> elements;
SplitString(rDirName, DIRECTORY_SEPARATOR_ASCHAR, elements);
// Do each element in turn
std::string pn;
for(unsigned int e = 0; e < elements.size(); ++e)
{
// Only do this if the element has some text in it
if(elements[e].size() > 0)
{
pn += elements[e];
if(!RaidFileRead::DirectoryExists(rSet, pn))
{
CreateDirectory(rSet, pn, false, mode);
}
// add separator
pn += DIRECTORY_SEPARATOR_ASCHAR;
}
}
return;
}
// Create a directory in every disc of the set
for(unsigned int l = 0; l < rSet.size(); ++l)
{
// build name
std::string dn(rSet[l] + DIRECTORY_SEPARATOR + rDirName);
// attempt to create
if(::mkdir(dn.c_str(), mode) != 0)
{
if(errno == EEXIST)
{
// No. Bad things.
THROW_EXCEPTION(RaidFileException, FileExistsInDirectoryCreation)
}
else
{
THROW_EXCEPTION(RaidFileException, OSError)
}
}
}
}
// --------------------------------------------------------------------------
//
// Function
// Name: RaidFileWrite::Read(void *, int, int)
// Purpose: Unsupported, will exception
// Created: 2003/08/21
//
// --------------------------------------------------------------------------
int RaidFileWrite::Read(void *pBuffer, int NBytes, int Timeout)
{
THROW_EXCEPTION(RaidFileException, UnsupportedReadWriteOrClose)
}
// --------------------------------------------------------------------------
//
// Function
// Name: RaidFileWrite::Close()
// Purpose: Close, discarding file.
// Created: 2003/08/21
//
// --------------------------------------------------------------------------
void RaidFileWrite::Close()
{
TRACE0("Warning: RaidFileWrite::Close() called, discarding file\n");
if(mOSFileHandle != -1)
{
Discard();
}
}
// --------------------------------------------------------------------------
//
// Function
// Name: RaidFileWrite::StreamDataLeft()
// Purpose: Never any data left to read!
// Created: 2003/08/21
//
// --------------------------------------------------------------------------
bool RaidFileWrite::StreamDataLeft()
{
return false;
}
// --------------------------------------------------------------------------
//
// Function
// Name: RaidFileWrite::StreamClosed()
// Purpose: Is stream closed for writing?
// Created: 2003/08/21
//
// --------------------------------------------------------------------------
bool RaidFileWrite::StreamClosed()
{
return mOSFileHandle == -1;
}
// --------------------------------------------------------------------------
//
// Function
// Name: RaidFileWrite::GetFileSize()
// Purpose: Returns the size of the file written.
// Can only be used before the file is commited.
// Created: 2003/09/03
//
// --------------------------------------------------------------------------
IOStream::pos_type RaidFileWrite::GetFileSize()
{
if(mOSFileHandle == -1)
{
THROW_EXCEPTION(RaidFileException, CanOnlyGetFileSizeBeforeCommit)
}
// Stat to get size
struct stat st;
if(fstat(mOSFileHandle, &st) != 0)
{
THROW_EXCEPTION(RaidFileException, OSError)
}
return st.st_size;
}
// --------------------------------------------------------------------------
//
// Function
// Name: RaidFileWrite::GetDiscUsageInBlocks()
// Purpose: Returns the amount of disc space used, in blocks.
// Can only be used before the file is commited.
// Created: 2003/09/03
//
// --------------------------------------------------------------------------
IOStream::pos_type RaidFileWrite::GetDiscUsageInBlocks()
{
if(mOSFileHandle == -1)
{
THROW_EXCEPTION(RaidFileException, CanOnlyGetUsageBeforeCommit)
}
// Stat to get size
struct stat st;
if(fstat(mOSFileHandle, &st) != 0)
{
THROW_EXCEPTION(RaidFileException, OSError)
}
// Then return calculation
RaidFileController &rcontroller(RaidFileController::GetController());
RaidFileDiscSet rdiscSet(rcontroller.GetDiscSet(mSetNumber));
return RaidFileUtil::DiscUsageInBlocks(st.st_size, rdiscSet);
}
syntax highlighted by Code2HTML, v. 0.9.1