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