|
1 | 1 | #include <stdbool.h> |
2 | 2 | #include <assert.h> |
| 3 | +#include <stdio.h> |
| 4 | +#include <stdlib.h> |
| 5 | +#include <string.h> |
| 6 | + |
| 7 | +#ifdef _WIN32 |
| 8 | +#include <windows.h> |
| 9 | +#include <winioctl.h> |
| 10 | +#include <getopt.h> |
| 11 | +#else |
3 | 12 | #include <argp.h> |
4 | 13 | #include <parted/parted.h> |
| 14 | +#endif |
5 | 15 |
|
6 | 16 | #include "version.h" |
7 | 17 | #include "libutils.h" |
8 | 18 |
|
9 | | -/* Argp's global variables. */ |
10 | | -const char *argp_program_version = "F3 Fix " F3_STR_VERSION; |
| 19 | +// Общие константы |
| 20 | +#define DEFAULT_FIRST_SEC 2048 |
| 21 | +#define WIN_SECTOR_SIZE 512 |
11 | 22 |
|
12 | | -/* Arguments. */ |
13 | | -static char adoc[] = "<DISK_DEV>"; |
14 | | - |
15 | | -static char doc[] = "F3 Fix -- edit the partition table of " |
16 | | - "a fake flash drive to have a single partition that fully covers " |
17 | | - "the real capacity of the drive"; |
18 | | - |
19 | | -static struct argp_option options[] = { |
20 | | - {"disk-type", 'd', "TYPE", 0, |
21 | | - "Disk type of the partition table", 2}, |
22 | | - {"fs-type", 'f', "TYPE", 0, |
23 | | - "Type of the file system of the partition", 0}, |
24 | | - {"boot", 'b', NULL, 0, |
25 | | - "Mark the partition for boot", 0}, |
26 | | - {"no-boot", 'n', NULL, 0, |
27 | | - "Do not mark the partition for boot", 0}, |
28 | | - {"first-sec", 'a', "SEC-NUM", 0, |
29 | | - "Sector where the partition starts", 0}, |
30 | | - {"last-sec", 'l', "SEC-NUM", 0, |
31 | | - "Sector where the partition ends", 0}, |
32 | | - {"list-disk-types", 'k', NULL, 0, |
33 | | - "List all supported disk types", 3}, |
34 | | - {"list-fs-types", 's', NULL, 0, |
35 | | - "List all supported types of file systems", 0}, |
36 | | - { 0 } |
37 | | -}; |
| 23 | +// Глобальные переменные |
| 24 | +const char *argp_program_version = "F3 Fix " F3_STR_VERSION; |
38 | 25 |
|
| 26 | +// Структура аргументов |
39 | 27 | struct args { |
40 | | - bool list_disk_types; |
41 | | - bool list_fs_types; |
42 | | - |
43 | | - bool boot; |
44 | | - |
45 | | - /* 29 free bytes. */ |
46 | | - |
47 | | - const char *dev_filename; |
48 | | - PedDiskType *disk_type; |
49 | | - PedFileSystemType *fs_type; |
50 | | - PedSector first_sec; |
51 | | - PedSector last_sec; |
| 28 | + bool list_disk_types; |
| 29 | + bool list_fs_types; |
| 30 | + bool boot; |
| 31 | + const char *dev_filename; |
| 32 | + const char *disk_type; |
| 33 | + const char *fs_type; |
| 34 | + long long first_sec; |
| 35 | + long long last_sec; |
52 | 36 | }; |
53 | 37 |
|
54 | | -static long long arg_to_long_long(const struct argp_state *state, |
55 | | - const char *arg) |
56 | | -{ |
57 | | - char *end; |
58 | | - long long ll = strtoll(arg, &end, 0); |
59 | | - if (!arg) |
60 | | - argp_error(state, "An integer must be provided"); |
61 | | - if (!*arg || *end) |
62 | | - argp_error(state, "`%s' is not an integer", arg); |
63 | | - return ll; |
| 38 | +#ifdef _WIN32 |
| 39 | +// Windows-специфичные функции |
| 40 | +static int fix_disk_win(const char *dev_path, long long start, long long end) { |
| 41 | + HANDLE hDevice = CreateFileA(dev_path, GENERIC_READ | GENERIC_WRITE, |
| 42 | + FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL); |
| 43 | + |
| 44 | + if (hDevice == INVALID_HANDLE_VALUE) { |
| 45 | + fprintf(stderr, "Error opening device: %lu\n", GetLastError()); |
| 46 | + return 0; |
| 47 | + } |
| 48 | + |
| 49 | + // Создание новой MBR |
| 50 | + CREATE_DISK createDisk = {0}; |
| 51 | + createDisk.PartitionStyle = PARTITION_STYLE_MBR; |
| 52 | + DWORD bytesReturned; |
| 53 | + |
| 54 | + if (!DeviceIoControl(hDevice, IOCTL_DISK_CREATE_DISK, |
| 55 | + &createDisk, sizeof(createDisk), NULL, 0, &bytesReturned, NULL)) { |
| 56 | + fprintf(stderr, "Create disk failed: %lu\n", GetLastError()); |
| 57 | + CloseHandle(hDevice); |
| 58 | + return 0; |
| 59 | + } |
| 60 | + |
| 61 | + // Настройка разделов |
| 62 | + DRIVE_LAYOUT_INFORMATION_EX layout = {0}; |
| 63 | + layout.PartitionStyle = PARTITION_STYLE_MBR; |
| 64 | + layout.Mbr.Signature = 0x12345678; |
| 65 | + |
| 66 | + // Расчет параметров раздела |
| 67 | + PARTITION_INFORMATION_EX part = {0}; |
| 68 | + part.PartitionStyle = PARTITION_STYLE_MBR; |
| 69 | + part.Mbr.PartitionType = 0x0C; // FAT32 |
| 70 | + part.StartingOffset.QuadPart = start * WIN_SECTOR_SIZE; |
| 71 | + part.PartitionLength.QuadPart = (end - start + 1) * WIN_SECTOR_SIZE; |
| 72 | + part.Mbr.BootIndicator = args.boot; |
| 73 | + |
| 74 | + memcpy(&layout.Mbr.PartitionEntry[0], &part, sizeof(PARTITION_INFORMATION_EX)); |
| 75 | + layout.PartitionCount = 1; |
| 76 | + |
| 77 | + if (!DeviceIoControl(hDevice, IOCTL_DISK_SET_DRIVE_LAYOUT_EX, |
| 78 | + &layout, sizeof(layout), NULL, 0, &bytesReturned, NULL)) { |
| 79 | + fprintf(stderr, "Set layout failed: %lu\n", GetLastError()); |
| 80 | + CloseHandle(hDevice); |
| 81 | + return 0; |
| 82 | + } |
| 83 | + |
| 84 | + CloseHandle(hDevice); |
| 85 | + return 1; |
64 | 86 | } |
65 | 87 |
|
66 | | -static error_t parse_opt(int key, char *arg, struct argp_state *state) |
67 | | -{ |
| 88 | +// Парсинг аргументов для Windows |
| 89 | +static void parse_args(int argc, char **argv, struct args *args) { |
| 90 | + int opt; |
| 91 | + static struct option long_options[] = { |
| 92 | + {"disk-type", required_argument, 0, 'd'}, |
| 93 | + {"fs-type", required_argument, 0, 'f'}, |
| 94 | + {"boot", no_argument, 0, 'b'}, |
| 95 | + {"no-boot", no_argument, 0, 'n'}, |
| 96 | + {"first-sec", required_argument, 0, 'a'}, |
| 97 | + {"last-sec", required_argument, 0, 'l'}, |
| 98 | + {"list-disk-types", no_argument, 0, 'k'}, |
| 99 | + {"list-fs-types", no_argument, 0, 's'}, |
| 100 | + {0, 0, 0, 0} |
| 101 | + }; |
| 102 | + |
| 103 | + while ((opt = getopt_long(argc, argv, "d:f:bn:a:l:ks", long_options, NULL)) != -1) { |
| 104 | + switch (opt) { |
| 105 | + case 'd': args->disk_type = optarg; break; |
| 106 | + case 'f': args->fs_type = optarg; break; |
| 107 | + case 'b': args->boot = true; break; |
| 108 | + case 'n': args->boot = false; break; |
| 109 | + case 'a': args->first_sec = atoll(optarg); break; |
| 110 | + case 'l': args->last_sec = atoll(optarg); break; |
| 111 | + case 'k': args->list_disk_types = true; break; |
| 112 | + case 's': args->list_fs_types = true; break; |
| 113 | + default: exit(EXIT_FAILURE); |
| 114 | + } |
| 115 | + } |
| 116 | + |
| 117 | + if (optind < argc) { |
| 118 | + args->dev_filename = argv[optind]; |
| 119 | + } |
| 120 | +} |
| 121 | + |
| 122 | +#else // Linux реализация |
| 123 | + |
| 124 | +// Оригинальные Linux-функции с argp |
| 125 | +static error_t parse_opt(int key, char *arg, struct argp_state *state) { |
68 | 126 | struct args *args = state->input; |
69 | 127 | long long ll; |
70 | 128 |
|
@@ -152,116 +210,62 @@ static error_t parse_opt(int key, char *arg, struct argp_state *state) |
152 | 210 | } |
153 | 211 |
|
154 | 212 | static struct argp argp = {options, parse_opt, adoc, doc, NULL, NULL, NULL}; |
155 | | - |
156 | | -static void list_disk_types(void) |
157 | | -{ |
158 | | - PedDiskType *type; |
159 | | - int i = 0; |
160 | | - printf("Disk types:\n"); |
161 | | - for (type = ped_disk_type_get_next(NULL); type; |
162 | | - type = ped_disk_type_get_next(type)) { |
163 | | - printf("%s\t", type->name); |
164 | | - i++; |
165 | | - if (i == 5) { |
166 | | - printf("\n"); |
167 | | - i = 0; |
168 | | - } |
169 | | - } |
170 | | - if (i > 0) |
171 | | - printf("\n"); |
172 | | - printf("\n"); |
173 | | -} |
174 | | - |
175 | | -static void list_fs_types(void) |
176 | | -{ |
177 | | - PedFileSystemType *fs_type; |
178 | | - int i = 0; |
179 | | - printf("File system types:\n"); |
180 | | - for (fs_type = ped_file_system_type_get_next(NULL); fs_type; |
181 | | - fs_type = ped_file_system_type_get_next(fs_type)) { |
182 | | - printf("%s\t", fs_type->name); |
183 | | - i++; |
184 | | - if (i == 5) { |
185 | | - printf("\n"); |
186 | | - i = 0; |
187 | | - } |
188 | | - } |
189 | | - if (i > 0) |
190 | | - printf("\n"); |
191 | | - printf("\n"); |
192 | | -} |
193 | | - |
194 | | -static PedSector map_sector_to_logical_sector(PedSector sector, |
195 | | - int logical_sector_size) |
196 | | -{ |
197 | | - assert(logical_sector_size >= 512); |
198 | | - assert(logical_sector_size % 512 == 0); |
199 | | - return sector / (logical_sector_size / 512); |
200 | | -} |
201 | | - |
202 | | -/* 0 on failure, 1 otherwise. */ |
203 | | -static int fix_disk(PedDevice *dev, PedDiskType *type, |
204 | | - PedFileSystemType *fs_type, int boot, PedSector start, PedSector end) |
205 | | -{ |
206 | | - PedDisk *disk; |
207 | | - PedPartition *part; |
208 | | - PedGeometry *geom; |
209 | | - PedConstraint *constraint; |
210 | | - int ret = 0; |
211 | | - |
212 | | - disk = ped_disk_new_fresh(dev, type); |
213 | | - if (!disk) |
214 | | - goto out; |
215 | | - |
216 | | - start = map_sector_to_logical_sector(start, dev->sector_size); |
217 | | - end = map_sector_to_logical_sector(end, dev->sector_size); |
218 | | - part = ped_partition_new(disk, PED_PARTITION_NORMAL, |
219 | | - fs_type, start, end); |
220 | | - if (!part) |
221 | | - goto disk; |
222 | | - if (boot && !ped_partition_set_flag(part, PED_PARTITION_BOOT, 1)) |
223 | | - goto part; |
224 | | - |
225 | | - geom = ped_geometry_new(dev, start, end - start + 1); |
226 | | - if (!geom) |
227 | | - goto part; |
228 | | - constraint = ped_constraint_exact(geom); |
229 | | - ped_geometry_destroy(geom); |
230 | | - if (!constraint) |
231 | | - goto part; |
232 | | - |
233 | | - ret = ped_disk_add_partition(disk, part, constraint); |
234 | | - ped_constraint_destroy(constraint); |
235 | | - if (!ret) |
236 | | - goto part; |
237 | | - /* ped_disk_print(disk); */ |
238 | | - |
239 | | - ret = ped_disk_commit(disk); |
240 | | - goto disk; |
241 | | - |
242 | | -part: |
243 | | - ped_partition_destroy(part); |
244 | | -disk: |
245 | | - ped_disk_destroy(disk); |
246 | | -out: |
247 | | - return ret; |
248 | | -} |
249 | | - |
250 | | -int main (int argc, char *argv[]) |
251 | | -{ |
252 | | - struct args args = { |
253 | | - /* Defaults. */ |
254 | | - .list_disk_types = false, |
255 | | - .list_fs_types = false, |
256 | | - |
257 | | - .boot = true, |
258 | | - |
259 | | - .disk_type = ped_disk_type_get("msdos"), |
260 | | - .fs_type = ped_file_system_type_get("fat32"), |
261 | | - .first_sec = 2048, /* Skip first 1MB. */ |
262 | | - }; |
263 | | - |
264 | | - PedDevice *dev; |
| 213 | +#endif |
| 214 | + |
| 215 | +int main(int argc, char *argv[]) { |
| 216 | + struct args args = { |
| 217 | + .list_disk_types = false, |
| 218 | + .list_fs_types = false, |
| 219 | + .boot = true, |
| 220 | + .disk_type = "msdos", |
| 221 | + .fs_type = "fat32", |
| 222 | + .first_sec = DEFAULT_FIRST_SEC, |
| 223 | + .last_sec = -1 |
| 224 | + }; |
| 225 | + |
| 226 | +#ifdef _WIN32 |
| 227 | + // Windows инициализация |
| 228 | + WSADATA wsaData; |
| 229 | + WSAStartup(MAKEWORD(2, 2), &wsaData); |
| 230 | + parse_args(argc, argv, &args); |
| 231 | +#else |
| 232 | + // Linux парсинг аргументов |
| 233 | + argp_parse(&argp, argc, argv, 0, NULL, &args); |
| 234 | +#endif |
| 235 | + |
| 236 | + // Общая логика |
| 237 | + if (args.list_disk_types) { |
| 238 | + printf("Supported disk types: msdos\n"); |
| 239 | + return 0; |
| 240 | + } |
| 241 | + |
| 242 | + if (args.list_fs_types) { |
| 243 | + printf("Supported filesystems: fat32\n"); |
| 244 | + return 0; |
| 245 | + } |
| 246 | + |
| 247 | + if (!args.dev_filename || args.last_sec < 0) { |
| 248 | + fprintf(stderr, "Missing required arguments\n"); |
| 249 | + return 1; |
| 250 | + } |
| 251 | + |
| 252 | +#ifdef _WIN32 |
| 253 | + // Windows: преобразование пути |
| 254 | + char win_path[MAX_PATH]; |
| 255 | + if (sscanf(args.dev_filename, "/dev/sd%c", &drive_letter) == 1) { |
| 256 | + int drive_num = tolower(drive_letter) - 'a'; |
| 257 | + snprintf(win_path, MAX_PATH, "\\\\.\\PhysicalDrive%d", drive_num); |
| 258 | + } else { |
| 259 | + strncpy(win_path, args.dev_filename, MAX_PATH); |
| 260 | + } |
| 261 | + |
| 262 | + if (!fix_disk_win(win_path, args.first_sec, args.last_sec)) { |
| 263 | + fprintf(stderr, "Failed to fix disk\n"); |
| 264 | + return 1; |
| 265 | + } |
| 266 | +#else |
| 267 | + // Linux реализация с libparted |
| 268 | + PedDevice *dev = ped_device_get(args.dev_filename); |
265 | 269 | int ret; |
266 | 270 |
|
267 | 271 | /* Read parameters. */ |
@@ -290,7 +294,8 @@ int main (int argc, char *argv[]) |
290 | 294 |
|
291 | 295 | ret = !fix_disk(dev, args.disk_type, args.fs_type, args.boot, |
292 | 296 | args.first_sec, args.last_sec); |
293 | | - printf("Drive `%s' was successfully fixed\n", args.dev_filename); |
294 | | - ped_device_destroy(dev); |
295 | | - return ret; |
| 297 | +#endif |
| 298 | + |
| 299 | + printf("Drive %s was successfully fixed\n", args.dev_filename); |
| 300 | + return 0; |
296 | 301 | } |
0 commit comments