-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathmksfs.c
394 lines (356 loc) · 14.8 KB
/
mksfs.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
/* Author: Benjamin David Lunt
* Forever Young Software
* Copyright (c) 1984-2017
*
* This code is included on the disc that is included with the book
* FYSOS: The Virtual File System, and is for that purpose only. You have
* the right to use it for learning purposes only. You may not modify it
* for redistribution for any other purpose unless you have written
* permission from the author.
*
* You may modify and use it in your own projects as long as they are
* for non profit only and not distributed. Any project for profit that
* uses this code must have written permission from the author.
*
* Last update: 19 Sept 2017
*
* usage:
* mksfs filename.txt [/V:a_label_goes_here]
*
* See the included files.txt file for an example of the resource file
*
* This utility will take a list of filenames and include those
* files in the image, creating root entries.
*
* Assumptions:
*
* - this utility assumes that the count of files you add to this image
* will fit within the amount of space you have for the Data Block Area
* and is hard coded for no more than 1024 files.
*
* - Remember, I didn't write this utility to be complete or robust.
* I wrote it to simply make a SFS image for use with this book.
* Please consider this if you add or modify to this utility.
*
* Thank you for your purchase and interest in my work.
*
* compile using gcc
* gcc -Os mksfs.c -o mksfs.exe -s
*/
#include <ctype.h>
#include <conio.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "ctype.h"
#include "misc.h"
#include "mksfs.h"
// we only support block sizes of 512. I didn't look to see if
// we can change this yet and still have the code work correctly.
#define SFS_BLOCK_SIZE 512
int main(int argc, char *argv[]) {
bit32u i;
int name_len, cnt;
size_t read;
bit32u reserved_blocks;
FILE *src, *targ;
struct S_RESOURCE *resources;
char filename[NAME_LEN_MAX];
char label[NAME_LEN_MAX] = "This is a volume label for this SFS volume.";
char *s, *t;
bit8u buffer[SFS_BLOCK_SIZE];
// print start string
printf(strtstr);
// we need to parse the command line and get the parameters found
parse_command(argc, argv, filename, label);
// now retrieve the resource file's contents
resources = parse_resource(filename);
if (!resources) {
printf("\n Error with Resource file. '%s'", filename);
if (resources) free(resources);
return -1;
}
// do we need to add sectors to end on a cylinder boundary?
bit32u cylinders = (bit32u) (resources->tot_sectors + ((16*63)-1)) / (16*63); // cylinders used
bit32u add = (bit32u) (((bit64u) cylinders * (16*63)) - resources->tot_sectors); // sectors to add to boundary on cylinder
if (add && (resources->tot_sectors > 2880)) { // don't add if floppy image
printf("\n Total Sectors does not end on cylinder boundary. Expand to %i? [Y|N] ", resources->tot_sectors + add);
if (toupper(getche()) == 'Y') {
resources->tot_sectors += add;
// need to calculate again since we added sectors
cylinders = (bit32u) ((resources->tot_sectors + ((16*63)-1)) / (16*63));
}
}
// create super block
struct S_SFS_SUPER super;
memset(&super, 0, sizeof(struct S_SFS_SUPER));
super.time_stamp = get_64kseconds();
//super.data_block_count; // Size of data area in blocks (updated later)
//super.index_size; // Size of index area *in bytes* (updated later)
super.magic_version = 0x1A534653; // Magic number (0x534653) + SFS version (0x10 for Version 1.0, 0x1A for v1.10)
super.total_blocks = resources->tot_sectors - resources->base_lba; // Total number of blocks in volume
//super.resv_blocks = 1; // Number of reserved blocks (updated later)
super.block_size = SFS_BLOCK_SIZE >> 8; // Block size (2^(x+7) where x = 2 = 512)
// create target file
if ((targ = fopen(resources->targ_filename, "w+b")) == NULL) {
printf("\nError creating target file: '%s'", resources->targ_filename);
return -1;
}
// create the MBR and padding sectors, if mbr file given
i = 0;
if (strlen(resources->mbr_filename)) {
if ((src = fopen(resources->mbr_filename, "rb")) == NULL) {
printf(" Error opening mbr.bin file.\n");
fclose(targ);
return -2;
}
fread(buffer, SFS_BLOCK_SIZE, 1, src);
// create and write the Disk Indentifier
// We call rand() multiple times.
* (bit32u *) &buffer[0x01B8] = (bit32u) ((rand() << 20) | (rand() << 10) | (rand() << 0));
* (bit16u *) &buffer[0x01BC] = 0x0000;
// create a single partition entry pointing to our partition
struct PART_TBLE *pt = (struct PART_TBLE *) &buffer[0x01BE];
pt->bi = 0x80;
lba_to_chs(&pt->start_chs, (bit32u) resources->base_lba);
pt->si = 0x53; //'S'
lba_to_chs(&pt->end_chs, (bit32u) ((cylinders * resources->heads * resources->spt) - 1 - resources->base_lba)); // last sector - 1 for the MBR
pt->startlba = (bit32u) resources->base_lba;
pt->size = (bit32u) ((cylinders * resources->heads * resources->spt) - resources->base_lba);
printf(" Writing MBR to LBA %" LL64BIT "i\n", (bit64u) (FTELL(targ) / SFS_BLOCK_SIZE));
fwrite(buffer, SFS_BLOCK_SIZE, 1, targ);
memset(buffer, 0, SFS_BLOCK_SIZE);
i = 1;
}
if (i<(bit32u) resources->base_lba)
printf(" Writing Padding between MBR and Base LBA...\n");
for (; i<(bit32u) resources->base_lba; i++)
fwrite(buffer, SFS_BLOCK_SIZE, 1, targ);
resources->tot_sectors -= resources->base_lba;
// write boot sector
reserved_blocks = 1;
if (strlen(resources->boot_filename)) {
if ((src = fopen(resources->boot_filename, "rb")) == NULL) {
printf("\nError opening boot file.");
fclose(targ);
return -2;
}
fread(buffer, SFS_BLOCK_SIZE, 1, src);
// update the sig and base lba within the given boot code
// this assumes that the coder of the boot code knew that this area was
// reserved for this data...
// this reserved area is the last few bytes of the first sector of the partition/disk
// sig dword (unique id for partition/disk)
// base_lba qword (0 for floppy, could be 63 for partitions)
// boot sig word (0xAA55)
* (bit32u *) &buffer[498] = ((rand() & 0xFFFF) << 16) | (rand() & 0xFFFF);
* (bit64u *) &buffer[502] = (bit64u) resources->base_lba;
* (bit16u *) &buffer[0x01FE] = 0xAA55;
printf("\n Writing boot code to LBA %" LL64BIT "i", (bit64u) (FTELL(targ) / SFS_BLOCK_SIZE));
fwrite(buffer, SFS_BLOCK_SIZE, 1, targ);
memset(buffer, 0, SFS_BLOCK_SIZE);
// are there any more sectors of the boot code?
while (fread(buffer, SFS_BLOCK_SIZE, 1, src)) {
fwrite(buffer, SFS_BLOCK_SIZE, 1, targ);
reserved_blocks++;
}
} else {
// write a dummy boot sector
memset(buffer, 0, SFS_BLOCK_SIZE);
* (bit16u *) &buffer[0x01FE] = 0xAA55;
fwrite(buffer, SFS_BLOCK_SIZE, 1, targ);
}
resources->tot_sectors -= reserved_blocks;
// allocate the Index Data Area buffer
// TODO: we currently assume less than 1024 files
int ida_count = 0;
void *ida = calloc(1024 * SFS_ENTRY_SIZE, 1);
// create the Start Marker Entry
struct S_SFS_START *start = (struct S_SFS_START *) ((bit8u *) ida + (ida_count * SFS_ENTRY_SIZE));
start->type = SFS_ENTRY_START;
start->crc = calc_crc(start, SFS_ENTRY_SIZE);
ida_count++;
/* Since we have an empty disk, we know that we can start with the
* first cluster and write files consecutively. Therefore, we will
* start with the first block after the boot.
*/
bit64u file_size, data_used = 0;
for (i=0; i<resources->file_cnt; i++) {
// if we are a directory only, just create the entry for it.
// we don't put anything in the data block area
if (resources->files[i].param == 1) {
// create the entry(s)
struct S_SFS_DIR *dir = (struct S_SFS_DIR *) ((bit8u *) ida + (ida_count * SFS_ENTRY_SIZE));
dir->type = SFS_ENTRY_DIR;
dir->num_cont = 0;
dir->time_stamp = get_64kseconds();
s = resources->files[i].filename;
name_len = strlen(s) + 1; // include the NULL
cnt = (name_len < DIR_NAME_LEN) ? name_len : DIR_NAME_LEN;
memcpy(dir->name, s, cnt);
name_len -= cnt;
s += cnt;
ida_count++;
while (name_len > 0) {
dir->num_cont++;
t = (char *) ((bit8u *) dir + (dir->num_cont * SFS_ENTRY_SIZE));
cnt = (name_len < SFS_ENTRY_SIZE) ? name_len : SFS_ENTRY_SIZE;
memcpy(t, s, cnt);
name_len -= cnt;
ida_count++;
}
dir->crc = 0;
dir->crc = calc_crc(dir, (1 + dir->num_cont) * SFS_ENTRY_SIZE);
if (strlen(resources->files[i].filename) < 32)
printf("\n Adding \"/%s\"", resources->files[i].filename);
else {
char temp[33];
strncpy(temp, resources->files[i].filename, 32);
temp[32] = '\0';
printf("\n Adding \"/%s\"...", temp);
}
} else {
// get the file to write to the image
if ((src = fopen(resources->files[i].path_filename, "rb")) == NULL) {
printf("\nError opening %s file.", resources->files[i].path_filename);
continue;
}
FSEEK(src, 0, SEEK_END);
file_size = FTELL(src);
rewind(src);
// create the entry(s)
struct S_SFS_FILE *file = (struct S_SFS_FILE *) ((bit8u *) ida + (ida_count * SFS_ENTRY_SIZE));
file->type = SFS_ENTRY_FILE;
file->num_cont = 0;
file->time_stamp = get_64kseconds();
file->start_block = reserved_blocks + data_used; // files are zero based from start of volume
file->end_block = (file->start_block + ((file_size + (SFS_BLOCK_SIZE - 1)) & ~(SFS_BLOCK_SIZE - 1)) / SFS_BLOCK_SIZE) - 1;
file->file_len = file_size;
s = resources->files[i].filename;
name_len = strlen(s) + 1; // include the NULL
cnt = (name_len < FILE_NAME_LEN) ? name_len : FILE_NAME_LEN;
memcpy(file->name, s, cnt);
name_len -= cnt;
s += cnt;
ida_count++;
while (name_len > 0) {
file->num_cont++;
t = (char *) ((bit8u *) file + (file->num_cont * SFS_ENTRY_SIZE));
cnt = (name_len < SFS_ENTRY_SIZE) ? name_len : SFS_ENTRY_SIZE;
memcpy(t, s, cnt);
name_len -= cnt;
ida_count++;
}
file->crc = 0;
file->crc = calc_crc(file, (1 + file->num_cont) * SFS_ENTRY_SIZE);
if (strlen(resources->files[i].filename) < 32)
printf("\n Writing \"%s\" to LBA %" LL64BIT "i", resources->files[i].filename, (bit64u) (FTELL(targ) / SFS_BLOCK_SIZE));
else {
char temp[33];
strncpy(temp, resources->files[i].filename, 32);
temp[32] = '\0';
printf("\n Writing \"%s\"... to LBA %" LL64BIT "i", temp, (bit64u) (FTELL(targ) / SFS_BLOCK_SIZE));
}
do {
// by clearing the buffer first, we make sure that the "padding" bytes are all zeros
memset(buffer, 0, SFS_BLOCK_SIZE);
read = fread(buffer, 1, SFS_BLOCK_SIZE, src);
if (read == 0)
break;
fwrite(buffer, SFS_BLOCK_SIZE, 1, targ);
resources->tot_sectors--;
data_used++;
} while (read == SFS_BLOCK_SIZE);
fclose(src);
}
// sanity check
if (ida_count >= 1023) {
printf("We went over...\n");
break;
}
}
// write remaining sectors (as zeros) (Free Space)
// we still write to end of media and then back track since the
// Index Data Area may not start on a block boundary
int ida_size = ((ida_count * SFS_ENTRY_SIZE) + (SFS_BLOCK_SIZE - 1)) / SFS_BLOCK_SIZE; // size of IDA in blocks
printf("\n Writing free space at LBA %" LL64BIT "i (%" LL64BIT "i blocks)", (bit64u) (FTELL(targ) / SFS_BLOCK_SIZE), resources->tot_sectors - ida_size);
memset(buffer, 0, SFS_BLOCK_SIZE);
while (resources->tot_sectors) {
fwrite(buffer, SFS_BLOCK_SIZE, 1, targ);
if ((resources->tot_sectors % 2500) == 0)
putch('.');
resources->tot_sectors--;
}
// create the Volume ID entry
struct S_SFS_VOL_ID *id = (struct S_SFS_VOL_ID *) ((bit8u *) ida + (ida_count * SFS_ENTRY_SIZE));
id->type = SFS_ENTRY_VOL_ID;
id->time_stamp = get_64kseconds();
name_len = strlen(label) + 1; // include the NULL
cnt = (name_len < VOLID_NAME_LEN) ? name_len : VOLID_NAME_LEN;
memcpy(id->name, label, cnt);
id->crc = calc_crc(id, 1 * SFS_ENTRY_SIZE);
ida_count++;
// now back up and write the index data area buffer
FSEEK(targ, -(ida_count * SFS_ENTRY_SIZE), SEEK_CUR);
fwrite(ida, ida_count * SFS_ENTRY_SIZE, 1, targ);
// now we need to go back and write the super
FSEEK(targ, resources->base_lba * SFS_BLOCK_SIZE, SEEK_SET);
printf("\n Updating Super block...");
fread(buffer, SFS_BLOCK_SIZE, 1, targ);
super.data_block_count = data_used;
super.index_size = ida_count * SFS_ENTRY_SIZE;
super.resv_blocks = reserved_blocks;
super.crc = calc_crc(&super.magic_version, 17); // zero byte check sum of super block
memcpy(&buffer[0x18E], &super, sizeof(struct S_SFS_SUPER));
FSEEK(targ, resources->base_lba * SFS_BLOCK_SIZE, SEEK_SET);
fwrite(buffer, SFS_BLOCK_SIZE, 1, targ);
// close the file
fclose(targ);
// free the index and resources buffer
free(ida);
free(resources);
// return good
return 0;
}
/* Parse command line. We are looking for the following items
* filename - This is the path/filename of the resource file to open
* /V - Volume Name
*/
void parse_command(int argc, char *argv[], char *filename, char *label) {
int i;
const char *s;
strcpy(filename, "");
for (i=1; i<argc; i++) {
s = argv[i];
if (*s == '/') {
s++;
if ((memcmp(s, "v:", 2) == 0) ||
(memcmp(s, "V:", 2) == 0)) {
strncpy(label, s + 2, NAME_LEN_MAX - 1);
label[NAME_LEN_MAX-1] = 0; // make sure null terminated
} else
printf("\n Unknown switch parameter: /%s", s);
} else
strcpy(filename, s);
}
}
// time(NULL) returns seconds since 1 Jan 1970
// days from 1 Jan 1970 to 1 Jan 1980 = (365 * 10) + 2
// seconds per day = (60 * 60 * 24)
bit64s get_64kseconds() {
#ifdef _MSC_VER
return (bit64s) time(NULL) * (bit64s) 65536;
#elif defined DJGPP
// DJGPP doesn't have an epoc of 1 Jan 1970 ??????
return (((bit64s) time(NULL) - (bit64s) (((365 * 10) + 2) * (60 * 60 * 24))) * (bit64s) 65536);
#else
# error "need a good time conversion routine"
#endif
}
bit8u calc_crc(void *ptr, int cnt) {
bit8u crc = 0, *p = (bit8u *) ptr;
while (cnt--)
crc += *p++;
return -crc;
}