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