1/*
2 * Copyright 2003-2009, Ingo Weinhold, ingo_weinhold@gmx.de.
3 * Distributed under the terms of the MIT License.
4 */
5
6
7#include "disk_device_manager.h"
8
9#include <stdio.h>
10
11#include <KernelExport.h>
12
13#include "KDiskDevice.h"
14#include "KDiskDeviceManager.h"
15#include "KDiskDeviceUtils.h"
16#include "KDiskSystem.h"
17#include "KPartition.h"
18
19
20// debugging
21//#define DBG(x)
22#define DBG(x) x
23#define OUT dprintf
24
25
26disk_device_data*
27write_lock_disk_device(partition_id partitionID)
28{
29	KDiskDeviceManager* manager = KDiskDeviceManager::Default();
30	if (KDiskDevice* device = manager->RegisterDevice(partitionID, false)) {
31		if (device->WriteLock())
32			return device->DeviceData();
33		// Only unregister, when the locking fails. The guarantees, that the
34		// lock owner also has a reference.
35		device->Unregister();
36	}
37	return NULL;
38}
39
40
41void
42write_unlock_disk_device(partition_id partitionID)
43{
44	KDiskDeviceManager* manager = KDiskDeviceManager::Default();
45	if (KDiskDevice* device = manager->RegisterDevice(partitionID, false)) {
46		device->WriteUnlock();
47		device->Unregister();
48
49		device->Unregister();
50	}
51}
52
53
54disk_device_data*
55read_lock_disk_device(partition_id partitionID)
56{
57	KDiskDeviceManager* manager = KDiskDeviceManager::Default();
58	if (KDiskDevice* device = manager->RegisterDevice(partitionID, false)) {
59		if (device->ReadLock())
60			return device->DeviceData();
61		// Only unregister, when the locking fails. The guarantees, that the
62		// lock owner also has a reference.
63		device->Unregister();
64	}
65	return NULL;
66}
67
68
69void
70read_unlock_disk_device(partition_id partitionID)
71{
72	KDiskDeviceManager* manager = KDiskDeviceManager::Default();
73	if (KDiskDevice* device = manager->RegisterDevice(partitionID, false)) {
74		device->ReadUnlock();
75		device->Unregister();
76
77		device->Unregister();
78	}
79}
80
81
82int32
83find_disk_device(const char* path)
84{
85	KDiskDeviceManager* manager = KDiskDeviceManager::Default();
86	partition_id id = -1;
87	if (KDiskDevice* device = manager->RegisterDevice(path)) {
88		id = device->ID();
89		device->Unregister();
90	}
91	return id;
92}
93
94
95int32
96find_partition(const char* path)
97{
98	KDiskDeviceManager* manager = KDiskDeviceManager::Default();
99	partition_id id = -1;
100	if (KPartition* partition = manager->RegisterPartition(path)) {
101		id = partition->ID();
102		partition->Unregister();
103	}
104	return id;
105}
106
107
108disk_device_data*
109get_disk_device(partition_id partitionID)
110{
111	KDiskDeviceManager* manager = KDiskDeviceManager::Default();
112	KDiskDevice* device = manager->FindDevice(partitionID, false);
113	return (device ? device->DeviceData() : NULL);
114}
115
116
117partition_data*
118get_partition(partition_id partitionID)
119{
120	KDiskDeviceManager* manager = KDiskDeviceManager::Default();
121	KPartition* partition = manager->FindPartition(partitionID);
122	return (partition ? partition->PartitionData() : NULL);
123}
124
125
126partition_data*
127get_parent_partition(partition_id partitionID)
128{
129	KDiskDeviceManager* manager = KDiskDeviceManager::Default();
130	KPartition* partition = manager->FindPartition(partitionID);
131	if (partition && partition->Parent())
132		return partition->Parent()->PartitionData();
133	return NULL;
134}
135
136
137partition_data*
138get_child_partition(partition_id partitionID, int32 index)
139{
140	KDiskDeviceManager* manager = KDiskDeviceManager::Default();
141	if (KPartition* partition = manager->FindPartition(partitionID)) {
142		if (KPartition* child = partition->ChildAt(index))
143			return child->PartitionData();
144	}
145	return NULL;
146}
147
148
149int
150open_partition(partition_id partitionID, int openMode)
151{
152	KDiskDeviceManager* manager = KDiskDeviceManager::Default();
153	KPartition* partition = manager->FindPartition(partitionID);
154	if (partition == NULL)
155		return B_BAD_VALUE;
156
157	int fd = -1;
158	status_t result = partition->Open(openMode, &fd);
159	if (result != B_OK)
160		return -1;
161
162	return fd;
163}
164
165
166partition_data*
167create_child_partition(partition_id partitionID, int32 index, off_t offset,
168	off_t size, partition_id childID)
169{
170	KDiskDeviceManager* manager = KDiskDeviceManager::Default();
171	if (KPartition* partition = manager->FindPartition(partitionID)) {
172		KPartition* child = NULL;
173		if (partition->CreateChild(childID, index, offset, size, &child)
174				== B_OK) {
175			return child->PartitionData();
176		} else {
177			DBG(OUT("  creating child (%" B_PRId32 ", %" B_PRId32 ") failed\n",
178				partitionID, index));
179		}
180	} else
181		DBG(OUT("  partition %" B_PRId32 " not found\n", partitionID));
182
183	return NULL;
184}
185
186
187bool
188delete_partition(partition_id partitionID)
189{
190	KDiskDeviceManager* manager = KDiskDeviceManager::Default();
191	if (KPartition* partition = manager->FindPartition(partitionID)) {
192		if (KPartition* parent = partition->Parent())
193			return parent->RemoveChild(partition);
194	}
195	return false;
196}
197
198
199void
200partition_modified(partition_id partitionID)
201{
202	// TODO: implemented
203}
204
205
206status_t
207scan_partition(partition_id partitionID)
208{
209	// get the partition
210	KDiskDeviceManager* manager = KDiskDeviceManager::Default();
211	KPartition* partition = manager->RegisterPartition(partitionID);
212	if (partition == NULL)
213		return B_ENTRY_NOT_FOUND;
214	PartitionRegistrar _(partition, true);
215
216	// scan it
217	return manager->ScanPartition(partition);
218}
219
220
221status_t
222get_default_partition_content_name(partition_id partitionID,
223	const char* fileSystemName, char* buffer, size_t bufferSize)
224{
225	KDiskDeviceManager* manager = KDiskDeviceManager::Default();
226	KPartition* partition = manager->RegisterPartition(partitionID);
227	if (partition == NULL)
228		return B_ENTRY_NOT_FOUND;
229
230	double size = partition->ContentSize();
231	partition->Unregister();
232
233	const char* const suffixes[] = {
234		"", "K", "M", "G", "T", "P", "E", NULL
235	};
236
237	int index = 0;
238	while (size >= 1024 && suffixes[index + 1]) {
239		size /= 1024;
240		index++;
241	}
242
243	// Our kernel snprintf() ignores the precision argument, so we manually
244	// do one digit precision.
245	uint64 result = uint64(size * 10 + 0.5);
246
247	snprintf(buffer, bufferSize, "%s Volume (%" B_PRId32 ".%" B_PRId32 " %sB)",
248		fileSystemName, int32(result / 10), int32(result % 10), suffixes[index]);
249
250	return B_OK;
251}
252
253
254disk_system_id
255find_disk_system(const char* name)
256{
257	KDiskDeviceManager* manager = KDiskDeviceManager::Default();
258	if (ManagerLocker locker = manager) {
259		if (KDiskSystem* diskSystem = manager->FindDiskSystem(name))
260			return diskSystem->ID();
261	}
262	return -1;
263}
264
265
266bool
267update_disk_device_job_progress(disk_job_id jobID, float progress)
268{
269#if 0
270	KDiskDeviceManager* manager = KDiskDeviceManager::Default();
271	if (ManagerLocker locker = manager) {
272		if (KDiskDeviceJob* job = manager->FindJob(jobID)) {
273			job->UpdateProgress(progress);
274			return true;
275		}
276	}
277#endif
278	return false;
279}
280
281
282bool
283update_disk_device_job_extra_progress(disk_job_id jobID, const char* info)
284{
285#if 0
286	KDiskDeviceManager* manager = KDiskDeviceManager::Default();
287	if (ManagerLocker locker = manager) {
288		if (KDiskDeviceJob* job = manager->FindJob(jobID)) {
289			job->UpdateExtraProgress(info);
290			return true;
291		}
292	}
293#endif
294	return false;
295}
296
297
298bool
299set_disk_device_job_error_message(disk_job_id jobID, const char* message)
300{
301#if 0
302	KDiskDeviceManager* manager = KDiskDeviceManager::Default();
303	if (ManagerLocker locker = manager) {
304		if (KDiskDeviceJob* job = manager->FindJob(jobID)) {
305			job->SetErrorMessage(message);
306			return true;
307		}
308	}
309#endif
310	return false;
311}
312
313
314uint32
315update_disk_device_job_interrupt_properties(disk_job_id jobID,
316	uint32 interruptProperties)
317{
318#if 0
319	bool paused = false;
320	KDiskDeviceManager* manager = KDiskDeviceManager::Default();
321	do {
322		sem_id pauseSemaphore = -1;
323		if (ManagerLocker locker = manager) {
324			// get the job and the respective job queue
325			if (KDiskDeviceJob* job = manager->FindJob(jobID)) {
326				if (KDiskDeviceJobQueue* jobQueue = job->JobQueue()) {
327					// terminate if canceled.
328					if (jobQueue->IsCanceled()) {
329						if (jobQueue->ShallReverse())
330							return B_DISK_DEVICE_JOB_REVERSE;
331						return B_DISK_DEVICE_JOB_CANCEL;
332					}
333					// set the new interrupt properties only when not
334					// requested to pause
335					if (jobQueue->IsPauseRequested())
336						pauseSemaphore = jobQueue->ReadyToPause();
337					else
338						job->SetInterruptProperties(interruptProperties);
339				}
340			}
341		}
342		// pause, if requested; redo the loop then
343		paused = (pauseSemaphore >= 0);
344		if (paused) {
345			acquire_sem(pauseSemaphore);
346			pauseSemaphore = -1;
347		}
348	} while (paused);
349#endif
350	return B_DISK_DEVICE_JOB_CONTINUE;
351}
352
353