1 /*
2 * Copyright 2003-2009, Haiku, Inc. All Rights Reserved.
3 * Distributed under the terms of the MIT License.
4 *
5 * Authors:
6 * Ingo Weinhold, bonefish@cs.tu-berlin.de
7 * Axel Dörfler, axeld@pinc-software.de
8 */
9
10 #include <DiskDeviceRoster.h>
11
12 #include <new>
13
14 #include <Directory.h>
15 #include <DiskDevice.h>
16 #include <DiskDevicePrivate.h>
17 #include <DiskSystem.h>
18 #include <Entry.h>
19 #include <FindDirectory.h>
20 #include <Message.h>
21 #include <Partition.h>
22 #include <Path.h>
23 #include <Volume.h>
24
25 #include <MessengerPrivate.h>
26
27 #include <syscalls.h>
28 #include <ddm_userland_interface_defs.h>
29
30
31 /*! \class BDiskDeviceRoster
32 \brief An interface for iterating through the disk devices known to the
33 system and for a notification mechanism provided to listen to their
34 changes.
35 */
36
37 /*! \brief find_directory constants of the add-on dirs to be searched. */
38 static const directory_which kAddOnDirs[] = {
39 B_USER_NONPACKAGED_ADDONS_DIRECTORY,
40 B_USER_ADDONS_DIRECTORY,
41 B_SYSTEM_NONPACKAGED_ADDONS_DIRECTORY,
42 B_SYSTEM_ADDONS_DIRECTORY,
43 };
44 /*! \brief Size of the kAddOnDirs array. */
45 static const int32 kAddOnDirCount
46 = sizeof(kAddOnDirs) / sizeof(directory_which);
47
48
49 /*! \brief Creates a BDiskDeviceRoster object.
50
51 The object is ready to be used after construction.
52 */
BDiskDeviceRoster()53 BDiskDeviceRoster::BDiskDeviceRoster()
54 : fDeviceCookie(0),
55 fDiskSystemCookie(0),
56 fJobCookie(0)
57 // fPartitionAddOnDir(NULL),
58 // fFSAddOnDir(NULL),
59 // fPartitionAddOnDirIndex(0),
60 // fFSAddOnDirIndex(0)
61 {
62 }
63
64
65 /*! \brief Frees all resources associated with the object.
66 */
~BDiskDeviceRoster()67 BDiskDeviceRoster::~BDiskDeviceRoster()
68 {
69 // if (fPartitionAddOnDir)
70 // delete fPartitionAddOnDir;
71 // if (fFSAddOnDir)
72 // delete fFSAddOnDir;
73 }
74
75
76 /*! \brief Returns the next BDiskDevice.
77 \param device Pointer to a pre-allocated BDiskDevice to be initialized to
78 represent the next device.
79 \return
80 - \c B_OK: Everything went fine.
81 - \c B_ENTRY_NOT_FOUND: The end of the list of devices had already been
82 reached.
83 - another error code
84 */
85 status_t
GetNextDevice(BDiskDevice * device)86 BDiskDeviceRoster::GetNextDevice(BDiskDevice* device)
87 {
88 if (!device)
89 return B_BAD_VALUE;
90
91 size_t neededSize = 0;
92 partition_id id = _kern_get_next_disk_device_id(&fDeviceCookie,
93 &neededSize);
94 if (id < 0)
95 return id;
96
97 return device->_SetTo(id, true, neededSize);
98 }
99
100
101 /*! \brief Rewinds the device list iterator.
102 \return \c B_OK, if everything went fine, another error code otherwise.
103 */
104 status_t
RewindDevices()105 BDiskDeviceRoster::RewindDevices()
106 {
107 fDeviceCookie = 0;
108 return B_OK;
109 }
110
111
112 status_t
GetNextDiskSystem(BDiskSystem * system)113 BDiskDeviceRoster::GetNextDiskSystem(BDiskSystem* system)
114 {
115 if (!system)
116 return B_BAD_VALUE;
117 user_disk_system_info info;
118 status_t error = _kern_get_next_disk_system_info(&fDiskSystemCookie,
119 &info);
120 if (error == B_OK)
121 error = system->_SetTo(&info);
122 return error;
123 }
124
125
126 status_t
RewindDiskSystems()127 BDiskDeviceRoster::RewindDiskSystems()
128 {
129 fDiskSystemCookie = 0;
130 return B_OK;
131 }
132
133
134 status_t
GetDiskSystem(BDiskSystem * system,const char * name)135 BDiskDeviceRoster::GetDiskSystem(BDiskSystem* system, const char* name)
136 {
137 if (!system)
138 return B_BAD_VALUE;
139
140 int32 cookie = 0;
141 user_disk_system_info info;
142 while (_kern_get_next_disk_system_info(&cookie, &info) == B_OK) {
143 if (!strcmp(name, info.name)
144 || !strcmp(name, info.short_name)
145 || !strcmp(name, info.pretty_name))
146 return system->_SetTo(&info);
147 }
148
149 return B_ENTRY_NOT_FOUND;
150 }
151
152
153 partition_id
RegisterFileDevice(const char * filename)154 BDiskDeviceRoster::RegisterFileDevice(const char* filename)
155 {
156 if (!filename)
157 return B_BAD_VALUE;
158 return _kern_register_file_device(filename);
159 }
160
161
162 status_t
UnregisterFileDevice(const char * filename)163 BDiskDeviceRoster::UnregisterFileDevice(const char* filename)
164 {
165 if (!filename)
166 return B_BAD_VALUE;
167 return _kern_unregister_file_device(-1, filename);
168 }
169
170
171 status_t
UnregisterFileDevice(partition_id device)172 BDiskDeviceRoster::UnregisterFileDevice(partition_id device)
173 {
174 if (device < 0)
175 return B_BAD_VALUE;
176 return _kern_unregister_file_device(device, NULL);
177 }
178
179
180 /*! \brief Iterates through the all devices.
181
182 The supplied visitor's Visit(BDiskDevice*) is invoked for each device.
183 If Visit() returns \c true, the iteration is terminated and this method
184 returns \c true. If supplied, \a device is set to the concerned device.
185
186 \param visitor The visitor.
187 \param device Pointer to a pre-allocated BDiskDevice to be initialized
188 to the device at which the iteration was terminated.
189 May be \c NULL.
190 \return \c true, if the iteration was terminated, \c false otherwise.
191 */
192 bool
VisitEachDevice(BDiskDeviceVisitor * visitor,BDiskDevice * device)193 BDiskDeviceRoster::VisitEachDevice(BDiskDeviceVisitor* visitor,
194 BDiskDevice* device)
195 {
196 bool terminatedEarly = false;
197 if (visitor) {
198 int32 oldCookie = fDeviceCookie;
199 fDeviceCookie = 0;
200 BDiskDevice deviceOnStack;
201 BDiskDevice* useDevice = device ? device : &deviceOnStack;
202 while (!terminatedEarly && GetNextDevice(useDevice) == B_OK)
203 terminatedEarly = visitor->Visit(useDevice);
204 fDeviceCookie = oldCookie;
205 if (!terminatedEarly)
206 useDevice->Unset();
207 }
208 return terminatedEarly;
209 }
210
211
212 /*! \brief Pre-order traverses the trees spanned by the BDiskDevices and their
213 subobjects.
214
215 The supplied visitor's Visit(BDiskDevice*) method is invoked for each
216 disk device and Visit(BPartition*) for each (non-disk device) partition.
217 If Visit() returns \c true, the iteration is terminated and this method
218 returns \c true. If supplied, \a device is set to the concerned device
219 and in \a partition the pointer to the partition object is returned.
220
221 \param visitor The visitor.
222 \param device Pointer to a pre-allocated BDiskDevice to be initialized
223 to the device at which the iteration was terminated.
224 May be \c NULL.
225 \param partition Pointer to a pre-allocated BPartition pointer to be set
226 to the partition at which the iteration was terminated.
227 May be \c NULL.
228 \return \c true, if the iteration was terminated, \c false otherwise.
229 */
230 bool
VisitEachPartition(BDiskDeviceVisitor * visitor,BDiskDevice * device,BPartition ** partition)231 BDiskDeviceRoster::VisitEachPartition(BDiskDeviceVisitor* visitor,
232 BDiskDevice* device, BPartition** partition)
233 {
234 bool terminatedEarly = false;
235 if (visitor) {
236 int32 oldCookie = fDeviceCookie;
237 fDeviceCookie = 0;
238 BDiskDevice deviceOnStack;
239 BDiskDevice* useDevice = device ? device : &deviceOnStack;
240 BPartition* foundPartition = NULL;
241 while (GetNextDevice(useDevice) == B_OK) {
242 foundPartition = useDevice->VisitEachDescendant(visitor);
243 if (foundPartition) {
244 terminatedEarly = true;
245 break;
246 }
247 }
248 fDeviceCookie = oldCookie;
249 if (!terminatedEarly)
250 useDevice->Unset();
251 else if (device && partition)
252 *partition = foundPartition;
253 }
254 return terminatedEarly;
255 }
256
257
258 /*! \brief Iterates through the all devices' partitions that are mounted.
259
260 The supplied visitor's Visit(BPartition*) is invoked for each mounted
261 partition.
262 If Visit() returns \c true, the iteration is terminated and this method
263 returns \c true. If supplied, \a device is set to the concerned device
264 and in \a partition the pointer to the partition object is returned.
265
266 \param visitor The visitor.
267 \param device Pointer to a pre-allocated BDiskDevice to be initialized
268 to the device at which the iteration was terminated.
269 May be \c NULL.
270 \param partition Pointer to a pre-allocated BPartition pointer to be set
271 to the partition at which the iteration was terminated.
272 May be \c NULL.
273 \return \c true, if the iteration was terminated, \c false otherwise.
274 */
275 bool
VisitEachMountedPartition(BDiskDeviceVisitor * visitor,BDiskDevice * device,BPartition ** partition)276 BDiskDeviceRoster::VisitEachMountedPartition(BDiskDeviceVisitor* visitor,
277 BDiskDevice* device, BPartition** partition)
278 {
279 bool terminatedEarly = false;
280 if (visitor) {
281 struct MountedPartitionFilter : public PartitionFilter {
282 virtual bool Filter(BPartition *partition, int32)
283 { return partition->IsMounted(); }
284 } filter;
285 PartitionFilterVisitor filterVisitor(visitor, &filter);
286 terminatedEarly
287 = VisitEachPartition(&filterVisitor, device, partition);
288 }
289 return terminatedEarly;
290 }
291
292
293 /*! \brief Iterates through the all devices' partitions that are mountable.
294
295 The supplied visitor's Visit(BPartition*) is invoked for each mountable
296 partition.
297 If Visit() returns \c true, the iteration is terminated and this method
298 returns \c true. If supplied, \a device is set to the concerned device
299 and in \a partition the pointer to the partition object is returned.
300
301 \param visitor The visitor.
302 \param device Pointer to a pre-allocated BDiskDevice to be initialized
303 to the device at which the iteration was terminated.
304 May be \c NULL.
305 \param partition Pointer to a pre-allocated BPartition pointer to be set
306 to the partition at which the iteration was terminated.
307 May be \c NULL.
308 \return \c true, if the iteration was terminated, \c false otherwise.
309 */
310 bool
VisitEachMountablePartition(BDiskDeviceVisitor * visitor,BDiskDevice * device,BPartition ** partition)311 BDiskDeviceRoster::VisitEachMountablePartition(BDiskDeviceVisitor* visitor,
312 BDiskDevice* device, BPartition** partition)
313 {
314 bool terminatedEarly = false;
315 if (visitor) {
316 struct MountablePartitionFilter : public PartitionFilter {
317 virtual bool Filter(BPartition *partition, int32)
318 { return partition->ContainsFileSystem(); }
319 } filter;
320 PartitionFilterVisitor filterVisitor(visitor, &filter);
321 terminatedEarly
322 = VisitEachPartition(&filterVisitor, device, partition);
323 }
324 return terminatedEarly;
325 }
326
327
328 /*! \brief Finds a BPartition by BVolume.
329 */
330 status_t
FindPartitionByVolume(const BVolume & volume,BDiskDevice * device,BPartition ** _partition)331 BDiskDeviceRoster::FindPartitionByVolume(const BVolume& volume,
332 BDiskDevice* device, BPartition** _partition)
333 {
334 class FindPartitionVisitor : public BDiskDeviceVisitor {
335 public:
336 FindPartitionVisitor(dev_t volume)
337 :
338 fVolume(volume)
339 {
340 }
341
342 virtual bool Visit(BDiskDevice* device)
343 {
344 return Visit(device, 0);
345 }
346
347 virtual bool Visit(BPartition* partition, int32 level)
348 {
349 BVolume volume;
350 return partition->GetVolume(&volume) == B_OK
351 && volume.Device() == fVolume;
352 }
353
354 private:
355 dev_t fVolume;
356 } visitor(volume.Device());
357
358 if (VisitEachMountedPartition(&visitor, device, _partition))
359 return B_OK;
360
361 return B_ENTRY_NOT_FOUND;
362 }
363
364
365 /*! \brief Finds a BPartition by mount path.
366 */
367 status_t
FindPartitionByMountPoint(const char * mountPoint,BDiskDevice * device,BPartition ** _partition)368 BDiskDeviceRoster::FindPartitionByMountPoint(const char* mountPoint,
369 BDiskDevice* device, BPartition** _partition)
370 {
371 BVolume volume(dev_for_path(mountPoint));
372 if (volume.InitCheck() == B_OK
373 && FindPartitionByVolume(volume, device, _partition))
374 return B_OK;
375
376 return B_ENTRY_NOT_FOUND;
377 }
378
379
380 /*! \brief Returns a BDiskDevice for a given ID.
381
382 The supplied \a device is initialized to the device identified by \a id.
383
384 \param id The ID of the device to be retrieved.
385 \param device Pointer to a pre-allocated BDiskDevice to be initialized
386 to the device identified by \a id.
387 \return
388 - \c B_OK: Everything went fine.
389 - \c B_ENTRY_NOT_FOUND: A device with ID \a id could not be found.
390 - other error codes
391 */
392 status_t
GetDeviceWithID(int32 id,BDiskDevice * device) const393 BDiskDeviceRoster::GetDeviceWithID(int32 id, BDiskDevice* device) const
394 {
395 if (!device)
396 return B_BAD_VALUE;
397 return device->_SetTo(id, true, 0);
398 }
399
400
401 /*! \brief Returns a BPartition for a given ID.
402
403 The supplied \a device is initialized to the device the partition
404 identified by \a id resides on, and \a partition is set to point to the
405 respective BPartition.
406
407 \param id The ID of the partition to be retrieved.
408 \param device Pointer to a pre-allocated BDiskDevice to be initialized
409 to the device the partition identified by \a id resides on.
410 \param partition Pointer to a pre-allocated BPartition pointer to be set
411 to the partition identified by \a id.
412 \return
413 - \c B_OK: Everything went fine.
414 - \c B_ENTRY_NOT_FOUND: A partition with ID \a id could not be found.
415 - other error codes
416 */
417 status_t
GetPartitionWithID(int32 id,BDiskDevice * device,BPartition ** partition) const418 BDiskDeviceRoster::GetPartitionWithID(int32 id, BDiskDevice* device,
419 BPartition** partition) const
420 {
421 if (!device || !partition)
422 return B_BAD_VALUE;
423
424 // retrieve the device data
425 status_t error = device->_SetTo(id, false, 0);
426 if (error != B_OK)
427 return error;
428
429 // find the partition object
430 *partition = device->FindDescendant(id);
431 if (!*partition) // should never happen!
432 return B_ENTRY_NOT_FOUND;
433
434 return B_OK;
435 }
436
437
438 status_t
GetDeviceForPath(const char * filename,BDiskDevice * device)439 BDiskDeviceRoster::GetDeviceForPath(const char* filename, BDiskDevice* device)
440 {
441 if (!filename || !device)
442 return B_BAD_VALUE;
443
444 // get the device ID
445 size_t neededSize = 0;
446 partition_id id = _kern_find_disk_device(filename, &neededSize);
447 if (id < 0)
448 return id;
449
450 // retrieve the device data
451 return device->_SetTo(id, true, neededSize);
452 }
453
454
455 status_t
GetPartitionForPath(const char * filename,BDiskDevice * device,BPartition ** partition)456 BDiskDeviceRoster::GetPartitionForPath(const char* filename,
457 BDiskDevice* device, BPartition** partition)
458 {
459 if (!filename || !device || !partition)
460 return B_BAD_VALUE;
461
462 // get the partition ID
463 size_t neededSize = 0;
464 partition_id id = _kern_find_partition(filename, &neededSize);
465 if (id < 0)
466 return id;
467
468 // retrieve the device data
469 status_t error = device->_SetTo(id, false, neededSize);
470 if (error != B_OK)
471 return error;
472
473 // find the partition object
474 *partition = device->FindDescendant(id);
475 if (!*partition) // should never happen!
476 return B_ENTRY_NOT_FOUND;
477 return B_OK;
478 }
479
480
481 status_t
GetFileDeviceForPath(const char * filename,BDiskDevice * device)482 BDiskDeviceRoster::GetFileDeviceForPath(const char* filename,
483 BDiskDevice* device)
484 {
485 if (!filename || !device)
486 return B_BAD_VALUE;
487
488 // get the device ID
489 size_t neededSize = 0;
490 partition_id id = _kern_find_file_disk_device(filename, &neededSize);
491 if (id < 0)
492 return id;
493
494 // retrieve the device data
495 return device->_SetTo(id, true, neededSize);
496 }
497
498
499 /*! \brief Adds a target to the list of targets to be notified on disk device
500 events.
501
502 \todo List the event mask flags, the events and describe the layout of the
503 notification message.
504
505 If \a target is already listening to events, this method replaces the
506 former event mask with \a eventMask.
507
508 \param target A BMessenger identifying the target to which the events
509 shall be sent.
510 \param eventMask A mask specifying on which events the target shall be
511 notified.
512 \return \c B_OK, if everything went fine, another error code otherwise.
513 */
514 status_t
StartWatching(BMessenger target,uint32 eventMask)515 BDiskDeviceRoster::StartWatching(BMessenger target, uint32 eventMask)
516 {
517 if (eventMask == 0)
518 return B_BAD_VALUE;
519
520 BMessenger::Private messengerPrivate(target);
521 port_id port = messengerPrivate.Port();
522 int32 token = messengerPrivate.Token();
523
524 return _kern_start_watching_disks(eventMask, port, token);
525 }
526
527
528 /*! \brief Remove a target from the list of targets to be notified on disk
529 device events.
530 \param target A BMessenger identifying the target to which notfication
531 message shall not longer be sent.
532 \return \c B_OK, if everything went fine, another error code otherwise.
533 */
534 status_t
StopWatching(BMessenger target)535 BDiskDeviceRoster::StopWatching(BMessenger target)
536 {
537 BMessenger::Private messengerPrivate(target);
538 port_id port = messengerPrivate.Port();
539 int32 token = messengerPrivate.Token();
540
541 return _kern_stop_watching_disks(port, token);
542 }
543
544 #if 0
545
546 /*! \brief Returns the next partitioning system capable of partitioning.
547
548 The returned \a shortName can be passed to BSession::Partition().
549
550 \param shortName Pointer to a pre-allocation char buffer, of size
551 \c B_FILE_NAME_LENGTH or larger into which the short name of the
552 partitioning system shall be written.
553 \param longName Pointer to a pre-allocation char buffer, of size
554 \c B_FILE_NAME_LENGTH or larger into which the long name of the
555 partitioning system shall be written. May be \c NULL.
556 \return
557 - \c B_OK: Everything went fine.
558 - \c B_BAD_VALUE: \c NULL \a shortName.
559 - \c B_ENTRY_NOT_FOUND: End of the list has been reached.
560 - other error codes
561 */
562 status_t
563 BDiskDeviceRoster::GetNextPartitioningSystem(char *shortName, char *longName)
564 {
565 status_t error = (shortName ? B_OK : B_BAD_VALUE);
566 if (error == B_OK) {
567 // search until an add-on has been found or the end of all directories
568 // has been reached
569 bool found = false;
570 do {
571 // get the next add-on in the current dir
572 AddOnImage image;
573 error = _GetNextAddOn(fPartitionAddOnDir, &image);
574 if (error == B_OK) {
575 // add-on loaded: get the function that creates an add-on
576 // object
577 BDiskScannerPartitionAddOn *(*create_add_on)();
578 if (get_image_symbol(image.ID(), "create_ds_partition_add_on",
579 B_SYMBOL_TYPE_TEXT,
580 (void**)&create_add_on) == B_OK) {
581 // create the add-on object and copy the requested data
582 if (BDiskScannerPartitionAddOn *addOn
583 = (*create_add_on)()) {
584 const char *addOnShortName = addOn->ShortName();
585 const char *addOnLongName = addOn->LongName();
586 if (addOnShortName && addOnLongName) {
587 strcpy(shortName, addOnShortName);
588 if (longName)
589 strcpy(longName, addOnLongName);
590 found = true;
591 }
592 delete addOn;
593 }
594 }
595 } else if (error == B_ENTRY_NOT_FOUND) {
596 // end of the current directory has been reached, try next dir
597 error = _GetNextAddOnDir(&fPartitionAddOnDir,
598 &fPartitionAddOnDirIndex,
599 "partition");
600 }
601 } while (error == B_OK && !found);
602 }
603 return error;
604 }
605
606
607 /*! \brief Returns the next file system capable of initializing.
608
609 The returned \a shortName can be passed to BPartition::Initialize().
610
611 \param shortName Pointer to a pre-allocation char buffer, of size
612 \c B_FILE_NAME_LENGTH or larger into which the short name of the
613 file system shall be written.
614 \param longName Pointer to a pre-allocation char buffer, of size
615 \c B_FILE_NAME_LENGTH or larger into which the long name of the
616 file system shall be written. May be \c NULL.
617 \return
618 - \c B_OK: Everything went fine.
619 - \c B_BAD_VALUE: \c NULL \a shortName.
620 - \c B_ENTRY_NOT_FOUND: End of the list has been reached.
621 - other error codes
622 */
623 status_t
624 BDiskDeviceRoster::GetNextFileSystem(char *shortName, char *longName)
625 {
626 status_t error = (shortName ? B_OK : B_BAD_VALUE);
627 if (error == B_OK) {
628 // search until an add-on has been found or the end of all directories
629 // has been reached
630 bool found = false;
631 do {
632 // get the next add-on in the current dir
633 AddOnImage image;
634 error = _GetNextAddOn(fFSAddOnDir, &image);
635 if (error == B_OK) {
636 // add-on loaded: get the function that creates an add-on
637 // object
638 BDiskScannerFSAddOn *(*create_add_on)();
639 if (get_image_symbol(image.ID(), "create_ds_fs_add_on",
640 B_SYMBOL_TYPE_TEXT,
641 (void**)&create_add_on) == B_OK) {
642 // create the add-on object and copy the requested data
643 if (BDiskScannerFSAddOn *addOn = (*create_add_on)()) {
644 const char *addOnShortName = addOn->ShortName();
645 const char *addOnLongName = addOn->LongName();
646 if (addOnShortName && addOnLongName) {
647 strcpy(shortName, addOnShortName);
648 if (longName)
649 strcpy(longName, addOnLongName);
650 found = true;
651 }
652 delete addOn;
653 }
654 }
655 } else if (error == B_ENTRY_NOT_FOUND) {
656 // end of the current directory has been reached, try next dir
657 error = _GetNextAddOnDir(&fFSAddOnDir, &fFSAddOnDirIndex,
658 "fs");
659 }
660 } while (error == B_OK && !found);
661 }
662 return error;
663 }
664
665
666 /*! \brief Rewinds the partitioning system list iterator.
667 \return \c B_OK, if everything went fine, another error code otherwise.
668 */
669 status_t
670 BDiskDeviceRoster::RewindPartitiningSystems()
671 {
672 if (fPartitionAddOnDir) {
673 delete fPartitionAddOnDir;
674 fPartitionAddOnDir = NULL;
675 }
676 fPartitionAddOnDirIndex = 0;
677 return B_OK;
678 }
679
680
681 /*! \brief Rewinds the file system list iterator.
682 \return \c B_OK, if everything went fine, another error code otherwise.
683 */
684 status_t
685 BDiskDeviceRoster::RewindFileSystems()
686 {
687 if (fFSAddOnDir) {
688 delete fFSAddOnDir;
689 fFSAddOnDir = NULL;
690 }
691 fFSAddOnDirIndex = 0;
692 return B_OK;
693 }
694
695
696 /*! \brief Returns a BDiskDevice for a given device, session or partition ID.
697
698 The supplied \a device is initialized to the device the object identified
699 by \a id belongs to.
700
701 \param fieldName "device_id", "sesison_id" or "partition_id" according to
702 the type of object the device shall be retrieved for.
703 \param id The ID of the device, session or partition to be retrieved.
704 \param device Pointer to a pre-allocated BDiskDevice to be initialized
705 to the device to be retrieved.
706 \return
707 - \c B_OK: Everything went fine.
708 - \c B_ENTRY_NOT_FOUND: A device, session or partition respectively with
709 ID \a id could not be found.
710 - other error codes
711 */
712 status_t
713 BDiskDeviceRoster::_GetObjectWithID(const char *fieldName, int32 id,
714 BDiskDevice *device) const
715 {
716 status_t error = (device ? B_OK : B_BAD_VALUE);
717 // compose request message
718 BMessage request(B_REG_GET_DISK_DEVICE);
719 if (error == B_OK)
720 error = request.AddInt32(fieldName, id);
721 // send request
722 BMessage reply;
723 if (error == B_OK)
724 error = fManager.SendMessage(&request, &reply);
725 // analyze reply
726 if (error == B_OK) {
727 // result
728 status_t result = B_OK;
729 error = reply.FindInt32("result", &result);
730 if (error == B_OK)
731 error = result;
732 // device
733 BMessage archive;
734 if (error == B_OK)
735 error = reply.FindMessage("device", &archive);
736 if (error == B_OK)
737 error = device->_Unarchive(&archive);
738 }
739 return error;
740 }
741
742
743 /*! \brief Finds and loads the next add-on of an add-on subdirectory.
744 \param directory The add-on directory.
745 \param image Pointer to an image_id into which the image ID of the loaded
746 add-on shall be written.
747 \return
748 - \c B_OK: Everything went fine.
749 - \c B_ENTRY_NOT_FOUND: End of directory.
750 - other error codes
751 */
752 status_t
753 BDiskDeviceRoster::_GetNextAddOn(BDirectory **directory, int32 *index,
754 const char *subdir, AddOnImage *image)
755 {
756 status_t error = (directory && index && subdir && image
757 ? B_OK : B_BAD_VALUE);
758 if (error == B_OK) {
759 // search until an add-on has been found or the end of all directories
760 // has been reached
761 bool found = false;
762 do {
763 // get the next add-on in the current dir
764 error = _GetNextAddOn(*directory, image);
765 if (error == B_OK) {
766 found = true;
767 } else if (error == B_ENTRY_NOT_FOUND) {
768 // end of the current directory has been reached, try next dir
769 error = _GetNextAddOnDir(directory, index, subdir);
770 }
771 } while (error == B_OK && !found);
772 }
773 return error;
774 }
775
776
777 /*! \brief Finds and loads the next add-on of an add-on subdirectory.
778 \param directory The add-on directory.
779 \param image Pointer to an image_id into which the image ID of the loaded
780 add-on shall be written.
781 \return
782 - \c B_OK: Everything went fine.
783 - \c B_ENTRY_NOT_FOUND: End of directory.
784 - other error codes
785 */
786 status_t
787 BDiskDeviceRoster::_GetNextAddOn(BDirectory *directory, AddOnImage *image)
788 {
789 status_t error = (directory ? B_OK : B_ENTRY_NOT_FOUND);
790 if (error == B_OK) {
791 // iterate through the entry list and try to load the entries
792 bool found = false;
793 while (error == B_OK && !found) {
794 BEntry entry;
795 error = directory->GetNextEntry(&entry);
796 BPath path;
797 if (error == B_OK && entry.GetPath(&path) == B_OK)
798 found = (image->Load(path.Path()) == B_OK);
799 }
800 }
801 return error;
802 }
803
804
805 /*! \brief Gets the next add-on directory path.
806 \param path Pointer to a BPath to be set to the found directory.
807 \param index Pointer to an index into the kAddOnDirs array indicating
808 which add-on dir shall be retrieved next.
809 \param subdir Name of the subdirectory (in the "disk_scanner" subdirectory
810 of the add-on directory) \a directory shall be set to.
811 \return
812 - \c B_OK: Everything went fine.
813 - \c B_ENTRY_NOT_FOUND: End of directory list.
814 - other error codes
815 */
816 status_t
817 BDiskDeviceRoster::_GetNextAddOnDir(BPath *path, int32 *index,
818 const char *subdir)
819 {
820 status_t error = (*index < kAddOnDirCount ? B_OK : B_ENTRY_NOT_FOUND);
821 // get the add-on dir path
822 if (error == B_OK) {
823 error = find_directory(kAddOnDirs[*index], path);
824 (*index)++;
825 }
826 // construct the subdirectory path
827 if (error == B_OK) {
828 error = path->Append("disk_scanner");
829 if (error == B_OK)
830 error = path->Append(subdir);
831 }
832 if (error == B_OK)
833 printf(" next add-on dir: `%s'\n", path->Path());
834 return error;
835 }
836
837
838 /*! \brief Gets the next add-on directory.
839 \param directory Pointer to a BDirectory* to be set to the found directory.
840 \param index Pointer to an index into the kAddOnDirs array indicating
841 which add-on dir shall be retrieved next.
842 \param subdir Name of the subdirectory (in the "disk_scanner" subdirectory
843 of the add-on directory) \a directory shall be set to.
844 \return
845 - \c B_OK: Everything went fine.
846 - \c B_ENTRY_NOT_FOUND: End of directory list.
847 - other error codes
848 */
849 status_t
850 BDiskDeviceRoster::_GetNextAddOnDir(BDirectory **directory, int32 *index,
851 const char *subdir)
852 {
853 BPath path;
854 status_t error = _GetNextAddOnDir(&path, index, subdir);
855 // create a BDirectory object, if there is none yet.
856 if (error == B_OK && !*directory) {
857 *directory = new BDirectory;
858 if (!*directory)
859 error = B_NO_MEMORY;
860 }
861 // init the directory
862 if (error == B_OK)
863 error = (*directory)->SetTo(path.Path());
864 // cleanup on error
865 if (error != B_OK && *directory) {
866 delete *directory;
867 *directory = NULL;
868 }
869 return error;
870 }
871
872
873 status_t
874 BDiskDeviceRoster::_LoadPartitionAddOn(const char *partitioningSystem,
875 AddOnImage *image, BDiskScannerPartitionAddOn **_addOn)
876 {
877 status_t error = partitioningSystem && image && _addOn
878 ? B_OK : B_BAD_VALUE;
879
880 // load the image
881 bool found = false;
882 BPath path;
883 BDirectory *directory = NULL;
884 int32 index = 0;
885 while (error == B_OK && !found) {
886 error = _GetNextAddOn(&directory, &index, "partition", image);
887 if (error == B_OK) {
888 // add-on loaded: get the function that creates an add-on
889 // object
890 BDiskScannerPartitionAddOn *(*create_add_on)();
891 if (get_image_symbol(image->ID(), "create_ds_partition_add_on",
892 B_SYMBOL_TYPE_TEXT,
893 (void**)&create_add_on) == B_OK) {
894 // create the add-on object and copy the requested data
895 if (BDiskScannerPartitionAddOn *addOn = (*create_add_on)()) {
896 if (!strcmp(addOn->ShortName(), partitioningSystem)) {
897 *_addOn = addOn;
898 found = true;
899 } else
900 delete addOn;
901 }
902 }
903 }
904 }
905 // cleanup
906 if (directory)
907 delete directory;
908 if (error != B_OK && image)
909 image->Unload();
910 return error;
911 }
912
913 #endif // 0
914