146b93b2cSIngo Weinhold/*
246b93b2cSIngo Weinhold * Copyright 2003-2007, Ingo Weinhold, ingo_weinhold@gmx.de.
346b93b2cSIngo Weinhold * Distributed under the terms of the MIT License.
446b93b2cSIngo Weinhold */
53e19fccbSIngo Weinhold
65c7270efSIngo Weinhold#include <DiskDevice.h>
75c7270efSIngo Weinhold
8686968fbSIngo Weinhold#include <ctype.h>
9686968fbSIngo Weinhold#include <errno.h>
10686968fbSIngo Weinhold#include <fcntl.h>
11e2ba090eSJérôme Duval#include <new>
12686968fbSIngo Weinhold#include <stdio.h>
13686968fbSIngo Weinhold#include <stdlib.h>
14686968fbSIngo Weinhold#include <string.h>
15686968fbSIngo Weinhold#include <unistd.h>
16b11d9a08SIngo Weinhold
173e19fccbSIngo Weinhold#include <DiskDevice.h>
185c7270efSIngo Weinhold#include <DiskDeviceVisitor.h>
19686968fbSIngo Weinhold#include <Drivers.h>
20b11d9a08SIngo Weinhold#include <Message.h>
215c7270efSIngo Weinhold#include <Path.h>
225c7270efSIngo Weinhold
23ca9e5772SIngo Weinhold#include <syscalls.h>
246b202f4eSIngo Weinhold#include <ddm_userland_interface_defs.h>
25ca9e5772SIngo Weinhold
26c70623faSIngo Weinhold#include "DiskDeviceJob.h"
27c70623faSIngo Weinhold#include "DiskDeviceJobGenerator.h"
28c70623faSIngo Weinhold#include "DiskDeviceJobQueue.h"
292f3ce2bfSBryce Groff#include <DiskSystemAddOnManager.h>
30a3a0e88eSIngo Weinhold
313e19fccbSIngo Weinhold
32270b97c8SStephan Aßmus//#define TRACE_DISK_DEVICE
33270b97c8SStephan Aßmus#undef TRACE
34270b97c8SStephan Aßmus#ifdef TRACE_DISK_DEVICE
35270b97c8SStephan Aßmus# define TRACE(x...) printf(x)
36270b97c8SStephan Aßmus#else
37270b97c8SStephan Aßmus# define TRACE(x...) do {} while (false)
38270b97c8SStephan Aßmus#endif
39270b97c8SStephan Aßmus
40270b97c8SStephan Aßmus
417c2e411dSIngo Weinhold/*!	\class BDiskDevice
427c2e411dSIngo Weinhold	\brief A BDiskDevice object represents a storage device.
437c2e411dSIngo Weinhold*/
447c2e411dSIngo Weinhold
4546b93b2cSIngo Weinhold
463e19fccbSIngo Weinhold// constructor
477c2e411dSIngo Weinhold/*!	\brief Creates an uninitialized BDiskDevice object.
487c2e411dSIngo Weinhold*/
493e19fccbSIngo WeinholdBDiskDevice::BDiskDevice()
50e1b526b9SJonas Sundström	:
51e1b526b9SJonas Sundström	fDeviceData(NULL)
523e19fccbSIngo Weinhold{
533e19fccbSIngo Weinhold}
543e19fccbSIngo Weinhold
5546b93b2cSIngo Weinhold
563e19fccbSIngo Weinhold// destructor
577c2e411dSIngo Weinhold/*!	\brief Frees all resources associated with this object.
587c2e411dSIngo Weinhold*/
593e19fccbSIngo WeinholdBDiskDevice::~BDiskDevice()
603e19fccbSIngo Weinhold{
61619c1705SIngo Weinhold	CancelModifications();
623e19fccbSIngo Weinhold}
633e19fccbSIngo Weinhold
6446b93b2cSIngo Weinhold
650cb59d9cSIngo Weinhold// HasMedia
660cb59d9cSIngo Weinhold/*!	\brief Returns whether the device contains a media.
670cb59d9cSIngo Weinhold	\return \c true, if the device contains a media, \c false otherwise.
680cb59d9cSIngo Weinhold*/
690cb59d9cSIngo Weinholdbool
700cb59d9cSIngo WeinholdBDiskDevice::HasMedia() const
710cb59d9cSIngo Weinhold{
7238bbc957SAxel Dörfler	return fDeviceData
7338bbc957SAxel Dörfler		&& (fDeviceData->device_flags & B_DISK_DEVICE_HAS_MEDIA) != 0;
740cb59d9cSIngo Weinhold}
750cb59d9cSIngo Weinhold
7646b93b2cSIngo Weinhold
770cb59d9cSIngo Weinhold// IsRemovableMedia
785c7270efSIngo Weinhold/*!	\brief Returns whether the device media are removable.
795c7270efSIngo Weinhold	\return \c true, if the device media are removable, \c false otherwise.
807c2e411dSIngo Weinhold*/
815c7270efSIngo Weinholdbool
820cb59d9cSIngo WeinholdBDiskDevice::IsRemovableMedia() const
837c2e411dSIngo Weinhold{
8438bbc957SAxel Dörfler	return fDeviceData
8538bbc957SAxel Dörfler		&& (fDeviceData->device_flags & B_DISK_DEVICE_REMOVABLE) != 0;
867c2e411dSIngo Weinhold}
877c2e411dSIngo Weinhold
8846b93b2cSIngo Weinhold
890cb59d9cSIngo Weinhold// IsReadOnlyMedia
905c7270efSIngo Weinholdbool
910cb59d9cSIngo WeinholdBDiskDevice::IsReadOnlyMedia() const
927c2e411dSIngo Weinhold{
9338bbc957SAxel Dörfler	return fDeviceData
9438bbc957SAxel Dörfler		&& (fDeviceData->device_flags & B_DISK_DEVICE_READ_ONLY) != 0;
950cb59d9cSIngo Weinhold}
960cb59d9cSIngo Weinhold
9746b93b2cSIngo Weinhold
980cb59d9cSIngo Weinhold// IsWriteOnceMedia
990cb59d9cSIngo Weinholdbool
1000cb59d9cSIngo WeinholdBDiskDevice::IsWriteOnceMedia() const
1010cb59d9cSIngo Weinhold{
10238bbc957SAxel Dörfler	return fDeviceData
10338bbc957SAxel Dörfler		&& (fDeviceData->device_flags & B_DISK_DEVICE_WRITE_ONCE) != 0;
1047c2e411dSIngo Weinhold}
1057c2e411dSIngo Weinhold
10646b93b2cSIngo Weinhold
1075c7270efSIngo Weinhold// Eject
1085c7270efSIngo Weinhold/*!	\brief Eject the device's media.
1095c7270efSIngo Weinhold
1105c7270efSIngo Weinhold	The device media must, of course, be removable, and the device must
1115c7270efSIngo Weinhold	support ejecting the media.
1125c7270efSIngo Weinhold
1135c7270efSIngo Weinhold	\param update If \c true, Update() is invoked after successful ejection.
1145c7270efSIngo Weinhold	\return
1155c7270efSIngo Weinhold	- \c B_OK: Everything went fine.
1165c7270efSIngo Weinhold	- \c B_NO_INIT: The device is not properly initialized.
1175c7270efSIngo Weinhold	- \c B_BAD_VALUE: The device media is not removable.
1185c7270efSIngo Weinhold	- other error codes
1197c2e411dSIngo Weinhold*/
1205c7270efSIngo Weinholdstatus_t
1215c7270efSIngo WeinholdBDiskDevice::Eject(bool update)
1223e19fccbSIngo Weinhold{
1232ec100b7SAxel Dörfler	if (fDeviceData == NULL)
1242ec100b7SAxel Dörfler		return B_NO_INIT;
1252ec100b7SAxel Dörfler
1265c7270efSIngo Weinhold	// check whether the device media is removable
1272ec100b7SAxel Dörfler	if (!IsRemovableMedia())
1282ec100b7SAxel Dörfler		return B_BAD_VALUE;
1292ec100b7SAxel Dörfler
1305c7270efSIngo Weinhold	// open, eject and close the device
1312ec100b7SAxel Dörfler	int fd = open(fDeviceData->path, O_RDONLY);
1322ec100b7SAxel Dörfler	if (fd < 0)
1332ec100b7SAxel Dörfler		return errno;
1342ec100b7SAxel Dörfler
1352ec100b7SAxel Dörfler	status_t status = B_OK;
1362ec100b7SAxel Dörfler	if (ioctl(fd, B_EJECT_DEVICE) != 0)
1372ec100b7SAxel Dörfler		status = errno;
1382ec100b7SAxel Dörfler
1392ec100b7SAxel Dörfler	close(fd);
1402ec100b7SAxel Dörfler
1412ec100b7SAxel Dörfler	if (status == B_OK && update)
1422ec100b7SAxel Dörfler		status = Update();
1432ec100b7SAxel Dörfler
1442ec100b7SAxel Dörfler	return status;
1453e19fccbSIngo Weinhold}
1463e19fccbSIngo Weinhold
14746b93b2cSIngo Weinhold
14892b9e333SIngo Weinhold// SetTo
14992b9e333SIngo Weinholdstatus_t
15092b9e333SIngo WeinholdBDiskDevice::SetTo(partition_id id)
15192b9e333SIngo Weinhold{
1521573b626SIngo Weinhold	return _SetTo(id, true, 0);
15392b9e333SIngo Weinhold}
15492b9e333SIngo Weinhold
15546b93b2cSIngo Weinhold
1565c7270efSIngo Weinhold// Update
1575c7270efSIngo Weinhold/*!	\brief Updates the object to reflect the latest changes to the device.
1585c7270efSIngo Weinhold
1595c7270efSIngo Weinhold	Note, that subobjects (BSessions, BPartitions) may be deleted during this
1605c7270efSIngo Weinhold	operation. It is also possible, that the device doesn't exist anymore --
1615c7270efSIngo Weinhold	e.g. if it is hot-pluggable. Then an error is returned and the object is
1625c7270efSIngo Weinhold	uninitialized.
1635c7270efSIngo Weinhold
1645c7270efSIngo Weinhold	\param updated Pointer to a bool variable which shall be set to \c true,
1655c7270efSIngo Weinhold		   if the object needed to be updated and to \c false otherwise.
1665c7270efSIngo Weinhold		   May be \c NULL. Is not touched, if the method fails.
1675c7270efSIngo Weinhold	\return \c B_OK, if the update went fine, another error code otherwise.
1687c2e411dSIngo Weinhold*/
1695c7270efSIngo Weinholdstatus_t
17046b93b2cSIngo WeinholdBDiskDevice::Update(bool* updated)
1713e19fccbSIngo Weinhold{
1721573b626SIngo Weinhold	if (InitCheck() != B_OK)
1731573b626SIngo Weinhold		return InitCheck();
1741573b626SIngo Weinhold
1751573b626SIngo Weinhold	// get the device data
1761573b626SIngo Weinhold	user_disk_device_data* data = NULL;
1771573b626SIngo Weinhold	status_t error = _GetData(ID(), true, 0, &data);
1781573b626SIngo Weinhold
1791573b626SIngo Weinhold	// set the data
1801573b626SIngo Weinhold	if (error == B_OK)
1811573b626SIngo Weinhold		error = _Update(data, updated);
1821573b626SIngo Weinhold
1831573b626SIngo Weinhold	// cleanup on error
1841573b626SIngo Weinhold	if (error != B_OK && data)
1851573b626SIngo Weinhold		free(data);
1861573b626SIngo Weinhold
1871573b626SIngo Weinhold	return error;
1883e19fccbSIngo Weinhold}
1893e19fccbSIngo Weinhold
19046b93b2cSIngo Weinhold
1915c7270efSIngo Weinhold// Unset
1925c7270efSIngo Weinholdvoid
1935c7270efSIngo WeinholdBDiskDevice::Unset()
1945c7270efSIngo Weinhold{
19592b9e333SIngo Weinhold	BPartition::_Unset();
1965c7270efSIngo Weinhold	free(fDeviceData);
1975c7270efSIngo Weinhold	fDeviceData = NULL;
1985c7270efSIngo Weinhold}
1995c7270efSIngo Weinhold
20046b93b2cSIngo Weinhold
20192b9e333SIngo Weinhold// InitCheck
20292b9e333SIngo Weinholdstatus_t
20392b9e333SIngo WeinholdBDiskDevice::InitCheck() const
20492b9e333SIngo Weinhold{
20538bbc957SAxel Dörfler	return fDeviceData ? B_OK : B_NO_INIT;
20692b9e333SIngo Weinhold}
20792b9e333SIngo Weinhold
20846b93b2cSIngo Weinhold
2095c7270efSIngo Weinhold// GetPath
2105c7270efSIngo Weinholdstatus_t
21146b93b2cSIngo WeinholdBDiskDevice::GetPath(BPath* path) const
2123e19fccbSIngo Weinhold{
2135c7270efSIngo Weinhold	if (!path || !fDeviceData)
2145c7270efSIngo Weinhold		return B_BAD_VALUE;
2155c7270efSIngo Weinhold	return path->SetTo(fDeviceData->path);
2163e19fccbSIngo Weinhold}
2173e19fccbSIngo Weinhold
21846b93b2cSIngo Weinhold
2195c7270efSIngo Weinhold// IsModified
2205c7270efSIngo Weinholdbool
2215c7270efSIngo WeinholdBDiskDevice::IsModified() const
2225c7270efSIngo Weinhold{
22327d7c366SIngo Weinhold	if (InitCheck() != B_OK)
22427d7c366SIngo Weinhold		return false;
22527d7c366SIngo Weinhold
22627d7c366SIngo Weinhold	struct IsModifiedVisitor : public BDiskDeviceVisitor {
227e1b526b9SJonas Sundström		virtual bool Visit(BDiskDevice* device)
22827d7c366SIngo Weinhold		{
22927d7c366SIngo Weinhold			return Visit(device, 0);
23027d7c366SIngo Weinhold		}
23138bbc957SAxel Dörfler
232e1b526b9SJonas Sundström		virtual bool Visit(BPartition* partition, int32 level)
23327d7c366SIngo Weinhold		{
23427d7c366SIngo Weinhold			return partition->_IsModified();
23527d7c366SIngo Weinhold		}
23627d7c366SIngo Weinhold	} visitor;
23727d7c366SIngo Weinhold
23827d7c366SIngo Weinhold	return (VisitEachDescendant(&visitor) != NULL);
2395c7270efSIngo Weinhold}
2405c7270efSIngo Weinhold
24146b93b2cSIngo Weinhold
2425c7270efSIngo Weinhold// PrepareModifications
243619c1705SIngo Weinhold/*!	\brief Initializes the partition hierarchy for modifications.
24438bbc957SAxel Dörfler *
245619c1705SIngo Weinhold * 	Subsequent modifications are performed on so-called \a shadow structure
246619c1705SIngo Weinhold * 	and not written to device until \ref CommitModifications is called.
247619c1705SIngo Weinhold *
248619c1705SIngo Weinhold * 	\note This call locks the device. You need to call \ref CommitModifications
249619c1705SIngo Weinhold * 		or \ref CancelModifications to unlock it.
250619c1705SIngo Weinhold */
2515c7270efSIngo Weinholdstatus_t
2525c7270efSIngo WeinholdBDiskDevice::PrepareModifications()
2535c7270efSIngo Weinhold{
254270b97c8SStephan Aßmus	TRACE("%p->BDiskDevice::PrepareModifications()\n", this);
255270b97c8SStephan Aßmus
25692b9e333SIngo Weinhold	// check initialization
25792b9e333SIngo Weinhold	status_t error = InitCheck();
258270b97c8SStephan Aßmus	if (error != B_OK) {
259270b97c8SStephan Aßmus		TRACE("  InitCheck() failed\n");
26092b9e333SIngo Weinhold		return error;
261270b97c8SStephan Aßmus	}
262270b97c8SStephan Aßmus	if (fDelegate) {
263270b97c8SStephan Aßmus		TRACE("  already prepared!\n");
26427d7c366SIngo Weinhold		return B_BAD_VALUE;
265270b97c8SStephan Aßmus	}
26646b93b2cSIngo Weinhold
267a3a0e88eSIngo Weinhold	// make sure the disk system add-ons are loaded
268a3a0e88eSIngo Weinhold	error = DiskSystemAddOnManager::Default()->LoadDiskSystems();
269270b97c8SStephan Aßmus	if (error != B_OK) {
270270b97c8SStephan Aßmus		TRACE("  failed to load disk systems\n");
271a3a0e88eSIngo Weinhold		return error;
272270b97c8SStephan Aßmus	}
273a3a0e88eSIngo Weinhold
27427d7c366SIngo Weinhold	// recursively create the delegates
27527d7c366SIngo Weinhold	error = _CreateDelegates();
27646b93b2cSIngo Weinhold
27727d7c366SIngo Weinhold	// init them
27827d7c366SIngo Weinhold	if (error == B_OK)
27927d7c366SIngo Weinhold		error = _InitDelegates();
280270b97c8SStephan Aßmus	else
281270b97c8SStephan Aßmus		TRACE("  failed to create delegates\n");
28227d7c366SIngo Weinhold
28327d7c366SIngo Weinhold	// delete all of them, if something went wrong
284a3a0e88eSIngo Weinhold	if (error != B_OK) {
285270b97c8SStephan Aßmus		TRACE("  failed to init delegates\n");
28627d7c366SIngo Weinhold		_DeleteDelegates();
287a3a0e88eSIngo Weinhold		DiskSystemAddOnManager::Default()->UnloadDiskSystems();
288a3a0e88eSIngo Weinhold	}
28946b93b2cSIngo Weinhold
290426b44c6SIngo Weinhold	return error;
2915c7270efSIngo Weinhold}
2925c7270efSIngo Weinhold
29346b93b2cSIngo Weinhold
2945c7270efSIngo Weinhold// CommitModifications
295619c1705SIngo Weinhold/*!	\brief Commits modifications to device.
296619c1705SIngo Weinhold *
297619c1705SIngo Weinhold * 	Creates a set of jobs that perform all the changes done after
298619c1705SIngo Weinhold * 	\ref PrepareModifications. The changes are then written to device.
299ad50b122SStephan Aßmus * 	Deletes and recreates all BPartition children to apply the changes,
300ad50b122SStephan Aßmus * 	so cached pointers to BPartition objects cannot be used after this
301ad50b122SStephan Aßmus * 	call.
302619c1705SIngo Weinhold * 	Unlocks the device for further use.
303619c1705SIngo Weinhold */
3045c7270efSIngo Weinholdstatus_t
3055c7270efSIngo WeinholdBDiskDevice::CommitModifications(bool synchronously,
30646b93b2cSIngo Weinhold	BMessenger progressMessenger, bool receiveCompleteProgressUpdates)
3075c7270efSIngo Weinhold{
308c70623faSIngo Weinhold// TODO: Support parameters!
309c3cfd913SIngo Weinhold	status_t error = InitCheck();
310c3cfd913SIngo Weinhold	if (error != B_OK)
311c3cfd913SIngo Weinhold		return error;
31227d7c366SIngo Weinhold
31327d7c366SIngo Weinhold	if (!fDelegate)
314c3cfd913SIngo Weinhold		return B_BAD_VALUE;
31546b93b2cSIngo Weinhold
316c70623faSIngo Weinhold	// generate jobs
317c70623faSIngo Weinhold	DiskDeviceJobQueue jobQueue;
318c70623faSIngo Weinhold	error = DiskDeviceJobGenerator(this, &jobQueue).GenerateJobs();
319c70623faSIngo Weinhold
320c70623faSIngo Weinhold	// do the jobs
321c70623faSIngo Weinhold	if (error == B_OK)
322c70623faSIngo Weinhold		error = jobQueue.Execute();
32327d7c366SIngo Weinhold
32427d7c366SIngo Weinhold	_DeleteDelegates();
325a3a0e88eSIngo Weinhold	DiskSystemAddOnManager::Default()->UnloadDiskSystems();
32627d7c366SIngo Weinhold
327c3cfd913SIngo Weinhold	if (error == B_OK)
3281573b626SIngo Weinhold		error = _SetTo(ID(), true, 0);
32946b93b2cSIngo Weinhold
330c3cfd913SIngo Weinhold	return error;
3315c7270efSIngo Weinhold}
3325c7270efSIngo Weinhold
33346b93b2cSIngo Weinhold
3345c7270efSIngo Weinhold// CancelModifications
335619c1705SIngo Weinhold/*!	\brief Cancels all modifications performed on the device.
336619c1705SIngo Weinhold *
337619c1705SIngo Weinhold * 	Nothing is written on the device and it is unlocked for further use.
338619c1705SIngo Weinhold */
3395c7270efSIngo Weinholdstatus_t
3405c7270efSIngo WeinholdBDiskDevice::CancelModifications()
3415c7270efSIngo Weinhold{
34292b9e333SIngo Weinhold	status_t error = InitCheck();
34392b9e333SIngo Weinhold	if (error != B_OK)
34492b9e333SIngo Weinhold		return error;
34527d7c366SIngo Weinhold
34627d7c366SIngo Weinhold	if (!fDelegate)
34792b9e333SIngo Weinhold		return B_BAD_VALUE;
34846b93b2cSIngo Weinhold
34927d7c366SIngo Weinhold	_DeleteDelegates();
350a3a0e88eSIngo Weinhold	DiskSystemAddOnManager::Default()->UnloadDiskSystems();
35127d7c366SIngo Weinhold
35292b9e333SIngo Weinhold	if (error == B_OK)
3531573b626SIngo Weinhold		error = _SetTo(ID(), true, 0);
35446b93b2cSIngo Weinhold
35592b9e333SIngo Weinhold	return error;
3565c7270efSIngo Weinhold}
3575c7270efSIngo Weinhold
35846b93b2cSIngo Weinhold
35938bbc957SAxel Dörfler/*!	\brief Returns whether or not this device is a virtual device backed
36038bbc957SAxel Dörfler		up by a file.
36138bbc957SAxel Dörfler*/
36238bbc957SAxel Dörflerbool
36338bbc957SAxel DörflerBDiskDevice::IsFile() const
36438bbc957SAxel Dörfler{
36538bbc957SAxel Dörfler	return fDeviceData
36638bbc957SAxel Dörfler		&& (fDeviceData->device_flags & B_DISK_DEVICE_IS_FILE) != 0;
36738bbc957SAxel Dörfler}
36838bbc957SAxel Dörfler
36938bbc957SAxel Dörfler
37038bbc957SAxel Dörfler/*!	\brief Retrieves the path of the file backing up the disk device.*/
37138bbc957SAxel Dörflerstatus_t
37238bbc957SAxel DörflerBDiskDevice::GetFilePath(BPath* path) const
37338bbc957SAxel Dörfler{
37438bbc957SAxel Dörfler	if (path == NULL)
37538bbc957SAxel Dörfler		return B_BAD_VALUE;
37638bbc957SAxel Dörfler	if (!IsFile())
37738bbc957SAxel Dörfler		return B_BAD_TYPE;
37838bbc957SAxel Dörfler
37938bbc957SAxel Dörfler	char pathBuffer[B_PATH_NAME_LENGTH];
38038bbc957SAxel Dörfler	status_t status = _kern_get_file_disk_device_path(
38138bbc957SAxel Dörfler		fDeviceData->device_partition_data.id, pathBuffer, sizeof(pathBuffer));
38238bbc957SAxel Dörfler	if (status != B_OK)
38338bbc957SAxel Dörfler		return status;
38438bbc957SAxel Dörfler
38538bbc957SAxel Dörfler	return path->SetTo(pathBuffer);
38638bbc957SAxel Dörfler}
38738bbc957SAxel Dörfler
38838bbc957SAxel Dörfler
389426b44c6SIngo Weinhold// copy constructor
390426b44c6SIngo Weinhold/*!	\brief Privatized copy constructor to avoid usage.
391426b44c6SIngo Weinhold*/
39246b93b2cSIngo WeinholdBDiskDevice::BDiskDevice(const BDiskDevice&)
393426b44c6SIngo Weinhold{
394426b44c6SIngo Weinhold}
395426b44c6SIngo Weinhold
39646b93b2cSIngo Weinhold
397426b44c6SIngo Weinhold// =
398426b44c6SIngo Weinhold/*!	\brief Privatized assignment operator to avoid usage.
399426b44c6SIngo Weinhold*/
40046b93b2cSIngo WeinholdBDiskDevice&
40146b93b2cSIngo WeinholdBDiskDevice::operator=(const BDiskDevice&)
402426b44c6SIngo Weinhold{
403426b44c6SIngo Weinhold	return *this;
404426b44c6SIngo Weinhold}
405426b44c6SIngo Weinhold
40646b93b2cSIngo Weinhold
407426b44c6SIngo Weinhold// _GetData
4085c7270efSIngo Weinholdstatus_t
4091573b626SIngo WeinholdBDiskDevice::_GetData(partition_id id, bool deviceOnly, size_t neededSize,
4101573b626SIngo Weinhold	user_disk_device_data** data)
4115c7270efSIngo Weinhold{
4125c7270efSIngo Weinhold	// get the device data
41346b93b2cSIngo Weinhold	void* buffer = NULL;
4145c7270efSIngo Weinhold	size_t bufferSize = 0;
4155c7270efSIngo Weinhold	if (neededSize > 0) {
4165c7270efSIngo Weinhold		// allocate initial buffer
4175c7270efSIngo Weinhold		buffer = malloc(neededSize);
4185c7270efSIngo Weinhold		if (!buffer)
4195c7270efSIngo Weinhold			return B_NO_MEMORY;
4205c7270efSIngo Weinhold		bufferSize = neededSize;
4215c7270efSIngo Weinhold	}
42246b93b2cSIngo Weinhold
4235c7270efSIngo Weinhold	status_t error = B_OK;
4245c7270efSIngo Weinhold	do {
4258354dac7SIngo Weinhold		error = _kern_get_disk_device_data(id, deviceOnly,
42627d7c366SIngo Weinhold			(user_disk_device_data*)buffer, bufferSize, &neededSize);
4275c7270efSIngo Weinhold		if (error == B_BUFFER_OVERFLOW) {
4285c7270efSIngo Weinhold			// buffer to small re-allocate it
429cee04e80SArtur Wyszynski			free(buffer);
43046b93b2cSIngo Weinhold
4315c7270efSIngo Weinhold			buffer = malloc(neededSize);
43246b93b2cSIngo Weinhold
4335c7270efSIngo Weinhold			if (buffer)
4345c7270efSIngo Weinhold				bufferSize = neededSize;
4355c7270efSIngo Weinhold			else
4365c7270efSIngo Weinhold				error = B_NO_MEMORY;
4375c7270efSIngo Weinhold		}
4385c7270efSIngo Weinhold	} while (error == B_BUFFER_OVERFLOW);
43946b93b2cSIngo Weinhold
440426b44c6SIngo Weinhold	// set result / cleanup on error
441426b44c6SIngo Weinhold	if (error == B_OK)
442426b44c6SIngo Weinhold		*data = (user_disk_device_data*)buffer;
443cee04e80SArtur Wyszynski	else
444426b44c6SIngo Weinhold		free(buffer);
44546b93b2cSIngo Weinhold
446426b44c6SIngo Weinhold	return error;
447426b44c6SIngo Weinhold}
448426b44c6SIngo Weinhold
44946b93b2cSIngo Weinhold
450426b44c6SIngo Weinhold// _SetTo
451426b44c6SIngo Weinholdstatus_t
4521573b626SIngo WeinholdBDiskDevice::_SetTo(partition_id id, bool deviceOnly, size_t neededSize)
453426b44c6SIngo Weinhold{
454426b44c6SIngo Weinhold	Unset();
45546b93b2cSIngo Weinhold
456426b44c6SIngo Weinhold	// get the device data
45746b93b2cSIngo Weinhold	user_disk_device_data* data = NULL;
4581573b626SIngo Weinhold	status_t error = _GetData(id, deviceOnly, neededSize, &data);
45946b93b2cSIngo Weinhold
4605c7270efSIngo Weinhold	// set the data
4615c7270efSIngo Weinhold	if (error == B_OK)
462426b44c6SIngo Weinhold		error = _SetTo(data);
46346b93b2cSIngo Weinhold
4645c7270efSIngo Weinhold	// cleanup on error
465426b44c6SIngo Weinhold	if (error != B_OK && data)
466426b44c6SIngo Weinhold		free(data);
46746b93b2cSIngo Weinhold
4685c7270efSIngo Weinhold	return error;
4695c7270efSIngo Weinhold}
4705c7270efSIngo Weinhold
47146b93b2cSIngo Weinhold
472671a7455SIngo Weinhold// _SetTo
4735c7270efSIngo Weinholdstatus_t
47446b93b2cSIngo WeinholdBDiskDevice::_SetTo(user_disk_device_data* data)
4755c7270efSIngo Weinhold{
4765c7270efSIngo Weinhold	Unset();
47746b93b2cSIngo Weinhold
4785c7270efSIngo Weinhold	if (!data)
4795c7270efSIngo Weinhold		return B_BAD_VALUE;
48046b93b2cSIngo Weinhold
4815c7270efSIngo Weinhold	fDeviceData = data;
48246b93b2cSIngo Weinhold
483671a7455SIngo Weinhold	status_t error = BPartition::_SetTo(this, NULL,
48446b93b2cSIngo Weinhold		&fDeviceData->device_partition_data);
4855c7270efSIngo Weinhold	if (error != B_OK) {
48692b9e333SIngo Weinhold		// If _SetTo() fails, the caller retains ownership of the supplied
48792b9e333SIngo Weinhold		// data. So, unset fDeviceData before calling Unset().
4885c7270efSIngo Weinhold		fDeviceData = NULL;
48992b9e333SIngo Weinhold		Unset();
4905c7270efSIngo Weinhold	}
49146b93b2cSIngo Weinhold
4925c7270efSIngo Weinhold	return error;
4935c7270efSIngo Weinhold}
4945c7270efSIngo Weinhold
49546b93b2cSIngo Weinhold
496686968fbSIngo Weinhold// _Update
497686968fbSIngo Weinholdstatus_t
49846b93b2cSIngo WeinholdBDiskDevice::_Update(user_disk_device_data* data, bool* updated)
499686968fbSIngo Weinhold{
500426b44c6SIngo Weinhold	if (!data || !fDeviceData || ID() != data->device_partition_data.id)
501426b44c6SIngo Weinhold		return B_BAD_VALUE;
502426b44c6SIngo Weinhold	bool _updated;
503426b44c6SIngo Weinhold	if (!updated)
504426b44c6SIngo Weinhold		updated = &_updated;
505426b44c6SIngo Weinhold	*updated = false;
50604adb291SIngo Weinhold
50704adb291SIngo Weinhold	// clear the user_data fields first
50804adb291SIngo Weinhold	_ClearUserData(&data->device_partition_data);
50904adb291SIngo Weinhold
510426b44c6SIngo Weinhold	// remove obsolete partitions
511426b44c6SIngo Weinhold	status_t error = _RemoveObsoleteDescendants(&data->device_partition_data,
51204adb291SIngo Weinhold		updated);
513426b44c6SIngo Weinhold	if (error != B_OK)
514426b44c6SIngo Weinhold		return error;
51504adb291SIngo Weinhold
516426b44c6SIngo Weinhold	// update existing partitions and add new ones
517426b44c6SIngo Weinhold	error = BPartition::_Update(&data->device_partition_data, updated);
518686968fbSIngo Weinhold	if (error == B_OK) {
51946b93b2cSIngo Weinhold		user_disk_device_data* oldData = fDeviceData;
520426b44c6SIngo Weinhold		fDeviceData = data;
521426b44c6SIngo Weinhold		// check for changes
522426b44c6SIngo Weinhold		if (data->device_flags != oldData->device_flags
523426b44c6SIngo Weinhold			|| strcmp(data->path, oldData->path)) {
524426b44c6SIngo Weinhold			*updated = true;
525686968fbSIngo Weinhold		}
526426b44c6SIngo Weinhold		free(oldData);
527686968fbSIngo Weinhold	}
52846b93b2cSIngo Weinhold
529686968fbSIngo Weinhold	return error;
530686968fbSIngo Weinhold}
531686968fbSIngo Weinhold
53246b93b2cSIngo Weinhold
533426b44c6SIngo Weinhold// _AcceptVisitor
534b11d9a08SIngo Weinholdbool
53546b93b2cSIngo WeinholdBDiskDevice::_AcceptVisitor(BDiskDeviceVisitor* visitor, int32 level)
536b11d9a08SIngo Weinhold{
537426b44c6SIngo Weinhold	return visitor->Visit(this);
538b11d9a08SIngo Weinhold}
539b11d9a08SIngo Weinhold
54004adb291SIngo Weinhold
54104adb291SIngo Weinhold// _ClearUserData
54204adb291SIngo Weinholdvoid
54304adb291SIngo WeinholdBDiskDevice::_ClearUserData(user_partition_data* data)
54404adb291SIngo Weinhold{
54504adb291SIngo Weinhold	data->user_data = NULL;
54604adb291SIngo Weinhold
54704adb291SIngo Weinhold	// recurse
54804adb291SIngo Weinhold	for (int i = 0; i < data->child_count; i++)
54904adb291SIngo Weinhold		_ClearUserData(data->children[i]);
55004adb291SIngo Weinhold}