[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 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 BOOL 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 BOOL 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 if(fopen_s(&fe, argv[0],"rb"))
182 {
183 printf("Error: unable to open external file '%s' for reading.", argv[0]);
184 return 1;
185 }
186 if(f_open(&fv, argv[1], FA_WRITE | FA_CREATE_ALWAYS))
187 {
188 printf("Error: unable to open file '%s' for writing.", argv[1]);
189 return 1;
190 }
191
192 char buff[32768];
193 UINT rdlen = 0;
194 UINT wrlen = 0;
195
196 while( (rdlen = fread(buff,1,32768,fe)) > 0 )
197 {
198 f_write(&fv,buff, rdlen, &wrlen);
199 }
200
201 fclose(fe);
202 f_close(&fv);
203 }
204 else if(strcmp(parg,"extract")==0)
205 {
206 NEED_PARAMS(2,2);
207
208 NEED_MOUNT();
209
210 // Arg 1: virtual file to extract
211 // Arg 2: external filename
212
213 FIL fe = {0};
214 FILE* fv;
215
216 if(f_open(&fe, argv[0], FA_READ))
217 {
218 printf("Error: unable to open file '%s' for reading.", argv[0]);
219 return 1;
220 }
221 if(fopen_s(&fv, argv[1],"wb"))
222 {
223 printf("Error: unable to open external file '%s' for writing.", argv[1]);
224 return 1;
225 }
226
227 char buff[32768];
228 UINT rdlen = 0;
229 UINT wrlen = 0;
230
231 while( (f_read(&fe, buff, 32768, &rdlen) == 0 ) && ( rdlen > 0) )
232 {
233 fwrite(buff, 1, rdlen, fv);
234 }
235
236 f_close(&fe);
237 fclose(fv);
238 }
239 else if(strcmp(parg,"move")==0)
240 {
241 NEED_PARAMS(2,2);
242
243 NEED_MOUNT();
244 // Arg 1: src path & filename
245 // Arg 2: new path & filename
246
247 if(f_rename(argv[0], argv[1]))
248 printf("Error moving/renaming '%s' to '%s'", argv[0],argv[1]);
249 }
250 else if(strcmp(parg,"copy")==0)
251 {
252 NEED_PARAMS(2,2)
253
254 NEED_MOUNT();
255 // Arg 1: src path & filename
256 // Arg 2: new path & filename
257
258 FIL fe = {0};
259 FIL fv = {0};
260
261 if(f_open(&fe, argv[0], FA_READ))
262 {
263 printf("Error: unable to open file '%s' for reading.", argv[0]);
264 return 1;
265 }
266 if(f_open(&fv, argv[1], FA_WRITE|FA_CREATE_ALWAYS))
267 {
268 printf("Error: unable to open file '%s' for writing.", argv[1]);
269 return 1;
270 }
271
272 char buff[32768];
273 UINT rdlen = 0;
274 UINT wrlen = 0;
275
276 while( (f_read(&fe, buff, 32768, &rdlen) == 0) && (rdlen > 0) )
277 {
278 f_write(&fv, buff, rdlen, &wrlen);
279 }
280
281 f_close(&fe);
282 f_close(&fv);
283 }
284 else if(strcmp(parg,"mkdir")==0)
285 {
286 NEED_PARAMS(1,1);
287
288 NEED_MOUNT();
289 // Arg 1: folder path
290 f_mkdir(argv[1]);
291 }
292 else if(strcmp(parg,"delete")==0)
293 {
294 NEED_PARAMS(1,1);
295
296 NEED_MOUNT();
297 // Arg 1: file/folder path (cannot delete non-empty folders)
298 f_unlink(argv[1]);
299 }
300 else if(strcmp(parg,"list")==0)
301 {
302 NEED_PARAMS(0,1);
303
304 // Arg 1: folder path (optional)
305 char* root = "/";
306
307 if(nargs == 1)
308 {
309 root = argv[0];
310 }
311
312 DIR dir = {0};
313
314 if(f_opendir(&dir, root))
315 {
316 printf("Error opening directory '%s'.\n",root);
317 return 1;
318 }
319
320 printf("Listing directory contents of: %s\n", root);
321
322 FILINFO info = {0};
323 CHAR lfname[257];
324 info.lfname = lfname;
325 info.lfsize = 256;
326 while( (!f_readdir(&dir,&info)) && (strlen(info.fname)>0))
327 {
328 if(strlen(info.lfname) > 0)
329 printf(" - %s (%s)\n", info.lfname, info.fname);
330 else
331 printf(" - %s\n", info.fname);
332 }
333 }
334 else
335 {
336 printf("Error: Unknown or invalid command: %s\n",argv[-1]);
337 goto print_help;
338 }
339 argv+=nargs;
340 argc-=nargs;
341 }
342
343 return 0;
344
345 print_help:
346 printf("Syntax: %s image_file [list of commands]\n\n", oargv[0]);
347 printf("Commands: [Note: both '/' and '-' are accepted as command prefixes.] \n");
348 printf(" /format <sectors> [<filesystem>] Formats the disk image.\n");
349 printf(" /boot <sector file> Writes a new boot sector.\n");
350 printf(" /add <src path> <dst path> Copies an external file or directory\n"
351 " into the image.\n");
352 printf(" /extract <src path> <dst path> Copies a file or directory from the image\n"
353 " into an external file or directory.\n");
354 printf(" /move <src path> <new path> Moves/renames a file or directory.\n");
355 printf(" /copy <src path> <new path> Copies a file or directory.\n");
356 printf(" /mkdir <src path> <new path> Creates a directory.\n");
357 printf(" /rmdir <src path> <new path> Creates a directory.\n");
358 printf(" /list [<pattern>] Lists files a directory (defaults to root).\n");
359 //printf(" /recursive Enables recursive processing for directories.\n");
360
361 return 1;
362 }
363