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