urbackup_backend/urbackupcommon/SparseFile.cpp

410 lines
9.1 KiB
C++

#include "SparseFile.h"
#include <algorithm>
#include <assert.h>
namespace
{
int64 roundUp(int64 numToRound, int64 multiple)
{
return ((numToRound + multiple - 1) / multiple) * multiple;
}
int64 roundDown(int64 numToRound, int64 multiple)
{
return ((numToRound / multiple) * multiple);
}
}
SparseFile::SparseFile(IFsFile * backing_file, IFile * sparse_extends_f, bool read_only, int64 blocksize, bool take_file_ownership, int64 max_size)
: backing_file(backing_file), has_error(false), seek_pos(0), backing_pos(0), take_file_ownership(take_file_ownership), max_size(max_size)
{
int64 n_extents;
sparse_extends_f->Seek(0);
if (sparse_extends_f->Read(reinterpret_cast<char*>(&n_extents), sizeof(n_extents)) != sizeof(n_extents))
{
has_error = true;
return;
}
std::vector<IFsFile::SSparseExtent> sparse_extents;
sparse_extents.resize(static_cast<size_t>(n_extents));
if (sparse_extends_f->Read(reinterpret_cast<char*>(sparse_extents.data()), static_cast<_u32>(sparse_extents.size()*sizeof(IFsFile::SSparseExtent)))
!= static_cast<_u32>(sparse_extents.size()*sizeof(IFsFile::SSparseExtent)))
{
has_error = true;
return;
}
initWithSparseExtents(sparse_extents, read_only, blocksize);
}
SparseFile::SparseFile(IFsFile * backing_file, const std::vector<IFsFile::SSparseExtent>& sparse_extents, bool read_only, int64 blocksize, bool take_file_ownership, int64 max_size)
: backing_file(backing_file), has_error(false), seek_pos(0), backing_pos(0), take_file_ownership(take_file_ownership), max_size(max_size)
{
initWithSparseExtents(sparse_extents, read_only, blocksize);
}
SparseFile::~SparseFile()
{
if (take_file_ownership)
{
Server->destroy(backing_file);
}
}
bool SparseFile::hasError()
{
return has_error;
}
namespace
{
class BackingReadStrOp : public SparseFile::IOrigOp
{
public:
BackingReadStrOp(IFile* backing_file)
: backing_file(backing_file)
{}
virtual _u32 origOp(_u32 buffer_offset, _u32 max_size, bool * has_error)
{
std::string ret_add = backing_file->Read(max_size, has_error);
ret += ret_add;
return static_cast<_u32>(ret_add.size());
}
std::string getRet()
{
return ret;
}
private:
std::string ret;
IFile* backing_file;
};
}
std::string SparseFile::Read(int64 spos, _u32 tr, bool * has_error)
{
if (!Seek(spos))
{
if (has_error) *has_error = true;
return std::string();
}
return Read(tr, has_error);
}
std::string SparseFile::Read(_u32 tr, bool * has_error)
{
BackingReadStrOp read_str_op(backing_file);
_u32 read = mappedOrigOp(&read_str_op, tr, has_error);
return read_str_op.getRet();
}
namespace
{
class BackingReadBufOp : public SparseFile::IOrigOp
{
public:
BackingReadBufOp(IFile* backing_file, char * buffer)
: backing_file(backing_file), buffer(buffer)
{}
virtual _u32 origOp(_u32 buffer_offset, _u32 max_size, bool * has_error)
{
return backing_file->Read(buffer+buffer_offset, max_size, has_error);
}
private:
char * buffer;
IFile* backing_file;
};
}
_u32 SparseFile::Read(char * buffer, _u32 bsize, bool * has_error)
{
BackingReadBufOp read_buf_op(backing_file, buffer);
return mappedOrigOp(&read_buf_op, bsize, has_error);
}
_u32 SparseFile::Read(int64 spos, char * buffer, _u32 bsize, bool * has_error)
{
if (!Seek(spos))
{
if (has_error) *has_error = true;
return 0;
}
return Read(buffer, bsize, has_error);
}
_u32 SparseFile::Write(const std::string & tw, bool * has_error)
{
return Write(tw.data(), static_cast<_u32>(tw.size()), has_error);
}
_u32 SparseFile::Write(int64 spos, const std::string & tw, bool * has_error)
{
if (!Seek(spos))
{
if (has_error) *has_error = true;
return 0;
}
return Write(tw, has_error);
}
namespace
{
class BackingWriteBufOp : public SparseFile::IOrigOp
{
public:
BackingWriteBufOp(IFile* backing_file, const char * buffer)
: backing_file(backing_file), buffer(buffer)
{}
virtual _u32 origOp(_u32 buffer_offset, _u32 max_size, bool * has_error)
{
return backing_file->Write(buffer + buffer_offset, max_size, has_error);
}
private:
const char * buffer;
IFile* backing_file;
};
}
_u32 SparseFile::Write(const char * buffer, _u32 bsize, bool * has_error)
{
BackingWriteBufOp write_buf_op(backing_file, buffer);
return mappedOrigOp(&write_buf_op, bsize, has_error);
}
_u32 SparseFile::Write(int64 spos, const char * buffer, _u32 bsize, bool * has_error)
{
if (!Seek(spos))
{
if (has_error) *has_error = true;
return 0;
}
return Write(buffer, bsize, has_error);
}
bool SparseFile::Seek(_i64 spos)
{
seek_pos = spos;
backing_pos = mapToBackingOffset(spos);
return backing_file->Seek(backing_pos);
}
_i64 SparseFile::Size(void)
{
return backing_file->Size()-sparse_extents_size;
}
_i64 SparseFile::RealSize()
{
return backing_file->Size();
}
bool SparseFile::PunchHole(_i64 spos, _i64 size)
{
int64 punch_start = mapToBackingOffset(spos);
int64 punch_end = mapToBackingOffset(spos + size);
return backing_file->PunchHole(punch_start, punch_end - punch_start);
}
bool SparseFile::Sync()
{
return backing_file->Sync();
}
std::string SparseFile::getFilename(void)
{
return backing_file->getFilename();
}
IFsFile::os_file_handle SparseFile::getOsHandle(bool release_handle)
{
return backing_file->getOsHandle(release_handle);
}
_i64 SparseFile::getSparseSize()
{
return sparse_extents_size;
}
void SparseFile::initWithSparseExtents(const std::vector<IFsFile::SSparseExtent>& sparse_extents, bool read_only, int64 blocksize)
{
int64 fpos = 0;
int64 last_offset = 0;
int64 max_offset = 0;
sparse_extents_size = 0;
for (size_t i = 0; i < sparse_extents.size(); ++i)
{
IFsFile::SSparseExtent curr_extent = sparse_extents[i];
int64 offset = roundUp(curr_extent.offset, blocksize);
int64 offset_end = roundDown(curr_extent.offset + curr_extent.size, blocksize);
if (offset < offset_end)
{
int64 extent_size = offset_end - offset;
fpos += offset - last_offset;
last_offset = offset + extent_size;
sparse_extents_size += extent_size;
sparse_offsets.push_back(SPosMap(fpos, offset + extent_size));
max_offset = (std::max)(max_offset, curr_extent.offset + curr_extent.size);
}
}
if (max_size > 0)
{
max_offset = (std::min)(max_size, max_offset);
}
if (!sparse_offsets.empty() && sparse_offsets[0].offset == 0)
{
backing_pos = sparse_offsets[0].backing_offset;
}
if (max_offset > backing_file->Size())
{
if (!backing_file->Resize(max_offset))
{
has_error = true;
return;
}
}
if (!backing_file->Seek(backing_pos))
{
has_error = true;
return;
}
}
SparseFile::SPosMap SparseFile::nextBackingOffset()
{
std::vector<SPosMap>::iterator it = std::upper_bound(sparse_offsets.begin(), sparse_offsets.end(), SPosMap(seek_pos, -1));
if (it != sparse_offsets.end())
{
return *it;
}
else
{
return SPosMap();
}
}
SparseFile::SPosMap SparseFile::lastBackingOffset(int64 offset)
{
std::vector<SPosMap>::iterator it = std::upper_bound(sparse_offsets.begin(), sparse_offsets.end(), SPosMap(offset, -1));
if (it != sparse_offsets.begin())
{
--it;
return *it;
}
else
{
return SPosMap();
}
}
_u32 SparseFile::mappedOrigOp(IOrigOp * orig_op, _u32 op_size, bool * has_error)
{
_u32 op_size_orig = op_size;
while (op_size > 0)
{
SPosMap next = nextBackingOffset();
_u32 max_size = static_cast<_u32>(op_size);
if (next.offset != -1)
{
max_size = static_cast<_u32>((std::min)(static_cast<int64>(op_size), next.offset - seek_pos));
}
_u32 buffer_offset = op_size_orig - op_size;
_u32 backing_op_size = orig_op->origOp(buffer_offset, max_size, has_error);
seek_pos += backing_op_size;
op_size -= backing_op_size;
if (has_error != NULL && *has_error)
{
return op_size_orig - op_size;
}
if (seek_pos == next.offset)
{
backing_pos = next.backing_offset;
if (!backing_file->Seek(backing_pos))
{
if (has_error != NULL)
{
*has_error = true;
}
return op_size_orig - op_size;
}
}
else
{
break;
}
}
return op_size_orig - op_size;
}
IVdlVolCache* SparseFile::createVdlVolCache()
{
return NULL;
}
int64 SparseFile::getValidDataLength(IVdlVolCache* vol_cache)
{
return -1;
}
int64 SparseFile::mapToBackingOffset(int64 offset)
{
SPosMap last = lastBackingOffset(offset);
if (last.offset == -1)
{
return offset;
}
else
{
last.backing_offset += offset - last.offset;
return last.backing_offset;
}
}
void SparseFile::resetSparseExtentIter()
{
}
IFsFile::SSparseExtent SparseFile::nextSparseExtent()
{
return SSparseExtent();
}
bool SparseFile::Resize(int64 new_size, bool set_sparse)
{
return backing_file->Resize(mapToBackingOffset(new_size), set_sparse);
}
std::vector<IFsFile::SFileExtent> SparseFile::getFileExtents(int64 starting_offset, int64 block_size, bool & more_data, unsigned int flags)
{
return std::vector<SFileExtent>();
}