+FSCTL_DISMOUNT_VOLUME define
[reactos.git] / tools / mkflpimg.c
1 #include <ctype.h>
2 #include <stdio.h>
3 #include <stdlib.h>
4 #include <string.h>
5 #include <time.h>
6
7 #define N_CYLINDERS         80
8 #define ROOT_ENTRY_SIZE     32
9
10 #define SECTOR_SIZE         512
11 #define SECTORS_PER_CLUSTER 1
12 #define N_RESERVED          1
13 #define N_FATS              2
14 #define N_ROOT_ENTRIES      224
15 #define SECTORS_PER_DISK    (N_HEADS * N_CYLINDERS * SECTORS_PER_TRACK)
16 #define MEDIA_TYPE          0xf0
17 #define SECTORS_PER_FAT     9
18 #define SECTORS_PER_TRACK   18
19 #define N_HEADS             2
20 #define SIGNATURE           0x29        /* only MS? */
21 #define END_SIGNATURE       0xaa55
22
23
24 #define ATTR_READONLY 0x01
25 #define ATTR_HIDDEN   0x02
26 #define ATTR_SYSTEM   0x04
27 #define ATTR_VOLUME   0x08
28 #define ATTR_SUBDIR   0x10
29 #define ATTR_ARCHIVE  0x20
30 #define ATTR_RES1     0x40
31 #define ATTR_RES2     0x80
32
33
34 typedef unsigned char disk_sector_t[SECTOR_SIZE];
35
36 typedef struct boot_sector
37 {
38   unsigned short jmp;
39   unsigned char  nop;
40   char           oem[8];
41   unsigned short bytes_per_sector;
42   unsigned char  sectors_per_cluster;
43   unsigned short reserved_sectors;
44   unsigned char  n_fats;
45   unsigned short n_root_entries;
46   unsigned short n_sectors;
47   unsigned char  media_type;
48   unsigned short sectors_per_fat;
49   unsigned short sectors_per_track;
50   unsigned short n_heads;
51   unsigned long  hidden_sectors;
52   unsigned long  huge_sectors;
53   unsigned char  drive;
54   unsigned char  reserved;
55   unsigned char  signature;
56   unsigned long  volume_id;
57   char           volume_label[11];
58   char           file_system[8];
59   unsigned char  boot_code[SECTOR_SIZE - 62 - 2];
60   unsigned short end_signature;
61 } __attribute__ ((packed)) boot_sector_t;
62
63
64 typedef struct root_entry
65 {
66   char           name[8];
67   char           extension[3];
68   unsigned char  attribute;
69   unsigned char  reserved[10];
70   unsigned short time;
71   unsigned short date;
72   unsigned short cluster;
73   unsigned long  size;
74 } __attribute ((packed)) root_entry_t;
75
76
77 disk_sector_t *new_image(char *bsfname)
78 {
79   FILE *bsf;
80   disk_sector_t *img;
81   boot_sector_t boot_sec;
82   root_entry_t *root;
83
84   if ((bsf = fopen(bsfname, "rb")) == NULL)
85   {
86     printf("Boot sector image file %s not found!\n", bsfname);
87     return NULL;
88   }
89   if (fread(&boot_sec, 1, SECTOR_SIZE, bsf) != SECTOR_SIZE)
90   {
91     printf("Unable to read boot sector image file %s!\n", bsfname);
92     fclose(bsf);
93     return NULL;
94   }
95   fclose(bsf);
96
97   if ( (boot_sec.bytes_per_sector != SECTOR_SIZE) ||
98        (boot_sec.sectors_per_cluster != SECTORS_PER_CLUSTER) ||
99        (boot_sec.reserved_sectors != N_RESERVED) ||
100        (boot_sec.n_fats != N_FATS) ||
101        (boot_sec.n_root_entries != N_ROOT_ENTRIES) ||
102        (boot_sec.n_sectors != SECTORS_PER_DISK) ||
103        (boot_sec.media_type != MEDIA_TYPE) ||
104        (boot_sec.sectors_per_fat != SECTORS_PER_FAT) ||
105        (boot_sec.sectors_per_track != SECTORS_PER_TRACK) ||
106        (boot_sec.n_heads != N_HEADS) ||
107 //       (boot_sec.signature != SIGNATURE) ||
108        (boot_sec.end_signature != END_SIGNATURE) )
109   {
110     printf("Invalid boot sector in file %s\n", bsfname);
111     return NULL;
112   }
113
114   if ((img = (disk_sector_t *)malloc(SECTOR_SIZE * SECTORS_PER_DISK)) == NULL)
115   {
116     printf("Not enough memory!\n");
117     return NULL;
118   }
119
120   memset(img, 0, SECTOR_SIZE * SECTORS_PER_TRACK);
121   memcpy(img, &boot_sec, SECTOR_SIZE);
122
123   root = (root_entry_t *)img[N_RESERVED + N_FATS * SECTORS_PER_FAT];
124   strncpy(root->name, "REACTOS       ", 11);
125   root->attribute = ATTR_VOLUME;
126   
127   return img;
128 }
129
130
131 void create_root_entry(root_entry_t *root, char *fname,
132                        unsigned short cluster, unsigned long size)
133 {
134   int i, j;
135   time_t t;
136   struct tm *localt;
137
138   i = 0;
139   j = 0;
140   while ((fname[j] != '\0') && (fname[j] != '.') && (i < 8))
141   {
142     root->name[i] = toupper(fname[j]);
143     i++;
144     j++;
145   }
146   while (i < 8)
147   {
148     root->name[i] = ' ';
149     i++;
150   }
151   if (fname[j] == '.')
152   {
153     i = 0;
154     j++;
155     while ((fname[j] != '\0') && (i < 3))
156     {
157       root->extension[i] = toupper(fname[j]);
158       i++;
159       j++;
160     }
161     while (i < 3)
162     {
163       root->extension[i] = ' ';
164       i++;
165     }
166   }
167   else
168   {
169     i = 0;
170     while (i < 3)
171     {
172       root->extension[i] = ' ';
173       i++;
174     }
175   }
176
177   root->attribute = ATTR_ARCHIVE;
178   t = time(0);
179   localt = localtime(&t);
180   root->time = (((localt->tm_hour & 0x001f) << 11) |
181                 ((localt->tm_min & 0x003f) << 5) |
182                 ((localt->tm_sec / 2) & 0x001f));
183   root->date = ((((localt->tm_year - 80) & 0x007f) << 9) |
184                 (((localt->tm_mon + 1) & 0x000f) << 5) |
185                  (localt->tm_mday & 0x001f));
186   root->cluster = cluster;
187   root->size = size;
188 }
189
190
191 void update_fat(unsigned char *fat, int cl_start, int cl_end)
192 {
193   int i, k;
194   unsigned short *cl;
195
196   for (i = cl_start; i < cl_end - 1; i++)
197   {
198     k = (i - 2) * 3 / 2;
199     cl = ((unsigned short *)&fat[k]);
200     if (i & 1)
201     {
202       *cl = (*cl & 0x000f) | (((i + 1) & 0x0fff) << 4);
203     }
204     else
205     {
206       *cl = (*cl & 0xf000) | ((i + 1) & 0x0fff);
207     }
208   }
209   k = (i - 2) * 3 / 2;
210   cl = ((unsigned short *)&fat[k]);
211   if (i & 1)
212   {
213     *cl = (*cl & 0x000f) | 0xfff0;
214   }
215   else
216   {
217     *cl = (*cl & 0xf000) | 0x0fff;
218   }
219 }
220
221
222 int copy_files(disk_sector_t *img, char *filenames[], int n_files)
223 {
224   int i, k;
225   FILE *f;
226   int cl_start, cl_end;
227   unsigned char *fat1, *fat2;
228   root_entry_t *root;
229   unsigned long n, size;
230
231   fat1 = (unsigned char *)img[N_RESERVED];
232   fat2 = (unsigned char *)img[N_RESERVED + SECTORS_PER_FAT];
233   root = (root_entry_t *)img[N_RESERVED + N_FATS * SECTORS_PER_FAT];
234
235   k = N_RESERVED +
236       N_FATS * SECTORS_PER_FAT +
237       N_ROOT_ENTRIES * ROOT_ENTRY_SIZE / SECTOR_SIZE;
238
239   cl_end = 1;
240
241   if (n_files > N_ROOT_ENTRIES)
242   {
243     n_files = N_ROOT_ENTRIES;
244   }
245
246   for (i = 0; i < n_files; i++)
247   {
248     cl_start = cl_end + 1;
249     if ((f = fopen(filenames[i], "rb")) == NULL)
250     {
251       printf("Error opening file %s!", filenames[i]);
252       return 1;
253     }
254
255     printf("  %s\n", filenames[i]);
256     
257     size = 0;
258     while ((n = fread(img[k], 1, SECTOR_SIZE, f)) > 0)
259     {
260       size += n;
261       cl_end++;
262       k++;
263     }
264     fclose(f);
265
266     root++;
267     create_root_entry(root, filenames[i], cl_start, size);
268
269     update_fat(fat1, cl_start, cl_end);
270   }
271   memcpy(fat2, fat1, SECTORS_PER_FAT * SECTOR_SIZE);
272
273   return 0;
274 }
275
276
277 int write_image(disk_sector_t *img, char *imgname)
278 {
279   FILE *f;
280
281   if ((f = fopen(imgname, "rb")) != NULL)
282   {
283     printf("Image file %s already exists!\n", imgname);
284     fclose(f);
285     free(img);
286     return 1;
287   }
288
289   f = fopen(imgname, "wb");
290   if (fwrite(img, SECTOR_SIZE, SECTORS_PER_DISK, f) != SECTORS_PER_DISK)
291   {
292     printf("Unable to write image file %s\n!", imgname);
293     fclose(f);
294     free(img);
295     return 1;
296   }
297   fclose(f);
298
299   free(img);
300   return 0;
301 }
302
303
304 int main(int argc, char *argv[])
305 {
306   disk_sector_t *img;
307   char *imgname;
308   char *bsfname;
309   char **filenames;
310   int n_files;
311
312   if (argc < 4)
313   {
314     printf("Usage: mkflpimg <image> <boot sector> <source files>\n");
315     return 1;
316   }
317
318   imgname = argv[1];
319   bsfname = argv[2];
320   filenames = &argv[3];
321   n_files = argc - 3;
322
323   printf("Creating image ...\n");
324   if ((img = new_image(bsfname)) == NULL)
325   {
326     return 1;
327   }
328
329   printf("Copying files ...\n");
330
331   if (copy_files(img, filenames, n_files))
332   {
333     return 1;
334   }
335
336   printf("Writing image file ...\n");
337
338   if (write_image(img, imgname))
339   {
340     return 1;
341   }
342   
343   printf("Finished.\n");
344
345   return 0;
346 }
347