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