xref: /haiku/src/add-ons/kernel/partitioning_systems/intel/intel.cpp (revision af8bd8f6b4889110b95b88999375e68c7f3eacff)
1 /*
2  * Copyright 2003-2007, Haiku, Inc. All Rights Reserved.
3  * Distributed under the terms of the MIT License.
4  *
5  * Authors:
6  *		Ingo Weinhold, bonefish@cs.tu-berlin.de
7  *		Tomas Kucera, kucerat@centrum.cz
8  */
9 
10 /*!
11 	\file intel.cpp
12 	\brief disk_scanner partition module for "intel" style partitions.
13 */
14 
15 // TODO: The implementation is very strict right now. It rejects a partition
16 // completely, if it finds an error in its partition tables. We should see,
17 // what error can be handled gracefully, e.g. by ignoring the partition
18 // descriptor or the whole partition table sector.
19 
20 #include <errno.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 
25 #include <util/kernel_cpp.h>
26 #include <AutoDeleter.h>
27 #include <ddm_modules.h>
28 #ifndef _BOOT_MODE
29 #	include <DiskDeviceTypes.h>
30 #else
31 #	include <boot/partitions.h>
32 //#	include "DiskDeviceUtils.h"
33 #endif
34 #include <KernelExport.h>
35 
36 #include "PartitionLocker.h"
37 #include "PartitionMap.h"
38 #include "PartitionMapParser.h"
39 #include "PartitionMapWriter.h"
40 
41 //#define TRACE(x) ;
42 #define TRACE(x) dprintf x
43 
44 // module names
45 #define INTEL_PARTITION_MODULE_NAME "partitioning_systems/intel/map/v1"
46 #define INTEL_EXTENDED_PARTITION_MODULE_NAME "partitioning_systems/intel/extended/v1"
47 
48 // no atomic_add() in the boot loader
49 #ifdef _BOOT_MODE
50 
51 inline int32
52 atomic_add(int32 *a, int32 num)
53 {
54 	int32 oldA = *a;
55 	*a += num;
56 	return oldA;
57 }
58 
59 #endif
60 
61 
62 // A PartitionMap with reference count.
63 struct PartitionMapCookie : PartitionMap {
64 	int32	ref_count;
65 };
66 
67 
68 #ifndef _BOOT_MODE
69 
70 // Maximal size of move buffer (in sectors).
71 static const int32 MAX_MOVE_BUFFER = 2 * 1024 * 4;
72 
73 // for logical partitions in Intel Extended Partition
74 // Count of free sectors after Partition Table Sector (at logical partition).
75 static const uint32 FREE_SECTORS_AFTER_PTS = 0;
76 // Count of free sectors after Master Boot Record.
77 static const uint32 FREE_SECTORS_AFTER_MBR = 0;
78 // size of logical partition header in blocks
79 static const uint32 PTS_OFFSET = FREE_SECTORS_AFTER_PTS + 1;
80 static const uint32 MBR_OFFSET = FREE_SECTORS_AFTER_MBR + 1;
81 
82 
83 typedef partitionable_space_data PartitionPosition;
84 
85 typedef void (*fc_get_sibling_partitions)(partition_data *partition,
86 		partition_data *child, off_t childOffset, partition_data **prec,
87 		partition_data **follow, off_t *prec_offset, off_t *prec_size,
88 		off_t *follow_offset, off_t *follow_size);
89 
90 typedef int32 (*fc_fill_partitionable_spaces_buffer)(partition_data *partition,
91 		PartitionPosition *positions);
92 
93 
94 #endif	//!_BOOT_MODE
95 
96 
97 // #pragma mark - Intel Partition Map Module
98 
99 
100 // module
101 static status_t pm_std_ops(int32 op, ...);
102 
103 // scanning
104 static float pm_identify_partition(int fd, partition_data *partition,
105 								   void **cookie);
106 static status_t pm_scan_partition(int fd, partition_data *partition,
107 								  void *cookie);
108 static void pm_free_identify_partition_cookie(partition_data *partition,
109 											  void *cookie);
110 static void pm_free_partition_cookie(partition_data *partition);
111 static void pm_free_partition_content_cookie(partition_data *partition);
112 
113 #ifndef _BOOT_MODE
114 // querying
115 static bool pm_supports_resizing(partition_data *partition);
116 static bool pm_supports_resizing_child(partition_data *partition,
117 									   partition_data *child);
118 static bool pm_supports_moving(partition_data *partition, bool *isNoOp);
119 static bool pm_supports_moving_child(partition_data *partition,
120 									 partition_data *child);
121 static bool pm_supports_setting_name(partition_data *partition);
122 static bool pm_supports_setting_content_name(partition_data *partition);
123 static bool pm_supports_setting_type(partition_data *partition);
124 static bool pm_supports_initializing(partition_data *partition);
125 static bool pm_supports_creating_child(partition_data *partition);
126 static bool pm_supports_deleting_child(partition_data *partition,
127 									   partition_data *child);
128 static bool pm_is_sub_system_for(partition_data *partition);
129 
130 static bool pm_validate_resize(partition_data *partition, off_t *size);
131 static bool pm_validate_resize_child(partition_data *partition,
132 									 partition_data *child, off_t *size);
133 static bool pm_validate_move(partition_data *partition, off_t *start);
134 static bool pm_validate_move_child(partition_data *partition,
135 								   partition_data *child, off_t *start);
136 static bool pm_validate_set_type(partition_data *partition, const char *type);
137 static bool pm_validate_initialize(partition_data *partition,
138 								   char *name, const char *parameters);
139 static bool pm_validate_create_child(partition_data *partition,
140 									 off_t *start, off_t *size,
141 									 const char *type, const char *parameters,
142 									 int32 *index);
143 static status_t pm_get_partitionable_spaces(partition_data *partition,
144 											partitionable_space_data *buffer,
145 											int32 count, int32 *actualCount);
146 static status_t pm_get_next_supported_type(partition_data *partition,
147 										   int32 *cookie, char *type);
148 static status_t get_type_for_content_type(const char *contentType,
149 										  char *type);
150 
151 // shadow partition modification
152 static status_t pm_shadow_changed(partition_data *partition, uint32 operation);
153 
154 // writing
155 static status_t pm_resize(int fd, partition_id partition, off_t size,
156 						  disk_job_id job);
157 static status_t pm_resize_child(int fd, partition_id partition, off_t size,
158 								disk_job_id job);
159 static status_t pm_move(int fd, partition_id partition, off_t offset,
160 						disk_job_id job);
161 static status_t pm_move_child(int fd, partition_id partition, partition_id child,
162 							  off_t offset, disk_job_id job);
163 static status_t pm_set_type(int fd, partition_id partition, const char *type,
164 							disk_job_id job);
165 static status_t pm_initialize(int fd, partition_id partition, const char *name,
166 							  const char *parameters, disk_job_id job);
167 static status_t pm_create_child(int fd, partition_id partition, off_t offset,
168 								off_t size, const char *type,
169 								const char *parameters, disk_job_id job,
170 								partition_id *childID);
171 static status_t pm_delete_child(int fd, partition_id partition,
172 								partition_id child, disk_job_id job);
173 
174 #endif
175 
176 #ifdef _BOOT_MODE
177 partition_module_info gIntelPartitionMapModule =
178 #else
179 static partition_module_info intel_partition_map_module =
180 #endif
181 {
182 	{
183 		INTEL_PARTITION_MODULE_NAME,
184 		0,
185 		pm_std_ops
186 	},
187 	INTEL_PARTITION_NAME,				// pretty_name
188 	0,									// flags
189 
190 	// scanning
191 	pm_identify_partition,				// identify_partition
192 	pm_scan_partition,					// scan_partition
193 	pm_free_identify_partition_cookie,	// free_identify_partition_cookie
194 	pm_free_partition_cookie,			// free_partition_cookie
195 	pm_free_partition_content_cookie,	// free_partition_content_cookie
196 
197 #ifndef _BOOT_MODE
198 	// querying
199 	NULL,								// supports_repairing
200 	pm_supports_resizing,				// supports_resizing
201 	pm_supports_resizing_child,			// supports_resizing_child
202 	pm_supports_moving,					// supports_moving
203 	pm_supports_moving_child,			// supports_moving_child
204 	pm_supports_setting_name,			// supports_setting_name
205 	pm_supports_setting_content_name,	// supports_setting_content_name
206 	pm_supports_setting_type,			// supports_setting_type
207 	NULL,								// supports_setting_parameters
208 	NULL,								// supports_setting_content_parameters
209 	pm_supports_initializing,			// supports_initializing
210 	NULL,								// supports_initializing_child
211 	pm_supports_creating_child,			// supports_creating_child
212 	pm_supports_deleting_child,			// supports_deleting_child
213 	pm_is_sub_system_for,				// is_sub_system_for
214 
215 	pm_validate_resize,					// validate_resize
216 	pm_validate_resize_child,			// validate_resize_child
217 	pm_validate_move,					// validate_move
218 	pm_validate_move_child,				// validate_move_child
219 	NULL,								// validate_set_name
220 	NULL,								// validate_set_content_name
221 	pm_validate_set_type,				// validate_set_type
222 	NULL,								// validate_set_parameters
223 	NULL,								// validate_set_content_parameters
224 	pm_validate_initialize,				// validate_initialize
225 	pm_validate_create_child,			// validate_create_child
226 	pm_get_partitionable_spaces,		// get_partitionable_spaces
227 	pm_get_next_supported_type,			// get_next_supported_type
228 	get_type_for_content_type,			// get_type_for_content_type
229 
230 	// shadow partition modification
231 	pm_shadow_changed,					// shadow_changed
232 
233 	// writing
234 	NULL,								// repair
235 	pm_resize,							// resize
236 	pm_resize_child,					// resize_child
237 	pm_move,							// move
238 	pm_move_child,						// move_child
239 	NULL,								// set_name
240 	NULL,								// set_content_name
241 	pm_set_type,						// set_type
242 	NULL,								// set_parameters
243 	NULL,								// set_content_parameters
244 	pm_initialize,						// initialize
245 	pm_create_child,					// create_child
246 	pm_delete_child,					// delete_child
247 #else
248 	NULL
249 #endif	// _BOOT_MODE
250 };
251 
252 
253 // #pragma mark - Intel Extended Partition Module
254 
255 
256 // module
257 static status_t ep_std_ops(int32 op, ...);
258 
259 // scanning
260 static float ep_identify_partition(int fd, partition_data *partition,
261 		void **cookie);
262 static status_t ep_scan_partition(int fd, partition_data *partition,
263 		void *cookie);
264 static void ep_free_identify_partition_cookie(partition_data *partition,
265 		void *cookie);
266 static void ep_free_partition_cookie(partition_data *partition);
267 static void ep_free_partition_content_cookie(partition_data *partition);
268 
269 #ifndef _BOOT_MODE
270 // querying
271 static bool ep_supports_resizing(partition_data *partition);
272 static bool ep_supports_resizing_child(partition_data *partition,
273 									   partition_data *child);
274 static bool ep_supports_moving(partition_data *partition, bool *isNoOp);
275 static bool ep_supports_moving_child(partition_data *partition,
276 									 partition_data *child);
277 static bool ep_supports_setting_name(partition_data *partition);
278 static bool ep_supports_setting_content_name(partition_data *partition);
279 static bool ep_supports_setting_type(partition_data *partition);
280 static bool ep_supports_initializing(partition_data *partition);
281 static bool ep_supports_creating_child(partition_data *partition);
282 static bool ep_supports_deleting_child(partition_data *partition,
283 									   partition_data *child);
284 static bool ep_is_sub_system_for(partition_data *partition);
285 
286 static bool ep_validate_resize(partition_data *partition, off_t *size);
287 static bool ep_validate_resize_child(partition_data *partition,
288 									 partition_data *child, off_t *size);
289 static bool ep_validate_move(partition_data *partition, off_t *start);
290 static bool ep_validate_move_child(partition_data *partition,
291 								   partition_data *child, off_t *start);
292 static bool ep_validate_set_type(partition_data *partition, const char *type);
293 static bool ep_validate_initialize(partition_data *partition,
294 								   char *name, const char *parameters);
295 static bool ep_validate_create_child(partition_data *partition,
296 									 off_t *start, off_t *size,
297 									 const char *type, const char *parameters,
298 									 int32 *index);
299 static status_t ep_get_partitionable_spaces(partition_data *partition,
300 											partitionable_space_data *buffer,
301 											int32 count, int32 *actualCount);
302 static status_t ep_get_next_supported_type(partition_data *partition,
303 										   int32 *cookie, char *type);
304 
305 // shadow partition modification
306 static status_t ep_shadow_changed(partition_data *partition, uint32 operation);
307 
308 // writing
309 static status_t ep_resize(int fd, partition_id partition, off_t size,
310 						  disk_job_id job);
311 static status_t ep_resize_child(int fd, partition_id partition, off_t size,
312 								disk_job_id job);
313 static status_t ep_move(int fd, partition_id partition, off_t offset,
314 						disk_job_id job);
315 static status_t ep_move_child(int fd, partition_id partition, partition_id child,
316 							  off_t offset, disk_job_id job);
317 static status_t ep_set_type(int fd, partition_id partition, const char *type,
318 							disk_job_id job);
319 static status_t ep_initialize(int fd, partition_id partition, const char *name,
320 							  const char *parameters, disk_job_id job);
321 static status_t ep_create_child(int fd, partition_id partition, off_t offset,
322 								off_t size, const char *type,
323 								const char *parameters, disk_job_id job,
324 								partition_id *childID);
325 static status_t ep_delete_child(int fd, partition_id partition,
326 								partition_id child, disk_job_id job);
327 
328 #endif
329 
330 
331 #ifdef _BOOT_MODE
332 partition_module_info gIntelExtendedPartitionModule =
333 #else
334 static partition_module_info intel_extended_partition_module =
335 #endif
336 {
337 	{
338 		INTEL_EXTENDED_PARTITION_MODULE_NAME,
339 		0,
340 		ep_std_ops
341 	},
342 	INTEL_EXTENDED_PARTITION_NAME,		// pretty_name
343 	0,									// flags
344 
345 	// scanning
346 	ep_identify_partition,				// identify_partition
347 	ep_scan_partition,					// scan_partition
348 	ep_free_identify_partition_cookie,	// free_identify_partition_cookie
349 	ep_free_partition_cookie,			// free_partition_cookie
350 	ep_free_partition_content_cookie,	// free_partition_content_cookie
351 
352 #ifndef _BOOT_MODE
353 	// querying
354 	NULL,								// supports_repairing
355 	ep_supports_resizing,				// supports_resizing
356 	ep_supports_resizing_child,			// supports_resizing_child
357 	ep_supports_moving,					// supports_moving
358 	ep_supports_moving_child,			// supports_moving_child
359 	ep_supports_setting_name,			// supports_setting_name
360 	ep_supports_setting_content_name,	// supports_setting_content_name
361 	ep_supports_setting_type,			// supports_setting_type
362 	NULL,								// supports_setting_parameters
363 	NULL,								// supports_setting_content_parameters
364 	ep_supports_initializing,			// supports_initializing
365 	NULL,								// supports_initializing_child
366 	ep_supports_creating_child,			// supports_creating_child
367 	ep_supports_deleting_child,			// supports_deleting_child
368 	ep_is_sub_system_for,				// is_sub_system_for
369 
370 	ep_validate_resize,					// validate_resize
371 	ep_validate_resize_child,			// validate_resize_child
372 	ep_validate_move,					// validate_move
373 	ep_validate_move_child,				// validate_move_child
374 	NULL,								// validate_set_name
375 	NULL,								// validate_set_content_name
376 	ep_validate_set_type,				// validate_set_type
377 	NULL,								// validate_set_parameters
378 	NULL,								// validate_set_content_parameters
379 	ep_validate_initialize,				// validate_initialize
380 	ep_validate_create_child,			// validate_create_child
381 	ep_get_partitionable_spaces,		// get_partitionable_spaces
382 	ep_get_next_supported_type,			// get_next_supported_type
383 	get_type_for_content_type,			// get_type_for_content_type
384 
385 	// shadow partition modification
386 	ep_shadow_changed,					// shadow_changed
387 
388 	// writing
389 	NULL,								// repair
390 	ep_resize,							// resize
391 	ep_resize_child,					// resize_child
392 	ep_move,							// move
393 	ep_move_child,						// move_child
394 	NULL,								// set_name
395 	NULL,								// set_content_name
396 	ep_set_type,						// set_type
397 	NULL,								// set_parameters
398 	NULL,								// set_content_parameters
399 	ep_initialize,						// initialize
400 	ep_create_child,					// create_child
401 	ep_delete_child,					// delete_child
402 #else	// _BOOT_MODE
403 	NULL
404 #endif	// _BOOT_MODE
405 };
406 
407 
408 #ifndef _BOOT_MODE
409 extern "C" partition_module_info *modules[];
410 _EXPORT partition_module_info *modules[] =
411 {
412 	&intel_partition_map_module,
413 	&intel_extended_partition_module,
414 	NULL
415 };
416 #endif
417 
418 
419 // #pragma mark - Intel Partition Map Module
420 
421 
422 // pm_std_ops
423 static status_t
424 pm_std_ops(int32 op, ...)
425 {
426 	TRACE(("intel: pm_std_ops(0x%lx)\n", op));
427 	switch(op) {
428 		case B_MODULE_INIT:
429 		case B_MODULE_UNINIT:
430 			return B_OK;
431 	}
432 	return B_ERROR;
433 }
434 
435 
436 // pm_identify_partition
437 static float
438 pm_identify_partition(int fd, partition_data *partition, void **cookie)
439 {
440 	// check parameters
441 	if (fd < 0 || !partition || !cookie)
442 		return -1;
443 
444 	TRACE(("intel: pm_identify_partition(%d, %ld: %lld, %lld, %ld)\n", fd,
445 		   partition->id, partition->offset, partition->size,
446 		   partition->block_size));
447 	// reject extended partitions
448 	if (partition->type
449 		&& !strcmp(partition->type, kPartitionTypeIntelExtended)) {
450 		return -1;
451 	}
452 
453 	// check block size
454 	uint32 blockSize = partition->block_size;
455 	if (blockSize < sizeof(partition_table_sector)) {
456 		TRACE(("intel: read_partition_map: bad block size: %ld, should be "
457 			">= %ld\n", blockSize, sizeof(partition_table_sector)));
458 		return -1;
459 	}
460 
461 	// allocate a PartitionMap
462 	PartitionMapCookie *map = new(nothrow) PartitionMapCookie;
463 	if (!map)
464 		return -1;
465 	map->ref_count = 1;
466 
467 	// read the partition structure
468 	PartitionMapParser parser(fd, 0, partition->size, blockSize);
469 	status_t error = parser.Parse(NULL, map);
470 	if (error == B_OK) {
471 		*cookie = map;
472 		return 0.5;
473 	}
474 
475 	// cleanup, if not detected
476 	delete map;
477 	return -1;
478 }
479 
480 // pm_scan_partition
481 static status_t
482 pm_scan_partition(int fd, partition_data *partition, void *cookie)
483 {
484 	// check parameters
485 	if (fd < 0 || !partition || !cookie)
486 		return B_ERROR;
487 
488 	TRACE(("intel: pm_scan_partition(%d, %ld: %lld, %lld, %ld)\n", fd,
489 		   partition->id, partition->offset, partition->size,
490 		   partition->block_size));
491 
492 	PartitionMapCookie *map = (PartitionMapCookie*)cookie;
493 	// fill in the partition_data structure
494 	partition->status = B_PARTITION_VALID;
495 	partition->flags |= B_PARTITION_PARTITIONING_SYSTEM;
496 	partition->content_size = partition->size;
497 	// (no content_name and content_parameters)
498 	// (content_type is set by the system)
499 
500 	partition->content_cookie = map;
501 	// children
502 	status_t error = B_OK;
503 	int32 index = 0;
504 	for (int32 i = 0; i < 4; i++) {
505 		PrimaryPartition *primary = map->PrimaryPartitionAt(i);
506 		if (!primary->IsEmpty()) {
507 			partition_data *child = create_child_partition(partition->id,
508 														   index, -1);
509 			index++;
510 			if (!child) {
511 				// something went wrong
512 				error = B_ERROR;
513 				break;
514 			}
515 
516 			child->offset = partition->offset + primary->Offset();
517 			child->size = primary->Size();
518 			child->block_size = partition->block_size;
519 			// (no name)
520 			char type[B_FILE_NAME_LENGTH];
521 			primary->GetTypeString(type);
522 			child->type = strdup(type);
523 			// parameters
524 			char buffer[128];
525 			sprintf(buffer, "type = %u ; active = %d", primary->Type(),
526 					primary->Active());
527 			child->parameters = strdup(buffer);
528 			child->cookie = primary;
529 			// check for allocation problems
530 			if (!child->type || !child->parameters) {
531 				error = B_NO_MEMORY;
532 				break;
533 			}
534 		}
535 	}
536 
537 	// keep map on success or cleanup on error
538 	if (error == B_OK) {
539 		atomic_add(&map->ref_count, 1);
540 	} else {
541 		partition->content_cookie = NULL;
542 		for (int32 i = 0; i < partition->child_count; i++) {
543 			if (partition_data *child = get_child_partition(partition->id, i))
544 				child->cookie = NULL;
545 		}
546 	}
547 
548 	return error;
549 }
550 
551 // pm_free_identify_partition_cookie
552 static void
553 pm_free_identify_partition_cookie(partition_data */*partition*/, void *cookie)
554 {
555 	if (cookie) {
556 		PartitionMapCookie *map = (PartitionMapCookie*)cookie;
557 		if (atomic_add(&map->ref_count, -1) == 1)
558 			delete map;
559 	}
560 }
561 
562 // pm_free_partition_cookie
563 static void
564 pm_free_partition_cookie(partition_data *partition)
565 {
566 	// called for the primary partitions: the PrimaryPartition is allocated
567 	// by the partition containing the partition map
568 	if (partition)
569 		partition->cookie = NULL;
570 }
571 
572 // pm_free_partition_content_cookie
573 static void
574 pm_free_partition_content_cookie(partition_data *partition)
575 {
576 	if (partition && partition->content_cookie) {
577 		pm_free_identify_partition_cookie(partition, partition->content_cookie);
578 		partition->content_cookie = NULL;
579 	}
580 }
581 
582 #ifndef _BOOT_MODE
583 
584 
585 // #pragma mark - Intel Partition Map - support functions
586 
587 
588 // pm_supports_resizing
589 static bool
590 pm_supports_resizing(partition_data *partition)
591 {
592 	TRACE(("intel: pm_supports_resizing(%ld: %lld, %lld, %ld, %s)\n",
593 		partition->id, partition->offset, partition->size,
594 		partition->block_size, partition->content_type));
595 
596 	return (partition && partition->content_type
597 		&& !strcmp(partition->content_type, kPartitionTypeIntel));
598 }
599 
600 // pm_supports_resizing_child
601 static bool
602 pm_supports_resizing_child(partition_data *partition, partition_data *child)
603 {
604 	TRACE(("intel: pm_supports_resizing_child(%ld: %lld, %lld, %ld, %s)\n",
605 		partition->id, partition->offset, partition->size,
606 		partition->block_size, partition->content_type));
607 
608 	return (partition && child && partition->content_type
609 			&& !strcmp(partition->content_type, kPartitionTypeIntel));
610 }
611 
612 // pm_supports_moving
613 static bool
614 pm_supports_moving(partition_data *partition, bool *isNoOp)
615 {
616 	TRACE(("intel: pm_supports_moving(%ld: %lld, %lld, %ld, %s)\n",
617 		partition->id, partition->offset, partition->size,
618 		partition->block_size, partition->content_type));
619 
620 	*isNoOp = true;
621 	return (partition && partition->content_type
622 		&& !strcmp(partition->content_type, kPartitionTypeIntel));
623 }
624 
625 // pm_supports_moving_child
626 static bool
627 pm_supports_moving_child(partition_data *partition, partition_data *child)
628 {
629 	TRACE(("intel: pm_supports_moving_child(%ld: %lld, %lld, %ld, %s)\n",
630 		partition->id, partition->offset, partition->size,
631 		partition->block_size, partition->content_type));
632 
633 	return (partition && child && partition->content_type
634 		&& !strcmp(partition->content_type, kPartitionTypeIntel));
635 }
636 
637 // pm_supports_setting_name
638 static bool
639 pm_supports_setting_name(partition_data *partition)
640 {
641 	return false;
642 }
643 
644 // pm_supports_setting_content_name
645 static bool
646 pm_supports_setting_content_name(partition_data *partition)
647 {
648 	return false;
649 }
650 
651 // pm_supports_setting_type
652 static bool
653 pm_supports_setting_type(partition_data *partition)
654 {
655 	TRACE(("intel: pm_supports_setting_type(%ld: %lld, %lld, %ld)\n",
656 		partition->id, partition->offset, partition->size,
657 		partition->block_size));
658 
659 	// partition should be child of "Intel Partition Map"
660 	partition_data *parent;
661 	return (partition
662 		&& (parent = get_parent_partition(partition->id))
663 		&& parent->content_type
664 		&& !strcmp(parent->content_type, kPartitionTypeIntel));
665 }
666 
667 // pm_supports_initializing
668 static bool
669 pm_supports_initializing(partition_data *partition)
670 {
671 	TRACE(("intel: pm_supports_initializing(%ld: %lld, %lld, %ld, %s, %d, %d)\n",
672 		partition->id, partition->offset, partition->size,
673 		partition->block_size, partition->content_type,
674 		partition->child_count == 0,
675 		partition->content_cookie == NULL));
676 
677 	return (partition
678 		&& !partition->content_type
679 		&& partition->child_count == 0
680 		&& partition->content_cookie == NULL);
681 }
682 
683 // pm_supports_creating_child
684 static bool
685 pm_supports_creating_child(partition_data *partition)
686 {
687 	TRACE(("intel: pm_supports_creating_child(%ld: %lld, %lld, %ld, %s, %ld)\n",
688 		partition->id, partition->offset, partition->size,
689 		partition->block_size, partition->content_type,
690 		partition->child_count));
691 
692 	int32 count_spaces = 0;
693 	return (partition && partition->content_type
694 		&& !strcmp(partition->content_type, kPartitionTypeIntel)
695 		&& partition->child_count < 4
696 		// free space check
697 		&& pm_get_partitionable_spaces(partition, NULL, 0, &count_spaces)
698 			== B_OK
699 		&& count_spaces);
700 }
701 
702 // pm_supports_deleting_child
703 static bool
704 pm_supports_deleting_child(partition_data *partition, partition_data *child)
705 {
706 	TRACE(("intel: pm_supports_deleting_child(%ld: %lld, %lld, %ld, %s)\n",
707 		partition->id, partition->offset, partition->size,
708 		partition->block_size, partition->content_type));
709 
710 	return (partition && child && partition->content_type
711 		&& !strcmp(partition->content_type, kPartitionTypeIntel));
712 }
713 
714 // pm_is_sub_system_for
715 static bool
716 pm_is_sub_system_for(partition_data *partition)
717 {
718 	// primary partition map doesn't naturally live in any other child partition
719 	return false;
720 }
721 
722 
723 // #pragma mark - Intel Partition Map - validate functions
724 
725 
726 // block_align (auxiliary function)
727 static inline
728 off_t
729 block_align(off_t offset, uint32 block_size)
730 {
731 	return offset / block_size * block_size;
732 }
733 
734 // block_align_up (auxiliary function)
735 static inline
736 off_t
737 block_align_up(off_t offset, uint32 block_size)
738 {
739 	return (offset + block_size - 1) / block_size * block_size;
740 }
741 
742 // validate_resize (auxiliary function)
743 static bool
744 validate_resize(partition_data *partition, off_t *size)
745 {
746 	off_t new_size = *size;
747 	// size remains the same?
748 	if (new_size == partition->size)
749 		return true;
750 
751 	if (new_size < 0)
752 		new_size = 0;
753 	else
754 		new_size = block_align(new_size, partition->block_size);
755 
756 	// grow partition?
757 	if (new_size > partition->size) {
758 		*size = new_size;
759 		return true;
760 	}
761 
762 	// shrink partition
763 	// no child has to be over the new size of the parent partition
764 	// TODO: shouldn't be just: off_t current_end = new_size; ??? probably not
765 	off_t current_end = partition->offset + new_size;
766 	for (int32 i = 0; i < partition->child_count; i++) {
767 		partition_data *child = get_child_partition(partition->id, i);
768 		if (child && child->offset + child->size > current_end)
769 			current_end = child->offset + child->size;
770 	}
771 	new_size = current_end - partition->offset;
772 	// make the size a multiple of the block size (greater one)
773 	new_size = block_align_up(new_size, partition->block_size);
774 	*size = new_size;
775 	return true;
776 }
777 
778 // pm_validate_resize
779 static bool
780 pm_validate_resize(partition_data *partition, off_t *size)
781 {
782 	TRACE(("intel: pm_validate_resize\n"));
783 
784 	if (!partition || !pm_supports_resizing(partition) || !size)
785 		return false;
786 
787 	return validate_resize(partition, size);
788 }
789 
790 // get_offset_ep (auxiliary function)
791 static inline off_t
792 get_offset_ep(const partition_data *partition)
793 {
794 	LogicalPartition *logical = (LogicalPartition *)partition->cookie;
795 	off_t diff_offset = logical->Offset() - logical->PTSOffset();
796 	return partition->offset - diff_offset;
797 }
798 
799 // get_size_ep (auxiliary function)
800 static inline off_t
801 get_size_ep(const partition_data *partition)
802 {
803 	LogicalPartition *logical = (LogicalPartition *)partition->cookie;
804 	off_t diff_offset = logical->Offset() - logical->PTSOffset();
805 	return partition->size + diff_offset;
806 }
807 
808 
809 // get_sibling_partitions_pm (auxiliary function)
810 /*!
811 	according to childOffset returns previous and next sibling or NULL
812 	precious, next output parameters
813 	partition - Intel Partition Map
814 */
815 static void
816 get_sibling_partitions_pm(partition_data *partition,
817 	partition_data *child, off_t childOffset, partition_data **previous,
818 	partition_data **next, off_t *previousOffset, off_t *previousSize,
819 	off_t *nextOffset, off_t *nextSize)
820 {
821 	// finding out sibling partitions
822 	partition_data *previousSibling = NULL;
823 	partition_data *nextSibling = NULL;
824 	for (int32 i = 0; i < partition->child_count; i++) {
825 		partition_data *sibling = get_child_partition(partition->id, i);
826 		if (sibling && sibling != child)
827 			if (sibling->offset <= childOffset) {
828 				if (!previousSibling || previousSibling->offset < sibling->offset)
829 					previousSibling = sibling;
830 			} else {
831 				// sibling->offset > childOffset
832 				if (!nextSibling || nextSibling->offset > sibling->offset)
833 					nextSibling = sibling;
834 			}
835 	}
836 	*previous = previousSibling;
837 	*next = nextSibling;
838 	if (previousSibling) {
839 		*previousOffset = previousSibling->offset;
840 		*previousSize = previousSibling->size;
841 	}
842 	if (nextSibling) {
843 		*nextOffset = nextSibling->offset;
844 		*nextSize = nextSibling->size;
845 	}
846 }
847 
848 // get_sibling_partitions_ep (auxiliary function)
849 /*!
850 	according to childOffset returns previous and next sibling or NULL
851 	previous, next output parameters
852 	partition - Intel Extended Partition
853 */
854 static void
855 get_sibling_partitions_ep(partition_data *partition,
856 	partition_data *child, off_t childOffset, partition_data **previous,
857 	partition_data **next, off_t *previousOffset, off_t *previousSize,
858 	off_t *nextOffset, off_t *nextSize)
859 {
860 	// finding out sibling partitions
861 	partition_data *previousSibling = NULL;
862 	partition_data *nextSibling = NULL;
863 	for (int32 i = 0; i < partition->child_count; i++) {
864 		partition_data *sibling = get_child_partition(partition->id, i);
865 		if (sibling && sibling != child)
866 			if (get_offset_ep(sibling) <= childOffset) {
867 				if (!previousSibling || previousSibling->offset < sibling->offset)
868 					previousSibling = sibling;
869 			} else {
870 				// get_offset_ep(sibling) > childOffset
871 				if (!nextSibling || nextSibling->offset > sibling->offset)
872 					nextSibling = sibling;
873 			}
874 	}
875 	*previous = previousSibling;
876 	*next = nextSibling;
877 	if (previousSibling) {
878 		*previousOffset = get_offset_ep(previousSibling);
879 		*previousSize = get_size_ep(previousSibling);
880 	}
881 	if (nextSibling) {
882 		*nextOffset = get_offset_ep(nextSibling);
883 		*nextSize = get_size_ep(nextSibling);
884 	}
885 }
886 
887 // validate_resize_child (auxiliary function)
888 static bool
889 validate_resize_child(partition_data *partition, partition_data *child,
890 	off_t childOffset, off_t childSize, off_t *size,
891 	fc_get_sibling_partitions getSiblingPartitions)
892 {
893 	// size remains the same?
894 	if (*size == childSize)
895 		return true;
896 	// shrink partition?
897 	if (*size < childSize) {
898 		if (*size < 0)
899 			*size = 0;
900 		// make the size a multiple of the block size
901 		*size = block_align(*size, partition->block_size);
902 		return true;
903 	}
904 	// grow partition
905 	// child must completely lie within the parent partition
906 	if (childOffset + *size > partition->offset + partition->size)
907 		*size = partition->offset + partition->size - childOffset;
908 
909 	// child must not intersect with sibling partitions
910 	// finding out sibling partitions
911 	partition_data *previousSibling = NULL;
912 	partition_data *nextSibling = NULL;
913 	off_t previousOffset = 0, previousSize = 0, nextOffset = 0, nextSize = 0;
914 
915 	getSiblingPartitions(partition, child, childOffset, &previousSibling,
916 		&nextSibling, &previousOffset, &previousSize, &nextOffset, &nextSize);
917 
918 	if (nextSibling && (nextOffset < childOffset + *size))
919 		*size = nextOffset - childOffset;
920 	*size = block_align(*size, partition->block_size);
921 	return true;
922 }
923 
924 // pm_validate_resize_child
925 static bool
926 pm_validate_resize_child(partition_data *partition, partition_data *child,
927 	off_t *size)
928 {
929 	TRACE(("intel: pm_validate_resize_child\n"));
930 
931 	if (!partition || !child || !size
932 		|| !pm_supports_resizing_child(partition, child)) {
933 		return false;
934 	}
935 
936 	return validate_resize_child(partition, child, child->offset,
937 		child->size, size, get_sibling_partitions_pm);
938 }
939 
940 // pm_validate_move
941 static bool
942 pm_validate_move(partition_data *partition, off_t *start)
943 {
944 	TRACE(("intel: pm_validate_move\n"));
945 
946 	bool isNoOp;
947 	if (!partition || !start || !pm_supports_moving(partition, &isNoOp))
948 		return false;
949 	// nothing to do here
950 	return true;
951 }
952 
953 // validate_move_child (auxiliary function)
954 static bool
955 validate_move_child(partition_data *partition, partition_data *child,
956 	off_t childOffset, off_t childSize, off_t *_start,
957 	fc_get_sibling_partitions getSiblingPartitions)
958 {
959 	off_t start = *_start;
960 
961 	if (start < 0)
962 		start = 0;
963 	else if (start + childSize > partition->size)
964 		start = partition->size - childSize;
965 
966 	start = block_align(start, partition->block_size);
967 
968 	// finding out sibling partitions
969 	partition_data *previousSibling = NULL;
970 	partition_data *nextSibling = NULL;
971 	off_t previousOffset = 0, previousSize = 0, nextOffset = 0, nextSize = 0;
972 
973 	getSiblingPartitions(partition, child, childOffset, &previousSibling,
974 		&nextSibling, &previousOffset, &previousSize, &nextOffset, &nextSize);
975 
976 	// we cannot move child over sibling partition
977 	if (start < childOffset) {
978 		// moving left
979 		if (previousSibling && previousOffset + previousSize > start) {
980 			start = previousOffset + previousSize;
981 			start = block_align_up(start, partition->block_size);
982 		}
983 	} else {
984 		// moving right
985 		if (nextSibling && nextOffset < start + childSize) {
986 			start = nextOffset - childSize;
987 			start = block_align(start, partition->block_size);
988 		}
989 	}
990 	*_start = start;
991 	return true;
992 }
993 
994 
995 // pm_validate_move_child
996 static bool
997 pm_validate_move_child(partition_data *partition, partition_data *child,
998 	off_t *start)
999 {
1000 	TRACE(("intel: pm_validate_move_child\n"));
1001 
1002 	if (!partition || !child || !start
1003 		|| !pm_supports_moving_child(partition, child))
1004 		return false;
1005 	if (*start == child->offset)
1006 		return true;
1007 
1008 	return validate_move_child(partition, child, child->offset,
1009 		child->size, start, get_sibling_partitions_pm);
1010 }
1011 
1012 // is_type_valid_pm (auxiliary function)
1013 /*!
1014 	type has to be known, only one extended partition is allowed
1015 	partition - intel partition map
1016 	child can be NULL
1017 */
1018 static bool
1019 is_type_valid_pm(const char *type, partition_data *partition,
1020 	PrimaryPartition *child = NULL)
1021 {
1022 	// validity check of the type
1023 	PartitionType ptype;
1024 	ptype.SetType(type);
1025 	if (!ptype.IsValid() || ptype.IsEmpty())
1026 		return false;
1027 
1028 	// only one extended partition is allowed
1029 	if (ptype.IsExtended()) {
1030 		PartitionMap *map = (PartitionMap*)partition->content_cookie;
1031 		if (!map)
1032 			return false;
1033 		for (int32 i = 0; i < partition->child_count; i++) {
1034 			PrimaryPartition *primary = map->PrimaryPartitionAt(i);
1035 			if (primary && primary->IsExtended() && primary != child)
1036 				return false;
1037 		}
1038 	}
1039 	return true;
1040 }
1041 
1042 // pm_validate_set_type
1043 static bool
1044 pm_validate_set_type(partition_data *partition, const char *type)
1045 {
1046 	TRACE(("intel: pm_validate_set_type\n"));
1047 
1048 	if (!partition || !pm_supports_setting_type(partition) || !type)
1049 		return false;
1050 
1051 	partition_data *father = get_parent_partition(partition->id);
1052 	if (!father)
1053 		return false;
1054 	PrimaryPartition *child = (PrimaryPartition*)partition->cookie;
1055 	if (!child)
1056 		return false;
1057 
1058 	// validity check of the type
1059 	return is_type_valid_pm(type, father, child);
1060 }
1061 
1062 // pm_validate_initialize
1063 static bool
1064 pm_validate_initialize(partition_data *partition, char *name,
1065 	const char *parameters)
1066 {
1067 	TRACE(("intel: pm_validate_initialize\n"));
1068 
1069 	if (!partition || !pm_supports_initializing(partition))
1070 		return false;
1071 	// name is ignored - we cannot set it to the intel partitioning map
1072 	// TODO: check parameters - don't know whether any parameters could be set
1073 	//		 to the intel partition map
1074 	return true;
1075 }
1076 
1077 // validate_create_child_partition (auxiliary function)
1078 static bool
1079 validate_create_child_partition(partition_data *partition, off_t *start,
1080 	off_t *size, fc_get_sibling_partitions getSiblingPartitions)
1081 {
1082 	// make the start and size a multiple of the block size
1083 	*start = block_align(*start, partition->block_size);
1084 	if (*size < 0)
1085 		*size = 0;
1086 	else
1087 		*size = block_align(*size, partition->block_size);
1088 
1089 	// child must completely lie within the parent partition
1090 	if (*start >= partition->offset + partition->size)
1091 		return false;
1092 	if (*start + *size > partition->offset + partition->size)
1093 		*size = partition->offset + partition->size - *start;
1094 
1095 	// new child must not intersect with sibling partitions
1096 	// finding out sibling partitions
1097 	partition_data *previousSibling = NULL;
1098 	partition_data *nextSibling = NULL;
1099 	off_t previousOffset = 0, previousSize = 0, nextOffset = 0, nextSize = 0;
1100 
1101 	getSiblingPartitions(partition, NULL, *start, &previousSibling,
1102 		&nextSibling, &previousOffset, &previousSize, &nextOffset, &nextSize);
1103 
1104 	// position check of the new partition
1105 	if (previousSibling && (previousOffset + previousSize > *start)) {
1106 		*start = previousOffset + previousSize;
1107 		*start = block_align_up(*start, partition->block_size);
1108 	}
1109 
1110 	if (nextSibling && (nextOffset < *start + *size))
1111 		*size = nextOffset - *start;
1112 	*size = block_align(*size, partition->block_size);
1113 	if (*size == 0)
1114 		return false;
1115 
1116 	return true;
1117 }
1118 
1119 // pm_validate_create_child
1120 /*!
1121 	index - returns position of the new partition (first free record in MBR)
1122 */
1123 static bool
1124 pm_validate_create_child(partition_data *partition, off_t *start, off_t *size,
1125 	const char *type, const char *parameters, int32 *index)
1126 {
1127 	TRACE(("intel: pm_validate_create_child\n"));
1128 
1129 	if (!partition || !pm_supports_creating_child(partition)
1130 			|| !start || !size || !type || !index) {
1131 		return false;
1132 	}
1133 
1134 	// TODO: check parameters
1135 	// type check
1136 	if (!is_type_valid_pm(type, partition))
1137 		return false;
1138 
1139 	// finding out index of the new partition (first free record in MBR)
1140 	// at least one record has to be free
1141 	PartitionMap *map = (PartitionMap*)partition->content_cookie;
1142 	if (!map)
1143 		return false;
1144 	int32 newIndex = -1;
1145 	for (int32 i = 0; i < 4; i++) {
1146 		PrimaryPartition *primary = map->PrimaryPartitionAt(i);
1147 		if (primary->IsEmpty()) {
1148 			newIndex = i;
1149 			break;
1150 		}
1151 	}
1152 	// this cannot happen
1153 	if (newIndex < 0)
1154 		return false;
1155 	*index = newIndex;
1156 
1157 	if (*start < partition->offset + MBR_OFFSET * partition->block_size) {
1158 		*start = partition->offset + MBR_OFFSET * partition->block_size;
1159 		*start = block_align_up(*start, partition->block_size);
1160 	}
1161 
1162 	return validate_create_child_partition(partition, start, size,
1163 		get_sibling_partitions_pm);
1164 }
1165 
1166 // cmp_partition_position
1167 static int
1168 cmp_partition_position(const void *o1, const void *o2) {
1169 	off_t offset1 = ((PartitionPosition*)o1)->offset;
1170 	off_t offset2 = ((PartitionPosition*)o2)->offset;
1171 	if (offset1 < offset2)
1172 		return -1;
1173 	else if (offset1 > offset2)
1174 		return 1;
1175 	return 0;
1176 }
1177 
1178 // fill_partitionable_spaces_buffer_pm
1179 /*!
1180 	positions - output buffer with sufficient size
1181 	returns partition count
1182 */
1183 static int32
1184 fill_partitionable_spaces_buffer_pm(partition_data *partition,
1185 	PartitionPosition *positions)
1186 {
1187 	int32 partition_count = 0;
1188 	for (int32 i = 0; i < partition->child_count; i++) {
1189 		const partition_data *child = get_child_partition(partition->id, i);
1190 		if (child) {
1191 			positions[partition_count].offset = child->offset;
1192 			positions[partition_count].size = child->size;
1193 			partition_count++;
1194 		}
1195 	}
1196 	return partition_count;
1197 }
1198 
1199 // fill_partitionable_spaces_buffer_ep
1200 /*!
1201 	positions - output buffer with sufficient size
1202 	returns partition count
1203 */
1204 static int32
1205 fill_partitionable_spaces_buffer_ep(partition_data *partition,
1206 	PartitionPosition *positions)
1207 {
1208 	int32 partition_count = 0;
1209 	for (int32 i = 0; i < partition->child_count; i++) {
1210 		const partition_data *child = get_child_partition(partition->id, i);
1211 		if (child) {
1212 			positions[partition_count].offset = get_offset_ep(child);
1213 			positions[partition_count].size = get_size_ep(child);
1214 			partition_count++;
1215 		}
1216 	}
1217 	return partition_count;
1218 }
1219 
1220 // get_partitionable_spaces (auxiliary function)
1221 static status_t
1222 get_partitionable_spaces(partition_data *partition,
1223 	partitionable_space_data *buffer, int32 count, int32 *_actualCount,
1224 	fc_fill_partitionable_spaces_buffer fillBuffer, off_t startOffset,
1225 	off_t limitSize = 0, off_t headerSize = 0)
1226 {
1227 	PartitionPosition *positions
1228 		= new(nothrow) PartitionPosition[partition->child_count];
1229 	if (!positions)
1230 		return B_NO_MEMORY;
1231 	// fill the array
1232 	int32 partition_count = fillBuffer(partition, positions);
1233 	// sort the array
1234 	qsort(positions, partition_count, sizeof(PartitionPosition),
1235 		cmp_partition_position);
1236 
1237 	// first sektor is MBR or EBR
1238 	off_t offset = startOffset + headerSize;
1239 	off_t size = 0;
1240 	int32 actualCount = 0;
1241 
1242 	// offset alignment (to upper bound)
1243 	offset = block_align_up(offset, partition->block_size);
1244 
1245 	// finding out all partitionable spaces
1246 	for (int32 i = 0; i < partition_count; i++) {
1247 		size = positions[i].offset - offset;
1248 		size = block_align(size, partition->block_size);
1249 		if (size > limitSize) {
1250 			if (actualCount < count) {
1251 				buffer[actualCount].offset = offset;
1252 				buffer[actualCount].size = size;
1253 			}
1254 			actualCount++;
1255 		}
1256 		offset = positions[i].offset + positions[i].size + headerSize;
1257 		offset = block_align_up(offset, partition->block_size);
1258 	}
1259 	// space in the end of partition
1260 	size = partition->offset + partition->size - offset;
1261 	size = block_align(size, partition->block_size);
1262 	if (size > 0) {
1263 		if (actualCount < count) {
1264 			buffer[actualCount].offset = offset;
1265 			buffer[actualCount].size = size;
1266 		}
1267 		actualCount++;
1268 	}
1269 
1270 	// cleanup
1271 	if (positions)
1272 		delete[] positions;
1273 
1274 	*_actualCount = actualCount;
1275 	TRACE(("intel: get_partitionable_spaces - found: %ld\n", actualCount));
1276 	return B_OK;
1277 }
1278 
1279 // pm_get_partitionable_spaces
1280 static status_t
1281 pm_get_partitionable_spaces(partition_data *partition,
1282 	partitionable_space_data *buffer, int32 count, int32 *actualCount)
1283 {
1284 	TRACE(("intel: pm_get_partitionable_spaces\n"));
1285 
1286 	if (!partition || !partition->content_type
1287 		|| strcmp(partition->content_type, kPartitionTypeIntel)
1288 		|| !actualCount) {
1289 		return B_BAD_VALUE;
1290 	}
1291 	if (count > 0 && !buffer)
1292 		return B_BAD_VALUE;
1293 
1294 	return get_partitionable_spaces(partition, buffer, count, actualCount,
1295 		fill_partitionable_spaces_buffer_pm, MBR_OFFSET * partition->block_size,
1296 		0, 0);
1297 }
1298 
1299 // pm_get_next_supported_type
1300 static status_t
1301 pm_get_next_supported_type(partition_data *partition, int32 *cookie, char *type)
1302 {
1303 	TRACE(("intel: pm_get_next_supported_type\n"));
1304 
1305 	if (!partition || !partition->content_type
1306 		|| strcmp(partition->content_type, kPartitionTypeIntel)
1307 		|| !cookie || !type) {
1308 		return B_BAD_VALUE;
1309 	}
1310 
1311 	if (*cookie < 1)
1312 		*cookie = 1;
1313 	else if (*cookie > 255)
1314 		return B_BAD_INDEX;
1315 
1316 	// finding out supported type
1317 	PartitionType ptype;
1318 	ptype.SetType(*cookie);
1319 	if (!ptype.IsValid())
1320 		ptype.FindNext();
1321 	if (!ptype.IsValid())
1322 		return B_BAD_INDEX;
1323 
1324 	ptype.GetTypeString(type);
1325 	*cookie = ptype.Type();
1326 	return B_OK;
1327 }
1328 
1329 // get_type_for_content_type (for both pm_* and ep_*)
1330 static status_t
1331 get_type_for_content_type(const char *contentType, char *type)
1332 {
1333 	TRACE(("intel: get_type_for_content_type(%s)\n",
1334 		   contentType));
1335 
1336 	if (!contentType || !type)
1337 		return B_BAD_VALUE;
1338 
1339 	PartitionType ptype;
1340 	ptype.SetContentType(contentType);
1341 	if (!ptype.IsValid())
1342 		return B_NAME_NOT_FOUND;
1343 
1344 	ptype.GetTypeString(type);
1345 	return B_OK;
1346 }
1347 
1348 // pm_shadow_changed
1349 static status_t
1350 pm_shadow_changed(partition_data *partition, uint32 operation)
1351 {
1352 	TRACE(("intel: pm_shadow_changed\n"));
1353 
1354 	if (!partition)
1355 		return B_BAD_VALUE;
1356 
1357 	// nothing to do here
1358 	return B_OK;
1359 }
1360 
1361 
1362 // #pragma mark - Intel Partition Map - writing functions
1363 
1364 
1365 // pm_resize
1366 static status_t
1367 pm_resize(int fd, partition_id partitionID, off_t size, disk_job_id job)
1368 {
1369 	TRACE(("intel: pm_resize\n"));
1370 
1371 	if (fd < 0)
1372 		return B_ERROR;
1373 
1374 	PartitionWriteLocker locker(partitionID);
1375 	if (!locker.IsLocked())
1376 		return B_ERROR;
1377 
1378 	// get out partition
1379 	partition_data *partition = get_partition(partitionID);
1380 	if (!partition)
1381 		return B_BAD_VALUE;
1382 
1383 	// validate the new size
1384 // TODO: The parameter has already been checked and must not be altered!
1385 	off_t validatedSize = size;
1386 	if (!pm_validate_resize(partition, &validatedSize))
1387 		return B_BAD_VALUE;
1388 
1389 	// update data stuctures
1390 	update_disk_device_job_progress(job, 0.0);
1391 
1392 // TODO: partition->size is not supposed to be touched.
1393 	partition->size = validatedSize;
1394 	partition->content_size = validatedSize;
1395 
1396 	// all changes applied
1397 	update_disk_device_job_progress(job, 1.0);
1398 	partition_modified(partitionID);
1399 	return B_OK;
1400 }
1401 
1402 // pm_resize_child
1403 static status_t
1404 pm_resize_child(int fd, partition_id partitionID, off_t size, disk_job_id job)
1405 {
1406 	TRACE(("intel: pm_resize_child\n"));
1407 
1408 	if (fd < 0)
1409 		return B_ERROR;
1410 
1411 	PartitionWriteLocker locker(partitionID);
1412 	if (!locker.IsLocked())
1413 		return B_ERROR;
1414 
1415 	// get out partition, child and partition map structure
1416 	partition_data *partition = get_parent_partition(partitionID);
1417 	partition_data *child = get_partition(partitionID);
1418 	if (!partition || !child)
1419 		return B_BAD_VALUE;
1420 	PartitionMap *map = (PartitionMap*)partition->content_cookie;
1421 	PrimaryPartition *primary = (PrimaryPartition*)child->cookie;
1422 	if (!map || !primary)
1423 		return B_BAD_VALUE;
1424 
1425 	// validate the new size
1426 // TODO: The parameter has already been checked and must not be altered!
1427 	off_t validatedSize = size;
1428 	if (!pm_validate_resize_child(partition, child, &validatedSize))
1429 		return B_BAD_VALUE;
1430 	if (child->size == validatedSize)
1431 		return B_OK;
1432 
1433 	// update data stuctures and write changes
1434 	update_disk_device_job_progress(job, 0.0);
1435 	primary->SetSize(validatedSize);
1436 
1437 // TODO: The partition is not supposed to be locked here!
1438 	PartitionMapWriter writer(fd, 0, partition->size, partition->block_size);
1439 	status_t error = writer.WriteMBR(NULL, map);
1440 	if (error != B_OK) {
1441 		// putting into previous state
1442 		primary->SetSize(child->size);
1443 		return error;
1444 	}
1445 
1446 	child->size = validatedSize;
1447 
1448 	// all changes applied
1449 	update_disk_device_job_progress(job, 1.0);
1450 	partition_modified(partitionID);
1451 	return B_OK;
1452 }
1453 
1454 // pm_move
1455 static status_t
1456 pm_move(int fd, partition_id partitionID, off_t offset, disk_job_id job)
1457 {
1458 	TRACE(("intel: pm_move\n"));
1459 
1460 	if (fd < 0)
1461 		return B_ERROR;
1462 
1463 // TODO: Should be a no-op!
1464 
1465 	PartitionWriteLocker locker(partitionID);
1466 	if (!locker.IsLocked())
1467 		return B_ERROR;
1468 
1469 	// get out partition
1470 	partition_data *partition = get_partition(partitionID);
1471 	if (!partition)
1472 		return B_BAD_VALUE;
1473 
1474 	// validate the new start
1475 	if (!pm_validate_move(partition, &offset))
1476 		return B_BAD_VALUE;
1477 
1478 	// nothing to do here
1479 	return B_OK;
1480 }
1481 
1482 // allocate_buffer (auxiliary function)
1483 /*!
1484 	tries to allocate buffer with the size: blockSize * tryAlloc
1485 	if it's not possible, tries smaller buffer (until the size: blockSize * 1)
1486 	returns pointer to the buffer (it's size is: blockSize * allocated)
1487 	or returns NULL - B_NO_MEMORY
1488 */
1489 static uint8*
1490 allocate_buffer(uint32 blockSize, int32 tryAlloc, int32 *allocated)
1491 {
1492 	uint8* buffer = NULL;
1493 	for (int32 i = tryAlloc; i > 1; i /= 2) {
1494 		buffer = new(nothrow) uint8[i * blockSize];
1495 		if (buffer) {
1496 			*allocated = i;
1497 			return buffer;
1498 		}
1499 	}
1500 	*allocated = 0;
1501 	return NULL;
1502 }
1503 
1504 // move_block (auxiliary function)
1505 static status_t
1506 move_block(int fd, off_t fromOffset, off_t toOffset, uint8 *buffer, int32 size)
1507 {
1508 	status_t error = B_OK;
1509 	// read block to buffer
1510 	if (read_pos(fd, fromOffset, buffer, size) != size) {
1511 		error = errno;
1512 		if (error == B_OK)
1513 			error = B_IO_ERROR;
1514 		TRACE(("intel: move_block(): reading failed: %lx\n", error));
1515 		return error;
1516 	}
1517 
1518 	// write block from buffer
1519 	if (write_pos(fd, toOffset, buffer, size) != size) {
1520 		error = errno;
1521 		if (error == B_OK)
1522 			error = B_IO_ERROR;
1523 		TRACE(("intel: move_block(): writing failed: %lx\n", error));
1524 	}
1525 
1526 	return error;
1527 }
1528 
1529 // move_partition (auxiliary function)
1530 static status_t
1531 move_partition(int fd, off_t fromOffset, off_t toOffset, off_t size,
1532 	uint8 *buffer, int32 buffer_size, disk_job_id job)
1533 {
1534 // TODO: This should be a service function of the DDM!
1535 	status_t error = B_OK;
1536 	off_t cycleCount = size / buffer_size;
1537 	int32 remainingSize = size - cycleCount * buffer_size;
1538 	update_disk_device_job_progress(job, 0.0);
1539 	for (off_t i = 0; i < cycleCount; i++) {
1540 		error = move_block(fd, fromOffset, toOffset, buffer, buffer_size);
1541 		if (error != B_OK)
1542 			return error;
1543 		fromOffset += buffer_size;
1544 		toOffset += buffer_size;
1545 		update_disk_device_job_progress(job, i * 1.0 / cycleCount);
1546 	}
1547 	if (remainingSize)
1548 		error = move_block(fd, fromOffset, toOffset, buffer, remainingSize);
1549 	update_disk_device_job_progress(job, 1.0);
1550 	return error;
1551 }
1552 
1553 // pm_move_child
1554 static status_t
1555 pm_move_child(int fd, partition_id partitionID, partition_id childID,
1556 	off_t offset, disk_job_id job)
1557 {
1558 	TRACE(("intel: pm_move_child\n"));
1559 
1560 	if (fd < 0)
1561 		return B_ERROR;
1562 
1563 	PartitionWriteLocker locker(partitionID);
1564 	if (!locker.IsLocked())
1565 		return B_ERROR;
1566 
1567 	// get partition, child and partition map structure
1568 	partition_data *partition = get_partition(partitionID);
1569 	partition_data *child = get_partition(childID);
1570 	if (!partition || !child)
1571 		return B_BAD_VALUE;
1572 	PartitionMap *map = (PartitionMap*)partition->content_cookie;
1573 	PrimaryPartition *primary = (PrimaryPartition*)child->cookie;
1574 	if (!map || !primary)
1575 		return B_BAD_VALUE;
1576 
1577 // TODO: The parameter has already been checked and must not be altered!
1578 	off_t validatedOffset = offset;
1579 	if (!pm_validate_move_child(partition, child, &validatedOffset))
1580 		return B_BAD_VALUE;
1581 
1582 	// if the old offset is the same, there is nothing to do
1583 	if (child->offset == validatedOffset)
1584 		return B_OK;
1585 
1586 	// buffer allocation
1587 	int32 allocated;
1588 	uint8 *buffer = allocate_buffer(partition->block_size, MAX_MOVE_BUFFER,
1589 		&allocated);
1590 	if (!buffer)
1591 		return B_NO_MEMORY;
1592 
1593 	// partition moving
1594 // TODO: The partition is not supposed to be locked at this point!
1595 	update_disk_device_job_progress(job, 0.0);
1596 	status_t error = B_OK;
1597 	error = move_partition(fd, child->offset, validatedOffset, child->size,
1598 		buffer, allocated * partition->block_size, job);
1599 	delete[] buffer;
1600 	if (error != B_OK)
1601 		return error;
1602 
1603 	// partition moved
1604 	// updating data structure
1605 	child->offset = validatedOffset;
1606 	primary->SetOffset(validatedOffset);
1607 
1608 	PartitionMapWriter writer(fd, 0, partition->size, partition->block_size);
1609 	error = writer.WriteMBR(NULL, map);
1610 	if (error != B_OK)
1611 		// something went wrong - this is fatal (partition has been moved)
1612 		// but MBR is not updated
1613 		return error;
1614 
1615 	// all changes applied
1616 	update_disk_device_job_progress(job, 1.0);
1617 	partition_modified(childID);
1618 	return B_OK;
1619 }
1620 
1621 // pm_set_type
1622 static status_t
1623 pm_set_type(int fd, partition_id partitionID, const char *type, disk_job_id job)
1624 {
1625 	TRACE(("intel: pm_set_type\n"));
1626 
1627 	if (fd < 0 || !type)
1628 		return B_BAD_VALUE;
1629 
1630 	PartitionWriteLocker locker(partitionID);
1631 	if (!locker.IsLocked())
1632 		return B_ERROR;
1633 
1634 	// get parent partition, child and partition map structure
1635 	partition_data *partition = get_parent_partition(partitionID);
1636 	partition_data *child = get_partition(partitionID);
1637 	if (!partition || !child)
1638 		return B_BAD_VALUE;
1639 	PartitionMap *map = (PartitionMap*)partition->content_cookie;
1640 	PrimaryPartition *primary = (PrimaryPartition*)child->cookie;
1641 	if (!map || !primary)
1642 		return B_BAD_VALUE;
1643 
1644 // TODO: The parameter has already been checked and must not be altered!
1645 	if (!pm_validate_set_type(child, type))
1646 		return B_BAD_VALUE;
1647 
1648 	// if the old type is the same, there is nothing to do
1649 	if (child->type && !strcmp(type, child->type))
1650 		return B_OK;
1651 
1652 	PartitionType ptype;
1653 	ptype.SetType(type);
1654 	// this is impossible
1655 	if (!ptype.IsValid() || ptype.IsEmpty())
1656 		return false;
1657 // TODO: Incompatible return value!
1658 
1659 	// setting type to the partition
1660 	update_disk_device_job_progress(job, 0.0);
1661 	uint8 oldType = primary->Type();
1662 	primary->SetType(ptype.Type());
1663 
1664 // TODO: The partition is not supposed to be locked at this point!
1665 	PartitionMapWriter writer(fd, 0, partition->size, partition->block_size);
1666 	status_t error = writer.WriteMBR(NULL, map);
1667 	if (error != B_OK) {
1668 		// something went wrong - putting into previous state
1669 		primary->SetType(oldType);
1670 		return error;
1671 	}
1672 
1673 	free(child->type);
1674 	child->type = strdup(type);
1675 	if (!child->type)
1676 		return B_NO_MEMORY;
1677 
1678 	// all changes applied
1679 	update_disk_device_job_progress(job, 1.0);
1680 	partition_modified(partitionID);
1681 	return B_OK;
1682 }
1683 
1684 
1685 // pm_initialize
1686 static status_t
1687 pm_initialize(int fd, partition_id partitionID, const char *name,
1688 	const char *parameters, disk_job_id job)
1689 {
1690 	TRACE(("intel: pm_initialize\n"));
1691 
1692 	if (fd < 0)
1693 		return B_ERROR;
1694 
1695 	PartitionWriteLocker locker(partitionID);
1696 	if (!locker.IsLocked())
1697 		return B_ERROR;
1698 
1699 	// get partition and partition map structure
1700 	partition_data *partition = get_partition(partitionID);
1701 	if (!partition)
1702 		return B_BAD_VALUE;
1703 
1704 	// name is ignored - we cannot set it to the intel partitioning map
1705 // TODO: The parameter has already been checked and must not be altered!
1706 	if (!pm_validate_initialize(partition, NULL, parameters))
1707 		return B_BAD_VALUE;
1708 
1709 	// partition init
1710 	update_disk_device_job_progress(job, 0.0);
1711 	// allocate a PartitionMap
1712 	PartitionMapCookie *map = new(nothrow) PartitionMapCookie;
1713 	if (!map)
1714 		return B_NO_MEMORY;
1715 	map->ref_count = 1;
1716 	// fill in the partition_data structure
1717 	partition->status = B_PARTITION_VALID;
1718 	partition->flags |= B_PARTITION_PARTITIONING_SYSTEM;
1719 	partition->content_size = partition->size;
1720 	// (no content_name and content_parameters)
1721 	// (content_type is set by the system)
1722 	partition->content_cookie = map;
1723 
1724 	for (int32 i = 0; i < 4; i++) {
1725 		PrimaryPartition *primary = map->PrimaryPartitionAt(i);
1726 		primary->Unset();
1727 	}
1728 
1729 	// we delete code area in MBR, if there is any
1730 // TODO: Huh?!
1731 	partition_table_sector pts;
1732 	pts.clear_code_area();
1733 
1734 	PartitionMapWriter writer(fd, 0, partition->size, partition->block_size);
1735 // TODO: The partition is not supposed to be locked at this point!
1736 	status_t error = writer.WriteMBR((uint8*)&pts, map);
1737 	if (error != B_OK)
1738 		return error;
1739 
1740 	// all changes applied
1741 	update_disk_device_job_progress(job, 1.0);
1742 	partition_modified(partitionID);
1743 	return B_OK;
1744 }
1745 
1746 // pm_create_child
1747 static status_t
1748 pm_create_child(int fd, partition_id partitionID, off_t offset, off_t size,
1749 	const char *type, const char *parameters, disk_job_id job,
1750 	partition_id *childID)
1751 	// childID is used for the return value, but is also an optional input
1752 	// parameter -- -1 to be ignored
1753 {
1754 	TRACE(("intel: pm_create_child\n"));
1755 
1756 	if (fd < 0 || !childID)
1757 		return B_BAD_VALUE;
1758 
1759 	PartitionWriteLocker locker(partitionID);
1760 	if (!locker.IsLocked())
1761 		return B_ERROR;
1762 
1763 	// get partition and partition map structure
1764 	partition_data *partition = get_partition(partitionID);
1765 	if (!partition)
1766 		return B_BAD_VALUE;
1767 	PartitionMap *map = (PartitionMap*)partition->content_cookie;
1768 	if (!map)
1769 		return B_BAD_VALUE;
1770 
1771 	// validate the offset, size and get index of the new partition
1772 // TODO: The parameters have already been checked and must not be altered!
1773 	off_t validatedOffset = offset;
1774 	off_t validatedSize = size;
1775 	int32 index = 0;
1776 
1777 	if (!pm_validate_create_child(partition, &validatedOffset, &validatedSize,
1778 			type, parameters, &index)) {
1779 		return B_BAD_VALUE;
1780 	}
1781 
1782 	// finding out free primary partition in the map (index from
1783 	// pm_validate_create_child)
1784 	PrimaryPartition *primary = map->PrimaryPartitionAt(index);
1785 	if (!primary->IsEmpty())
1786 		return B_BAD_DATA;
1787 
1788 	// creating partition
1789 	update_disk_device_job_progress(job, 0.0);
1790 	partition_data *child = create_child_partition(partition->id, index,
1791 		*childID);
1792 	if (!child)
1793 		return B_ERROR;
1794 
1795 	PartitionType ptype;
1796 	ptype.SetType(type);
1797 
1798 	primary->SetPTSOffset(0);
1799 	primary->SetOffset(validatedOffset);
1800 	primary->SetSize(validatedSize);
1801 	primary->SetType(ptype.Type());
1802 	// TODO: correctly fill active parameter
1803 	primary->SetActive(false);
1804 
1805 	// write changes to disk
1806 	PartitionMapWriter writer(fd, 0, partition->size, partition->block_size);
1807 // TODO: The partition is not supposed to be locked at this point!
1808 	status_t error = writer.WriteMBR(NULL, map);
1809 	if (error != B_OK) {
1810 		// putting into previous state
1811 		primary->Unset();
1812 		delete_partition(child->id);
1813 		return error;
1814 	}
1815 
1816 	*childID = child->id;
1817 
1818 	child->offset = partition->offset + primary->Offset();
1819 	child->size = primary->Size();
1820 	child->block_size = partition->block_size;
1821 	// (no name)
1822 	child->type = strdup(type);
1823 	// parameters
1824 	child->parameters = strdup(parameters);
1825 	child->cookie = primary;
1826 	// check for allocation problems
1827 	if (!child->type || !child->parameters)
1828 		return B_NO_MEMORY;
1829 
1830 	// all changes applied
1831 	update_disk_device_job_progress(job, 1.0);
1832 	partition_modified(partitionID);
1833 	return B_OK;
1834 }
1835 
1836 // pm_delete_child
1837 static status_t
1838 pm_delete_child(int fd, partition_id partitionID, partition_id childID,
1839 	disk_job_id job)
1840 {
1841 	TRACE(("intel: pm_delete_child\n"));
1842 
1843 	if (fd < 0)
1844 		return B_ERROR;
1845 
1846 	PartitionWriteLocker locker(partitionID);
1847 	if (!locker.IsLocked())
1848 		return B_ERROR;
1849 
1850 	partition_data *partition = get_partition(partitionID);
1851 	partition_data *child = get_partition(childID);
1852 	if (!partition || !child)
1853 		return B_BAD_VALUE;
1854 
1855 	if (!pm_supports_deleting_child(partition, child))
1856 		return B_ERROR;
1857 
1858 	PartitionMap *map = (PartitionMap*)partition->content_cookie;
1859 	PrimaryPartition *primary = (PrimaryPartition*)child->cookie;
1860 	if (!map || !primary)
1861 		return B_BAD_VALUE;
1862 
1863 	// deleting child
1864 	update_disk_device_job_progress(job, 0.0);
1865 	if (!delete_partition(childID))
1866 		return B_ERROR;
1867 	primary->Unset();
1868 
1869 	// write changes to disk
1870 	PartitionMapWriter writer(fd, 0, partition->size, partition->block_size);
1871 // TODO: The partition is not supposed to be locked at this point!
1872 	status_t error = writer.WriteMBR(NULL, map);
1873 	if (error != B_OK)
1874 		return error;
1875 
1876 	// all changes applied
1877 	update_disk_device_job_progress(job, 1.0);
1878 	partition_modified(partitionID);
1879 	return B_OK;
1880 }
1881 
1882 #endif	// !_BOOT_MODE
1883 
1884 
1885 // #pragma mark - Intel Extended Partition Module
1886 
1887 
1888 // ep_std_ops
1889 static status_t
1890 ep_std_ops(int32 op, ...)
1891 {
1892 	TRACE(("intel: ep_std_ops(0x%lx)\n", op));
1893 	switch(op) {
1894 		case B_MODULE_INIT:
1895 		case B_MODULE_UNINIT:
1896 			return B_OK;
1897 	}
1898 	return B_ERROR;
1899 }
1900 
1901 // ep_identify_partition
1902 static float
1903 ep_identify_partition(int fd, partition_data *partition, void **cookie)
1904 {
1905 	// check parameters
1906 	if (fd < 0 || !partition || !cookie || !partition->cookie)
1907 		return -1;
1908 
1909 	TRACE(("intel: ep_identify_partition(%d, %lld, %lld, %ld)\n", fd,
1910 		   partition->offset, partition->size, partition->block_size));
1911 
1912 	// our parent must be a intel partition map partition and we must have
1913 	// extended partition type
1914 	if (!partition->type
1915 		|| strcmp(partition->type, kPartitionTypeIntelExtended)) {
1916 		return -1;
1917 	}
1918 	partition_data *parent = get_parent_partition(partition->id);
1919 	if (!parent || !parent->content_type
1920 		|| strcmp(parent->content_type, kPartitionTypeIntel)) {
1921 		return -1;
1922 	}
1923 
1924 	// things seem to be in order
1925 	return 0.95;
1926 }
1927 
1928 // ep_scan_partition
1929 static status_t
1930 ep_scan_partition(int fd, partition_data *partition, void *cookie)
1931 {
1932 	// check parameters
1933 	if (fd < 0 || !partition || !partition->cookie)
1934 		return B_ERROR;
1935 
1936 	TRACE(("intel: ep_scan_partition(%d, %lld, %lld, %ld)\n", fd,
1937 		partition->offset, partition->size, partition->block_size));
1938 
1939 	partition_data *parent = get_parent_partition(partition->id);
1940 	if (!parent)
1941 		return B_ERROR;
1942 	PrimaryPartition *primary = (PrimaryPartition*)partition->cookie;
1943 	// fill in the partition_data structure
1944 	partition->status = B_PARTITION_VALID;
1945 	partition->flags |= B_PARTITION_PARTITIONING_SYSTEM;
1946 	partition->content_size = partition->size;
1947 	// (no content_name and content_parameters)
1948 	// (content_type is set by the system)
1949 
1950 	partition->content_cookie = primary;
1951 	// children
1952 	status_t error = B_OK;
1953 	int32 index = 0;
1954 	for (int32 i = 0; i < primary->CountLogicalPartitions(); i++) {
1955 		LogicalPartition *logical = primary->LogicalPartitionAt(i);
1956 		partition_data *child = create_child_partition(partition->id,
1957 													   index, -1);
1958 		index++;
1959 		if (!child) {
1960 			// something went wrong
1961 			TRACE(("intel: ep_scan_partition(): failed to create child "
1962 				"partition\n"));
1963 			error = B_ERROR;
1964 			break;
1965 		}
1966 		child->offset = parent->offset + logical->Offset();
1967 		child->size = logical->Size();
1968 		child->block_size = partition->block_size;
1969 		// (no name)
1970 		char type[B_FILE_NAME_LENGTH];
1971 		logical->GetTypeString(type);
1972 		child->type = strdup(type);
1973 
1974 		// parameters
1975 		char buffer[128];
1976 		sprintf(buffer, "type = %u ; active = %d", logical->Type(),
1977 			logical->Active());
1978 		child->parameters = strdup(buffer);
1979 		child->cookie = logical;
1980 		// check for allocation problems
1981 		if (!child->type || !child->parameters) {
1982 			TRACE(("intel: ep_scan_partition(): failed to allocation type "
1983 				"or parameters\n"));
1984 			error = B_NO_MEMORY;
1985 			break;
1986 		}
1987 	}
1988 	// cleanup on error
1989 	if (error != B_OK) {
1990 		partition->content_cookie = NULL;
1991 		for (int32 i = 0; i < partition->child_count; i++) {
1992 			if (partition_data *child = get_child_partition(partition->id, i))
1993 				child->cookie = NULL;
1994 		}
1995 	}
1996 	return error;
1997 }
1998 
1999 // ep_free_identify_partition_cookie
2000 static void
2001 ep_free_identify_partition_cookie(partition_data *partition, void *cookie)
2002 {
2003 	// nothing to do
2004 }
2005 
2006 // ep_free_partition_cookie
2007 static void
2008 ep_free_partition_cookie(partition_data *partition)
2009 {
2010 	// the logical partition's cookie belongs to the partition map partition
2011 	if (partition)
2012 		partition->cookie = NULL;
2013 }
2014 
2015 // ep_free_partition_content_cookie
2016 static void
2017 ep_free_partition_content_cookie(partition_data *partition)
2018 {
2019 	// the extended partition's cookie belongs to the partition map partition
2020 	if (partition)
2021 		partition->content_cookie = NULL;
2022 }
2023 
2024 
2025 #ifndef _BOOT_MODE
2026 
2027 
2028 // #pragma mark - Intel Extended Partition - support functions
2029 
2030 
2031 // ep_supports_resizing
2032 static bool
2033 ep_supports_resizing(partition_data *partition)
2034 {
2035 	TRACE(("intel: ep_supports_resizing(%ld: %lld, %lld, %ld, %s)\n",
2036 		partition->id, partition->offset, partition->size,
2037 		partition->block_size, partition->content_type));
2038 
2039 
2040 	return (partition && partition->content_type
2041 		&& !strcmp(partition->content_type, kPartitionTypeIntelExtended));
2042 }
2043 
2044 // ep_supports_resizing_child
2045 static bool
2046 ep_supports_resizing_child(partition_data *partition, partition_data *child)
2047 {
2048 	TRACE(("intel: ep_supports_resizing_child(%ld: %lld, %lld, %ld, %s)\n",
2049 		partition->id, partition->offset, partition->size,
2050 		partition->block_size, partition->content_type));
2051 
2052 
2053 	return (partition && child && partition->content_type
2054 		&& !strcmp(partition->content_type, kPartitionTypeIntelExtended));
2055 }
2056 
2057 // ep_supports_moving
2058 static bool
2059 ep_supports_moving(partition_data *partition, bool *isNoOp)
2060 {
2061 	TRACE(("intel: ep_supports_moving(%ld: %lld, %lld, %ld, %s)\n",
2062 		partition->id, partition->offset, partition->size,
2063 		partition->block_size, partition->content_type));
2064 
2065 
2066 	*isNoOp = true;
2067 	return (partition && partition->content_type
2068 		&& !strcmp(partition->content_type, kPartitionTypeIntelExtended));
2069 }
2070 
2071 // ep_supports_moving_child
2072 static bool
2073 ep_supports_moving_child(partition_data *partition, partition_data *child)
2074 {
2075 	TRACE(("intel: ep_supports_moving_child(%ld: %lld, %lld, %ld, %s)\n",
2076 		partition->id, partition->offset, partition->size,
2077 		partition->block_size, partition->content_type));
2078 
2079 
2080 	return (partition && child && partition->content_type
2081 		&& !strcmp(partition->content_type, kPartitionTypeIntelExtended));
2082 }
2083 
2084 // ep_supports_setting_name
2085 static bool
2086 ep_supports_setting_name(partition_data *partition)
2087 {
2088 	return false;
2089 }
2090 
2091 // ep_supports_setting_content_name
2092 static bool
2093 ep_supports_setting_content_name(partition_data *partition)
2094 {
2095 	return false;
2096 }
2097 
2098 // ep_supports_setting_type
2099 static bool
2100 ep_supports_setting_type(partition_data *partition)
2101 {
2102 	TRACE(("intel: ep_supports_setting_type(%ld: %lld, %lld, %ld)\n",
2103 		partition->id, partition->offset, partition->size,
2104 		partition->block_size));
2105 
2106 	// partition should be child of "Intel Extended Partition"
2107 	partition_data *parent;
2108 	return (partition
2109 		&& (parent = get_parent_partition(partition->id))
2110 		&& parent->content_type
2111 		&& !strcmp(parent->content_type, kPartitionTypeIntelExtended));
2112 }
2113 
2114 // ep_supports_initializing
2115 static bool
2116 ep_supports_initializing(partition_data *partition)
2117 {
2118 	TRACE(("intel: ep_supports_initializing(%ld: %lld, %lld, %ld, %s)\n",
2119 		partition->id, partition->offset, partition->size,
2120 		partition->block_size, partition->content_type));
2121 
2122 	return (partition
2123 		&& !partition->content_type
2124 		&& partition->child_count == 0
2125 		&& partition->content_cookie == NULL);
2126 }
2127 
2128 // ep_supports_creating_child
2129 static bool
2130 ep_supports_creating_child(partition_data *partition)
2131 {
2132 	TRACE(("intel: ep_supports_creating_child(%ld: %lld, %lld, %ld, %s)\n",
2133 		partition->id, partition->offset, partition->size,
2134 		partition->block_size, partition->content_type));
2135 
2136 
2137 	int32 countSpaces = 0;
2138 	return (partition && partition->content_type
2139 		&& !strcmp(partition->content_type, kPartitionTypeIntelExtended)
2140 		// free space check
2141 		&& ep_get_partitionable_spaces(partition, NULL, 0, &countSpaces)
2142 			== B_OK
2143 		&& countSpaces);
2144 }
2145 
2146 // ep_supports_deleting_child
2147 static bool
2148 ep_supports_deleting_child(partition_data *partition, partition_data *child)
2149 {
2150 	TRACE(("intel: ep_supports_deleting_child(%ld: %lld, %lld, %ld, %s)\n",
2151 		partition->id, partition->offset, partition->size,
2152 		partition->block_size, partition->content_type));
2153 
2154 
2155 	return (partition && child && partition->content_type
2156 		&& !strcmp(partition->content_type, kPartitionTypeIntelExtended));
2157 }
2158 
2159 // ep_is_sub_system_for
2160 static bool
2161 ep_is_sub_system_for(partition_data *partition)
2162 {
2163 	TRACE(("intel: ep_is_sub_system_for(%ld: %lld, %lld, %ld, %s)\n",
2164 		partition->id, partition->offset, partition->size,
2165 		partition->block_size, partition->content_type));
2166 
2167 
2168 	// Intel Extended Partition can live in child partition of Intel Partition
2169 	// Map
2170 	return (partition && partition->content_type
2171 		&& !strcmp(partition->content_type, kPartitionTypeIntel));
2172 }
2173 
2174 
2175 // #pragma mark - Intel Extended Partition - validate functions
2176 
2177 
2178 // ep_validate_resize
2179 static bool
2180 ep_validate_resize(partition_data *partition, off_t *size)
2181 {
2182 	TRACE(("intel: ep_validate_resize\n"));
2183 
2184 	if (!partition || !ep_supports_resizing(partition) || !size)
2185 		return false;
2186 
2187 	return validate_resize(partition, size);
2188 }
2189 
2190 // ep_validate_resize_child
2191 static bool
2192 ep_validate_resize_child(partition_data *partition, partition_data *child,
2193 	off_t *_size)
2194 {
2195 	TRACE(("intel: ep_validate_resize_child\n"));
2196 
2197 	if (!partition || !child || !_size
2198 		|| !ep_supports_resizing_child(partition, child))
2199 		return false;
2200 
2201 	// validate position
2202 	off_t diff_offset = child->offset - get_offset_ep(child);
2203 	off_t size = *_size + diff_offset;
2204 	if (!validate_resize_child(partition, child, get_offset_ep(child),
2205 		 get_size_ep(child), &size, get_sibling_partitions_ep))
2206 		return false;
2207 	*_size = size - diff_offset;
2208 	return true;
2209 }
2210 
2211 // ep_validate_move
2212 static bool
2213 ep_validate_move(partition_data *partition, off_t *start)
2214 {
2215 	TRACE(("intel: ep_validate_move\n"));
2216 
2217 	bool isNoOp;
2218 	if (!partition || !start || !ep_supports_moving(partition, &isNoOp))
2219 		return false;
2220 	// nothing to do here
2221 	return true;
2222 }
2223 
2224 // ep_validate_move_child
2225 static bool
2226 ep_validate_move_child(partition_data *partition, partition_data *child,
2227 					   off_t *_start)
2228 {
2229 	TRACE(("intel: ep_validate_move_child\n"));
2230 
2231 	if (!partition || !child || !_start
2232 		|| !ep_supports_moving_child(partition, child))
2233 		return false;
2234 	if (*_start == child->offset)
2235 		return true;
2236 
2237 	// validate position
2238 	off_t diff_offset = child->offset - get_offset_ep(child);
2239 	off_t start = *_start - diff_offset;
2240 	if (!validate_move_child(partition, child, get_offset_ep(child),
2241 		 get_size_ep(child), &start, get_sibling_partitions_ep))
2242 		return false;
2243 	*_start = start + diff_offset;
2244 	return true;
2245 }
2246 
2247 // is_type_valid_ep (auxiliary function)
2248 static inline bool
2249 is_type_valid_ep(const char *type)
2250 {
2251 	// validity check of the type - it has to be known
2252 	PartitionType ptype;
2253 	ptype.SetType(type);
2254 	return (ptype.IsValid() && !ptype.IsEmpty() && !ptype.IsExtended());
2255 }
2256 
2257 // ep_validate_set_type
2258 static bool
2259 ep_validate_set_type(partition_data *partition, const char *type)
2260 {
2261 	TRACE(("intel: ep_validate_set_type\n"));
2262 
2263 	if (!partition || !ep_supports_setting_type(partition) || !type)
2264 		return false;
2265 
2266 	// validity check of the type
2267 	return is_type_valid_ep(type);
2268 }
2269 
2270 // ep_validate_initialize
2271 static bool
2272 ep_validate_initialize(partition_data *partition, char *name,
2273 	const char *parameters)
2274 {
2275 	TRACE(("intel: ep_validate_initialize\n"));
2276 
2277 	if (!partition || !ep_supports_initializing(partition))
2278 		return false;
2279 	// name is ignored - we cannot set it to the Intel Extended Partition
2280 	// TODO: check parameters - don't know whether any parameters could be set
2281 	//		 to the Intel Extended Partition
2282 	return true;
2283 }
2284 
2285 // ep_validate_create_child
2286 static bool
2287 ep_validate_create_child(partition_data *partition, off_t *_start, off_t *_size,
2288 	const char *type, const char *parameters, int32 *index)
2289 	// index - returns position of the new partition (the last one)
2290 {
2291 	TRACE(("intel: ep_validate_create_child\n"));
2292 
2293 	if (!partition || !ep_supports_creating_child(partition)
2294 		|| !_start || !_size || !type || !index) {
2295 		return false;
2296 	}
2297 
2298 	// TODO: check parameters
2299 	// type check
2300 	if (!is_type_valid_ep(type))
2301 		return false;
2302 
2303 	// finding out index of the new partition (it will be the last child)
2304 	*index = partition->child_count;
2305 
2306 	// validate position
2307 	off_t diffOffset = PTS_OFFSET * partition->block_size;
2308 	off_t start = *_start - diffOffset;
2309 	off_t size = *_size + diffOffset;
2310 	if (start < partition->offset + PTS_OFFSET * partition->block_size) {
2311 		start = partition->offset + PTS_OFFSET * partition->block_size;
2312 		start = block_align_up(start, partition->block_size);
2313 	}
2314 	if (!validate_create_child_partition(partition, &start, &size,
2315 			get_sibling_partitions_ep)) {
2316 		return false;
2317 	}
2318 	*_start = start + diffOffset;
2319 	*_size = size - diffOffset;
2320 	if (*_size == 0)
2321 		return false;
2322 	return true;
2323 }
2324 
2325 // ep_get_partitionable_spaces
2326 static status_t
2327 ep_get_partitionable_spaces(partition_data *partition,
2328 	partitionable_space_data *buffer, int32 count, int32 *actualCount)
2329 {
2330 	TRACE(("intel: ep_get_partitionable_spaces\n"));
2331 
2332 	if (!partition || !partition->content_type
2333 		|| strcmp(partition->content_type, kPartitionTypeIntelExtended)
2334 		|| !actualCount) {
2335 		return B_BAD_VALUE;
2336 	}
2337 	if (count > 0 && !buffer)
2338 		return B_BAD_VALUE;
2339 
2340 	return get_partitionable_spaces(partition, buffer, count, actualCount,
2341 		fill_partitionable_spaces_buffer_ep,
2342 		partition->offset + PTS_OFFSET * partition->block_size,
2343 		PTS_OFFSET * partition->block_size,
2344 		PTS_OFFSET * partition->block_size);
2345 }
2346 
2347 // ep_get_next_supported_type
2348 static status_t
2349 ep_get_next_supported_type(partition_data *partition, int32 *cookie, char *type)
2350 {
2351 	TRACE(("intel: ep_get_next_supported_type\n"));
2352 
2353 	if (!partition || !partition->content_type
2354 		|| strcmp(partition->content_type, kPartitionTypeIntelExtended)
2355 		|| !cookie || !type) {
2356 		return B_BAD_VALUE;
2357 	}
2358 
2359 	if (*cookie < 1)
2360 		*cookie = 1;
2361 	else if (*cookie > 255)
2362 		return B_BAD_INDEX;
2363 
2364 	// finding out supported type
2365 	PartitionType ptype;
2366 	ptype.SetType(*cookie);
2367 	if (!ptype.IsValid())
2368 		ptype.FindNext();
2369 	while (ptype.IsValid() && ptype.IsExtended())
2370 		ptype.FindNext();
2371 	if (!ptype.IsValid())
2372 		return B_BAD_INDEX;
2373 
2374 	ptype.GetTypeString(type);
2375 	*cookie = ptype.Type();
2376 	return B_OK;
2377 }
2378 
2379 // ep_shadow_changed
2380 static status_t
2381 ep_shadow_changed(partition_data *partition, uint32 operation)
2382 {
2383 	TRACE(("intel: ep_shadow_changed\n"));
2384 
2385 	if (!partition)
2386 		return B_BAD_VALUE;
2387 
2388 	// nothing to do here
2389 	return B_OK;
2390 }
2391 
2392 
2393 // #pragma mark - Intel Extended Partition - write functions
2394 
2395 
2396 // ep_resize
2397 static status_t
2398 ep_resize(int fd, partition_id partitionID, off_t size, disk_job_id job)
2399 {
2400 	TRACE(("intel: ep_resize\n"));
2401 
2402 	if (fd < 0)
2403 		return B_ERROR;
2404 
2405 	PartitionWriteLocker locker(partitionID);
2406 	if (!locker.IsLocked())
2407 		return B_ERROR;
2408 
2409 	// get out partition
2410 	partition_data *partition = get_partition(partitionID);
2411 	if (!partition)
2412 		return B_BAD_VALUE;
2413 
2414 	// validate the new size
2415 // TODO: The parameter has already been checked and must not be altered!
2416 	off_t validatedSize = size;
2417 	if (!ep_validate_resize(partition, &validatedSize))
2418 		return B_BAD_VALUE;
2419 
2420 	// update data stuctures
2421 	update_disk_device_job_progress(job, 0.0);
2422 
2423 // TODO: partition->size is not supposed to be touched.
2424 	partition->size = validatedSize;
2425 	partition->content_size = validatedSize;
2426 
2427 	// all changes applied
2428 	update_disk_device_job_progress(job, 1.0);
2429 	partition_modified(partitionID);
2430 	return B_OK;
2431 }
2432 
2433 // ep_resize_child
2434 static status_t
2435 ep_resize_child(int fd, partition_id partitionID, off_t size, disk_job_id job)
2436 {
2437 	TRACE(("intel: ep_resize_child\n"));
2438 
2439 	if (fd < 0)
2440 		return B_ERROR;
2441 
2442 	PartitionWriteLocker locker(partitionID);
2443 	if (!locker.IsLocked())
2444 		return B_ERROR;
2445 
2446 	// get out partition, child and LogicalPartition structure
2447 	partition_data *partition = get_parent_partition(partitionID);
2448 	partition_data *child = get_partition(partitionID);
2449 	if (!partition || !child)
2450 		return B_BAD_VALUE;
2451 	LogicalPartition *logical = (LogicalPartition*)child->cookie;
2452 	if (!logical)
2453 		return B_BAD_VALUE;
2454 
2455 	// validate the new size
2456 // TODO: The parameter has already been checked and must not be altered!
2457 	off_t validatedSize = size;
2458 	if (!ep_validate_resize_child(partition, child, &validatedSize))
2459 		return B_BAD_VALUE;
2460 	if (child->size == validatedSize)
2461 		return B_OK;
2462 
2463 	// update data stuctures and write changes
2464 	update_disk_device_job_progress(job, 0.0);
2465 	logical->SetSize(validatedSize);
2466 
2467 	PartitionMapWriter writer(fd, partition->offset, partition->size, partition->block_size);
2468 // TODO: The partition is not supposed to be locked here!
2469 	status_t error = writer.WriteLogical(NULL, logical);
2470 	if (error != B_OK) {
2471 		// putting into previous state
2472 		logical->SetSize(child->size);
2473 		return error;
2474 	}
2475 	LogicalPartition *prev = logical->Previous();
2476 	error = prev ? writer.WriteLogical(NULL, prev)
2477 				 : writer.WriteExtendedHead(NULL, logical);
2478 	if (error != B_OK)
2479 		// this should be not so fatal
2480 		return error;
2481 
2482 	child->size = validatedSize;
2483 
2484 	// all changes applied
2485 	update_disk_device_job_progress(job, 1.0);
2486 	partition_modified(partitionID);
2487 	return B_OK;
2488 }
2489 
2490 // ep_move
2491 static status_t
2492 ep_move(int fd, partition_id partitionID, off_t offset, disk_job_id job)
2493 {
2494 	TRACE(("intel: ep_move\n"));
2495 
2496 	if (fd < 0)
2497 		return B_ERROR;
2498 
2499 	PartitionWriteLocker locker(partitionID);
2500 	if (!locker.IsLocked())
2501 		return B_ERROR;
2502 
2503 	// get out partition
2504 	partition_data *partition = get_partition(partitionID);
2505 	if (!partition)
2506 		return B_BAD_VALUE;
2507 
2508 	// validate the new start
2509 // TODO: The parameter has already been checked and must not be altered!
2510 	if (!ep_validate_move(partition, &offset))
2511 		return B_BAD_VALUE;
2512 
2513 	// nothing to do here
2514 	return B_OK;
2515 }
2516 
2517 // ep_move_child
2518 static status_t
2519 ep_move_child(int fd, partition_id partitionID, partition_id childID,
2520 	off_t offset, disk_job_id job)
2521 {
2522 	TRACE(("intel: ep_move_child\n"));
2523 
2524 	if (fd < 0)
2525 		return B_ERROR;
2526 
2527 	PartitionWriteLocker locker(partitionID);
2528 	if (!locker.IsLocked())
2529 		return B_ERROR;
2530 
2531 	// get partition, child and LogicalPartition structure
2532 	partition_data *partition = get_partition(partitionID);
2533 	partition_data *child = get_partition(childID);
2534 	if (!partition || !child)
2535 		return B_BAD_VALUE;
2536 	LogicalPartition *logical = (LogicalPartition*)child->cookie;
2537 	if (!logical)
2538 		return B_BAD_VALUE;
2539 
2540 // TODO: The parameter has already been checked and must not be altered!
2541 	off_t validatedOffset = offset;
2542 	if (!ep_validate_move_child(partition, child, &validatedOffset))
2543 		return B_BAD_VALUE;
2544 
2545 	// if the old offset is the same, there is nothing to do
2546 	if (child->offset == validatedOffset)
2547 		return B_OK;
2548 
2549 	off_t diffOffset = validatedOffset - child->offset;
2550 
2551 	// buffer allocation
2552 	int32 allocated;
2553 	uint8 *buffer = allocate_buffer(partition->block_size, MAX_MOVE_BUFFER, &allocated);
2554 	if (!buffer)
2555 		return B_NO_MEMORY;
2556 
2557 	// partition moving
2558 	update_disk_device_job_progress(job, 0.0);
2559 	status_t error = B_OK;
2560 	// move partition with its header (PTS table)
2561 	off_t pts_offset = logical->Offset() - logical->PTSOffset();
2562 	error = move_partition(fd, child->offset - pts_offset, validatedOffset - pts_offset,
2563 						   child->size + pts_offset, buffer,
2564 						   allocated * partition->block_size, job);
2565 	delete[] buffer;
2566 	if (error != B_OK)
2567 		return error;
2568 
2569 	// partition moved
2570 	// updating data structure
2571 	child->offset = validatedOffset;
2572 	logical->SetOffset(logical->Offset() + diffOffset);
2573 	logical->SetPTSOffset(logical->PTSOffset() + diffOffset);
2574 
2575 	PartitionMapWriter writer(fd, partition->offset, partition->size, partition->block_size);
2576 // TODO: The partition is not supposed to be locked here!
2577 	error = writer.WriteLogical(NULL, logical);
2578 	if (error != B_OK)
2579 		// something went wrong - this is fatal (partition has been moved)
2580 		// but EBR is not updated
2581 		return error;
2582 	LogicalPartition *prev = logical->Previous();
2583 	error = prev ? writer.WriteLogical(NULL, prev)
2584 				 : writer.WriteExtendedHead(NULL, logical);
2585 	if (error != B_OK)
2586 		// this is fatal - linked list is not updated
2587 		return error;
2588 
2589 	// all changes applied
2590 	update_disk_device_job_progress(job, 1.0);
2591 	partition_modified(childID);
2592 	return B_OK;
2593 }
2594 
2595 // ep_set_type
2596 static status_t
2597 ep_set_type(int fd, partition_id partitionID, const char *type, disk_job_id job)
2598 {
2599 	TRACE(("intel: ep_set_type\n"));
2600 
2601 	if (fd < 0 || !type)
2602 		return B_BAD_VALUE;
2603 
2604 	PartitionWriteLocker locker(partitionID);
2605 	if (!locker.IsLocked())
2606 		return B_ERROR;
2607 
2608 	// get partition, child and LogicalPartition structure
2609 	partition_data *partition = get_parent_partition(partitionID);
2610 	partition_data *child = get_partition(partitionID);
2611 	if (!partition || !child)
2612 		return B_BAD_VALUE;
2613 	LogicalPartition *logical = (LogicalPartition*)child->cookie;
2614 	if (!logical)
2615 		return B_BAD_VALUE;
2616 
2617 // TODO: The parameter has already been checked and must not be altered!
2618 	if (!ep_validate_set_type(child, type))
2619 		return B_BAD_VALUE;
2620 
2621 	// if the old type is the same, there is nothing to do
2622 	if (child->type && !strcmp(type, child->type))
2623 		return B_OK;
2624 
2625 	PartitionType ptype;
2626 	ptype.SetType(type);
2627 	// this is impossible
2628 	if (!ptype.IsValid() || ptype.IsEmpty() || ptype.IsExtended())
2629 		return false;
2630 
2631 	// setting type to the partition
2632 	update_disk_device_job_progress(job, 0.0);
2633 	uint8 oldType = logical->Type();
2634 	logical->SetType(ptype.Type());
2635 
2636 	PartitionMapWriter writer(fd, partition->offset, partition->size,
2637 		partition->block_size);
2638 // TODO: The partition is not supposed to be locked here!
2639 	status_t error = writer.WriteLogical(NULL, logical);
2640 	if (error != B_OK) {
2641 		// something went wrong - putting into previous state
2642 		logical->SetType(oldType);
2643 		return error;
2644 	}
2645 
2646 	free(child->type);
2647 	child->type = strdup(type);
2648 	if (!child->type)
2649 		return B_NO_MEMORY;
2650 
2651 	// all changes applied
2652 	update_disk_device_job_progress(job, 1.0);
2653 	partition_modified(partitionID);
2654 	return B_OK;
2655 }
2656 
2657 // ep_initialize
2658 static status_t
2659 ep_initialize(int fd, partition_id partitionID, const char *name,
2660 			  const char *parameters, disk_job_id job)
2661 {
2662 	TRACE(("intel: ep_initialize\n"));
2663 
2664 	if (fd < 0)
2665 		return B_ERROR;
2666 
2667 	PartitionWriteLocker locker(partitionID);
2668 	if (!locker.IsLocked())
2669 		return B_ERROR;
2670 
2671 	// get partition
2672 	partition_data *partition = get_partition(partitionID);
2673 	if (!partition)
2674 		return B_BAD_VALUE;
2675 
2676 	// name is ignored - we cannot set it to the Intel Extended Partition
2677 // TODO: The parameter has already been checked and must not be altered!
2678 	if (!ep_validate_initialize(partition, NULL, parameters))
2679 		return B_BAD_VALUE;
2680 
2681 	// partition init (we have no child partition)
2682 	update_disk_device_job_progress(job, 0.0);
2683 	PrimaryPartition *primary = (PrimaryPartition*)partition->cookie;
2684 	// fill in the partition_data structure
2685 	partition->status = B_PARTITION_VALID;
2686 	partition->flags |= B_PARTITION_PARTITIONING_SYSTEM;
2687 	partition->content_size = partition->size;
2688 	// (no content_name and content_parameters)
2689 	// (content_type is set by the system)
2690 	partition->content_cookie = primary;
2691 
2692 	// we delete code area in EBR - nothing should be there
2693 	partition_table_sector pts;
2694 	pts.clear_code_area();
2695 
2696 	PartitionMapWriter writer(fd, partition->offset, partition->size, partition->block_size);
2697 // TODO: The partition is not supposed to be locked here!
2698 	status_t error = writer.WriteExtendedHead((uint8*)&pts, NULL);
2699 	if (error != B_OK)
2700 		return error;
2701 
2702 	// all changes applied
2703 	update_disk_device_job_progress(job, 1.0);
2704 	partition_modified(partitionID);
2705 	return B_OK;
2706 }
2707 
2708 // ep_create_child
2709 /*!
2710 	childID is used for the return value, but is also an optional input
2711 	parameter -- -1 to be ignored
2712 */
2713 static status_t
2714 ep_create_child(int fd, partition_id partitionID, off_t offset, off_t size,
2715 	const char *type, const char *parameters, disk_job_id job,
2716 	partition_id *childID)
2717 {
2718 	TRACE(("intel: ep_create_child\n"));
2719 
2720 	if (fd < 0 || !childID)
2721 		return B_BAD_VALUE;
2722 
2723 	PartitionWriteLocker locker(partitionID);
2724 	if (!locker.IsLocked())
2725 		return B_ERROR;
2726 
2727 	// get parent, partition and PrimaryPartition structure
2728 	partition_data *parent = get_parent_partition(partitionID);
2729 	partition_data *partition = get_partition(partitionID);
2730 	if (!parent || !partition)
2731 		return B_BAD_VALUE;
2732 	PrimaryPartition *primary = (PrimaryPartition*)partition->cookie;
2733 	if (!primary)
2734 		return B_BAD_VALUE;
2735 
2736 	// validate the offset, size and get index of the new partition
2737 // TODO: The parameter has already been checked and must not be altered!
2738 	off_t validatedOffset = offset;
2739 	off_t validatedSize = size;
2740 	int32 index = 0;
2741 
2742 	if (!ep_validate_create_child(partition, &validatedOffset, &validatedSize,
2743 			type, parameters, &index)) {
2744 		return B_BAD_VALUE;
2745 	}
2746 
2747 	LogicalPartition *logical = new(nothrow) LogicalPartition;
2748 	if (!logical)
2749 		return B_NO_MEMORY;
2750 
2751 	// creating partition
2752 	update_disk_device_job_progress(job, 0.0);
2753 	partition_data *child = create_child_partition(partition->id, index,
2754 		*childID);
2755 	if (!child)
2756 		return B_ERROR;
2757 
2758 	PartitionType ptype;
2759 	ptype.SetType(type);
2760 
2761 	logical->SetPTSOffset(validatedOffset - PTS_OFFSET * partition->block_size
2762 		- partition->offset);
2763 	logical->SetOffset(validatedOffset - partition->offset);
2764 	logical->SetSize(validatedSize);
2765 	logical->SetType(ptype.Type());
2766 	// TODO: correctly fill active parameter
2767 	logical->SetActive(false);
2768 
2769 	// we delete code area in EBR - nothing should be there
2770 	partition_table_sector pts;
2771 	pts.clear_code_area();
2772 
2773 	// write changes to disk
2774 	PartitionMapWriter writer(fd, partition->offset, partition->size,
2775 		partition->block_size);
2776 // TODO: The partition is not supposed to be locked here!
2777 	status_t error = writer.WriteLogical((uint8*)&pts, logical);
2778 	if (error != B_OK) {
2779 		// putting into previous state
2780 		delete_partition(child->id);
2781 		delete logical;
2782 		return error;
2783 	}
2784 	// update linked list
2785 	primary->AddLogicalPartition(logical);
2786 	LogicalPartition *prev = logical->Previous();
2787 	error = prev ? writer.WriteLogical(NULL, prev)
2788 		: writer.WriteExtendedHead(NULL, logical);
2789 	if (error != B_OK) {
2790 		// putting into previous state
2791 		delete_partition(child->id);
2792 		primary->RemoveLogicalPartition(logical);
2793 		delete logical;
2794 		return error;
2795 	}
2796 
2797 	*childID = child->id;
2798 
2799 	child->offset = partition->offset + logical->Offset();
2800 	child->size = logical->Size();
2801 	child->block_size = partition->block_size;
2802 	// (no name)
2803 	child->type = strdup(type);
2804 	// parameters
2805 	child->parameters = strdup(parameters);
2806 	child->cookie = logical;
2807 	// check for allocation problems
2808 	if (!child->type || !child->parameters)
2809 		error = B_NO_MEMORY;
2810 
2811 	// all changes applied
2812 	update_disk_device_job_progress(job, 1.0);
2813 	partition_modified(partitionID);
2814 	return B_OK;
2815 }
2816 
2817 // ep_delete_child
2818 static status_t
2819 ep_delete_child(int fd, partition_id partitionID, partition_id childID,
2820 	disk_job_id job)
2821 {
2822 	TRACE(("intel: ep_delete_child\n"));
2823 
2824 	if (fd < 0)
2825 		return B_ERROR;
2826 
2827 	PartitionWriteLocker locker(partitionID);
2828 	if (!locker.IsLocked())
2829 		return B_ERROR;
2830 
2831 	partition_data *partition = get_partition(partitionID);
2832 	partition_data *child = get_partition(childID);
2833 	if (!partition || !child)
2834 		return B_BAD_VALUE;
2835 
2836 	if (!ep_supports_deleting_child(partition, child))
2837 		return B_ERROR;
2838 
2839 	PrimaryPartition *primary = (PrimaryPartition*)partition->cookie;
2840 	LogicalPartition *logical = (LogicalPartition*)child->cookie;
2841 	if (!primary || !logical)
2842 		return B_BAD_VALUE;
2843 
2844 	// deleting child
2845 	update_disk_device_job_progress(job, 0.0);
2846 	if (!delete_partition(childID))
2847 		return B_ERROR;
2848 
2849 	LogicalPartition *next_logical = logical->Next();
2850 	LogicalPartition *prev_logical = logical->Previous();
2851 	primary->RemoveLogicalPartition(logical);
2852 	delete logical;
2853 
2854 	// write changes to disk
2855 	PartitionMapWriter writer(fd, partition->offset, partition->size, partition->block_size);
2856 // TODO: The partition is not supposed to be locked here!
2857 	status_t error = prev_logical ? writer.WriteLogical(NULL, prev_logical)
2858 		: writer.WriteExtendedHead(NULL, next_logical);
2859 	if (error != B_OK)
2860 		return error;
2861 
2862 	// all changes applied
2863 	update_disk_device_job_progress(job, 1.0);
2864 	partition_modified(partitionID);
2865 	return B_OK;
2866 }
2867 
2868 #endif	// !_BOOT_MODE
2869