xref: /haiku/src/add-ons/kernel/file_systems/xfs/Volume.cpp (revision 4a55cc230cf7566cadcbb23b1928eefff8aea9a2)
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 
14 Volume::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 
23 Volume::~Volume()
24 {
25 	mutex_destroy(&fLock);
26 	TRACE("Volume::Destructor : Removing Volume");
27 }
28 
29 
30 bool
31 Volume::IsValidSuperBlock() const
32 {
33 	return fSuperBlock.IsValid();
34 }
35 
36 
37 status_t
38 Volume::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, offsetof(XfsSuperBlock, sb_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 
76 status_t
77 Volume::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 
141 status_t
142 Volume::Unmount()
143 {
144 	TRACE("Volume::Unmount(): Unmounting");
145 
146 	TRACE("Volume::Unmount(): Closing device");
147 	close(fDevice);
148 
149 	return B_OK;
150 }
151