1/*
2 * Copyright 2001 - 2017, Axel D��rfler, axeld @pinc - software.de.
3 * Copyright 2020, Shubham Bhagat, shubhambhagat111@yahoo.com
4 * All rights reserved. Distributed under the terms of the MIT License.
5 */
6
7
8#include "Volume.h"
9
10#include "Checksum.h"
11#include "Inode.h"
12
13
14Volume::Volume(fs_volume *volume)
15	: fFSVolume(volume)
16{
17	fFlags = 0;
18	mutex_init(&fLock, "xfs volume");
19	TRACE("Volume::Volume() : Initialising volume");
20}
21
22
23Volume::~Volume()
24{
25	mutex_destroy(&fLock);
26	TRACE("Volume::Destructor : Removing Volume");
27}
28
29
30bool
31Volume::IsValidSuperBlock() const
32{
33	return fSuperBlock.IsValid();
34}
35
36
37status_t
38Volume::Identify(int fd, XfsSuperBlock *superBlock)
39{
40
41	TRACE("Volume::Identify() : Identifying Volume in progress");
42
43	//Create a buffer of 512 bytes for Crc verification
44	char buf[512];
45
46	if(read_pos(fd, 0, buf, 512) != 512)
47		return B_IO_ERROR;
48
49	memcpy(superBlock, buf, sizeof(XfsSuperBlock));
50
51	int version = B_BENDIAN_TO_HOST_INT16(superBlock->Version()) & XFS_SB_VERSION_NUMBITS;
52
53	// if its V5 filesystem check for superblock checksum
54	if (superBlock->MagicNum() == B_HOST_TO_BENDIAN_INT32(XFS_SB_MAGIC)
55		&& (version == 5 || superBlock->Crc() != 0)) {
56
57		TRACE("Superblock Crc: (%" B_PRIu32 ")\n", superBlock->Crc());
58
59		if(!xfs_verify_cksum(buf, 512, XfsSuperBlock::Offset_crc())) {
60			 ERROR("Filesystem is corrupted");
61			 return B_BAD_VALUE;
62		}
63
64	}
65
66	superBlock->SwapEndian();
67
68	if (!superBlock->IsValid()) {
69		ERROR("Volume::Identify(): Invalid Superblock!\n");
70		return B_BAD_VALUE;
71	}
72	return B_OK;
73}
74
75
76status_t
77Volume::Mount(const char *deviceName, uint32 flags)
78{
79	TRACE("Volume::Mount() : Mounting in progress");
80
81	flags |= B_MOUNT_READ_ONLY;
82
83	if ((flags & B_MOUNT_READ_ONLY) != 0) {
84		TRACE("Volume::Mount(): Read only\n");
85	} else {
86		TRACE("Volume::Mount(): Read write\n");
87	}
88
89	DeviceOpener opener(deviceName, (flags & B_MOUNT_READ_ONLY) != 0
90										? O_RDONLY
91										: O_RDWR);
92	fDevice = opener.Device();
93	if (fDevice < B_OK) {
94		ERROR("Volume::Mount(): couldn't open device\n");
95		return fDevice;
96	}
97
98	if (opener.IsReadOnly())
99		fFlags |= VOLUME_READ_ONLY;
100
101	// read the superblock
102	status_t status = Identify(fDevice, &fSuperBlock);
103	if (status != B_OK) {
104		ERROR("Volume::Mount(): Invalid super block!\n");
105		return B_BAD_VALUE;
106	}
107
108	if ((fSuperBlock.Version() & XFS_SB_VERSION_NUMBITS) == 5)
109		TRACE("Volume::Mount(): Valid Version 5 SuperBlock.\n");
110	else
111		TRACE("Volume::Mount(): Valid Version 4 SuperBlock.\n");
112
113
114	// check if the device size is large enough to hold the file system
115	off_t diskSize;
116	if (opener.GetSize(&diskSize) != B_OK) {
117		ERROR("Volume:Mount() Unable to get diskSize");
118		return B_ERROR;
119	}
120
121	opener.Keep();
122
123	//publish the root inode
124	Inode* rootInode = new(std::nothrow) Inode(this, Root());
125	if (rootInode == NULL)
126		return B_NO_MEMORY;
127
128	status = rootInode->Init();
129	if (status != B_OK)
130		return status;
131
132	status = publish_vnode(FSVolume(), Root(),
133		(void*)rootInode, &gxfsVnodeOps, rootInode->Mode(), 0);
134	if (status != B_OK)
135		return B_BAD_VALUE;
136
137	return B_OK;
138}
139
140
141status_t
142Volume::Unmount()
143{
144	TRACE("Volume::Unmount(): Unmounting");
145
146	TRACE("Volume::Unmount(): Closing device");
147	close(fDevice);
148
149	return B_OK;
150}
151