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