· 5 years ago · Nov 23, 2020, 04:16 AM
1#include <assert.h>
2#include <stdio.h>
3#include <stdlib.h>
4#include <string.h>
5#include <unistd.h>
6#include "LibDisk.h"
7#include "LibFS.h"
8
9// set to 1 to have detailed debug print-outs and 0 to have none
10#define FSDEBUG 1
11
12#
13if FSDEBUG
14#define dprintf printf#
15else
16#define dprintf noprintf
17void noprintf(char *str, ...) {}#
18endif
19
20// the file system partitions the disk into five parts:
21
22// 1. the superblock (one sector), which contains a magic number at
23// its first four bytes (integer)
24#define SUPERBLOCK_START_SECTOR 0
25
26// the magic number chosen for our file system
27#define OS_MAGIC 0xdeadbeef
28
29// 2. the inode bitmap (one or more sectors), which indicates whether
30// the particular entry in the inode table (#4) is currently in use
31#define INODE_BITMAP_START_SECTOR 1
32
33// the total number of bytes and sectors needed for the inode bitmap;
34// we use one bit for each inode (whether it's a file or directory) to
35// indicate whether the particular inode in the inode table is in use
36#define INODE_BITMAP_SIZE((MAX_FILES + 7) / 8)
37#define INODE_BITMAP_SECTORS((INODE_BITMAP_SIZE + SECTOR_SIZE - 1) / SECTOR_SIZE)
38
39// 3. the sector bitmap (one or more sectors), which indicates whether
40// the particular sector in the disk is currently in use
41#define SECTOR_BITMAP_START_SECTOR(INODE_BITMAP_START_SECTOR + INODE_BITMAP_SECTORS)
42
43// the total number of bytes and sectors needed for the data block
44// bitmap (we call it the sector bitmap); we use one bit for each
45// sector of the disk to indicate whether the sector is in use or not
46#define SECTOR_BITMAP_SIZE((TOTAL_SECTORS + 7) / 8)
47#define SECTOR_BITMAP_SECTORS((SECTOR_BITMAP_SIZE + SECTOR_SIZE - 1) / SECTOR_SIZE)
48
49// 4. the inode table (one or more sectors), which contains the inodes
50// stored consecutively
51#define INODE_TABLE_START_SECTOR(SECTOR_BITMAP_START_SECTOR + SECTOR_BITMAP_SECTORS)
52
53// an inode is used to represent each file or directory; the data
54// structure supposedly contains all necessary information about the
55// corresponding file or directory
56typedef struct _inode
57{
58 int size; // the size of the file or number of directory entries
59 int type; // 0 means regular file; 1 means directory
60 int data[MAX_SECTORS_PER_FILE]; // indices to sectors containing data blocks
61}
62inode_t;
63
64// the inode structures are stored consecutively and yet they don't
65// straddle accross the sector boundaries; that is, there may be
66// fragmentation towards the end of each sector used by the inode
67// table; each entry of the inode table is an inode structure; there
68// are as many entries in the table as the number of files allowed in
69// the system; the inode bitmap (#2) indicates whether the entries are
70// current in use or not
71#define INODES_PER_SECTOR(SECTOR_SIZE / sizeof(inode_t))
72#define INODE_TABLE_SECTORS((MAX_FILES + INODES_PER_SECTOR - 1) / INODES_PER_SECTOR)
73
74// 5. the data blocks; all the rest sectors are reserved for data
75// blocks for the content of files and directories
76#define DATABLOCK_START_SECTOR(INODE_TABLE_START_SECTOR + INODE_TABLE_SECTORS)
77
78// other file related definitions
79
80// max length of a path is 256 bytes (including the ending null)
81#define MAX_PATH 256
82
83// max length of a filename is 16 bytes (including the ending null)
84#define MAX_NAME 16
85
86// max number of open files is 256
87#define MAX_OPEN_FILES 256
88
89// each directory entry represents a file/directory in the parent
90// directory, and consists of a file/directory name (less than 16
91// bytes) and an integer inode number
92typedef struct _dirent
93{
94 char fname[MAX_NAME]; // name of the file
95 int inode; // inode of the file
96}
97dirent_t;
98
99// the number of directory entries that can be contained in a sector
100#define DIRENTS_PER_SECTOR(SECTOR_SIZE / sizeof(dirent_t))
101
102// global errno value here
103int osErrno;
104
105// the name of the disk backstore file (with which the file system is booted)
106static char bs_filename[1024];
107
108/*the following functions are internal helper functions */
109
110// check magic number in the superblock; return 1 if OK, and 0 if not
111static int check_magic()
112{
113 char buf[SECTOR_SIZE];
114 if (Disk_Read(SUPERBLOCK_START_SECTOR, buf) < 0)
115 return 0;
116 if (*(int*) buf == OS_MAGIC) return 1;
117 else return 0;
118}
119
120// initialize a bitmap with 'num' sectors starting from 'start'
121// sector; all bits should be set to zero except that the first
122// 'nbits' number of bits are set to one
123static void bitmap_init(int start, int num, int nbits)
124{
125 /*YOUR CODE */
126}
127
128// set the first unused bit from a bitmap of 'nbits' bits (flip the
129// first zero appeared in the bitmap to one) and return its location;
130// return -1 if the bitmap is already full (no more zeros)
131static int bitmap_first_unused(int start, int num, int nbits)
132{
133 /*YOUR CODE */
134 return -1;
135}
136
137// reset the i-th bit of a bitmap with 'num' sectors starting from
138// 'start' sector; return 0 if successful, -1 otherwise
139static int bitmap_reset(int start, int num, int ibit)
140{
141 /*YOUR CODE */
142 return -1;
143}
144
145// return 1 if the file name is illegal; otherwise, return 0; legal
146// characters for a file name include letters (case sensitive),
147// numbers, dots, dashes, and underscores; and a legal file name
148// should not be more than MAX_NAME-1 in length
149static int illegal_filename(char *name)
150{
151 /*YOUR CODE */
152 return 1;
153}
154
155// return the child inode of the given file name 'fname' from the
156// parent inode; the parent inode is currently stored in the segment
157// of inode table in the cache (we cache only one disk sector for
158// this); once found, both cached_inode_sector and cached_inode_buffer
159// may be updated to point to the segment of inode table containing
160// the child inode; the function returns -1 if no such file is found;
161// it returns -2 is something else is wrong (such as parent is not
162// directory, or there's read error, etc.)
163static int find_child_inode(int parent_inode, char *fname,
164 int *cached_inode_sector, char *cached_inode_buffer)
165{
166 int cached_start_entry = ((*cached_inode_sector) - INODE_TABLE_START_SECTOR) *INODES_PER_SECTOR;
167 int offset = parent_inode - cached_start_entry;
168 assert(0 <= offset && offset< INODES_PER_SECTOR);
169 inode_t *parent = (inode_t*)(cached_inode_buffer + offset* sizeof(inode_t));
170 dprintf("... load parent inode: %d (size=%d, type=%d)\n",
171 parent_inode, parent->size, parent->type);
172 if (parent->type != 1)
173 {
174 dprintf("... parent not a directory\n");
175 return -2;
176 }
177
178 int nentries = parent->size; // remaining number of directory entries
179 int idx = 0;
180 while (nentries > 0)
181 {
182 char buf[SECTOR_SIZE]; // cached content of directory entries
183 if (Disk_Read(parent->data[idx], buf) < 0) return -2;
184 for (int i = 0; i < DIRENTS_PER_SECTOR; i++)
185 {
186 if (i > nentries) break;
187 if (!strcmp(((dirent_t*) buf)[i].fname, fname))
188 {
189 // found the file/directory; update inode cache
190 int child_inode = ((dirent_t*) buf)[i].inode;
191 dprintf("... found child_inode=%d\n", child_inode);
192 int sector = INODE_TABLE_START_SECTOR + child_inode / INODES_PER_SECTOR;
193 if (sector != (*cached_inode_sector))
194 { *cached_inode_sector = sector;
195 if (Disk_Read(sector, cached_inode_buffer) < 0) return -2;
196 dprintf("... load inode table for child\n");
197 }
198 return child_inode;
199 }
200 }
201 idx++;
202 nentries -= DIRENTS_PER_SECTOR;
203 }
204 dprintf("... could not find child inode\n");
205 return -1; // not found
206}
207
208// follow the absolute path; if successful, return the inode of the
209// parent directory immediately before the last file/directory in the
210// path; for example, for '/a/b/c/d.txt', the parent is '/a/b/c' and
211// the child is 'd.txt'; the child's inode is returned through the
212// parameter 'last_inode' and its file name is returned through the
213// parameter 'last_fname' (both are references); it's possible that
214// the last file/directory is not in its parent directory, in which
215// case, 'last_inode' points to -1; if the function returns -1, it
216// means that we cannot follow the path
217static int follow_path(char *path, int *last_inode, char *last_fname)
218{
219 if (!path)
220 {
221 dprintf("... invalid path\n");
222 return -1;
223 }
224 if (path[0] != '/')
225 {
226 dprintf("... '%s' not absolute path\n", path);
227 return -1;
228 }
229
230 // make a copy of the path (skip leading '/'); this is necessary
231 // since the path is going to be modified by strsep()
232 char pathstore[MAX_PATH];
233 strncpy(pathstore, path + 1, MAX_PATH - 1);
234 pathstore[MAX_PATH - 1] = '\0'; // for safety
235 char *lpath = pathstore;
236
237 int parent_inode = -1, child_inode = 0; // start from root
238 // cache the disk sector containing the root inode
239 int cached_sector = INODE_TABLE_START_SECTOR;
240 char cached_buffer[SECTOR_SIZE];
241 if (Disk_Read(cached_sector, cached_buffer) < 0) return -1;
242 dprintf("... load inode table for root from disk sector %d\n", cached_sector);
243
244 // for each file/directory name separated by '/'
245 char *token;
246 while ((token = strsep(&lpath, "/")) != NULL)
247 {
248 dprintf("... process token: '%s'\n", token);
249 if (*token == '\0') continue; // multiple '/' ignored
250 if (illegal_filename(token))
251 {
252 dprintf("... illegal file name: '%s'\n", token);
253 return -1;
254 }
255 if (child_inode < 0)
256 {
257 // regardless whether child_inode was not found previously, or
258 // there was issues related to the parent (say, not a
259 // directory), or there was a read error, we abort
260 dprintf("... parent inode can't be established\n");
261 return -1;
262 }
263 parent_inode = child_inode;
264 child_inode = find_child_inode(parent_inode, token, &cached_sector, cached_buffer);
265 if (last_fname) strcpy(last_fname, token);
266 }
267 if (child_inode < -1) return -1; // if there was error, abort
268 else
269 {
270 // there was no error, several possibilities:
271 // 1) '/': parent = -1, child = 0
272 // 2) '/valid-dirs.../last-valid-dir/not-found': parent=last-valid-dir, child=-1
273 // 3) '/valid-dirs.../last-valid-dir/found: parent=last-valid-dir, child=found
274 // in the first case, we set parent=child=0 as special case
275 if (parent_inode == -1 && child_inode == 0) parent_inode = 0;
276 dprintf("... found parent_inode=%d, child_inode=%d\n", parent_inode, child_inode);
277 *last_inode = child_inode;
278 return parent_inode;
279 }
280}
281
282// add a new file or directory (determined by 'type') of given name
283// 'file' under parent directory represented by 'parent_inode'
284int add_inode(int type, int parent_inode, char *file)
285{
286 // get a new inode for child
287 int child_inode = bitmap_first_unused(INODE_BITMAP_START_SECTOR, INODE_BITMAP_SECTORS, INODE_BITMAP_SIZE);
288 if (child_inode < 0)
289 {
290 dprintf("... error: inode table is full\n");
291 return -1;
292 }
293 dprintf("... new child inode %d\n", child_inode);
294
295 // load the disk sector containing the child inode
296 int inode_sector = INODE_TABLE_START_SECTOR + child_inode / INODES_PER_SECTOR;
297 char inode_buffer[SECTOR_SIZE];
298 if (Disk_Read(inode_sector, inode_buffer) < 0) return -1;
299 dprintf("... load inode table for child inode from disk sector %d\n", inode_sector);
300
301 // get the child inode
302 int inode_start_entry = (inode_sector - INODE_TABLE_START_SECTOR) *INODES_PER_SECTOR;
303 int offset = child_inode - inode_start_entry;
304 assert(0 <= offset && offset< INODES_PER_SECTOR);
305 inode_t *child = (inode_t*)(inode_buffer + offset* sizeof(inode_t));
306
307 // update the new child inode and write to disk
308 memset(child, 0, sizeof(inode_t));
309 child->type = type;
310 if (Disk_Write(inode_sector, inode_buffer) < 0) return -1;
311 dprintf("... update child inode %d (size=%d, type=%d), update disk sector %d\n",
312 child_inode, child->size, child->type, inode_sector);
313
314 // get the disk sector containing the parent inode
315 inode_sector = INODE_TABLE_START_SECTOR + parent_inode / INODES_PER_SECTOR;
316 if (Disk_Read(inode_sector, inode_buffer) < 0) return -1;
317 dprintf("... load inode table for parent inode %d from disk sector %d\n",
318 parent_inode, inode_sector);
319
320 // get the parent inode
321 inode_start_entry = (inode_sector - INODE_TABLE_START_SECTOR) *INODES_PER_SECTOR;
322 offset = parent_inode - inode_start_entry;
323 assert(0 <= offset && offset< INODES_PER_SECTOR);
324 inode_t *parent = (inode_t*)(inode_buffer + offset* sizeof(inode_t));
325 dprintf("... get parent inode %d (size=%d, type=%d)\n",
326 parent_inode, parent->size, parent->type);
327
328 // get the dirent sector
329 if (parent->type != 1)
330 {
331 dprintf("... error: parent inode is not directory\n");
332 return -2; // parent not directory
333 }
334 int group = parent->size / DIRENTS_PER_SECTOR;
335 char dirent_buffer[SECTOR_SIZE];
336 if (group *DIRENTS_PER_SECTOR == parent->size)
337 {
338 // new disk sector is needed
339 int newsec = bitmap_first_unused(SECTOR_BITMAP_START_SECTOR, SECTOR_BITMAP_SECTORS, SECTOR_BITMAP_SIZE);
340 if (newsec < 0)
341 {
342 dprintf("... error: disk is full\n");
343 return -1;
344 }
345 parent->data[group] = newsec;
346 memset(dirent_buffer, 0, SECTOR_SIZE);
347 dprintf("... new disk sector %d for dirent group %d\n", newsec, group);
348 }
349 else
350 {
351 if (Disk_Read(parent->data[group], dirent_buffer) < 0)
352 return -1;
353 dprintf("... load disk sector %d for dirent group %d\n", parent->data[group], group);
354 }
355
356 // add the dirent and write to disk
357 int start_entry = group * DIRENTS_PER_SECTOR;
358 offset = parent->size - start_entry;
359 dirent_t *dirent = (dirent_t*)(dirent_buffer + offset* sizeof(dirent_t));
360 strncpy(dirent->fname, file, MAX_NAME);
361 dirent->inode = child_inode;
362 if (Disk_Write(parent->data[group], dirent_buffer) < 0) return -1;
363 dprintf("... append dirent %d (name='%s', inode=%d) to group %d, update disk sector %d\n",
364 parent->size, dirent->fname, dirent->inode, group, parent->data[group]);
365
366 // update parent inode and write to disk
367 parent->size++;
368 if (Disk_Write(inode_sector, inode_buffer) < 0) return -1;
369 dprintf("... update parent inode on disk sector %d\n", inode_sector);
370
371 return 0;
372}
373
374// used by both File_Create() and Dir_Create(); type=0 is file, type=1
375// is directory
376int create_file_or_directory(int type, char *pathname)
377{
378 int child_inode;
379 char last_fname[MAX_NAME];
380 int parent_inode = follow_path(pathname, &child_inode, last_fname);
381 if (parent_inode >= 0)
382 {
383 if (child_inode >= 0)
384 {
385 dprintf("... file/directory '%s' already exists, failed to create\n", pathname);
386 osErrno = E_CREATE;
387 return -1;
388 }
389 else
390 {
391 if (add_inode(type, parent_inode, last_fname) >= 0)
392 {
393 dprintf("... successfully created file/directory: '%s'\n", pathname);
394 return 0;
395 }
396 else
397 {
398 dprintf("... error: something wrong with adding child inode\n");
399 osErrno = E_CREATE;
400 return -1;
401 }
402 }
403 }
404 else
405 {
406 dprintf("... error: something wrong with the file/path: '%s'\n", pathname);
407 osErrno = E_CREATE;
408 return -1;
409 }
410}
411
412// remove the child from parent; the function is called by both
413// File_Unlink() and Dir_Unlink(); the function returns 0 if success,
414// -1 if general error, -2 if directory not empty, -3 if wrong type
415int remove_inode(int type, int parent_inode, int child_inode)
416{
417 /*YOUR CODE */
418 return -1;
419}
420
421// representing an open file
422typedef struct _open_file
423{
424 int inode; // pointing to the inode of the file (0 means entry not used)
425 int size; // file size cached here for convenience
426 int pos; // read/write position
427}
428open_file_t;
429static open_file_t open_files[MAX_OPEN_FILES];
430
431// return true if the file pointed to by inode has already been open
432int is_file_open(int inode)
433{
434 for (int i = 0; i < MAX_OPEN_FILES; i++)
435 {
436 if (open_files[i].inode == inode)
437 return 1;
438 }
439 return 0;
440}
441
442// return a new file descriptor not used; -1 if full
443int new_file_fd()
444{
445 for (int i = 0; i < MAX_OPEN_FILES; i++)
446 {
447 if (open_files[i].inode <= 0)
448 return i;
449 }
450 return -1;
451}
452
453/*end of internal helper functions, start of API functions */
454
455int FS_Boot(char *backstore_fname)
456{
457 dprintf("FS_Boot('%s'):\n", backstore_fname);
458 // initialize a new disk (this is a simulated disk)
459 if (Disk_Init() < 0)
460 {
461 dprintf("... disk init failed\n");
462 osErrno = E_GENERAL;
463 return -1;
464 }
465 dprintf("... disk initialized\n");
466
467 // we should copy the filename down; if not, the user may change the
468 // content pointed to by 'backstore_fname' after calling this function
469 strncpy(bs_filename, backstore_fname, 1024);
470 bs_filename[1023] = '\0'; // for safety
471
472 // we first try to load disk from this file
473 if (Disk_Load(bs_filename) < 0)
474 {
475 dprintf("... load disk from file '%s' failed\n", bs_filename);
476
477 // if we can't open the file; it means the file does not exist, we
478 // need to create a new file system on disk
479 if (diskErrno == E_OPENING_FILE)
480 {
481 dprintf("... couldn't open file, create new file system\n");
482
483 // format superblock
484 char buf[SECTOR_SIZE];
485 memset(buf, 0, SECTOR_SIZE);
486 *(int*) buf = OS_MAGIC;
487 if (Disk_Write(SUPERBLOCK_START_SECTOR, buf) < 0)
488 {
489 dprintf("... failed to format superblock\n");
490 osErrno = E_GENERAL;
491 return -1;
492 }
493 dprintf("... formatted superblock (sector %d)\n", SUPERBLOCK_START_SECTOR);
494
495 // format inode bitmap (reserve the first inode to root)
496 bitmap_init(INODE_BITMAP_START_SECTOR, INODE_BITMAP_SECTORS, 1);
497 dprintf("... formatted inode bitmap (start=%d, num=%d)\n",
498 (int) INODE_BITMAP_START_SECTOR, (int) INODE_BITMAP_SECTORS);
499
500 // format sector bitmap (reserve the first few sectors to
501 // superblock, inode bitmap, sector bitmap, and inode table)
502 bitmap_init(SECTOR_BITMAP_START_SECTOR, SECTOR_BITMAP_SECTORS,
503 DATABLOCK_START_SECTOR);
504 dprintf("... formatted sector bitmap (start=%d, num=%d)\n",
505 (int) SECTOR_BITMAP_START_SECTOR, (int) SECTOR_BITMAP_SECTORS);
506
507 // format inode tables
508 for (int i = 0; i < INODE_TABLE_SECTORS; i++)
509 {
510 memset(buf, 0, SECTOR_SIZE);
511 if (i == 0)
512 {
513 // the first inode table entry is the root directory
514 ((inode_t*) buf)->size = 0;
515 ((inode_t*) buf)->type = 1;
516 }
517 if (Disk_Write(INODE_TABLE_START_SECTOR + i, buf) < 0)
518 {
519 dprintf("... failed to format inode table\n");
520 osErrno = E_GENERAL;
521 return -1;
522 }
523 }
524 dprintf("... formatted inode table (start=%d, num=%d)\n",
525 (int) INODE_TABLE_START_SECTOR, (int) INODE_TABLE_SECTORS);
526
527 // we need to synchronize the disk to the backstore file (so
528 // that we don't lose the formatted disk)
529 if (Disk_Save(bs_filename) < 0)
530 {
531 // if can't write to file, something's wrong with the backstore
532 dprintf("... failed to save disk to file '%s'\n", bs_filename);
533 osErrno = E_GENERAL;
534 return -1;
535 }
536 else
537 {
538 // everything's good now, boot is successful
539 dprintf("... successfully formatted disk, boot successful\n");
540 memset(open_files, 0, MAX_OPEN_FILES* sizeof(open_file_t));
541 return 0;
542 }
543 }
544 else
545 {
546 // something wrong loading the file: invalid param or error reading
547 dprintf("... couldn't read file '%s', boot failed\n", bs_filename);
548 osErrno = E_GENERAL;
549 return -1;
550 }
551 }
552 else
553 {
554 dprintf("... load disk from file '%s' successful\n", bs_filename);
555
556 // we successfully loaded the disk, we need to do two more checks,
557 // first the file size must be exactly the size as expected (thiis
558 // supposedly should be folded in Disk_Load(); and it's not)
559 int sz = 0;
560 FILE *f = fopen(bs_filename, "r");
561 if (f)
562 {
563 fseek(f, 0, SEEK_END);
564 sz = ftell(f);
565 fclose(f);
566 }
567 if (sz != SECTOR_SIZE *TOTAL_SECTORS)
568 {
569 dprintf("... check size of file '%s' failed\n", bs_filename);
570 osErrno = E_GENERAL;
571 return -1;
572 }
573 dprintf("... check size of file '%s' successful\n", bs_filename);
574
575 // check magic
576 if (check_magic())
577 {
578 // everything's good by now, boot is successful
579 dprintf("... check magic successful\n");
580 memset(open_files, 0, MAX_OPEN_FILES* sizeof(open_file_t));
581 return 0;
582 }
583 else
584 {
585 // mismatched magic number
586 dprintf("... check magic failed, boot failed\n");
587 osErrno = E_GENERAL;
588 return -1;
589 }
590 }
591}
592
593int FS_Sync()
594{
595 if (Disk_Save(bs_filename) < 0)
596 {
597 // if can't write to file, something's wrong with the backstore
598 dprintf("FS_Sync():\n... failed to save disk to file '%s'\n", bs_filename);
599 osErrno = E_GENERAL;
600 return -1;
601 }
602 else
603 {
604 // everything's good now, sync is successful
605 dprintf("FS_Sync():\n... successfully saved disk to file '%s'\n", bs_filename);
606 return 0;
607 }
608}
609
610int File_Create(char *file)
611{
612 dprintf("File_Create('%s'):\n", file);
613 return create_file_or_directory(0, file);
614}
615
616int File_Unlink(char *file)
617{
618 /*YOUR CODE */
619 return -1;
620}
621
622int File_Open(char *file)
623{
624 dprintf("File_Open('%s'):\n", file);
625 int fd = new_file_fd();
626 if (fd < 0)
627 {
628 dprintf("... max open files reached\n");
629 osErrno = E_TOO_MANY_OPEN_FILES;
630 return -1;
631 }
632
633 int child_inode;
634 follow_path(file, &child_inode, NULL);
635 if (child_inode >= 0)
636 {
637 // child is the one
638 // load the disk sector containing the inode
639 int inode_sector = INODE_TABLE_START_SECTOR + child_inode / INODES_PER_SECTOR;
640 char inode_buffer[SECTOR_SIZE];
641 if (Disk_Read(inode_sector, inode_buffer) < 0)
642 {
643 osErrno = E_GENERAL;
644 return -1;
645 }
646 dprintf("... load inode table for inode from disk sector %d\n", inode_sector);
647
648 // get the inode
649 int inode_start_entry = (inode_sector - INODE_TABLE_START_SECTOR) *INODES_PER_SECTOR;
650 int offset = child_inode - inode_start_entry;
651 assert(0 <= offset && offset< INODES_PER_SECTOR);
652 inode_t *child = (inode_t*)(inode_buffer + offset* sizeof(inode_t));
653 dprintf("... inode %d (size=%d, type=%d)\n",
654 child_inode, child->size, child->type);
655
656 if (child->type != 0)
657 {
658 dprintf("... error: '%s' is not a file\n", file);
659 osErrno = E_GENERAL;
660 return -1;
661 }
662
663 // initialize open file entry and return its index
664 open_files[fd].inode = child_inode;
665 open_files[fd].size = child->size;
666 open_files[fd].pos = 0;
667 return fd;
668 }
669 else
670 {
671 dprintf("... file '%s' is not found\n", file);
672 osErrno = E_NO_SUCH_FILE;
673 return -1;
674 }
675}
676
677int File_Read(int fd, void *buffer, int size)
678{
679 /*YOUR CODE */
680 int f_inode = open_files[fd].inode;
681 if (f_inode == 0)
682 {
683 osErrno = E_BAD_FD;
684 return -1;
685 }
686 dprintf(".....the initial size is %d\n", size);
687
688 /* load the disk sector containing the child inode */
689 char inode_buffer[SECTOR_SIZE];
690 int inode_sector = INODE_TABLE_START_SECTOR + f_inode / INODES_PER_SECTOR;
691 if (Disk_Read(inode_sector, inode_buffer) < 0)
692 return -1;
693 dprintf("... load inode table for child inode from disk sector %d\n", inode_sector);
694
695 // get the child inode
696 int inode_start_entry = (inode_sector - INODE_TABLE_START_SECTOR) *INODES_PER_SECTOR;
697 int offset = f_inode - inode_start_entry;
698 assert(offset< INODES_PER_SECTOR);
699 assert(0 <= offset);
700 inode_t *node = (inode_t*)(inode_buffer + offset* sizeof(inode_t));
701
702 int beginSector = open_files[fd].pos / 512; // figure out which sector we want to read
703 int beginByte; // for iterating bytes
704 char *temp = calloc(512, sizeof(char));
705 char *data = (char*) buffer;
706 int tempsize = size;
707 int count = 0;
708 dprintf("the current pos is %d\n", beginSector);
709
710 while (count < tempsize && node->data[beginSector])
711 {
712 Disk_Read(node->data[beginSector], temp);
713 beginByte = (count == 0) ? open_files[fd].pos % SECTOR_SIZE : 0;
714 for (;beginByte < SECTOR_SIZE && count < size;beginByte++,count++)
715 {
716 data[count] = temp[beginByte];
717 }
718 beginSector++;
719 }
720 open_files[fd].pos += count;
721 return count;
722}
723
724int File_Write(int fd, void *buffer, int size)
725{
726 /*YOUR CODE */
727 // not enough space on the disk
728 if(fd<0 && fd>MAX_OPEN_FILES) {
729 osErrno = E_NO_SPACE;
730 return -1;
731 }
732 int f_inode = open_files[fd].inode;
733 // if the file is not opened
734 if (f_inode < 1)
735 {
736 osErrno = E_BAD_FD;
737 return -1;
738 }
739 int end = ((size+open_files[fd].pos+SECTOR_SIZE-1)/SECTOR_SIZE);
740 // file exceeds maximum file size
741 if(end > 29){
742 osErrno = E_FILE_TOO_BIG;
743 return -1;
744 }
745
746 /* load the disk sector containing the child inode */
747 char inode_buffer[SECTOR_SIZE];
748 int inode_sector = INODE_TABLE_START_SECTOR + f_inode / INODES_PER_SECTOR;
749 dprintf("... load inode table for child inode from disk sector %d\n", inode_sector);
750 if (Disk_Read(inode_sector, inode_buffer) < 0)
751 return -1;
752
753 /*get the child inode*/
754 int inode_start_entry = (inode_sector - INODE_TABLE_START_SECTOR) *INODES_PER_SECTOR;
755 int offset = f_inode - inode_start_entry;
756 assert(0 <= offset);
757 assert(offset< INODES_PER_SECTOR);
758 inode_t *node = (inode_t*)(inode_buffer + offset* sizeof(inode_t));
759
760 char *temp = (char*) buffer;
761 int tempsize = size;
762 int finalCount = 0;
763 int beginByte;
764 int beginSector = open_files[fd].pos / SECTOR_SIZE;
765 int count = 0;
766
767 for (count=0;count<size;count++)
768 {
769 /*loop until the bytes written is less than the size*/
770 int firstUnused = bitmap_first_unused(SECTOR_BITMAP_START_SECTOR, SECTOR_BITMAP_SECTORS, SECTOR_BITMAP_SIZE);
771 node->data[beginSector] = firstUnused;
772 char *writeBuffer = calloc(512, sizeof(char));
773 beginByte = (count == 0) ? open_files[fd].pos % SECTOR_SIZE : 0;
774 dprintf("the new sector where will be written %d\n", node->data[beginSector]);
775 for (;beginByte < 512 && tempsize > 0;beginByte++,tempsize--);
776 {
777 writeBuffer[beginByte] = temp[count];
778 }
779 dprintf("Written the following: %s\n", writeBuffer);
780 Disk_Write(node->data[beginSector++], writeBuffer);
781 finalCount=count;
782 }
783 node->size += finalCount;
784 open_files[fd].size += finalCount;
785 open_files[fd].pos += finalCount;
786
787 Disk_Write(inode_sector, inode_buffer);
788
789 return finalCount;
790}
791
792int File_Seek(int fd, int offset)
793{
794 /*YOUR CODE */
795 dprintf("File_Seek (%d):\n", fd);
796
797 int fd_size = open_files[fd].size;
798 int fd_inode = open_files[fd].inode;
799
800 if (offset< 0 || fd_size < offset)
801 {
802 osErrno = E_SEEK_OUT_OF_BOUNDS;
803 return -1;
804 }
805
806 if (fd_inode = 0)
807 {
808 osErrno = E_BAD_FD;
809 return -1;
810 }
811 dprintf("... file seeked successfully\n");
812 open_files[fd].pos = offset;
813 return 0;
814}
815
816int File_Close(int fd)
817{
818 dprintf("File_Close(%d):\n", fd);
819 if (0 > fd || fd > MAX_OPEN_FILES)
820 {
821 dprintf("... fd=%d out of bound\n", fd);
822 osErrno = E_BAD_FD;
823 return -1;
824 }
825 if (open_files[fd].inode <= 0)
826 {
827 dprintf("... fd=%d not an open file\n", fd);
828 osErrno = E_BAD_FD;
829 return -1;
830 }
831
832 dprintf("... file closed successfully\n");
833 open_files[fd].inode = 0;
834 return 0;
835}
836
837int Dir_Create(char *path)
838{
839 dprintf("Dir_Create('%s'):\n", path);
840 return create_file_or_directory(1, path);
841}
842
843int Dir_Unlink(char *path)
844{
845 /*YOUR CODE */
846 return -1;
847}
848
849int Dir_Size(char *path)
850{
851 /*YOUR CODE */
852 return 0;
853}
854
855int Dir_Read(char *path, void *buffer, int size)
856{
857 /*YOUR CODE */
858 return -1;
859}