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