xref: /haiku/src/kits/storage/disk_device/DiskDeviceList.cpp (revision 97901ec593ec4dd50ac115c1c35a6d72f6e489a5)
1 /*
2  * Copyright 2003-2006, Haiku Inc.
3  * Distributed under the terms of the MIT License.
4  *
5  * Authors:
6  *		Ingo Weinhold, bonefish@users.sf.net
7  */
8 
9 #include <DiskDeviceList.h>
10 
11 #include <AutoLocker.h>
12 #include <DiskDevice.h>
13 #include <DiskDevicePrivate.h>
14 #include <DiskDeviceRoster.h>
15 #include <Locker.h>
16 #include <Looper.h>
17 #include <Partition.h>
18 
19 #include <new>
20 using namespace std;
21 
22 // constructor
23 /*!	\brief Creates an empty BDiskDeviceList object.
24 */
25 BDiskDeviceList::BDiskDeviceList(bool useOwnLocker)
26 	: fLocker(NULL),
27 	  fDevices(20, true),
28 	  fSubscribed(false)
29 {
30 	if (useOwnLocker)
31 		fLocker = new(nothrow) BLocker("BDiskDeviceList_fLocker");
32 }
33 
34 // destructor
35 /*!	\brief Frees all resources associated with the object.
36 */
37 BDiskDeviceList::~BDiskDeviceList()
38 {
39 	delete fLocker;
40 }
41 
42 // MessageReceived
43 /*!	\brief Implemented to handle notification messages.
44 */
45 void
46 BDiskDeviceList::MessageReceived(BMessage *message)
47 {
48 	AutoLocker<BDiskDeviceList> _(this);
49 	switch (message->what) {
50 		case B_DEVICE_UPDATE:
51 		{
52 			uint32 event;
53 			if (message->FindInt32("event", (int32*)&event) == B_OK) {
54 				switch (event) {
55 					case B_DEVICE_MOUNT_POINT_MOVED:
56 						_MountPointMoved(message);
57 						break;
58 					case B_DEVICE_PARTITION_MOUNTED:
59 						_PartitionMounted(message);
60 						break;
61 					case B_DEVICE_PARTITION_UNMOUNTED:
62 						_PartitionUnmounted(message);
63 						break;
64 					case B_DEVICE_PARTITION_INITIALIZED:
65 						_PartitionInitialized(message);
66 						break;
67 					case B_DEVICE_PARTITION_RESIZED:
68 						_PartitionResized(message);
69 						break;
70 					case B_DEVICE_PARTITION_MOVED:
71 						_PartitionMoved(message);
72 						break;
73 					case B_DEVICE_PARTITION_CREATED:
74 						_PartitionCreated(message);
75 						break;
76 					case B_DEVICE_PARTITION_DELETED:
77 						_PartitionDeleted(message);
78 						break;
79 					case B_DEVICE_PARTITION_DEFRAGMENTED:
80 						_PartitionDefragmented(message);
81 						break;
82 					case B_DEVICE_PARTITION_REPAIRED:
83 						_PartitionRepaired(message);
84 						break;
85 					case B_DEVICE_MEDIA_CHANGED:
86 						_MediaChanged(message);
87 						break;
88 					case B_DEVICE_ADDED:
89 						_DeviceAdded(message);
90 						break;
91 					case B_DEVICE_REMOVED:
92 						_DeviceRemoved(message);
93 						break;
94 				}
95 			}
96 		}
97 		default:
98 			BHandler::MessageReceived(message);
99 	}
100 }
101 
102 // SetNextHandler
103 /*!	\brief Implemented to unsubscribe from notification services when going
104 		   to be detached from looper.
105 */
106 void
107 BDiskDeviceList::SetNextHandler(BHandler *handler)
108 {
109 	if (!handler) {
110 		AutoLocker<BDiskDeviceList> _(this);
111 		if (fSubscribed)
112 			_StopWatching();
113 	}
114 	BHandler::SetNextHandler(handler);
115 }
116 
117 // Fetch
118 /*!	\brief Empties the list and refills it according to the current state.
119 
120 	Furthermore, if added to a looper, the list subscribes to notification
121 	services needed to keep the list up-to-date.
122 
123 	If an error occurs, the list Unset()s itself.
124 
125 	The object doesn't need to be locked, when this method is invoked. The
126 	method does itself try to lock the list, but doesn't fail, if that
127 	doesn't succeed. That way an object can be used without locking in a
128 	single threaded environment.
129 
130 	\return \c B_OK, if everything went fine, another error code otherwise.
131 */
132 status_t
133 BDiskDeviceList::Fetch()
134 {
135 	Unset();
136 	AutoLocker<BDiskDeviceList> _(this);
137 	// register for notifications
138 	status_t error = B_OK;
139 	if (Looper())
140 		error = _StartWatching();
141 	// get the devices
142 	BDiskDeviceRoster roster;
143 	while (error == B_OK) {
144 		if (BDiskDevice *device = new(nothrow) BDiskDevice) {
145 			status_t status = roster.GetNextDevice(device);
146 			if (status == B_OK)
147 				fDevices.AddItem(device);
148 			else if (status == B_ENTRY_NOT_FOUND)
149 				break;
150 			else
151 				error = status;
152 		} else
153 			error = B_NO_MEMORY;
154 	}
155 	// cleanup on error
156 	if (error != B_OK)
157 		Unset();
158 	return error;
159 }
160 
161 // Unset
162 /*!	\brief Empties the list and unsubscribes from all notification services.
163 
164 	The object doesn't need to be locked, when this method is invoked. The
165 	method does itself try to lock the list, but doesn't fail, if that
166 	doesn't succeed. That way an object can be used without locking in a
167 	single threaded environment.
168 */
169 void
170 BDiskDeviceList::Unset()
171 {
172 	AutoLocker<BDiskDeviceList> _(this);
173 	// unsubscribe from notification services
174 	_StopWatching();
175 	// empty the list
176 	fDevices.MakeEmpty();
177 }
178 
179 // Lock
180 /*!	\brief Locks the list.
181 
182 	If on construction it had been specified, that the list shall use an
183 	own BLocker, then this locker is locked, otherwise LockLooper() is
184 	invoked.
185 
186 	\return \c true, if the list could be locked successfully, \c false
187 			otherwise.
188 */
189 bool
190 BDiskDeviceList::Lock()
191 {
192 	if (fLocker)
193 		return fLocker->Lock();
194 	return LockLooper();
195 }
196 
197 // Unlock
198 /*!	\brief Unlocks the list.
199 
200 	If on construction it had been specified, that the list shall use an
201 	own BLocker, then this locker is unlocked, otherwise UnlockLooper() is
202 	invoked.
203 */
204 void
205 BDiskDeviceList::Unlock()
206 {
207 	if (fLocker)
208 		return fLocker->Unlock();
209 	return UnlockLooper();
210 }
211 
212 // CountDevices
213 /*!	\brief Returns the number of devices in the list.
214 
215 	The list must be locked.
216 
217 	\return The number of devices in the list.
218 */
219 int32
220 BDiskDeviceList::CountDevices() const
221 {
222 	return fDevices.CountItems();
223 }
224 
225 // DeviceAt
226 /*!	\brief Retrieves a device by index.
227 
228 	The list must be locked.
229 
230 	\param index The list index of the device to be returned.
231 	\return The device with index \a index, or \c NULL, if the list is not
232 			locked or \a index is out of range.
233 */
234 BDiskDevice *
235 BDiskDeviceList::DeviceAt(int32 index) const
236 {
237 	return fDevices.ItemAt(index);
238 }
239 
240 // VisitEachDevice
241 /*!	\brief Iterates through the all devices in the list.
242 
243 	The supplied visitor's Visit(BDiskDevice*) is invoked for each device.
244 	If Visit() returns \c true, the iteration is terminated and this method
245 	returns the respective device.
246 
247 	The list must be locked.
248 
249 	\param visitor The visitor.
250 	\return The respective device, if the iteration was terminated early,
251 			\c NULL otherwise.
252 */
253 BDiskDevice *
254 BDiskDeviceList::VisitEachDevice(BDiskDeviceVisitor *visitor)
255 {
256 	if (visitor) {
257 		for (int32 i = 0; BDiskDevice *device = DeviceAt(i); i++) {
258 			if (visitor->Visit(device))
259 				return device;
260 		}
261 	}
262 	return NULL;
263 }
264 
265 // VisitEachPartition
266 /*!	\brief Iterates through the all devices' partitions.
267 
268 	The supplied visitor's Visit(BPartition*) is invoked for each partition.
269 	If Visit() returns \c true, the iteration is terminated and this method
270 	returns the respective partition.
271 
272 	The list must be locked.
273 
274 	\param visitor The visitor.
275 	\return The respective partition, if the iteration was terminated early,
276 			\c NULL otherwise.
277 */
278 BPartition *
279 BDiskDeviceList::VisitEachPartition(BDiskDeviceVisitor *visitor)
280 {
281 	if (visitor) {
282 		for (int32 i = 0; BDiskDevice *device = DeviceAt(i); i++) {
283 			if (BPartition *partition = device->VisitEachDescendant(visitor))
284 				return partition;
285 		}
286 	}
287 	return NULL;
288 }
289 
290 // VisitEachMountedPartition
291 /*!	\brief Iterates through the all devices' partitions that are mounted.
292 
293 	The supplied visitor's Visit(BPartition*) is invoked for each mounted
294 	partition.
295 	If Visit() returns \c true, the iteration is terminated and this method
296 	returns the respective partition.
297 
298 	The list must be locked.
299 
300 	\param visitor The visitor.
301 	\return The respective partition, if the iteration was terminated early,
302 			\c NULL otherwise.
303 */
304 BPartition *
305 BDiskDeviceList::VisitEachMountedPartition(BDiskDeviceVisitor *visitor)
306 {
307 	BPartition *partition = NULL;
308 	if (visitor) {
309 		struct MountedPartitionFilter : public PartitionFilter {
310 			virtual ~MountedPartitionFilter() {};
311 			virtual bool Filter(BPartition *partition, int32 level)
312 				{ return partition->IsMounted(); }
313 		} filter;
314 		PartitionFilterVisitor filterVisitor(visitor, &filter);
315 		partition = VisitEachPartition(&filterVisitor);
316 	}
317 	return partition;
318 }
319 
320 // VisitEachMountablePartition
321 /*!	\brief Iterates through the all devices' partitions that are mountable.
322 
323 	The supplied visitor's Visit(BPartition*) is invoked for each mountable
324 	partition.
325 	If Visit() returns \c true, the iteration is terminated and this method
326 	returns the respective partition.
327 
328 	The list must be locked.
329 
330 	\param visitor The visitor.
331 	\return The respective partition, if the iteration was terminated early,
332 			\c NULL otherwise.
333 */
334 BPartition *
335 BDiskDeviceList::VisitEachMountablePartition(BDiskDeviceVisitor *visitor)
336 {
337 	BPartition *partition = NULL;
338 	if (visitor) {
339 		struct MountablePartitionFilter : public PartitionFilter {
340 			virtual ~MountablePartitionFilter() {};
341 			virtual bool Filter(BPartition *partition, int32 level)
342 				{ return partition->ContainsFileSystem(); }
343 		} filter;
344 		PartitionFilterVisitor filterVisitor(visitor, &filter);
345 		partition = VisitEachPartition(&filterVisitor);
346 	}
347 	return partition;
348 }
349 
350 // DeviceWithID
351 /*!	\brief Retrieves a device by ID.
352 
353 	The list must be locked.
354 
355 	\param id The ID of the device to be returned.
356 	\return The device with ID \a id, or \c NULL, if the list is not
357 			locked or no device with ID \a id is in the list.
358 */
359 BDiskDevice *
360 BDiskDeviceList::DeviceWithID(int32 id) const
361 {
362 	IDFinderVisitor visitor(id);
363 	return const_cast<BDiskDeviceList*>(this)->VisitEachDevice(&visitor);
364 }
365 
366 // PartitionWithID
367 /*!	\brief Retrieves a partition by ID.
368 
369 	The list must be locked.
370 
371 	\param id The ID of the partition to be returned.
372 	\return The partition with ID \a id, or \c NULL, if the list is not
373 			locked or no partition with ID \a id is in the list.
374 */
375 BPartition *
376 BDiskDeviceList::PartitionWithID(int32 id) const
377 {
378 	IDFinderVisitor visitor(id);
379 	return const_cast<BDiskDeviceList*>(this)->VisitEachPartition(&visitor);
380 }
381 
382 // MountPointMoved
383 /*!	\brief Invoked, when the mount point of a partition has been moved.
384 
385 	The list is locked, when this method is invoked.
386 
387 	\param partition The concerned partition.
388 */
389 void
390 BDiskDeviceList::MountPointMoved(BPartition *partition)
391 {
392 	PartitionChanged(partition, B_DEVICE_MOUNT_POINT_MOVED);
393 }
394 
395 // PartitionMounted
396 /*!	\brief Invoked, when a partition has been mounted.
397 
398 	The list is locked, when this method is invoked.
399 
400 	\param partition The concerned partition.
401 */
402 void
403 BDiskDeviceList::PartitionMounted(BPartition *partition)
404 {
405 	PartitionChanged(partition, B_DEVICE_PARTITION_MOUNTED);
406 }
407 
408 // PartitionUnmounted
409 /*!	\brief Invoked, when a partition has been unmounted.
410 
411 	The list is locked, when this method is invoked.
412 
413 	\param partition The concerned partition.
414 */
415 void
416 BDiskDeviceList::PartitionUnmounted(BPartition *partition)
417 {
418 	PartitionChanged(partition, B_DEVICE_PARTITION_UNMOUNTED);
419 }
420 
421 // PartitionInitialized
422 /*!	\brief Invoked, when a partition has been initialized.
423 
424 	The list is locked, when this method is invoked.
425 
426 	\param partition The concerned partition.
427 */
428 void
429 BDiskDeviceList::PartitionInitialized(BPartition *partition)
430 {
431 	PartitionChanged(partition, B_DEVICE_PARTITION_INITIALIZED);
432 }
433 
434 // PartitionResized
435 /*!	\brief Invoked, when a partition has been resized.
436 
437 	The list is locked, when this method is invoked.
438 
439 	\param partition The concerned partition.
440 */
441 void
442 BDiskDeviceList::PartitionResized(BPartition *partition)
443 {
444 	PartitionChanged(partition, B_DEVICE_PARTITION_RESIZED);
445 }
446 
447 // PartitionMoved
448 /*!	\brief Invoked, when a partition has been moved.
449 
450 	The list is locked, when this method is invoked.
451 
452 	\param partition The concerned partition.
453 */
454 void
455 BDiskDeviceList::PartitionMoved(BPartition *partition)
456 {
457 	PartitionChanged(partition, B_DEVICE_PARTITION_MOVED);
458 }
459 
460 // PartitionCreated
461 /*!	\brief Invoked, when a partition has been created.
462 
463 	The list is locked, when this method is invoked.
464 
465 	\param partition The concerned partition.
466 */
467 void
468 BDiskDeviceList::PartitionCreated(BPartition *partition)
469 {
470 }
471 
472 // PartitionDeleted
473 /*!	\brief Invoked, when a partition has been deleted.
474 
475 	The method is called twice for a deleted partition. The first time
476 	before the BDiskDevice the partition belongs to has been updated. The
477 	\a partition parameter will point to a still valid BPartition object.
478 	On the second invocation the device object will have been updated and
479 	the partition object will have been deleted -- \a partition will be
480 	\c NULL then.
481 
482 	The list is locked, when this method is invoked.
483 
484 	\param partition The concerned partition. Only non- \c NULL on the first
485 		   invocation.
486 	\param partitionID The ID of the concerned partition.
487 */
488 void
489 BDiskDeviceList::PartitionDeleted(BPartition *partition,
490 	partition_id partitionID)
491 {
492 }
493 
494 // PartitionDefragmented
495 /*!	\brief Invoked, when a partition has been defragmented.
496 
497 	The list is locked, when this method is invoked.
498 
499 	\param partition The concerned partition.
500 */
501 void
502 BDiskDeviceList::PartitionDefragmented(BPartition *partition)
503 {
504 	PartitionChanged(partition, B_DEVICE_PARTITION_DEFRAGMENTED);
505 }
506 
507 // PartitionRepaired
508 /*!	\brief Invoked, when a partition has been repaired.
509 
510 	The list is locked, when this method is invoked.
511 
512 	\param partition The concerned partition.
513 */
514 void
515 BDiskDeviceList::PartitionRepaired(BPartition *partition)
516 {
517 	PartitionChanged(partition, B_DEVICE_PARTITION_REPAIRED);
518 }
519 
520 // PartitionChanged
521 /*!	\brief Catch-all method invoked by the \c Partition*() hooks, save by
522 		   PartitionCreated() and PartitionDeleted().
523 
524 	If you're interested only in the fact, that something about the partition
525 	changed, you can just override this hook instead of the ones telling you
526 	exactly what happened.
527 
528 	\param partition The concerned partition.
529 	\param event The event that occurred, if you are interested in it after all.
530 */
531 void
532 BDiskDeviceList::PartitionChanged(BPartition *partition, uint32 event)
533 {
534 }
535 
536 // MediaChanged
537 /*!	\brief Invoked, when the media of a device has been changed.
538 
539 	The list is locked, when this method is invoked.
540 
541 	\param device The concerned device.
542 */
543 void
544 BDiskDeviceList::MediaChanged(BDiskDevice *device)
545 {
546 }
547 
548 // DeviceAdded
549 /*!	\brief Invoked, when a device has been added.
550 
551 	The list is locked, when this method is invoked.
552 
553 	\param device The concerned device.
554 */
555 void
556 BDiskDeviceList::DeviceAdded(BDiskDevice *device)
557 {
558 }
559 
560 // DeviceRemoved
561 /*!	\brief Invoked, when a device has been removed.
562 
563 	The supplied object is already removed from the list and is going to be
564 	deleted after the hook returns.
565 
566 	The list is locked, when this method is invoked.
567 
568 	\param device The concerned device.
569 */
570 void
571 BDiskDeviceList::DeviceRemoved(BDiskDevice *device)
572 {
573 }
574 
575 // _StartWatching
576 /*!	\brief Starts watching for disk device notifications.
577 
578 	The object must be locked (if possible at all), when this method is
579 	invoked.
580 
581 	\return \c B_OK, if everything went fine, another error code otherwise.
582 */
583 status_t
584 BDiskDeviceList::_StartWatching()
585 {
586 	if (!Looper() || fSubscribed)
587 		return B_BAD_VALUE;
588 
589 	status_t error = BDiskDeviceRoster().StartWatching(BMessenger(this));
590 	fSubscribed = (error == B_OK);
591 	return error;
592 }
593 
594 // _StopWatching
595 /*!	\brief Stop watching for disk device notifications.
596 
597 	The object must be locked (if possible at all), when this method is
598 	invoked.
599 */
600 void
601 BDiskDeviceList::_StopWatching()
602 {
603 	if (fSubscribed) {
604 		BDiskDeviceRoster().StopWatching(BMessenger(this));
605 		fSubscribed = false;
606 	}
607 }
608 
609 // _MountPointMoved
610 /*!	\brief Handles a "mount point moved" message.
611 	\param message The respective notification message.
612 */
613 void
614 BDiskDeviceList::_MountPointMoved(BMessage *message)
615 {
616 	if (_UpdateDevice(message) != NULL) {
617 		if (BPartition *partition = _FindPartition(message))
618 			MountPointMoved(partition);
619 	}
620 }
621 
622 // _PartitionMounted
623 /*!	\brief Handles a "partition mounted" message.
624 	\param message The respective notification message.
625 */
626 void
627 BDiskDeviceList::_PartitionMounted(BMessage *message)
628 {
629 	if (_UpdateDevice(message) != NULL) {
630 		if (BPartition *partition = _FindPartition(message))
631 			PartitionMounted(partition);
632 	}
633 }
634 
635 // _PartitionUnmounted
636 /*!	\brief Handles a "partition unmounted" message.
637 	\param message The respective notification message.
638 */
639 void
640 BDiskDeviceList::_PartitionUnmounted(BMessage *message)
641 {
642 	if (_UpdateDevice(message) != NULL) {
643 		if (BPartition *partition = _FindPartition(message))
644 			PartitionUnmounted(partition);
645 	}
646 }
647 
648 // _PartitionInitialized
649 /*!	\brief Handles a "partition initialized" message.
650 	\param message The respective notification message.
651 */
652 void
653 BDiskDeviceList::_PartitionInitialized(BMessage *message)
654 {
655 	if (_UpdateDevice(message) != NULL) {
656 		if (BPartition *partition = _FindPartition(message))
657 			PartitionInitialized(partition);
658 	}
659 }
660 
661 // _PartitionResized
662 /*!	\brief Handles a "partition resized" message.
663 	\param message The respective notification message.
664 */
665 void
666 BDiskDeviceList::_PartitionResized(BMessage *message)
667 {
668 	if (_UpdateDevice(message) != NULL) {
669 		if (BPartition *partition = _FindPartition(message))
670 			PartitionResized(partition);
671 	}
672 }
673 
674 // _PartitionMoved
675 /*!	\brief Handles a "partition moved" message.
676 	\param message The respective notification message.
677 */
678 void
679 BDiskDeviceList::_PartitionMoved(BMessage *message)
680 {
681 	if (_UpdateDevice(message) != NULL) {
682 		if (BPartition *partition = _FindPartition(message))
683 			PartitionMoved(partition);
684 	}
685 }
686 
687 // _PartitionCreated
688 /*!	\brief Handles a "partition created" message.
689 	\param message The respective notification message.
690 */
691 void
692 BDiskDeviceList::_PartitionCreated(BMessage *message)
693 {
694 	if (_UpdateDevice(message) != NULL) {
695 		if (BPartition *partition = _FindPartition(message))
696 			PartitionCreated(partition);
697 	}
698 }
699 
700 // _PartitionDeleted
701 /*!	\brief Handles a "partition deleted" message.
702 	\param message The respective notification message.
703 */
704 void
705 BDiskDeviceList::_PartitionDeleted(BMessage *message)
706 {
707 	if (BPartition *partition = _FindPartition(message)) {
708 		partition_id id = partition->ID();
709 		PartitionDeleted(partition, id);
710 		if (_UpdateDevice(message))
711 			PartitionDeleted(NULL, id);
712 	}
713 }
714 
715 // _PartitionDefragmented
716 /*!	\brief Handles a "partition defragmented" message.
717 	\param message The respective notification message.
718 */
719 void
720 BDiskDeviceList::_PartitionDefragmented(BMessage *message)
721 {
722 	if (_UpdateDevice(message) != NULL) {
723 		if (BPartition *partition = _FindPartition(message))
724 			PartitionDefragmented(partition);
725 	}
726 }
727 
728 // _PartitionRepaired
729 /*!	\brief Handles a "partition repaired" message.
730 	\param message The respective notification message.
731 */
732 void
733 BDiskDeviceList::_PartitionRepaired(BMessage *message)
734 {
735 	if (_UpdateDevice(message) != NULL) {
736 		if (BPartition *partition = _FindPartition(message))
737 			PartitionRepaired(partition);
738 	}
739 }
740 
741 // _MediaChanged
742 /*!	\brief Handles a "media changed" message.
743 	\param message The respective notification message.
744 */
745 void
746 BDiskDeviceList::_MediaChanged(BMessage *message)
747 {
748 	if (BDiskDevice *device = _UpdateDevice(message))
749 		MediaChanged(device);
750 }
751 
752 // _DeviceAdded
753 /*!	\brief Handles a "device added" message.
754 	\param message The respective notification message.
755 */
756 void
757 BDiskDeviceList::_DeviceAdded(BMessage *message)
758 {
759 	int32 id;
760 	if (message->FindInt32("device_id", &id) == B_OK && !DeviceWithID(id)) {
761 		BDiskDevice *device = new(nothrow) BDiskDevice;
762 		if (BDiskDeviceRoster().GetDeviceWithID(id, device) == B_OK) {
763 			fDevices.AddItem(device);
764 			DeviceAdded(device);
765 		} else
766 			delete device;
767 	}
768 }
769 
770 // _DeviceRemoved
771 /*!	\brief Handles a "device removed" message.
772 	\param message The respective notification message.
773 */
774 void
775 BDiskDeviceList::_DeviceRemoved(BMessage *message)
776 {
777 	if (BDiskDevice *device = _FindDevice(message)) {
778 		fDevices.RemoveItem(device, false);
779 		DeviceRemoved(device);
780 		delete device;
781 	}
782 }
783 
784 // _FindDevice
785 /*!	\brief Returns the device for the ID contained in a motification message.
786 	\param message The notification message.
787 	\return The device with the ID, or \c NULL, if the ID or the device could
788 			not be found.
789 */
790 BDiskDevice *
791 BDiskDeviceList::_FindDevice(BMessage *message)
792 {
793 	BDiskDevice *device = NULL;
794 	int32 id;
795 	if (message->FindInt32("device_id", &id) == B_OK)
796 		device = DeviceWithID(id);
797 	return device;
798 }
799 
800 // _FindPartition
801 /*!	\brief Returns the partition for the ID contained in a motification
802 		   message.
803 	\param message The notification message.
804 	\return The partition with the ID, or \c NULL, if the ID or the partition
805 			could not be found.*/
806 BPartition *
807 BDiskDeviceList::_FindPartition(BMessage *message)
808 {
809 	BPartition *partition = NULL;
810 	int32 id;
811 	if (message->FindInt32("partition_id", &id) == B_OK)
812 		partition = PartitionWithID(id);
813 	return partition;
814 }
815 
816 // _UpdateDevice
817 /*!	\brief Finds the device for the ID contained in a motification message
818 		   and updates it.
819 	\param message The notification message.
820 	\return The device with the ID, or \c NULL, if the ID or the device could
821 			not be found.
822 */
823 BDiskDevice *
824 BDiskDeviceList::_UpdateDevice(BMessage *message)
825 {
826 	BDiskDevice *device = _FindDevice(message);
827 	if (device) {
828 		if (device->Update() != B_OK) {
829 			fDevices.RemoveItem(device);
830 			device = NULL;
831 		}
832 	}
833 	return device;
834 }
835 
836