* Copyright 2001 - 2017, Axel DΓΆrfler, axeld @pinc - software.de.
* Copyright 2020, Shubham Bhagat, shubhambhagat111@yahoo.com
* All rights reserved. Distributed under the terms of the MIT License.
*/
#include "Volume.h"
#include "Checksum.h"
#include "Inode.h"
Volume::Volume(fs_volume *volume)
: fFSVolume(volume)
{
fFlags = 0;
mutex_init(&fLock, "xfs volume");
TRACE("Volume::Volume() : Initialising volume");
}
Volume::~Volume()
{
mutex_destroy(&fLock);
TRACE("Volume::Destructor : Removing Volume");
}
bool
Volume::IsValidSuperBlock() const
{
return fSuperBlock.IsValid();
}
status_t
Volume::Identify(int fd, XfsSuperBlock *superBlock)
{
TRACE("Volume::Identify() : Identifying Volume in progress");
char buf[512];
if(read_pos(fd, 0, buf, 512) != 512)
return B_IO_ERROR;
memcpy(superBlock, buf, sizeof(XfsSuperBlock));
int version = B_BENDIAN_TO_HOST_INT16(superBlock->Version()) & XFS_SB_VERSION_NUMBITS;
if (superBlock->MagicNum() == B_HOST_TO_BENDIAN_INT32(XFS_SB_MAGIC)
&& (version == 5 || superBlock->Crc() != 0)) {
TRACE("Superblock Crc: (%" B_PRIu32 ")\n", superBlock->Crc());
if(!xfs_verify_cksum(buf, 512, XfsSuperBlock::Offset_crc())) {
ERROR("Filesystem is corrupted");
return B_BAD_VALUE;
}
}
superBlock->SwapEndian();
if (!superBlock->IsValid()) {
ERROR("Volume::Identify(): Invalid Superblock!\n");
return B_BAD_VALUE;
}
return B_OK;
}
status_t
Volume::Mount(const char *deviceName, uint32 flags)
{
TRACE("Volume::Mount() : Mounting in progress");
flags |= B_MOUNT_READ_ONLY;
if ((flags & B_MOUNT_READ_ONLY) != 0) {
TRACE("Volume::Mount(): Read only\n");
} else {
TRACE("Volume::Mount(): Read write\n");
}
DeviceOpener opener(deviceName, (flags & B_MOUNT_READ_ONLY) != 0
? O_RDONLY
: O_RDWR);
fDevice = opener.Device();
if (fDevice < B_OK) {
ERROR("Volume::Mount(): couldn't open device\n");
return fDevice;
}
if (opener.IsReadOnly())
fFlags |= VOLUME_READ_ONLY;
status_t status = Identify(fDevice, &fSuperBlock);
if (status != B_OK) {
ERROR("Volume::Mount(): Invalid super block!\n");
return B_BAD_VALUE;
}
if ((fSuperBlock.Version() & XFS_SB_VERSION_NUMBITS) == 5)
TRACE("Volume::Mount(): Valid Version 5 SuperBlock.\n");
else
TRACE("Volume::Mount(): Valid Version 4 SuperBlock.\n");
off_t diskSize;
if (opener.GetSize(&diskSize) != B_OK) {
ERROR("Volume:Mount() Unable to get diskSize");
return B_ERROR;
}
opener.Keep();
Inode* rootInode = new(std::nothrow) Inode(this, Root());
if (rootInode == NULL)
return B_NO_MEMORY;
status = rootInode->Init();
if (status != B_OK)
return status;
status = publish_vnode(FSVolume(), Root(),
(void*)rootInode, &gxfsVnodeOps, rootInode->Mode(), 0);
if (status != B_OK)
return B_BAD_VALUE;
return B_OK;
}
status_t
Volume::Unmount()
{
TRACE("Volume::Unmount(): Unmounting");
TRACE("Volume::Unmount(): Closing device");
close(fDevice);
return B_OK;
}