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