Anonymous avatar Anonymous committed 7e61769

Implement resizing and moving. Interface almost ready. (fdisk@sv.gnu.org/fdisk--main--0--patch-12)
fdisk@sv.gnu.org/fdisk--main--0--patch-12
Keywords:

Comments (0)

Files changed (3)

 
 /* Menu drawing function */
 void
-menu_draw (MenuItem *items, int item_len, MenuOptions opts, const char *keys, int selected) {
+menu_draw (const MenuItem *items, int item_len, MenuOptions opts, const char *keys, int selected) {
 	int i, y = LINES - 2 - MENUSIZE + (opts & MENU_TITLE ? 1 : 0), x = MENUDIV;
 	int item_size = item_len + (opts & MENU_BUTTON ? 2 : 0);
 	const char *desc;
 /* Menu display function. The selected parameter specifies the item that is selected by
  * default and the keys string includes the keys that should be accepted by the interface. */
 static int
-do_menu (MenuItem *items, int item_len, MenuOptions opts, const char *keys, int selected) {
+do_menu (const MenuItem *items, int item_len, MenuOptions opts, const char *keys, int selected) {
 	int i, key = 0, count = 0, redraw = 1;
 	
 	/* Count the items and make sure that the selected item is available */
 }
 static void show_info();
 static void plist_draw (PedDisk *cdisk, PedPartition *selected, int selnum, int *start);
-static int do_plist (PedDisk *cdisk, PedPartition **part);
+static int do_plist (PedDisk *cdisk, PedPartition **part, PedPartitionType have, PedPartitionType havent);
 
 static const StrList*
 do_strlist (const char *prompt, const StrList *strlist) {
 		return 0; /* TODO, although it might not get used */
 	}
 	menu_title(prompt);
-	return do_plist(*disk,value);
+	return do_plist(*disk,value,0,PED_PARTITION_EXTENDED | PED_PARTITION_FREESPACE);
 }
 
 
 	notice_waitkey(warning);
 }
 
+/* Get previous non-METADATA partition. Needed for menu navigation */
+/* FIXME: This is *ugly*. Fix it. Can be fixed with a expand/collapse
+          list of logical partitions. At least it works. */
+static PedPartition *
+disk_get_prev_nmd_partition(PedDisk *cdisk, PedPartition *part) {
+	PedPartition *temp_a, *temp_b;
+	/* temp_a will iterate through partitions that are not METADATA, while
+	   temp_b will iterate through all partitions. When temp_b reaches our partition,
+	   temp_a is the partition we are looking for. */
+	temp_a = NULL;
+	temp_b = temp_a;
+	do {
+		if (ped_disk_next_partition(cdisk,temp_b) == part)
+			break;
+		temp_b = ped_disk_next_partition(cdisk,temp_b);
+		if (!temp_b || !(temp_b->type & PED_PARTITION_METADATA))
+			temp_a = temp_b;
+	} while (temp_b);
+	return temp_a;
+}
+
+/* We ask the user where to put the partition in a region. Used for creating and resizing partitions */
+/* first and last mark the margins of the region, start and end mark the current values */
+static int
+_query_part_position(const MenuItem* menu, PedSector *start, PedSector *end, 
+		     PedSector first, PedSector last, PedConstraint *constraint, UIOpts *opts) {
+	PedSector length = *end-*start+1, min_len = 0, max_len;
+	int key,i,done;
+	char *temp,*temp2,*def_str, keys[6], buf[SMALLBUF];
+	i = 0;
+	/* If we have a constraint, check whether we can move the partition start */
+	if (constraint && (constraint->start_align->grain_size == 0 || constraint->start_range->length == 1))
+		key = 'f';
+	else {
+		/* If there the first possible sector is not the start of the selected partition,
+			we need one choice in the menu to make the start fixed and one to move it back.
+			When it is, 'b' and 'f' do the same. We ditch 'b' for more friendly resize menu,
+			action_new should use 'f' as it doesn't matter there. 
+			FIXME: I wrote this fragment better, but ruined it. Now I'm too lazy to fix it */
+		if (first < *start) keys[i++] = 'b';
+		keys[i++] = 'f'; keys[i++] = 'e'; keys[i++] = 'c';
+		keys [i++] = ESC;
+		keys [i] = '\0';
+		/* NOTE: Run menu_title before running this function */
+		//menu_title(_("Where do you want to put the partition"));
+		key = do_menu(menu, 11, MENU_BUTTON | MENU_TITLE, keys, 0);
+	}
+	if (key == ESC)
+		return 0;
+	else {
+		if (key == 'c') {
+			*opts |= UI_CUSTOM_VALUES;
+		} else {
+			*opts &= ~UI_CUSTOM_VALUES;
+			if (key == 'f')
+				max_len = last-*start+1;
+			else
+				max_len = last-first+1;
+			if (constraint) {
+				max_len = MIN(constraint->max_size,max_len);
+				min_len = constraint->min_size;
+			}
+			done = 0;
+			while (!done) {
+				/* Put the max and min size on the prompt */
+				temp = ped_unit_format(dev,min_len);
+				temp2 = ped_unit_format(dev,max_len);
+				if (temp && temp2) {
+					snprintf(buf,SMALLBUF,_("Size (min %s, max %s)"),
+						temp, temp2);
+				} else {
+					strncpy(buf,_("Size"),SMALLBUF);
+				}
+				if (temp) ped_free(temp);
+				if (temp2) ped_free(temp2);
+				def_str = ped_unit_format(dev,length);
+				if (def_str) temp = strdup(def_str);
+				if (!read_char(buf, &temp)) {
+					if (temp) ped_free(temp);
+					if (def_str) ped_free(def_str);
+					return 0;
+				}
+	
+				done = 1;
+				/* Get the new size only if the user modified it */
+				if(strcmp(temp,def_str)) {
+					if (!ped_unit_parse(temp,dev,&length,NULL)) {
+						warning_waitkey(N_("This is an invalid partition size"));
+						done = 0;
+					}
+					else if (length > max_len) {
+						length = max_len;
+					} else if (length < min_len) {
+						length = min_len;
+					}
+				}
+				if (temp) ped_free(temp);
+				if (def_str) ped_free(def_str);
+			}
+			if (key == 'b') {
+				*start = first;
+				*end = first+length-1;
+			}
+			else if (key == 'e') {
+				*end = last;
+				*start = last-length+1;
+			}
+			else if (key == 'f') {
+				*end = *start+length-1;
+			}
+		}
+	}
+	return 1;
+	
+}
 
 /* Here we define our menu operations */
 static int
 action_new (PedPartition **part) {
 	static MenuItem part_position[] = {
-		{ 'b', N_("Begining"), N_("Create the partition at the begining of the free space") },
+		{ 'f', N_("Begining"), N_("Create the partition at the begining of the free space") },
 		{ 'e', N_("End"), N_("Create the partition at the end of the free space") },
 		{ 'c', N_("Custom"), N_("Select custom start and end position of the partition") },
 		{ ESC, N_("Cancel"), N_("Do not create a partition") },
 		{ ESC, N_("Cancel"), N_("Do not create a partition") },
 		{ 0, NULL, NULL }
 	};
-	const char pos_keys[] = {'b', 'e', 'c', ESC, '\0'};
 	const char type_keys[] = {'p', 'e', ESC, '\0'};
-	char *temp,*def_str;
 	PedPartitionType type;
-	PedSector start, end, length, def_len;
+	PedSector start, end;
 	int key,success = 1,done;
-	if((*part)->type & PED_PARTITION_LOGICAL)
+	UIOpts opts = UI_DEFAULT;
+	if (!((*part)->type & PED_PARTITION_FREESPACE)) {
+		warning_waitkey(N_("Report a bug in the function menu_new and win a cookie."));
+		return 0;
+	}
+	/* If the free space rests inside the extended partition, this is true, make use of it */
+	if((*part)->type & PED_PARTITION_LOGICAL) 
 		type = PED_PARTITION_LOGICAL;
-	else if ((*part)->type & PED_PARTITION_FREESPACE) {
+	else {
 		if(!can_create_primary(disk)) {
 			warning_waitkey(N_("Cannot create more primary partitions"));
 			return 0;
 			else if (key == 'e') type = PED_PARTITION_EXTENDED;
 		}
 		else type = PED_PARTITION_NORMAL;
-	} else {
-		warning_waitkey(N_("Report a bug in the function menu_new and win a cookie."));
+	}
+
+	start = (*part)->geom.start;
+	end = (*part)->geom.end;
+	menu_title(_("Where do you want to put the partition"));
+	if(!_query_part_position(part_position,&start,&end,start,end,NULL,&opts))
 		return 0;
-	}	
-	menu_title(_("Where do you want to put the partition"));
-	key = do_menu(part_position, 8, MENU_BUTTON | MENU_TITLE, pos_keys, 0);
-	if (key == ESC)
+
+	if (!do_mkpart(disk,start,end,type,NULL,part,opts,&uiquery)) {
+		warning_waitkey(N_("Can't create partition."));
 		return 0;
-	else {
-		start = (*part)->geom.start;
-		end = (*part)->geom.end;
-		if (key == 'c') {
-			success = do_mkpart (disk, start, end, type, NULL, part, UI_CUSTOM_VALUES, &uiquery);
+	}
+	return 1;	
+}
+
+/* FIXME: Either there is a bug here, or libparted doesn't work as expected */
+action_resize (PedPartition **part) {
+	static MenuItem part_position[] = {
+		{ 'f', N_("Fixed start"), N_("Don't move the beginning of the partition") },
+		/* FIXME: Wording. */
+		{ 'b', N_("Begining"), N_("Place it as back as possible on partitions that support it") },
+		{ 'e', N_("End"), N_("Place it as forward as possible on partitions that support it") },
+		{ 'c', N_("Custom"), N_("Select custom start and end position of the partition") },
+		{ ESC, N_("Cancel"), N_("Do not resize the partition") },
+		{ 0, NULL, NULL }
+	};
+	static MenuItem resize_menu[] = {
+		{ 'r', N_("Resize"), N_("Resize the filesystem") },
+		{ 'c', N_("Change size"), N_("Change the size of the partition (if you know what you are doing)") },
+		{ ESC, N_("Cancel"), N_("Do not resize the partition") },
+		{ 0, NULL, NULL }
+	};
+	const char resize_keys[] = { 'r', 'c', ESC, '\0' };
+	int key;
+	PedConstraint *constraint = NULL;
+	PedFileSystem *fs = NULL;
+	PedSector start,end,first,last;
+	UIOpts opts = UI_WARN_COMMIT;
+	if (!((*part)->type & PED_PARTITION_EXTENDED)) {
+		menu_title(_("What do you want to do?"));
+		key = do_menu(resize_menu, 11, MENU_BUTTON | MENU_TITLE,resize_keys, 0);
+		if (key == ESC)
+			return 0;
+		if (key == 'r') {
+			fs = ped_file_system_open(&(*part)->geom);
+			if (!fs) {
+				warning_waitkey(_("Could not open the filesystem for resizing"));
+				return 0;
+			}
+			constraint = ped_file_system_get_resize_constraint(fs);
+			if (!constraint || constraint->min_size == constraint->max_size) {
+				warning_waitkey(_("We can't resize this filesystem type"));
+				ped_file_system_close (fs);
+				return 0;
+			}
+			ped_file_system_close (fs);
 		} else {
-			length = (*part)->geom.length;
-			def_len = length;
-			done = 0;
-			while (!done) {
-				def_str = ped_unit_format(dev,length);
-				if (def_str) temp = strdup(def_str);
-				if (!read_char(_("Size"), &temp)) {
-					if (temp) ped_free(temp);
-					if (def_str) ped_free(def_str);
-					return 0;
-				}
-				done = 1;
-				/* Get the new size only if the user modified it */
-				if(strcmp(temp,def_str)) {
-					if (!ped_unit_parse(temp,dev,&length,NULL)) {
-						warning_waitkey(N_("This is an invalid partition size"));
-						done = 0;
-					}
-					else if (length > def_len) {
-						length = def_len;
-					}
-				}
-				if (temp) ped_free(temp);
-				if (def_str) ped_free(def_str);
-			}
-			if (key == 'b') {
-				success = do_mkpart(disk, start, start+length-1, type, NULL, part, UI_DEFAULT,&uiquery);
-			}
-			else if (key == 'e') {
-				success = do_mkpart(disk, end-length+1, end, type, NULL, part, UI_DEFAULT, &uiquery);
-			}
+			opts |= UI_NO_FS_RESIZE;
 		}
 	}
-	if (!success)
-		warning_waitkey(N_("Can't create partition."));
-	return success;
+	char buf[SMALLBUF];
+
+	start = (*part)->geom.start;
+	end = (*part)->geom.end;
+	first = start;
+
+	if ((*part)->prev && (*part)->prev->type & PED_PARTITION_FREESPACE)
+		first = (*part)->prev->geom.start;
+	else first = start;
+
+	if ((*part)->next && (*part)->next->type & PED_PARTITION_FREESPACE)
+		last = (*part)->next->geom.end;
+	else last = end;
+
+	menu_title(_("Where to place the resized partition"));
+	if(!_query_part_position(part_position,&start,&end,first,last,constraint,&opts)) {
+		if (constraint) ped_constraint_destroy (constraint);
+		return 0;
+	}
+	if (constraint) ped_constraint_destroy (constraint);
 	
+
+	if (start != (*part)->geom.start || end != (*part)->geom.end)
+		if (!do_resize(disk,*part,start,end,opts,&uiquery)) {
+			warning_waitkey(N_("Couldn't resize partition."));
+			return 0;
+		}
+	return 1;
 }
 
 static int
+action_move (PedPartition **part) {
+	/* Combine this with new partition? */
+	static MenuItem part_position[] = {
+		{ 'f', N_("Begining"), N_("Move the partition to the begining of the free space") },
+		{ 'e', N_("End"), N_("Move the partition to the end of the free space") },
+		{ 'c', N_("Custom"), N_("Select custom start and end position of the partition") },
+		{ ESC, N_("Cancel"), N_("Do not move the partition") },
+		{ 0, NULL, NULL }
+	};
+	PedPartition *dst = NULL;
+	PedSector start,end,length;
+	PedConstraint *constraint = NULL;
+	PedFileSystem *fs = NULL;
+	UIOpts opts = UI_WARN_COMMIT;
+	fs = ped_file_system_open(&(*part)->geom);
+	if (!fs) {
+		warning_waitkey(N_("Can't open the filesystem"));
+		return 0;
+	}
+	constraint = ped_file_system_get_copy_constraint(fs,dev);
+	if (!constraint) {
+		warning_waitkey(N_("We can't move this partition"));
+		return 0;
+	}
+	ped_file_system_close (fs);
+	menu_title(_("Select free space to move the partition to"));
+	if (!do_plist(disk, &dst, PED_PARTITION_FREESPACE, 0)) {
+		ped_constraint_destroy (constraint);
+		return 0;
+	}
+	if (!dst) {
+		ped_constraint_destroy (constraint);
+		return 0; 
+	}
+	start = dst->geom.start;
+	end = dst->geom.end;
+	length = dst->geom.length;
+	
+	if (length < constraint->min_size) {
+		ped_constraint_destroy (constraint);
+		warning_waitkey(N_("You can't move this partition here"));
+		return 0;
+	}
+	length = MIN(length,(*part)->geom.length);
+	length = MAX(length,constraint->min_size);
+	end = start+length-1;
+	if(!_query_part_position(part_position,&start,&end,start,dst->geom.end,constraint,&opts)) {
+		ped_constraint_destroy (constraint);
+		return 0;
+	}
+	ped_constraint_destroy (constraint);
+	if (!do_move(disk,*part,start,end,opts,&uiquery)) {
+		warning_waitkey(N_("Partition move failed"));
+		return 0;
+	}
+	return 1;
+}
+static int
 action_mkfs (PedPartition **part) {
 	char buf[SMALLBUF];
 	const PedFileSystemType *type = NULL;
 }
 
 static int
+action_delete(PedPartition **part) {
+	int go = 1;
+	PedPartition *temp;
+	/* Remember either the previous partition so we can select the free space */
+	temp = disk_get_prev_nmd_partition(disk, *part);
+	if (temp && temp->type & PED_PARTITION_FREESPACE)
+		temp = disk_get_prev_nmd_partition(disk, temp); 
+
+	getbool(_("Do you want to delete this partition?"),&go);
+	if (!go) return 0;
+	if (!do_rm(disk,*part, &uiquery)) {
+		warning_waitkey(N_("Can't delete partition"));
+		return 0;
+	}
+	do {
+		temp = ped_disk_next_partition(disk,temp);
+	} while (temp && temp->type & PED_PARTITION_METADATA); 
+	*part = temp;
+	return 1;
+}
+
+static int
 action_commit () {
 	if (!do_commit(disk,&uiquery)) {
 		warning_waitkey(N_("Commit failed."));
 	refresh();
 }
 
-/* Get previous non-METADATA partition. Needed for menu navigation */
-/* FIXME: This is *ugly*. Fix it. Can be fixed with a expand/collapse
-          list of logical partitions. At least it works. */
-static PedPartition *
-disk_get_prev_nmd_partition(PedDisk *cdisk, PedPartition *part) {
-	PedPartition *temp_a, *temp_b;
-	/* temp_a will iterate through partitions that are not METADATA, while
-	   temp_b will iterate through all partitions. When temp_b reaches our partition,
-	   temp_a is the partition we are looking for. */
-	temp_a = NULL;
-	temp_b = temp_a;
-	do {
-		if (ped_disk_next_partition(cdisk,temp_b) == part)
-			break;
-		temp_b = ped_disk_next_partition(cdisk,temp_b);
-		if (!temp_b || !(temp_b->type & PED_PARTITION_METADATA))
-			temp_a = temp_b;
-	} while (temp_b);
-	return temp_a;
-}
-
 static MenuItem main_menu[] = {
 	{ 'b', N_("Bootable"), N_("Toggle bootable flag of the current partition") },
 	{ 'n', N_("New"), N_("Create new partition from free space") },
         { 0, NULL, NULL }
 };
 
-const char keys_ext[] = { 'd','u','w','q','p','h',UP_KEY,DOWN_KEY, '\0' };
+const char keys_ext[] = { 'd','u','w','q','p','h','r',UP_KEY,DOWN_KEY, '\0' };
 const char keys_free[] = { 'n','s','u','w','q','p','h',UP_KEY,DOWN_KEY, '\0' };
 const char keys_part[] = { 'b','f','c','a','y','r','o','d','t','u','w','q','p','h',UP_KEY,DOWN_KEY, '\0' };
 /*bfcayrodtuwqph*/
 		//redraw = 1;
 		key = 0;
 	}
+	else if (key == 'r') {
+		action_resize(part);
+		//redraw = 1;
+		key = 0;
+	}
+	else if (key == 'd') {
+		action_delete(part);
+		//redraw = 1;
+		key = 0;
+	}
+	else if (key == 'o') {
+		action_move(part);
+		//redraw = 1;
+		key = 0;
+	}
 	else {
 		warning_waitkey("Unimplemented");	 /* TODO */
 		key = 0;
 }
 
 
-/* Okay, this is our partition list. If there is no pointer to partition given, ASSume main menu */
+/* Okay, this is our partition list. If there is no pointer to partition given, ASSume main menu
+   have and havent aren't perfect, but work for our purposes */
 static int
-do_plist (PedDisk *cdisk, PedPartition **part) {
+do_plist (PedDisk *cdisk, PedPartition **part, PedPartitionType have, PedPartitionType havent) {
 	int key = 0, i, redraw = 1, selnum = 0, start = 0;
 	const char* keys;
 	PedPartition *selected = NULL;
 			redraw = 0;
 		}
 		if (part) {
-			if (selected->type & PED_PARTITION_EXTENDED || 
-			    selected->type & PED_PARTITION_FREESPACE)
+			if ((!have || selected->type & have) && !(havent && selected->type & havent))
+				keys = keys_partselect;
+			else
 				keys = keys_cantselect;
-			else
-				keys = keys_partselect;
 		}
 		else if (selected->type & PED_PARTITION_EXTENDED)
 			keys = keys_ext;
 	int test = 0;
 
 	show_info();
-	do_plist(disk,NULL);
+	do_plist(disk,NULL,0,0);
 	endwin();
 }
 int
 
         if (!disk)
                 goto error;
-	if (opts & UI_WARN_COMMIT)
+	if (opts & UI_WARN_COMMIT && !(part->type == PED_PARTITION_EXTENDED || (opts & UI_NO_FS_RESIZE)))
 		if (!ask_boolean_question 
 		(_("WARNING: This writes all data to disk automatically, continue?"),uiquery)) 
 			return 1;
                         goto error;
         }
 
-        start = part->geom.start;
-        end = part->geom.end;
         if (!get_sector (_("Start"), disk->dev, &start, &range_start, opts & UI_CUSTOM_VALUES, uiquery))
                 goto error;
         if (!get_sector (_("End"), disk->dev, &end, &range_end, opts & UI_CUSTOM_VALUES, uiquery))
                 goto error;
         snap_to_boundaries (&new_geom, &part->geom, disk,
                             range_start, range_end);
-
-        if (part->type == PED_PARTITION_EXTENDED) {
+	/* If the partition is extended or we have UI_NO_FS_RESIZE, don't try to resize the fs, FIXME */
+        if (part->type == PED_PARTITION_EXTENDED || (opts & UI_NO_FS_RESIZE)) {
                 constraint = constraint_from_start_end (disk->dev,
                                 range_start, range_end);
                 if (!ped_disk_set_partition_geom (disk, part, constraint,
                                                   new_geom.start, new_geom.end))
                         goto error_destroy_constraint;
-                ped_partition_set_system (part, NULL);
+		if (part->type == PED_PARTITION_EXTENDED)
+                	ped_partition_set_system (part, NULL);
+
+		uiquery->need_commit = 1;
         } else {
-                fs = ped_file_system_open (&part->geom);
-                if (!fs)
-                        goto error;
-                constraint = constraint_intersect_and_destroy (
-                                ped_file_system_get_resize_constraint (fs),
-                                constraint_from_start_end (
-                                        disk->dev, range_start, range_end));
+		fs = ped_file_system_open (&part->geom);
+		if (!fs)
+			goto error;
+		constraint = constraint_intersect_and_destroy (
+				ped_file_system_get_resize_constraint (fs),
+				constraint_from_start_end (
+					disk->dev, range_start, range_end));
                 if (!ped_disk_set_partition_geom (disk, part, constraint,
                                                   new_geom.start, new_geom.end))
                         goto error_close_fs;
                 /* may have changed... eg fat16 -> fat32 */
                 ped_partition_set_system (part, fs->type);
                 ped_file_system_close (fs);
+
+		ped_disk_commit (disk);
+		uiquery->need_commit = 0;
         }
 
-        ped_disk_commit (disk);
-	uiquery->need_commit = 0;
         ped_constraint_destroy (constraint);
         if (range_start != NULL)
                 ped_geometry_destroy (range_start);
 	UI_DEFAULT = 0,
 	UI_WARN_COMMIT = 1,	/* Warn the user if the operation commits the data to the disk */
 	UI_CUSTOM_VALUES = 2, 	/* Allow the user to adjust start/end on resize, etc */
-	UI_SPECIFY_PART_TYPE = 4 /* Allow the user to specify the partition type */
+	UI_SPECIFY_PART_TYPE = 4, /* Allow the user to specify the partition type */
+	UI_NO_FS_RESIZE = 8 	/* Resize will only change geometry, will not resize filesystem */
 };
 
 extern int _can_create_primary (const PedDisk*);
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.