xref: /haiku/src/add-ons/kernel/partitioning_systems/intel/write_support.cpp (revision 9760dcae2038d47442f4658c2575844c6cf92c40)
1 /*
2  * Copyright 2003-2009, 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 #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: %ld\n", actualCount));
683 
684 	*_actualCount = actualCount;
685 
686 	if (count < actualCount)
687 		return B_BUFFER_OVERFLOW;
688 	return B_OK;
689 }
690 
691 
692 // pm_get_partitionable_spaces
693 status_t
694 pm_get_partitionable_spaces(partition_data* partition,
695 	partitionable_space_data* buffer, int32 count, int32* actualCount)
696 {
697 	TRACE(("intel: pm_get_partitionable_spaces\n"));
698 
699 	if (!partition || !partition->content_type
700 		|| strcmp(partition->content_type, kPartitionTypeIntel)
701 		|| !actualCount) {
702 		return B_BAD_VALUE;
703 	}
704 	if (count > 0 && !buffer)
705 		return B_BAD_VALUE;
706 
707 	return get_partitionable_spaces(partition, buffer, count, actualCount,
708 		fill_partitionable_spaces_buffer_pm, MBR_OFFSET * partition->block_size,
709 		0, 0);
710 }
711 
712 
713 // pm_get_next_supported_type
714 status_t
715 pm_get_next_supported_type(partition_data* partition, int32* cookie,
716 	char* _type)
717 {
718 	TRACE(("intel: pm_get_next_supported_type\n"));
719 
720 	if (!partition || !partition->content_type
721 		|| strcmp(partition->content_type, kPartitionTypeIntel)
722 		|| !cookie || !_type) {
723 		return B_BAD_VALUE;
724 	}
725 
726 	if (*cookie > 255)
727 		return B_ENTRY_NOT_FOUND;
728 	if (*cookie < 1)
729 		*cookie = 1;
730 
731 	uint8 type = *cookie;
732 
733 	// get type
734 	PartitionType ptype;
735 	ptype.SetType(type);
736 	if (!ptype.IsValid())
737 		return B_ENTRY_NOT_FOUND;
738 
739 	ptype.GetTypeString(_type);
740 
741 	// find next type
742 	if (ptype.FindNext())
743 		*cookie = ptype.Type();
744 	else
745 		*cookie = 256;
746 
747 	return B_OK;
748 }
749 
750 // pm_shadow_changed
751 status_t
752 pm_shadow_changed(partition_data* partition, partition_data* child,
753 	uint32 operation)
754 {
755 	TRACE(("intel: pm_shadow_changed(%p, %p, %lu)\n", partition, child,
756 		operation));
757 
758 	switch (operation) {
759 		case B_PARTITION_SHADOW:
760 		{
761 			// get the physical partition
762 			partition_data* physicalPartition = get_partition(
763 				partition->id);
764 			if (!physicalPartition) {
765 				dprintf("intel: pm_shadow_changed(B_PARTITION_SHADOW): no "
766 					"physical partition with ID %ld\n", partition->id);
767 				return B_ERROR;
768 			}
769 
770 			// clone the map
771 			if (!physicalPartition->content_cookie) {
772 				dprintf("intel: pm_shadow_changed(B_PARTITION_SHADOW): no "
773 					"content cookie, physical partition: %ld\n", partition->id);
774 				return B_ERROR;
775 			}
776 
777 			PartitionMapCookie* map = new(nothrow) PartitionMapCookie;
778 			if (!map)
779 				return B_NO_MEMORY;
780 
781 			status_t error = map->Assign(
782 				*(PartitionMapCookie*)physicalPartition->content_cookie);
783 			if (error != B_OK) {
784 				delete map;
785 				return error;
786 			}
787 
788 			partition->content_cookie = map;
789 
790 			return B_OK;
791 		}
792 
793 		case B_PARTITION_SHADOW_CHILD:
794 		{
795 			// get the physical child partition
796 			partition_data* physical = get_partition(child->id);
797 			if (!physical) {
798 				dprintf("intel: pm_shadow_changed(B_PARTITION_SHADOW_CHILD): "
799 					"no physical partition with ID %ld\n", child->id);
800 				return B_ERROR;
801 			}
802 
803 			if (!physical->cookie) {
804 				dprintf("intel: pm_shadow_changed(B_PARTITION_SHADOW_CHILD): "
805 					"no cookie, physical partition: %ld\n", child->id);
806 				return B_ERROR;
807 			}
808 
809 			// primary partition index
810 			int32 index = ((PrimaryPartition*)physical->cookie)->Index();
811 
812 			if (!partition->content_cookie) {
813 				dprintf("intel: pm_shadow_changed(B_PARTITION_SHADOW_CHILD): "
814 					"no content cookie, physical partition: %ld\n",
815 					partition->id);
816 				return B_ERROR;
817 			}
818 
819 			// get the primary partition
820 			PartitionMapCookie* map
821 				= ((PartitionMapCookie*)partition->content_cookie);
822 			PrimaryPartition* primary = map->PrimaryPartitionAt(index);
823 
824 			if (!primary || primary->IsEmpty()) {
825 				dprintf("intel: pm_shadow_changed(B_PARTITION_SHADOW_CHILD): "
826 					"partition %ld is empty, primary index: %ld\n", child->id,
827 					index);
828 				return B_BAD_VALUE;
829 			}
830 
831 			child->cookie = primary;
832 
833 			return B_OK;
834 		}
835 
836 		case B_PARTITION_INITIALIZE:
837 		{
838 			// create an empty partition map
839 			PartitionMapCookie* map = new(nothrow) PartitionMapCookie;
840 			if (!map)
841 				return B_NO_MEMORY;
842 
843 			partition->content_cookie = map;
844 
845 			return B_OK;
846 		}
847 
848 		case B_PARTITION_CREATE_CHILD:
849 		{
850 			if (!partition->content_cookie) {
851 				dprintf("intel: pm_shadow_changed(B_PARTITION_CREATE_CHILD): "
852 					"no content cookie, partition: %ld\n", partition->id);
853 				return B_ERROR;
854 			}
855 
856 			PartitionMapCookie* map
857 				= ((PartitionMapCookie*)partition->content_cookie);
858 
859 			// find an empty primary partition slot
860 			PrimaryPartition* primary = NULL;
861 			for (int32 i = 0; i < 4; i++) {
862 				if (map->PrimaryPartitionAt(i)->IsEmpty()) {
863 					primary = map->PrimaryPartitionAt(i);
864 					break;
865 				}
866 			}
867 
868 			if (!primary) {
869 				dprintf("intel: pm_shadow_changed(B_PARTITION_CREATE_CHILD): "
870 					"no empty primary slot, partition: %ld\n", partition->id);
871 				return B_ERROR;
872 			}
873 
874 			// apply type
875 			PartitionType type;
876 			type.SetType(child->type);
877 			if (!type.IsValid()) {
878 				dprintf("intel: pm_shadow_changed(B_PARTITION_CREATE_CHILD): "
879 					"invalid partition type, partition: %ld\n", partition->id);
880 				return B_ERROR;
881 			}
882 
883 			primary->SetType(type.Type());
884 
885 			// TODO: Apply parameters!
886 
887 			child->cookie = primary;
888 
889 			return B_OK;
890 		}
891 
892 		case B_PARTITION_DEFRAGMENT:
893 		case B_PARTITION_REPAIR:
894 		case B_PARTITION_RESIZE:
895 		case B_PARTITION_RESIZE_CHILD:
896 		case B_PARTITION_MOVE:
897 		case B_PARTITION_MOVE_CHILD:
898 		case B_PARTITION_SET_NAME:
899 		case B_PARTITION_SET_CONTENT_NAME:
900 		case B_PARTITION_SET_TYPE:
901 		case B_PARTITION_SET_PARAMETERS:
902 		case B_PARTITION_SET_CONTENT_PARAMETERS:
903 		case B_PARTITION_DELETE_CHILD:
904 			break;
905 	}
906 
907 	return B_ERROR;
908 }
909 
910 
911 // #pragma mark - Intel Partition Map - writing functions
912 
913 
914 // pm_resize
915 status_t
916 pm_resize(int fd, partition_id partitionID, off_t size, disk_job_id job)
917 {
918 	TRACE(("intel: pm_resize\n"));
919 
920 	if (fd < 0)
921 		return B_ERROR;
922 
923 	PartitionWriteLocker locker(partitionID);
924 	if (!locker.IsLocked())
925 		return B_ERROR;
926 
927 	// get out partition
928 	partition_data* partition = get_partition(partitionID);
929 	if (!partition)
930 		return B_BAD_VALUE;
931 
932 	// validate the new size
933 // TODO: The parameter has already been checked and must not be altered!
934 	off_t validatedSize = size;
935 	if (!pm_validate_resize(partition, &validatedSize))
936 		return B_BAD_VALUE;
937 
938 	// update data stuctures
939 	update_disk_device_job_progress(job, 0.0);
940 
941 // TODO: partition->size is not supposed to be touched.
942 	partition->size = validatedSize;
943 	partition->content_size = validatedSize;
944 
945 	// all changes applied
946 	update_disk_device_job_progress(job, 1.0);
947 	partition_modified(partitionID);
948 	return B_OK;
949 }
950 
951 
952 // pm_resize_child
953 status_t
954 pm_resize_child(int fd, partition_id partitionID, off_t size, disk_job_id job)
955 {
956 	TRACE(("intel: pm_resize_child\n"));
957 
958 	if (fd < 0)
959 		return B_ERROR;
960 
961 	PartitionWriteLocker locker(partitionID);
962 	if (!locker.IsLocked())
963 		return B_ERROR;
964 
965 	// get out partition, child and partition map structure
966 	partition_data* partition = get_parent_partition(partitionID);
967 	partition_data* child = get_partition(partitionID);
968 	if (!partition || !child)
969 		return B_BAD_VALUE;
970 	PartitionMap* map = (PartitionMap*)partition->content_cookie;
971 	PrimaryPartition* primary = (PrimaryPartition*)child->cookie;
972 	if (!map || !primary)
973 		return B_BAD_VALUE;
974 
975 	// validate the new size
976 // TODO: The parameter has already been checked and must not be altered!
977 	off_t validatedSize = size;
978 	if (!pm_validate_resize_child(partition, child, &validatedSize))
979 		return B_BAD_VALUE;
980 	if (child->size == validatedSize)
981 		return B_OK;
982 
983 	// update data stuctures and write changes
984 	update_disk_device_job_progress(job, 0.0);
985 	primary->SetSize(validatedSize);
986 
987 // TODO: The partition is not supposed to be locked here!
988 	PartitionMapWriter writer(fd, primary->BlockSize());
989 		// TODO: disk size?
990 	status_t error = writer.WriteMBR(map, false);
991 	if (error != B_OK) {
992 		// putting into previous state
993 		primary->SetSize(child->size);
994 		return error;
995 	}
996 
997 	child->size = validatedSize;
998 
999 	// all changes applied
1000 	update_disk_device_job_progress(job, 1.0);
1001 	partition_modified(partitionID);
1002 	return B_OK;
1003 }
1004 
1005 
1006 // pm_move
1007 status_t
1008 pm_move(int fd, partition_id partitionID, off_t offset, disk_job_id job)
1009 {
1010 	TRACE(("intel: pm_move\n"));
1011 
1012 	if (fd < 0)
1013 		return B_ERROR;
1014 
1015 // TODO: Should be a no-op!
1016 
1017 	PartitionWriteLocker locker(partitionID);
1018 	if (!locker.IsLocked())
1019 		return B_ERROR;
1020 
1021 	// get out partition
1022 	partition_data* partition = get_partition(partitionID);
1023 	if (!partition)
1024 		return B_BAD_VALUE;
1025 
1026 	// validate the new start
1027 	if (!pm_validate_move(partition, &offset))
1028 		return B_BAD_VALUE;
1029 
1030 	// nothing to do here
1031 	return B_OK;
1032 }
1033 
1034 
1035 // allocate_buffer (auxiliary function)
1036 /*!
1037 	tries to allocate buffer with the size: blockSize * tryAlloc
1038 	if it's not possible, tries smaller buffer (until the size: blockSize * 1)
1039 	returns pointer to the buffer (it's size is: blockSize * allocated)
1040 	or returns NULL - B_NO_MEMORY
1041 */
1042 static uint8*
1043 allocate_buffer(uint32 blockSize, int32 tryAlloc, int32* allocated)
1044 {
1045 	uint8* buffer = NULL;
1046 	for (int32 i = tryAlloc; i > 1; i /= 2) {
1047 		buffer = new(nothrow) uint8[i * blockSize];
1048 		if (buffer) {
1049 			*allocated = i;
1050 			return buffer;
1051 		}
1052 	}
1053 	*allocated = 0;
1054 	return NULL;
1055 }
1056 
1057 
1058 // move_block (auxiliary function)
1059 static status_t
1060 move_block(int fd, off_t fromOffset, off_t toOffset, uint8* buffer, int32 size)
1061 {
1062 	status_t error = B_OK;
1063 	// read block to buffer
1064 	if (read_pos(fd, fromOffset, buffer, size) != size) {
1065 		error = errno;
1066 		if (error == B_OK)
1067 			error = B_IO_ERROR;
1068 		TRACE(("intel: move_block(): reading failed: %lx\n", error));
1069 		return error;
1070 	}
1071 
1072 	// write block from buffer
1073 	if (write_pos(fd, toOffset, buffer, size) != size) {
1074 		error = errno;
1075 		if (error == B_OK)
1076 			error = B_IO_ERROR;
1077 		TRACE(("intel: move_block(): writing failed: %lx\n", error));
1078 	}
1079 
1080 	return error;
1081 }
1082 
1083 
1084 // move_partition (auxiliary function)
1085 static status_t
1086 move_partition(int fd, off_t fromOffset, off_t toOffset, off_t size,
1087 	uint8* buffer, int32 buffer_size, disk_job_id job)
1088 {
1089 	// TODO: This should be a service function of the DDM!
1090 	// TODO: This seems to be broken if source and destination overlap.
1091 	status_t error = B_OK;
1092 	off_t cycleCount = size / buffer_size;
1093 	int32 remainingSize = size - cycleCount * buffer_size;
1094 	update_disk_device_job_progress(job, 0.0);
1095 	for (off_t i = 0; i < cycleCount; i++) {
1096 		error = move_block(fd, fromOffset, toOffset, buffer, buffer_size);
1097 		if (error != B_OK)
1098 			return error;
1099 		fromOffset += buffer_size;
1100 		toOffset += buffer_size;
1101 		update_disk_device_job_progress(job, (float)i / cycleCount);
1102 	}
1103 	if (remainingSize)
1104 		error = move_block(fd, fromOffset, toOffset, buffer, remainingSize);
1105 	update_disk_device_job_progress(job, 1.0);
1106 	return error;
1107 }
1108 
1109 
1110 // pm_move_child
1111 status_t
1112 pm_move_child(int fd, partition_id partitionID, partition_id childID,
1113 	off_t offset, disk_job_id job)
1114 {
1115 	TRACE(("intel: pm_move_child\n"));
1116 
1117 	if (fd < 0)
1118 		return B_ERROR;
1119 
1120 	PartitionWriteLocker locker(partitionID);
1121 	if (!locker.IsLocked())
1122 		return B_ERROR;
1123 
1124 	// get partition, child and partition map structure
1125 	partition_data* partition = get_partition(partitionID);
1126 	partition_data* child = get_partition(childID);
1127 	if (!partition || !child)
1128 		return B_BAD_VALUE;
1129 	PartitionMap* map = (PartitionMap*)partition->content_cookie;
1130 	PrimaryPartition* primary = (PrimaryPartition*)child->cookie;
1131 	if (!map || !primary)
1132 		return B_BAD_VALUE;
1133 
1134 	// TODO: The parameter has already been checked and must not be altered!
1135 	off_t validatedOffset = offset;
1136 	if (!pm_validate_move_child(partition, child, &validatedOffset))
1137 		return B_BAD_VALUE;
1138 
1139 	// if the old offset is the same, there is nothing to do
1140 	if (child->offset == validatedOffset)
1141 		return B_OK;
1142 
1143 	// buffer allocation
1144 	int32 allocated;
1145 	uint8* buffer = allocate_buffer(partition->block_size, MAX_MOVE_BUFFER,
1146 		&allocated);
1147 	if (!buffer)
1148 		return B_NO_MEMORY;
1149 
1150 	// partition moving
1151 	// TODO: The partition is not supposed to be locked at this point!
1152 	update_disk_device_job_progress(job, 0.0);
1153 	status_t error = B_OK;
1154 	error = move_partition(fd, child->offset, validatedOffset, child->size,
1155 		buffer, allocated * partition->block_size, job);
1156 	delete[] buffer;
1157 	if (error != B_OK)
1158 		return error;
1159 
1160 	// partition moved
1161 	// updating data structure
1162 	child->offset = validatedOffset;
1163 	primary->SetOffset(validatedOffset);
1164 
1165 	PartitionMapWriter writer(fd, partition->block_size);
1166 		// TODO: disk size?
1167 	error = writer.WriteMBR(map, false);
1168 	if (error != B_OK)
1169 		// something went wrong - this is fatal (partition has been moved)
1170 		// but MBR is not updated
1171 		return error;
1172 
1173 	// all changes applied
1174 	update_disk_device_job_progress(job, 1.0);
1175 	partition_modified(childID);
1176 	return B_OK;
1177 }
1178 
1179 
1180 // pm_set_type
1181 status_t
1182 pm_set_type(int fd, partition_id partitionID, const char* type, disk_job_id job)
1183 {
1184 	TRACE(("intel: pm_set_type\n"));
1185 
1186 	if (fd < 0 || !type)
1187 		return B_BAD_VALUE;
1188 
1189 	PartitionWriteLocker locker(partitionID);
1190 	if (!locker.IsLocked())
1191 		return B_ERROR;
1192 
1193 	// get parent partition, child and partition map structure
1194 	partition_data* partition = get_parent_partition(partitionID);
1195 	partition_data* child = get_partition(partitionID);
1196 	if (!partition || !child)
1197 		return B_BAD_VALUE;
1198 	PartitionMap* map = (PartitionMap*)partition->content_cookie;
1199 	PrimaryPartition* primary = (PrimaryPartition*)child->cookie;
1200 	if (!map || !primary)
1201 		return B_BAD_VALUE;
1202 
1203 // TODO: The parameter has already been checked and must not be altered!
1204 	if (!pm_validate_set_type(child, type))
1205 		return B_BAD_VALUE;
1206 
1207 	// if the old type is the same, there is nothing to do
1208 	if (child->type && !strcmp(type, child->type))
1209 		return B_OK;
1210 
1211 	PartitionType ptype;
1212 	ptype.SetType(type);
1213 	// this is impossible
1214 	if (!ptype.IsValid() || ptype.IsEmpty())
1215 		return false;
1216 	// TODO: Incompatible return value!
1217 
1218 	// setting type to the partition
1219 	update_disk_device_job_progress(job, 0.0);
1220 	uint8 oldType = primary->Type();
1221 	primary->SetType(ptype.Type());
1222 
1223 	// TODO: The partition is not supposed to be locked at this point!
1224 	PartitionMapWriter writer(fd, primary->BlockSize());
1225 		// TODO: disk size?
1226 	status_t error = writer.WriteMBR(map, false);
1227 	if (error != B_OK) {
1228 		// something went wrong - putting into previous state
1229 		primary->SetType(oldType);
1230 		return error;
1231 	}
1232 
1233 	free(child->type);
1234 	child->type = strdup(type);
1235 	if (!child->type)
1236 		return B_NO_MEMORY;
1237 
1238 	// all changes applied
1239 	update_disk_device_job_progress(job, 1.0);
1240 	partition_modified(partitionID);
1241 	return B_OK;
1242 }
1243 
1244 
1245 // pm_initialize
1246 status_t
1247 pm_initialize(int fd, partition_id partitionID, const char* name,
1248 	const char* parameters, off_t partitionSize, disk_job_id job)
1249 {
1250 	TRACE(("intel: pm_initialize\n"));
1251 
1252 	if (fd < 0)
1253 		return B_ERROR;
1254 
1255 	PartitionWriteLocker locker(partitionID);
1256 	if (!locker.IsLocked())
1257 		return B_ERROR;
1258 
1259 	// get partition and partition map structure
1260 	partition_data* partition = get_partition(partitionID);
1261 	if (!partition)
1262 		return B_BAD_VALUE;
1263 	update_disk_device_job_progress(job, 0.0);
1264 
1265 	// we will write an empty partition map
1266 	PartitionMap map;
1267 
1268 	// write the sector to disk
1269 	PartitionMapWriter writer(fd, partition->block_size);
1270 		// TODO: disk size or 2 * SECTOR_SIZE?
1271 	status_t error = writer.WriteMBR(&map, true);
1272 	if (error != B_OK)
1273 		return error;
1274 
1275 	// rescan partition
1276 	error = scan_partition(partitionID);
1277 	if (error != B_OK)
1278 		return error;
1279 
1280 	// all changes applied
1281 	update_disk_device_job_progress(job, 1.0);
1282 	partition_modified(partitionID);
1283 
1284 	return B_OK;
1285 }
1286 
1287 
1288 // pm_create_child
1289 /*!	childID is used for the return value, but is also an optional input
1290 	parameter -- -1 to be ignored
1291 */
1292 status_t
1293 pm_create_child(int fd, partition_id partitionID, off_t offset, off_t size,
1294 	const char* type, const char* name, const char* parameters,
1295 	disk_job_id job, partition_id* childID)
1296 {
1297 	TRACE(("intel: pm_create_child\n"));
1298 
1299 	if (fd < 0 || !childID)
1300 		return B_BAD_VALUE;
1301 
1302 	PartitionWriteLocker locker(partitionID);
1303 	if (!locker.IsLocked())
1304 		return B_ERROR;
1305 
1306 	// get partition and partition map structure
1307 	partition_data* partition = get_partition(partitionID);
1308 	if (!partition)
1309 		return B_BAD_VALUE;
1310 	PartitionMap* map = (PartitionMap*)partition->content_cookie;
1311 	if (!map)
1312 		return B_BAD_VALUE;
1313 
1314 	// validate the offset, size and get index of the new partition
1315 	// TODO: The parameters have already been checked and must not be altered!
1316 	off_t validatedOffset = offset;
1317 	off_t validatedSize = size;
1318 	int32 index = 0;
1319 
1320 	if (!pm_validate_create_child(partition, &validatedOffset, &validatedSize,
1321 			type, name, parameters, &index)) {
1322 		return B_BAD_VALUE;
1323 	}
1324 
1325 	// finding out free primary partition in the map (index from
1326 	// pm_validate_create_child)
1327 	PrimaryPartition* primary = map->PrimaryPartitionAt(index);
1328 	if (!primary->IsEmpty())
1329 		return B_BAD_DATA;
1330 
1331 	// creating partition
1332 	update_disk_device_job_progress(job, 0.0);
1333 	partition_data* child = create_child_partition(partition->id, index,
1334 		validatedOffset, validatedSize, *childID);
1335 	if (!child)
1336 		return B_ERROR;
1337 
1338 	PartitionType ptype;
1339 	ptype.SetType(type);
1340 
1341 	// check parameters
1342 	void* handle = parse_driver_settings_string(parameters);
1343 	if (handle == NULL)
1344 		return B_ERROR;
1345 
1346 	bool active = get_driver_boolean_parameter(handle, "active", false, true);
1347 	delete_driver_settings(handle);
1348 
1349 	// set the active flags to false
1350 	if (active) {
1351 		for (int i = 0; i < 4; i++) {
1352 			PrimaryPartition* partition = map->PrimaryPartitionAt(i);
1353 			partition->SetActive(false);
1354 		}
1355 	}
1356 
1357 	primary->SetPartitionTableOffset(0);
1358 	primary->SetOffset(validatedOffset);
1359 	primary->SetSize(validatedSize);
1360 	primary->SetType(ptype.Type());
1361 	primary->SetActive(active);
1362 
1363 	// write changes to disk
1364 	PartitionMapWriter writer(fd, primary->BlockSize());
1365 
1366 	// TODO: The partition is not supposed to be locked at this point!
1367 	status_t error = writer.WriteMBR(map, false);
1368 	if (error != B_OK) {
1369 		// putting into previous state
1370 		primary->Unset();
1371 		delete_partition(child->id);
1372 		return error;
1373 	}
1374 
1375 	*childID = child->id;
1376 
1377 	child->block_size = primary->BlockSize();
1378 	// (no name)
1379 	child->type = strdup(type);
1380 	// parameters
1381 	child->parameters = strdup(parameters);
1382 	child->cookie = primary;
1383 	// check for allocation problems
1384 	if (!child->type || !child->parameters)
1385 		return B_NO_MEMORY;
1386 
1387 	// rescan partition if needed
1388 	if (strcmp(type, INTEL_EXTENDED_PARTITION_NAME) == 0) {
1389 		writer.ClearExtendedHead(primary);
1390 		error = scan_partition(partitionID);
1391 		if (error != B_OK)
1392 			return error;
1393 	}
1394 
1395 	// all changes applied
1396 	update_disk_device_job_progress(job, 1.0);
1397 	partition_modified(partitionID);
1398 	return B_OK;
1399 }
1400 
1401 
1402 // pm_delete_child
1403 status_t
1404 pm_delete_child(int fd, partition_id partitionID, partition_id childID,
1405 	disk_job_id job)
1406 {
1407 	TRACE(("intel: pm_delete_child\n"));
1408 
1409 	if (fd < 0)
1410 		return B_ERROR;
1411 
1412 	PartitionWriteLocker locker(partitionID);
1413 	if (!locker.IsLocked())
1414 		return B_ERROR;
1415 
1416 	partition_data* partition = get_partition(partitionID);
1417 	partition_data* child = get_partition(childID);
1418 	if (!partition || !child)
1419 		return B_BAD_VALUE;
1420 
1421 	PartitionMap* map = (PartitionMap*)partition->content_cookie;
1422 	PrimaryPartition* primary = (PrimaryPartition*)child->cookie;
1423 	if (!map || !primary)
1424 		return B_BAD_VALUE;
1425 
1426 	// deleting child
1427 	update_disk_device_job_progress(job, 0.0);
1428 	if (!delete_partition(childID))
1429 		return B_ERROR;
1430 	primary->Unset();
1431 
1432 	// write changes to disk
1433 	PartitionMapWriter writer(fd, primary->BlockSize());
1434 		// TODO: disk size or 2 * SECTOR_SIZE?
1435 	// TODO: The partition is not supposed to be locked at this point!
1436 	status_t error = writer.WriteMBR(map, false);
1437 	if (error != B_OK)
1438 		return error;
1439 
1440 	// all changes applied
1441 	update_disk_device_job_progress(job, 1.0);
1442 	partition_modified(partitionID);
1443 	return B_OK;
1444 }
1445 
1446 
1447 // #pragma mark - Intel Extended Partition - support functions
1448 
1449 
1450 // ep_get_supported_operations
1451 uint32
1452 ep_get_supported_operations(partition_data* partition, uint32 mask)
1453 {
1454 	uint32 flags = B_DISK_SYSTEM_SUPPORTS_RESIZING
1455 		| B_DISK_SYSTEM_SUPPORTS_MOVING
1456 		| B_DISK_SYSTEM_SUPPORTS_SETTING_CONTENT_PARAMETERS;
1457 
1458 	// initializing
1459 	if (partition_data* parent = get_parent_partition(partition->id)) {
1460 		if (partition->type
1461 			&& strcmp(partition->type, kPartitionTypeIntelExtended) == 0
1462 			&& strcmp(parent->content_type, kPartitionTypeIntel) == 0) {
1463 			flags |= B_DISK_SYSTEM_SUPPORTS_INITIALIZING;
1464 		}
1465 	}
1466 
1467 	// creating child
1468 	int32 countSpaces = 0;
1469 	if (ep_get_partitionable_spaces(partition, NULL, 0, &countSpaces)
1470 			== B_BUFFER_OVERFLOW
1471 		&& countSpaces > 0) {
1472 		flags |= B_DISK_SYSTEM_SUPPORTS_CREATING_CHILD;
1473 	}
1474 
1475 	return flags;
1476 }
1477 
1478 
1479 // ep_get_supported_child_operations
1480 uint32
1481 ep_get_supported_child_operations(partition_data* partition,
1482 	partition_data* child, uint32 mask)
1483 {
1484 	return B_DISK_SYSTEM_SUPPORTS_RESIZING_CHILD
1485 		| B_DISK_SYSTEM_SUPPORTS_MOVING_CHILD
1486 		| B_DISK_SYSTEM_SUPPORTS_SETTING_TYPE
1487 		| B_DISK_SYSTEM_SUPPORTS_DELETING_CHILD;
1488 }
1489 
1490 
1491 // ep_is_sub_system_for
1492 bool
1493 ep_is_sub_system_for(partition_data* partition)
1494 {
1495 	if (partition == NULL)
1496 		return false;
1497 
1498 	TRACE(("intel: ep_is_sub_system_for(%ld: %lld, %lld, %ld, %s)\n",
1499 		partition->id, partition->offset, partition->size,
1500 		partition->block_size, partition->content_type));
1501 
1502 	// Intel Extended Partition can live in child partition of Intel Partition
1503 	// Map
1504 	return partition->content_type
1505 		&& !strcmp(partition->content_type, kPartitionTypeIntel);
1506 }
1507 
1508 
1509 // #pragma mark - Intel Extended Partition - validate functions
1510 
1511 
1512 // ep_validate_resize
1513 bool
1514 ep_validate_resize(partition_data* partition, off_t* size)
1515 {
1516 	TRACE(("intel: ep_validate_resize\n"));
1517 
1518 	if (!partition || !size)
1519 		return false;
1520 
1521 	return validate_resize(partition, size);
1522 }
1523 
1524 
1525 // ep_validate_resize_child
1526 bool
1527 ep_validate_resize_child(partition_data* partition, partition_data* child,
1528 	off_t* _size)
1529 {
1530 	TRACE(("intel: ep_validate_resize_child\n"));
1531 
1532 	if (!partition || !child || !_size)
1533 		return false;
1534 
1535 	// validate position
1536 	off_t size = *_size;
1537 	if (!validate_resize_child(partition, child, child->offset,
1538 		 child->size, &size, get_sibling_partitions_ep))
1539 		return false;
1540 	*_size = size;
1541 	return true;
1542 }
1543 
1544 
1545 // ep_validate_move
1546 bool
1547 ep_validate_move(partition_data* partition, off_t* start)
1548 {
1549 	TRACE(("intel: ep_validate_move\n"));
1550 
1551 	if (!partition || !start)
1552 		return false;
1553 	// nothing to do here
1554 	return true;
1555 }
1556 
1557 
1558 // ep_validate_move_child
1559 bool
1560 ep_validate_move_child(partition_data* partition, partition_data* child,
1561 	off_t* _start)
1562 {
1563 	TRACE(("intel: ep_validate_move_child\n"));
1564 
1565 	if (!partition || !child || !_start)
1566 		return false;
1567 	if (*_start == child->offset)
1568 		return true;
1569 
1570 	// validate position
1571 	off_t start = *_start;
1572 	if (!validate_move_child(partition, child, child->offset,
1573 		child->size, &start, get_sibling_partitions_ep))
1574 		return false;
1575 	*_start = start;
1576 	return true;
1577 }
1578 
1579 
1580 // is_type_valid_ep (auxiliary function)
1581 static inline bool
1582 is_type_valid_ep(const char* type)
1583 {
1584 	// validity check of the type - it has to be known
1585 	PartitionType ptype;
1586 	ptype.SetType(type);
1587 	return (ptype.IsValid() && !ptype.IsEmpty() && !ptype.IsExtended());
1588 }
1589 
1590 
1591 // ep_validate_set_type
1592 bool
1593 ep_validate_set_type(partition_data* partition, const char* type)
1594 {
1595 	TRACE(("intel: ep_validate_set_type\n"));
1596 
1597 	if (!partition || !type)
1598 		return false;
1599 
1600 	// validity check of the type
1601 	return is_type_valid_ep(type);
1602 }
1603 
1604 
1605 // ep_validate_initialize
1606 bool
1607 ep_validate_initialize(partition_data* partition, char* name,
1608 	const char* parameters)
1609 {
1610 	TRACE(("intel: ep_validate_initialize\n"));
1611 
1612 	if (!partition || !(ep_get_supported_operations(partition)
1613 			& B_DISK_SYSTEM_SUPPORTS_INITIALIZING)) {
1614 		return false;
1615 	}
1616 	// name is ignored - we cannot set it to the Intel Extended Partition
1617 	// TODO: check parameters - don't know whether any parameters could be set
1618 	//		 to the Intel Extended Partition
1619 	return true;
1620 }
1621 
1622 
1623 // ep_validate_create_child
1624 bool
1625 ep_validate_create_child(partition_data* partition, off_t* offset, off_t* size,
1626 	const char* type, const char* name, const char* parameters, int32* index)
1627 	// index - returns position of the new partition (the last one)
1628 {
1629 	return false;
1630 }
1631 
1632 
1633 // ep_get_partitionable_spaces
1634 status_t
1635 ep_get_partitionable_spaces(partition_data* partition,
1636 	partitionable_space_data* buffer, int32 count, int32* actualCount)
1637 {
1638 	TRACE(("intel: ep_get_partitionable_spaces\n"));
1639 
1640 	if (!partition || !partition->content_type
1641 		|| strcmp(partition->content_type, kPartitionTypeIntelExtended)
1642 		|| !actualCount) {
1643 		return B_BAD_VALUE;
1644 	}
1645 	if (count > 0 && !buffer)
1646 		return B_BAD_VALUE;
1647 
1648 	return get_partitionable_spaces(partition, buffer, count, actualCount,
1649 		fill_partitionable_spaces_buffer_ep,
1650 		partition->offset + PTS_OFFSET * partition->block_size,
1651 		PTS_OFFSET * partition->block_size,
1652 		PTS_OFFSET * partition->block_size);
1653 }
1654 
1655 
1656 // ep_get_next_supported_type
1657 status_t
1658 ep_get_next_supported_type(partition_data* partition, int32* cookie,
1659 	char* _type)
1660 {
1661 	TRACE(("intel: ep_get_next_supported_type\n"));
1662 
1663 	if (!partition || !partition->content_type
1664 		|| strcmp(partition->content_type, kPartitionTypeIntelExtended)
1665 		|| !cookie || !_type) {
1666 		return B_BAD_VALUE;
1667 	}
1668 
1669 	if (*cookie > 255)
1670 		return B_ENTRY_NOT_FOUND;
1671 	if (*cookie < 1)
1672 		*cookie = 1;
1673 
1674 	uint8 type = *cookie;
1675 
1676 	// get type
1677 	PartitionType ptype;
1678 	ptype.SetType(type);
1679 	while (ptype.IsValid() && !ptype.IsExtended())
1680 		ptype.FindNext();
1681 
1682 	if (!ptype.IsValid())
1683 		return B_ENTRY_NOT_FOUND;
1684 
1685 	ptype.GetTypeString(_type);
1686 
1687 	// find next type
1688 	if (ptype.FindNext())
1689 		*cookie = ptype.Type();
1690 	else
1691 		*cookie = 256;
1692 
1693 	return B_OK;
1694 }
1695 
1696 
1697 // ep_shadow_changed
1698 status_t
1699 ep_shadow_changed(partition_data* partition, partition_data* child,
1700 	uint32 operation)
1701 {
1702 	TRACE(("intel: ep_shadow_changed\n"));
1703 
1704 	if (!partition)
1705 		return B_BAD_VALUE;
1706 
1707 	// nothing to do here
1708 	return B_OK;
1709 }
1710 
1711 
1712 bool
1713 check_partition_location_ep(partition_data* partition, off_t offset,
1714 	off_t size, off_t ptsOffset)
1715 {
1716 	if (!partition)
1717 		return false;
1718 
1719 	// make sure we are sector aligned
1720 	off_t alignedOffset = sector_align(offset, partition->block_size);
1721 	if (alignedOffset != offset)
1722 		return false;
1723 
1724 	// partition does not lie within extended partition
1725 	if (offset < partition->offset
1726 		|| offset > partition->offset + partition->size
1727 		&& offset + size <= partition->offset + partition->size)
1728 		return false;
1729 
1730 	// check if the new partition table is within an existing partition
1731 	// or that the new partition does not overwrite an existing partition
1732 	// table.
1733 	for (int32 i = 0; i < partition->child_count; i++) {
1734 		partition_data* sibling = get_child_partition(partition->id, i);
1735 		LogicalPartition* logical = (LogicalPartition*)sibling->cookie;
1736 		if (logical == NULL)
1737 			return false;
1738 		if (ptsOffset > logical->Offset()
1739 			&& ptsOffset < logical->Offset() + logical->Size())
1740 			return false;
1741 		if (logical->PartitionTableOffset() >= offset
1742 			&& logical->PartitionTableOffset() < offset + size
1743 			|| logical->PartitionTableOffset() == ptsOffset)
1744 			return false;
1745 	}
1746 
1747 	return true;
1748 }
1749 
1750 
1751 // #pragma mark - Intel Extended Partition - write functions
1752 
1753 
1754 // ep_resize
1755 status_t
1756 ep_resize(int fd, partition_id partitionID, off_t size, disk_job_id job)
1757 {
1758 	TRACE(("intel: ep_resize\n"));
1759 
1760 	if (fd < 0)
1761 		return B_ERROR;
1762 
1763 	PartitionWriteLocker locker(partitionID);
1764 	if (!locker.IsLocked())
1765 		return B_ERROR;
1766 
1767 	// get out partition
1768 	partition_data* partition = get_partition(partitionID);
1769 	if (!partition)
1770 		return B_BAD_VALUE;
1771 
1772 	// validate the new size
1773 	// TODO: The parameter has already been checked and must not be altered!
1774 	off_t validatedSize = size;
1775 	if (!ep_validate_resize(partition, &validatedSize))
1776 		return B_BAD_VALUE;
1777 
1778 	// update data stuctures
1779 	update_disk_device_job_progress(job, 0.0);
1780 
1781 	// TODO: partition->size is not supposed to be touched.
1782 	partition->size = validatedSize;
1783 	partition->content_size = validatedSize;
1784 
1785 	// all changes applied
1786 	update_disk_device_job_progress(job, 1.0);
1787 	partition_modified(partitionID);
1788 	return B_OK;
1789 }
1790 
1791 
1792 // ep_resize_child
1793 status_t
1794 ep_resize_child(int fd, partition_id partitionID, off_t size, disk_job_id job)
1795 {
1796 	TRACE(("intel: ep_resize_child\n"));
1797 
1798 	if (fd < 0)
1799 		return B_ERROR;
1800 
1801 	PartitionWriteLocker locker(partitionID);
1802 	if (!locker.IsLocked())
1803 		return B_ERROR;
1804 
1805 	// get out partition, child and LogicalPartition structure
1806 	partition_data* partition = get_parent_partition(partitionID);
1807 	partition_data* child = get_partition(partitionID);
1808 	if (!partition || !child)
1809 		return B_BAD_VALUE;
1810 	LogicalPartition* logical = (LogicalPartition*)child->cookie;
1811 	PrimaryPartition* primary = (PrimaryPartition*)partition->cookie;
1812 	if (!logical || !primary)
1813 		return B_BAD_VALUE;
1814 
1815 	// validate the new size
1816 	// TODO: The parameter has already been checked and must not be altered!
1817 	off_t validatedSize = size;
1818 	if (!ep_validate_resize_child(partition, child, &validatedSize))
1819 		return B_BAD_VALUE;
1820 	if (child->size == validatedSize)
1821 		return B_OK;
1822 
1823 	// update data stuctures and write changes
1824 	update_disk_device_job_progress(job, 0.0);
1825 	logical->SetSize(validatedSize);
1826 
1827 	PartitionMapWriter writer(fd, partition->block_size);
1828 	// TODO: The partition is not supposed to be locked here!
1829 	status_t error = writer.WriteLogical(logical, primary, false);
1830 	if (error != B_OK) {
1831 		// putting into previous state
1832 		logical->SetSize(child->size);
1833 		return error;
1834 	}
1835 	LogicalPartition* prev = logical->Previous();
1836 	error = prev ? writer.WriteLogical(prev, primary, false)
1837 				 : writer.WriteLogical(logical, primary, false);
1838 	if (error != B_OK)
1839 		// this should be not so fatal
1840 		return error;
1841 
1842 	child->size = validatedSize;
1843 
1844 	// all changes applied
1845 	update_disk_device_job_progress(job, 1.0);
1846 	partition_modified(partitionID);
1847 	return B_OK;
1848 }
1849 
1850 
1851 // ep_move
1852 status_t
1853 ep_move(int fd, partition_id partitionID, off_t offset, disk_job_id job)
1854 {
1855 	TRACE(("intel: ep_move\n"));
1856 
1857 	if (fd < 0)
1858 		return B_ERROR;
1859 
1860 	PartitionWriteLocker locker(partitionID);
1861 	if (!locker.IsLocked())
1862 		return B_ERROR;
1863 
1864 	// get out partition
1865 	partition_data* partition = get_partition(partitionID);
1866 	if (!partition)
1867 		return B_BAD_VALUE;
1868 
1869 	// validate the new start
1870 	// TODO: The parameter has already been checked and must not be altered!
1871 	if (!ep_validate_move(partition, &offset))
1872 		return B_BAD_VALUE;
1873 
1874 	// nothing to do here
1875 	return B_OK;
1876 }
1877 
1878 
1879 // ep_move_child
1880 status_t
1881 ep_move_child(int fd, partition_id partitionID, partition_id childID,
1882 	off_t offset, disk_job_id job)
1883 {
1884 	TRACE(("intel: ep_move_child\n"));
1885 
1886 	if (fd < 0)
1887 		return B_ERROR;
1888 
1889 	PartitionWriteLocker locker(partitionID);
1890 	if (!locker.IsLocked())
1891 		return B_ERROR;
1892 
1893 	// get partition, child and LogicalPartition structure
1894 	partition_data* partition = get_partition(partitionID);
1895 	partition_data* child = get_partition(childID);
1896 	if (!partition || !child)
1897 		return B_BAD_VALUE;
1898 	LogicalPartition* logical = (LogicalPartition*)child->cookie;
1899 	PrimaryPartition* primary = (PrimaryPartition*)partition->cookie;
1900 	if (!logical || !primary)
1901 		return B_BAD_VALUE;
1902 
1903 	// TODO: The parameter has already been checked and must not be altered!
1904 	off_t validatedOffset = offset;
1905 	if (!ep_validate_move_child(partition, child, &validatedOffset))
1906 		return B_BAD_VALUE;
1907 
1908 	// if the old offset is the same, there is nothing to do
1909 	if (child->offset == validatedOffset)
1910 		return B_OK;
1911 
1912 	off_t diffOffset = validatedOffset - child->offset;
1913 
1914 	// buffer allocation
1915 	int32 allocated;
1916 	uint8* buffer = allocate_buffer(partition->block_size, MAX_MOVE_BUFFER,
1917 		&allocated);
1918 	if (!buffer)
1919 		return B_NO_MEMORY;
1920 
1921 	// partition moving
1922 	update_disk_device_job_progress(job, 0.0);
1923 	status_t error = B_OK;
1924 	// move partition with its header (partition table)
1925 	off_t pts_offset = logical->Offset() - logical->PartitionTableOffset();
1926 	error = move_partition(fd, child->offset - pts_offset,
1927 		validatedOffset - pts_offset, child->size + pts_offset, buffer,
1928 		allocated * partition->block_size, job);
1929 	delete[] buffer;
1930 	if (error != B_OK)
1931 		return error;
1932 
1933 	// partition moved
1934 	// updating data structure
1935 	child->offset = validatedOffset;
1936 	logical->SetOffset(logical->Offset() + diffOffset);
1937 	logical->SetPartitionTableOffset(logical->PartitionTableOffset() + diffOffset);
1938 
1939 	PartitionMapWriter writer(fd, partition->block_size);
1940 		// TODO: If partition->offset is > prev->offset, then writing
1941 		// the previous logical partition table will fail!
1942 	// TODO: The partition is not supposed to be locked here!
1943 	error = writer.WriteLogical(logical, primary, false);
1944 	if (error != B_OK)
1945 		// something went wrong - this is fatal (partition has been moved)
1946 		// but EBR is not updated
1947 		return error;
1948 	LogicalPartition* prev = logical->Previous();
1949 	error = prev ? writer.WriteLogical(prev, primary, false)
1950 				 : writer.WriteLogical(logical, primary, false);
1951 	if (error != B_OK)
1952 		// this is fatal - linked list is not updated
1953 		return error;
1954 
1955 	// all changes applied
1956 	update_disk_device_job_progress(job, 1.0);
1957 	partition_modified(childID);
1958 	return B_OK;
1959 }
1960 
1961 
1962 // ep_set_type
1963 status_t
1964 ep_set_type(int fd, partition_id partitionID, const char* type, disk_job_id job)
1965 {
1966 	TRACE(("intel: ep_set_type\n"));
1967 
1968 	if (fd < 0 || !type)
1969 		return B_BAD_VALUE;
1970 
1971 	PartitionWriteLocker locker(partitionID);
1972 	if (!locker.IsLocked())
1973 		return B_ERROR;
1974 
1975 	// get partition, child and LogicalPartition structure
1976 	partition_data* partition = get_parent_partition(partitionID);
1977 	partition_data* child = get_partition(partitionID);
1978 	if (!partition || !child)
1979 		return B_BAD_VALUE;
1980 	LogicalPartition* logical = (LogicalPartition*)child->cookie;
1981 	PrimaryPartition* primary = (PrimaryPartition*)partition->cookie;
1982 	if (!logical || !primary)
1983 		return B_BAD_VALUE;
1984 
1985 	// TODO: The parameter has already been checked and must not be altered!
1986 	if (!ep_validate_set_type(child, type))
1987 		return B_BAD_VALUE;
1988 
1989 	// if the old type is the same, there is nothing to do
1990 	if (child->type && !strcmp(type, child->type))
1991 		return B_OK;
1992 
1993 	PartitionType ptype;
1994 	ptype.SetType(type);
1995 	// this is impossible
1996 	if (!ptype.IsValid() || ptype.IsEmpty() || ptype.IsExtended())
1997 		return false;
1998 
1999 	// setting type to the partition
2000 	update_disk_device_job_progress(job, 0.0);
2001 	uint8 oldType = logical->Type();
2002 	logical->SetType(ptype.Type());
2003 
2004 	PartitionMapWriter writer(fd, partition->block_size);
2005 	// TODO: The partition is not supposed to be locked here!
2006 	status_t error = writer.WriteLogical(logical, primary, false);
2007 	if (error != B_OK) {
2008 		// something went wrong - putting into previous state
2009 		logical->SetType(oldType);
2010 		return error;
2011 	}
2012 
2013 	free(child->type);
2014 	child->type = strdup(type);
2015 	if (!child->type)
2016 		return B_NO_MEMORY;
2017 
2018 	// all changes applied
2019 	update_disk_device_job_progress(job, 1.0);
2020 	partition_modified(partitionID);
2021 	return B_OK;
2022 }
2023 
2024 
2025 // ep_initialize
2026 status_t
2027 ep_initialize(int fd, partition_id partitionID, const char* name,
2028 	const char* parameters, off_t partitionSize, disk_job_id job)
2029 {
2030 	TRACE(("intel: ep_initialize\n"));
2031 
2032 	if (fd < 0)
2033 		return B_ERROR;
2034 
2035 	PartitionWriteLocker locker(partitionID);
2036 	if (!locker.IsLocked())
2037 		return B_ERROR;
2038 
2039 	// get partition
2040 	partition_data* partition = get_partition(partitionID);
2041 	PrimaryPartition* primary = (PrimaryPartition*)partition->cookie;
2042 	if (!partition || !primary)
2043 		return B_BAD_VALUE;
2044 
2045 	// name is ignored - we cannot set it to the Intel Extended Partition
2046 // TODO: The parameter has already been checked and must not be altered!
2047 	if (!ep_validate_initialize(partition, NULL, parameters))
2048 		return B_BAD_VALUE;
2049 
2050 	// partition init (we have no child partition)
2051 	update_disk_device_job_progress(job, 0.0);
2052 	// fill in the partition_data structure
2053 	partition->status = B_PARTITION_VALID;
2054 	partition->flags |= B_PARTITION_PARTITIONING_SYSTEM;
2055 	partition->content_size = partition->size;
2056 	// (no content_name and content_parameters)
2057 	// (content_type is set by the system)
2058 	partition->content_cookie = primary;
2059 
2060 	// we delete code area in EBR - nothing should be there
2061 	partition_table table;
2062 	table.clear_code_area();
2063 
2064 	PartitionMapWriter writer(fd, partition->block_size);
2065 	// TODO: The partition is not supposed to be locked here!
2066 	status_t error = writer.ClearExtendedHead(primary);
2067 	if (error != B_OK)
2068 		return error;
2069 
2070 	// all changes applied
2071 	update_disk_device_job_progress(job, 1.0);
2072 	partition_modified(partitionID);
2073 	return B_OK;
2074 }
2075 
2076 
2077 // ep_create_child
2078 /*!
2079 	childID is used for the return value, but is also an optional input
2080 	parameter -- -1 to be ignored
2081 */
2082 status_t
2083 ep_create_child(int fd, partition_id partitionID, off_t offset, off_t size,
2084 	const char* type, const char* name, const char* parameters, disk_job_id job,
2085 	partition_id* childID)
2086 {
2087 	TRACE(("intel: ep_create_child\n"));
2088 
2089 	if (fd < 0 || !childID)
2090 		return B_BAD_VALUE;
2091 
2092 	// aquire lock
2093 	PartitionWriteLocker locker(partitionID);
2094 	if (!locker.IsLocked())
2095 		return B_ERROR;
2096 
2097 	// get partition data
2098 	partition_data* partition = get_partition(partitionID);
2099 	partition_data* parent = get_parent_partition(partitionID);
2100 	if (partition == NULL || parent == NULL)
2101 		return B_BAD_VALUE;
2102 
2103 	PrimaryPartition* primary = (PrimaryPartition*)partition->cookie;
2104 	if (!primary)
2105 		return B_BAD_VALUE;
2106 
2107 	// parse parameters
2108 	void* handle = parse_driver_settings_string(parameters);
2109 	if (handle == NULL)
2110 		return B_ERROR;
2111 
2112 	bool active = get_driver_boolean_parameter(handle, "active", false, true);
2113 
2114 	off_t ptsOffset = 0;
2115 	const char* buffer = get_driver_parameter(
2116 		handle, "partition_table_offset", NULL, NULL);
2117 	if (buffer != NULL)
2118 		ptsOffset = strtoull(buffer, NULL, 10);
2119 	else {
2120 		delete_driver_settings(handle);
2121 		return B_BAD_VALUE;
2122 	}
2123 	delete_driver_settings(handle);
2124 
2125 	// check the partition location
2126 	if (!check_partition_location_ep(partition, offset, size, ptsOffset))
2127 		return B_BAD_VALUE;
2128 
2129 	// creating partition
2130 	update_disk_device_job_progress(job, 0.0);
2131 	partition_data* child = create_child_partition(partition->id,
2132 		partition->child_count, offset, size, *childID);
2133 	if (!child)
2134 		return B_ERROR;
2135 
2136 	// setup logical partition
2137 	LogicalPartition* logical = new(nothrow) LogicalPartition;
2138 	if (!logical)
2139 		return B_NO_MEMORY;
2140 
2141 	PartitionType ptype;
2142 	ptype.SetType(type);
2143 	logical->SetPartitionTableOffset(ptsOffset - parent->offset);
2144 	logical->SetOffset(offset);
2145 	logical->SetSize(size);
2146 	logical->SetType(ptype.Type());
2147 	logical->SetActive(active);
2148 	logical->SetPrimaryPartition(primary);
2149 	logical->SetBlockSize(partition->block_size);
2150 	primary->AddLogicalPartition(logical);
2151 
2152 	int parentFD = open_partition(parent->id, O_RDWR);
2153 	if (parentFD < 0) {
2154 		primary->RemoveLogicalPartition(logical);
2155 		delete logical;
2156 		return B_IO_ERROR;
2157 	}
2158 
2159 	// write changes to disk
2160 	PartitionMapWriter writer(parentFD, primary->BlockSize());
2161 
2162 	// Write the logical partition's EBR first in case of failure.
2163 	// This way we will not add a partition to the previous logical
2164 	// partition. If there is no previous logical partition then write
2165 	// the current partition's EBR to the first sector of the primary partition
2166 	status_t error = writer.WriteLogical(logical, primary, true);
2167 	if (error != B_OK) {
2168 		primary->RemoveLogicalPartition(logical);
2169 		delete logical;
2170 		return error;
2171 	}
2172 
2173 	LogicalPartition* previous = logical->Previous();
2174 	if (previous != NULL) {
2175 		error = writer.WriteLogical(previous, primary, true);
2176 		if (error != B_OK) {
2177 			primary->RemoveLogicalPartition(logical);
2178 			delete logical;
2179 			return error;
2180 		}
2181 	}
2182 	*childID = child->id;
2183 
2184 	child->block_size = logical->BlockSize();
2185 	child->type = strdup(type);
2186 	child->parameters = strdup(parameters);
2187 	child->cookie = logical;
2188 	// check for allocation problems
2189 	if (!child->type || !child->parameters)
2190 		error = B_NO_MEMORY;
2191 
2192 	// all changes applied
2193 	update_disk_device_job_progress(job, 1.0);
2194 	partition_modified(partitionID);
2195 	return B_OK;
2196 }
2197 
2198 
2199 // ep_delete_child
2200 status_t
2201 ep_delete_child(int fd, partition_id partitionID, partition_id childID,
2202 	disk_job_id job)
2203 {
2204 	TRACE(("intel: ep_delete_child\n"));
2205 
2206 	if (fd < 0)
2207 		return B_ERROR;
2208 
2209 	PartitionWriteLocker locker(partitionID);
2210 	if (!locker.IsLocked())
2211 		return B_ERROR;
2212 
2213 	partition_data* partition = get_partition(partitionID);
2214 	partition_data* parent = get_parent_partition(partitionID);
2215 	partition_data* child = get_partition(childID);
2216 	if (partition == NULL || parent == NULL || child == NULL)
2217 		return B_BAD_VALUE;
2218 
2219 	PrimaryPartition* primary = (PrimaryPartition*)partition->cookie;
2220 	LogicalPartition* logical = (LogicalPartition*)child->cookie;
2221 	if (primary == NULL || logical == NULL)
2222 		return B_BAD_VALUE;
2223 
2224 	// deleting child
2225 	update_disk_device_job_progress(job, 0.0);
2226 	if (!delete_partition(childID))
2227 		return B_ERROR;
2228 
2229 	LogicalPartition* previous = logical->Previous();
2230 	LogicalPartition* next = logical->Next();
2231 
2232 	primary->RemoveLogicalPartition(logical);
2233 	delete logical;
2234 
2235 	int parentFD = open_partition(parent->id, O_RDWR);
2236 	if (parentFD < 0)
2237 		return B_IO_ERROR;
2238 
2239 	// write changes to disk
2240 	PartitionMapWriter writer(parentFD, primary->BlockSize());
2241 
2242 	status_t error;
2243 	if (previous != NULL) {
2244 		error = writer.WriteLogical(previous, primary, true);
2245 	} else {
2246 		error = writer.WriteExtendedHead(next, primary, true);
2247 
2248 		if (next != NULL) {
2249 			next->SetPartitionTableOffset(primary->Offset());
2250 
2251 			partition_data* nextSibling = NULL;
2252 			if (get_partition_from_offset_ep(partition, next->Offset(),
2253 				&nextSibling)) {
2254 				char buffer[128];
2255 				sprintf(buffer, "active %s ;\npartition_table_offset %lld ;\n",
2256 					next->Active() ? "true" : "false",
2257 					next->PartitionTableOffset());
2258 				nextSibling->parameters = strdup(buffer);
2259 			}
2260 		}
2261 	}
2262 
2263 	close(parentFD);
2264 
2265 	if (error != B_OK) {
2266 		delete logical;
2267 		return error;
2268 	}
2269 
2270 	// all changes applied
2271 	update_disk_device_job_progress(job, 1.0);
2272 	partition_modified(partitionID);
2273 	return B_OK;
2274 }
2275 
2276