📄 common.c
字号:
/* GNU fdisk - a clone of Linux fdisk. Copyright (C) 2006 Free Software Foundation, Inc. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA*/#include "../config.h"#include "strlist.h"#define N_(String) String#if ENABLE_NLS# include <libintl.h># include <locale.h># define _(String) dgettext (PACKAGE, String)# define P_(String) dgettext ("parted", String)#else# define _(String) (String)# define P_(String) (String)#endif /* ENABLE_NLS */#include <parted/parted.h>#include <parted/debug.h>#include <stdarg.h>#include <stdlib.h>#include <string.h>#include <unistd.h>#include "common.h"#define SMALLBUF 256/* Here we store the struct with interface functions */static UICalls *uiquery;static int MEGABYTE_SECTORS (PedDevice* dev){ return PED_MEGABYTE_SIZE / dev->sector_size;}/* TODO: Decide if these should be moved to UICalls */StrList *disk_type_list;StrList *fs_type_list;//StrList *fs_type_resize;StrList *fs_type_mkfs;StrList *flag_name_list;intinit_flag_str (){ PedPartitionFlag walk; flag_name_list = NULL; for (walk = ped_partition_flag_next(0); walk; walk =ped_partition_flag_next(walk)) { flag_name_list = str_list_append(flag_name_list, ped_partition_flag_get_name(walk)); if (!flag_name_list) return 0; } return 1;}intinit_fs_type_str (){ PedFileSystemType* walk; fs_type_list = NULL; for (walk = ped_file_system_type_get_next (NULL); walk; walk = ped_file_system_type_get_next (walk)) { fs_type_list = str_list_append (fs_type_list, walk->name); if (walk->ops->create != NULL) fs_type_mkfs = str_list_append(fs_type_mkfs, walk->name); //if (talk->ops->resize != NULL) // fs_type_resize = str_list_append(fs_type_mkfs, walk->name); if (!fs_type_list) return 0; } return 1;}intinit_disk_type_str (){ PedDiskType* walk; disk_type_list = NULL; for (walk = ped_disk_type_get_next (NULL); walk; walk = ped_disk_type_get_next (walk)) { disk_type_list = str_list_append (disk_type_list, walk->name); if (!disk_type_list) return 0; } return 1;}int_can_create_primary (const PedDisk* disk){ int i; for (i = 1; i <= ped_disk_get_max_primary_partition_count (disk); i++) { if (!ped_disk_get_partition (disk, i)) return 1; } return 0;}int_can_create_extended (const PedDisk* disk){ if (!_can_create_primary (disk)) return 0; if (!ped_disk_type_check_feature (disk->type, PED_DISK_TYPE_EXTENDED)) return 0; if (ped_disk_extended_partition (disk)) return 0; return 1;}int_can_create_logical (const PedDisk* disk){ if (!ped_disk_type_check_feature (disk->type, PED_DISK_TYPE_EXTENDED)) return 0; return ped_disk_extended_partition (disk) != 0;}static int_partition_warn_busy (PedPartition* part){ char* path = ped_partition_get_path (part); if (ped_partition_is_busy (part)) { ped_exception_throw ( PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL, _("Partition %s is being used. You must unmount it " "before you modify it."), path); ped_free (path); return 0; } ped_free (path); return 1;}static int_disk_warn_busy (PedDisk* disk){ if (ped_device_is_busy (disk->dev)) { if (ped_exception_throw ( PED_EXCEPTION_WARNING, PED_EXCEPTION_IGNORE_CANCEL, _("Partition(s) on %s are being used."), disk->dev->path) != PED_EXCEPTION_IGNORE) return 0; } return 1;}static int_warn_ext_not_empty (PedPartition *part) { /* If this is not an extended partition, it is ok */ if (!(part->type & PED_PARTITION_EXTENDED)) return 1; for (part = part->part_list; part; part = part->next) { if (part->type == PED_PARTITION_LOGICAL) { if(ped_exception_throw ( PED_EXCEPTION_WARNING, PED_EXCEPTION_YES_NO, _("The extended partition is not empty. " "Deleting it will delete any partitions " "inside it. Do you want to continue?")) == PED_EXCEPTION_NO) return 0; else return 1; } } return 1;}/* Get previous non-METADATA partition. */PedPartition *disk_get_prev_nmd_partition(PedDisk *disk, PedPartition *part) { PedPartition *walk_a, *walk_b; /* walk_a will iterate through partitions that are not METADATA, while walk_b will iterate through all partitions. When walk_b reaches our partition, walk_a is the partition we are looking for. */ walk_a = NULL; walk_b = walk_a; do { if (ped_disk_next_partition(disk,walk_b) == part) break; walk_b = ped_disk_next_partition(disk,walk_b); if (!walk_b || !(walk_b->type & PED_PARTITION_METADATA)) walk_a = walk_b; } while (walk_b); return walk_a;}/* This function returns the number of a metadata sectors, which are needed after a partition, for example, in msdos partition table, the sector, after a logical partition, describes the next logical partition */static PedSector metadata_tail_sectors(PedPartition *part) { /* TODO: Make this support other partition types */ if (part == NULL || part->disk->type == NULL) return 0; if (!strcmp(part->disk->type->name, "msdos") && part->type & PED_PARTITION_LOGICAL) { return 1; } return 0;}/* This function changes "sector" to "new_sector" if the new value lies * within the required range. */static intsnap (PedSector* sector, PedSector new_sector, PedGeometry* range){ PED_ASSERT (ped_geometry_test_sector_inside (range, *sector), return 0); if (!ped_geometry_test_sector_inside (range, new_sector)) return 0; *sector = new_sector; return 1;}typedef enum { MOVE_NO = 0, MOVE_STILL = 1, MOVE_UP = 2, MOVE_DOWN = 4} EMoves;enum { /* Don't change these values */ SECT_START = 0, SECT_END = -1};/* Find the prefered way to adjust the sector s inside range. * If a move isn't allowed or is out of range it can't be selected. * what contains SECT_START if the sector to adjust is a start sector * or SECT_END if it's an end one. * The prefered move is to the nearest allowed boundary of the part * partition (if at equal distance: to start if SECT_START or to end * if SECT_END). * The distance is returned in dist. */static EMovesprefer_snap (PedSector s, int what, PedGeometry* range, EMoves* allow, PedPartition* part, PedSector* dist){ PedSector up_dist = -1, down_dist = -1; PedSector new_sect; EMoves move; PED_ASSERT (what == SECT_START || what == SECT_END, return 0); if (!(*allow & (MOVE_UP | MOVE_DOWN))) { *dist = 0; return MOVE_STILL; } if (*allow & MOVE_UP) { new_sect = part->geom.end + 1 + what; if (ped_geometry_test_sector_inside (range, new_sect)) up_dist = new_sect - s; else *allow &= ~MOVE_UP; } if (*allow & MOVE_DOWN) { new_sect = part->geom.start + what; if (ped_geometry_test_sector_inside (range, new_sect)) down_dist = s - new_sect; else *allow &= ~MOVE_DOWN; } move = MOVE_STILL; if ((*allow & MOVE_UP) && (*allow & MOVE_DOWN)) { if (down_dist < up_dist || (down_dist == up_dist && what == SECT_START) ) move = MOVE_DOWN; else if (up_dist < down_dist || (down_dist == up_dist && what == SECT_END) ) move = MOVE_UP; else PED_ASSERT (0, return 0); } else if (*allow & MOVE_UP) move = MOVE_UP; else if (*allow & MOVE_DOWN) move = MOVE_DOWN; *dist = ( move == MOVE_DOWN ? down_dist : ( move == MOVE_UP ? up_dist : 0 ) ); return move;}/* Snaps a partition to nearby partition boundaries. This is useful for * gobbling up small amounts of free space, and also for reinterpreting small * changes to a partition as non-changes (eg: perhaps the user only wanted to * resize the end of a partition). * Note that this isn't the end of the story... this function is * always called before the constraint solver kicks in. So you don't need to * worry too much about inadvertantly creating overlapping partitions, etc. */static voidsnap_to_boundaries (PedGeometry* new_geom, PedGeometry* old_geom, PedDisk* disk, PedGeometry* start_range, PedGeometry* end_range){ PedPartition* start_part; PedPartition* end_part; PedSector start = new_geom->start; PedSector end = new_geom->end; PedSector start_dist = -1, end_dist = -1; EMoves start_allow, end_allow, start_want, end_want; int adjacent; start_want = end_want = MOVE_NO; start_allow = end_allow = MOVE_STILL | MOVE_UP | MOVE_DOWN; start_part = ped_disk_get_partition_by_sector (disk, start); end_part = ped_disk_get_partition_by_sector (disk, end); adjacent = (start_part->geom.end + 1 == end_part->geom.start); /* If we can snap to old_geom, then we will... */ /* and this will enforce the snapped positions */ if (old_geom) { if (snap (&start, old_geom->start, start_range)) start_allow = MOVE_STILL; if (snap (&end, old_geom->end, end_range)) end_allow = MOVE_STILL; } /* If start and end are on the same partition, we */ /* don't allow them to cross. */ if (start_part == end_part) { start_allow &= ~MOVE_UP; end_allow &= ~MOVE_DOWN; } /* Let's find our way */ start_want = prefer_snap (start, SECT_START, start_range, &start_allow, start_part, &start_dist ); end_want = prefer_snap (end, SECT_END, end_range, &end_allow, end_part, &end_dist ); PED_ASSERT (start_dist >= 0 && end_dist >= 0, return); /* If start and end are on adjacent partitions, */ /* and if they would prefer crossing, then refrain */ /* the farthest to do so. */ if (adjacent && start_want == MOVE_UP && end_want == MOVE_DOWN) { if (end_dist < start_dist) { start_allow &= ~MOVE_UP; start_want = prefer_snap (start, SECT_START, start_range, &start_allow, start_part, &start_dist ); PED_ASSERT (start_dist >= 0, return); } else { end_allow &= ~MOVE_DOWN; end_want = prefer_snap (end, SECT_END, end_range, &end_allow, end_part, &end_dist ); PED_ASSERT (end_dist >= 0, return); } } /* New positions */ start = ( start_want == MOVE_DOWN ? start_part->geom.start : ( start_want == MOVE_UP ? start_part->geom.end + 1 : start ) ); end = ( end_want == MOVE_DOWN ? end_part->geom.start - 1 : ( end_want == MOVE_UP ? end_part->geom.end : end ) ); PED_ASSERT (ped_geometry_test_sector_inside(start_range,start), return); PED_ASSERT (ped_geometry_test_sector_inside (end_range, end), return); PED_ASSERT (start <= end, PED_DEBUG (0, "start = %d, end = %d\n", start, end)); ped_geometry_set (new_geom, start, end - start + 1);}/* This function makes a range less strict... *//* FIXME: Make this in a better way */static voidfuzzify (PedGeometry *geom, PedDevice *dev, PedConstraint *constraint, PedSector before, PedSector after) { PedGeometry *new_geom; if (!constraint) constraint = ped_device_get_constraint(dev); PedSector start = geom->start-before; start = (start > 0 ? start : 0); PedSector end = geom->start+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); ped_geometry_set (geom, new_geom->start, new_geom->length);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -