1/*
2 * Copyright 2020 Suhel Mehta, mehtasuhel@gmail.com
3 * All rights reserved. Distributed under the terms of the MIT License.
4 */
5#include "Volume.h"
6
7#include "DeviceOpener.h"
8#include "Inode.h"
9
10
11#define TRACE_UFS2
12#ifdef TRACE_UFS2
13#define TRACE(x...) dprintf("\33[34mufs2:\33[0m " x);
14#else
15#define TRACE(x...) ;
16#endif
17#define ERROR(x...) dprintf("\33[34mufs2:\33[0m " x)
18
19
20bool
21ufs2_super_block::IsValid()
22{
23	if (fs_magic != FS_UFS2_MAGIC)
24		return false;
25
26	return true;
27}
28
29
30const char*
31Volume::Name() const
32{
33	// The name may be empty, in that case, userspace will generate one.
34	return fSuperBlock.fs_volname;
35}
36
37
38bool
39Volume::IsValidSuperBlock()
40{
41	return fSuperBlock.IsValid();
42}
43
44
45Volume::Volume(fs_volume *volume)
46	: fFSVolume(volume),
47	fRootNode(NULL)
48{
49	fFlags = 0;
50	mutex_init(&fLock, "ufs2 volume");
51	TRACE("Volume::Volume() : Initialising volume\n");
52}
53
54
55Volume::~Volume()
56{
57	mutex_destroy(&fLock);
58	TRACE("Volume::Destructor : Removing Volume\n");
59}
60
61
62status_t
63Volume::Identify(int fd, ufs2_super_block *superBlock)
64{
65	if (read_pos(fd, SBLOCK_UFS2, superBlock,
66		sizeof(ufs2_super_block)) != sizeof(ufs2_super_block))
67		return B_IO_ERROR;
68
69
70	if (!superBlock->IsValid()) {
71		ERROR("Invalid superblock! Identify failed!!\n");
72		return B_BAD_VALUE;
73	}
74
75	return B_OK;
76}
77
78
79status_t
80Volume::Mount(const char *deviceName, uint32 flags)
81{
82	TRACE("Mounting volume... Please wait.\n");
83	flags |= B_MOUNT_READ_ONLY;
84	if ((flags & B_MOUNT_READ_ONLY) != 0)
85	{
86		TRACE("Volume is read only\n");
87	}
88	else
89	{
90		TRACE("Volume is read write\n");
91	}
92
93	DeviceOpener opener(deviceName, (flags & B_MOUNT_READ_ONLY) != 0
94									? O_RDONLY:O_RDWR);
95	fDevice = opener.Device();
96	if (fDevice < B_OK) {
97		ERROR("Could not open device\n");
98		return fDevice;
99	}
100
101	if (opener.IsReadOnly())
102		fFlags |= VOLUME_READ_ONLY;
103
104	status_t status = Identify(fDevice, &fSuperBlock);
105	if (status != B_OK) {
106		ERROR("Invalid super block\n");
107		return status;
108	}
109
110	TRACE("Valid super block\n");
111
112	fRootNode = new(std::nothrow) Inode(this, UFS2_ROOT);
113	status = publish_vnode(this->FSVolume(), UFS2_ROOT, (void*)fRootNode,
114			&gufs2VnodeOps, fRootNode->Mode(), 0);
115
116	opener.Keep();
117	return B_OK;
118
119}
120
121
122status_t
123Volume::Unmount()
124{
125	TRACE("Unmounting the volume");
126
127	TRACE("Closing device");
128	close(fDevice);
129
130	return B_OK;
131}
132