xref: /haiku/src/add-ons/disk_systems/gpt/GPTPartitionHandle.cpp (revision 4a55cc230cf7566cadcbb23b1928eefff8aea9a2)
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 
36 GPTPartitionHandle::GPTPartitionHandle(BMutablePartition* partition)
37 	:
38 	BPartitionHandle(partition)
39 {
40 }
41 
42 
43 GPTPartitionHandle::~GPTPartitionHandle()
44 {
45 }
46 
47 
48 status_t
49 GPTPartitionHandle::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 
72 uint32
73 GPTPartitionHandle::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 
95 uint32
96 GPTPartitionHandle::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 
109 status_t
110 GPTPartitionHandle::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 
127 status_t
128 GPTPartitionHandle::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 
152 status_t
153 GPTPartitionHandle::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 
169 status_t
170 GPTPartitionHandle::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 
193 status_t
194 GPTPartitionHandle::SetName(BMutablePartition* child, const char* name)
195 {
196 	return child->SetName(name);
197 }
198 
199 
200 status_t
201 GPTPartitionHandle::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 
212 status_t
213 GPTPartitionHandle::SetType(BMutablePartition* child, const char* type)
214 {
215 	return child->SetType(type);
216 }
217 
218 
219 status_t
220 GPTPartitionHandle::ValidateCreateChild(off_t* _offset, off_t* _size,
221 	const char* typeString, BString* name, const char* parameters)
222 {
223 	return B_OK;
224 }
225 
226 
227 status_t
228 GPTPartitionHandle::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 
250 status_t
251 GPTPartitionHandle::DeleteChild(BMutablePartition* child)
252 {
253 	BMutablePartition* parent = child->Parent();
254 	return parent->DeleteChild(child);
255 }
256