2 * Copyright 2003-2011, Haiku, Inc. All Rights Reserved.
3 * Distributed under the terms of the MIT License.
6 * Ingo Weinhold, ingo_weinhold@gmx.de
7 * Tomas Kucera, kucerat@centrum.cz
11 #include "write_support.h"
20 #include <DiskDeviceTypes.h>
21 #include <KernelExport.h>
23 #include <AutoDeleter.h>
26 #include "PartitionLocker.h"
27 #include "PartitionMap.h"
28 #include "PartitionMapParser.h"
29 #include "PartitionMapWriter.h"
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
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
;
78 int32 countSpaces
= 0;
79 if (partition
->child_count
< 4
81 && pm_get_partitionable_spaces(partition
, NULL
, 0, &countSpaces
)
84 flags
|= B_DISK_SYSTEM_SUPPORTS_CREATING_CHILD
;
91 // pm_get_supported_child_operations
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
105 pm_is_sub_system_for(partition_data
* partition
)
107 // primary partition map doesn't naturally live in any other child partition
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
;
127 // #pragma mark - Intel Partition Map - validate functions
130 // sector_align (auxiliary function)
132 sector_align(off_t offset
, int32 blockSize
)
134 return offset
/ blockSize
* blockSize
;
138 // sector_align_up (auxiliary function)
140 sector_align_up(off_t offset
, int32 blockSize
)
142 return (offset
+ blockSize
- 1) / blockSize
* blockSize
;
146 // validate_resize (auxiliary function)
148 validate_resize(partition_data
* partition
, off_t
* size
)
150 off_t newSize
= *size
;
151 // size remains the same?
152 if (newSize
== partition
->size
)
158 newSize
= sector_align(newSize
, partition
->block_size
);
161 if (newSize
> partition
->size
) {
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
);
184 // pm_validate_resize
186 pm_validate_resize(partition_data
* partition
, off_t
* size
)
188 TRACE(("intel: pm_validate_resize\n"));
190 if (!partition
|| !size
)
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
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
;
219 // sibling->offset > childOffset
220 if (!nextSibling
|| nextSibling
->offset
> sibling
->offset
)
221 nextSibling
= sibling
;
225 *previous
= previousSibling
;
227 if (previousSibling
) {
228 *previousOffset
= previousSibling
->offset
;
229 *previousSize
= previousSibling
->size
;
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
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
;
260 // get_offset_ep(sibling) > childOffset
261 if (!nextSibling
|| nextSibling
->offset
> sibling
->offset
)
262 nextSibling
= sibling
;
266 *previous
= previousSibling
;
268 if (previousSibling
) {
269 *previousOffset
= previousSibling
->offset
;
270 *previousSize
= previousSibling
->size
;
273 *nextOffset
= nextSibling
->offset
;
274 *nextSize
= nextSibling
->size
;
279 // validate_resize_child (auxiliary function)
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
)
289 if (*size
< childSize
) {
292 // make the size a multiple of the block size
293 *size
= sector_align(*size
, partition
->block_size
);
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
);
317 // pm_validate_resize_child
319 pm_validate_resize_child(partition_data
* partition
, partition_data
* child
,
322 TRACE(("intel: pm_validate_resize_child\n"));
324 if (!partition
|| !child
|| !size
)
327 return validate_resize_child(partition
, child
, child
->offset
,
328 child
->size
, size
, get_sibling_partitions_pm
);
334 pm_validate_move(partition_data
* partition
, off_t
* start
)
336 TRACE(("intel: pm_validate_move\n"));
338 if (!partition
|| !start
)
340 // nothing to do here
345 // validate_move_child (auxiliary function)
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
;
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
) {
371 if (previousSibling
&& previousOffset
+ previousSize
> start
) {
372 start
= previousOffset
+ previousSize
;
373 start
= sector_align_up(start
, partition
->block_size
);
377 if (nextSibling
&& nextOffset
< start
+ childSize
) {
378 start
= nextOffset
- childSize
;
379 start
= sector_align(start
, partition
->block_size
);
387 // pm_validate_move_child
389 pm_validate_move_child(partition_data
* partition
, partition_data
* child
,
392 TRACE(("intel: pm_validate_move_child\n"));
394 if (!partition
|| !child
|| !start
)
396 if (*start
== child
->offset
)
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
410 is_type_valid_pm(const char* type
, partition_data
* partition
,
411 PrimaryPartition
* child
= NULL
)
413 // validity check of the type
416 if (!ptype
.IsValid() || ptype
.IsEmpty())
419 // only one extended partition is allowed
420 if (ptype
.IsExtended()) {
421 PartitionMap
* map
= (PartitionMap
*)partition
->content_cookie
;
424 for (int32 i
= 0; i
< partition
->child_count
; i
++) {
425 PrimaryPartition
* primary
= map
->PrimaryPartitionAt(i
);
426 if (primary
&& primary
->IsExtended() && primary
!= child
)
434 // pm_validate_set_type
436 pm_validate_set_type(partition_data
* partition
, const char* type
)
438 TRACE(("intel: pm_validate_set_type\n"));
440 if (!partition
|| !type
)
443 partition_data
* parent
= get_parent_partition(partition
->id
);
446 PrimaryPartition
* child
= (PrimaryPartition
*)partition
->cookie
;
450 // validity check of the type
451 return is_type_valid_pm(type
, parent
, child
);
454 // pm_validate_initialize
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
)) {
470 // parameters are ignored, too
476 // validate_create_child_partition (auxiliary function)
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
);
486 *size
= sector_align(*size
, partition
->block_size
);
488 // child must completely lie within the parent partition
489 if (*start
>= partition
->offset
+ partition
->size
)
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
);
519 // pm_validate_create_child
521 index - returns position of the new partition (first free record in MBR)
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
) {
536 // TODO: check parameters
538 if (!is_type_valid_pm(type
, partition
))
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
;
547 for (int32 i
= 0; i
< 4; i
++) {
548 PrimaryPartition
* primary
= map
->PrimaryPartitionAt(i
);
549 if (primary
->IsEmpty()) {
554 // this cannot happen
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
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
)
578 if (offset1
> offset2
)
585 // fill_partitionable_spaces_buffer_pm
587 positions - output buffer with sufficient size
588 returns partition count
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
);
598 positions
[partition_count
].offset
= child
->offset
;
599 positions
[partition_count
].size
= child
->size
;
603 return partition_count
;
607 // fill_partitionable_spaces_buffer_ep
609 positions - output buffer with sufficient size
610 returns partition count
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
);
620 positions
[partition_count
].offset
= child
->offset
;
621 positions
[partition_count
].size
= child
->size
;
625 return partition_count
;
629 // get_partitionable_spaces (auxiliary function)
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
];
641 int32 partition_count
= fillBuffer(partition
, positions
);
643 qsort(positions
, partition_count
, sizeof(PartitionPosition
),
644 cmp_partition_position
);
646 // first sektor is MBR or EBR
647 off_t offset
= startOffset
+ headerSize
;
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
;
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
);
671 if (actualCount
< count
) {
672 buffer
[actualCount
].offset
= offset
;
673 buffer
[actualCount
].size
= size
;
682 TRACE(("intel: get_partitionable_spaces - found: %" B_PRId32
"\n",
685 *_actualCount
= actualCount
;
687 if (count
< actualCount
)
688 return B_BUFFER_OVERFLOW
;
693 // pm_get_partitionable_spaces
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
)
705 if (count
> 0 && !buffer
)
708 return get_partitionable_spaces(partition
, buffer
, count
, actualCount
,
709 fill_partitionable_spaces_buffer_pm
, MBR_OFFSET
* partition
->block_size
,
714 // pm_get_next_supported_type
716 pm_get_next_supported_type(partition_data
* partition
, int32
* cookie
,
719 TRACE(("intel: pm_get_next_supported_type\n"));
721 if (!partition
|| !partition
->content_type
722 || strcmp(partition
->content_type
, kPartitionTypeIntel
)
723 || !cookie
|| !_type
) {
728 return B_ENTRY_NOT_FOUND
;
732 uint8 type
= *cookie
;
737 if (!ptype
.IsValid())
738 return B_ENTRY_NOT_FOUND
;
740 ptype
.GetTypeString(_type
);
743 if (ptype
.FindNext())
744 *cookie
= ptype
.Type();
753 pm_shadow_changed(partition_data
* partition
, partition_data
* child
,
756 TRACE(("intel: pm_shadow_changed(%p, %p, %" B_PRIu32
")\n", partition
,
760 case B_PARTITION_SHADOW
:
762 // get the physical partition
763 partition_data
* physicalPartition
= get_partition(
765 if (!physicalPartition
) {
766 dprintf("intel: pm_shadow_changed(B_PARTITION_SHADOW): no "
767 "physical partition with ID %" B_PRId32
"\n",
773 if (!physicalPartition
->content_cookie
) {
774 dprintf("intel: pm_shadow_changed(B_PARTITION_SHADOW): no "
775 "content cookie, physical partition: %" B_PRId32
"\n",
780 PartitionMapCookie
* map
= new(nothrow
) PartitionMapCookie
;
784 status_t error
= map
->Assign(
785 *(PartitionMapCookie
*)physicalPartition
->content_cookie
);
791 partition
->content_cookie
= map
;
796 case B_PARTITION_SHADOW_CHILD
:
798 // get the physical child partition
799 partition_data
* physical
= get_partition(child
->id
);
801 dprintf("intel: pm_shadow_changed(B_PARTITION_SHADOW_CHILD): "
802 "no physical partition with ID %" B_PRId32
"\n", child
->id
);
806 if (!physical
->cookie
) {
807 dprintf("intel: pm_shadow_changed(B_PARTITION_SHADOW_CHILD): "
808 "no cookie, physical partition: %" B_PRId32
"\n",
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",
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
);
835 child
->cookie
= primary
;
840 case B_PARTITION_INITIALIZE
:
842 // create an empty partition map
843 PartitionMapCookie
* map
= new(nothrow
) PartitionMapCookie
;
847 partition
->content_cookie
= map
;
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",
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
);
874 dprintf("intel: pm_shadow_changed(B_PARTITION_CREATE_CHILD): "
875 "no empty primary slot, partition: %" B_PRId32
"\n",
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",
890 primary
->SetType(type
.Type());
892 // TODO: Apply parameters!
894 child
->cookie
= primary
;
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
:
918 // #pragma mark - Intel Partition Map - writing functions
923 pm_resize(int fd
, partition_id partitionID
, off_t size
, disk_job_id job
)
925 TRACE(("intel: pm_resize\n"));
930 PartitionWriteLocker
locker(partitionID
);
931 if (!locker
.IsLocked())
935 partition_data
* partition
= get_partition(partitionID
);
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
))
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
);
961 pm_resize_child(int fd
, partition_id partitionID
, off_t size
, disk_job_id job
)
963 TRACE(("intel: pm_resize_child\n"));
968 PartitionWriteLocker
locker(partitionID
);
969 if (!locker
.IsLocked())
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
)
977 PartitionMap
* map
= (PartitionMap
*)partition
->content_cookie
;
978 PrimaryPartition
* primary
= (PrimaryPartition
*)child
->cookie
;
979 if (!map
|| !primary
)
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
))
987 if (child
->size
== validatedSize
)
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());
997 status_t error
= writer
.WriteMBR(map
, false);
999 // putting into previous state
1000 primary
->SetSize(child
->size
);
1004 child
->size
= validatedSize
;
1006 // all changes applied
1007 update_disk_device_job_progress(job
, 1.0);
1008 partition_modified(partitionID
);
1015 pm_move(int fd
, partition_id partitionID
, off_t offset
, disk_job_id job
)
1017 TRACE(("intel: pm_move\n"));
1022 // TODO: Should be a no-op!
1024 PartitionWriteLocker
locker(partitionID
);
1025 if (!locker
.IsLocked())
1028 // get out partition
1029 partition_data
* partition
= get_partition(partitionID
);
1033 // validate the new start
1034 if (!pm_validate_move(partition
, &offset
))
1037 // nothing to do here
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
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
];
1065 // move_block (auxiliary function)
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
) {
1075 TRACE(("intel: move_block(): reading failed: %" B_PRIx32
"\n", error
));
1079 // write block from buffer
1080 if (write_pos(fd
, toOffset
, buffer
, size
) != size
) {
1084 TRACE(("intel: move_block(): writing failed: %" B_PRIx32
"\n", error
));
1091 // move_partition (auxiliary function)
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
);
1106 fromOffset
+= buffer_size
;
1107 toOffset
+= buffer_size
;
1108 update_disk_device_job_progress(job
, (float)i
/ cycleCount
);
1111 error
= move_block(fd
, fromOffset
, toOffset
, buffer
, remainingSize
);
1112 update_disk_device_job_progress(job
, 1.0);
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"));
1127 PartitionWriteLocker
locker(partitionID
);
1128 if (!locker
.IsLocked())
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
)
1136 PartitionMap
* map
= (PartitionMap
*)partition
->content_cookie
;
1137 PrimaryPartition
* primary
= (PrimaryPartition
*)child
->cookie
;
1138 if (!map
|| !primary
)
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
))
1146 // if the old offset is the same, there is nothing to do
1147 if (child
->offset
== validatedOffset
)
1150 // buffer allocation
1152 uint8
* buffer
= allocate_buffer(partition
->block_size
, MAX_MOVE_BUFFER
,
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
);
1168 // updating data structure
1169 child
->offset
= validatedOffset
;
1170 primary
->SetOffset(validatedOffset
);
1172 PartitionMapWriter
writer(fd
, partition
->block_size
);
1174 error
= writer
.WriteMBR(map
, false);
1176 // something went wrong - this is fatal (partition has been moved)
1177 // but MBR is not updated
1180 // all changes applied
1181 update_disk_device_job_progress(job
, 1.0);
1182 partition_modified(childID
);
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
)
1196 PartitionWriteLocker
locker(partitionID
);
1197 if (!locker
.IsLocked())
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
)
1205 PartitionMap
* map
= (PartitionMap
*)partition
->content_cookie
;
1206 PrimaryPartition
* primary
= (PrimaryPartition
*)child
->cookie
;
1207 if (!map
|| !primary
)
1210 // TODO: The parameter has already been checked and must not be altered!
1211 if (!pm_validate_set_type(child
, type
))
1214 // if the old type is the same, there is nothing to do
1215 if (child
->type
&& !strcmp(type
, child
->type
))
1218 PartitionType ptype
;
1219 ptype
.SetType(type
);
1220 // this is impossible
1221 if (!ptype
.IsValid() || ptype
.IsEmpty())
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());
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
);
1241 child
->type
= strdup(type
);
1245 // all changes applied
1246 update_disk_device_job_progress(job
, 1.0);
1247 partition_modified(partitionID
);
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"));
1262 PartitionWriteLocker
locker(partitionID
);
1263 if (!locker
.IsLocked())
1266 // get partition and partition map structure
1267 partition_data
* partition
= get_partition(partitionID
);
1270 update_disk_device_job_progress(job
, 0.0);
1272 // we will write an empty partition 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);
1283 error
= scan_partition(partitionID
);
1287 // all changes applied
1288 update_disk_device_job_progress(job
, 1.0);
1289 partition_modified(partitionID
);
1296 pm_uninitialize(int fd
, partition_id partitionID
, off_t partitionSize
,
1297 uint32 blockSize
, disk_job_id job
)
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
);
1307 MemoryDeleter
blockDeleter(block
);
1309 memset(block
, 0, blockSize
);
1311 if (write_pos(fd
, 0, block
, blockSize
) < 0)
1314 update_disk_device_job_progress(job
, 1.0);
1321 /*! childID is used for the return value, but is also an optional input
1322 parameter -- -1 to be ignored
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
)
1334 PartitionWriteLocker
locker(partitionID
);
1335 if (!locker
.IsLocked())
1338 // get partition and partition map structure
1339 partition_data
* partition
= get_partition(partitionID
);
1342 PartitionMap
* map
= (PartitionMap
*)partition
->content_cookie
;
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
;
1352 if (!pm_validate_create_child(partition
, &validatedOffset
, &validatedSize
,
1353 type
, name
, parameters
, &index
)) {
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())
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
);
1370 PartitionType ptype
;
1371 ptype
.SetType(type
);
1374 void* handle
= parse_driver_settings_string(parameters
);
1378 bool active
= get_driver_boolean_parameter(handle
, "active", false, true);
1379 delete_driver_settings(handle
);
1381 // set the active flags to false
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
1403 delete_partition(child
->id
);
1407 *childID
= child
->id
;
1409 child
->block_size
= primary
->BlockSize();
1411 child
->type
= strdup(type
);
1413 child
->parameters
= strdup(parameters
);
1414 child
->cookie
= primary
;
1415 // check for allocation problems
1416 if (!child
->type
|| !child
->parameters
)
1419 // rescan partition if needed
1420 if (strcmp(type
, INTEL_EXTENDED_PARTITION_NAME
) == 0) {
1421 writer
.ClearExtendedHead(primary
);
1422 error
= scan_partition(partitionID
);
1427 // all changes applied
1428 update_disk_device_job_progress(job
, 1.0);
1429 partition_modified(partitionID
);
1436 pm_delete_child(int fd
, partition_id partitionID
, partition_id childID
,
1439 TRACE(("intel: pm_delete_child\n"));
1444 PartitionWriteLocker
locker(partitionID
);
1445 if (!locker
.IsLocked())
1448 partition_data
* partition
= get_partition(partitionID
);
1449 partition_data
* child
= get_partition(childID
);
1450 if (!partition
|| !child
)
1453 PartitionMap
* map
= (PartitionMap
*)partition
->content_cookie
;
1454 PrimaryPartition
* primary
= (PrimaryPartition
*)child
->cookie
;
1455 if (!map
|| !primary
)
1459 update_disk_device_job_progress(job
, 0.0);
1460 if (!delete_partition(childID
))
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);
1472 // all changes applied
1473 update_disk_device_job_progress(job
, 1.0);
1474 partition_modified(partitionID
);
1479 // #pragma mark - Intel Extended Partition - support functions
1482 // ep_get_supported_operations
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
;
1491 if (partition_data
* parent
= get_parent_partition(partition
->id
)) {
1493 && strcmp(partition
->type
, kPartitionTypeIntelExtended
) == 0
1494 && strcmp(parent
->content_type
, kPartitionTypeIntel
) == 0) {
1495 flags
|= B_DISK_SYSTEM_SUPPORTS_INITIALIZING
;
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
;
1511 // ep_get_supported_child_operations
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
1525 ep_is_sub_system_for(partition_data
* partition
)
1527 if (partition
== NULL
)
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
1536 return partition
->content_type
1537 && !strcmp(partition
->content_type
, kPartitionTypeIntel
);
1541 // #pragma mark - Intel Extended Partition - validate functions
1544 // ep_validate_resize
1546 ep_validate_resize(partition_data
* partition
, off_t
* size
)
1548 TRACE(("intel: ep_validate_resize\n"));
1550 if (!partition
|| !size
)
1553 return validate_resize(partition
, size
);
1557 // ep_validate_resize_child
1559 ep_validate_resize_child(partition_data
* partition
, partition_data
* child
,
1562 TRACE(("intel: ep_validate_resize_child\n"));
1564 if (!partition
|| !child
|| !_size
)
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
))
1579 ep_validate_move(partition_data
* partition
, off_t
* start
)
1581 TRACE(("intel: ep_validate_move\n"));
1583 if (!partition
|| !start
)
1585 // nothing to do here
1590 // ep_validate_move_child
1592 ep_validate_move_child(partition_data
* partition
, partition_data
* child
,
1595 TRACE(("intel: ep_validate_move_child\n"));
1597 if (!partition
|| !child
|| !_start
)
1599 if (*_start
== child
->offset
)
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
))
1612 // is_type_valid_ep (auxiliary function)
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
1625 ep_validate_set_type(partition_data
* partition
, const char* type
)
1627 TRACE(("intel: ep_validate_set_type\n"));
1629 if (!partition
|| !type
)
1632 // validity check of the type
1633 return is_type_valid_ep(type
);
1637 // ep_validate_initialize
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
)) {
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
1655 // ep_validate_create_child
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)
1665 // ep_get_partitionable_spaces
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
)
1677 if (count
> 0 && !buffer
)
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
1690 ep_get_next_supported_type(partition_data
* partition
, int32
* cookie
,
1693 TRACE(("intel: ep_get_next_supported_type\n"));
1695 if (!partition
|| !partition
->content_type
1696 || strcmp(partition
->content_type
, kPartitionTypeIntelExtended
)
1697 || !cookie
|| !_type
) {
1702 return B_ENTRY_NOT_FOUND
;
1706 uint8 type
= *cookie
;
1709 PartitionType ptype
;
1710 ptype
.SetType(type
);
1711 while (ptype
.IsValid() && !ptype
.IsExtended())
1714 if (!ptype
.IsValid())
1715 return B_ENTRY_NOT_FOUND
;
1717 ptype
.GetTypeString(_type
);
1720 if (ptype
.FindNext())
1721 *cookie
= ptype
.Type();
1729 // ep_shadow_changed
1731 ep_shadow_changed(partition_data
* partition
, partition_data
* child
,
1734 TRACE(("intel: ep_shadow_changed\n"));
1739 // nothing to do here
1745 check_partition_location_ep(partition_data
* partition
, off_t offset
,
1746 off_t size
, off_t ptsOffset
)
1751 // make sure we are sector aligned
1752 off_t alignedOffset
= sector_align(offset
, partition
->block_size
);
1753 if (alignedOffset
!= offset
)
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
))
1762 // check if the new partition table is within an existing partition
1763 // or that the new partition does not overwrite an existing partition
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
)
1770 if (ptsOffset
> logical
->Offset()
1771 && ptsOffset
< logical
->Offset() + logical
->Size())
1773 if ((logical
->PartitionTableOffset() >= offset
1774 && logical
->PartitionTableOffset() < offset
+ size
)
1775 || logical
->PartitionTableOffset() == ptsOffset
)
1783 // #pragma mark - Intel Extended Partition - write functions
1788 ep_resize(int fd
, partition_id partitionID
, off_t size
, disk_job_id job
)
1790 TRACE(("intel: ep_resize\n"));
1795 PartitionWriteLocker
locker(partitionID
);
1796 if (!locker
.IsLocked())
1799 // get out partition
1800 partition_data
* partition
= get_partition(partitionID
);
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
))
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
);
1826 ep_resize_child(int fd
, partition_id partitionID
, off_t size
, disk_job_id job
)
1828 TRACE(("intel: ep_resize_child\n"));
1833 PartitionWriteLocker
locker(partitionID
);
1834 if (!locker
.IsLocked())
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
)
1842 LogicalPartition
* logical
= (LogicalPartition
*)child
->cookie
;
1843 PrimaryPartition
* primary
= (PrimaryPartition
*)partition
->cookie
;
1844 if (!logical
|| !primary
)
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
))
1852 if (child
->size
== validatedSize
)
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
);
1867 LogicalPartition
* prev
= logical
->Previous();
1868 error
= prev
? writer
.WriteLogical(prev
, primary
, false)
1869 : writer
.WriteLogical(logical
, primary
, false);
1871 // this should be not so fatal
1874 child
->size
= validatedSize
;
1876 // all changes applied
1877 update_disk_device_job_progress(job
, 1.0);
1878 partition_modified(partitionID
);
1885 ep_move(int fd
, partition_id partitionID
, off_t offset
, disk_job_id job
)
1887 TRACE(("intel: ep_move\n"));
1892 PartitionWriteLocker
locker(partitionID
);
1893 if (!locker
.IsLocked())
1896 // get out partition
1897 partition_data
* partition
= get_partition(partitionID
);
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
))
1906 // nothing to do here
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"));
1921 PartitionWriteLocker
locker(partitionID
);
1922 if (!locker
.IsLocked())
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
)
1930 LogicalPartition
* logical
= (LogicalPartition
*)child
->cookie
;
1931 PrimaryPartition
* primary
= (PrimaryPartition
*)partition
->cookie
;
1932 if (!logical
|| !primary
)
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
))
1940 // if the old offset is the same, there is nothing to do
1941 if (child
->offset
== validatedOffset
)
1944 off_t diffOffset
= validatedOffset
- child
->offset
;
1946 // buffer allocation
1948 uint8
* buffer
= allocate_buffer(partition
->block_size
, MAX_MOVE_BUFFER
,
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
);
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);
1977 // something went wrong - this is fatal (partition has been moved)
1978 // but EBR is not updated
1980 LogicalPartition
* prev
= logical
->Previous();
1981 error
= prev
? writer
.WriteLogical(prev
, primary
, false)
1982 : writer
.WriteLogical(logical
, primary
, false);
1984 // this is fatal - linked list is not updated
1987 // all changes applied
1988 update_disk_device_job_progress(job
, 1.0);
1989 partition_modified(childID
);
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
)
2003 PartitionWriteLocker
locker(partitionID
);
2004 if (!locker
.IsLocked())
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
)
2012 LogicalPartition
* logical
= (LogicalPartition
*)child
->cookie
;
2013 PrimaryPartition
* primary
= (PrimaryPartition
*)partition
->cookie
;
2014 if (!logical
|| !primary
)
2017 // TODO: The parameter has already been checked and must not be altered!
2018 if (!ep_validate_set_type(child
, type
))
2021 // if the old type is the same, there is nothing to do
2022 if (child
->type
&& !strcmp(type
, child
->type
))
2025 PartitionType ptype
;
2026 ptype
.SetType(type
);
2027 // this is impossible
2028 if (!ptype
.IsValid() || ptype
.IsEmpty() || ptype
.IsExtended())
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
);
2046 child
->type
= strdup(type
);
2050 // all changes applied
2051 update_disk_device_job_progress(job
, 1.0);
2052 partition_modified(partitionID
);
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"));
2067 PartitionWriteLocker
locker(partitionID
);
2068 if (!locker
.IsLocked())
2072 partition_data
* partition
= get_partition(partitionID
);
2076 PrimaryPartition
* primary
= (PrimaryPartition
*)partition
->cookie
;
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
))
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
);
2105 // all changes applied
2106 update_disk_device_job_progress(job
, 1.0);
2107 partition_modified(partitionID
);
2114 childID is used for the return value, but is also an optional input
2115 parameter -- -1 to be ignored
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
)
2128 PartitionWriteLocker
locker(partitionID
);
2129 if (!locker
.IsLocked())
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
)
2138 PrimaryPartition
* primary
= (PrimaryPartition
*)partition
->cookie
;
2143 void* handle
= parse_driver_settings_string(parameters
);
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
);
2153 ptsOffset
= strtoull(buffer
, NULL
, 10);
2155 delete_driver_settings(handle
);
2158 delete_driver_settings(handle
);
2160 // check the partition location
2161 if (!check_partition_location_ep(partition
, offset
, size
, ptsOffset
))
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
);
2171 // setup logical partition
2172 LogicalPartition
* logical
= new(nothrow
) LogicalPartition
;
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
);
2189 primary
->RemoveLogicalPartition(logical
);
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
);
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
);
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
);
2236 ep_delete_child(int fd
, partition_id partitionID
, partition_id childID
,
2239 TRACE(("intel: ep_delete_child\n"));
2244 PartitionWriteLocker
locker(partitionID
);
2245 if (!locker
.IsLocked())
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
)
2254 PrimaryPartition
* primary
= (PrimaryPartition
*)partition
->cookie
;
2255 LogicalPartition
* logical
= (LogicalPartition
*)child
->cookie
;
2256 if (primary
== NULL
|| logical
== NULL
)
2260 update_disk_device_job_progress(job
, 0.0);
2261 if (!delete_partition(childID
))
2264 LogicalPartition
* previous
= logical
->Previous();
2265 LogicalPartition
* next
= logical
->Next();
2267 primary
->RemoveLogicalPartition(logical
);
2270 int parentFD
= open_partition(parent
->id
, O_RDWR
);
2274 // write changes to disk
2275 PartitionMapWriter
writer(parentFD
, primary
->BlockSize());
2278 if (previous
!= NULL
) {
2279 error
= writer
.WriteLogical(previous
, primary
, true);
2281 error
= writer
.WriteExtendedHead(next
, primary
, true);
2284 next
->SetPartitionTableOffset(primary
->Offset());
2286 partition_data
* nextSibling
= NULL
;
2287 if (get_partition_from_offset_ep(partition
, next
->Offset(),
2290 sprintf(buffer
, "active %s ;\npartition_table_offset %" B_PRId64
2291 " ;\n", next
->Active() ? "true" : "false",
2292 next
->PartitionTableOffset());
2293 nextSibling
->parameters
= strdup(buffer
);
2303 // all changes applied
2304 update_disk_device_job_progress(job
, 1.0);
2305 partition_modified(partitionID
);