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