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