ReactOS  0.4.12-dev-918-g6c6e7b8
fatten.c
Go to the documentation of this file.
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 <ctype.h>
12 #include "fatfs/ff.h"
13 #include "fatfs/diskio.h"
14 
16 static int isMounted = 0;
17 static unsigned char buff[32768];
18 
19 // tool needed by fatfs
21 {
22  /* 31-25: Year(0-127 org.1980), 24-21: Month(1-12), 20-16: Day(1-31) */
23  /* 15-11: Hour(0-23), 10-5: Minute(0-59), 4-0: Second(0-29 *2) */
24 
25  time_t rawtime;
26  struct tm * timeinfo;
27 
28  time(&rawtime);
29  timeinfo = localtime(&rawtime);
30 
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 + 1,
49  timeinfo->tm_year - 80,
50  }
51  };
52 
53  return myTime.whole;
54  }
55 }
56 
57 void print_help(const char* name)
58 {
59  printf("\n");
60  printf("Syntax: %s image_file [list of commands]\n\n", name);
61 #if _WIN32
62  printf("Commands: [Note: both '/' and '-' are accepted as command prefixes.]\n");
63 #else
64  printf("Commands:\n");
65 #endif
66  // printf(" -format <sectors> [<filesystem>] [<custom header label>]\n"
67  printf(" -format <sectors> [<custom header label>]\n"
68  " Formats the disk image.\n");
69  printf(" -boot <sector file>\n"
70  " Writes a new boot sector.\n");
71  printf(" -add <src path> <dst path>\n"
72  " Copies an external file or directory into the image.\n");
73  printf(" -extract <src path> <dst path>\n"
74  " Copies a file or directory from the image into an external file\n"
75  " or directory.\n");
76  printf(" -move <src path> <new path>\n"
77  " Moves/renames a file or directory.\n");
78  printf(" -copy <src path> <new path>\n"
79  " Copies a file or directory.\n");
80  printf(" -mkdir <src path> <new path>\n"
81  " Creates a directory.\n");
82  printf(" -rmdir <src path> <new path>\n"
83  " Creates a directory.\n");
84  printf(" -list [<pattern>]\n"
85  " Lists files a directory (defaults to root).\n");
86 }
87 
88 #define PRINT_HELP_AND_QUIT() \
89  do { \
90  ret = 1; \
91  print_help(oargv[0]); \
92  goto exit; \
93  } while (0)
94 
95 int is_command(const char* parg)
96 {
97 #if _WIN32
98  return (parg[0] == '/') || (parg[0] == '-');
99 #else
100  return (parg[0] == '-');
101 #endif
102 }
103 
104 #define NEED_PARAMS(_min_, _max_) \
105  do {\
106  if (nargs < _min_) { fprintf(stderr, "Error: Too few args for command %s.\n" , argv[-1]); PRINT_HELP_AND_QUIT(); } \
107  if (nargs > _max_) { fprintf(stderr, "Error: Too many args for command %s.\n", argv[-1]); PRINT_HELP_AND_QUIT(); } \
108  } while(0)
109 
110 int need_mount(void)
111 {
112  int r;
113 
114  if (isMounted)
115  return FR_OK;
116 
117  r = f_mount(&g_Filesystem, "0:", 0);
118  if (r)
119  return r;
120 
121  isMounted = 1;
122  return FR_OK;
123 }
124 
125 #define NEED_MOUNT() \
126  do { ret = need_mount(); if(ret) \
127  {\
128  fprintf(stderr, "Error: Could not mount disk (%d).\n", ret); \
129  goto exit; \
130  } } while(0)
131 
132 int main(int oargc, char* oargv[])
133 {
134  int ret;
135  int argc = oargc - 1;
136  char** argv = oargv + 1;
137 
138  // first parameter must be the image file.
139  if (argc == 0)
140  {
141  fprintf(stderr, "Error: First parameter must be a filename.\n");
143  }
144 
145  if (is_command(argv[0]))
146  {
147  fprintf(stderr, "Error: First parameter must be a filename, found '%s' instead.\n", argv[0]);
149  }
150 
151  if (disk_openimage(0, argv[0]))
152  {
153  fprintf(stderr, "Error: Could not open image file '%s'.\n", argv[0]);
154  ret = 1;
155  goto exit;
156  }
157 
158  argc--;
159  argv++;
160 
161  while (argc > 0)
162  {
163  char* parg = *argv;
164  int nargs = 0;
165  int i = 0;
166 
167  if (!is_command(parg))
168  {
169  fprintf(stderr, "Error: Expected a command, found '%s' instead.\n", parg);
171  }
172 
173  parg++;
174  argv++;
175  argc--;
176 
177  // find next command, to calculare number of args
178  while ((argv[i] != NULL) && !is_command(argv[i++]))
179  nargs++;
180 
181  if (strcmp(parg, "format") == 0)
182  {
183  // NOTE: The fs driver detects which FAT format fits best based on size
184  int sectors;
185 
186  NEED_PARAMS(1, 2);
187 
188  // Arg 1: number of sectors
189  sectors = atoi(argv[0]);
190 
191  if (sectors <= 0)
192  {
193  fprintf(stderr, "Error: Sectors must be > 0\n");
194  ret = 1;
195  goto exit;
196  }
197 
199  {
200  fprintf(stderr, "Error: Failed to set sector count to %d.\n", sectors);
201  ret = 1;
202  goto exit;
203  }
204 
205  NEED_MOUNT();
206 
207  ret = f_mkfs("0:", 1, sectors < 4096 ? 1 : 8);
208  if (ret)
209  {
210  fprintf(stderr, "Error: Formatting drive: %d.\n", ret);
211  goto exit;
212  }
213 
214  // Arg 2: custom header label (optional)
215  if (nargs > 1)
216  {
217 #define FAT_VOL_LABEL_LEN 11
218  char vol_label[2 + FAT_VOL_LABEL_LEN + 1]; // Null-terminated buffer
219  char* label = vol_label + 2; // The first two characters are reserved for the drive number "0:"
220  char ch;
221 
222  int i, invalid = 0;
223  int len = strlen(argv[1]);
224 
225  if (len <= FAT_VOL_LABEL_LEN)
226  {
227  // Verify each character (should be printable ASCII)
228  // and copy it in uppercase.
229  for (i = 0; i < len; i++)
230  {
231  ch = toupper(argv[1][i]);
232  if ((ch < 0x20) || !isprint(ch))
233  {
234  invalid = 1;
235  break;
236  }
237 
238  label[i] = ch;
239  }
240 
241  if (!invalid)
242  {
243  // Pad the label with spaces
244  while (len < FAT_VOL_LABEL_LEN)
245  {
246  label[len++] = ' ';
247  }
248  }
249  }
250  else
251  {
252  invalid = 1;
253  }
254 
255  if (invalid)
256  {
257  fprintf(stderr, "Error: Header label is limited to 11 printable uppercase ASCII symbols.");
258  ret = 1;
259  goto exit;
260  }
261 
262  if (disk_read(0, buff, 0, 1))
263  {
264  fprintf(stderr, "Error: Unable to read existing boot sector from image.");
265  ret = 1;
266  goto exit;
267  }
268 
270  {
272  }
273  else
274  {
276  }
277 
278  if (disk_write(0, buff, 0, 1))
279  {
280  fprintf(stderr, "Error: Unable to write new boot sector to image.");
281  ret = 1;
282  goto exit;
283  }
284 
285  // Set also the directory volume label
286  memcpy(vol_label, "0:", 2);
287  vol_label[2 + FAT_VOL_LABEL_LEN] = '\0';
288  if (f_setlabel(vol_label))
289  {
290  fprintf(stderr, "Error: Unable to set the volume label.");
291  ret = 1;
292  goto exit;
293  }
294  }
295  }
296  else if (strcmp(parg, "boot") == 0)
297  {
298  FILE* fe;
299  BYTE* temp = buff + 1024;
300 
301  NEED_PARAMS(1, 1);
302 
303  // Arg 1: boot file
304 
305  fe = fopen(argv[0], "rb");
306  if (!fe)
307  {
308  fprintf(stderr, "Error: Unable to open external file '%s' for reading.", argv[0]);
309  ret = 1;
310  goto exit;
311  }
312 
313  if (!fread(buff, 512, 1, fe))
314  {
315  fprintf(stderr, "Error: Unable to read boot sector from file '%s'.", argv[0]);
316  fclose(fe);
317  ret = 1;
318  goto exit;
319  }
320 
321  fclose(fe);
322 
323  NEED_MOUNT();
324 
325  if (disk_read(0, temp, 0, 1))
326  {
327  fprintf(stderr, "Error: Unable to read existing boot sector from image.");
328  ret = 1;
329  goto exit;
330  }
331 
333  {
334  printf("TODO: Writing boot sectors for FAT32 images not yet supported.");
335  ret = 1;
336  goto exit;
337  }
338  else
339  {
340 #define FAT16_HEADER_START 3
341 #define FAT16_HEADER_END 62
342 
344  }
345 
346  if (disk_write(0, buff, 0, 1))
347  {
348  fprintf(stderr, "Error: Unable to write new boot sector to image.");
349  ret = 1;
350  goto exit;
351  }
352  }
353  else if (strcmp(parg, "add") == 0)
354  {
355  FILE* fe;
356  FIL fv = { 0 };
357  UINT rdlen = 0;
358  UINT wrlen = 0;
359 
360  NEED_PARAMS(2, 2);
361 
362  NEED_MOUNT();
363 
364  // Arg 1: external file to add
365  // Arg 2: virtual filename
366 
367  fe = fopen(argv[0], "rb");
368  if (!fe)
369  {
370  fprintf(stderr, "Error: Unable to open external file '%s' for reading.", argv[0]);
371  ret = 1;
372  goto exit;
373  }
374 
375  if (f_open(&fv, argv[1], FA_WRITE | FA_CREATE_ALWAYS))
376  {
377  fprintf(stderr, "Error: Unable to open file '%s' for writing.", argv[1]);
378  fclose(fe);
379  ret = 1;
380  goto exit;
381  }
382 
383  while ((rdlen = fread(buff, 1, sizeof(buff), fe)) > 0)
384  {
385  if (f_write(&fv, buff, rdlen, &wrlen) || wrlen < rdlen)
386  {
387  fprintf(stderr, "Error: Unable to write '%d' bytes to disk.", wrlen);
388  ret = 1;
389  goto exit;
390  }
391  }
392 
393  fclose(fe);
394  f_close(&fv);
395  }
396  else if (strcmp(parg, "extract") == 0)
397  {
398  FIL fe = { 0 };
399  FILE* fv;
400  UINT rdlen = 0;
401  UINT wrlen = 0;
402 
403  NEED_PARAMS(2, 2);
404 
405  NEED_MOUNT();
406 
407  // Arg 1: virtual file to extract
408  // Arg 2: external filename
409 
410  if (f_open(&fe, argv[0], FA_READ))
411  {
412  fprintf(stderr, "Error: Unable to open file '%s' for reading.", argv[0]);
413  ret = 1;
414  goto exit;
415  }
416 
417  fv = fopen(argv[1], "wb");
418  if (!fv)
419  {
420  fprintf(stderr, "Error: Unable to open external file '%s' for writing.", argv[1]);
421  f_close(&fe);
422  ret = 1;
423  goto exit;
424  }
425 
426  while ((f_read(&fe, buff, sizeof(buff), &rdlen) == 0) && (rdlen > 0))
427  {
428  if (fwrite(buff, 1, rdlen, fv) < rdlen)
429  {
430  fprintf(stderr, "Error: Unable to write '%d' bytes to file.", rdlen);
431  ret = 1;
432  goto exit;
433  }
434  }
435 
436  f_close(&fe);
437  fclose(fv);
438  }
439  else if (strcmp(parg, "move") == 0)
440  {
441  NEED_PARAMS(2, 2);
442 
443  NEED_MOUNT();
444  // Arg 1: src path & filename
445  // Arg 2: new path & filename
446 
447  if (f_rename(argv[0], argv[1]))
448  {
449  fprintf(stderr, "Error: Unable to move/rename '%s' to '%s'", argv[0], argv[1]);
450  ret = 1;
451  goto exit;
452  }
453  }
454  else if (strcmp(parg, "copy") == 0)
455  {
456  FIL fe = { 0 };
457  FIL fv = { 0 };
458  UINT rdlen = 0;
459  UINT wrlen = 0;
460 
461  NEED_PARAMS(2, 2);
462 
463  NEED_MOUNT();
464  // Arg 1: src path & filename
465  // Arg 2: new path & filename
466 
467  if (f_open(&fe, argv[0], FA_READ))
468  {
469  fprintf(stderr, "Error: Unable to open file '%s' for reading.", argv[0]);
470  ret = 1;
471  goto exit;
472  }
473  if (f_open(&fv, argv[1], FA_WRITE | FA_CREATE_ALWAYS))
474  {
475  fprintf(stderr, "Error: Unable to open file '%s' for writing.", argv[1]);
476  f_close(&fe);
477  ret = 1;
478  goto exit;
479  }
480 
481  while ((f_read(&fe, buff, sizeof(buff), &rdlen) == 0) && (rdlen > 0))
482  {
483  if (f_write(&fv, buff, rdlen, &wrlen) || wrlen < rdlen)
484  {
485  fprintf(stderr, "Error: Unable to write '%d' bytes to disk.", wrlen);
486  ret = 1;
487  goto exit;
488  }
489  }
490 
491  f_close(&fe);
492  f_close(&fv);
493  }
494  else if (strcmp(parg, "mkdir") == 0)
495  {
496  NEED_PARAMS(1, 1);
497 
498  NEED_MOUNT();
499 
500  // Arg 1: folder path
501  if (f_mkdir(argv[0]))
502  {
503  fprintf(stderr, "Error: Unable to create directory.");
504  ret = 1;
505  goto exit;
506  }
507  }
508  else if (strcmp(parg, "delete") == 0)
509  {
510  NEED_PARAMS(1, 1);
511 
512  NEED_MOUNT();
513 
514  // Arg 1: file/folder path (cannot delete non-empty folders)
515  if (f_unlink(argv[0]))
516  {
517  fprintf(stderr, "Error: Unable to delete file or directory.");
518  ret = 1;
519  goto exit;
520  }
521  }
522  else if (strcmp(parg, "list") == 0)
523  {
524  char* root = "/";
525  DIR dir = { 0 };
526  FILINFO info = { 0 };
527  char lfname[257];
528 
529  NEED_PARAMS(0, 1);
530 
531  // Arg 1: folder path (optional)
532 
533  if (nargs == 1)
534  {
535  root = argv[0];
536  }
537 
538  if (f_opendir(&dir, root))
539  {
540  fprintf(stderr, "Error: Unable to opening directory '%s' for listing.\n", root);
541  ret = 1;
542  goto exit;
543  }
544 
545  printf("Listing directory contents of: %s\n", root);
546 
547  info.lfname = lfname;
548  info.lfsize = sizeof(lfname)-1;
549  while ((!f_readdir(&dir, &info)) && (strlen(info.fname) > 0))
550  {
551  if (strlen(info.lfname) > 0)
552  printf(" - %s (%s)\n", info.lfname, info.fname);
553  else
554  printf(" - %s\n", info.fname);
555  }
556  }
557  else
558  {
559  fprintf(stderr, "Error: Unknown or invalid command: %s\n", argv[-1]);
561  }
562  argv += nargs;
563  argc -= nargs;
564  }
565 
566  ret = 0;
567 
568 exit:
569 
570  disk_cleanup(0);
571 
572  return ret;
573 }
#define FAT_VOL_LABEL_LEN
static const WCHAR invalid[]
Definition: assoc.c:39
static int argc
Definition: ServiceArgs.c:12
FRESULT f_mkfs(const TCHAR *path, BYTE sfd, UINT au)
Definition: ff.c:4068
int main(int oargc, char *oargv[])
Definition: fatten.c:132
int tm_min
Definition: time.h:78
#define SET_SECTOR_COUNT
Definition: diskio.h:61
ACPI_SIZE strlen(const char *String)
Definition: utclib.c:269
GLdouble GLdouble GLdouble r
Definition: gl.h:2055
DSTATUS disk_openimage(BYTE pdrv, const char *imageFileName)
Definition: diskio.c:24
#define NEED_MOUNT()
Definition: fatten.c:125
WCHAR Second[]
Definition: FormatMessage.c:12
Definition: ff.h:168
FRESULT f_unlink(const TCHAR *path)
Definition: ff.c:3526
FRESULT f_close(FIL *fp)
Definition: ff.c:2857
int tm_mday
Definition: time.h:80
int is_command(const char *parg)
Definition: fatten.c:95
#define PRINT_HELP_AND_QUIT()
Definition: fatten.c:88
Definition: ff.h:78
int need_mount(void)
Definition: fatten.c:110
int tm_year
Definition: time.h:82
__u16 time
Definition: mkdosfs.c:366
_Check_return_opt_ _CRTIMP size_t __cdecl fwrite(_In_reads_bytes_(_Size *_Count) const void *_Str, _In_ size_t _Size, _In_ size_t _Count, _Inout_ FILE *_File)
#define argv
Definition: mplay32.c:18
#define FA_WRITE
Definition: ff.h:298
#define FA_READ
Definition: ff.h:294
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
_Check_return_opt_ _CRTIMP size_t __cdecl fread(_Out_writes_bytes_(_ElementSize *_Count) void *_DstBuf, _In_ size_t _ElementSize, _In_ size_t _Count, _Inout_ FILE *_File)
_Check_return_opt_ _CRTIMP int __cdecl fprintf(_Inout_ FILE *_File, _In_z_ _Printf_format_string_ const char *_Format,...)
static NTSTATUS disk_write(RDPCLIENT *This, NTHANDLE handle, uint8 *data, uint32 length, uint32 offset, uint32 *result)
Definition: disk.c:585
#define FA_CREATE_ALWAYS
Definition: ff.h:300
BYTE fs_type
Definition: ff.h:79
Definition: dirent.h:39
smooth NULL
Definition: ftsmooth.c:416
int tm_mon
Definition: time.h:81
unsigned int dir
Definition: maze.c:112
static int isMounted
Definition: fatten.c:16
FRESULT f_readdir(DIR *dp, FILINFO *fno)
Definition: ff.c:3275
FRESULT f_read(FIL *fp, void *buff, UINT btr, UINT *br)
Definition: ff.c:2586
DRESULT disk_ioctl(BYTE pdrv, BYTE cmd, void *buff)
Definition: diskio.c:169
int toupper(int c)
Definition: utclib.c:881
#define FAT16_HEADER_START
unsigned long DWORD
Definition: ntddk_ex.h:95
VOID disk_cleanup(BYTE pdrv)
Definition: diskio.c:48
int ret
FRESULT f_mount(FATFS *fs, const TCHAR *path, BYTE opt)
Definition: ff.c:2402
#define FS_FAT32
Definition: ff.h:311
#define memcpy(s1, s2, n)
Definition: mkisofs.h:878
GLenum GLsizei len
Definition: glext.h:6722
unsigned char BYTE
Definition: mem.h:68
_Check_return_opt_ _CRTIMP int __cdecl fclose(_Inout_ FILE *_File)
_Check_return_ _CRTIMP FILE *__cdecl fopen(_In_z_ const char *_Filename, _In_z_ const char *_Mode)
Definition: time.h:76
_CRTIMP struct tm *__cdecl localtime(const time_t *_Time)
Definition: time.h:426
uint8_t label[11]
Definition: fsck.fat.h:65
FRESULT f_opendir(DIR *dp, const TCHAR *path)
Definition: ff.c:3187
DWORD get_fattime(void)
Definition: fatten.c:20
_In_ PLARGE_INTEGER _In_ BOOLEAN _Out_ PFAT_TIME_STAMP FatTime
Definition: fatprocs.h:1905
__kernel_time_t time_t
Definition: linux.h:252
static calc_node_t temp
Definition: rpn_ieee.c:38
FRESULT f_setlabel(const TCHAR *label)
Definition: ff.c:3906
#define NEED_PARAMS(_min_, _max_)
Definition: fatten.c:104
Definition: ff.h:114
FRESULT f_mkdir(const TCHAR *path)
Definition: ff.c:3595
unsigned int UINT
Definition: ndis.h:50
__u8 sectors[2]
Definition: mkdosfs.c:366
int tm_sec
Definition: time.h:77
#define isprint(c)
Definition: acclib.h:73
_Check_return_ int __cdecl atoi(_In_z_ const char *_Str)
Definition: name.c:36
#define FAT16_HEADER_END
Definition: ff.h:185
int tm_hour
Definition: time.h:79
FILE * stderr
int strcmp(const char *String1, const char *String2)
Definition: utclib.c:469
void print_help(const char *name)
Definition: fatten.c:57
static BOOLEAN disk_read(u64 physical, void *dest, u32 count)
Definition: btrfs.c:254
static FATFS g_Filesystem
Definition: fatten.c:15
void exit(int exitcode)
Definition: _exit.c:33
FRESULT f_rename(const TCHAR *path_old, const TCHAR *path_new)
Definition: ff.c:3713
FRESULT f_write(FIL *fp, const void *buff, UINT btw, UINT *bw)
Definition: ff.c:2687
static unsigned char buff[32768]
Definition: fatten.c:17
#define printf
Definition: config.h:203
FRESULT f_open(FIL *fp, const TCHAR *path, BYTE mode)
Definition: ff.c:2449