[FATTEN]
[reactos.git] / reactos / tools / fatten / fatten.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS FAT Image Creator
4 * FILE: tools/fatten/fatten.c
5 * PURPOSE: FAT Image Creator (for EFI Boot)
6 * PROGRAMMERS: David Quintana
7 */
8 #include <stdio.h>
9 #include <string.h>
10 #include <time.h>
11 #include <ctype.h>
12 #include "fatfs/ff.h"
13 #include "fatfs/diskio.h"
14
15 static FATFS g_Filesystem;
16 static int isMounted = 0;
17 static char buff[32768];
18
19 // tool needed by fatfs
20 DWORD get_fattime()
21 {
22 /* 31-25: Year(0-127 org.1980), 24-21: Month(1-12), 20-16: Day(1-31) */
23 /* 15-11: Hour(0-23), 10-5: Minute(0-59), 4-0: Second(0-29 *2) */
24
25 time_t rawtime;
26 struct tm * timeinfo;
27
28 time(&rawtime);
29 timeinfo = localtime(&rawtime);
30
31 {
32 union FatTime {
33 struct {
34 DWORD Second : 5; // div 2
35 DWORD Minute : 6;
36 DWORD Hour : 5;
37 DWORD Day : 5;
38 DWORD Month : 4;
39 DWORD Year : 7; // year-1980
40 };
41 DWORD whole;
42 } myTime = {
43 {
44 timeinfo->tm_sec / 2,
45 timeinfo->tm_min,
46 timeinfo->tm_hour,
47 timeinfo->tm_mday,
48 timeinfo->tm_mon,
49 timeinfo->tm_year - 80,
50 }
51 };
52
53 return myTime.whole;
54 }
55 }
56
57 int is_command(const char* parg)
58 {
59 #if _WIN32
60 return (parg[0] == '/') || (parg[0] == '-');
61 #else
62 return (parg[0] == '-');
63 #endif
64 }
65
66 #define NEED_PARAMS(_min_,_max_) \
67 do {\
68 if(nargs<_min_) { printf("Too few args for command %s.\n",argv[-1]); PRINT_HELP_AND_QUIT(); } \
69 if(nargs>_max_) { printf("Too many args for command %s.\n",argv[-1]); PRINT_HELP_AND_QUIT(); } \
70 } while(0)
71
72 int need_mount()
73 {
74 int r;
75
76 if (isMounted)
77 return FR_OK;
78
79 r = f_mount(&g_Filesystem, "0:", 0);
80 if (r)
81 return r;
82
83 isMounted = 1;
84 return FR_OK;
85 }
86
87 #define NEED_MOUNT() \
88 do { ret = need_mount(); if(ret) \
89 {\
90 printf("Error: could not mount disk (%d). \n", ret); \
91 PRINT_HELP_AND_QUIT(); \
92 } } while(0)
93
94 void print_help(char const * const name)
95 {
96 printf("Syntax: %s image_file [list of commands]\n\n", name);
97 #if _WIN32
98 printf("Commands: [Note: both '/' and '-' are accepted as command prefixes.]\n");
99 #else
100 printf("Commands:\n");
101 #endif
102 printf(" -format <sectors> [<filesystem>]\n"
103 " Formats the disk image.\n");
104 printf(" -boot <sector file> [<custom header label>]\n"
105 " Writes a new boot sector.\n");
106 printf(" -add <src path> <dst path>\n"
107 " Copies an external file or directory into the image.\n");
108 printf(" -extract <src path> <dst path>\n"
109 " Copies a file or directory from the image into an external file\n"
110 " or directory.\n");
111 printf(" -move <src path> <new path>\n"
112 " Moves/renames a file or directory.\n");
113 printf(" -copy <src path> <new path>\n"
114 " Copies a file or directory.\n");
115 printf(" -mkdir <src path> <new path>\n"
116 " Creates a directory.\n");
117 printf(" -rmdir <src path> <new path>\n"
118 " Creates a directory.\n");
119 printf(" -list [<pattern>]\n"
120 " Lists files a directory (defaults to root).\n");
121 }
122
123 #define PRINT_HELP_AND_QUIT() \
124 do { \
125 ret = 1; \
126 print_help(oargv[0]); \
127 goto exit; \
128 } while (0)
129
130 int main(int oargc, char* oargv[])
131 {
132 int ret;
133 int argc = oargc - 1;
134 char** argv = oargv + 1;
135
136 // first parameter must be the image file.
137 if (argc == 0)
138 {
139 PRINT_HELP_AND_QUIT();
140 }
141
142 if (is_command(argv[0]))
143 {
144 printf("Error: first parameter must be a filename, found '%s' instead. \n", argv[0]);
145 PRINT_HELP_AND_QUIT();
146 }
147
148 if (disk_openimage(0, argv[0]))
149 {
150 printf("Error: could not open image file '%s'. \n", argv[0]);
151 PRINT_HELP_AND_QUIT();
152 }
153
154 argc--;
155 argv++;
156
157 while (argc > 0)
158 {
159 char *parg = *argv;
160 int nargs = 0;
161 int i = 0;
162
163 if (!is_command(parg))
164 {
165 printf("Error: Expected a command, found '%s' instead. \n", parg);
166 PRINT_HELP_AND_QUIT();
167 }
168
169 parg++;
170 argv++;
171 argc--;
172
173 // find next command, to calculare number of args
174 while ((argv[i] != NULL) && !is_command(argv[i++]))
175 nargs++;
176
177 if (strcmp(parg, "format") == 0)
178 {
179 // NOTE: The fs driver detects which FAT format fits best based on size
180 int sectors;
181
182 NEED_PARAMS(1, 2);
183
184 // Arg 1: number of sectors
185 sectors = atoi(argv[0]);
186
187 if (sectors <= 0)
188 {
189 printf("Error: Sectors must be > 0\n");
190 ret = 1;
191 goto exit;
192 }
193
194 disk_ioctl(0, SET_SECTOR_COUNT, &sectors);
195
196 NEED_MOUNT();
197
198 ret = f_mkfs("0:", 1, sectors < 4096 ? 1 : 8);
199 if (ret)
200 {
201 printf("ERROR: Formatting drive: %d.\n", ret);
202 PRINT_HELP_AND_QUIT();
203 }
204
205 // Arg 2: custom header label (optional)
206 if (nargs > 1)
207 {
208 char label[8];
209
210 int i, invalid=0;
211 int len = strlen(argv[1]);
212
213 if (len <= 8)
214 {
215 // Copy and verify each character
216 for (i = 0; i < len; i++)
217 {
218 char ch = argv[1][i];
219 label[i] = ch;
220
221 if (!isupper(ch) && !isspace(ch))
222 {
223 invalid =1;
224 break;
225 }
226 }
227
228 if (!invalid)
229 {
230 // Pad the label with spaces
231 while (len < 8)
232 {
233 label[len++] = ' ';
234 }
235 }
236 }
237 else
238 {
239 invalid = 1;
240 }
241
242 if (invalid)
243 {
244 printf("Error: header label is limited to 8 uppercase letters and spaces.");
245 ret = 1;
246 goto exit;
247 }
248
249 if (disk_read(0, buff, 0, 1))
250 {
251 printf("Error: unable to read existing boot sector from image.");
252 ret = 1;
253 goto exit;
254 }
255
256
257 if (g_Filesystem.fs_type == FS_FAT32)
258 {
259 memcpy(buff + 71, label, 8);
260 }
261 else
262 {
263 memcpy(buff + 43, label, 8);
264 }
265
266 if (disk_write(0, buff, 0, 1))
267 {
268 printf("Error: unable to write new boot sector to image.");
269 ret = 1;
270 goto exit;
271 }
272
273 }
274 }
275 else if (strcmp(parg, "boot") == 0)
276 {
277 FILE* fe;
278 BYTE* temp = buff + 1024;
279
280 NEED_PARAMS(1, 1);
281
282 // Arg 1: boot file
283
284 fe = fopen(argv[0], "rb");
285
286 if (!fe)
287 {
288 printf("Error: unable to open external file '%s' for reading.", argv[0]);
289 ret = 1;
290 goto exit;
291 }
292
293 if(!fread(buff, 512, 1, fe))
294 {
295 printf("Error: unable to read boot sector from file '%s'.", argv[0]);
296 fclose(fe);
297 ret = 1;
298 goto exit;
299 }
300
301 fclose(fe);
302
303 NEED_MOUNT();
304
305 if(disk_read(0, temp, 0, 1))
306 {
307 printf("Error: unable to read existing boot sector from image.");
308 ret = 1;
309 goto exit;
310 }
311
312 if (g_Filesystem.fs_type == FS_FAT32)
313 {
314 printf("TODO: writing boot sectors for FAT32 images not yet supported.");
315 ret = 1;
316 goto exit;
317 }
318 else
319 {
320 #define FAT16_HEADER_START 3
321 #define FAT16_HEADER_END 62
322
323 memcpy(buff + FAT16_HEADER_START, temp + FAT16_HEADER_START, FAT16_HEADER_END - FAT16_HEADER_START);
324 }
325
326 if (disk_write(0, buff, 0, 1))
327 {
328 printf("Error: unable to write new boot sector to image.");
329 ret = 1;
330 goto exit;
331 }
332 }
333 else if (strcmp(parg, "add") == 0)
334 {
335 FILE* fe;
336 FIL fv = { 0 };
337 UINT rdlen = 0;
338 UINT wrlen = 0;
339
340 NEED_PARAMS(2, 2);
341
342 NEED_MOUNT();
343
344 // Arg 1: external file to add
345 // Arg 2: virtual filename
346
347 fe = fopen(argv[0], "rb");
348
349 if (!fe)
350 {
351 printf("Error: unable to open external file '%s' for reading.", argv[0]);
352 ret = 1;
353 goto exit;
354 }
355
356 if (f_open(&fv, argv[1], FA_WRITE | FA_CREATE_ALWAYS))
357 {
358 printf("Error: unable to open file '%s' for writing.", argv[1]);
359 fclose(fe);
360 ret = 1;
361 goto exit;
362 }
363
364 while ((rdlen = fread(buff, 1, sizeof(buff), fe)) > 0)
365 {
366 f_write(&fv, buff, rdlen, &wrlen);
367 }
368
369 fclose(fe);
370 f_close(&fv);
371 }
372 else if (strcmp(parg, "extract") == 0)
373 {
374 FIL fe = { 0 };
375 FILE* fv;
376 UINT rdlen = 0;
377 UINT wrlen = 0;
378
379 NEED_PARAMS(2, 2);
380
381 NEED_MOUNT();
382
383 // Arg 1: virtual file to extract
384 // Arg 2: external filename
385
386 if (f_open(&fe, argv[0], FA_READ))
387 {
388 printf("Error: unable to open file '%s' for reading.", argv[0]);
389 ret = 1;
390 goto exit;
391 }
392
393 fv = fopen(argv[1], "wb");
394
395 if (!fv)
396 {
397 printf("Error: unable to open external file '%s' for writing.", argv[1]);
398 f_close(&fe);
399 ret = 1;
400 goto exit;
401 }
402
403 while ((f_read(&fe, buff, sizeof(buff), &rdlen) == 0) && (rdlen > 0))
404 {
405 fwrite(buff, 1, rdlen, fv);
406 }
407
408 f_close(&fe);
409 fclose(fv);
410 }
411 else if (strcmp(parg, "move") == 0)
412 {
413 NEED_PARAMS(2, 2);
414
415 NEED_MOUNT();
416 // Arg 1: src path & filename
417 // Arg 2: new path & filename
418
419 if (f_rename(argv[0], argv[1]))
420 printf("Error moving/renaming '%s' to '%s'", argv[0], argv[1]);
421 }
422 else if (strcmp(parg, "copy") == 0)
423 {
424 FIL fe = { 0 };
425 FIL fv = { 0 };
426 UINT rdlen = 0;
427 UINT wrlen = 0;
428
429 NEED_PARAMS(2, 2);
430
431 NEED_MOUNT();
432 // Arg 1: src path & filename
433 // Arg 2: new path & filename
434
435 if (f_open(&fe, argv[0], FA_READ))
436 {
437 printf("Error: unable to open file '%s' for reading.", argv[0]);
438 ret = 1;
439 goto exit;
440 }
441 if (f_open(&fv, argv[1], FA_WRITE | FA_CREATE_ALWAYS))
442 {
443 printf("Error: unable to open file '%s' for writing.", argv[1]);
444 f_close(&fe);
445 ret = 1;
446 goto exit;
447 }
448
449 while ((f_read(&fe, buff, sizeof(buff), &rdlen) == 0) && (rdlen > 0))
450 {
451 f_write(&fv, buff, rdlen, &wrlen);
452 }
453
454 f_close(&fe);
455 f_close(&fv);
456 }
457 else if (strcmp(parg, "mkdir") == 0)
458 {
459 NEED_PARAMS(1, 1);
460
461 NEED_MOUNT();
462
463 // Arg 1: folder path
464 f_mkdir(argv[0]);
465 }
466 else if (strcmp(parg, "delete") == 0)
467 {
468 NEED_PARAMS(1, 1);
469
470 NEED_MOUNT();
471
472 // Arg 1: file/folder path (cannot delete non-empty folders)
473 f_unlink(argv[0]);
474 }
475 else if (strcmp(parg, "list") == 0)
476 {
477 char* root = "/";
478 DIR dir = { 0 };
479 FILINFO info = { 0 };
480 char lfname[257];
481
482 NEED_PARAMS(0, 1);
483
484 // Arg 1: folder path (optional)
485
486 if (nargs == 1)
487 {
488 root = argv[0];
489 }
490
491 if (f_opendir(&dir, root))
492 {
493 printf("Error opening directory '%s'.\n", root);
494 ret = 1;
495 goto exit;
496 }
497
498 printf("Listing directory contents of: %s\n", root);
499
500 info.lfname = lfname;
501 info.lfsize = 256;
502 while ((!f_readdir(&dir, &info)) && (strlen(info.fname) > 0))
503 {
504 if (strlen(info.lfname) > 0)
505 printf(" - %s (%s)\n", info.lfname, info.fname);
506 else
507 printf(" - %s\n", info.fname);
508 }
509 }
510 else
511 {
512 printf("Error: Unknown or invalid command: %s\n", argv[-1]);
513 PRINT_HELP_AND_QUIT();
514 }
515 argv += nargs;
516 argc -= nargs;
517 }
518
519 ret = 0;
520
521 exit:
522
523 disk_cleanup(0);
524
525 return ret;
526 }
527