a94886058abff3b69f146feed8e20b1331bd49b1
[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 FATFS g_Filesystem;
15
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 - 1980,
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 printf("Commands: [Note: both '/' and '-' are accepted as command prefixes.] \n");
98 printf(" /format <sectors> [<filesystem>] Formats the disk image.\n");
99 printf(" /boot <sector file> Writes a new boot sector.\n");
100 printf(" /add <src path> <dst path> Copies an external file or directory\n"
101 " into the image.\n");
102 printf(" /extract <src path> <dst path> Copies a file or directory from the image\n"
103 " into an external file or directory.\n");
104 printf(" /move <src path> <new path> Moves/renames a file or directory.\n");
105 printf(" /copy <src path> <new path> Copies a file or directory.\n");
106 printf(" /mkdir <src path> <new path> Creates a directory.\n");
107 printf(" /rmdir <src path> <new path> Creates a directory.\n");
108 printf(" /list [<pattern>] Lists files a directory (defaults to root).\n");
109 //printf(" /recursive Enables recursive processing for directories.\n");
110 }
111
112 #define PRINT_HELP_AND_QUIT() \
113 do { \
114 ret = 1; \
115 print_help(oargv[0]); \
116 goto exit; \
117 } while (0)
118
119 int main(int oargc, char* oargv[])
120 {
121 int ret;
122 int argc = oargc - 1;
123 char** argv = oargv + 1;
124
125 // first parameter must be the image file.
126 if (argc == 0)
127 {
128 PRINT_HELP_AND_QUIT();
129 }
130
131 if (is_command(argv[0]))
132 {
133 printf("Error: first parameter must be a filename, found '%s' instead. \n", argv[0]);
134 PRINT_HELP_AND_QUIT();
135 }
136
137 if (disk_openimage(0, argv[0]))
138 {
139 printf("Error: could not open image file '%s'. \n", argv[0]);
140 PRINT_HELP_AND_QUIT();
141 }
142
143 argc--;
144 argv++;
145
146 while (argc > 0)
147 {
148 char *parg = *argv;
149 int nargs = 0;
150 int i = 0;
151
152 if (!is_command(parg))
153 {
154 printf("Error: Expected a command, found '%s' instead. \n", parg);
155 PRINT_HELP_AND_QUIT();
156 }
157
158 parg++;
159 argv++;
160 argc--;
161
162 // find next command, to calculare number of args
163 while ((argv[i] != NULL) && !is_command(argv[i++]))
164 nargs++;
165
166 if (strcmp(parg, "format") == 0)
167 {
168 // NOTE: The fs driver detects which FAT format fits best based on size
169 int sectors;
170
171 NEED_PARAMS(1, 1);
172
173 // Arg 1: number of sectors
174 sectors = atoi(argv[0]);
175
176 if (sectors <= 0)
177 {
178 printf("Error: Sectors must be > 0\n");
179 ret = 1;
180 goto exit;
181 }
182
183 disk_ioctl(0, SET_SECTOR_COUNT, &sectors);
184
185 NEED_MOUNT();
186
187 ret = f_mkfs("0:", 1, sectors < 4096 ? 1 : 8);
188 if (ret)
189 {
190 printf("ERROR: Formatting drive: %d.\n", ret);
191 PRINT_HELP_AND_QUIT();
192 }
193 }
194 else if (strcmp(parg, "boot") == 0)
195 {
196 FILE* fe;
197 BYTE* temp = buff + 1024;
198
199 NEED_PARAMS(1, 1);
200
201 // Arg 1: boot file
202
203 fe = fopen(argv[0], "rb");
204
205 if (!fe)
206 {
207 printf("Error: unable to open external file '%s' for reading.", argv[0]);
208 ret = 1;
209 goto exit;
210 }
211
212 if(!fread(buff, 512, 1, fe))
213 {
214 printf("Error: unable to read boot sector from file '%s'.", argv[0]);
215 ret = 1;
216 goto exit;
217 }
218
219 NEED_MOUNT();
220
221 if(disk_read(0, temp, 0, 1))
222 {
223 printf("Error: unable to read existing boot sector from image.");
224 ret = 1;
225 goto exit;
226 }
227
228 if (g_Filesystem.fs_type == FS_FAT32)
229 {
230 printf("TODO: writing boot sectors for FAT32 images not yet supported.");
231 ret = 1;
232 goto exit;
233 }
234 else
235 {
236 // Quick&dirty hardcoded length.
237 memcpy(buff + 2, temp + 2, 0x3E - 0x02);
238 }
239
240 if (disk_write(0, buff, 0, 1))
241 {
242 printf("Error: unable to write new boot sector to image.");
243 ret = 1;
244 goto exit;
245 }
246
247 fclose(fe);
248 }
249 else if (strcmp(parg, "add") == 0)
250 {
251 FILE* fe;
252 FIL fv = { 0 };
253 UINT rdlen = 0;
254 UINT wrlen = 0;
255
256 NEED_PARAMS(2, 2);
257
258 NEED_MOUNT();
259
260 // Arg 1: external file to add
261 // Arg 2: virtual filename
262
263 fe = fopen(argv[0], "rb");
264
265 if (!fe)
266 {
267 printf("Error: unable to open external file '%s' for reading.", argv[0]);
268 ret = 1;
269 goto exit;
270 }
271
272 if (f_open(&fv, argv[1], FA_WRITE | FA_CREATE_ALWAYS))
273 {
274 printf("Error: unable to open file '%s' for writing.", argv[1]);
275 fclose(fe);
276 ret = 1;
277 goto exit;
278 }
279
280 while ((rdlen = fread(buff, 1, 32768, fe)) > 0)
281 {
282 f_write(&fv, buff, rdlen, &wrlen);
283 }
284
285 fclose(fe);
286 f_close(&fv);
287 }
288 else if (strcmp(parg, "extract") == 0)
289 {
290 FIL fe = { 0 };
291 FILE* fv;
292 UINT rdlen = 0;
293 UINT wrlen = 0;
294
295 NEED_PARAMS(2, 2);
296
297 NEED_MOUNT();
298
299 // Arg 1: virtual file to extract
300 // Arg 2: external filename
301
302 if (f_open(&fe, argv[0], FA_READ))
303 {
304 printf("Error: unable to open file '%s' for reading.", argv[0]);
305 ret = 1;
306 goto exit;
307 }
308
309 fv = fopen(argv[1], "wb");
310
311 if (!fv)
312 {
313 printf("Error: unable to open external file '%s' for writing.", argv[1]);
314 f_close(&fe);
315 ret = 1;
316 goto exit;
317 }
318
319 while ((f_read(&fe, buff, 32768, &rdlen) == 0) && (rdlen > 0))
320 {
321 fwrite(buff, 1, rdlen, fv);
322 }
323
324 f_close(&fe);
325 fclose(fv);
326 }
327 else if (strcmp(parg, "move") == 0)
328 {
329 NEED_PARAMS(2, 2);
330
331 NEED_MOUNT();
332 // Arg 1: src path & filename
333 // Arg 2: new path & filename
334
335 if (f_rename(argv[0], argv[1]))
336 printf("Error moving/renaming '%s' to '%s'", argv[0], argv[1]);
337 }
338 else if (strcmp(parg, "copy") == 0)
339 {
340 FIL fe = { 0 };
341 FIL fv = { 0 };
342 UINT rdlen = 0;
343 UINT wrlen = 0;
344
345 NEED_PARAMS(2, 2);
346
347 NEED_MOUNT();
348 // Arg 1: src path & filename
349 // Arg 2: new path & filename
350
351 if (f_open(&fe, argv[0], FA_READ))
352 {
353 printf("Error: unable to open file '%s' for reading.", argv[0]);
354 ret = 1;
355 goto exit;
356 }
357 if (f_open(&fv, argv[1], FA_WRITE | FA_CREATE_ALWAYS))
358 {
359 printf("Error: unable to open file '%s' for writing.", argv[1]);
360 f_close(&fe);
361 ret = 1;
362 goto exit;
363 }
364
365 while ((f_read(&fe, buff, 32768, &rdlen) == 0) && (rdlen > 0))
366 {
367 f_write(&fv, buff, rdlen, &wrlen);
368 }
369
370 f_close(&fe);
371 f_close(&fv);
372 }
373 else if (strcmp(parg, "mkdir") == 0)
374 {
375 NEED_PARAMS(1, 1);
376
377 NEED_MOUNT();
378
379 // Arg 1: folder path
380 f_mkdir(argv[0]);
381 }
382 else if (strcmp(parg, "delete") == 0)
383 {
384 NEED_PARAMS(1, 1);
385
386 NEED_MOUNT();
387
388 // Arg 1: file/folder path (cannot delete non-empty folders)
389 f_unlink(argv[0]);
390 }
391 else if (strcmp(parg, "list") == 0)
392 {
393 char* root = "/";
394 DIR dir = { 0 };
395 FILINFO info = { 0 };
396 char lfname[257];
397
398 NEED_PARAMS(0, 1);
399
400 // Arg 1: folder path (optional)
401
402 if (nargs == 1)
403 {
404 root = argv[0];
405 }
406
407 if (f_opendir(&dir, root))
408 {
409 printf("Error opening directory '%s'.\n", root);
410 ret = 1;
411 goto exit;
412 }
413
414 printf("Listing directory contents of: %s\n", root);
415
416 info.lfname = lfname;
417 info.lfsize = 256;
418 while ((!f_readdir(&dir, &info)) && (strlen(info.fname) > 0))
419 {
420 if (strlen(info.lfname) > 0)
421 printf(" - %s (%s)\n", info.lfname, info.fname);
422 else
423 printf(" - %s\n", info.fname);
424 }
425 }
426 else
427 {
428 printf("Error: Unknown or invalid command: %s\n", argv[-1]);
429 PRINT_HELP_AND_QUIT();
430 }
431 argv += nargs;
432 argc -= nargs;
433 }
434
435 ret = 0;
436
437 exit:
438
439 disk_cleanup(0);
440
441 return ret;
442 }
443