xref: /haiku/src/add-ons/kernel/partitioning_systems/intel/write_support.cpp (revision af435dd1c9460acc910170b4f82f44bfd3f557c9)
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).
36 static 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).
40 static const uint32 FREE_SECTORS_AFTER_PTS = 63;
41 // Count of free sectors after Master Boot Record.
42 static const uint32 FREE_SECTORS_AFTER_MBR = 63;
43 // size of logical partition header in blocks
44 static const uint32 PTS_OFFSET = FREE_SECTORS_AFTER_PTS + 1;
45 static const uint32 MBR_OFFSET = FREE_SECTORS_AFTER_MBR + 1;
46 
47 
48 typedef partitionable_space_data PartitionPosition;
49 
50 typedef 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 
55 typedef int32 (*fc_fill_partitionable_spaces_buffer)(partition_data* partition,
56 		PartitionPosition* positions);
57 
58 
59 status_t pm_get_partitionable_spaces(partition_data* partition,
60 	partitionable_space_data* buffer, int32 count, int32* actualCount);
61 status_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
69 uint32
pm_get_supported_operations(partition_data * partition,uint32 mask)70 pm_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
92 uint32
pm_get_supported_child_operations(partition_data * partition,partition_data * child,uint32 mask)93 pm_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
104 bool
pm_is_sub_system_for(partition_data * partition)105 pm_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 
111 bool
get_partition_from_offset_ep(partition_data * partition,off_t offset,partition_data ** nextPartition)112 get_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)
131 static inline off_t
sector_align(off_t offset,int32 blockSize)132 sector_align(off_t offset, int32 blockSize)
133 {
134 	return offset / blockSize * blockSize;
135 }
136 
137 
138 // sector_align_up (auxiliary function)
139 static inline off_t
sector_align_up(off_t offset,int32 blockSize)140 sector_align_up(off_t offset, int32 blockSize)
141 {
142 	return (offset + blockSize - 1) / blockSize * blockSize;
143 }
144 
145 
146 // validate_resize (auxiliary function)
147 static bool
validate_resize(partition_data * partition,off_t * size)148 validate_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
185 bool
pm_validate_resize(partition_data * partition,off_t * size)186 pm_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 */
203 static void
get_sibling_partitions_pm(partition_data * partition,partition_data * child,off_t childOffset,partition_data ** previous,partition_data ** next,off_t * previousOffset,off_t * previousSize,off_t * nextOffset,off_t * nextSize)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 	}
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 */
244 static void
get_sibling_partitions_ep(partition_data * partition,partition_data * child,off_t childOffset,partition_data ** previous,partition_data ** next,off_t * previousOffset,off_t * previousSize,off_t * nextOffset,off_t * nextSize)245 get_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)
280 static bool
validate_resize_child(partition_data * partition,partition_data * child,off_t childOffset,off_t childSize,off_t * size,fc_get_sibling_partitions getSiblingPartitions)281 validate_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
318 bool
pm_validate_resize_child(partition_data * partition,partition_data * child,off_t * size)319 pm_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
333 bool
pm_validate_move(partition_data * partition,off_t * start)334 pm_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)
346 static bool
validate_move_child(partition_data * partition,partition_data * child,off_t childOffset,off_t childSize,off_t * _start,fc_get_sibling_partitions getSiblingPartitions)347 validate_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
388 bool
pm_validate_move_child(partition_data * partition,partition_data * child,off_t * start)389 pm_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 */
409 static bool
is_type_valid_pm(const char * type,partition_data * partition,PrimaryPartition * child=NULL)410 is_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
435 bool
pm_validate_set_type(partition_data * partition,const char * type)436 pm_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
455 bool
pm_validate_initialize(partition_data * partition,char * name,const char * parameters)456 pm_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)
477 static bool
validate_create_child_partition(partition_data * partition,off_t * start,off_t * size,fc_get_sibling_partitions getSiblingPartitions)478 validate_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 */
523 bool
pm_validate_create_child(partition_data * partition,off_t * start,off_t * size,const char * type,const char * name,const char * parameters,int32 * index)524 pm_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
570 static int
cmp_partition_position(const void * o1,const void * o2)571 cmp_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 */
590 static int32
fill_partitionable_spaces_buffer_pm(partition_data * partition,PartitionPosition * positions)591 fill_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 */
612 static int32
fill_partitionable_spaces_buffer_ep(partition_data * partition,PartitionPosition * positions)613 fill_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)
630 static status_t
get_partitionable_spaces(partition_data * partition,partitionable_space_data * buffer,int32 count,int32 * _actualCount,fc_fill_partitionable_spaces_buffer fillBuffer,off_t startOffset,off_t limitSize=0,off_t headerSize=0)631 get_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
694 status_t
pm_get_partitionable_spaces(partition_data * partition,partitionable_space_data * buffer,int32 count,int32 * actualCount)695 pm_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
715 status_t
pm_get_next_supported_type(partition_data * partition,int32 * cookie,char * _type)716 pm_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
752 status_t
pm_shadow_changed(partition_data * partition,partition_data * child,uint32 operation)753 pm_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
922 status_t
pm_resize(int fd,partition_id partitionID,off_t size,disk_job_id job)923 pm_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
960 status_t
pm_resize_child(int fd,partition_id partitionID,off_t size,disk_job_id job)961 pm_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
1014 status_t
pm_move(int fd,partition_id partitionID,off_t offset,disk_job_id job)1015 pm_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 */
1049 static uint8*
allocate_buffer(uint32 blockSize,int32 tryAlloc,int32 * allocated)1050 allocate_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)
1066 static status_t
move_block(int fd,off_t fromOffset,off_t toOffset,uint8 * buffer,int32 size)1067 move_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)
1092 static status_t
move_partition(int fd,off_t fromOffset,off_t toOffset,off_t size,uint8 * buffer,int32 buffer_size,disk_job_id job)1093 move_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
1118 status_t
pm_move_child(int fd,partition_id partitionID,partition_id childID,off_t offset,disk_job_id job)1119 pm_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
1188 status_t
pm_set_type(int fd,partition_id partitionID,const char * type,disk_job_id job)1189 pm_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
1253 status_t
pm_set_parameters(int fd,partition_id partitionID,const char * parameters,disk_job_id job)1254 pm_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
1327 status_t
pm_initialize(int fd,partition_id partitionID,const char * name,const char * parameters,off_t partitionSize,disk_job_id job)1328 pm_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 
1369 status_t
pm_uninitialize(int fd,partition_id partitionID,off_t partitionSize,uint32 blockSize,disk_job_id job)1370 pm_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 */
1398 status_t
pm_create_child(int fd,partition_id partitionID,off_t offset,off_t size,const char * type,const char * name,const char * parameters,disk_job_id job,partition_id * childID)1399 pm_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
1509 status_t
pm_delete_child(int fd,partition_id partitionID,partition_id childID,disk_job_id job)1510 pm_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
1557 uint32
ep_get_supported_operations(partition_data * partition,uint32 mask)1558 ep_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
1586 uint32
ep_get_supported_child_operations(partition_data * partition,partition_data * child,uint32 mask)1587 ep_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
1598 bool
ep_is_sub_system_for(partition_data * partition)1599 ep_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
1619 bool
ep_validate_resize(partition_data * partition,off_t * size)1620 ep_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
1632 bool
ep_validate_resize_child(partition_data * partition,partition_data * child,off_t * _size)1633 ep_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
1652 bool
ep_validate_move(partition_data * partition,off_t * start)1653 ep_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
1665 bool
ep_validate_move_child(partition_data * partition,partition_data * child,off_t * _start)1666 ep_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)
1687 static inline bool
is_type_valid_ep(const char * type)1688 is_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
1698 bool
ep_validate_set_type(partition_data * partition,const char * type)1699 ep_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
1712 bool
ep_validate_initialize(partition_data * partition,char * name,const char * parameters)1713 ep_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
1730 bool
ep_validate_create_child(partition_data * partition,off_t * offset,off_t * size,const char * type,const char * name,const char * parameters,int32 * index)1731 ep_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
1740 status_t
ep_get_partitionable_spaces(partition_data * partition,partitionable_space_data * buffer,int32 count,int32 * actualCount)1741 ep_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
1763 status_t
ep_get_next_supported_type(partition_data * partition,int32 * cookie,char * _type)1764 ep_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
1804 status_t
ep_shadow_changed(partition_data * partition,partition_data * child,uint32 operation)1805 ep_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 
1818 bool
check_partition_location_ep(partition_data * partition,off_t offset,off_t size,off_t ptsOffset)1819 check_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
1861 status_t
ep_resize(int fd,partition_id partitionID,off_t size,disk_job_id job)1862 ep_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
1899 status_t
ep_resize_child(int fd,partition_id partitionID,off_t size,disk_job_id job)1900 ep_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
1958 status_t
ep_move(int fd,partition_id partitionID,off_t offset,disk_job_id job)1959 ep_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
1986 status_t
ep_move_child(int fd,partition_id partitionID,partition_id childID,off_t offset,disk_job_id job)1987 ep_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
2069 status_t
ep_set_type(int fd,partition_id partitionID,const char * type,disk_job_id job)2070 ep_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
2132 status_t
ep_initialize(int fd,partition_id partitionID,const char * name,const char * parameters,off_t partitionSize,disk_job_id job)2133 ep_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 */
2191 status_t
ep_create_child(int fd,partition_id partitionID,off_t offset,off_t size,const char * type,const char * name,const char * parameters,disk_job_id job,partition_id * childID)2192 ep_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
2309 status_t
ep_delete_child(int fd,partition_id partitionID,partition_id childID,disk_job_id job)2310 ep_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