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