mirror of
https://github.com/AltraMayor/f3.git
synced 2025-08-03 18:46:00 -04:00

@pbludov reported and fixed this bug in the following issue: https://github.com/AltraMayor/f3/issues/26
297 lines
6.4 KiB
C
297 lines
6.4 KiB
C
#include <stdbool.h>
|
|
#include <assert.h>
|
|
#include <argp.h>
|
|
#include <parted/parted.h>
|
|
|
|
#include "version.h"
|
|
#include "libutils.h"
|
|
|
|
/* Argp's global variables. */
|
|
const char *argp_program_version = "F3 Fix " F3_STR_VERSION;
|
|
|
|
/* Arguments. */
|
|
static char adoc[] = "<DISK_DEV>";
|
|
|
|
static char doc[] = "F3 Fix -- edit the partition table of "
|
|
"a fake flash drive to have a single partition that fully covers "
|
|
"the real capacity of the drive";
|
|
|
|
static struct argp_option options[] = {
|
|
{"disk-type", 'd', "TYPE", 0,
|
|
"Disk type of the partition table", 2},
|
|
{"fs-type", 'f', "TYPE", 0,
|
|
"Type of the file system of the partition", 0},
|
|
{"boot", 'b', NULL, 0,
|
|
"Mark the partition for boot", 0},
|
|
{"no-boot", 'n', NULL, 0,
|
|
"Do not mark the partition for boot", 0},
|
|
{"first-sec", 'a', "SEC-NUM", 0,
|
|
"Sector where the partition starts", 0},
|
|
{"last-sec", 'l', "SEC-NUM", 0,
|
|
"Sector where the partition ends", 0},
|
|
{"list-disk-types", 'k', NULL, 0,
|
|
"List all supported disk types", 3},
|
|
{"list-fs-types", 's', NULL, 0,
|
|
"List all supported types of file systems", 0},
|
|
{ 0 }
|
|
};
|
|
|
|
struct args {
|
|
bool list_disk_types;
|
|
bool list_fs_types;
|
|
|
|
bool boot;
|
|
|
|
/* 29 free bytes. */
|
|
|
|
const char *dev_filename;
|
|
PedDiskType *disk_type;
|
|
PedFileSystemType *fs_type;
|
|
PedSector first_sec;
|
|
PedSector last_sec;
|
|
};
|
|
|
|
static long long arg_to_long_long(const struct argp_state *state,
|
|
const char *arg)
|
|
{
|
|
char *end;
|
|
long long ll = strtoll(arg, &end, 0);
|
|
if (!arg)
|
|
argp_error(state, "An integer must be provided");
|
|
if (!*arg || *end)
|
|
argp_error(state, "`%s' is not an integer", arg);
|
|
return ll;
|
|
}
|
|
|
|
static error_t parse_opt(int key, char *arg, struct argp_state *state)
|
|
{
|
|
struct args *args = state->input;
|
|
long long ll;
|
|
|
|
switch (key) {
|
|
case 'd':
|
|
args->disk_type = ped_disk_type_get(arg);
|
|
if (!args->disk_type)
|
|
argp_error(state,
|
|
"Disk type `%s' is not supported; use --list-disk-types to see the supported types",
|
|
arg);
|
|
break;
|
|
|
|
case 'f':
|
|
args->fs_type = ped_file_system_type_get(arg);
|
|
if (!args->fs_type)
|
|
argp_error(state,
|
|
"File system type `%s' is not supported; use --list-fs-types to see the supported types",
|
|
arg);
|
|
break;
|
|
|
|
case 'b':
|
|
args->boot = true;
|
|
break;
|
|
|
|
case 'n':
|
|
args->boot = false;
|
|
break;
|
|
|
|
case 'a':
|
|
ll = arg_to_long_long(state, arg);
|
|
if (ll < 0)
|
|
argp_error(state,
|
|
"First sector must be greater or equal to 0");
|
|
args->first_sec = ll;
|
|
break;
|
|
|
|
case 'l':
|
|
ll = arg_to_long_long(state, arg);
|
|
if (ll < 0)
|
|
argp_error(state,
|
|
"Last sector must be greater or equal to 0");
|
|
args->last_sec = ll;
|
|
break;
|
|
|
|
case 'k':
|
|
args->list_disk_types = true;
|
|
break;
|
|
|
|
case 's':
|
|
args->list_fs_types = true;
|
|
break;
|
|
|
|
case ARGP_KEY_INIT:
|
|
args->dev_filename = NULL;
|
|
args->last_sec = -1;
|
|
break;
|
|
|
|
case ARGP_KEY_ARG:
|
|
if (args->dev_filename)
|
|
argp_error(state,
|
|
"Wrong number of arguments; only one is allowed");
|
|
args->dev_filename = arg;
|
|
break;
|
|
|
|
case ARGP_KEY_END:
|
|
if (args->list_disk_types || args->list_fs_types)
|
|
break;
|
|
|
|
if (!args->dev_filename)
|
|
argp_error(state,
|
|
"The disk device was not specified");
|
|
|
|
if (args->last_sec < 0)
|
|
argp_error(state,
|
|
"Option --last-sec is required");
|
|
if (args->first_sec > args->last_sec)
|
|
argp_error(state,
|
|
"Option --fist_sec must be less or equal to option --last_sec");
|
|
break;
|
|
|
|
default:
|
|
return ARGP_ERR_UNKNOWN;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static struct argp argp = {options, parse_opt, adoc, doc, NULL, NULL, NULL};
|
|
|
|
static void list_disk_types(void)
|
|
{
|
|
PedDiskType *type;
|
|
int i = 0;
|
|
printf("Disk types:\n");
|
|
for (type = ped_disk_type_get_next(NULL); type;
|
|
type = ped_disk_type_get_next(type)) {
|
|
printf("%s\t", type->name);
|
|
i++;
|
|
if (i == 5) {
|
|
printf("\n");
|
|
i = 0;
|
|
}
|
|
}
|
|
if (i > 0)
|
|
printf("\n");
|
|
printf("\n");
|
|
}
|
|
|
|
static void list_fs_types(void)
|
|
{
|
|
PedFileSystemType *fs_type;
|
|
int i = 0;
|
|
printf("File system types:\n");
|
|
for (fs_type = ped_file_system_type_get_next(NULL); fs_type;
|
|
fs_type = ped_file_system_type_get_next(fs_type)) {
|
|
printf("%s\t", fs_type->name);
|
|
i++;
|
|
if (i == 5) {
|
|
printf("\n");
|
|
i = 0;
|
|
}
|
|
}
|
|
if (i > 0)
|
|
printf("\n");
|
|
printf("\n");
|
|
}
|
|
|
|
static PedSector map_sector_to_logical_sector(PedSector sector,
|
|
int logical_sector_size)
|
|
{
|
|
assert(logical_sector_size >= 512);
|
|
assert(logical_sector_size % 512 == 0);
|
|
return sector / (logical_sector_size / 512);
|
|
}
|
|
|
|
/* 0 on failure, 1 otherwise. */
|
|
static int fix_disk(PedDevice *dev, PedDiskType *type,
|
|
PedFileSystemType *fs_type, int boot, PedSector start, PedSector end)
|
|
{
|
|
PedDisk *disk;
|
|
PedPartition *part;
|
|
PedGeometry *geom;
|
|
PedConstraint *constraint;
|
|
int ret = 0;
|
|
|
|
disk = ped_disk_new_fresh(dev, type);
|
|
if (!disk)
|
|
goto out;
|
|
|
|
start = map_sector_to_logical_sector(start, dev->sector_size);
|
|
end = map_sector_to_logical_sector(end, dev->sector_size);
|
|
part = ped_partition_new(disk, PED_PARTITION_NORMAL,
|
|
fs_type, start, end);
|
|
if (!part)
|
|
goto disk;
|
|
if (boot && !ped_partition_set_flag(part, PED_PARTITION_BOOT, 1))
|
|
goto part;
|
|
|
|
geom = ped_geometry_new(dev, start, end - start + 1);
|
|
if (!geom)
|
|
goto part;
|
|
constraint = ped_constraint_exact(geom);
|
|
ped_geometry_destroy(geom);
|
|
if (!constraint)
|
|
goto part;
|
|
|
|
ret = ped_disk_add_partition(disk, part, constraint);
|
|
ped_constraint_destroy(constraint);
|
|
if (!ret)
|
|
goto part;
|
|
/* ped_disk_print(disk); */
|
|
|
|
ret = ped_disk_commit(disk);
|
|
goto disk;
|
|
|
|
part:
|
|
ped_partition_destroy(part);
|
|
disk:
|
|
ped_disk_destroy(disk);
|
|
out:
|
|
return ret;
|
|
}
|
|
|
|
int main (int argc, char *argv[])
|
|
{
|
|
struct args args = {
|
|
/* Defaults. */
|
|
.list_disk_types = false,
|
|
.list_fs_types = false,
|
|
|
|
.boot = true,
|
|
|
|
.disk_type = ped_disk_type_get("msdos"),
|
|
.fs_type = ped_file_system_type_get("fat32"),
|
|
.first_sec = 2048, /* Skip first 1MB. */
|
|
};
|
|
|
|
PedDevice *dev;
|
|
int ret;
|
|
|
|
/* Read parameters. */
|
|
argp_parse(&argp, argc, argv, 0, NULL, &args);
|
|
print_header(stdout, "fix");
|
|
|
|
if (args.list_disk_types)
|
|
list_disk_types();
|
|
|
|
if (args.list_fs_types)
|
|
list_fs_types();
|
|
|
|
if (args.list_disk_types || args.list_fs_types) {
|
|
/* If the user has asked for the types,
|
|
* she doesn't want to fix the drive yet.
|
|
*/
|
|
return 0;
|
|
}
|
|
|
|
/* XXX If @dev is a partition, refer the user to
|
|
* the disk of this partition.
|
|
*/
|
|
dev = ped_device_get(args.dev_filename);
|
|
if (!dev)
|
|
return 1;
|
|
|
|
ret = !fix_disk(dev, args.disk_type, args.fs_type, args.boot,
|
|
args.first_sec, args.last_sec);
|
|
printf("Drive `%s' was successfully fixed\n", args.dev_filename);
|
|
ped_device_destroy(dev);
|
|
return ret;
|
|
}
|