#include "Inode.h"
#include <string.h>
#define TRACE_UFS2
#ifdef TRACE_UFS2
#define TRACE(x...) dprintf("\33[34mufs2:\33[0m " x)
#else
#define TRACE(x...) ;
#endif
#define ERROR(x...) dprintf("\33[34mufs2:\33[0m " x)
Inode::Inode(Volume* volume, ino_t id)
:
fVolume(volume),
fID(id),
fCache(NULL),
fMap(NULL)
{
rw_lock_init(&fLock, "ufs2 inode");
int fd = fVolume->Device();
ufs2_super_block* superblock = (ufs2_super_block* )&fVolume->SuperBlock();
int64_t fs_block = ino_to_fsba(superblock, id);
int64_t offset_in_block = ino_to_fsbo(superblock, id);
int64_t offset = fs_block * superblock->fs_fsize + offset_in_block * sizeof(fNode);
if (read_pos(fd, offset, (void*)&fNode, sizeof(fNode)) != sizeof(fNode)) {
ERROR("Inode::Inode(): IO Error\n");
fInitStatus = B_IO_ERROR;
return;
}
fInitStatus = B_OK;
if (fInitStatus == B_OK) {
if (!IsDirectory() && !IsSymLink()) {
fCache = file_cache_create(fVolume->ID(), ID(), Size());
fMap = file_map_create(fVolume->ID(), ID(), Size());
}
}
}
Inode::Inode(Volume* volume, ino_t id, const ufs2_inode& item)
:
fVolume(volume),
fID(id),
fCache(NULL),
fMap(NULL),
fInitStatus(B_OK),
fNode(item)
{
if (!IsDirectory() && !IsSymLink()) {
fCache = file_cache_create(fVolume->ID(), ID(), Size());
fMap = file_map_create(fVolume->ID(), ID(), Size());
}
}
Inode::Inode(Volume* volume)
:
fVolume(volume),
fID(0),
fCache(NULL),
fMap(NULL),
fInitStatus(B_NO_INIT)
{
rw_lock_init(&fLock, "ufs2 inode");
}
Inode::~Inode()
{
TRACE("Inode destructor\n");
file_cache_delete(FileCache());
file_map_delete(Map());
TRACE("Inode destructor: Done\n");
}
status_t
Inode::InitCheck()
{
return fInitStatus;
}
status_t
Inode::ReadAt(off_t file_offset, uint8* buffer, size_t* _length)
{
int fd = fVolume->Device();
ufs2_super_block super_block = fVolume->SuperBlock();
int32_t blockSize = super_block.fs_bsize;
off_t pos;
int64_t size = Size();
off_t startBlockNumber = file_offset / blockSize;
off_t endBlockNumber = (file_offset + *_length) / blockSize;
off_t blockOffset = file_offset % blockSize;
ssize_t length = 0;
if (size <= file_offset || size < 0 || file_offset < 0) {
*_length = 0;
return B_OK;
}
if ((int64_t) *_length > size - file_offset)
*_length = size - file_offset;
if (startBlockNumber != endBlockNumber) {
ssize_t remainingLength = blockSize - blockOffset;
for (; startBlockNumber <= endBlockNumber; startBlockNumber++) {
pos = FindBlock(startBlockNumber, blockOffset);
if (remainingLength > (int64_t) *_length - length)
remainingLength = *_length - length;
length += read_pos(fd, pos, buffer + length, remainingLength);
blockOffset = 0;
remainingLength = *_length - length;
remainingLength = blockSize;
}
*_length = length;
return B_OK;
}
pos = FindBlock(startBlockNumber, blockOffset);
length = read_pos(fd, pos, buffer, *_length);
*_length = length;
return B_OK;
}
off_t
Inode::FindBlock(off_t blockNumber, off_t blockOffset)
{
int fd = fVolume->Device();
ufs2_super_block super_block = fVolume->SuperBlock();
int32_t blockSize = super_block.fs_bsize;
int32_t fragmentSize = super_block.fs_fsize;
off_t indirectOffset;
int64_t directBlock;
off_t numberOfBlockPointers = blockSize / 8;
const off_t numberOfIndirectBlocks = numberOfBlockPointers;
const off_t numberOfDoubleIndirectBlocks = numberOfBlockPointers
* numberOfBlockPointers;
if (blockNumber < 12) {
return GetBlockPointer(blockNumber) * fragmentSize + blockOffset;
} else if (blockNumber < numberOfIndirectBlocks + 12) {
blockNumber = blockNumber - 12;
indirectOffset = GetIndirectBlockPointer() *
fragmentSize + (8 * blockNumber);
read_pos(fd, indirectOffset,
(void*)&directBlock, sizeof(directBlock));
return directBlock * fragmentSize + blockOffset;
} else if (blockNumber < numberOfDoubleIndirectBlocks
+ numberOfIndirectBlocks + 12) {
blockNumber = blockNumber - numberOfBlockPointers - 12;
off_t indirectBlockNumber = blockNumber / numberOfBlockPointers;
indirectOffset = GetDoubleIndirectBlockPtr() *
fragmentSize + (8 * indirectBlockNumber);
int64_t indirectPointer;
read_pos(fd, indirectOffset,
(void*)&indirectPointer, sizeof(directBlock));
indirectOffset = indirectPointer * fragmentSize
+ (8 * (blockNumber % numberOfBlockPointers));
read_pos(fd, indirectOffset,
(void*)&directBlock, sizeof(directBlock));
return directBlock * fragmentSize + blockOffset;
} else if (blockNumber < (numberOfIndirectBlocks
* numberOfDoubleIndirectBlocks)
+ (numberOfDoubleIndirectBlocks + numberOfBlockPointers + 12)) {
blockNumber = blockNumber - numberOfDoubleIndirectBlocks
- numberOfBlockPointers - 12;
off_t indirectBlockNumber = blockNumber / numberOfDoubleIndirectBlocks;
indirectOffset = GetTripleIndirectBlockPtr() *
fragmentSize + (8 * indirectBlockNumber);
int64_t indirectPointer;
read_pos(fd, indirectOffset,
(void*)&indirectPointer, sizeof(directBlock));
indirectBlockNumber = blockNumber / numberOfBlockPointers;
indirectOffset = indirectPointer * fragmentSize
+ (8 * indirectBlockNumber);
read_pos(fd, indirectOffset,
(void*)&indirectPointer, sizeof(directBlock));
indirectOffset = indirectPointer * fragmentSize
+ (8 * (blockNumber % numberOfBlockPointers));
read_pos(fd, indirectOffset,
(void*)&directBlock, sizeof(directBlock));
return directBlock * fragmentSize + blockOffset;
}
return B_BAD_VALUE;
}
status_t
Inode::ReadLink(char* buffer, size_t *_bufferSize)
{
strlcpy(buffer, fNode.symlinkpath, *_bufferSize);
return B_OK;
}
status_t
Inode::CheckPermissions(int accessMode) const
{
if ((accessMode & W_OK) != 0)
return B_READ_ONLY_DEVICE;
return check_access_permissions(accessMode, Mode(), (gid_t)GroupID(),
(uid_t)UserID());
}