1 // KDiskDevice.cpp 2 3 #include <errno.h> 4 #include <fcntl.h> 5 #include <stdio.h> 6 #include <unistd.h> 7 8 #include <KernelExport.h> 9 #include <Drivers.h> 10 11 #include "ddm_userland_interface.h" 12 #include "KDiskDevice.h" 13 #include "KDiskDeviceUtils.h" 14 #include "KShadowPartition.h" 15 #include "KPath.h" 16 #include "UserDataWriter.h" 17 18 // debugging 19 //#define DBG(x) 20 #define DBG(x) x 21 #define OUT dprintf 22 23 // constructor 24 KDiskDevice::KDiskDevice(partition_id id) 25 : KPhysicalPartition(id), 26 fDeviceData(), 27 fLocker("diskdevice"), 28 fFD(-1), 29 fMediaStatus(B_ERROR), 30 fShadowOwner(-1) 31 { 32 Unset(); 33 fDevice = this; 34 fPublished = true; 35 } 36 37 // destructor 38 KDiskDevice::~KDiskDevice() 39 { 40 Unset(); 41 } 42 43 // SetTo 44 status_t 45 KDiskDevice::SetTo(const char *path) 46 { 47 // check initialization and parameter 48 status_t error = InitCheck(); 49 if (error != B_OK) 50 return error; 51 if (!path) 52 return B_BAD_VALUE; 53 Unset(); 54 // set the path 55 error = set_string(fDeviceData.path, path); 56 if (error != B_OK) 57 return error; 58 // open the device 59 fFD = open(path, O_RDONLY); 60 if (fFD < 0) 61 return errno; 62 // get media status 63 error = GetMediaStatus(&fMediaStatus); 64 if (error != B_OK) 65 return error; 66 if (fMediaStatus == B_DEV_MEDIA_CHANGED) 67 fMediaStatus = B_OK; 68 // get device geometry 69 if (fMediaStatus == B_OK) { 70 error = GetGeometry(&fDeviceData.geometry); 71 if (error != B_OK) 72 return error; 73 } else { 74 // no media: try to get the device geometry, but don't fail, if 75 // we can't get it 76 GetGeometry(&fDeviceData.geometry); 77 } 78 // set device flags 79 if (fDeviceData.geometry.removable) 80 SetDeviceFlags(DeviceFlags() | B_DISK_DEVICE_REMOVABLE); 81 if (fMediaStatus == B_OK) 82 SetDeviceFlags(DeviceFlags() | B_DISK_DEVICE_HAS_MEDIA); 83 if (fDeviceData.geometry.read_only) 84 SetDeviceFlags(DeviceFlags() | B_DISK_DEVICE_READ_ONLY); 85 if (fDeviceData.geometry.write_once) 86 SetDeviceFlags(DeviceFlags() | B_DISK_DEVICE_WRITE_ONCE); 87 // update partition data 88 _InitPartitionData(); 89 return B_OK; 90 } 91 92 // Unset 93 void 94 KDiskDevice::Unset() 95 { 96 if (fFD >= 0) { 97 close(fFD); 98 fFD = -1; 99 } 100 fMediaStatus = B_ERROR; 101 fShadowOwner = -1; 102 fDeviceData.id = -1; 103 fDeviceData.flags = 0; 104 if (fDeviceData.path) { 105 free(fDeviceData.path); 106 fDeviceData.path = NULL; 107 } 108 fDeviceData.geometry.bytes_per_sector = 0; 109 fDeviceData.geometry.sectors_per_track = 0; 110 fDeviceData.geometry.cylinder_count = 0; 111 fDeviceData.geometry.head_count = 0; 112 fDeviceData.geometry.device_type = B_DISK; 113 fDeviceData.geometry.removable = true; 114 fDeviceData.geometry.read_only = true; 115 fDeviceData.geometry.write_once = false; 116 } 117 118 // InitCheck 119 status_t 120 KDiskDevice::InitCheck() const 121 { 122 return fLocker.InitCheck(); 123 } 124 125 // ReadLock 126 bool 127 KDiskDevice::ReadLock() 128 { 129 return fLocker.ReadLock(); 130 } 131 132 // ReadUnlock 133 void 134 KDiskDevice::ReadUnlock() 135 { 136 fLocker.ReadUnlock(); 137 } 138 139 // IsReadLocked 140 bool 141 KDiskDevice::IsReadLocked(bool orWriteLocked) 142 { 143 return fLocker.IsReadLocked(orWriteLocked); 144 } 145 146 // WriteLock 147 bool 148 KDiskDevice::WriteLock() 149 { 150 return fLocker.WriteLock(); 151 } 152 153 // WriteUnlock 154 void 155 KDiskDevice::WriteUnlock() 156 { 157 fLocker.WriteUnlock(); 158 } 159 160 // IsWriteLocked 161 bool 162 KDiskDevice::IsWriteLocked() 163 { 164 return fLocker.IsWriteLocked(); 165 } 166 167 // PrepareForRemoval 168 bool 169 KDiskDevice::PrepareForRemoval() 170 { 171 if (ShadowOwner() >= 0) 172 DeleteShadowDevice(); 173 return KPhysicalPartition::PrepareForRemoval(); 174 } 175 176 // SetID 177 void 178 KDiskDevice::SetID(partition_id id) 179 { 180 KPhysicalPartition::SetID(id); 181 fDeviceData.id = id; 182 } 183 184 // PublishDevice 185 status_t 186 KDiskDevice::PublishDevice() 187 { 188 // PublishDevice() and UnpublishDevice() are no-ops for KDiskDevices, 189 // since they are always published. 190 return B_OK; 191 } 192 193 // UnpublishDevice 194 status_t 195 KDiskDevice::UnpublishDevice() 196 { 197 // PublishDevice() and UnpublishDevice() are no-ops for KDiskDevices, 198 // since they are always published. 199 return B_OK; 200 } 201 202 203 // SetDeviceFlags 204 void 205 KDiskDevice::SetDeviceFlags(uint32 flags) 206 { 207 fDeviceData.flags = flags; 208 } 209 210 // DeviceFlags 211 uint32 212 KDiskDevice::DeviceFlags() const 213 { 214 return fDeviceData.flags; 215 } 216 217 // IsReadOnlyMedia 218 bool 219 KDiskDevice::IsReadOnlyMedia() const 220 { 221 return fDeviceData.geometry.read_only; 222 } 223 224 // IsWriteOnce 225 bool 226 KDiskDevice::IsWriteOnce() const 227 { 228 return fDeviceData.geometry.write_once; 229 } 230 231 // IsRemovable 232 bool 233 KDiskDevice::IsRemovable() const 234 { 235 return fDeviceData.geometry.removable; 236 } 237 238 // HasMedia 239 bool 240 KDiskDevice::HasMedia() const 241 { 242 return (fMediaStatus == B_OK); 243 } 244 245 // SetPath 246 status_t 247 KDiskDevice::SetPath(const char *path) 248 { 249 return set_string(fDeviceData.path, path); 250 } 251 252 // Path 253 const char * 254 KDiskDevice::Path() const 255 { 256 return fDeviceData.path; 257 } 258 259 // GetPath 260 status_t 261 KDiskDevice::GetPath(KPath *path) const 262 { 263 if (!path || path->InitCheck() != B_OK) 264 return B_BAD_VALUE; 265 if (!fDeviceData.path) 266 return B_NO_INIT; 267 return path->SetPath(fDeviceData.path); 268 } 269 270 // SetFD 271 void 272 KDiskDevice::SetFD(int fd) 273 { 274 fFD = fd; 275 } 276 277 // FD 278 int 279 KDiskDevice::FD() const 280 { 281 return fFD; 282 } 283 284 // DeviceData 285 disk_device_data * 286 KDiskDevice::DeviceData() 287 { 288 return &fDeviceData; 289 } 290 291 // DeviceData 292 const disk_device_data * 293 KDiskDevice::DeviceData() const 294 { 295 return &fDeviceData; 296 } 297 298 // CreateShadowDevice 299 status_t 300 KDiskDevice::CreateShadowDevice(team_id team) 301 { 302 if (fShadowOwner >= 0 || team < 0 || !HasMedia()) 303 return B_BAD_VALUE; 304 // create the shadow partitions 305 status_t error = CreateShadowPartition(); 306 if (error == B_OK) 307 SetShadowOwner(team); 308 return error; 309 } 310 311 // DeleteShadowDevice 312 status_t 313 KDiskDevice::DeleteShadowDevice() 314 { 315 if (fShadowOwner < 0) 316 return B_BAD_VALUE; 317 UnsetShadowPartition(true); 318 SetShadowOwner(-1); 319 return B_OK; 320 } 321 322 // SetShadowOwner 323 void 324 KDiskDevice::SetShadowOwner(team_id team) 325 { 326 fShadowOwner = team; 327 } 328 329 // ShadowOwner 330 team_id 331 KDiskDevice::ShadowOwner() const 332 { 333 return fShadowOwner; 334 } 335 336 // WriteUserData 337 void 338 KDiskDevice::WriteUserData(UserDataWriter &writer, user_partition_data *data) 339 { 340 return KPhysicalPartition::WriteUserData(writer, data); 341 } 342 343 // WriteUserData 344 void 345 KDiskDevice::WriteUserData(UserDataWriter &writer, bool shadow) 346 { 347 KPartition *partition = shadow ? ShadowPartition() : static_cast<KPartition *>(this); 348 if (!partition) 349 partition = this; 350 user_disk_device_data *data 351 = writer.AllocateDeviceData(partition->CountChildren()); 352 char *path = writer.PlaceString(Path()); 353 if (data) { 354 data->device_flags = DeviceFlags(); 355 data->path = path; 356 writer.AddRelocationEntry(&data->path); 357 partition->WriteUserData(writer, &data->device_partition_data); 358 } else 359 partition->WriteUserData(writer, NULL); 360 } 361 362 // Dump 363 void 364 KDiskDevice::Dump(bool deep, int32 level) 365 { 366 OUT("device %ld: %s\n", ID(), Path()); 367 OUT(" media status: %s\n", strerror(fMediaStatus)); 368 OUT(" device flags: %lx\n", DeviceFlags()); 369 if (fMediaStatus == B_OK) 370 KPhysicalPartition::Dump(deep, 0); 371 } 372 373 // GetMediaStatus 374 status_t 375 KDiskDevice::GetMediaStatus(status_t *mediaStatus) 376 { 377 status_t error = B_OK; 378 if (ioctl(fFD, B_GET_MEDIA_STATUS, mediaStatus) != 0) 379 error = errno; 380 // maybe the device driver doesn't implement this ioctl -- see, if getting 381 // the device geometry succeeds 382 if (error != B_OK) { 383 device_geometry geometry; 384 if (GetGeometry(&geometry) == B_OK) { 385 // if the device is not removable, we can ignore the failed ioctl 386 // and return a media status of B_OK 387 if (!geometry.removable) { 388 error = B_OK; 389 *mediaStatus = B_OK; 390 } 391 } 392 } 393 return error; 394 } 395 396 // GetGeometry 397 status_t 398 KDiskDevice::GetGeometry(device_geometry *geometry) 399 { 400 if (ioctl(fFD, B_GET_GEOMETRY, geometry) != 0) 401 return errno; 402 return B_OK; 403 } 404 405 // _InitPartitionData 406 void 407 KDiskDevice::_InitPartitionData() 408 { 409 fDeviceData.id = fPartitionData.id; 410 fPartitionData.block_size = fDeviceData.geometry.bytes_per_sector; 411 fPartitionData.offset = 0; 412 fPartitionData.size = (off_t)fPartitionData.block_size 413 * fDeviceData.geometry.sectors_per_track 414 * fDeviceData.geometry.cylinder_count 415 * fDeviceData.geometry.head_count; 416 fPartitionData.flags |= B_PARTITION_IS_DEVICE; 417 } 418 419