1/*
2 * Copyright 2013, Axel D��rfler, axeld@pinc-software.de.
3 * Copyright 2007, Ingo Weinhold, bonefish@users.sf.net.
4 * Distributed under the terms of the MIT License.
5 */
6
7
8#include "GPTPartitionHandle.h"
9
10#include <new>
11#include <stdio.h>
12
13#include <DiskDeviceTypes.h>
14#include <MutablePartition.h>
15#include <PartitioningInfo.h>
16#include <PartitionParameterEditor.h>
17#include <Path.h>
18#include <SupportDefs.h>
19
20#include <AutoDeleter.h>
21
22#include "guid.h"
23#include "gpt_known_guids.h"
24#include "utility.h"
25
26
27//#define TRACE_GPT_PARTITION_HANDLE
28#undef TRACE
29#ifdef TRACE_GPT_PARTITION_HANDLE
30#	define TRACE(x...) printf(x)
31#else
32#	define TRACE(x...) do {} while (false)
33#endif
34
35
36GPTPartitionHandle::GPTPartitionHandle(BMutablePartition* partition)
37	:
38	BPartitionHandle(partition)
39{
40}
41
42
43GPTPartitionHandle::~GPTPartitionHandle()
44{
45}
46
47
48status_t
49GPTPartitionHandle::Init()
50{
51	// TODO: how to get the path of a BMutablePartition?
52	//BPath path;
53	//status_t status = Partition()->GetPath(&path);
54	//if (status != B_OK)
55		//return status;
56
57	//fd = open(path.Path(), O_RDONLY);
58	//if (fd < 0)
59		//return errno;
60
61	//fHeader = new EFI::Header(fd, Partition()->BlockSize(),
62		//Partition()->BlockSize());
63	//status = fHeader->InitCheck();
64	//if (status != B_OK)
65		//return status;
66
67	//close(fd);
68	return B_OK;
69}
70
71
72uint32
73GPTPartitionHandle::SupportedOperations(uint32 mask)
74{
75	uint32 flags = B_DISK_SYSTEM_SUPPORTS_RESIZING
76		| B_DISK_SYSTEM_SUPPORTS_MOVING
77		| B_DISK_SYSTEM_SUPPORTS_SETTING_CONTENT_PARAMETERS
78		| B_DISK_SYSTEM_SUPPORTS_NAME
79		| B_DISK_SYSTEM_SUPPORTS_SETTING_NAME
80		| B_DISK_SYSTEM_SUPPORTS_INITIALIZING;
81
82	// creating child
83	if ((mask & B_DISK_SYSTEM_SUPPORTS_CREATING_CHILD) != 0) {
84		BPartitioningInfo info;
85		if (GetPartitioningInfo(&info) == B_OK
86			&& info.CountPartitionableSpaces() > 1) {
87			flags |= B_DISK_SYSTEM_SUPPORTS_CREATING_CHILD;
88		}
89	}
90
91	return flags;
92}
93
94
95uint32
96GPTPartitionHandle::SupportedChildOperations(const BMutablePartition* child,
97	uint32 mask)
98{
99	return B_DISK_SYSTEM_SUPPORTS_NAME
100		| B_DISK_SYSTEM_SUPPORTS_SETTING_NAME
101		| B_DISK_SYSTEM_SUPPORTS_RESIZING_CHILD
102		| B_DISK_SYSTEM_SUPPORTS_MOVING_CHILD
103		| B_DISK_SYSTEM_SUPPORTS_SETTING_TYPE
104		| B_DISK_SYSTEM_SUPPORTS_SETTING_PARAMETERS
105		| B_DISK_SYSTEM_SUPPORTS_DELETING_CHILD;
106}
107
108
109status_t
110GPTPartitionHandle::GetNextSupportedType(const BMutablePartition* child,
111	int32* cookie, BString* type)
112{
113	int32 index = *cookie;
114	TRACE("GPTPartitionHandle::GetNextSupportedType(child: %p, cookie: %" B_PRId32 ")\n",
115		child, index);
116
117	if (index >= int32(B_COUNT_OF(kTypeMap)))
118		return B_ENTRY_NOT_FOUND;
119
120	type->SetTo(kTypeMap[index].type);
121	*cookie = index + 1;
122
123	return B_OK;
124}
125
126
127status_t
128GPTPartitionHandle::GetPartitioningInfo(BPartitioningInfo* info)
129{
130	// init to the full size (minus the GPT table header and entries)
131	off_t size = Partition()->ContentSize();
132	// TODO: use fHeader
133	size_t headerSize = Partition()->BlockSize() + 16384;
134	status_t status = info->SetTo(Partition()->BlockSize() + headerSize,
135		size - Partition()->BlockSize() - 2 * headerSize);
136	if (status != B_OK)
137		return status;
138
139	// Exclude the space of the existing partitions
140	size_t count = Partition()->CountChildren();
141	for (size_t index = 0; index < count; index++) {
142		BMutablePartition* child = Partition()->ChildAt(index);
143		status = info->ExcludeOccupiedSpace(child->Offset(), child->Size());
144		if (status != B_OK)
145			return status;
146	}
147
148	return B_OK;
149}
150
151
152status_t
153GPTPartitionHandle::GetParameterEditor(B_PARAMETER_EDITOR_TYPE type,
154	BPartitionParameterEditor** editor)
155{
156	*editor = NULL;
157	if (type == B_CREATE_PARAMETER_EDITOR || type == B_PROPERTIES_PARAMETER_EDITOR) {
158		try {
159			*editor = new BPartitionParameterEditor();
160		} catch (std::bad_alloc&) {
161			return B_NO_MEMORY;
162		}
163		return B_OK;
164	}
165	return B_NOT_SUPPORTED;
166}
167
168
169status_t
170GPTPartitionHandle::ValidateSetName(const BMutablePartition *child, BString* name)
171{
172	// UCS-2 can use up to 2 code points per character, and GPT allows
173	// a maximum of 36 code units;
174	size_t length = name->CountChars();
175	if (length == 0)
176		return B_OK;
177
178	size_t size = length * 2;
179	uint16 buffer[size + 1];
180
181	do {
182		size = to_ucs2(name->String(), length, buffer, length * 2);
183		if (size <= 36)
184			return B_OK;
185		length--;
186		name->TruncateChars(length, false);
187	} while (size > 36 && length > 0);
188
189	return B_OK;
190}
191
192
193status_t
194GPTPartitionHandle::SetName(BMutablePartition* child, const char* name)
195{
196	return child->SetName(name);
197}
198
199
200status_t
201GPTPartitionHandle::ValidateSetType(const BMutablePartition* child,
202	const char* type)
203{
204	for (size_t i = 0; i < B_COUNT_OF(kTypeMap); i++) {
205		if (strcmp(type, kTypeMap[i].type) == 0)
206			return B_OK;
207	}
208	return B_BAD_VALUE;
209}
210
211
212status_t
213GPTPartitionHandle::SetType(BMutablePartition* child, const char* type)
214{
215	return child->SetType(type);
216}
217
218
219status_t
220GPTPartitionHandle::ValidateCreateChild(off_t* _offset, off_t* _size,
221	const char* typeString, BString* name, const char* parameters)
222{
223	return B_OK;
224}
225
226
227status_t
228GPTPartitionHandle::CreateChild(off_t offset, off_t size,
229	const char* typeString, const char* name, const char* parameters,
230	BMutablePartition** _child)
231{
232	// create the child
233	BMutablePartition* partition = Partition();
234	BMutablePartition* child;
235	status_t status = partition->CreateChild(partition->CountChildren(),
236		typeString, name, parameters, &child);
237	if (status != B_OK)
238		return status;
239
240	// init the child
241	child->SetOffset(offset);
242	child->SetSize(size);
243	child->SetBlockSize(partition->BlockSize());
244
245	*_child = child;
246	return B_OK;
247}
248
249
250status_t
251GPTPartitionHandle::DeleteChild(BMutablePartition* child)
252{
253	BMutablePartition* parent = child->Parent();
254	return parent->DeleteChild(child);
255}
256