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