· 8 years ago · Apr 24, 2018, 09:16 AM
1*/
2
3/* file descriptor used for open files */
4struct file_descriptor {
5 __u32 clusterpos; /* number of bytes from start of cluster */
6 __u32 position; /* number of bytes from start of file */
7 __u16 cluster; /* points to an entry in the fat */
8 struct dos_dir_entry *dde; /* corresponding dde */
9} __attribute__((packed));
10
11struct file_descriptor fd_table[MAX_FILES];
12
13/**
14 * begin of public functions
15 */
16
17/* can be used for your initialization code */
18void fs_init()
19{
20 char *bootSector;
21 bootSector = malloc ( SECTOR_SIZE );
22 if (!bootSector) {
23 die("ERROR: Out of memory!\n");
24 }
25
26 bios_read(0, bootSector);
27 memcpy(&fbs, bootSector, sizeof(fbs));
28
29#ifdef DEBUG
30 bootsector_debug();
31#endif
32
33 if (fbs.sectors / fbs.sec_per_clus > MAX_CLUSTERS) {
34 die("ERROR: Disk Image is not FAT12 compatible!\n");
35 }
36
37 /* get FATs */
38 __u16 i;
39 if (fbs.fats == 2) { /* 2 FATs (normal case) */
40 FAT1 = malloc(SECTOR_SIZE * fbs.fat_length);
41 FAT2 = malloc(SECTOR_SIZE * fbs.fat_length);
42
43 for(i=0; i<fbs.fat_length; i++) {
44 bios_read(fbs.reserved + i, (char *) FAT1 + SECTOR_SIZE*i);
45 bios_read(fbs.reserved + fbs.fat_length + i, (char *) FAT2 + SECTOR_SIZE*i);
46 }
47 } else { /* only 1 FAT */
48 FAT1 = malloc(SECTOR_SIZE * fbs.fat_length);
49 FAT2 = NULL;
50
51 for(i=0; i<fbs.fat_length; i++) {
52 bios_read(fbs.reserved + i, (char *) FAT1 + SECTOR_SIZE*i);
53 }
54 }
55
56 /* initialize file_table */
57 memset(file_table, 0, MAX_FILES*sizeof(int));
58}
59
60/* opens a file */
61int fs_open(const char *p)
62{
63 char filename[NAME_SIZE+EXT_SIZE+1];
64 struct dos_dir_entry *dde = NULL;
65 int index;
66
67 /* check if a new file can be opened */
68 if (insert_into_filetable(NULL) == -1) {
69 die("ERROR: No more files can be opened!\n");
70 }
71
72 /* parse the path */
73 dde = parse_path(p, filename);
74
75 /* now we are in correct dir, thus find file */
76 dde = search_dir(dde, filename);
77
78 /* catch error if no file was found */
79 if (!dde || !(IS_FILE((*dde)))) {
80 die("ERROR: No entry found!\n");
81 }
82
83 /* add file to file_table */
84 index = insert_into_filetable(dde);
85
86#ifdef DEBUG
87 printf("File has been opened. (index = %d)\n", index);
88 print_fat();
89#endif
90 return index;
91}
92
93/* closes a file */
94void fs_close(int fd)
95{
96 if (fd < 0 || fd > MAX_FILES) {
97 die("ERROR: no valid file descriptor!\n");
98 }
99 file_table[fd] = 0;
100}
101
102/* reads from a file len bytes into the buffer */
103int fs_read(int fd, void *buffer, int len)
104{
105 char tmpBuf[SECTOR_SIZE*fbs.sec_per_clus + 1];
106 __u16 nextCluster = 0;
107 struct file_descriptor *fds = NULL;
108 int remainingLen = len;
109 void *bufferPos = buffer;
110 __u32 size = 0, position = 0, clusterpos = 0, bytesRead = 0, toread = 0, sectoroffset = 0;
111
112#ifdef DEBUG
113 printf("\n**** READING STARTED\n");
114#endif
115
116 if (fd < 0 || fd > MAX_FILES || file_table[fd] == 0) {
117 die("ERROR: No valid file descriptor\n");
118 }
119
120 fds = (struct file_descriptor *) file_table[fd];
121 size = fds->dde->size;
122 position = fds->position;
123 clusterpos = fds->clusterpos;
124 nextCluster = (__u16) fds->cluster;
125
126 do {
127 // loop through the sectors
128#ifdef DEBUG
129 printf("From Cluster: %i\n", nextCluster);
130#endif
131 int j;
132 for (j = 0; j < fbs.sec_per_clus && (size-position) > 0 && remainingLen > 0; j++) {
133
134 // Skipping the untwanted sectors..
135
136 if (j < (int) fds->clusterpos / SECTOR_SIZE) {
137 continue;
138 }
139
140#ifdef DEBUG
141 printf("Reading Sector: %i\n", GET_SECTOR(nextCluster)+j);
142 printf("Remaining: %i\n", remainingLen);
143 printf("Position: %i\n", position);
144 printf("In Clster: %i\n", clusterpos);
145#endif
146
147 // we are in the right sector now
148 bios_read(GET_SECTOR(nextCluster)+j, tmpBuf);
149 // where to start
150 sectoroffset = clusterpos - (j * SECTOR_SIZE);
151
152 // how many bytes to read in the current sector
153 if ((SECTOR_SIZE - sectoroffset) < (size - position) && (SECTOR_SIZE - sectoroffset) < remainingLen) {
154 toread = (SECTOR_SIZE - sectoroffset);
155 } else if ((size - position) < (SECTOR_SIZE - sectoroffset) && (size-position) < remainingLen) {
156 toread = (size - position);
157 } else {
158 toread = remainingLen;
159 }
160
161 //memcpy(buffer+bytesRead, tmpBuf+sectoroffset, toread);
162 remainingLen -= toread;
163 bytesRead += toread;
164 clusterpos += toread;
165 position += toread;
166
167
168#ifdef DEBUG
169 printf("---\n");
170 printf("Read: %i\n", bytesRead);
171 printf("------------------------\n");
172#endif
173 memcpy(bufferPos, tmpBuf, toread);
174 bufferPos += toread;
175
176 }
177
178
179 // We set the offset to the 1.5x what's in nextCluster
180 int offset = (int)(nextCluster + (nextCluster >> 1));
181#ifdef DEBUG
182 printf("Offset in FAT is: %i\n", offset);
183 printf("Cluster is odd: %i\n", (nextCluster & 1));
184#endif
185 // Because of this FAT12 Quirk, the addresses are not necessarily byte aligned. If the previous Cluster address was odd, we shift the address
186 nextCluster = (*(__u16 *)(FAT1 + offset)) >> (((nextCluster & 1) * 4));
187 //clusterpos = 0;
188 // We only need 12bit
189 nextCluster = nextCluster & 0xFFF;
190 if ((size - position) <= 0 || remainingLen <= 0) {
191 //fds->cluster = nextCluster;
192 fds->position = position;
193 if (fbs.sec_per_clus * SECTOR_SIZE == clusterpos) {
194 fds->clusterpos = 0;
195 fds->cluster = nextCluster;
196 } else {
197 fds->clusterpos = clusterpos;
198 }
199 return bytesRead;
200
201 }
202#ifdef DEBUG
203 printf("Next Cluster: %x\n", nextCluster);
204#endif
205 //nextCluster = nextCluster && 0xFFF;
206 } while (nextCluster < 0xFF8 && nextCluster > 0x000);
207
208 return bytesRead;
209
210 return -1;
211}
212
213/*
214 * creates a file
215 * (consider the dir structure already there)
216 */
217int fs_creat(const char *p)
218{
219 char filename[NAME_SIZE+EXT_SIZE+1];
220 char name[NAME_SIZE+1], ext[EXT_SIZE+1];
221 char dir[SECTOR_SIZE];
222 struct dos_dir_entry *dde = NULL, *free_dde = NULL, *dde_tmp;
223 int index, i;
224 int freeCluster, currentSector;
225
226 /* check if a new file can be opened */
227 if (insert_into_filetable(NULL) == -1) {
228 die("ERROR: Cannot create file. No more files can be opened!\n");
229 }
230
231 /* parse the path */
232 dde = parse_path(p, filename);
233
234 /* check if file is already available */
235 if (search_dir(dde, filename)) {
236 die("ERROR: There already exists a file with the same name. Cannot create a new one!\n");
237 }
238
239 if (dde == NULL) {
240 /* -> create file in root dir */
241#ifdef DEBUG
242 printf("Create file in root directory!\n");
243 printf(" Filename to be written: '%s'\n", filename);
244#endif
245
246 /* search for free dde in rootdir */
247 for (i=0; i < ROOT_DIR_LEN; i++) {
248 currentSector = ROOT_DIR_POS + i;
249 bios_read(currentSector, dir);
250
251 /* get first dde */
252 dde_tmp = (struct dos_dir_entry *) dir;
253
254 /* loop through dde's and check for filename */
255 while ((char *) dde_tmp < (dir + SECTOR_SIZE)) {
256
257#ifdef DEBUG
258 printf("DDE:\n");
259 printf(" Pos: 0x%x\n", (unsigned) dde_tmp);
260 printf(" Filename = %s, Ext = %s\n", dde_tmp->name, dde_tmp->ext);
261#endif
262
263 /* first byte of free dde is 0 */
264 if(*((char *) dde_tmp) == 0) {
265 free_dde = dde_tmp;
266 break;
267 }
268
269 dde_tmp++;
270 }
271 if (free_dde) break;
272 }
273 } else {
274 /* -> create file in sub dir */
275#ifdef DEBUG
276 printf("Create file at path '%s'\n", p);
277 printf(" Subdir has been found!\n");
278 printf(" Filename to be written: '%s'\n", filename);
279#endif
280
281 /* search for free dde in subdir */
282 for (i=0; i < fbs.sec_per_clus; i++) {
283 currentSector = GET_SECTOR(dde->start) + i;
284 bios_read(currentSector, dir);
285
286 /* get first dde */
287 dde_tmp = (struct dos_dir_entry *) dir;
288
289 /* loop through dde's and check for filename */
290 while ((char *) dde_tmp < (dir + SECTOR_SIZE)) {
291
292#ifdef DEBUG
293 printf("DDE:\n");
294 printf(" Pos: 0x%x\n", (unsigned) dde_tmp);
295 printf(" Filename = %s, Ext = %s\n", dde_tmp->name, dde_tmp->ext);
296#endif
297
298 /* first byte of free dde is 0 */
299 if(*((char *) dde_tmp) == 0) {
300 free_dde = dde_tmp;
301 break;
302 }
303
304 dde_tmp++;
305 }
306 if (free_dde) break;
307 }
308 }
309
310 if (free_dde == NULL) {
311 // TODO: allocate new cluster for this subdir
312
313 return -1;
314 }
315
316 /* a free dde has ben found, thus allocate a dde */
317#ifdef DEBUG
318 printf("\n Free dde has been found!\n");
319 printf(" dde at 0x%x\n", (unsigned int) free_dde);
320#endif
321
322 /* split filename */
323 if (!fileToNameExt(filename, name, ext)) {
324 die("ERROR: could not parse filename!\n");
325 }
326
327 /* get a free cluster */
328 if ((freeCluster = get_free_cluster()) == -1) {
329 die("ERROR: no free cluster available!\n");
330 }
331
332 /* set FAT entry */
333 if (set_fat_entry(freeCluster, _EOF) == -1) {
334 die("ERROR: could not set FAT entry\n");
335 }
336
337#ifdef DEBUG
338 print_fat();
339#endif
340
341 /* write free_dde */
342 strncpy((char *) (free_dde->name), name, NAME_SIZE);
343 strncpy((char *) (free_dde->ext), ext, EXT_SIZE);
344 free_dde->attr = 0x0;
345 free_dde->lcase = 0x0;
346 write_timestamp(free_dde, CREATE);
347 free_dde->starthi = 0x0;
348 free_dde->start = freeCluster;
349 free_dde->size = 0;
350
351 /* write current sector to disk */
352 bios_write(currentSector, dir);
353
354 /* insert new file into filetable */
355 index = insert_into_filetable(free_dde);
356
357#ifdef DEBUG
358 printf("\nDDE has been written:\n");
359 printf(" Pos: 0x%x\n", (unsigned) free_dde);
360 printf(" Filename: %s, Ext = %s\n", free_dde->name, free_dde->ext);
361 printf(" Date: 0x%x\n", (int) free_dde->cdate);
362 printf(" Time: 0x%x\n", (int) free_dde->ctime);
363 printf(" Start: %d\n", (int) free_dde->start);
364 printf(" val of start clus: 0x%x\n", (int) get_fat_entry(free_dde->start));
365#endif
366
367 return index;
368}
369
370/* writes a file */
371int fs_write(int fd, void *buffer, int len)
372{
373 /* !! PRIMITIVE VERSION !! */
374 /* just writes a few bytes at the beginning of the file */
375
376 struct file_descriptor *fds;
377 char tmp_buf[SECTOR_SIZE], cluster[SECTOR_SIZE];
378 int num, rest;
379 int cluster_nr;
380
381 if (fd < 0 || fd > MAX_FILES || file_table[fd] == 0) {
382 die("ERROR: No valid file descriptor!\n");
383 }
384
385 fds = (struct file_descriptor *) file_table[fd];
386
387 //rest = len % SECTOR_SIZE; /* rest of a 512B block */
388 //num = (len - rest) % SECTOR_SIZE; /* how many 512B sectors */
389
390 memcpy(tmp_buf, buffer, SECTOR_SIZE);
391
392 /* get cluster nr from file */
393 cluster_nr = fds->dde->start;
394
395 /* write buffer into file */
396 bios_write(GET_SECTOR(cluster_nr), tmp_buf);
397
398 /* update dde */
399
400
401 return len;
402}
403
404
405/**
406 * Begin of private functions
407 */
408
409/**
410 * parse_path - Parse path p and navigate to correct subdirectory
411 * Write the filename into 'filename'.
412 *
413 * Returns the dde of the directory where the file 'filename' can
414 * be found or should be created, respectively.
415 */
416
417struct dos_dir_entry *parse_path(const char* p, char *filename)
418{
419 char path[strlen(p)+1];
420 char *files, *tmp;
421 struct dos_dir_entry *dde = NULL;
422
423 /* copy p into path */
424 strcpy(path, p);
425
426 /* split the path into dirs and files */
427 files = strtok(path, "/");
428
429 /* walk through subdirectories */
430 while ((tmp = strtok(NULL, "/")) != NULL) {
431 /* search for current subdir */
432 dde = search_dir(dde, files);
433
434 /* catch error if no entry was found or it is not a subdir */
435 if (!dde || !(IS_SUBDIR((*dde)))) {
436 die("ERROR: Subdirectory not found!\n");
437 }
438 files = tmp;
439 }
440
441 /* copy the filename into 'filename' */
442 strcpy(filename, files);
443
444 return dde;
445}
446
447/**
448 * insert_into_filetable - insert file into the file table
449 * Returns the index, -1 if full
450 *
451 * Note: if dde = NULL, then the functions
452 * checks if there is a free slot available!
453 * Returns either -1 (no) or 1 (yes)
454 */
455int insert_into_filetable (const struct dos_dir_entry *dde)
456{
457 int i;
458 if (dde) {
459 /* -> insert file with this dde into file table */
460 for (i=0; i < MAX_FILES; i++) {
461 if (file_table[i] == 0) {
462 /* free position found, write file descriptor */
463 fd_table[i].position = 0;
464 fd_table[i].clusterpos = 0;
465 fd_table[i].dde = (struct dos_dir_entry *) dde;
466 fd_table[i].cluster = dde->start;
467 file_table[i] = &fd_table[i];
468
469 /* return index */
470 return i;
471 }
472 }
473 } else {
474 /* -> check if there is a free slot available */
475 for (i=0; i < MAX_FILES; i++) {
476 if (file_table[i] == 0) {
477 /* there is a free slot */
478 return 1;
479 }
480 }
481 }
482
483 /* not successful */
484 return -1;
485}
486
487/**
488 * search_dir - search a directory for the dos_dir_entry of a given filename
489 * Input parameters:
490 * - const struct dos_dir_entry *dde: pointer to the dde where search should start
491 * (if NULL, root_dir will be searched)
492 * - char *filename: name of the file to be searched for
493 *
494 * returns the dde corresponding to filename or NULL if nothing was found
495 */
496
497struct dos_dir_entry *search_dir(const struct dos_dir_entry *dde, char *filename)
498{
499 char root_dir[SECTOR_SIZE];
500 char cluster[SECTOR_SIZE];
501 struct dos_dir_entry *dde_tmp;
502 char name[NAME_SIZE+1], ext[EXT_SIZE+1];
503 int i, brk = 0;
504
505 if (!fileToNameExt(filename, name, ext)) {
506 die("ERROR: could not parse filename\n");
507 }
508
509 if(dde == NULL) {
510 /* search in root dir */
511#ifdef DEBUG
512 printf("Search root dir for file %s\n", filename);
513#endif
514 for (i=0; i < ROOT_DIR_LEN; i++) {
515 /* after first dde is empty, all followings are empty aswell, thus break */
516 if (brk) break;
517
518 /* read sector */
519 bios_read(ROOT_DIR_POS + i, root_dir);
520
521 /* get first dde */
522 dde_tmp = (struct dos_dir_entry *) root_dir;
523
524 /* loop through dde's and check for filename */
525 while ((char *) dde_tmp < (root_dir + SECTOR_SIZE)) {
526 if(*((char *) dde_tmp) == 0) {
527 brk = 1;
528 }
529#ifdef DEBUG
530 printf("DDE:\n");
531 printf(" Pos: 0x%x\n", (unsigned) dde_tmp);
532 printf(" Filename = %s, Ext = %s\n", dde_tmp->name, dde_tmp->ext);
533#endif
534
535 /* check if dde corresponds to filename */
536 if (!(strncasecmp((char *) name, (char *) dde_tmp->name, NAME_SIZE)) &&
537 !(strncasecmp((char *) ext, (char *) dde_tmp->ext , EXT_SIZE ))) {
538#ifdef DEBUG
539 printf("File found!\n");
540#endif
541
542 return dde_tmp;
543 }
544
545 dde_tmp++;
546 }
547 }
548 } else {
549#ifdef DEBUG
550 printf("Hangle through subdirs. file = %s\n", filename);
551#endif
552
553 for (i=0; i < fbs.sec_per_clus; i++) {
554 /* after first dde is empty, all followings are empty aswell, thus break */
555 if (brk) break;
556#ifdef DEBUG
557 printf("First cluster of current dde = %d\n", dde->start);
558 printf("Root_dir_pos = %d\n", ROOT_DIR_POS);
559 printf("Root_dir_len = %d\n", ROOT_DIR_LEN);
560 printf("Get sector number %d\n", GET_SECTOR(dde->start)+i);
561#endif
562 /* read sector */
563 bios_read(GET_SECTOR(dde->start) + i, cluster);
564
565 /* get first dde of subdirectory */
566 dde_tmp = (struct dos_dir_entry *) cluster;
567
568 /* loop through dde's and check for filename */
569 while ((char *) dde_tmp < (cluster + SECTOR_SIZE)) {
570 if(*((char *) dde_tmp) == 0) {
571 brk = 1;
572 }
573#ifdef DEBUG
574 printf("DDE:\n");
575 printf(" Pos: 0x%x\n", (unsigned) dde_tmp);
576 printf(" Filename = %s, Ext = %s\n", dde_tmp->name, dde_tmp->ext);
577#endif
578
579 /* check if dde corresponds to filename */
580 if (!(strncasecmp((char *) name, (char *) dde_tmp->name, NAME_SIZE)) &&
581 !(strncasecmp((char *) ext, (char *) dde_tmp->ext , EXT_SIZE ))) {
582
583 return dde_tmp;
584 }
585
586 dde_tmp++;
587 }
588 }
589 }
590
591 /* nothing found */
592 return NULL;
593}
594
595/**
596 * get_free_cluster - searches the FAT for a free cluster
597 *
598 * Returns the cluster number, -1 on error
599 */
600int get_free_cluster()
601{
602 __u16 cluster, val;
603
604#ifdef DEBUG
605 printf("\nFind free cluster:\n");
606 printf(" Start FAT: 0x%x\n", (unsigned) FAT1);
607#endif
608
609 for(cluster = 2; cluster < MAX_CLUSTERS; cluster++) {
610 val = get_fat_entry(cluster);
611
612#ifdef DEBUG
613 printf(" Fat entry for cluster %d has val 0x%x\n", cluster, val);
614#endif
615
616packed into three bytes:
617 * uv.wx.yz => xuv,yzw
618 */
619__u16 get_fat_entry(const int clus)
620{
621 unsigned char *entry;
622 int offset;
623 __u16 val;
624
625 /* check input parameters for consistency */
626 if(clus < 2 || clus > MAX_CLUSTERS) {
627
628
629/* Print the FAT (Nr 1) */
630void print_fat()
631{
632 unsigned char *it = FAT1;
633 struct file_descriptor *fds = NULL;
634 int i, counter = 2;
635 __u16 val;
636
637 printf("\n--- FAT - DEBUG ---\n");
638 printf("File Descriptor Table and its pointers to the FAT:\n");
639 for (i=0; i<MAX_FILES; i++) {
640 fds = file_table[i];
641 if (fds) {
642 printf(" File %d starts at cluster %d.\n", i, fds->dde->start);
643 }
644 fds = NULL;
645 }
646
647 printf("\nPrint out of the File Allocation Table:\n");
648 printf("(0 values are omitted)\n");
649
650 while(it < FAT2) {
651 val = get_fat_entry(counter);
652
653 if(val != 0) {
654 printf("%3d. Position = 0x%x, Value = 0x%x\n", counter, (unsigned) it, val);
655 }
656 counter++;
657 it += 3;
658 }
659 printf("\n--- END FAT - DEBUG ---\n\n");
660}