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