xref: /haiku/src/add-ons/kernel/partitioning_systems/intel/write_support.cpp (revision 7a74a5df454197933bc6e80a542102362ee98703)
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: %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 status_t
1289 pm_uninitialize(int fd, partition_id partitionID, off_t partitionSize,
1290 	uint32 blockSize, disk_job_id job)
1291 {
1292 	if (blockSize == 0)
1293 		return B_BAD_VALUE;
1294 
1295 	// We overwrite the first block, which contains the partition table.
1296 	// Allocate a buffer, we can clear and write.
1297 	void* block = malloc(blockSize);
1298 	if (block == NULL)
1299 		return B_NO_MEMORY;
1300 	MemoryDeleter blockDeleter(block);
1301 
1302 	memset(block, 0, blockSize);
1303 
1304 	if (write_pos(fd, 0, block, blockSize) < 0)
1305 		return errno;
1306 
1307 	update_disk_device_job_progress(job, 1.0);
1308 
1309 	return B_OK;
1310 }
1311 
1312 
1313 // pm_create_child
1314 /*!	childID is used for the return value, but is also an optional input
1315 	parameter -- -1 to be ignored
1316 */
1317 status_t
1318 pm_create_child(int fd, partition_id partitionID, off_t offset, off_t size,
1319 	const char* type, const char* name, const char* parameters,
1320 	disk_job_id job, partition_id* childID)
1321 {
1322 	TRACE(("intel: pm_create_child\n"));
1323 
1324 	if (fd < 0 || !childID)
1325 		return B_BAD_VALUE;
1326 
1327 	PartitionWriteLocker locker(partitionID);
1328 	if (!locker.IsLocked())
1329 		return B_ERROR;
1330 
1331 	// get partition and partition map structure
1332 	partition_data* partition = get_partition(partitionID);
1333 	if (!partition)
1334 		return B_BAD_VALUE;
1335 	PartitionMap* map = (PartitionMap*)partition->content_cookie;
1336 	if (!map)
1337 		return B_BAD_VALUE;
1338 
1339 	// validate the offset, size and get index of the new partition
1340 	// TODO: The parameters have already been checked and must not be altered!
1341 	off_t validatedOffset = offset;
1342 	off_t validatedSize = size;
1343 	int32 index = 0;
1344 
1345 	if (!pm_validate_create_child(partition, &validatedOffset, &validatedSize,
1346 			type, name, parameters, &index)) {
1347 		return B_BAD_VALUE;
1348 	}
1349 
1350 	// finding out free primary partition in the map (index from
1351 	// pm_validate_create_child)
1352 	PrimaryPartition* primary = map->PrimaryPartitionAt(index);
1353 	if (!primary->IsEmpty())
1354 		return B_BAD_DATA;
1355 
1356 	// creating partition
1357 	update_disk_device_job_progress(job, 0.0);
1358 	partition_data* child = create_child_partition(partition->id, index,
1359 		validatedOffset, validatedSize, *childID);
1360 	if (!child)
1361 		return B_ERROR;
1362 
1363 	PartitionType ptype;
1364 	ptype.SetType(type);
1365 
1366 	// check parameters
1367 	void* handle = parse_driver_settings_string(parameters);
1368 	if (handle == NULL)
1369 		return B_ERROR;
1370 
1371 	bool active = get_driver_boolean_parameter(handle, "active", false, true);
1372 	delete_driver_settings(handle);
1373 
1374 	// set the active flags to false
1375 	if (active) {
1376 		for (int i = 0; i < 4; i++) {
1377 			PrimaryPartition* partition = map->PrimaryPartitionAt(i);
1378 			partition->SetActive(false);
1379 		}
1380 	}
1381 
1382 	primary->SetPartitionTableOffset(0);
1383 	primary->SetOffset(validatedOffset);
1384 	primary->SetSize(validatedSize);
1385 	primary->SetType(ptype.Type());
1386 	primary->SetActive(active);
1387 
1388 	// write changes to disk
1389 	PartitionMapWriter writer(fd, primary->BlockSize());
1390 
1391 	// TODO: The partition is not supposed to be locked at this point!
1392 	status_t error = writer.WriteMBR(map, false);
1393 	if (error != B_OK) {
1394 		// putting into previous state
1395 		primary->Unset();
1396 		delete_partition(child->id);
1397 		return error;
1398 	}
1399 
1400 	*childID = child->id;
1401 
1402 	child->block_size = primary->BlockSize();
1403 	// (no name)
1404 	child->type = strdup(type);
1405 	// parameters
1406 	child->parameters = strdup(parameters);
1407 	child->cookie = primary;
1408 	// check for allocation problems
1409 	if (!child->type || !child->parameters)
1410 		return B_NO_MEMORY;
1411 
1412 	// rescan partition if needed
1413 	if (strcmp(type, INTEL_EXTENDED_PARTITION_NAME) == 0) {
1414 		writer.ClearExtendedHead(primary);
1415 		error = scan_partition(partitionID);
1416 		if (error != B_OK)
1417 			return error;
1418 	}
1419 
1420 	// all changes applied
1421 	update_disk_device_job_progress(job, 1.0);
1422 	partition_modified(partitionID);
1423 	return B_OK;
1424 }
1425 
1426 
1427 // pm_delete_child
1428 status_t
1429 pm_delete_child(int fd, partition_id partitionID, partition_id childID,
1430 	disk_job_id job)
1431 {
1432 	TRACE(("intel: pm_delete_child\n"));
1433 
1434 	if (fd < 0)
1435 		return B_ERROR;
1436 
1437 	PartitionWriteLocker locker(partitionID);
1438 	if (!locker.IsLocked())
1439 		return B_ERROR;
1440 
1441 	partition_data* partition = get_partition(partitionID);
1442 	partition_data* child = get_partition(childID);
1443 	if (!partition || !child)
1444 		return B_BAD_VALUE;
1445 
1446 	PartitionMap* map = (PartitionMap*)partition->content_cookie;
1447 	PrimaryPartition* primary = (PrimaryPartition*)child->cookie;
1448 	if (!map || !primary)
1449 		return B_BAD_VALUE;
1450 
1451 	// deleting child
1452 	update_disk_device_job_progress(job, 0.0);
1453 	if (!delete_partition(childID))
1454 		return B_ERROR;
1455 	primary->Unset();
1456 
1457 	// write changes to disk
1458 	PartitionMapWriter writer(fd, primary->BlockSize());
1459 		// TODO: disk size or 2 * SECTOR_SIZE?
1460 	// TODO: The partition is not supposed to be locked at this point!
1461 	status_t error = writer.WriteMBR(map, false);
1462 	if (error != B_OK)
1463 		return error;
1464 
1465 	// all changes applied
1466 	update_disk_device_job_progress(job, 1.0);
1467 	partition_modified(partitionID);
1468 	return B_OK;
1469 }
1470 
1471 
1472 // #pragma mark - Intel Extended Partition - support functions
1473 
1474 
1475 // ep_get_supported_operations
1476 uint32
1477 ep_get_supported_operations(partition_data* partition, uint32 mask)
1478 {
1479 	uint32 flags = B_DISK_SYSTEM_SUPPORTS_RESIZING
1480 		| B_DISK_SYSTEM_SUPPORTS_MOVING
1481 		| B_DISK_SYSTEM_SUPPORTS_SETTING_CONTENT_PARAMETERS;
1482 
1483 	// initializing
1484 	if (partition_data* parent = get_parent_partition(partition->id)) {
1485 		if (partition->type
1486 			&& strcmp(partition->type, kPartitionTypeIntelExtended) == 0
1487 			&& strcmp(parent->content_type, kPartitionTypeIntel) == 0) {
1488 			flags |= B_DISK_SYSTEM_SUPPORTS_INITIALIZING;
1489 		}
1490 	}
1491 
1492 	// creating child
1493 	int32 countSpaces = 0;
1494 	if (ep_get_partitionable_spaces(partition, NULL, 0, &countSpaces)
1495 			== B_BUFFER_OVERFLOW
1496 		&& countSpaces > 0) {
1497 		flags |= B_DISK_SYSTEM_SUPPORTS_CREATING_CHILD;
1498 	}
1499 
1500 	return flags;
1501 }
1502 
1503 
1504 // ep_get_supported_child_operations
1505 uint32
1506 ep_get_supported_child_operations(partition_data* partition,
1507 	partition_data* child, uint32 mask)
1508 {
1509 	return B_DISK_SYSTEM_SUPPORTS_RESIZING_CHILD
1510 		| B_DISK_SYSTEM_SUPPORTS_MOVING_CHILD
1511 		| B_DISK_SYSTEM_SUPPORTS_SETTING_TYPE
1512 		| B_DISK_SYSTEM_SUPPORTS_DELETING_CHILD;
1513 }
1514 
1515 
1516 // ep_is_sub_system_for
1517 bool
1518 ep_is_sub_system_for(partition_data* partition)
1519 {
1520 	if (partition == NULL)
1521 		return false;
1522 
1523 	TRACE(("intel: ep_is_sub_system_for(%ld: %lld, %lld, %ld, %s)\n",
1524 		partition->id, partition->offset, partition->size,
1525 		partition->block_size, partition->content_type));
1526 
1527 	// Intel Extended Partition can live in child partition of Intel Partition
1528 	// Map
1529 	return partition->content_type
1530 		&& !strcmp(partition->content_type, kPartitionTypeIntel);
1531 }
1532 
1533 
1534 // #pragma mark - Intel Extended Partition - validate functions
1535 
1536 
1537 // ep_validate_resize
1538 bool
1539 ep_validate_resize(partition_data* partition, off_t* size)
1540 {
1541 	TRACE(("intel: ep_validate_resize\n"));
1542 
1543 	if (!partition || !size)
1544 		return false;
1545 
1546 	return validate_resize(partition, size);
1547 }
1548 
1549 
1550 // ep_validate_resize_child
1551 bool
1552 ep_validate_resize_child(partition_data* partition, partition_data* child,
1553 	off_t* _size)
1554 {
1555 	TRACE(("intel: ep_validate_resize_child\n"));
1556 
1557 	if (!partition || !child || !_size)
1558 		return false;
1559 
1560 	// validate position
1561 	off_t size = *_size;
1562 	if (!validate_resize_child(partition, child, child->offset,
1563 		 child->size, &size, get_sibling_partitions_ep))
1564 		return false;
1565 	*_size = size;
1566 	return true;
1567 }
1568 
1569 
1570 // ep_validate_move
1571 bool
1572 ep_validate_move(partition_data* partition, off_t* start)
1573 {
1574 	TRACE(("intel: ep_validate_move\n"));
1575 
1576 	if (!partition || !start)
1577 		return false;
1578 	// nothing to do here
1579 	return true;
1580 }
1581 
1582 
1583 // ep_validate_move_child
1584 bool
1585 ep_validate_move_child(partition_data* partition, partition_data* child,
1586 	off_t* _start)
1587 {
1588 	TRACE(("intel: ep_validate_move_child\n"));
1589 
1590 	if (!partition || !child || !_start)
1591 		return false;
1592 	if (*_start == child->offset)
1593 		return true;
1594 
1595 	// validate position
1596 	off_t start = *_start;
1597 	if (!validate_move_child(partition, child, child->offset,
1598 		child->size, &start, get_sibling_partitions_ep))
1599 		return false;
1600 	*_start = start;
1601 	return true;
1602 }
1603 
1604 
1605 // is_type_valid_ep (auxiliary function)
1606 static inline bool
1607 is_type_valid_ep(const char* type)
1608 {
1609 	// validity check of the type - it has to be known
1610 	PartitionType ptype;
1611 	ptype.SetType(type);
1612 	return (ptype.IsValid() && !ptype.IsEmpty() && !ptype.IsExtended());
1613 }
1614 
1615 
1616 // ep_validate_set_type
1617 bool
1618 ep_validate_set_type(partition_data* partition, const char* type)
1619 {
1620 	TRACE(("intel: ep_validate_set_type\n"));
1621 
1622 	if (!partition || !type)
1623 		return false;
1624 
1625 	// validity check of the type
1626 	return is_type_valid_ep(type);
1627 }
1628 
1629 
1630 // ep_validate_initialize
1631 bool
1632 ep_validate_initialize(partition_data* partition, char* name,
1633 	const char* parameters)
1634 {
1635 	TRACE(("intel: ep_validate_initialize\n"));
1636 
1637 	if (!partition || !(ep_get_supported_operations(partition)
1638 			& B_DISK_SYSTEM_SUPPORTS_INITIALIZING)) {
1639 		return false;
1640 	}
1641 	// name is ignored - we cannot set it to the Intel Extended Partition
1642 	// TODO: check parameters - don't know whether any parameters could be set
1643 	//		 to the Intel Extended Partition
1644 	return true;
1645 }
1646 
1647 
1648 // ep_validate_create_child
1649 bool
1650 ep_validate_create_child(partition_data* partition, off_t* offset, off_t* size,
1651 	const char* type, const char* name, const char* parameters, int32* index)
1652 	// index - returns position of the new partition (the last one)
1653 {
1654 	return false;
1655 }
1656 
1657 
1658 // ep_get_partitionable_spaces
1659 status_t
1660 ep_get_partitionable_spaces(partition_data* partition,
1661 	partitionable_space_data* buffer, int32 count, int32* actualCount)
1662 {
1663 	TRACE(("intel: ep_get_partitionable_spaces\n"));
1664 
1665 	if (!partition || !partition->content_type
1666 		|| strcmp(partition->content_type, kPartitionTypeIntelExtended)
1667 		|| !actualCount) {
1668 		return B_BAD_VALUE;
1669 	}
1670 	if (count > 0 && !buffer)
1671 		return B_BAD_VALUE;
1672 
1673 	return get_partitionable_spaces(partition, buffer, count, actualCount,
1674 		fill_partitionable_spaces_buffer_ep,
1675 		partition->offset + PTS_OFFSET * partition->block_size,
1676 		PTS_OFFSET * partition->block_size,
1677 		PTS_OFFSET * partition->block_size);
1678 }
1679 
1680 
1681 // ep_get_next_supported_type
1682 status_t
1683 ep_get_next_supported_type(partition_data* partition, int32* cookie,
1684 	char* _type)
1685 {
1686 	TRACE(("intel: ep_get_next_supported_type\n"));
1687 
1688 	if (!partition || !partition->content_type
1689 		|| strcmp(partition->content_type, kPartitionTypeIntelExtended)
1690 		|| !cookie || !_type) {
1691 		return B_BAD_VALUE;
1692 	}
1693 
1694 	if (*cookie > 255)
1695 		return B_ENTRY_NOT_FOUND;
1696 	if (*cookie < 1)
1697 		*cookie = 1;
1698 
1699 	uint8 type = *cookie;
1700 
1701 	// get type
1702 	PartitionType ptype;
1703 	ptype.SetType(type);
1704 	while (ptype.IsValid() && !ptype.IsExtended())
1705 		ptype.FindNext();
1706 
1707 	if (!ptype.IsValid())
1708 		return B_ENTRY_NOT_FOUND;
1709 
1710 	ptype.GetTypeString(_type);
1711 
1712 	// find next type
1713 	if (ptype.FindNext())
1714 		*cookie = ptype.Type();
1715 	else
1716 		*cookie = 256;
1717 
1718 	return B_OK;
1719 }
1720 
1721 
1722 // ep_shadow_changed
1723 status_t
1724 ep_shadow_changed(partition_data* partition, partition_data* child,
1725 	uint32 operation)
1726 {
1727 	TRACE(("intel: ep_shadow_changed\n"));
1728 
1729 	if (!partition)
1730 		return B_BAD_VALUE;
1731 
1732 	// nothing to do here
1733 	return B_OK;
1734 }
1735 
1736 
1737 bool
1738 check_partition_location_ep(partition_data* partition, off_t offset,
1739 	off_t size, off_t ptsOffset)
1740 {
1741 	if (!partition)
1742 		return false;
1743 
1744 	// make sure we are sector aligned
1745 	off_t alignedOffset = sector_align(offset, partition->block_size);
1746 	if (alignedOffset != offset)
1747 		return false;
1748 
1749 	// partition does not lie within extended partition
1750 	if (offset < partition->offset
1751 		|| (offset > partition->offset + partition->size
1752 		&& offset + size <= partition->offset + partition->size))
1753 		return false;
1754 
1755 	// check if the new partition table is within an existing partition
1756 	// or that the new partition does not overwrite an existing partition
1757 	// table.
1758 	for (int32 i = 0; i < partition->child_count; i++) {
1759 		partition_data* sibling = get_child_partition(partition->id, i);
1760 		LogicalPartition* logical = (LogicalPartition*)sibling->cookie;
1761 		if (logical == NULL)
1762 			return false;
1763 		if (ptsOffset > logical->Offset()
1764 			&& ptsOffset < logical->Offset() + logical->Size())
1765 			return false;
1766 		if ((logical->PartitionTableOffset() >= offset
1767 			&& logical->PartitionTableOffset() < offset + size)
1768 			|| logical->PartitionTableOffset() == ptsOffset)
1769 			return false;
1770 	}
1771 
1772 	return true;
1773 }
1774 
1775 
1776 // #pragma mark - Intel Extended Partition - write functions
1777 
1778 
1779 // ep_resize
1780 status_t
1781 ep_resize(int fd, partition_id partitionID, off_t size, disk_job_id job)
1782 {
1783 	TRACE(("intel: ep_resize\n"));
1784 
1785 	if (fd < 0)
1786 		return B_ERROR;
1787 
1788 	PartitionWriteLocker locker(partitionID);
1789 	if (!locker.IsLocked())
1790 		return B_ERROR;
1791 
1792 	// get out partition
1793 	partition_data* partition = get_partition(partitionID);
1794 	if (!partition)
1795 		return B_BAD_VALUE;
1796 
1797 	// validate the new size
1798 	// TODO: The parameter has already been checked and must not be altered!
1799 	off_t validatedSize = size;
1800 	if (!ep_validate_resize(partition, &validatedSize))
1801 		return B_BAD_VALUE;
1802 
1803 	// update data stuctures
1804 	update_disk_device_job_progress(job, 0.0);
1805 
1806 	// TODO: partition->size is not supposed to be touched.
1807 	partition->size = validatedSize;
1808 	partition->content_size = validatedSize;
1809 
1810 	// all changes applied
1811 	update_disk_device_job_progress(job, 1.0);
1812 	partition_modified(partitionID);
1813 	return B_OK;
1814 }
1815 
1816 
1817 // ep_resize_child
1818 status_t
1819 ep_resize_child(int fd, partition_id partitionID, off_t size, disk_job_id job)
1820 {
1821 	TRACE(("intel: ep_resize_child\n"));
1822 
1823 	if (fd < 0)
1824 		return B_ERROR;
1825 
1826 	PartitionWriteLocker locker(partitionID);
1827 	if (!locker.IsLocked())
1828 		return B_ERROR;
1829 
1830 	// get out partition, child and LogicalPartition structure
1831 	partition_data* partition = get_parent_partition(partitionID);
1832 	partition_data* child = get_partition(partitionID);
1833 	if (!partition || !child)
1834 		return B_BAD_VALUE;
1835 	LogicalPartition* logical = (LogicalPartition*)child->cookie;
1836 	PrimaryPartition* primary = (PrimaryPartition*)partition->cookie;
1837 	if (!logical || !primary)
1838 		return B_BAD_VALUE;
1839 
1840 	// validate the new size
1841 	// TODO: The parameter has already been checked and must not be altered!
1842 	off_t validatedSize = size;
1843 	if (!ep_validate_resize_child(partition, child, &validatedSize))
1844 		return B_BAD_VALUE;
1845 	if (child->size == validatedSize)
1846 		return B_OK;
1847 
1848 	// update data stuctures and write changes
1849 	update_disk_device_job_progress(job, 0.0);
1850 	logical->SetSize(validatedSize);
1851 
1852 	PartitionMapWriter writer(fd, partition->block_size);
1853 	// TODO: The partition is not supposed to be locked here!
1854 	status_t error = writer.WriteLogical(logical, primary, false);
1855 	if (error != B_OK) {
1856 		// putting into previous state
1857 		logical->SetSize(child->size);
1858 		return error;
1859 	}
1860 	LogicalPartition* prev = logical->Previous();
1861 	error = prev ? writer.WriteLogical(prev, primary, false)
1862 				 : writer.WriteLogical(logical, primary, false);
1863 	if (error != B_OK)
1864 		// this should be not so fatal
1865 		return error;
1866 
1867 	child->size = validatedSize;
1868 
1869 	// all changes applied
1870 	update_disk_device_job_progress(job, 1.0);
1871 	partition_modified(partitionID);
1872 	return B_OK;
1873 }
1874 
1875 
1876 // ep_move
1877 status_t
1878 ep_move(int fd, partition_id partitionID, off_t offset, disk_job_id job)
1879 {
1880 	TRACE(("intel: ep_move\n"));
1881 
1882 	if (fd < 0)
1883 		return B_ERROR;
1884 
1885 	PartitionWriteLocker locker(partitionID);
1886 	if (!locker.IsLocked())
1887 		return B_ERROR;
1888 
1889 	// get out partition
1890 	partition_data* partition = get_partition(partitionID);
1891 	if (!partition)
1892 		return B_BAD_VALUE;
1893 
1894 	// validate the new start
1895 	// TODO: The parameter has already been checked and must not be altered!
1896 	if (!ep_validate_move(partition, &offset))
1897 		return B_BAD_VALUE;
1898 
1899 	// nothing to do here
1900 	return B_OK;
1901 }
1902 
1903 
1904 // ep_move_child
1905 status_t
1906 ep_move_child(int fd, partition_id partitionID, partition_id childID,
1907 	off_t offset, disk_job_id job)
1908 {
1909 	TRACE(("intel: ep_move_child\n"));
1910 
1911 	if (fd < 0)
1912 		return B_ERROR;
1913 
1914 	PartitionWriteLocker locker(partitionID);
1915 	if (!locker.IsLocked())
1916 		return B_ERROR;
1917 
1918 	// get partition, child and LogicalPartition structure
1919 	partition_data* partition = get_partition(partitionID);
1920 	partition_data* child = get_partition(childID);
1921 	if (!partition || !child)
1922 		return B_BAD_VALUE;
1923 	LogicalPartition* logical = (LogicalPartition*)child->cookie;
1924 	PrimaryPartition* primary = (PrimaryPartition*)partition->cookie;
1925 	if (!logical || !primary)
1926 		return B_BAD_VALUE;
1927 
1928 	// TODO: The parameter has already been checked and must not be altered!
1929 	off_t validatedOffset = offset;
1930 	if (!ep_validate_move_child(partition, child, &validatedOffset))
1931 		return B_BAD_VALUE;
1932 
1933 	// if the old offset is the same, there is nothing to do
1934 	if (child->offset == validatedOffset)
1935 		return B_OK;
1936 
1937 	off_t diffOffset = validatedOffset - child->offset;
1938 
1939 	// buffer allocation
1940 	int32 allocated;
1941 	uint8* buffer = allocate_buffer(partition->block_size, MAX_MOVE_BUFFER,
1942 		&allocated);
1943 	if (!buffer)
1944 		return B_NO_MEMORY;
1945 
1946 	// partition moving
1947 	update_disk_device_job_progress(job, 0.0);
1948 	status_t error = B_OK;
1949 	// move partition with its header (partition table)
1950 	off_t pts_offset = logical->Offset() - logical->PartitionTableOffset();
1951 	error = move_partition(fd, child->offset - pts_offset,
1952 		validatedOffset - pts_offset, child->size + pts_offset, buffer,
1953 		allocated * partition->block_size, job);
1954 	delete[] buffer;
1955 	if (error != B_OK)
1956 		return error;
1957 
1958 	// partition moved
1959 	// updating data structure
1960 	child->offset = validatedOffset;
1961 	logical->SetOffset(logical->Offset() + diffOffset);
1962 	logical->SetPartitionTableOffset(logical->PartitionTableOffset() + diffOffset);
1963 
1964 	PartitionMapWriter writer(fd, partition->block_size);
1965 		// TODO: If partition->offset is > prev->offset, then writing
1966 		// the previous logical partition table will fail!
1967 	// TODO: The partition is not supposed to be locked here!
1968 	error = writer.WriteLogical(logical, primary, false);
1969 	if (error != B_OK)
1970 		// something went wrong - this is fatal (partition has been moved)
1971 		// but EBR is not updated
1972 		return error;
1973 	LogicalPartition* prev = logical->Previous();
1974 	error = prev ? writer.WriteLogical(prev, primary, false)
1975 				 : writer.WriteLogical(logical, primary, false);
1976 	if (error != B_OK)
1977 		// this is fatal - linked list is not updated
1978 		return error;
1979 
1980 	// all changes applied
1981 	update_disk_device_job_progress(job, 1.0);
1982 	partition_modified(childID);
1983 	return B_OK;
1984 }
1985 
1986 
1987 // ep_set_type
1988 status_t
1989 ep_set_type(int fd, partition_id partitionID, const char* type, disk_job_id job)
1990 {
1991 	TRACE(("intel: ep_set_type\n"));
1992 
1993 	if (fd < 0 || !type)
1994 		return B_BAD_VALUE;
1995 
1996 	PartitionWriteLocker locker(partitionID);
1997 	if (!locker.IsLocked())
1998 		return B_ERROR;
1999 
2000 	// get partition, child and LogicalPartition structure
2001 	partition_data* partition = get_parent_partition(partitionID);
2002 	partition_data* child = get_partition(partitionID);
2003 	if (!partition || !child)
2004 		return B_BAD_VALUE;
2005 	LogicalPartition* logical = (LogicalPartition*)child->cookie;
2006 	PrimaryPartition* primary = (PrimaryPartition*)partition->cookie;
2007 	if (!logical || !primary)
2008 		return B_BAD_VALUE;
2009 
2010 	// TODO: The parameter has already been checked and must not be altered!
2011 	if (!ep_validate_set_type(child, type))
2012 		return B_BAD_VALUE;
2013 
2014 	// if the old type is the same, there is nothing to do
2015 	if (child->type && !strcmp(type, child->type))
2016 		return B_OK;
2017 
2018 	PartitionType ptype;
2019 	ptype.SetType(type);
2020 	// this is impossible
2021 	if (!ptype.IsValid() || ptype.IsEmpty() || ptype.IsExtended())
2022 		return false;
2023 
2024 	// setting type to the partition
2025 	update_disk_device_job_progress(job, 0.0);
2026 	uint8 oldType = logical->Type();
2027 	logical->SetType(ptype.Type());
2028 
2029 	PartitionMapWriter writer(fd, partition->block_size);
2030 	// TODO: The partition is not supposed to be locked here!
2031 	status_t error = writer.WriteLogical(logical, primary, false);
2032 	if (error != B_OK) {
2033 		// something went wrong - putting into previous state
2034 		logical->SetType(oldType);
2035 		return error;
2036 	}
2037 
2038 	free(child->type);
2039 	child->type = strdup(type);
2040 	if (!child->type)
2041 		return B_NO_MEMORY;
2042 
2043 	// all changes applied
2044 	update_disk_device_job_progress(job, 1.0);
2045 	partition_modified(partitionID);
2046 	return B_OK;
2047 }
2048 
2049 
2050 // ep_initialize
2051 status_t
2052 ep_initialize(int fd, partition_id partitionID, const char* name,
2053 	const char* parameters, off_t partitionSize, disk_job_id job)
2054 {
2055 	TRACE(("intel: ep_initialize\n"));
2056 
2057 	if (fd < 0)
2058 		return B_ERROR;
2059 
2060 	PartitionWriteLocker locker(partitionID);
2061 	if (!locker.IsLocked())
2062 		return B_ERROR;
2063 
2064 	// get partition
2065 	partition_data* partition = get_partition(partitionID);
2066 	if (!partition)
2067 		return B_BAD_VALUE;
2068 
2069 	PrimaryPartition* primary = (PrimaryPartition*)partition->cookie;
2070 	if (!primary)
2071 		return B_BAD_VALUE;
2072 
2073 	// name is ignored - we cannot set it to the Intel Extended Partition
2074 // TODO: The parameter has already been checked and must not be altered!
2075 	if (!ep_validate_initialize(partition, NULL, parameters))
2076 		return B_BAD_VALUE;
2077 
2078 	// partition init (we have no child partition)
2079 	update_disk_device_job_progress(job, 0.0);
2080 	// fill in the partition_data structure
2081 	partition->status = B_PARTITION_VALID;
2082 	partition->flags |= B_PARTITION_PARTITIONING_SYSTEM;
2083 	partition->content_size = partition->size;
2084 	// (no content_name and content_parameters)
2085 	// (content_type is set by the system)
2086 	partition->content_cookie = primary;
2087 
2088 	// we delete code area in EBR - nothing should be there
2089 	partition_table table;
2090 	table.clear_code_area();
2091 
2092 	PartitionMapWriter writer(fd, partition->block_size);
2093 	// TODO: The partition is not supposed to be locked here!
2094 	status_t error = writer.ClearExtendedHead(primary);
2095 	if (error != B_OK)
2096 		return error;
2097 
2098 	// all changes applied
2099 	update_disk_device_job_progress(job, 1.0);
2100 	partition_modified(partitionID);
2101 	return B_OK;
2102 }
2103 
2104 
2105 // ep_create_child
2106 /*!
2107 	childID is used for the return value, but is also an optional input
2108 	parameter -- -1 to be ignored
2109 */
2110 status_t
2111 ep_create_child(int fd, partition_id partitionID, off_t offset, off_t size,
2112 	const char* type, const char* name, const char* parameters, disk_job_id job,
2113 	partition_id* childID)
2114 {
2115 	TRACE(("intel: ep_create_child\n"));
2116 
2117 	if (fd < 0 || !childID)
2118 		return B_BAD_VALUE;
2119 
2120 	// aquire lock
2121 	PartitionWriteLocker locker(partitionID);
2122 	if (!locker.IsLocked())
2123 		return B_ERROR;
2124 
2125 	// get partition data
2126 	partition_data* partition = get_partition(partitionID);
2127 	partition_data* parent = get_parent_partition(partitionID);
2128 	if (partition == NULL || parent == NULL)
2129 		return B_BAD_VALUE;
2130 
2131 	PrimaryPartition* primary = (PrimaryPartition*)partition->cookie;
2132 	if (!primary)
2133 		return B_BAD_VALUE;
2134 
2135 	// parse parameters
2136 	void* handle = parse_driver_settings_string(parameters);
2137 	if (handle == NULL)
2138 		return B_ERROR;
2139 
2140 	bool active = get_driver_boolean_parameter(handle, "active", false, true);
2141 
2142 	off_t ptsOffset = 0;
2143 	const char* buffer = get_driver_parameter(
2144 		handle, "partition_table_offset", NULL, NULL);
2145 	if (buffer != NULL)
2146 		ptsOffset = strtoull(buffer, NULL, 10);
2147 	else {
2148 		delete_driver_settings(handle);
2149 		return B_BAD_VALUE;
2150 	}
2151 	delete_driver_settings(handle);
2152 
2153 	// check the partition location
2154 	if (!check_partition_location_ep(partition, offset, size, ptsOffset))
2155 		return B_BAD_VALUE;
2156 
2157 	// creating partition
2158 	update_disk_device_job_progress(job, 0.0);
2159 	partition_data* child = create_child_partition(partition->id,
2160 		partition->child_count, offset, size, *childID);
2161 	if (!child)
2162 		return B_ERROR;
2163 
2164 	// setup logical partition
2165 	LogicalPartition* logical = new(nothrow) LogicalPartition;
2166 	if (!logical)
2167 		return B_NO_MEMORY;
2168 
2169 	PartitionType ptype;
2170 	ptype.SetType(type);
2171 	logical->SetPartitionTableOffset(ptsOffset - parent->offset);
2172 	logical->SetOffset(offset);
2173 	logical->SetSize(size);
2174 	logical->SetType(ptype.Type());
2175 	logical->SetActive(active);
2176 	logical->SetPrimaryPartition(primary);
2177 	logical->SetBlockSize(partition->block_size);
2178 	primary->AddLogicalPartition(logical);
2179 
2180 	int parentFD = open_partition(parent->id, O_RDWR);
2181 	if (parentFD < 0) {
2182 		primary->RemoveLogicalPartition(logical);
2183 		delete logical;
2184 		return B_IO_ERROR;
2185 	}
2186 
2187 	// write changes to disk
2188 	PartitionMapWriter writer(parentFD, primary->BlockSize());
2189 
2190 	// Write the logical partition's EBR first in case of failure.
2191 	// This way we will not add a partition to the previous logical
2192 	// partition. If there is no previous logical partition then write
2193 	// the current partition's EBR to the first sector of the primary partition
2194 	status_t error = writer.WriteLogical(logical, primary, true);
2195 	if (error != B_OK) {
2196 		primary->RemoveLogicalPartition(logical);
2197 		delete logical;
2198 		return error;
2199 	}
2200 
2201 	LogicalPartition* previous = logical->Previous();
2202 	if (previous != NULL) {
2203 		error = writer.WriteLogical(previous, primary, true);
2204 		if (error != B_OK) {
2205 			primary->RemoveLogicalPartition(logical);
2206 			delete logical;
2207 			return error;
2208 		}
2209 	}
2210 	*childID = child->id;
2211 
2212 	child->block_size = logical->BlockSize();
2213 	child->type = strdup(type);
2214 	child->parameters = strdup(parameters);
2215 	child->cookie = logical;
2216 	// check for allocation problems
2217 	if (!child->type || !child->parameters)
2218 		error = B_NO_MEMORY;
2219 
2220 	// all changes applied
2221 	update_disk_device_job_progress(job, 1.0);
2222 	partition_modified(partitionID);
2223 	return B_OK;
2224 }
2225 
2226 
2227 // ep_delete_child
2228 status_t
2229 ep_delete_child(int fd, partition_id partitionID, partition_id childID,
2230 	disk_job_id job)
2231 {
2232 	TRACE(("intel: ep_delete_child\n"));
2233 
2234 	if (fd < 0)
2235 		return B_ERROR;
2236 
2237 	PartitionWriteLocker locker(partitionID);
2238 	if (!locker.IsLocked())
2239 		return B_ERROR;
2240 
2241 	partition_data* partition = get_partition(partitionID);
2242 	partition_data* parent = get_parent_partition(partitionID);
2243 	partition_data* child = get_partition(childID);
2244 	if (partition == NULL || parent == NULL || child == NULL)
2245 		return B_BAD_VALUE;
2246 
2247 	PrimaryPartition* primary = (PrimaryPartition*)partition->cookie;
2248 	LogicalPartition* logical = (LogicalPartition*)child->cookie;
2249 	if (primary == NULL || logical == NULL)
2250 		return B_BAD_VALUE;
2251 
2252 	// deleting child
2253 	update_disk_device_job_progress(job, 0.0);
2254 	if (!delete_partition(childID))
2255 		return B_ERROR;
2256 
2257 	LogicalPartition* previous = logical->Previous();
2258 	LogicalPartition* next = logical->Next();
2259 
2260 	primary->RemoveLogicalPartition(logical);
2261 	delete logical;
2262 
2263 	int parentFD = open_partition(parent->id, O_RDWR);
2264 	if (parentFD < 0)
2265 		return B_IO_ERROR;
2266 
2267 	// write changes to disk
2268 	PartitionMapWriter writer(parentFD, primary->BlockSize());
2269 
2270 	status_t error;
2271 	if (previous != NULL) {
2272 		error = writer.WriteLogical(previous, primary, true);
2273 	} else {
2274 		error = writer.WriteExtendedHead(next, primary, true);
2275 
2276 		if (next != NULL) {
2277 			next->SetPartitionTableOffset(primary->Offset());
2278 
2279 			partition_data* nextSibling = NULL;
2280 			if (get_partition_from_offset_ep(partition, next->Offset(),
2281 				&nextSibling)) {
2282 				char buffer[128];
2283 				sprintf(buffer, "active %s ;\npartition_table_offset %lld ;\n",
2284 					next->Active() ? "true" : "false",
2285 					next->PartitionTableOffset());
2286 				nextSibling->parameters = strdup(buffer);
2287 			}
2288 		}
2289 	}
2290 
2291 	close(parentFD);
2292 
2293 	if (error != B_OK)
2294 		return error;
2295 
2296 	// all changes applied
2297 	update_disk_device_job_progress(job, 1.0);
2298 	partition_modified(partitionID);
2299 	return B_OK;
2300 }
2301 
2302