# HG changeset patch # User Milko Krachounov # Date 1297272361 -7200 # Node ID 0f191a3d4eae5a2e8bf1a33427a6f1c864cd2bf1 # Parent 8c37b046c0605c4f71b78feb003e4d315b0f091f Implement --align similar to parted's, update query_part_position to add the appropriate fuzz to both sides (except for resizing), and fix a bug in fuzzify diff -r 8c37b046c060 -r 0f191a3d4eae src/cfdisk.c --- a/src/cfdisk.c Tue Feb 08 14:31:21 2011 +0200 +++ b/src/cfdisk.c Wed Feb 09 19:26:01 2011 +0200 @@ -96,6 +96,7 @@ {"version", 'v', NULL, N_("displays the version")}, {"arrow-cursor", 'a', NULL, N_("use an arrow cursor instead of reverse video")}, {"new-table", 'z', NULL, N_("create a new partition table on the disk")}, + {"align", 'A', N_("TYPE"),N_("use align TYPE, can be none, cyl, min or opt")}, {"units", 'u', N_("UNIT"),N_("sets the default display units to UNIT")}, {"list-partition-types", 't', NULL, N_("displays a list of supported partition types")}, {NULL, 0, NULL, NULL} @@ -1076,6 +1077,7 @@ } ped_disk_destroy(c->disk); c->disk = ped_disk_new(c->dev); + init_disk_flags(c->disk); uiquery.need_commit = 0; if (part) { *part = ped_disk_get_partition(c->disk,partnum); @@ -1248,7 +1250,7 @@ PedFileSystem *fs = NULL; PedSector first,last; PartPos pos; - UIOpts opts = UI_WARN_COMMIT; + UIOpts opts = UI_WARN_COMMIT | UI_SNAP_TO_START; if (!((*part)->type & PED_PARTITION_EXTENDED)) { if ((*part)->fs_type && (*part)->fs_type->ops->resize) { menu_title(_("What do you want to do?")); @@ -2446,6 +2448,8 @@ else do_quit (0,NULL); } else { ped_exception_leave_all(); + if (!init_disk_flags(disk)) + do_quit(1,_("Internal error initializing disk flags")); } } else { if (!perform_mklabel (dev, &disk, NULL)) @@ -2560,12 +2564,14 @@ main (int argc, char **argv) { PedUnit unit = -1; char *devname; + AlignType align_type; PedDevice *dev; #ifdef HAVE_GETOPT_H static struct option long_options[] = { { "new-table", no_argument, NULL, 'z' }, { "version", no_argument, NULL, 'v' }, { "arrow-cursor", no_argument, NULL, 'a' }, + { "align", required_argument, NULL, 'A' }, { "units", required_argument, NULL, 'u' }, { "help", no_argument, NULL, 'h' }, { "list-partition-types", no_argument, NULL, 't' }, @@ -2573,10 +2579,10 @@ }; int opt,option_index; - while ((opt = getopt_long(argc,argv, "hazvtu:", long_options, &option_index)) != -1) { + while ((opt = getopt_long(argc,argv, "hazvtA:u:", long_options, &option_index)) != -1) { #else int opt; - while ((opt = getopt(argc,argv,"hazvtu:")) != -1) { + while ((opt = getopt(argc,argv,"hazvtA:u:")) != -1) { #endif switch (opt) { case 'v': @@ -2591,6 +2597,12 @@ case 'z': new_table = 1; break; + case 'A': + align_type = string_to_align_type(optarg); + if (align_type == ALIGNMENT_INVALID) + print_usage(); + partition_align_type = align_type; + break; case 'u': unit = ped_unit_get_by_name(optarg); break; diff -r 8c37b046c060 -r 0f191a3d4eae src/common.c --- a/src/common.c Tue Feb 08 14:31:21 2011 +0200 +++ b/src/common.c Wed Feb 09 19:26:01 2011 +0200 @@ -55,6 +55,15 @@ int compat_mode = 1; /* Start compatible with fdisk and cfdisk */ +/* This variable is global and referred from fdisk.c and cfdisk.c + * The value specifies how the partitions will be aligned, + * values of ALIGNMENT_OPTIMAL and ALIGNMENT_MINIMAL are handled + * by the functions in this file, while ALIGNMENT_CYLINDER is + * handled by fdisk.c and cfdisk.c. + */ + +AlignType partition_align_type = ALIGNMENT_NONE; + /* Here we store the struct with interface functions */ static UICalls *uiquery; @@ -162,8 +171,95 @@ return ped_disk_extended_partition (disk) != 0; } +/* This function returns a device constraint that is optionally + * aligned if partition_align_type is either ALIGNMENT_OPTIMAL + * or ALIGNMENT_MINIMAL. + */ +static PedConstraint * +_get_aligned_device_constraint(PedDevice *dev) +{ + if (partition_align_type == ALIGNMENT_OPTIMAL) + return ped_device_get_optimal_aligned_constraint(dev); + else if (partition_align_type == ALIGNMENT_MINIMAL) + return ped_device_get_minimal_aligned_constraint(dev); + else + return ped_device_get_constraint(dev); +} +/* Return a new geometry aligned according to partition_align_type. + * Returns NULL if it didn't succeed. + */ +static PedGeometry * +_get_aligned_geometry(PedGeometry *geometry, int keep_inside) +{ + PedConstraint *constraint; + PedGeometry * new; + + constraint = _get_aligned_device_constraint(geometry->dev); + if (keep_inside) { + constraint = constraint_intersect_and_destroy( + constraint, + ped_constraint_new_from_max(geometry)); + } + + new = ped_constraint_solve_nearest(constraint, geometry); + ped_constraint_destroy(constraint); + return new; +} + +/* Returns 1 if the partition is aligned correctly in regards to + * align_type. + */ +static int +_is_partition_aligned(PedPartition *part, AlignType align_type) +{ + + PedAlignment *alignment = NULL; + + switch (partition_align_type) { + case ALIGNMENT_OPTIMAL: + alignment = ped_device_get_optimum_alignment (part->disk->dev); + break; + case ALIGNMENT_MINIMAL: + alignment = ped_device_get_minimum_alignment (part->disk->dev); + break; + } + + if (!alignment) + return 1; + + int aligned = 1; + if (alignment->grain_size == 0) + aligned = 0; + else if (part->geom.start % alignment->grain_size != alignment->offset) + aligned = 0; + ped_alignment_destroy(alignment); + + return aligned; +} + +/* Warn the user if the partition isn't aligned correctly + * as specified by the partition_align_type global. + * Returns 1 if the partition is correctly aligned, or + * if the user accepted the partition as it is. Otherwise, + * return 0. + */ +static int +_partition_warn_unaligned(PedPartition *part) +{ + if (_is_partition_aligned(part, partition_align_type)) + return 1; + + if (ped_exception_throw(PED_EXCEPTION_WARNING, + PED_EXCEPTION_IGNORE_CANCEL, + _("The resulting partition is not properly " + "aligned for best performance")) + == PED_EXCEPTION_CANCEL) + return 0; + + return 1; +} static int _partition_warn_busy (PedPartition* part) @@ -439,7 +535,7 @@ constraint = ped_device_get_constraint(dev); PedSector start = geom->start-before; start = (start > 0 ? start : 0); - PedSector end = geom->start+after; + PedSector end = geom->end+after; end = (end < dev->length-1LL ? end : dev->length-1LL); ped_geometry_set (geom, start, end-start+1); new_geom = ped_constraint_solve_nearest (constraint, geom); @@ -507,6 +603,29 @@ } +AlignType +string_to_align_type(const char *name) +{ + if (!strcmp(name, "none")) + return ALIGNMENT_NONE; + if (!strncmp(name, "opt", 3)) + return ALIGNMENT_OPTIMAL; + if (!strncmp(name, "min", 3)) + return ALIGNMENT_MINIMAL; + if (!strncmp(name, "cyl", 3)) + return ALIGNMENT_CYLINDER; + return ALIGNMENT_INVALID; +} + +int +init_disk_flags(PedDisk *disk) +{ + if (ped_disk_is_flag_available(disk, PED_DISK_CYLINDER_ALIGNMENT)) + if (!ped_disk_set_flag(disk, PED_DISK_CYLINDER_ALIGNMENT, + partition_align_type == ALIGNMENT_CYLINDER)) + return 0; + return 1; +} /* PedSector is signed, so we can use this to move in both directions */ static int @@ -658,31 +777,43 @@ the sector with the range so that the sector is equal to the desired result */ if (where == 'b') { - /* As the start is not equal to the end of - the partition, we will add some fuzz */ - /* FIXME */ - pos->start.range = ped_geometry_new(dev, - first, 64LL); + /* Fuzzing both start and end with range->length. + * TODO: range->length / 2 might be a better choice + * ...or a constraint with a range for min and max + * size based on this constraint which isn't possible + * with the API right now. + */ + pos->start.range = ped_geometry_new(dev, first, 1); + fuzzify(pos->start.range, dev, NULL, + range->length, range->length); + pos->start.sector = first; - pos->start.sector = first; /* Desired: end = first+length-1LL */ pos->end.sector = length; pos->end.range = range; move_sector(dev,&(pos->end),first-1LL); } else if (where == 'e') { - /* If the end has changed, we will add some fuzz */ - if (pos->end.sector != last) - pos->end.range = ped_geometry_new(dev, - last-63LL, 64LL); + /* Fuzzing both start and end with range->length */ + pos->end.range = ped_geometry_new(dev, last, 1); + fuzzify(pos->end.range, dev, NULL, + range->length, range->length); + pos->end.sector = last; - pos->end.sector = last; /* Desired: start = last-length+1LL */ pos->start.sector = length; pos->start.range = range; move_sector(dev,&(pos->start),last-2*length+1LL); } else if (where == 's') { + /* If UI_SNAP_TO_START isn't true, add fuzz to the + * start, otherwise don't. + */ + pos->start.range = ped_geometry_new(dev, pos->start.sector, 1); + if (!(*opts & UI_SNAP_TO_START)) + fuzzify(pos->start.range, dev, NULL, + range->length, range->length); + /* Desired: end = start+length-1LL */ pos->end.sector = length; pos->end.range = range; @@ -729,6 +860,10 @@ PedDisk* new_disk = ped_disk_new (dev); if (!new_disk) return 0; + if (!init_disk_flags(new_disk)) { + ped_disk_destroy(new_disk); + return 0; + } *value = new_disk; } return 1; @@ -1072,14 +1207,18 @@ /* Looks for the first suitable free space for a new partition */ place_part_start(PedDisk *disk, PartPos *pos, PedPartitionType type) { + PedGeometry *aligned; PedPartition *part = NULL; type = (type & PED_PARTITION_LOGICAL) | PED_PARTITION_FREESPACE; for (part = ped_disk_next_partition(disk, NULL); part; part = ped_disk_next_partition(disk,part)) { if (part->type == type) { - pos->start.sector = part->geom.start; + aligned = _get_aligned_geometry(&part->geom, 1); + + pos->start.sector = aligned->start; pos->start.range = ped_geometry_new (disk->dev, - part->geom.start, 8LL); + aligned->start, 1); + ped_geometry_destroy(aligned); return 1; } } @@ -1089,12 +1228,16 @@ /* This function looks where to place the end of a new partition */ static int place_part_end(PedDisk *disk, PartPos *pos) { + PedGeometry *aligned; PedPartition *part = ped_disk_get_partition_by_sector(disk, pos->start.sector); if (part->type & PED_PARTITION_FREESPACE) { - pos->end.sector = part->geom.end; + aligned = _get_aligned_geometry(&part->geom, 1); + + pos->end.sector = aligned->end; pos->end.range = ped_geometry_new (disk->dev, - part->geom.end - 7LL, 8LL); + aligned->end, 1); + ped_geometry_destroy(aligned); return 1; } else @@ -1132,7 +1275,7 @@ if (!get_sector (start, disk->dev, &(pos->start), -1LL, opts)) return 0; - + /* If we are creating a new partition and want to look where to place its end ... */ if (opts & PLACE_END_NEWPART) @@ -1291,10 +1434,17 @@ goto error; } - *disk = ped_disk_new_fresh (dev, type); - if (!*disk) + PedDisk *new_disk = ped_disk_new_fresh (dev, type); + if (!new_disk) goto error; + if (!init_disk_flags(new_disk)) { + ped_disk_destroy(new_disk); + goto error; + } + + *disk = new_disk; + /*if (!ped_disk_commit (*disk)) goto error;*/ uiquery->need_commit = 1; @@ -1448,8 +1598,6 @@ /* Check if the partition occupying the space before the place we are trying to put this one, requires a metadata sectors after it, and if so, increase the range of the constraint */ - - fuzzify(pos->start.range, disk->dev, NULL, 0, metadata_tail_sectors( disk_get_prev_nmd_partition( @@ -1470,7 +1618,7 @@ pos->start.range, pos->end.range); PED_ASSERT (user_constraint != NULL, return 0); - dev_constraint = ped_device_get_constraint (disk->dev); + dev_constraint = _get_aligned_device_constraint(disk->dev); PED_ASSERT (dev_constraint != NULL, return 0); final_constraint = ped_constraint_intersect (user_constraint, @@ -1490,10 +1638,10 @@ end_usr = ped_unit_format (disk->dev, pos->end.sector); start_sol = ped_unit_format (disk->dev, part->geom.start); end_sol = ped_unit_format (disk->dev, part->geom.end); - /* TODO: With the changes from 06/08/06, we might remove - the "if" and warn the user always if this is out of - range */ - if (opts & UI_CUSTOM_VALUES) + if (!ped_geometry_test_sector_inside(pos->start.range, + part->geom.start) || + !ped_geometry_test_sector_inside(pos->end.range, + part->geom.end)) switch (ped_exception_throw ( PED_EXCEPTION_WARNING, PED_EXCEPTION_YES_NO, @@ -1512,6 +1660,8 @@ /* undo partition addition */ goto error_remove_part; } + if (!_partition_warn_unaligned(part)) + goto error_remove_part; } else { goto error_remove_part; } diff -r 8c37b046c060 -r 0f191a3d4eae src/common.h --- a/src/common.h Tue Feb 08 14:31:21 2011 +0200 +++ b/src/common.h Wed Feb 09 19:26:01 2011 +0200 @@ -59,16 +59,31 @@ enum _UIOpts { UI_DEFAULT = 0, /* Warn the user if the operation commits the data to the disk */ - UI_WARN_COMMIT = 1, + UI_WARN_COMMIT = 1 << 0, /* Allow the user to adjust start/end on resize, etc */ - UI_CUSTOM_VALUES = 2, + UI_CUSTOM_VALUES = 1 << 1, /* Allow the user to specify the partition type */ - UI_SPECIFY_PART_TYPE = 4, + UI_SPECIFY_PART_TYPE = 1 << 2, + /* Prefer the beginning to be snapped to the old begining + * e.g. during resize */ + UI_SNAP_TO_START = 1 << 3, /* Option specific for each function */ - UI_FUNCTION_SPECIFIC_1 = 8, - UI_FUNCTION_SPECIFIC_2 = 16 + UI_FUNCTION_SPECIFIC_1 = 1 << 4, + UI_FUNCTION_SPECIFIC_2 = 1 << 5 }; +typedef enum _AlignType AlignType; +enum _AlignType { + /* ALIGNMENT_INVALID shouldn't be assigned to partition_align_type */ + ALIGNMENT_INVALID = 0, + ALIGNMENT_NONE, + ALIGNMENT_MINIMAL, + ALIGNMENT_CYLINDER, + ALIGNMENT_OPTIMAL +}; + +extern AlignType partition_align_type; + /* Structures used to specify partition position */ typedef struct _SectPos SectPos; struct _SectPos { @@ -169,6 +184,13 @@ extern int fix_part_position(PedDevice *dev, PedSector *start, PedSector *end, PedSector first, PedSector last); +/* This function converts none, cyl*, opt*, and min* to an AlignType */ +extern AlignType string_to_align_type(const char *); + +/* This function takes care of initializing the alignment flags + * and should be called after a disk is created. Returns 1 on success */ +extern int init_disk_flags(PedDisk *); + /* Choose the partition position */ extern int query_part_position(const char* prompt, const void* context, PartPos* pos, diff -r 8c37b046c060 -r 0f191a3d4eae src/fdisk.c --- a/src/fdisk.c Tue Feb 08 14:31:21 2011 +0200 +++ b/src/fdisk.c Wed Feb 09 19:26:01 2011 +0200 @@ -110,6 +110,7 @@ #endif /* GNU_EXT */ { "interactive", no_argument, NULL, 'i', "where necessary, prompts for user intervention"}, { "script", no_argument, NULL, 'p', "never prompts for user intervention"}, + { "align", required_argument, NULL, 'A', "specify align to be none, cyl, min or opt"}, { "sector-units", no_argument, NULL, 'u', "use sectors instead of cylinder as a default unit"}, { "sector-size", required_argument, NULL, 'b', "specify the sector size in bytes"}, { "cylinders", required_argument, NULL, 'C', "specify the number of cylinders, actually does nothing"}, @@ -129,7 +130,7 @@ * to this string * * NOTE: I will make function to build dynamic in the future */ -static const char* short_option_string = "hlipvLGs:utb:C:H:S:r"; +static const char* short_option_string = "hlipvLGs:A:utb:C:H:S:r"; @@ -540,6 +541,7 @@ ped_disk_destroy(*disk); *disk = ped_disk_new(dev); + init_disk_flags(*disk); uiquery.need_commit = 0; } @@ -939,6 +941,7 @@ label_disk = ped_disk_new_fresh (label_dev, ped_disk_type_get ("bsd")); } + init_disk_flags(label_disk); in_menu = 2; logical_offset = count_logical_partition(*disk); fdisk_interactive_menu(&label_disk, fdisk_bsd_menu_commands, 2); @@ -1313,6 +1316,7 @@ if (!disk) // Not fatal error continue; + init_disk_flags(disk); if (fdisk_print_raw) do_raw (&disk); else @@ -1532,7 +1536,7 @@ PedSector first,last; PedConstraint *constraint = NULL; PedPartitionType desired; - UIOpts ui_opts = UI_WARN_COMMIT; + UIOpts ui_opts = UI_WARN_COMMIT | UI_SNAP_TO_START; if (!get_partition (_("Partition"), *disk, &part)) return 0; @@ -1705,6 +1709,14 @@ if (!(*disk = ped_disk_new (dev))) return 0; + /* Initialize the disk flags */ + if (!init_disk_flags(*disk)) { + ped_disk_destroy(*disk); + *disk = NULL; + return 0; + } + + /* Tell the user we are using the new device. */ fdisk_print_using_dev (dev); @@ -2552,7 +2564,7 @@ static int _parse_options (int* argc_ptr, char*** argv_ptr) { - int opt; + int opt, align_type; struct option *options_table, *ptr; /* Build option table we need two pointers because getopt long @@ -2595,6 +2607,14 @@ case 't': print_partition_types(); break; + case 'A': + align_type = string_to_align_type(optarg); + if (align_type == ALIGNMENT_INVALID) { + fdisk_usage_msg(); + return 0; + } + partition_align_type = align_type; + break; case 'u': ped_unit_set_default(PED_UNIT_SECTOR); cylinder_unit = 0; diff -r 8c37b046c060 -r 0f191a3d4eae src/ui.c --- a/src/ui.c Tue Feb 08 14:31:21 2011 +0200 +++ b/src/ui.c Wed Feb 09 19:26:01 2011 +0200 @@ -653,6 +653,10 @@ "content won't be recoverable.\n")); if((disk = ped_disk_new_fresh(*dev, ped_disk_type_get("msdos"))) == NULL) return EXIT_FAILURE; + if(!init_disk_flags(disk)) { + ped_disk_destroy(disk); + return EXIT_FAILURE; + } } else { @@ -706,6 +710,11 @@ if(!disk) return EXIT_FAILURE; /* what bad? :( */ + if (!init_disk_flags(disk)) { + ped_disk_destroy(disk); + return EXIT_FAILURE; + } + /* Free other resources */ free(str); free(supported_types); @@ -717,6 +726,10 @@ disk = ped_disk_new(*dev); if(!disk) return EXIT_FAILURE; + if(!init_disk_flags(disk)) { + ped_disk_destroy(disk); + return EXIT_FAILURE; + } } /*** diff -r 8c37b046c060 -r 0f191a3d4eae tests/check_advanced.c --- a/tests/check_advanced.c Tue Feb 08 14:31:21 2011 +0200 +++ b/tests/check_advanced.c Wed Feb 09 19:26:01 2011 +0200 @@ -152,6 +152,7 @@ disk2 = ped_disk_new(dev2); //fail_unless(1, "hm"); + init_disk_flags(disk2); srand(129312); int i;