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 #include "Volume.h" 7 8 9 class DeviceOpener 10 { 11 public: 12 DeviceOpener(int fd, int mode); 13 DeviceOpener(const char *device, int mode); 14 ~DeviceOpener(); 15 16 int Open(const char *device, int mode); 17 int Open(int fd, int mode); 18 void* InitCache(off_t numBlocks, uint32 blockSize); 19 void RemoveCache(bool allowWrites); 20 21 void Keep(); 22 23 int Device() const { return fDevice; } 24 int Mode() const { return fMode; } 25 bool IsReadOnly() const 26 { return _IsReadOnly(fMode); } 27 28 status_t GetSize(off_t* _size, uint32* _blockSize = NULL); 29 30 private: 31 static bool _IsReadOnly(int mode) 32 { return (mode & O_RWMASK) == O_RDONLY; } 33 static bool _IsReadWrite(int mode) 34 { return (mode & O_RWMASK) == O_RDWR; } 35 36 int fDevice; 37 int fMode; 38 void* fBlockCache; 39 }; 40 41 42 DeviceOpener::DeviceOpener(const char *device, int mode) 43 : fBlockCache(NULL) 44 { 45 Open(device, mode); 46 } 47 48 49 DeviceOpener::DeviceOpener(int fd, int mode) 50 : fBlockCache(NULL) 51 { 52 Open(fd, mode); 53 } 54 55 56 DeviceOpener::~DeviceOpener() 57 { 58 if (fDevice >= 0) { 59 RemoveCache(false); 60 close(fDevice); 61 } 62 } 63 64 65 int 66 DeviceOpener::Open(const char *device, int mode) 67 { 68 fDevice = open(device, mode | O_NOCACHE); 69 if (fDevice < 0) 70 fDevice = errno; 71 72 if (fDevice < 0 && _IsReadWrite(mode)){ 73 // try again to open read-only (don't rely on a specific error code) 74 return Open(device, O_RDONLY | O_NOCACHE); 75 } 76 77 if (fDevice >= 0) { 78 // opening succeeded 79 fMode = mode; 80 if (_IsReadWrite(mode)) { 81 // check out if the device really allows for read/write access 82 device_geometry geometry; 83 if (!ioctl(fDevice, B_GET_GEOMETRY, &geometry)) { 84 85 if (geometry.read_only) { 86 // reopen device read-only 87 close(fDevice); 88 return Open(device, O_RDONLY | O_NOCACHE); 89 } 90 } 91 } 92 } 93 94 return fDevice; 95 } 96 97 98 int 99 DeviceOpener::Open(int fd, int mode) 100 { 101 fDevice = dup(fd); 102 if (fDevice < 0) 103 return errno; 104 105 fMode = mode; 106 107 return fDevice; 108 } 109 110 111 void* 112 DeviceOpener::InitCache(off_t numBlocks, uint32 blockSize) 113 { 114 return fBlockCache = block_cache_create(fDevice, numBlocks, blockSize, 115 IsReadOnly()); 116 } 117 118 119 void 120 DeviceOpener::RemoveCache(bool allowWrites) 121 { 122 if (fBlockCache == NULL) 123 return; 124 125 block_cache_delete(fBlockCache, allowWrites); 126 fBlockCache = NULL; 127 } 128 129 130 void 131 DeviceOpener::Keep() 132 { 133 fDevice = -1; 134 } 135 136 137 /*! Returns the size of the device in bytes. It uses B_GET_GEOMETRY 138 to compute the size, or fstat() if that failed. 139 */ 140 status_t 141 DeviceOpener::GetSize(off_t *_size, uint32 *_blockSize) 142 { 143 device_geometry geometry; 144 if (ioctl(fDevice, B_GET_GEOMETRY, &geometry) < 0) { 145 // maybe it's just a file 146 struct stat stat; 147 if (fstat(fDevice, &stat) < 0) 148 return B_ERROR; 149 150 if (_size) 151 *_size = stat.st_size; 152 if (_blockSize) // that shouldn't cause us any problems 153 *_blockSize = 512; 154 155 return B_OK; 156 } 157 158 if (_size) { 159 *_size = 1LL * geometry.head_count * geometry.cylinder_count 160 * geometry.sectors_per_track * geometry.bytes_per_sector; 161 } 162 if (_blockSize) 163 *_blockSize = geometry.bytes_per_sector; 164 165 return B_OK; 166 } 167 168 169 Volume::Volume(fs_volume *volume) 170 : fFSVolume(volume) 171 { 172 fFlags = 0; 173 mutex_init(&fLock, "xfs volume"); 174 TRACE("Volume::Volume() : Initialising volume"); 175 } 176 177 178 Volume::~Volume() 179 { 180 mutex_destroy(&fLock); 181 TRACE("Volume::Destructor : Removing Volume"); 182 } 183 184 185 bool 186 Volume::IsValidSuperBlock() 187 { 188 return fSuperBlock.IsValid(); 189 } 190 191 192 status_t 193 Volume::Identify(int fd, XfsSuperBlock *superBlock) 194 { 195 196 TRACE("Volume::Identify() : Identifying Volume in progress"); 197 198 if (read_pos(fd, 0, superBlock, sizeof(XfsSuperBlock)) 199 != sizeof(XfsSuperBlock)) 200 return B_IO_ERROR; 201 202 superBlock->SwapEndian(); 203 204 if (!superBlock->IsValid()) { 205 ERROR("Volume::Identify(): Invalid Superblock!\n"); 206 return B_BAD_VALUE; 207 } 208 return B_OK; 209 } 210 211 212 status_t 213 Volume::Mount(const char *deviceName, uint32 flags) 214 { 215 TRACE("Volume::Mount() : Mounting in progress"); 216 217 flags |= B_MOUNT_READ_ONLY; 218 219 if ((flags & B_MOUNT_READ_ONLY) != 0) { 220 TRACE("Volume::Mount(): Read only\n"); 221 } else { 222 TRACE("Volume::Mount(): Read write\n"); 223 } 224 225 DeviceOpener opener(deviceName, (flags & B_MOUNT_READ_ONLY) != 0 226 ? O_RDONLY 227 : O_RDWR); 228 fDevice = opener.Device(); 229 if (fDevice < B_OK) { 230 ERROR("Volume::Mount(): couldn't open device\n"); 231 return fDevice; 232 } 233 234 if (opener.IsReadOnly()) 235 fFlags |= VOLUME_READ_ONLY; 236 237 // read the superblock 238 status_t status = Identify(fDevice, &fSuperBlock); 239 if (status != B_OK) { 240 ERROR("Volume::Mount(): Invalid super block!\n"); 241 return B_BAD_VALUE; 242 } 243 244 TRACE("Volume::Mount(): Valid SuperBlock.\n"); 245 246 // check if the device size is large enough to hold the file system 247 off_t diskSize; 248 if (opener.GetSize(&diskSize) != B_OK) { 249 ERROR("Volume:Mount() Unable to get diskSize"); 250 return B_ERROR; 251 } 252 253 opener.Keep(); 254 return B_OK; 255 } 256 257 258 status_t 259 Volume::Unmount() 260 { 261 TRACE("Volume::Unmount(): Unmounting"); 262 263 TRACE("Volume::Unmount(): Closing device"); 264 close(fDevice); 265 266 return B_OK; 267 } 268