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