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