vfs: check userland buffers before reading them.
[haiku.git] / src / add-ons / kernel / partitioning_systems / intel / write_support.cpp
blobb9d2bb0794df9b51ada2a6675ec442a0d3170c8a
1 /*
2 * Copyright 2003-2011, Haiku, Inc. All Rights Reserved.
3 * Distributed under the terms of the MIT License.
5 * Authors:
6 * Ingo Weinhold, ingo_weinhold@gmx.de
7 * Tomas Kucera, kucerat@centrum.cz
8 */
11 #include "write_support.h"
13 #include <errno.h>
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <string.h>
18 #include <new>
20 #include <DiskDeviceTypes.h>
21 #include <KernelExport.h>
23 #include <AutoDeleter.h>
25 #include "intel.h"
26 #include "PartitionLocker.h"
27 #include "PartitionMap.h"
28 #include "PartitionMapParser.h"
29 #include "PartitionMapWriter.h"
32 //#define TRACE(x) ;
33 #define TRACE(x) dprintf x
35 // Maximal size of move buffer (in sectors).
36 static const int32 MAX_MOVE_BUFFER = 2 * 1024 * 4;
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;
48 typedef partitionable_space_data PartitionPosition;
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);
55 typedef int32 (*fc_fill_partitionable_spaces_buffer)(partition_data* partition,
56 PartitionPosition* positions);
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);
65 // #pragma mark - Intel Partition Map - support functions
68 // pm_get_supported_operations
69 uint32
70 pm_get_supported_operations(partition_data* partition, uint32 mask)
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;
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;
87 return flags;
91 // pm_get_supported_child_operations
92 uint32
93 pm_get_supported_child_operations(partition_data* partition,
94 partition_data* child, uint32 mask)
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;
103 // pm_is_sub_system_for
104 bool
105 pm_is_sub_system_for(partition_data* partition)
107 // primary partition map doesn't naturally live in any other child partition
108 return false;
111 bool
112 get_partition_from_offset_ep(partition_data* partition, off_t offset,
113 partition_data** nextPartition)
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;
123 return false;
127 // #pragma mark - Intel Partition Map - validate functions
130 // sector_align (auxiliary function)
131 static inline off_t
132 sector_align(off_t offset, int32 blockSize)
134 return offset / blockSize * blockSize;
138 // sector_align_up (auxiliary function)
139 static inline off_t
140 sector_align_up(off_t offset, int32 blockSize)
142 return (offset + blockSize - 1) / blockSize * blockSize;
146 // validate_resize (auxiliary function)
147 static bool
148 validate_resize(partition_data* partition, off_t* size)
150 off_t newSize = *size;
151 // size remains the same?
152 if (newSize == partition->size)
153 return true;
155 if (newSize < 0)
156 newSize = 0;
157 else
158 newSize = sector_align(newSize, partition->block_size);
160 // grow partition?
161 if (newSize > partition->size) {
162 *size = newSize;
163 return true;
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;
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;
184 // pm_validate_resize
185 bool
186 pm_validate_resize(partition_data* partition, off_t* size)
188 TRACE(("intel: pm_validate_resize\n"));
190 if (!partition || !size)
191 return false;
193 return validate_resize(partition, size);
197 // get_sibling_partitions_pm (auxiliary function)
199 according to childOffset returns previous and next sibling or NULL
200 precious, next output parameters
201 partition - Intel Partition Map
203 static void
204 get_sibling_partitions_pm(partition_data* partition,
205 partition_data* child, off_t childOffset, partition_data** previous,
206 partition_data** next, off_t* previousOffset, off_t* previousSize,
207 off_t* nextOffset, off_t* nextSize)
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;
225 *previous = previousSibling;
226 *next = nextSibling;
227 if (previousSibling) {
228 *previousOffset = previousSibling->offset;
229 *previousSize = previousSibling->size;
231 if (nextSibling) {
232 *nextOffset = nextSibling->offset;
233 *nextSize = nextSibling->size;
238 // get_sibling_partitions_ep (auxiliary function)
240 according to childOffset returns previous and next sibling or NULL
241 previous, next output parameters
242 partition - Intel Extended Partition
244 static void
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)
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;
266 *previous = previousSibling;
267 *next = nextSibling;
268 if (previousSibling) {
269 *previousOffset = previousSibling->offset;
270 *previousSize = previousSibling->size;
272 if (nextSibling) {
273 *nextOffset = nextSibling->offset;
274 *nextSize = nextSibling->size;
279 // validate_resize_child (auxiliary function)
280 static bool
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)
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;
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;
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;
307 getSiblingPartitions(partition, child, childOffset, &previousSibling,
308 &nextSibling, &previousOffset, &previousSize, &nextOffset, &nextSize);
310 if (nextSibling && (nextOffset < childOffset + *size))
311 *size = nextOffset - childOffset;
312 *size = sector_align(*size, partition->block_size);
313 return true;
317 // pm_validate_resize_child
318 bool
319 pm_validate_resize_child(partition_data* partition, partition_data* child,
320 off_t* size)
322 TRACE(("intel: pm_validate_resize_child\n"));
324 if (!partition || !child || !size)
325 return false;
327 return validate_resize_child(partition, child, child->offset,
328 child->size, size, get_sibling_partitions_pm);
332 // pm_validate_move
333 bool
334 pm_validate_move(partition_data* partition, off_t* start)
336 TRACE(("intel: pm_validate_move\n"));
338 if (!partition || !start)
339 return false;
340 // nothing to do here
341 return true;
345 // validate_move_child (auxiliary function)
346 static bool
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)
351 off_t start = *_start;
353 if (start < 0)
354 start = 0;
355 else if (start + childSize > partition->size)
356 start = partition->size - childSize;
358 start = sector_align(start, partition->block_size);
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;
365 getSiblingPartitions(partition, child, childOffset, &previousSibling,
366 &nextSibling, &previousOffset, &previousSize, &nextOffset, &nextSize);
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);
375 } else {
376 // moving right
377 if (nextSibling && nextOffset < start + childSize) {
378 start = nextOffset - childSize;
379 start = sector_align(start, partition->block_size);
382 *_start = start;
383 return true;
387 // pm_validate_move_child
388 bool
389 pm_validate_move_child(partition_data* partition, partition_data* child,
390 off_t* start)
392 TRACE(("intel: pm_validate_move_child\n"));
394 if (!partition || !child || !start)
395 return false;
396 if (*start == child->offset)
397 return true;
399 return validate_move_child(partition, child, child->offset,
400 child->size, start, get_sibling_partitions_pm);
403 // is_type_valid_pm (auxiliary function)
405 type has to be known, only one extended partition is allowed
406 partition - intel partition map
407 child can be NULL
409 static bool
410 is_type_valid_pm(const char* type, partition_data* partition,
411 PrimaryPartition* child = NULL)
413 // validity check of the type
414 PartitionType ptype;
415 ptype.SetType(type);
416 if (!ptype.IsValid() || ptype.IsEmpty())
417 return false;
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;
430 return true;
434 // pm_validate_set_type
435 bool
436 pm_validate_set_type(partition_data* partition, const char* type)
438 TRACE(("intel: pm_validate_set_type\n"));
440 if (!partition || !type)
441 return false;
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;
450 // validity check of the type
451 return is_type_valid_pm(type, parent, child);
454 // pm_validate_initialize
455 bool
456 pm_validate_initialize(partition_data* partition, char* name,
457 const char* parameters)
459 TRACE(("intel: pm_validate_initialize\n"));
461 if (!partition || !(pm_get_supported_operations(partition)
462 & B_DISK_SYSTEM_SUPPORTS_INITIALIZING)) {
463 return false;
466 // name is ignored
467 if (name)
468 name[0] = '\0';
470 // parameters are ignored, too
472 return true;
476 // validate_create_child_partition (auxiliary function)
477 static bool
478 validate_create_child_partition(partition_data* partition, off_t* start,
479 off_t* size, fc_get_sibling_partitions getSiblingPartitions)
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);
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;
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;
500 getSiblingPartitions(partition, NULL, *start, &previousSibling,
501 &nextSibling, &previousOffset, &previousSize, &nextOffset, &nextSize);
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);
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;
515 return true;
519 // pm_validate_create_child
521 index - returns position of the new partition (first free record in MBR)
523 bool
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)
527 TRACE(("intel: pm_validate_create_child\n"));
529 if (!partition || !(pm_get_supported_operations(partition)
530 & B_DISK_SYSTEM_SUPPORTS_CREATING_CHILD)
531 || !start || !size || !type || !index) {
532 return false;
535 // TODO: check name
536 // TODO: check parameters
537 // type check
538 if (!is_type_valid_pm(type, partition))
539 return false;
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;
554 // this cannot happen
555 if (newIndex < 0)
556 return false;
557 *index = newIndex;
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);
564 return validate_create_child_partition(partition, start, size,
565 get_sibling_partitions_pm);
569 // cmp_partition_position
570 static int
571 cmp_partition_position(const void* o1, const void* o2)
573 off_t offset1 = ((PartitionPosition*)o1)->offset;
574 off_t offset2 = ((PartitionPosition*)o2)->offset;
576 if (offset1 < offset2)
577 return -1;
578 if (offset1 > offset2)
579 return 1;
581 return 0;
585 // fill_partitionable_spaces_buffer_pm
587 positions - output buffer with sufficient size
588 returns partition count
590 static int32
591 fill_partitionable_spaces_buffer_pm(partition_data* partition,
592 PartitionPosition* positions)
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++;
603 return partition_count;
607 // fill_partitionable_spaces_buffer_ep
609 positions - output buffer with sufficient size
610 returns partition count
612 static int32
613 fill_partitionable_spaces_buffer_ep(partition_data* partition,
614 PartitionPosition* positions)
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++;
625 return partition_count;
629 // get_partitionable_spaces (auxiliary function)
630 static status_t
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)
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);
646 // first sektor is MBR or EBR
647 off_t offset = startOffset + headerSize;
648 off_t size = 0;
649 int32 actualCount = 0;
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;
662 actualCount++;
664 offset = positions[i].offset + positions[i].size + headerSize;
665 offset = sector_align_up(offset, partition->block_size);
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;
675 actualCount++;
678 // cleanup
679 if (positions)
680 delete[] positions;
682 TRACE(("intel: get_partitionable_spaces - found: %" B_PRId32 "\n",
683 actualCount));
685 *_actualCount = actualCount;
687 if (count < actualCount)
688 return B_BUFFER_OVERFLOW;
689 return B_OK;
693 // pm_get_partitionable_spaces
694 status_t
695 pm_get_partitionable_spaces(partition_data* partition,
696 partitionable_space_data* buffer, int32 count, int32* actualCount)
698 TRACE(("intel: pm_get_partitionable_spaces\n"));
700 if (!partition || !partition->content_type
701 || strcmp(partition->content_type, kPartitionTypeIntel)
702 || !actualCount) {
703 return B_BAD_VALUE;
705 if (count > 0 && !buffer)
706 return B_BAD_VALUE;
708 return get_partitionable_spaces(partition, buffer, count, actualCount,
709 fill_partitionable_spaces_buffer_pm, MBR_OFFSET * partition->block_size,
710 0, 0);
714 // pm_get_next_supported_type
715 status_t
716 pm_get_next_supported_type(partition_data* partition, int32* cookie,
717 char* _type)
719 TRACE(("intel: pm_get_next_supported_type\n"));
721 if (!partition || !partition->content_type
722 || strcmp(partition->content_type, kPartitionTypeIntel)
723 || !cookie || !_type) {
724 return B_BAD_VALUE;
727 if (*cookie > 255)
728 return B_ENTRY_NOT_FOUND;
729 if (*cookie < 1)
730 *cookie = 1;
732 uint8 type = *cookie;
734 // get type
735 PartitionType ptype;
736 ptype.SetType(type);
737 if (!ptype.IsValid())
738 return B_ENTRY_NOT_FOUND;
740 ptype.GetTypeString(_type);
742 // find next type
743 if (ptype.FindNext())
744 *cookie = ptype.Type();
745 else
746 *cookie = 256;
748 return B_OK;
751 // pm_shadow_changed
752 status_t
753 pm_shadow_changed(partition_data* partition, partition_data* child,
754 uint32 operation)
756 TRACE(("intel: pm_shadow_changed(%p, %p, %" B_PRIu32 ")\n", partition,
757 child, operation));
759 switch (operation) {
760 case B_PARTITION_SHADOW:
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;
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;
780 PartitionMapCookie* map = new(nothrow) PartitionMapCookie;
781 if (!map)
782 return B_NO_MEMORY;
784 status_t error = map->Assign(
785 *(PartitionMapCookie*)physicalPartition->content_cookie);
786 if (error != B_OK) {
787 delete map;
788 return error;
791 partition->content_cookie = map;
793 return B_OK;
796 case B_PARTITION_SHADOW_CHILD:
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;
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;
813 // primary partition index
814 int32 index = ((PrimaryPartition*)physical->cookie)->Index();
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;
823 // get the primary partition
824 PartitionMapCookie* map
825 = ((PartitionMapCookie*)partition->content_cookie);
826 PrimaryPartition* primary = map->PrimaryPartitionAt(index);
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;
835 child->cookie = primary;
837 return B_OK;
840 case B_PARTITION_INITIALIZE:
842 // create an empty partition map
843 PartitionMapCookie* map = new(nothrow) PartitionMapCookie;
844 if (!map)
845 return B_NO_MEMORY;
847 partition->content_cookie = map;
849 return B_OK;
852 case B_PARTITION_CREATE_CHILD:
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;
861 PartitionMapCookie* map
862 = ((PartitionMapCookie*)partition->content_cookie);
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;
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;
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;
890 primary->SetType(type.Type());
892 // TODO: Apply parameters!
894 child->cookie = primary;
896 return B_OK;
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;
914 return B_ERROR;
918 // #pragma mark - Intel Partition Map - writing functions
921 // pm_resize
922 status_t
923 pm_resize(int fd, partition_id partitionID, off_t size, disk_job_id job)
925 TRACE(("intel: pm_resize\n"));
927 if (fd < 0)
928 return B_ERROR;
930 PartitionWriteLocker locker(partitionID);
931 if (!locker.IsLocked())
932 return B_ERROR;
934 // get out partition
935 partition_data* partition = get_partition(partitionID);
936 if (!partition)
937 return B_BAD_VALUE;
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;
945 // update data stuctures
946 update_disk_device_job_progress(job, 0.0);
948 // TODO: partition->size is not supposed to be touched.
949 partition->size = validatedSize;
950 partition->content_size = validatedSize;
952 // all changes applied
953 update_disk_device_job_progress(job, 1.0);
954 partition_modified(partitionID);
955 return B_OK;
959 // pm_resize_child
960 status_t
961 pm_resize_child(int fd, partition_id partitionID, off_t size, disk_job_id job)
963 TRACE(("intel: pm_resize_child\n"));
965 if (fd < 0)
966 return B_ERROR;
968 PartitionWriteLocker locker(partitionID);
969 if (!locker.IsLocked())
970 return B_ERROR;
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;
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;
990 // update data stuctures and write changes
991 update_disk_device_job_progress(job, 0.0);
992 primary->SetSize(validatedSize);
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;
1004 child->size = validatedSize;
1006 // all changes applied
1007 update_disk_device_job_progress(job, 1.0);
1008 partition_modified(partitionID);
1009 return B_OK;
1013 // pm_move
1014 status_t
1015 pm_move(int fd, partition_id partitionID, off_t offset, disk_job_id job)
1017 TRACE(("intel: pm_move\n"));
1019 if (fd < 0)
1020 return B_ERROR;
1022 // TODO: Should be a no-op!
1024 PartitionWriteLocker locker(partitionID);
1025 if (!locker.IsLocked())
1026 return B_ERROR;
1028 // get out partition
1029 partition_data* partition = get_partition(partitionID);
1030 if (!partition)
1031 return B_BAD_VALUE;
1033 // validate the new start
1034 if (!pm_validate_move(partition, &offset))
1035 return B_BAD_VALUE;
1037 // nothing to do here
1038 return B_OK;
1042 // allocate_buffer (auxiliary function)
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
1049 static uint8*
1050 allocate_buffer(uint32 blockSize, int32 tryAlloc, int32* allocated)
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;
1060 *allocated = 0;
1061 return NULL;
1065 // move_block (auxiliary function)
1066 static status_t
1067 move_block(int fd, off_t fromOffset, off_t toOffset, uint8* buffer, int32 size)
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;
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));
1087 return error;
1091 // move_partition (auxiliary function)
1092 static status_t
1093 move_partition(int fd, off_t fromOffset, off_t toOffset, off_t size,
1094 uint8* buffer, int32 buffer_size, disk_job_id job)
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);
1110 if (remainingSize)
1111 error = move_block(fd, fromOffset, toOffset, buffer, remainingSize);
1112 update_disk_device_job_progress(job, 1.0);
1113 return error;
1117 // pm_move_child
1118 status_t
1119 pm_move_child(int fd, partition_id partitionID, partition_id childID,
1120 off_t offset, disk_job_id job)
1122 TRACE(("intel: pm_move_child\n"));
1124 if (fd < 0)
1125 return B_ERROR;
1127 PartitionWriteLocker locker(partitionID);
1128 if (!locker.IsLocked())
1129 return B_ERROR;
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;
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;
1146 // if the old offset is the same, there is nothing to do
1147 if (child->offset == validatedOffset)
1148 return B_OK;
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;
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;
1167 // partition moved
1168 // updating data structure
1169 child->offset = validatedOffset;
1170 primary->SetOffset(validatedOffset);
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;
1180 // all changes applied
1181 update_disk_device_job_progress(job, 1.0);
1182 partition_modified(childID);
1183 return B_OK;
1187 // pm_set_type
1188 status_t
1189 pm_set_type(int fd, partition_id partitionID, const char* type, disk_job_id job)
1191 TRACE(("intel: pm_set_type\n"));
1193 if (fd < 0 || !type)
1194 return B_BAD_VALUE;
1196 PartitionWriteLocker locker(partitionID);
1197 if (!locker.IsLocked())
1198 return B_ERROR;
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;
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;
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;
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!
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());
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;
1240 free(child->type);
1241 child->type = strdup(type);
1242 if (!child->type)
1243 return B_NO_MEMORY;
1245 // all changes applied
1246 update_disk_device_job_progress(job, 1.0);
1247 partition_modified(partitionID);
1248 return B_OK;
1252 // pm_initialize
1253 status_t
1254 pm_initialize(int fd, partition_id partitionID, const char* name,
1255 const char* parameters, off_t partitionSize, disk_job_id job)
1257 TRACE(("intel: pm_initialize\n"));
1259 if (fd < 0)
1260 return B_ERROR;
1262 PartitionWriteLocker locker(partitionID);
1263 if (!locker.IsLocked())
1264 return B_ERROR;
1266 // get partition and partition map structure
1267 partition_data* partition = get_partition(partitionID);
1268 if (!partition)
1269 return B_BAD_VALUE;
1270 update_disk_device_job_progress(job, 0.0);
1272 // we will write an empty partition map
1273 PartitionMap map;
1275 // write the sector to disk
1276 PartitionMapWriter writer(fd, partition->block_size);
1277 // TODO: disk size or 2 * SECTOR_SIZE?
1278 status_t error = writer.WriteMBR(&map, true);
1279 if (error != B_OK)
1280 return error;
1282 // rescan partition
1283 error = scan_partition(partitionID);
1284 if (error != B_OK)
1285 return error;
1287 // all changes applied
1288 update_disk_device_job_progress(job, 1.0);
1289 partition_modified(partitionID);
1291 return B_OK;
1295 status_t
1296 pm_uninitialize(int fd, partition_id partitionID, off_t partitionSize,
1297 uint32 blockSize, disk_job_id job)
1299 if (blockSize == 0)
1300 return B_BAD_VALUE;
1302 // We overwrite the first block, which contains the partition table.
1303 // Allocate a buffer, we can clear and write.
1304 void* block = malloc(blockSize);
1305 if (block == NULL)
1306 return B_NO_MEMORY;
1307 MemoryDeleter blockDeleter(block);
1309 memset(block, 0, blockSize);
1311 if (write_pos(fd, 0, block, blockSize) < 0)
1312 return errno;
1314 update_disk_device_job_progress(job, 1.0);
1316 return B_OK;
1320 // pm_create_child
1321 /*! childID is used for the return value, but is also an optional input
1322 parameter -- -1 to be ignored
1324 status_t
1325 pm_create_child(int fd, partition_id partitionID, off_t offset, off_t size,
1326 const char* type, const char* name, const char* parameters,
1327 disk_job_id job, partition_id* childID)
1329 TRACE(("intel: pm_create_child\n"));
1331 if (fd < 0 || !childID)
1332 return B_BAD_VALUE;
1334 PartitionWriteLocker locker(partitionID);
1335 if (!locker.IsLocked())
1336 return B_ERROR;
1338 // get partition and partition map structure
1339 partition_data* partition = get_partition(partitionID);
1340 if (!partition)
1341 return B_BAD_VALUE;
1342 PartitionMap* map = (PartitionMap*)partition->content_cookie;
1343 if (!map)
1344 return B_BAD_VALUE;
1346 // validate the offset, size and get index of the new partition
1347 // TODO: The parameters have already been checked and must not be altered!
1348 off_t validatedOffset = offset;
1349 off_t validatedSize = size;
1350 int32 index = 0;
1352 if (!pm_validate_create_child(partition, &validatedOffset, &validatedSize,
1353 type, name, parameters, &index)) {
1354 return B_BAD_VALUE;
1357 // finding out free primary partition in the map (index from
1358 // pm_validate_create_child)
1359 PrimaryPartition* primary = map->PrimaryPartitionAt(index);
1360 if (!primary->IsEmpty())
1361 return B_BAD_DATA;
1363 // creating partition
1364 update_disk_device_job_progress(job, 0.0);
1365 partition_data* child = create_child_partition(partition->id, index,
1366 validatedOffset, validatedSize, *childID);
1367 if (!child)
1368 return B_ERROR;
1370 PartitionType ptype;
1371 ptype.SetType(type);
1373 // check parameters
1374 void* handle = parse_driver_settings_string(parameters);
1375 if (handle == NULL)
1376 return B_ERROR;
1378 bool active = get_driver_boolean_parameter(handle, "active", false, true);
1379 delete_driver_settings(handle);
1381 // set the active flags to false
1382 if (active) {
1383 for (int i = 0; i < 4; i++) {
1384 PrimaryPartition* partition = map->PrimaryPartitionAt(i);
1385 partition->SetActive(false);
1389 primary->SetPartitionTableOffset(0);
1390 primary->SetOffset(validatedOffset);
1391 primary->SetSize(validatedSize);
1392 primary->SetType(ptype.Type());
1393 primary->SetActive(active);
1395 // write changes to disk
1396 PartitionMapWriter writer(fd, primary->BlockSize());
1398 // TODO: The partition is not supposed to be locked at this point!
1399 status_t error = writer.WriteMBR(map, false);
1400 if (error != B_OK) {
1401 // putting into previous state
1402 primary->Unset();
1403 delete_partition(child->id);
1404 return error;
1407 *childID = child->id;
1409 child->block_size = primary->BlockSize();
1410 // (no name)
1411 child->type = strdup(type);
1412 // parameters
1413 child->parameters = strdup(parameters);
1414 child->cookie = primary;
1415 // check for allocation problems
1416 if (!child->type || !child->parameters)
1417 return B_NO_MEMORY;
1419 // rescan partition if needed
1420 if (strcmp(type, INTEL_EXTENDED_PARTITION_NAME) == 0) {
1421 writer.ClearExtendedHead(primary);
1422 error = scan_partition(partitionID);
1423 if (error != B_OK)
1424 return error;
1427 // all changes applied
1428 update_disk_device_job_progress(job, 1.0);
1429 partition_modified(partitionID);
1430 return B_OK;
1434 // pm_delete_child
1435 status_t
1436 pm_delete_child(int fd, partition_id partitionID, partition_id childID,
1437 disk_job_id job)
1439 TRACE(("intel: pm_delete_child\n"));
1441 if (fd < 0)
1442 return B_ERROR;
1444 PartitionWriteLocker locker(partitionID);
1445 if (!locker.IsLocked())
1446 return B_ERROR;
1448 partition_data* partition = get_partition(partitionID);
1449 partition_data* child = get_partition(childID);
1450 if (!partition || !child)
1451 return B_BAD_VALUE;
1453 PartitionMap* map = (PartitionMap*)partition->content_cookie;
1454 PrimaryPartition* primary = (PrimaryPartition*)child->cookie;
1455 if (!map || !primary)
1456 return B_BAD_VALUE;
1458 // deleting child
1459 update_disk_device_job_progress(job, 0.0);
1460 if (!delete_partition(childID))
1461 return B_ERROR;
1462 primary->Unset();
1464 // write changes to disk
1465 PartitionMapWriter writer(fd, primary->BlockSize());
1466 // TODO: disk size or 2 * SECTOR_SIZE?
1467 // TODO: The partition is not supposed to be locked at this point!
1468 status_t error = writer.WriteMBR(map, false);
1469 if (error != B_OK)
1470 return error;
1472 // all changes applied
1473 update_disk_device_job_progress(job, 1.0);
1474 partition_modified(partitionID);
1475 return B_OK;
1479 // #pragma mark - Intel Extended Partition - support functions
1482 // ep_get_supported_operations
1483 uint32
1484 ep_get_supported_operations(partition_data* partition, uint32 mask)
1486 uint32 flags = B_DISK_SYSTEM_SUPPORTS_RESIZING
1487 | B_DISK_SYSTEM_SUPPORTS_MOVING
1488 | B_DISK_SYSTEM_SUPPORTS_SETTING_CONTENT_PARAMETERS;
1490 // initializing
1491 if (partition_data* parent = get_parent_partition(partition->id)) {
1492 if (partition->type
1493 && strcmp(partition->type, kPartitionTypeIntelExtended) == 0
1494 && strcmp(parent->content_type, kPartitionTypeIntel) == 0) {
1495 flags |= B_DISK_SYSTEM_SUPPORTS_INITIALIZING;
1499 // creating child
1500 int32 countSpaces = 0;
1501 if (ep_get_partitionable_spaces(partition, NULL, 0, &countSpaces)
1502 == B_BUFFER_OVERFLOW
1503 && countSpaces > 0) {
1504 flags |= B_DISK_SYSTEM_SUPPORTS_CREATING_CHILD;
1507 return flags;
1511 // ep_get_supported_child_operations
1512 uint32
1513 ep_get_supported_child_operations(partition_data* partition,
1514 partition_data* child, uint32 mask)
1516 return B_DISK_SYSTEM_SUPPORTS_RESIZING_CHILD
1517 | B_DISK_SYSTEM_SUPPORTS_MOVING_CHILD
1518 | B_DISK_SYSTEM_SUPPORTS_SETTING_TYPE
1519 | B_DISK_SYSTEM_SUPPORTS_DELETING_CHILD;
1523 // ep_is_sub_system_for
1524 bool
1525 ep_is_sub_system_for(partition_data* partition)
1527 if (partition == NULL)
1528 return false;
1530 TRACE(("intel: ep_is_sub_system_for(%" B_PRId32 ": %" B_PRId64 ", "
1531 "%" B_PRId64 ", %" B_PRId32 ", %s)\n", partition->id, partition->offset,
1532 partition->size, partition->block_size, partition->content_type));
1534 // Intel Extended Partition can live in child partition of Intel Partition
1535 // Map
1536 return partition->content_type
1537 && !strcmp(partition->content_type, kPartitionTypeIntel);
1541 // #pragma mark - Intel Extended Partition - validate functions
1544 // ep_validate_resize
1545 bool
1546 ep_validate_resize(partition_data* partition, off_t* size)
1548 TRACE(("intel: ep_validate_resize\n"));
1550 if (!partition || !size)
1551 return false;
1553 return validate_resize(partition, size);
1557 // ep_validate_resize_child
1558 bool
1559 ep_validate_resize_child(partition_data* partition, partition_data* child,
1560 off_t* _size)
1562 TRACE(("intel: ep_validate_resize_child\n"));
1564 if (!partition || !child || !_size)
1565 return false;
1567 // validate position
1568 off_t size = *_size;
1569 if (!validate_resize_child(partition, child, child->offset,
1570 child->size, &size, get_sibling_partitions_ep))
1571 return false;
1572 *_size = size;
1573 return true;
1577 // ep_validate_move
1578 bool
1579 ep_validate_move(partition_data* partition, off_t* start)
1581 TRACE(("intel: ep_validate_move\n"));
1583 if (!partition || !start)
1584 return false;
1585 // nothing to do here
1586 return true;
1590 // ep_validate_move_child
1591 bool
1592 ep_validate_move_child(partition_data* partition, partition_data* child,
1593 off_t* _start)
1595 TRACE(("intel: ep_validate_move_child\n"));
1597 if (!partition || !child || !_start)
1598 return false;
1599 if (*_start == child->offset)
1600 return true;
1602 // validate position
1603 off_t start = *_start;
1604 if (!validate_move_child(partition, child, child->offset,
1605 child->size, &start, get_sibling_partitions_ep))
1606 return false;
1607 *_start = start;
1608 return true;
1612 // is_type_valid_ep (auxiliary function)
1613 static inline bool
1614 is_type_valid_ep(const char* type)
1616 // validity check of the type - it has to be known
1617 PartitionType ptype;
1618 ptype.SetType(type);
1619 return (ptype.IsValid() && !ptype.IsEmpty() && !ptype.IsExtended());
1623 // ep_validate_set_type
1624 bool
1625 ep_validate_set_type(partition_data* partition, const char* type)
1627 TRACE(("intel: ep_validate_set_type\n"));
1629 if (!partition || !type)
1630 return false;
1632 // validity check of the type
1633 return is_type_valid_ep(type);
1637 // ep_validate_initialize
1638 bool
1639 ep_validate_initialize(partition_data* partition, char* name,
1640 const char* parameters)
1642 TRACE(("intel: ep_validate_initialize\n"));
1644 if (!partition || !(ep_get_supported_operations(partition)
1645 & B_DISK_SYSTEM_SUPPORTS_INITIALIZING)) {
1646 return false;
1648 // name is ignored - we cannot set it to the Intel Extended Partition
1649 // TODO: check parameters - don't know whether any parameters could be set
1650 // to the Intel Extended Partition
1651 return true;
1655 // ep_validate_create_child
1656 bool
1657 ep_validate_create_child(partition_data* partition, off_t* offset, off_t* size,
1658 const char* type, const char* name, const char* parameters, int32* index)
1659 // index - returns position of the new partition (the last one)
1661 return false;
1665 // ep_get_partitionable_spaces
1666 status_t
1667 ep_get_partitionable_spaces(partition_data* partition,
1668 partitionable_space_data* buffer, int32 count, int32* actualCount)
1670 TRACE(("intel: ep_get_partitionable_spaces\n"));
1672 if (!partition || !partition->content_type
1673 || strcmp(partition->content_type, kPartitionTypeIntelExtended)
1674 || !actualCount) {
1675 return B_BAD_VALUE;
1677 if (count > 0 && !buffer)
1678 return B_BAD_VALUE;
1680 return get_partitionable_spaces(partition, buffer, count, actualCount,
1681 fill_partitionable_spaces_buffer_ep,
1682 partition->offset + PTS_OFFSET * partition->block_size,
1683 PTS_OFFSET * partition->block_size,
1684 PTS_OFFSET * partition->block_size);
1688 // ep_get_next_supported_type
1689 status_t
1690 ep_get_next_supported_type(partition_data* partition, int32* cookie,
1691 char* _type)
1693 TRACE(("intel: ep_get_next_supported_type\n"));
1695 if (!partition || !partition->content_type
1696 || strcmp(partition->content_type, kPartitionTypeIntelExtended)
1697 || !cookie || !_type) {
1698 return B_BAD_VALUE;
1701 if (*cookie > 255)
1702 return B_ENTRY_NOT_FOUND;
1703 if (*cookie < 1)
1704 *cookie = 1;
1706 uint8 type = *cookie;
1708 // get type
1709 PartitionType ptype;
1710 ptype.SetType(type);
1711 while (ptype.IsValid() && !ptype.IsExtended())
1712 ptype.FindNext();
1714 if (!ptype.IsValid())
1715 return B_ENTRY_NOT_FOUND;
1717 ptype.GetTypeString(_type);
1719 // find next type
1720 if (ptype.FindNext())
1721 *cookie = ptype.Type();
1722 else
1723 *cookie = 256;
1725 return B_OK;
1729 // ep_shadow_changed
1730 status_t
1731 ep_shadow_changed(partition_data* partition, partition_data* child,
1732 uint32 operation)
1734 TRACE(("intel: ep_shadow_changed\n"));
1736 if (!partition)
1737 return B_BAD_VALUE;
1739 // nothing to do here
1740 return B_OK;
1744 bool
1745 check_partition_location_ep(partition_data* partition, off_t offset,
1746 off_t size, off_t ptsOffset)
1748 if (!partition)
1749 return false;
1751 // make sure we are sector aligned
1752 off_t alignedOffset = sector_align(offset, partition->block_size);
1753 if (alignedOffset != offset)
1754 return false;
1756 // partition does not lie within extended partition
1757 if (offset < partition->offset
1758 || (offset > partition->offset + partition->size
1759 && offset + size <= partition->offset + partition->size))
1760 return false;
1762 // check if the new partition table is within an existing partition
1763 // or that the new partition does not overwrite an existing partition
1764 // table.
1765 for (int32 i = 0; i < partition->child_count; i++) {
1766 partition_data* sibling = get_child_partition(partition->id, i);
1767 LogicalPartition* logical = (LogicalPartition*)sibling->cookie;
1768 if (logical == NULL)
1769 return false;
1770 if (ptsOffset > logical->Offset()
1771 && ptsOffset < logical->Offset() + logical->Size())
1772 return false;
1773 if ((logical->PartitionTableOffset() >= offset
1774 && logical->PartitionTableOffset() < offset + size)
1775 || logical->PartitionTableOffset() == ptsOffset)
1776 return false;
1779 return true;
1783 // #pragma mark - Intel Extended Partition - write functions
1786 // ep_resize
1787 status_t
1788 ep_resize(int fd, partition_id partitionID, off_t size, disk_job_id job)
1790 TRACE(("intel: ep_resize\n"));
1792 if (fd < 0)
1793 return B_ERROR;
1795 PartitionWriteLocker locker(partitionID);
1796 if (!locker.IsLocked())
1797 return B_ERROR;
1799 // get out partition
1800 partition_data* partition = get_partition(partitionID);
1801 if (!partition)
1802 return B_BAD_VALUE;
1804 // validate the new size
1805 // TODO: The parameter has already been checked and must not be altered!
1806 off_t validatedSize = size;
1807 if (!ep_validate_resize(partition, &validatedSize))
1808 return B_BAD_VALUE;
1810 // update data stuctures
1811 update_disk_device_job_progress(job, 0.0);
1813 // TODO: partition->size is not supposed to be touched.
1814 partition->size = validatedSize;
1815 partition->content_size = validatedSize;
1817 // all changes applied
1818 update_disk_device_job_progress(job, 1.0);
1819 partition_modified(partitionID);
1820 return B_OK;
1824 // ep_resize_child
1825 status_t
1826 ep_resize_child(int fd, partition_id partitionID, off_t size, disk_job_id job)
1828 TRACE(("intel: ep_resize_child\n"));
1830 if (fd < 0)
1831 return B_ERROR;
1833 PartitionWriteLocker locker(partitionID);
1834 if (!locker.IsLocked())
1835 return B_ERROR;
1837 // get out partition, child and LogicalPartition structure
1838 partition_data* partition = get_parent_partition(partitionID);
1839 partition_data* child = get_partition(partitionID);
1840 if (!partition || !child)
1841 return B_BAD_VALUE;
1842 LogicalPartition* logical = (LogicalPartition*)child->cookie;
1843 PrimaryPartition* primary = (PrimaryPartition*)partition->cookie;
1844 if (!logical || !primary)
1845 return B_BAD_VALUE;
1847 // validate the new size
1848 // TODO: The parameter has already been checked and must not be altered!
1849 off_t validatedSize = size;
1850 if (!ep_validate_resize_child(partition, child, &validatedSize))
1851 return B_BAD_VALUE;
1852 if (child->size == validatedSize)
1853 return B_OK;
1855 // update data stuctures and write changes
1856 update_disk_device_job_progress(job, 0.0);
1857 logical->SetSize(validatedSize);
1859 PartitionMapWriter writer(fd, partition->block_size);
1860 // TODO: The partition is not supposed to be locked here!
1861 status_t error = writer.WriteLogical(logical, primary, false);
1862 if (error != B_OK) {
1863 // putting into previous state
1864 logical->SetSize(child->size);
1865 return error;
1867 LogicalPartition* prev = logical->Previous();
1868 error = prev ? writer.WriteLogical(prev, primary, false)
1869 : writer.WriteLogical(logical, primary, false);
1870 if (error != B_OK)
1871 // this should be not so fatal
1872 return error;
1874 child->size = validatedSize;
1876 // all changes applied
1877 update_disk_device_job_progress(job, 1.0);
1878 partition_modified(partitionID);
1879 return B_OK;
1883 // ep_move
1884 status_t
1885 ep_move(int fd, partition_id partitionID, off_t offset, disk_job_id job)
1887 TRACE(("intel: ep_move\n"));
1889 if (fd < 0)
1890 return B_ERROR;
1892 PartitionWriteLocker locker(partitionID);
1893 if (!locker.IsLocked())
1894 return B_ERROR;
1896 // get out partition
1897 partition_data* partition = get_partition(partitionID);
1898 if (!partition)
1899 return B_BAD_VALUE;
1901 // validate the new start
1902 // TODO: The parameter has already been checked and must not be altered!
1903 if (!ep_validate_move(partition, &offset))
1904 return B_BAD_VALUE;
1906 // nothing to do here
1907 return B_OK;
1911 // ep_move_child
1912 status_t
1913 ep_move_child(int fd, partition_id partitionID, partition_id childID,
1914 off_t offset, disk_job_id job)
1916 TRACE(("intel: ep_move_child\n"));
1918 if (fd < 0)
1919 return B_ERROR;
1921 PartitionWriteLocker locker(partitionID);
1922 if (!locker.IsLocked())
1923 return B_ERROR;
1925 // get partition, child and LogicalPartition structure
1926 partition_data* partition = get_partition(partitionID);
1927 partition_data* child = get_partition(childID);
1928 if (!partition || !child)
1929 return B_BAD_VALUE;
1930 LogicalPartition* logical = (LogicalPartition*)child->cookie;
1931 PrimaryPartition* primary = (PrimaryPartition*)partition->cookie;
1932 if (!logical || !primary)
1933 return B_BAD_VALUE;
1935 // TODO: The parameter has already been checked and must not be altered!
1936 off_t validatedOffset = offset;
1937 if (!ep_validate_move_child(partition, child, &validatedOffset))
1938 return B_BAD_VALUE;
1940 // if the old offset is the same, there is nothing to do
1941 if (child->offset == validatedOffset)
1942 return B_OK;
1944 off_t diffOffset = validatedOffset - child->offset;
1946 // buffer allocation
1947 int32 allocated;
1948 uint8* buffer = allocate_buffer(partition->block_size, MAX_MOVE_BUFFER,
1949 &allocated);
1950 if (!buffer)
1951 return B_NO_MEMORY;
1953 // partition moving
1954 update_disk_device_job_progress(job, 0.0);
1955 status_t error = B_OK;
1956 // move partition with its header (partition table)
1957 off_t pts_offset = logical->Offset() - logical->PartitionTableOffset();
1958 error = move_partition(fd, child->offset - pts_offset,
1959 validatedOffset - pts_offset, child->size + pts_offset, buffer,
1960 allocated * partition->block_size, job);
1961 delete[] buffer;
1962 if (error != B_OK)
1963 return error;
1965 // partition moved
1966 // updating data structure
1967 child->offset = validatedOffset;
1968 logical->SetOffset(logical->Offset() + diffOffset);
1969 logical->SetPartitionTableOffset(logical->PartitionTableOffset() + diffOffset);
1971 PartitionMapWriter writer(fd, partition->block_size);
1972 // TODO: If partition->offset is > prev->offset, then writing
1973 // the previous logical partition table will fail!
1974 // TODO: The partition is not supposed to be locked here!
1975 error = writer.WriteLogical(logical, primary, false);
1976 if (error != B_OK)
1977 // something went wrong - this is fatal (partition has been moved)
1978 // but EBR is not updated
1979 return error;
1980 LogicalPartition* prev = logical->Previous();
1981 error = prev ? writer.WriteLogical(prev, primary, false)
1982 : writer.WriteLogical(logical, primary, false);
1983 if (error != B_OK)
1984 // this is fatal - linked list is not updated
1985 return error;
1987 // all changes applied
1988 update_disk_device_job_progress(job, 1.0);
1989 partition_modified(childID);
1990 return B_OK;
1994 // ep_set_type
1995 status_t
1996 ep_set_type(int fd, partition_id partitionID, const char* type, disk_job_id job)
1998 TRACE(("intel: ep_set_type\n"));
2000 if (fd < 0 || !type)
2001 return B_BAD_VALUE;
2003 PartitionWriteLocker locker(partitionID);
2004 if (!locker.IsLocked())
2005 return B_ERROR;
2007 // get partition, child and LogicalPartition structure
2008 partition_data* partition = get_parent_partition(partitionID);
2009 partition_data* child = get_partition(partitionID);
2010 if (!partition || !child)
2011 return B_BAD_VALUE;
2012 LogicalPartition* logical = (LogicalPartition*)child->cookie;
2013 PrimaryPartition* primary = (PrimaryPartition*)partition->cookie;
2014 if (!logical || !primary)
2015 return B_BAD_VALUE;
2017 // TODO: The parameter has already been checked and must not be altered!
2018 if (!ep_validate_set_type(child, type))
2019 return B_BAD_VALUE;
2021 // if the old type is the same, there is nothing to do
2022 if (child->type && !strcmp(type, child->type))
2023 return B_OK;
2025 PartitionType ptype;
2026 ptype.SetType(type);
2027 // this is impossible
2028 if (!ptype.IsValid() || ptype.IsEmpty() || ptype.IsExtended())
2029 return false;
2031 // setting type to the partition
2032 update_disk_device_job_progress(job, 0.0);
2033 uint8 oldType = logical->Type();
2034 logical->SetType(ptype.Type());
2036 PartitionMapWriter writer(fd, partition->block_size);
2037 // TODO: The partition is not supposed to be locked here!
2038 status_t error = writer.WriteLogical(logical, primary, false);
2039 if (error != B_OK) {
2040 // something went wrong - putting into previous state
2041 logical->SetType(oldType);
2042 return error;
2045 free(child->type);
2046 child->type = strdup(type);
2047 if (!child->type)
2048 return B_NO_MEMORY;
2050 // all changes applied
2051 update_disk_device_job_progress(job, 1.0);
2052 partition_modified(partitionID);
2053 return B_OK;
2057 // ep_initialize
2058 status_t
2059 ep_initialize(int fd, partition_id partitionID, const char* name,
2060 const char* parameters, off_t partitionSize, disk_job_id job)
2062 TRACE(("intel: ep_initialize\n"));
2064 if (fd < 0)
2065 return B_ERROR;
2067 PartitionWriteLocker locker(partitionID);
2068 if (!locker.IsLocked())
2069 return B_ERROR;
2071 // get partition
2072 partition_data* partition = get_partition(partitionID);
2073 if (!partition)
2074 return B_BAD_VALUE;
2076 PrimaryPartition* primary = (PrimaryPartition*)partition->cookie;
2077 if (!primary)
2078 return B_BAD_VALUE;
2080 // name is ignored - we cannot set it to the Intel Extended Partition
2081 // TODO: The parameter has already been checked and must not be altered!
2082 if (!ep_validate_initialize(partition, NULL, parameters))
2083 return B_BAD_VALUE;
2085 // partition init (we have no child partition)
2086 update_disk_device_job_progress(job, 0.0);
2087 // fill in the partition_data structure
2088 partition->status = B_PARTITION_VALID;
2089 partition->flags |= B_PARTITION_PARTITIONING_SYSTEM;
2090 partition->content_size = partition->size;
2091 // (no content_name and content_parameters)
2092 // (content_type is set by the system)
2093 partition->content_cookie = primary;
2095 // we delete code area in EBR - nothing should be there
2096 partition_table table;
2097 table.clear_code_area();
2099 PartitionMapWriter writer(fd, partition->block_size);
2100 // TODO: The partition is not supposed to be locked here!
2101 status_t error = writer.ClearExtendedHead(primary);
2102 if (error != B_OK)
2103 return error;
2105 // all changes applied
2106 update_disk_device_job_progress(job, 1.0);
2107 partition_modified(partitionID);
2108 return B_OK;
2112 // ep_create_child
2114 childID is used for the return value, but is also an optional input
2115 parameter -- -1 to be ignored
2117 status_t
2118 ep_create_child(int fd, partition_id partitionID, off_t offset, off_t size,
2119 const char* type, const char* name, const char* parameters, disk_job_id job,
2120 partition_id* childID)
2122 TRACE(("intel: ep_create_child\n"));
2124 if (fd < 0 || !childID)
2125 return B_BAD_VALUE;
2127 // aquire lock
2128 PartitionWriteLocker locker(partitionID);
2129 if (!locker.IsLocked())
2130 return B_ERROR;
2132 // get partition data
2133 partition_data* partition = get_partition(partitionID);
2134 partition_data* parent = get_parent_partition(partitionID);
2135 if (partition == NULL || parent == NULL)
2136 return B_BAD_VALUE;
2138 PrimaryPartition* primary = (PrimaryPartition*)partition->cookie;
2139 if (!primary)
2140 return B_BAD_VALUE;
2142 // parse parameters
2143 void* handle = parse_driver_settings_string(parameters);
2144 if (handle == NULL)
2145 return B_ERROR;
2147 bool active = get_driver_boolean_parameter(handle, "active", false, true);
2149 off_t ptsOffset = 0;
2150 const char* buffer = get_driver_parameter(
2151 handle, "partition_table_offset", NULL, NULL);
2152 if (buffer != NULL)
2153 ptsOffset = strtoull(buffer, NULL, 10);
2154 else {
2155 delete_driver_settings(handle);
2156 return B_BAD_VALUE;
2158 delete_driver_settings(handle);
2160 // check the partition location
2161 if (!check_partition_location_ep(partition, offset, size, ptsOffset))
2162 return B_BAD_VALUE;
2164 // creating partition
2165 update_disk_device_job_progress(job, 0.0);
2166 partition_data* child = create_child_partition(partition->id,
2167 partition->child_count, offset, size, *childID);
2168 if (!child)
2169 return B_ERROR;
2171 // setup logical partition
2172 LogicalPartition* logical = new(nothrow) LogicalPartition;
2173 if (!logical)
2174 return B_NO_MEMORY;
2176 PartitionType ptype;
2177 ptype.SetType(type);
2178 logical->SetPartitionTableOffset(ptsOffset - parent->offset);
2179 logical->SetOffset(offset);
2180 logical->SetSize(size);
2181 logical->SetType(ptype.Type());
2182 logical->SetActive(active);
2183 logical->SetPrimaryPartition(primary);
2184 logical->SetBlockSize(partition->block_size);
2185 primary->AddLogicalPartition(logical);
2187 int parentFD = open_partition(parent->id, O_RDWR);
2188 if (parentFD < 0) {
2189 primary->RemoveLogicalPartition(logical);
2190 delete logical;
2191 return B_IO_ERROR;
2194 // write changes to disk
2195 PartitionMapWriter writer(parentFD, primary->BlockSize());
2197 // Write the logical partition's EBR first in case of failure.
2198 // This way we will not add a partition to the previous logical
2199 // partition. If there is no previous logical partition then write
2200 // the current partition's EBR to the first sector of the primary partition
2201 status_t error = writer.WriteLogical(logical, primary, true);
2202 if (error != B_OK) {
2203 primary->RemoveLogicalPartition(logical);
2204 delete logical;
2205 return error;
2208 LogicalPartition* previous = logical->Previous();
2209 if (previous != NULL) {
2210 error = writer.WriteLogical(previous, primary, true);
2211 if (error != B_OK) {
2212 primary->RemoveLogicalPartition(logical);
2213 delete logical;
2214 return error;
2217 *childID = child->id;
2219 child->block_size = logical->BlockSize();
2220 child->type = strdup(type);
2221 child->parameters = strdup(parameters);
2222 child->cookie = logical;
2223 // check for allocation problems
2224 if (!child->type || !child->parameters)
2225 error = B_NO_MEMORY;
2227 // all changes applied
2228 update_disk_device_job_progress(job, 1.0);
2229 partition_modified(partitionID);
2230 return B_OK;
2234 // ep_delete_child
2235 status_t
2236 ep_delete_child(int fd, partition_id partitionID, partition_id childID,
2237 disk_job_id job)
2239 TRACE(("intel: ep_delete_child\n"));
2241 if (fd < 0)
2242 return B_ERROR;
2244 PartitionWriteLocker locker(partitionID);
2245 if (!locker.IsLocked())
2246 return B_ERROR;
2248 partition_data* partition = get_partition(partitionID);
2249 partition_data* parent = get_parent_partition(partitionID);
2250 partition_data* child = get_partition(childID);
2251 if (partition == NULL || parent == NULL || child == NULL)
2252 return B_BAD_VALUE;
2254 PrimaryPartition* primary = (PrimaryPartition*)partition->cookie;
2255 LogicalPartition* logical = (LogicalPartition*)child->cookie;
2256 if (primary == NULL || logical == NULL)
2257 return B_BAD_VALUE;
2259 // deleting child
2260 update_disk_device_job_progress(job, 0.0);
2261 if (!delete_partition(childID))
2262 return B_ERROR;
2264 LogicalPartition* previous = logical->Previous();
2265 LogicalPartition* next = logical->Next();
2267 primary->RemoveLogicalPartition(logical);
2268 delete logical;
2270 int parentFD = open_partition(parent->id, O_RDWR);
2271 if (parentFD < 0)
2272 return B_IO_ERROR;
2274 // write changes to disk
2275 PartitionMapWriter writer(parentFD, primary->BlockSize());
2277 status_t error;
2278 if (previous != NULL) {
2279 error = writer.WriteLogical(previous, primary, true);
2280 } else {
2281 error = writer.WriteExtendedHead(next, primary, true);
2283 if (next != NULL) {
2284 next->SetPartitionTableOffset(primary->Offset());
2286 partition_data* nextSibling = NULL;
2287 if (get_partition_from_offset_ep(partition, next->Offset(),
2288 &nextSibling)) {
2289 char buffer[128];
2290 sprintf(buffer, "active %s ;\npartition_table_offset %" B_PRId64
2291 " ;\n", next->Active() ? "true" : "false",
2292 next->PartitionTableOffset());
2293 nextSibling->parameters = strdup(buffer);
2298 close(parentFD);
2300 if (error != B_OK)
2301 return error;
2303 // all changes applied
2304 update_disk_device_job_progress(job, 1.0);
2305 partition_modified(partitionID);
2306 return B_OK;