· 6 years ago · Nov 14, 2019, 02:30 AM
1#include <assert.h>
2#include <stdio.h>
3#include <stdlib.h>
4#include <string.h>
5#include <unistd.h>
6#include <ctype.h>
7#include "LibDisk.h"
8#include "LibFS.h"
9
10// set to 1 to have detailed debug print-outs and 0 to have none
11#define FSDEBUG 1
12
13#if FSDEBUG
14#define dprintf printf
15#else
16#define dprintf noprintf
17void noprintf(char* str, ...) {}
18#endif
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 int size; // the size of the file or number of directory entries
58 int type; // 0 means regular file; 1 means directory
59 int data[MAX_SECTORS_PER_FILE]; // indices to sectors containing data blocks
60} inode_t;
61
62// the inode structures are stored consecutively and yet they don't
63// straddle accross the sector boundaries; that is, there may be
64// fragmentation towards the end of each sector used by the inode
65// table; each entry of the inode table is an inode structure; there
66// are as many entries in the table as the number of files allowed in
67// the system; the inode bitmap (#2) indicates whether the entries are
68// current in use or not
69#define INODES_PER_SECTOR (SECTOR_SIZE/sizeof(inode_t))
70#define INODE_TABLE_SECTORS ((MAX_FILES+INODES_PER_SECTOR-1)/INODES_PER_SECTOR)
71
72// 5. the data blocks; all the rest sectors are reserved for data
73// blocks for the content of files and directories
74#define DATABLOCK_START_SECTOR (INODE_TABLE_START_SECTOR+INODE_TABLE_SECTORS)
75
76// other file related definitions
77
78// max length of a path is 256 bytes (including the ending null)
79#define MAX_PATH 256
80
81// max length of a filename is 16 bytes (including the ending null)
82#define MAX_NAME 16
83
84// max number of open files is 256
85#define MAX_OPEN_FILES 256
86
87// each directory entry represents a file/directory in the parent
88// directory, and consists of a file/directory name (less than 16
89// bytes) and an integer inode number
90typedef struct _dirent {
91 char fname[MAX_NAME]; // name of the file
92 int inode; // inode of the file
93} dirent_t;
94
95// the number of directory entries that can be contained in a sector
96#define DIRENTS_PER_SECTOR (SECTOR_SIZE/sizeof(dirent_t))
97
98// global errno value here
99int osErrno;
100
101// the name of the disk backstore file (with which the file system is booted)
102static char bs_filename[1024];
103
104/* the following functions are internal helper functions */
105//find min
106int min(int num1, int num2){
107 return (num1 > num2) ? num2 : num1;
108}
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#define CHARBITS (8) //number of bits in a char
121
122/*
123 The following functions were created by ehenl001@fiu to for bit manipulation
124*/
125static void set_bit(char *bitmap, int index)
126{
127 ( bitmap[(index/CHARBITS)] |= (1UL << (index % CHARBITS)));
128}
129
130static void clear_bit(char *bitmap, int index)
131{
132 ( bitmap[(index/CHARBITS)] &= ~(1UL << (index % CHARBITS)));
133}
134
135static int test_bit(char *bitmap, int index)
136{
137 return ( bitmap[(index/CHARBITS)] & (1UL << (index % CHARBITS))) > 0;
138}
139
140static int array_size(int numBits)
141{
142 return (numBits/CHARBITS+(!!(numBits%CHARBITS)));
143}
144/*
145 // format sector bitmap (reserve the first few sectors to superblock, inode bitmap, sector bitmap, and inode table)
146 bitmap_init(SECTOR_BITMAP_START_SECTOR = 2, SECTOR_BITMAP_SECTORS = 3,
147 DATABLOCK_START_SECTOR=?);
148*/
149// initialize a bitmap with 'num' sectors starting from 'start'
150// sector; all bits should be set to zero except that the first
151// 'nbits' number of bits are set to one
152// type for inode bitmap sector = 0
153// type for sector bitmap sector = 1
154static void bitmap_init(int start, int num, int nbits, int type)
155{
156 /* YOUR CODE */
157 dprintf("...start bitmap initialization with start=%d, num=%d, nbits=%d\n",start, num, nbits);
158 //create bitmap with size of arry of chars neccessary to support num bits
159 char *bitmap;
160 //get size of bit array in bytes
161 //if type then bitmap sector, else inode sector
162 int size = -1;
163 if(type){
164 size = array_size(SECTOR_BITMAP_SIZE * CHARBITS);
165 }else{
166 size = array_size(INODE_BITMAP_SIZE * CHARBITS);
167 }
168 //allocate the neccessary bytes for the num size bitmap
169 bitmap = (char *)calloc(size, sizeof(char));
170
171 //initialize all bits to 0 (clear all bits)
172 for (int i = 0; i < num; i++)
173 {
174 clear_bit(bitmap,i);
175 }
176
177 //for nbits set the bit (bit = 1)
178 for (int i = 0; i < nbits; i++)
179 {
180 set_bit(bitmap,i);
181 }
182
183 //set the bits of the sector that thec current bitmap occupies
184 for(int i = start; i < start + num; i++) set_bit(bitmap, i);
185
186 //print all bits for testing
187 /*
188 for (int i = 0; i < num; i++)
189 {
190 printf("%d: %lu\n",i, test_bit(bitmap,i));
191 }
192 */
193 // check if bitmap will fit in one sector (SECTOR_SIZE > size(bitmap))
194 if(SECTOR_SIZE >= size)
195 {
196 //printf("SECTOR_SIZE >= size -> %d > %lu", SECTOR_SIZE, size);
197 if(Disk_Write(start, bitmap)<0)
198 {
199 dprintf("Error initializing bitmap, func=bitmap_init\n");
200 }
201 else{
202 dprintf("...bitmap wrote to disk successfully using 1 sector to store, func=bitmap_init\n");
203 }
204
205
206 }
207 else
208 {
209 //printf("size > SECTOR_SIZE -> %lu > %d", size, SECTOR_SIZE );
210 char buff[SECTOR_SIZE];
211 int toXfr = size;//track total bytes to write to disk
212 int numBytes = 0;
213 int i = -1;
214 int numSectorUsed = 0;
215
216 for (i = 0; i<= size; i+=SECTOR_SIZE)
217 {
218 if(toXfr>SECTOR_SIZE)
219 {
220 numBytes = SECTOR_SIZE;
221 }
222 else
223 {
224 numBytes = toXfr;
225 }
226 memcpy(buff, &bitmap[i], numBytes);//copy to buff numBytes of bitmap
227 if(Disk_Write(start++, buff)<0)
228 {
229 dprintf("Error initializing bitmap");
230 }
231 numSectorUsed +=1;
232 toXfr = toXfr - numBytes;//update number of bytes remaining to write to disk
233
234 //for testing
235 /*
236 for(int y = 0; y < numBytes; y++)
237 {
238 printf("%d",buff[y]);
239 }
240
241 printf("\n");
242 printf("Copied %d bytes, %d remaining\n", numBytes, toXfr);
243 */
244 }
245 dprintf("...bitmap written to disk using %d sectors to store on disk, func=bitmap_init\n", numSectorUsed);
246 }
247 free(bitmap);
248 dprintf("... mem freed for bitmap, func=bitmap_init\n");
249}
250
251// set the first unused bit from a bitmap of 'nbits' bits (flip the
252// first zero appeared in the bitmap to one) and return its location;
253// return -1 if the bitmap is already full (no more zeros)
254static int bitmap_first_unused(int start, int num, int nbits)
255{
256 /* YOUR CODE */
257
258 dprintf("...bitmap_first_unused called\n");
259
260 char buff[SECTOR_SIZE];
261
262 //determine number of sectors the bitmap occupies
263 int secRemain = (nbits / CHARBITS)%SECTOR_SIZE;
264 int numSec = (nbits / CHARBITS)/SECTOR_SIZE;
265 int found = 0;
266 int firstUnused = -1;
267 if(secRemain)
268 {
269 numSec += 1;
270 }
271
272 //determine number of bytes needed to represent bitmap with nbits
273 int bmpARRLen = array_size(nbits);
274 int currSec = start;
275
276 //prep bitmap array
277 char *bitmap;
278 bitmap = (char*)calloc(bmpARRLen, sizeof(char));
279 int index = 0; //track index in bmp where next chunk from buff will be stored
280 int numBytes = bmpARRLen; //track remaining bytes to be copied to form complete bitmap
281 int bytesToCopy = -1;
282
283 for(int i = 0; i < numSec; i++)
284 {
285 //read each sector and build full bitmap
286 if(Disk_Read(currSec, buff) < 0)
287 {
288 dprintf("...could not retrieve bitmap from disk in func bitmap_first_unused\n");
289 return -1;
290 }
291 //copy buff to bitmap
292 index = SECTOR_SIZE * i;
293 if(numBytes<=SECTOR_SIZE)
294 {
295 bytesToCopy = numBytes;
296 }
297 else
298 {
299 bytesToCopy = SECTOR_SIZE;
300 numBytes -= SECTOR_SIZE;
301 }
302 memcpy(&bitmap[index], buff, bytesToCopy);
303 }
304
305 //search for first bit equal to 0
306 for(int i =0; i < nbits; i++)
307 {
308 //if equal to 0 set bit and return i
309 if (test_bit(bitmap, i) == 0)
310 {
311 //set ith bit to 1
312 set_bit(bitmap, i);
313 found = 1;
314 firstUnused = i;
315 }
316 if(found){
317 dprintf("...found unused bit in bitmap at index %d, func=bitmap_first_unused", firstUnused);
318 break;
319 }
320 }
321
322 //write new bit map to disk
323 numBytes = bmpARRLen;
324 currSec = start;
325 index = 0;
326 for(int i = 0; i < numSec; i++)
327 {
328 //check if remaining bytes to be copied (numBytes) is less than sector size
329 if(numBytes <= SECTOR_SIZE)
330 {
331 bytesToCopy = numBytes;
332 }
333 else
334 {
335 bytesToCopy = SECTOR_SIZE;
336 }
337 //copy from bitmap to buff
338 memcpy(buff, &bitmap[index], bytesToCopy);
339 //write to currSec full bitmap or part of full bitmap
340 if(Disk_Write(currSec, buff) < 0) return -1;
341 //update index, beginning of next section of bitmap to copy
342 index = SECTOR_SIZE * i;
343 //update remaining number of bytes needing to be written to disk
344 numBytes -= bytesToCopy;
345 }
346 //free allocated memory of bitmap
347 free(bitmap);
348
349 //if unused is found return its index, else return -1
350 if(found)
351 {
352 return firstUnused;
353 }
354 else
355 {
356 dprintf("...no unused bits in bitmap, func=bitmap_first_unused\n");
357 return -1;
358 }
359}
360
361// reset the i-th bit of a bitmap with 'num' sectors starting from
362// 'start' sector; return 0 if successful, -1 otherwise
363static int bitmap_reset(int start, int num, int ibit)
364{
365 dprintf("... called bitmap_reset\n");
366 /* YOUR CODE */
367 char buff[SECTOR_SIZE];
368 //determine bitmap length
369 int bmpARRLen = -1;
370
371 //check if num of bits is a multiple of 8, if there is a remainder then the neccessary length
372 //of an array to hold num bits is 1 + (number of bits / bits in a char = 8) otherwise its just (number of bits / bits in a char = 8)
373 bmpARRLen = num*SECTOR_SIZE;
374
375 //initialize bitmap arrary with length equal to bmpARRLen
376 char *bitmap;
377
378 //allocate the neccessary bytes for the num size bitmap
379 bitmap = (char *)calloc(bmpARRLen, sizeof(char));
380
381 //determine number of sectors the bitmap occupies
382 int numSec = num;
383
384 //check if bitmap only occupies one sector
385 if(numSec == 1)
386 {
387 //bitmap only ooccupies one sector, read the bitmap from start sector
388 if(Disk_Read(start, buff) < 0) {
389 dprintf("...cannot read bitmap from disk, func=bitmap_reset\n");
390 return -1;}
391
392 //copy from buffer to bitmap
393 memcpy(bitmap, buff, bmpARRLen);
394
395 }
396 else
397 {
398 for(int i = 0; i < numSec; i++)
399 {
400 int secRd = start + i;
401 //read from sector
402 if(Disk_Read(secRd, buff) < 0) {
403 dprintf("...cannot read bitmap from disk, func=bitmap_reset\n");
404 return -1;}
405 //copy to bitmap
406 int index = i * SECTOR_SIZE;
407
408 memcpy(&bitmap[index], buff, SECTOR_SIZE);
409 }
410 }
411
412 if(test_bit(bitmap, ibit) == 0)
413 {
414 dprintf("...error cannot clear bit in %d index, func=bitmap_reset\n", ibit);
415 return -1;
416 }
417 else
418 {
419 clear_bit(bitmap, ibit);
420 dprintf("...bit in %d index cleared successfully, func=bitmap_reset\n", ibit);
421 }
422 //bytes to transfer from bitmap to buffer then write to disk
423 int toXfr = bmpARRLen;
424 //track num bytes to write to disk for each write to disk
425 int numBytes = -1;
426 //write bitmap to memory
427 for (int i = 0; i<= num; i+=SECTOR_SIZE)
428 {
429 if(toXfr>SECTOR_SIZE)//num bytes to write larger than sector size
430 {
431 numBytes = SECTOR_SIZE;
432 }
433 else
434 {
435 numBytes = toXfr;
436 }
437 memcpy(buff, &bitmap[i], numBytes);//copy to buff numBytes of bitmap
438 if(Disk_Write(start++, buff)<0)
439 {
440 dprintf("...writing bitmap to disk, func=bitmap_reset\n");
441 return -1;
442 }
443 toXfr = toXfr - numBytes;//update number of bytes remaining to write to disk
444
445 }
446
447
448 return 0;
449}
450// return 1 if the file name is illegal; otherwise, return 0; legal
451// characters for a file name include letters (case sensitive),
452// numbers, dots, dashes, and underscores; and a legal file name
453// should not be more than MAX_NAME-1 in length
454static int illegal_filename(char* name)
455{
456 // Check if name is non empty or too long
457 if(name==NULL || strlen(name)==0 || strlen(name)>=MAX_NAME)
458 {
459 dprintf("... Filename is null or too long: %s\n", name);
460 return 1;
461 }
462
463 // Check if entries only contain allowed elements
464 for(int i=0; i < strlen(name);i++){
465 if(!(isalpha(name[i]) || isdigit(name[i]) ||
466 name[i] == '.' || name[i] == '_' || name[i] == '-' || name[i] == '/'))
467 {
468 dprintf("... Invalid characters in filename: %s\n", name);
469 return 1; }
470 }
471
472 return 0;
473}
474
475// return the child inode of the given file name 'fname' from the
476// parent inode; the parent inode is currently stored in the segment
477// of inode table in the cache (we cache only one disk sector for
478// this); once found, both cached_inode_sector and cached_inode_buffer
479// may be updated to point to the segment of inode table containing
480// the child inode; the function returns -1 if no such file is found;
481// it returns -2 is something else is wrong (such as parent is not
482// directory, or there's read error, etc.)
483static int find_child_inode(int parent_inode, char* fname,
484 int *cached_inode_sector, char* cached_inode_buffer)
485{
486 int cached_start_entry = ((*cached_inode_sector)-INODE_TABLE_START_SECTOR)*INODES_PER_SECTOR;
487 int offset = parent_inode-cached_start_entry;
488 assert(0 <= offset && offset < INODES_PER_SECTOR);
489 inode_t* parent = (inode_t*)(cached_inode_buffer+offset*sizeof(inode_t));
490 dprintf("... load parent inode: %d (size=%d, type=%d)\n",
491 parent_inode, parent->size, parent->type);
492 if(parent->type != 1) {
493 dprintf("... parent not a directory\n");
494 return -2;
495 }
496
497 int nentries = parent->size; // remaining number of directory entries
498 dprintf("... number of dir entries: %d\n", nentries);
499 int idx = 0;
500 while(nentries > 0) {
501 char buf[SECTOR_SIZE]; // cached content of directory entries
502 if(Disk_Read(parent->data[idx], buf) < 0) return -2;
503 for(int i=0; i<DIRENTS_PER_SECTOR; i++) {
504 if(i>nentries) break;
505 if(!strcmp(((dirent_t*)buf)[i].fname, fname)) {
506 // found the file/directory; update inode cache
507 int child_inode = ((dirent_t*)buf)[i].inode;
508 dprintf("... found child_inode=%d\n", child_inode);
509 int sector = INODE_TABLE_START_SECTOR+child_inode/INODES_PER_SECTOR;
510 if(sector != (*cached_inode_sector)) {
511 *cached_inode_sector = sector;
512 if(Disk_Read(sector, cached_inode_buffer) < 0) return -2;
513 dprintf("... load inode table for child\n");
514 }
515 return child_inode;
516 }
517 }
518 idx++; nentries -= DIRENTS_PER_SECTOR;
519 }
520 dprintf("... could not find child inode\n");
521 return -1; // not found
522}
523
524// follow the absolute path; if successful, return the inode of the
525// parent directory immediately before the last file/directory in the
526// path; for example, for '/a/b/c/d.txt', the parent is '/a/b/c' and
527// the child is 'd.txt'; the child's inode is returned through the
528// parameter 'last_inode' and its file name is returned through the
529// parameter 'last_fname' (both are references); it's possible that
530// the last file/directory is not in its parent directory, in which
531// case, 'last_inode' points to -1; if the function returns -1, it
532// means that we cannot follow the path
533static int follow_path(char* path, int* last_inode, char* last_fname)
534{
535 if(!path) {
536 dprintf("... invalid path\n");
537 return -1;
538 }
539 if(path[0] != '/') {
540 dprintf("... '%s' not absolute path\n", path);
541 return -1;
542 }
543
544 // make a copy of the path (skip leading '/'); this is necessary
545 // since the path is going to be modified by strsep()
546 char pathstore[MAX_PATH];
547 strncpy(pathstore, path+1, MAX_PATH-1);
548 pathstore[MAX_PATH-1] = '\0'; // for safety
549 char* lpath = pathstore;
550
551 int parent_inode = -1, child_inode = 0; // start from root
552 // cache the disk sector containing the root inode
553 int cached_sector = INODE_TABLE_START_SECTOR;
554 char cached_buffer[SECTOR_SIZE];
555 if(Disk_Read(cached_sector, cached_buffer) < 0) return -1;
556 dprintf("... load inode table for root from disk sector %d\n", cached_sector);
557
558 // for each file/directory name separated by '/'
559 char* token;
560 while((token = strsep(&lpath, "/")) != NULL) {
561 dprintf("... process token: '%s'\n", token);
562 if(*token == '\0') continue; // multiple '/' ignored
563 if(illegal_filename(token)) {
564 dprintf("... illegal file name: '%s'\n", token);
565 return -1;
566 }
567 if(child_inode < 0) {
568 // regardless whether child_inode was not found previously, or
569 // there was issues related to the parent (say, not a
570 // directory), or there was a read error, we abort
571 dprintf("... parent inode can't be established\n");
572 return -1;
573 }
574 parent_inode = child_inode;
575 child_inode = find_child_inode(parent_inode, token,
576 &cached_sector, cached_buffer);
577 if(last_fname) strcpy(last_fname, token);
578 }
579 if(child_inode < -1) return -1; // if there was error, abort
580 else {
581 // there was no error, several possibilities:
582 // 1) '/': parent = -1, child = 0
583 // 2) '/valid-dirs.../last-valid-dir/not-found': parent=last-valid-dir, child=-1
584 // 3) '/valid-dirs.../last-valid-dir/found: parent=last-valid-dir, child=found
585 // in the first case, we set parent=child=0 as special case
586 if(parent_inode==-1 && child_inode==0) parent_inode = 0;
587 dprintf("... found parent_inode=%d, child_inode=%d\n", parent_inode, child_inode);
588 *last_inode = child_inode;
589 return parent_inode;
590 }
591}
592
593// add a new file or directory (determined by 'type') of given name
594// 'file' under parent directory represented by 'parent_inode'
595int add_inode(int type, int parent_inode, char* file)
596{
597 // get a new inode for child
598 int child_inode = bitmap_first_unused(INODE_BITMAP_START_SECTOR, INODE_BITMAP_SECTORS, INODE_BITMAP_SIZE);
599 if(child_inode < 0) {
600 dprintf("... error: inode table is full\n");
601 return -1;
602 }
603 dprintf("... new child inode %d\n", child_inode);
604
605 // load the disk sector containing the child inode
606 int inode_sector = INODE_TABLE_START_SECTOR+child_inode/INODES_PER_SECTOR;
607 char inode_buffer[SECTOR_SIZE];
608 if(Disk_Read(inode_sector, inode_buffer) < 0) return -1;
609 dprintf("... load inode table for child inode from disk sector %d\n", inode_sector);
610
611 // get the child inode
612 int inode_start_entry = (inode_sector-INODE_TABLE_START_SECTOR)*INODES_PER_SECTOR;
613 int offset = child_inode-inode_start_entry;
614 assert(0 <= offset && offset < INODES_PER_SECTOR);
615 inode_t* child = (inode_t*)(inode_buffer+offset*sizeof(inode_t));
616
617 // update the new child inode and write to disk
618 memset(child, 0, sizeof(inode_t));
619 child->type = type;
620 if(Disk_Write(inode_sector, inode_buffer) < 0) return -1;
621 dprintf("... update child inode %d (size=%d, type=%d), update disk sector %d\n",
622 child_inode, child->size, child->type, inode_sector);
623
624 // get the disk sector containing the parent inode
625 inode_sector = INODE_TABLE_START_SECTOR+parent_inode/INODES_PER_SECTOR;
626 if(Disk_Read(inode_sector, inode_buffer) < 0) return -1;
627 dprintf("... load inode table for parent inode %d from disk sector %d\n",
628 parent_inode, inode_sector);
629
630 // get the parent inode
631 inode_start_entry = (inode_sector-INODE_TABLE_START_SECTOR)*INODES_PER_SECTOR;
632 offset = parent_inode-inode_start_entry;
633 assert(0 <= offset && offset < INODES_PER_SECTOR);
634 inode_t* parent = (inode_t*)(inode_buffer+offset*sizeof(inode_t));
635 dprintf("... get parent inode %d (size=%d, type=%d)\n",
636 parent_inode, parent->size, parent->type);
637
638 // get the dirent sector
639 if(parent->type != 1) {
640 dprintf("... error: parent inode is not directory\n");
641 return -2; // parent not directory
642 }
643 int group = parent->size/DIRENTS_PER_SECTOR;
644 char dirent_buffer[SECTOR_SIZE];
645 if(group*DIRENTS_PER_SECTOR == parent->size) {
646 // new disk sector is needed
647 int newsec = bitmap_first_unused(SECTOR_BITMAP_START_SECTOR, SECTOR_BITMAP_SECTORS, SECTOR_BITMAP_SIZE);
648 if(newsec < 0) {
649 dprintf("... error: disk is full\n");
650 return -1;
651 }
652 parent->data[group] = newsec;
653 memset(dirent_buffer, 0, SECTOR_SIZE);
654 dprintf("... new disk sector %d for dirent group %d\n", newsec, group);
655 } else {
656 if(Disk_Read(parent->data[group], dirent_buffer) < 0)
657 return -1;
658 dprintf("... load disk sector %d for dirent group %d\n", parent->data[group], group);
659 }
660
661 // add the dirent and write to disk
662 int start_entry = group*DIRENTS_PER_SECTOR;
663 offset = parent->size-start_entry;
664 dirent_t* dirent = (dirent_t*)(dirent_buffer+offset*sizeof(dirent_t));
665 strncpy(dirent->fname, file, MAX_NAME);
666 dirent->inode = child_inode;
667 if(Disk_Write(parent->data[group], dirent_buffer) < 0) return -1;
668 dprintf("... append dirent %d (name='%s', inode=%d) to group %d, update disk sector %d\n",
669 parent->size, dirent->fname, dirent->inode, group, parent->data[group]);
670
671 // update parent inode and write to disk
672 parent->size++;
673 if(Disk_Write(inode_sector, inode_buffer) < 0) return -1;
674 dprintf("... update parent inode on disk sector %d\n", inode_sector);
675
676 return 0;
677}
678
679// used by both File_Create() and Dir_Create(); type=0 is file, type=1
680// is directory
681int create_file_or_directory(int type, char* pathname)
682{
683 int child_inode;
684 char last_fname[MAX_NAME];
685 int parent_inode = follow_path(pathname, &child_inode, last_fname);
686 if(parent_inode >= 0)
687 {
688 if(child_inode >= 0)
689 {
690 dprintf("... file/directory '%s' already exists, failed to create\n", pathname);
691 osErrno = E_CREATE;
692 return -1;
693 } else
694 {
695 if(add_inode(type, parent_inode, last_fname) >= 0)
696 {
697 dprintf("... successfully created file/directory: '%s'\n", pathname);
698 return 0;
699 }
700 else {
701 dprintf("... error: something wrong with adding child inode\n");
702 osErrno = E_CREATE;
703 return -1;
704 }
705 }
706 } else {
707 dprintf("... error: something wrong with the file/path: '%s'\n", pathname);
708 osErrno = E_CREATE;
709 return -1;
710 }
711}
712
713// remove the child from parent; the function is called by both
714// File_Unlink() and Dir_Unlink(); the function returns 0 if success,
715// -1 if general error, -2 if directory not empty, -3 if wrong type
716int remove_inode(int type, int parent_inode, int child_inode)
717{
718
719 dprintf("... remove inode %d\n", child_inode);
720
721 // load the disk sector containing the child inode
722 int inode_sector = INODE_TABLE_START_SECTOR+child_inode/INODES_PER_SECTOR;
723 char inode_buffer[SECTOR_SIZE];
724 if(Disk_Read(inode_sector, inode_buffer) < 0) return -1;
725 dprintf("... load inode table for child inode from disk sector %d\n", inode_sector);
726
727 // get the child inode
728 int inode_start_entry = (inode_sector-INODE_TABLE_START_SECTOR)*INODES_PER_SECTOR;
729 int offset = child_inode-inode_start_entry;
730 assert(0 <= offset && offset < INODES_PER_SECTOR);
731 inode_t* child = (inode_t*)(inode_buffer+offset*sizeof(inode_t));
732
733 // check for right type
734 if(child->type!=type){
735 dprintf("... error: the type parameter does not match the actual inode type\n");
736 return -3;
737 }
738
739 // check if child is non-empty directory
740 if(child->type==1 && child->size>0){
741 dprintf("... error: inode is non-empty directory\n");
742 return -2;
743 }
744
745 // delete the child inode
746 memset(child, 0, sizeof(inode_t));
747 if(Disk_Write(inode_sector, inode_buffer) < 0) return -1;
748 dprintf("... delete inode %d, update disk sector %d\n",
749 child_inode, inode_sector);
750
751 // get the disk sector containing the parent inode
752 inode_sector = INODE_TABLE_START_SECTOR+parent_inode/INODES_PER_SECTOR;
753 if(Disk_Read(inode_sector, inode_buffer) < 0) return -1;
754 dprintf("... load inode table for parent inode %d from disk sector %d\n",
755 parent_inode, inode_sector);
756
757 // get the parent inode
758 inode_start_entry = (inode_sector-INODE_TABLE_START_SECTOR)*INODES_PER_SECTOR;
759 offset = parent_inode-inode_start_entry;
760 assert(0 <= offset && offset < INODES_PER_SECTOR);
761 inode_t* parent = (inode_t*)(inode_buffer+offset*sizeof(inode_t));
762 dprintf("... get parent inode %d (size=%d, type=%d)\n",
763 parent_inode, parent->size, parent->type);
764
765 // check if parent is directory
766 if(parent->type != 1) {
767 dprintf("... error: parent inode is not directory\n");
768 return -3;
769 }
770
771 // check if parent is non-empty
772 if(parent->size < 1) {
773 dprintf("... error: parent directory has no entries\n");
774 return -1;
775 }
776
777 // reset bit of child inode in bitmap
778 if (bitmap_reset(INODE_BITMAP_START_SECTOR, INODE_BITMAP_SECTORS, child_inode) < 0) {
779 dprintf("... error: reset inode in bitmap unsuccessful\n");
780 return -1;
781 }
782
783 int remainder = parent->size % DIRENTS_PER_SECTOR;
784 int group = (parent->size+DIRENTS_PER_SECTOR-1)/DIRENTS_PER_SECTOR;
785 char dirent_buffer[SECTOR_SIZE];
786 dirent_t* dirent;
787 int counter = 0;
788 int found = 0;
789
790 // search for the dirent in every group
791 for(int i = 0; i<group; i++){
792
793 if(Disk_Read(parent->data[i], dirent_buffer) < 0) return -1;
794 dprintf("... search for child in disk sector %d for dirent group %d\n", parent->data[i], i);
795
796 for(int j=0; j<DIRENTS_PER_SECTOR; j++){
797 counter ++;
798 dirent = (dirent_t*)(dirent_buffer+j*sizeof(dirent_t));
799
800 if(counter < parent->size && (!found)) {
801
802 // Case 1: Child node found and last dirent in the same sector
803 if(dirent->inode == child_inode && i == group-1) {
804 dirent_t* last_dirent = (dirent_t*)(dirent_buffer+(remainder-1)*sizeof(dirent_t));
805 memcpy(dirent, last_dirent, sizeof(dirent_t));
806 memset(last_dirent, 0, sizeof(dirent_t));
807 if(Disk_Write(parent->data[i], dirent_buffer) < 0) return -1;
808 dprintf("... delete dirent (inode=%d) from group %d, update disk sector %d\n",
809 child_inode, i, parent->data[i]);
810 found=1;
811
812 // Case 2: Child node found, but last dirent in other sector
813 } else if(dirent->inode == child_inode) {
814 char last_dirent_buffer[SECTOR_SIZE];
815 if(Disk_Read(parent->data[group-1], last_dirent_buffer) < 0) return -1;
816 dprintf("... load last dirent from parent %d in disk sector %d for dirent group %d\n",
817 parent_inode, parent->data[group-1], group-1);
818 dirent_t* last_dirent = (dirent_t*)(last_dirent_buffer+(remainder-1)*sizeof(dirent_t));
819 memcpy(dirent, last_dirent, sizeof(dirent_t));
820 memset(last_dirent, 0, sizeof(dirent_t));
821 if(Disk_Write(parent->data[i], dirent_buffer) < 0) return -1;
822 dprintf("...delete dirent (inode=%d) from group %d, update disk sector %d\n",
823 child_inode, i, parent->data[i]);
824 if(Disk_Write(parent->data[group-1], last_dirent_buffer) < 0) return -1;
825 dprintf("...copy last dirent with inode %d into group %d, update disk sector %d\n",
826 dirent->inode, group-1, parent->data[group-1]);
827 found=1;
828 }
829
830 } else if(!found) {
831
832 // Case 3: Child found and last dirent from parent
833 if(dirent->inode == child_inode) {
834 memset(dirent, 0, sizeof(dirent_t));
835 if(Disk_Write(parent->data[i], dirent_buffer) < 0) return -1;
836 dprintf("... delete dirent (inode=%d) from group %d, update disk sector %d\n",
837 child_inode, group-1, parent->data[i]);
838 found=1;
839
840 // Case 4: Child node not found, and reached last dirent from parent
841 } else if(counter >= parent->size) {
842 dprintf("Counter: %d, Parent size: %d\n", counter, parent->size);
843 dprintf("... error: child inode could not be found in parent directory\n");
844 return -1;
845 }
846 }
847 }
848 }
849
850 // delete inode in inode sector
851
852
853 // check for remaining dirents from parent in that sector (otherwise reset sector bitmap)
854 if (remainder == 1) {
855 // disk sector has to be freed
856 if (bitmap_reset(SECTOR_BITMAP_START_SECTOR, SECTOR_BITMAP_SECTORS, parent->data[group]) < 0) {
857 dprintf("... error: free sector in bitmap unsuccessful\n");
858 return -1;
859 }
860 parent->data[group-1] = 0;
861 }
862
863 // update parent inode and write to disk
864 parent->size--;
865 if(Disk_Write(inode_sector, inode_buffer) < 0) return -1;
866 dprintf("... update parent inode on disk sector %d\n", inode_sector);
867
868 return 0;
869
870}
871// representing an open file
872typedef struct _open_file {
873 int inode; // pointing to the inode of the file (0 means entry not used)
874 int size; // file size cached here for convenience
875 int pos; // read/write position
876} open_file_t;
877static open_file_t open_files[MAX_OPEN_FILES];
878
879// return true if the file pointed to by inode has already been open
880int is_file_open(int inode)
881{
882 for(int i=0; i<MAX_OPEN_FILES; i++) {
883 if(open_files[i].inode == inode)
884 return 1;
885 }
886 return 0;
887}
888
889// return a new file descriptor not used; -1 if full
890int new_file_fd()
891{
892 for(int i=0; i<MAX_OPEN_FILES; i++) {
893 if(open_files[i].inode <= 0)
894 return i;
895 }
896 return -1;
897}
898
899/* end of internal helper functions, start of API functions */
900
901int FS_Boot(char* backstore_fname)
902{
903 dprintf("FS_Boot('%s'):\n", backstore_fname);
904 // initialize a new disk (this is a simulated disk)
905 if(Disk_Init() < 0) {
906 dprintf("... disk init failed\n");
907 osErrno = E_GENERAL;
908 return -1;
909 }
910 dprintf("... disk initialized\n");
911
912 // we should copy the filename down; if not, the user may change the
913 // content pointed to by 'backstore_fname' after calling this function
914 strncpy(bs_filename, backstore_fname, 1024);
915 bs_filename[1023] = '\0'; // for safety
916
917 // we first try to load disk from this file
918 if(Disk_Load(bs_filename) < 0) {
919 dprintf("... load disk from file '%s' failed\n", bs_filename);
920
921 // if we can't open the file; it means the file does not exist, we
922 // need to create a new file system on disk
923 if(diskErrno == E_OPENING_FILE) {
924 dprintf("... couldn't open file, create new file system\n");
925
926 // format superblock
927 char buf[SECTOR_SIZE];
928 memset(buf, 0, SECTOR_SIZE);
929 *(int*)buf = OS_MAGIC;
930 if(Disk_Write(SUPERBLOCK_START_SECTOR, buf) < 0) {
931 dprintf("... failed to format superblock\n");
932 osErrno = E_GENERAL;
933 return -1;
934 }
935 dprintf("... formatted superblock (sector %d)\n", SUPERBLOCK_START_SECTOR);
936
937 // format inode bitmap (reserve the first inode to root)
938 // type for inode bitmap sector = 0
939 dprintf("... calling bitmap int for inode bitmap with start=%d, num=%d, nbits=1\n", INODE_BITMAP_START_SECTOR, INODE_BITMAP_SECTORS);
940 bitmap_init(INODE_BITMAP_START_SECTOR, INODE_BITMAP_SECTORS, 1, 0);
941 dprintf("... formatted inode bitmap (start=%d, num=%d)\n",
942 (int)INODE_BITMAP_START_SECTOR, (int)INODE_BITMAP_SECTORS);
943
944 // format sector bitmap (reserve the first few sectors to
945 // superblock, inode bitmap, sector bitmap, and inode table)
946 // type for sector bitmap sector = 1
947 dprintf("... calling bitmap int for sector bitmap with start=%d, num=%d, nbits=%ld\n", SECTOR_BITMAP_START_SECTOR, SECTOR_BITMAP_SECTORS, DATABLOCK_START_SECTOR);
948 bitmap_init(SECTOR_BITMAP_START_SECTOR, SECTOR_BITMAP_SECTORS,
949 DATABLOCK_START_SECTOR, 1);
950 dprintf("... (start=%d, num=%d)\n",
951 (int)SECTOR_BITMAP_START_SECTOR, (int)SECTOR_BITMAP_SECTORS);
952
953 // format inode tables
954 for(int i=0; i<INODE_TABLE_SECTORS; i++) {
955 memset(buf, 0, SECTOR_SIZE);
956 if(i==0) {
957 // the first inode table entry is the root directory
958 ((inode_t*)buf)->size = 0;
959 ((inode_t*)buf)->type = 1;
960 }
961 if(Disk_Write(INODE_TABLE_START_SECTOR+i, buf) < 0) {
962 dprintf("... failed to format inode table\n");
963 osErrno = E_GENERAL;
964 return -1;
965 }
966 }
967 dprintf("... formatted inode table (start=%d, num=%d)\n",
968 (int)INODE_TABLE_START_SECTOR, (int)INODE_TABLE_SECTORS);
969
970 // we need to synchronize the disk to the backstore file (so
971 // that we don't lose the formatted disk)
972 if(Disk_Save(bs_filename) < 0) {
973 // if can't write to file, something's wrong with the backstore
974 dprintf("... failed to save disk to file '%s'\n", bs_filename);
975 osErrno = E_GENERAL;
976 return -1;
977 } else {
978 // everything's good now, boot is successful
979 dprintf("... successfully formatted disk, boot successful\n");
980 memset(open_files, 0, MAX_OPEN_FILES*sizeof(open_file_t));
981 return 0;
982 }
983 } else {
984 // something wrong loading the file: invalid param or error reading
985 dprintf("... couldn't read file '%s', boot failed\n", bs_filename);
986 osErrno = E_GENERAL;
987 return -1;
988 }
989 } else {
990 dprintf("... load disk from file '%s' successful\n", bs_filename);
991
992 // we successfully loaded the disk, we need to do two more checks,
993 // first the file size must be exactly the size as expected (thiis
994 // supposedly should be folded in Disk_Load(); and it's not)
995 int sz = 0;
996 FILE* f = fopen(bs_filename, "r");
997 if(f) {
998 fseek(f, 0, SEEK_END);
999 sz = ftell(f);
1000 fclose(f);
1001 }
1002 if(sz != SECTOR_SIZE*TOTAL_SECTORS) {
1003 dprintf("... check size of file '%s' failed\n", bs_filename);
1004 osErrno = E_GENERAL;
1005 return -1;
1006 }
1007 dprintf("... check size of file '%s' successful\n", bs_filename);
1008
1009 // check magic
1010 if(check_magic()) {
1011 // everything's good by now, boot is successful
1012 dprintf("... check magic successful\n");
1013 memset(open_files, 0, MAX_OPEN_FILES*sizeof(open_file_t));
1014 return 0;
1015 } else {
1016 // mismatched magic number
1017 dprintf("... check magic failed, boot failed\n");
1018 osErrno = E_GENERAL;
1019 return -1;
1020 }
1021 }
1022}
1023
1024int FS_Sync()
1025{
1026 dprintf("FS_Sync():\n");
1027 if(Disk_Save(bs_filename) < 0) {
1028 // if can't write to file, something's wrong with the backstore
1029 dprintf("FS_Sync():\n... failed to save disk to file '%s'\n", bs_filename);
1030 osErrno = E_GENERAL;
1031 return -1;
1032 } else {
1033 // everything's good now, sync is successful
1034 dprintf("FS_Sync():\n... successfully saved disk to file '%s'\n", bs_filename);
1035 return 0;
1036 }
1037}
1038
1039int File_Create(char* file)
1040{
1041 dprintf("File_Create('%s'):\n", file);
1042 return create_file_or_directory(0, file);
1043}
1044
1045//TODO: check if really remove the data blocks
1046int File_Unlink(char* file)
1047{
1048 dprintf("File_Unlink('%s'):\n", file);
1049 int child_inode;
1050
1051 int parent_inode = follow_path(file, &child_inode, NULL);
1052
1053
1054 if(child_inode >= 0) //file exists
1055 {
1056 //check if file is open
1057 if(is_file_open(child_inode)){
1058 dprintf("... %s is an open file. Cannot unlink\n", file);
1059 osErrno = E_FILE_IN_USE;
1060 return -1;
1061 }
1062
1063
1064 int remove = remove_inode(0, parent_inode, child_inode);
1065 if(remove == -1){
1066 dprintf("... error: general error when unlinking file\n");
1067 osErrno = E_GENERAL;
1068 return -1;
1069 }
1070 else if(remove == -3){
1071 dprintf("... error: no file, incorrect type\n");
1072 osErrno = E_NO_SUCH_FILE;
1073 return -1;
1074 }
1075 else{
1076 return 0;
1077 }
1078
1079 }
1080
1081 else{ //file does not exist
1082 dprintf("... %s file does not exist\n", file);
1083 osErrno = E_NO_SUCH_FILE;
1084 return -1;
1085
1086 }
1087}
1088
1089int File_Open(char* file)
1090{
1091 dprintf("File_Open('%s'):\n", file);
1092 int fd = new_file_fd();
1093 if(fd < 0) {
1094 dprintf("... max open files reached\n");
1095 osErrno = E_TOO_MANY_OPEN_FILES;
1096 return -1;
1097 }
1098
1099 int child_inode;
1100 follow_path(file, &child_inode, NULL);
1101 if(child_inode >= 0) { // child is the one
1102 // load the disk sector containing the inode
1103 int inode_sector = INODE_TABLE_START_SECTOR+child_inode/INODES_PER_SECTOR;
1104 char inode_buffer[SECTOR_SIZE];
1105 if(Disk_Read(inode_sector, inode_buffer) < 0) { osErrno = E_GENERAL; return -1; }
1106 dprintf("... load inode table for inode from disk sector %d\n", inode_sector);
1107
1108 // get the inode
1109 int inode_start_entry = (inode_sector-INODE_TABLE_START_SECTOR)*INODES_PER_SECTOR;
1110 int offset = child_inode-inode_start_entry;
1111 assert(0 <= offset && offset < INODES_PER_SECTOR);
1112 inode_t* child = (inode_t*)(inode_buffer+offset*sizeof(inode_t));
1113 dprintf("... inode %d (size=%d, type=%d)\n",
1114 child_inode, child->size, child->type);
1115
1116 if(child->type != 0) {
1117 dprintf("... error: '%s' is not a file\n", file);
1118 osErrno = E_GENERAL;
1119 return -1;
1120 }
1121
1122 // initialize open file entry and return its index
1123 open_files[fd].inode = child_inode;
1124 open_files[fd].size = child->size;
1125 open_files[fd].pos = 0;
1126
1127
1128
1129
1130 return fd;
1131 } else {
1132 dprintf("... file '%s' is not found\n", file);
1133 osErrno = E_NO_SUCH_FILE;
1134 return -1;
1135 }
1136}
1137
1138//TODO: fix reading size in forloop
1139int File_Read(int fd, void* buffer, int size)
1140{
1141 dprintf("File_Read(%d, buffer, %d):\n", fd, size);
1142 //check if fd is valid index
1143 if(fd < 0 || fd > MAX_OPEN_FILES){
1144 dprintf("... fd=%d out of bound", fd);
1145 osErrno = E_BAD_FD;
1146 return -1;
1147 }
1148
1149 open_file_t file = open_files[fd];
1150
1151 //check if not an open file
1152 if(file.inode <= 0){
1153 dprintf("... fd=%d not an open file\n", fd);
1154 osErrno = E_BAD_FD;
1155 return -1;
1156 }
1157 int position = file.pos;
1158 int remReadSize = 0;
1159
1160 //check if file size is empty
1161 if(file.size == 0)
1162 {
1163 //none to read
1164 return 0;
1165 }
1166
1167 //determine how many bytes to read
1168 if(file.size - position == 0)
1169 {
1170 //none to read
1171 return 0;
1172 }
1173 else{
1174 //if less than size is remaining, read only remaining
1175 //else pick size
1176 remReadSize = min(file.size - position, size);
1177
1178 }
1179 memset(buffer, 0, remReadSize);
1180
1181
1182 /***read contents of data blocks***/
1183
1184 //load file's inode disk sectors
1185 int inode = file.inode;
1186 int inode_sector = INODE_TABLE_START_SECTOR+inode/INODES_PER_SECTOR;
1187 char inode_buffer[SECTOR_SIZE];
1188 if(Disk_Read(inode_sector, inode_buffer) < 0) { osErrno = E_GENERAL; return -1; }
1189 dprintf("... load inode table for inode from disk sector %d\n", inode_sector);
1190
1191 //get inode
1192 int inode_start_entry = (inode_sector-INODE_TABLE_START_SECTOR)*INODES_PER_SECTOR;
1193 int offset = inode-inode_start_entry;
1194 assert(0 <= offset && offset < INODES_PER_SECTOR);
1195 inode_t* fileInode = (inode_t*)(inode_buffer+offset*sizeof(inode_t));
1196 dprintf("... inode %d (size=%d, type=%d)\n",
1197 inode, fileInode->size, fileInode->type);
1198
1199 //FILES_PER_SECTOR (SECTOR_SIZE/SIZEOF(open_file_t))
1200 int i = 0;
1201 //read data from given datablock pointers
1202 for(i = file.pos; i < remReadSize; i++){
1203 if(Disk_Read(fileInode->data[i], (char*)buffer+i*SECTOR_SIZE) < 0){
1204 dprintf("... error: cant read sector %d\n", fileInode->data[i]);
1205 osErrno=E_GENERAL;
1206 return -1;
1207 }
1208 }
1209
1210 File_Seek(fd, i);
1211
1212
1213 return remReadSize;
1214}
1215
1216int File_Write(int fd, void* buffer, int size)
1217{
1218 dprintf("File_Write(%d, buffer, %d):\n",fd, size);
1219 //check if fd is valid index
1220 if(fd < 0 || fd > MAX_OPEN_FILES){
1221 dprintf("... fd=%d out of bound", fd);
1222 osErrno = E_BAD_FD;
1223 return -1;
1224 }
1225
1226 open_file_t file = open_files[fd];
1227
1228 //check if not an open file
1229 if(file.inode <= 0){
1230 dprintf("... fd=%d not an open file\n", fd);
1231 osErrno = E_BAD_FD;
1232 return -1;
1233 }
1234
1235 int extraSectorsNeeded = (size/SECTOR_SIZE + size%SECTOR_SIZE);
1236
1237 //check if extra data doesn't go over max sectors per file
1238 if(file.pos + extraSectorsNeeded > MAX_SECTORS_PER_FILE){
1239 dprintf("... fd=%d at position=%d cannot add %d data sectors. No more space\n",
1240 fd, file.pos, size);
1241 osErrno = E_FILE_TOO_BIG;
1242 return -1;
1243 }
1244
1245 dprintf("... extra sectors needed=%d for fd=%d at position=%d\n", extraSectorsNeeded,
1246 fd, file.pos);
1247 //load file's inode disk sectors
1248 int inode = file.inode;
1249 int inode_sector = INODE_TABLE_START_SECTOR+inode/INODES_PER_SECTOR;
1250 char inode_buffer[SECTOR_SIZE];
1251 if(Disk_Read(inode_sector, inode_buffer) < 0) { osErrno = E_GENERAL; return -1; }
1252 dprintf("... load inode table for inode from disk sector %d\n", inode_sector);
1253
1254 //get inode
1255 int inode_start_entry = (inode_sector-INODE_TABLE_START_SECTOR)*INODES_PER_SECTOR;
1256 int offset = inode-inode_start_entry;
1257 assert(0 <= offset && offset < INODES_PER_SECTOR);
1258 inode_t* fileInode = (inode_t*)(inode_buffer+offset*sizeof(inode_t));
1259 dprintf("... inode %d (size=%d, type=%d)\n",
1260 inode, fileInode->size, fileInode->type);
1261
1262
1263 //write data from after the last occupied data pointer
1264 int i = 0;
1265 for(i = file.pos; i < extraSectorsNeeded; i++){
1266 if(fileInode->data[i] == 0){ //find first sector to use
1267 int newsec = bitmap_first_unused(SECTOR_BITMAP_START_SECTOR, SECTOR_BITMAP_SECTORS, SECTOR_BITMAP_SIZE);
1268 fileInode->data[i] = newsec;
1269 dprintf("Data[%d]=%d\n", i, fileInode->data[i]);
1270 }
1271
1272 if(Disk_Write(fileInode->data[i], (char*)buffer+i*SECTOR_SIZE) < 0) {
1273 dprintf("... failed to write buffer data\n");
1274 osErrno = E_GENERAL;
1275 return -1;
1276 }
1277 /***TODO: need to check if write cannot complete due to lack of space on disk. how?***/
1278 }
1279
1280 //set new read/write position
1281 open_files[fd].pos = i;
1282
1283 //update file size
1284 int currSize = file.size;
1285 open_files[fd].size = currSize + extraSectorsNeeded;
1286
1287 return size;
1288}
1289
1290int File_Seek(int fd, int offset)
1291{
1292 dprintf("File_Seek(%d, %d):\n", fd, offset);
1293 //check if fd is valid index
1294 if(fd < 0 || fd > MAX_OPEN_FILES){
1295 dprintf("... fd=%d out of bound\n", fd);
1296 osErrno = E_BAD_FD;
1297 return -1;
1298 }
1299 //check if open file
1300 if(open_files[fd].inode <= 0) {
1301 dprintf("... fd=%d not an open file\n", fd);
1302 osErrno = E_BAD_FD;
1303 return -1;
1304 }
1305
1306 //check if offset is within bounds
1307 if(offset > open_files[fd].size || offset == -1){
1308 dprintf("... offset=%d out of bound\n", fd);
1309 osErrno = E_SEEK_OUT_OF_BOUNDS;
1310 return -1;
1311 }
1312
1313 open_files[fd].pos = offset;
1314
1315 return open_files[fd].pos;
1316}
1317
1318int File_Close(int fd)
1319{
1320 dprintf("File_Close(%d):\n", fd);
1321 if(0 > fd || fd > MAX_OPEN_FILES) {
1322 dprintf("... fd=%d out of bound\n", fd);
1323 osErrno = E_BAD_FD;
1324 return -1;
1325 }
1326 if(open_files[fd].inode <= 0) {
1327 dprintf("... fd=%d not an open file\n", fd);
1328 osErrno = E_BAD_FD;
1329 return -1;
1330 }
1331
1332
1333
1334 dprintf("... file closed successfully\n");
1335 open_files[fd].inode = 0;
1336 return 0;
1337}
1338
1339int Dir_Create(char* path)
1340{
1341 dprintf("Dir_Create('%s'):\n", path);
1342 return create_file_or_directory(1, path);
1343}
1344
1345int Dir_Unlink(char* path)
1346{
1347 dprintf("Dir_Unlink('%s'):\n", path);
1348 // no empty path and no root directory allowed
1349 if(path==NULL) {
1350 dprintf("... error: empty path (NULL) for directory unlink");
1351 osErrno = E_GENERAL;
1352 return -1;
1353 }
1354
1355 if(strcmp(path, "/")==0) {
1356 dprintf("... error: not allowed to unlink root directory");
1357 osErrno = E_ROOT_DIR;
1358 return -1;
1359 }
1360
1361 // find parent and children (if theres any)
1362 int child_inode;
1363 dprintf("... calling follow path with path: %s\n", path);
1364 int parent_inode = follow_path(path, &child_inode, NULL);
1365 dprintf("... follow path returned parent inode: %d\n", parent_inode);
1366 if(parent_inode < 0) {
1367 dprintf("... error: directory '%s' not found\n", path);
1368 osErrno = E_NO_SUCH_DIR;
1369 return -1;
1370 }
1371
1372 int remove = remove_inode(1, parent_inode, child_inode);
1373
1374 if (remove==-1) {
1375 dprintf("... error: general error when unlinking directory\n");
1376 osErrno = E_GENERAL;
1377 return -1;
1378 } else if (remove==-3) {
1379 dprintf("... error: no directory, wrong type\n");
1380 osErrno = E_NO_SUCH_DIR;
1381 return -1;
1382 } else if (remove==-2) {
1383 dprintf("... error: directory %s not empty", path);
1384 osErrno = E_DIR_NOT_EMPTY;
1385 return -1;
1386 } else {
1387 return 0;
1388 }
1389
1390
1391}
1392
1393int Dir_Size(char* path)
1394{
1395 dprintf("Dir_Size('%s'):\n", path);
1396 // no empty path allowed
1397 if(path==NULL) {
1398 dprintf("... error: empty path (NULL) given as parameter\n");
1399 osErrno = E_GENERAL;
1400 return -1;
1401 }
1402
1403 // directory has to exist
1404 int child_inode;
1405 int parent_inode = follow_path(path, &child_inode, NULL);
1406 if(parent_inode < 0) {
1407 dprintf("... error: directory '%s' not found\n", path);
1408 osErrno = E_NO_SUCH_DIR;
1409 return -1;
1410 }
1411
1412 // load the disk sector containing the child inode
1413 int inode_sector = INODE_TABLE_START_SECTOR+child_inode/INODES_PER_SECTOR;
1414 char inode_buffer[SECTOR_SIZE];
1415 if(Disk_Read(inode_sector, inode_buffer) < 0) return -1;
1416 dprintf("... load inode table for child inode from disk sector %d\n", inode_sector);
1417
1418 // get the child inode
1419 int inode_start_entry = (inode_sector-INODE_TABLE_START_SECTOR)*INODES_PER_SECTOR;
1420 int offset = child_inode-inode_start_entry;
1421 assert(0 <= offset && offset < INODES_PER_SECTOR);
1422 inode_t* child = (inode_t*)(inode_buffer+offset*sizeof(inode_t));
1423
1424 // check for type
1425 if (child->type!=1) {
1426 dprintf("... error: wrong type, path leads to file\n");
1427 osErrno = E_GENERAL;
1428 return -1;
1429 }
1430
1431 return child->size*sizeof(dirent_t);
1432}
1433
1434int Dir_Read(char* path, void* buffer, int size)
1435{
1436 dprintf("Dir_Read('%s', buffer, %d):\n", path, size);
1437 int real_size = Dir_Size(path);
1438 if(real_size<0) return -1;
1439 if(real_size==0) return 0;
1440
1441 // check if size of buffer is large enough to hold all elements in the directory
1442 if (size<real_size) {
1443 osErrno=E_BUFFER_TOO_SMALL;
1444 return -1;
1445 }
1446
1447 // initialize buffer
1448 memset(buffer, 0, size);
1449
1450 // load disk sector from directory
1451 int inode;
1452 char inode_buffer[SECTOR_SIZE];
1453 int parent_inode=follow_path(path, &inode, NULL);
1454 if(parent_inode<0) return -1;
1455 int inode_sector = INODE_TABLE_START_SECTOR+inode/INODES_PER_SECTOR;
1456 if(Disk_Read(inode_sector, inode_buffer) < 0) return -1;
1457 dprintf("... load inode table for parent inode %d from disk sector %d\n",
1458 inode, inode_sector);
1459
1460 // get the parent inode
1461 int inode_start_entry = (inode_sector-INODE_TABLE_START_SECTOR)*INODES_PER_SECTOR;
1462 int offset = inode-inode_start_entry;
1463 assert(0 <= offset && offset < INODES_PER_SECTOR);
1464 inode_t* dir_inode = (inode_t*)(inode_buffer+offset*sizeof(inode_t));
1465 dprintf("... get inode %d (size=%d, type=%d)\n",
1466 inode, dir_inode->size, dir_inode->type);
1467
1468 // read the directory entries into the buffer
1469 int remainder=dir_inode->size%DIRENTS_PER_SECTOR;
1470 int group=dir_inode->size/DIRENTS_PER_SECTOR;
1471
1472 // a) completely filled sectors
1473 for(int i=0; i<group;i++) {
1474 if(Disk_Read(dir_inode->data[i], (char*)buffer+i*SECTOR_SIZE) < 0) {
1475 dprintf("... error: cant read sector %d\n", dir_inode->data[i]);
1476 osErrno=E_GENERAL;
1477 return -1;
1478 }
1479 }
1480
1481 // b) partly filled sector
1482 if(remainder) {
1483 if(Disk_Read(dir_inode->data[group], inode_buffer) < 0){
1484 dprintf("... error: cant read sector %d\n", dir_inode->data[group]);
1485 osErrno=E_GENERAL;
1486 return -1;
1487 }
1488 strncpy((char*)buffer+group*SECTOR_SIZE, inode_buffer, remainder*sizeof(dirent_t));
1489 }
1490
1491 return dir_inode->size;
1492}