[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 "fatfs/ff.h"
12 #include "fatfs/diskio.h"
13
14 char* 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]); goto print_help; } \
71 if(nargs>_max_) { printf("Too many args for command %s.\n",argv[-1]); goto print_help; } \
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", imageFileName, ret); \
93 goto print_help; \
94 } } while(0)
95
96 int main(int oargc, char* oargv[])
97 {
98 int ret;
99 int argc = oargc - 1;
100 char** argv = oargv + 1;
101
102 // first parameter must be the image file.
103 if (argc == 0)
104 {
105 goto print_help;
106 }
107
108 if (is_command(argv[0]))
109 {
110 printf("Error: first parameter must be a filename, found '%s' instead. \n", argv[0]);
111 goto print_help;
112 }
113
114 imageFileName = argv[0];
115
116 if (disk_initialize(0))
117 {
118 printf("Error: could not open image file '%s'. \n", imageFileName);
119 goto print_help;
120 }
121
122 argc--;
123 argv++;
124
125 while (argc > 0)
126 {
127 char *parg = *argv;
128 int nargs = 0;
129 int i = 0;
130
131 if (!is_command(parg))
132 {
133 printf("Error: Expected a command, found '%s' instead. \n", parg);
134 goto print_help;
135 }
136
137 parg++;
138 argv++;
139 argc--;
140
141 // find next command, to calculare number of args
142 while ((argv[i] != NULL) && !is_command(argv[i++]))
143 nargs++;
144
145 if (strcmp(parg, "format") == 0)
146 {
147 // NOTE: The fs driver detects which FAT format fits best based on size
148 int sectors;
149
150 NEED_PARAMS(1, 1);
151
152 NEED_MOUNT();
153
154 // Arg 1: number of sectors
155 sectors = atoi(argv[0]);
156
157 if (sectors <= 0)
158 {
159 printf("Error: Sectors must be > 0\n");
160 return 1;
161 }
162
163 disk_ioctl(0, SET_SECTOR_COUNT, &sectors);
164
165 ret = f_mkfs("0:", 1, 4096);
166 if (ret)
167 {
168 printf("ERROR: Formatting drive: %d.\n", ret);
169 goto print_help;
170 }
171 }
172 else if (strcmp(parg, "boot") == 0)
173 {
174 NEED_PARAMS(1, 1);
175
176 // Arg 1: boot file
177 printf("Not Implemented.");
178 }
179 else if (strcmp(parg, "add") == 0)
180 {
181 FILE* fe;
182 FIL fv = { 0 };
183 UINT rdlen = 0;
184 UINT wrlen = 0;
185
186 NEED_PARAMS(2, 2);
187
188 NEED_MOUNT();
189
190 // Arg 1: external file to add
191 // Arg 2: virtual filename
192
193 fe = fopen(argv[0], "rb");
194
195 if (!fe)
196 {
197 printf("Error: unable to open external file '%s' for reading.", argv[0]);
198 return 1;
199 }
200
201 if (f_open(&fv, argv[1], FA_WRITE | FA_CREATE_ALWAYS))
202 {
203 printf("Error: unable to open file '%s' for writing.", argv[1]);
204 return 1;
205 }
206
207 while ((rdlen = fread(buff, 1, 32768, fe)) > 0)
208 {
209 f_write(&fv, buff, rdlen, &wrlen);
210 }
211
212 fclose(fe);
213 f_close(&fv);
214 }
215 else if (strcmp(parg, "extract") == 0)
216 {
217 FIL fe = { 0 };
218 FILE* fv;
219 UINT rdlen = 0;
220 UINT wrlen = 0;
221
222 NEED_PARAMS(2, 2);
223
224 NEED_MOUNT();
225
226 // Arg 1: virtual file to extract
227 // Arg 2: external filename
228
229 if (f_open(&fe, argv[0], FA_READ))
230 {
231 printf("Error: unable to open file '%s' for reading.", argv[0]);
232 return 1;
233 }
234
235 fv = fopen(argv[1], "wb");
236
237 if (!fv)
238 {
239 printf("Error: unable to open external file '%s' for writing.", argv[1]);
240 return 1;
241 }
242
243 while ((f_read(&fe, buff, 32768, &rdlen) == 0) && (rdlen > 0))
244 {
245 fwrite(buff, 1, rdlen, fv);
246 }
247
248 f_close(&fe);
249 fclose(fv);
250 }
251 else if (strcmp(parg, "move") == 0)
252 {
253 NEED_PARAMS(2, 2);
254
255 NEED_MOUNT();
256 // Arg 1: src path & filename
257 // Arg 2: new path & filename
258
259 if (f_rename(argv[0], argv[1]))
260 printf("Error moving/renaming '%s' to '%s'", argv[0], argv[1]);
261 }
262 else if (strcmp(parg, "copy") == 0)
263 {
264 FIL fe = { 0 };
265 FIL fv = { 0 };
266 UINT rdlen = 0;
267 UINT wrlen = 0;
268
269 NEED_PARAMS(2, 2);
270
271 NEED_MOUNT();
272 // Arg 1: src path & filename
273 // Arg 2: new path & filename
274
275 if (f_open(&fe, argv[0], FA_READ))
276 {
277 printf("Error: unable to open file '%s' for reading.", argv[0]);
278 return 1;
279 }
280 if (f_open(&fv, argv[1], FA_WRITE | FA_CREATE_ALWAYS))
281 {
282 printf("Error: unable to open file '%s' for writing.", argv[1]);
283 return 1;
284 }
285
286 while ((f_read(&fe, buff, 32768, &rdlen) == 0) && (rdlen > 0))
287 {
288 f_write(&fv, buff, rdlen, &wrlen);
289 }
290
291 f_close(&fe);
292 f_close(&fv);
293 }
294 else if (strcmp(parg, "mkdir") == 0)
295 {
296 NEED_PARAMS(1, 1);
297
298 NEED_MOUNT();
299
300 // Arg 1: folder path
301 f_mkdir(argv[0]);
302 }
303 else if (strcmp(parg, "delete") == 0)
304 {
305 NEED_PARAMS(1, 1);
306
307 NEED_MOUNT();
308
309 // Arg 1: file/folder path (cannot delete non-empty folders)
310 f_unlink(argv[0]);
311 }
312 else if (strcmp(parg, "list") == 0)
313 {
314 char* root = "/";
315 DIR dir = { 0 };
316 FILINFO info = { 0 };
317 char lfname[257];
318
319 NEED_PARAMS(0, 1);
320
321 // Arg 1: folder path (optional)
322
323 if (nargs == 1)
324 {
325 root = argv[0];
326 }
327
328 if (f_opendir(&dir, root))
329 {
330 printf("Error opening directory '%s'.\n", root);
331 return 1;
332 }
333
334 printf("Listing directory contents of: %s\n", root);
335
336 info.lfname = lfname;
337 info.lfsize = 256;
338 while ((!f_readdir(&dir, &info)) && (strlen(info.fname) > 0))
339 {
340 if (strlen(info.lfname) > 0)
341 printf(" - %s (%s)\n", info.lfname, info.fname);
342 else
343 printf(" - %s\n", info.fname);
344 }
345 }
346 else
347 {
348 printf("Error: Unknown or invalid command: %s\n", argv[-1]);
349 goto print_help;
350 }
351 argv += nargs;
352 argc -= nargs;
353 }
354
355 return 0;
356
357 print_help:
358 printf("Syntax: %s image_file [list of commands]\n\n", oargv[0]);
359 printf("Commands: [Note: both '/' and '-' are accepted as command prefixes.] \n");
360 printf(" /format <sectors> [<filesystem>] Formats the disk image.\n");
361 printf(" /boot <sector file> Writes a new boot sector.\n");
362 printf(" /add <src path> <dst path> Copies an external file or directory\n"
363 " into the image.\n");
364 printf(" /extract <src path> <dst path> Copies a file or directory from the image\n"
365 " into an external file or directory.\n");
366 printf(" /move <src path> <new path> Moves/renames a file or directory.\n");
367 printf(" /copy <src path> <new path> Copies a file or directory.\n");
368 printf(" /mkdir <src path> <new path> Creates a directory.\n");
369 printf(" /rmdir <src path> <new path> Creates a directory.\n");
370 printf(" /list [<pattern>] Lists files a directory (defaults to root).\n");
371 //printf(" /recursive Enables recursive processing for directories.\n");
372
373 return 1;
374 }
375