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