· 6 years ago · Nov 08, 2019, 06:58 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 0
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#define CHARBITS (8) //number of bits in a char
120
121/*
122 The following functions were created by ehenl001@fiu to for bit manipulation
123*/
124static void set_bit(char *bitmap, int index)
125{
126 ( bitmap[(index/CHARBITS)] |= (1UL << (index % CHARBITS)));
127}
128
129static void clear_bit(char *bitmap, int index)
130{
131 ( bitmap[(index/CHARBITS)] &= ~(1UL << (index % CHARBITS)));
132}
133
134static int test_bit(char *bitmap, int index)
135{
136 return ( bitmap[(index/CHARBITS)] & (1UL << (index % CHARBITS))) > 0;
137}
138
139static int array_size(int numBits)
140{
141 return (numBits/CHARBITS+(!!(numBits%CHARBITS)));
142}
143
144// initialize a bitmap with 'num' sectors starting from 'start'
145// sector; all bits should be set to zero except that the first
146// 'nbits' number of bits are set to one
147static void bitmap_init(int start, int num, int nbits)
148{
149 /* YOUR CODE */
150 //create bitmap with size of arry of chars neccessary to support num bits
151 char *bitmap;
152 //get size of bit array in bytes
153 int size = array_size(num);
154 //allocate the neccessary bytes for the num size bitmap
155 bitmap = (char *)calloc(size, sizeof(char));
156
157 //initialize all bits to 0 (clear all bits)
158 for (int i = 0; i < num; i++)
159 {
160 clear_bit(bitmap,i);
161 }
162
163 //for nbits set the bit (bit = 1)
164 for (int i = 0; i < nbits; i++)
165 {
166 set_bit(bitmap,i);
167 }
168 //print all bits for testing
169 /*
170 for (int i = 0; i < num; i++)
171 {
172 printf("%d: %lu\n",i, test_bit(bitmap,i));
173 }
174 */
175 // check if bitmap will fit in one sector (SECTOR_SIZE > size(bitmap))
176 if(SECTOR_SIZE >= size)
177 {
178 //printf("SECTOR_SIZE >= size -> %d > %lu", SECTOR_SIZE, size);
179 if(Disk_Write(start, bitmap)<0)
180 {
181 dprintf("Error initializing bitmap");
182 }
183
184 }
185 else
186 {
187 //printf("size > SECTOR_SIZE -> %lu > %d", size, SECTOR_SIZE );
188 char buff[SECTOR_SIZE];
189 int toXfr = size;//track total bytes to write to disk
190 int numBytes = 0;
191
192 for (int i = 0; i<= size; i+=SECTOR_SIZE)
193 {
194 if(toXfr>SECTOR_SIZE)
195 {
196 numBytes = SECTOR_SIZE;
197 }
198 else
199 {
200 numBytes = toXfr;
201 }
202 memcpy(buff, &bitmap[i], numBytes);//copy to buff numBytes of bitmap
203 if(Disk_Write(start++, buff)<0)
204 {
205 dprintf("Error initializing bitmap");
206 }
207 toXfr = toXfr - numBytes;//update number of bytes remaining to write to disk
208
209 //for testing
210 /*
211 for(int y = 0; y < numBytes; y++)
212 {
213 printf("%d",buff[y]);
214 }
215
216 printf("\n");
217 printf("Copied %d bytes, %d remaining\n", numBytes, toXfr);
218 */
219 }
220 }
221 free(bitmap);
222}
223
224// set the first unused bit from a bitmap of 'nbits' bits (flip the
225// first zero appeared in the bitmap to one) and return its location;
226// return -1 if the bitmap is already full (no more zeros)
227static int bitmap_first_unused(int start, int num, int nbits)
228{
229 /* YOUR CODE */
230
231 char buff[SECTOR_SIZE];
232
233 //determine number of sectors the bitmap occupies
234 int secRemain = (nbits / CHARBITS)%SECTOR_SIZE;
235 int numSec = (nbits / CHARBITS)/SECTOR_SIZE;
236 int found = 0;
237 int firstUnused = -1;
238 if(secRemain)
239 {
240 numSec += 1;
241 }
242
243 //determine number of bytes needed to represent bitmap with nbits
244 int bmpARRLen = array_size(nbits);
245 int currSec = start;
246
247 //prep bitmap array
248 char *bitmap;
249 bitmap = (char*)calloc(bmpARRLen, sizeof(char));
250 int index = 0; //track index in bmp where next chunk from buff will be stored
251 int numBytes = bmpARRLen; //track remaining bytes to be copied to form complete bitmap
252 int bytesToCopy = -1;
253
254 for(int i = 0; i < numSec; i++)
255 {
256 //read each sector and build full bitmap
257 if(Disk_Read(currSec, buff) < 0) return -1;
258 //copy buff to bitmap
259 index = SECTOR_SIZE * i;
260 if(numBytes<=SECTOR_SIZE)
261 {
262 bytesToCopy = numBytes;
263 }
264 else
265 {
266 bytesToCopy = SECTOR_SIZE;
267 numBytes -= SECTOR_SIZE;
268 }
269 memcpy(&bitmap[index], buff, bytesToCopy);
270 }
271
272 //search for first bit equal to 0
273 for(int i =0; i < nbits; i++)
274 {
275 //if equal to 0 set bit and return i
276 if (test_bit(bitmap, i) == 0)
277 {
278 //set ith bit to 1
279 set_bit(bitmap, i);
280 found = 1;
281 firstUnused = i;
282 }
283 if(found) break;
284 }
285
286 //write new bit map to disk
287 numBytes = bmpARRLen;
288 currSec = start;
289 index = 0;
290 for(int i = 0; i < numSec; i++)
291 {
292 //check if remaining bytes to be copied (numBytes) is less than sector size
293 if(numBytes <= SECTOR_SIZE)
294 {
295 bytesToCopy = numBytes;
296 }
297 else
298 {
299 bytesToCopy = SECTOR_SIZE;
300 }
301 //copy from bitmap to buff
302 memcpy(buff, &bitmap[index], bytesToCopy);
303 //write to currSec full bitmap or part of full bitmap
304 if(Disk_Write(currSec, buff) < 0) return -1;
305 //update index, beginning of next section of bitmap to copy
306 index = SECTOR_SIZE * i;
307 //update remaining number of bytes needing to be written to disk
308 numBytes -= bytesToCopy;
309 }
310 //free allocated memory of bitmap
311 free(bitmap);
312
313 //if unused is found return its index, else return -1
314 if(found)
315 {
316 return firstUnused;
317 }
318 else
319 {
320 return -1;
321 }
322}
323
324// reset the i-th bit of a bitmap with 'num' sectors starting from
325// 'start' sector; return 0 if successful, -1 otherwise
326static int bitmap_reset(int start, int num, int ibit)
327{
328 /* YOUR CODE */
329 char buff[SECTOR_SIZE];
330 //determine bitmap length
331 int bmpARRLen = -1;
332
333 //check if num of bits is a multiple of 8, if there is a remainder then the neccessary length
334 //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)
335 bmpARRLen = array_size(num);
336
337 //initialize bitmap arrary with length equal to bmpARRLen
338 char *bitmap;
339
340 //allocate the neccessary bytes for the num size bitmap
341 bitmap = (char *)calloc(bmpARRLen, sizeof(char));
342
343 //determine number of sectors the bitmap occupies
344 int numSec = 1 + (num / CHARBITS)/SECTOR_SIZE;
345
346 //check if bitmap only occupies one sector
347 if(numSec == 1)
348 {
349 //bitmap only ooccupies one sector, read the bitmap from start sector
350 if(Disk_Read(start, buff) < 0) return -1;
351
352 //copy from buffer to bitmap
353 memcpy(bitmap, buff, bmpARRLen);
354
355 }
356 else
357 {
358 for(int i = 0; i < numSec; i++)
359 {
360 int secRd = start + i;
361 //read from sector
362 if(Disk_Read(secRd, buff) < 0) return -1;
363 //copy to bitmap
364 int index = i * SECTOR_SIZE;
365
366 memcpy(&bitmap[index], buff, SECTOR_SIZE);
367 }
368 }
369
370 if(test_bit(bitmap, ibit) == 0)
371 {
372 return -1;
373 }
374 else
375 {
376 clear_bit(bitmap, ibit);
377 }
378 //bytes to transfer from bitmap to buffer then write to disk
379 int toXfr = bmpARRLen;
380 //track num bytes to write to disk for each write to disk
381 int numBytes = -1;
382 //write bitmap to memory
383 for (int i = 0; i<= num; i+=SECTOR_SIZE)
384 {
385 if(toXfr>SECTOR_SIZE)//num bytes to write larger than sector size
386 {
387 numBytes = SECTOR_SIZE;
388 }
389 else
390 {
391 numBytes = toXfr;
392 }
393 memcpy(buff, &bitmap[i], numBytes);//copy to buff numBytes of bitmap
394 if(Disk_Write(start++, buff)<0)
395 {
396 dprintf("Error writing bitmap to disk");
397 return -1;
398 }
399 toXfr = toXfr - numBytes;//update number of bytes remaining to write to disk
400
401 }
402
403
404 return 0;
405}
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 if(Disk_Save(bs_filename) < 0) {
919 // if can't write to file, something's wrong with the backstore
920 dprintf("FS_Sync():\n... failed to save disk to file '%s'\n", bs_filename);
921 osErrno = E_GENERAL;
922 return -1;
923 } else {
924 // everything's good now, sync is successful
925 dprintf("FS_Sync():\n... successfully saved disk to file '%s'\n", bs_filename);
926 return 0;
927 }
928}
929
930int File_Create(char* file)
931{
932 dprintf("File_Create('%s'):\n", file);
933 if(!illegal_filename(file))
934 {
935 return create_file_or_directory(0, file);
936 }
937 osErrno = E_CREATE;
938 dprintf("...Illegal Filename in File_Create: %s\n", file);
939 return -1;
940}
941
942int File_Unlink(char* file)
943{
944 int child_inode;
945
946 int parent_inode = follow_path(file, &child_inode, NULL);
947
948
949 if(child_inode >= 0) //file exists
950 {
951 //check if file is open
952 if(is_file_open(child_inode)){
953 dprintf("... %s is an open file. Cannot unlink\n", file);
954 osErrno = E_FILE_IN_USE;
955 return -1;
956 }
957
958 int remove = remove_inode(0, parent_inode, child_inode);
959 if(remove == -1){
960 dprintf("... error: general error when unlinking file\n");
961 osErrno = E_GENERAL;
962 return -1;
963 }
964 else if(remove == -3){
965 dprintf("... error: no file, incorrect type\n");
966 osErrno = E_NO_SUCH_FILE;
967 return -1;
968 }
969 else{
970 return 0;
971 }
972
973 }
974
975 else{ //file does not exist
976 dprintf("... %s file does not exist\n", file);
977 osErrno = E_NO_SUCH_FILE;
978 return -1;
979
980 }
981}
982
983int File_Open(char* file)
984{
985 dprintf("File_Open('%s'):\n", file);
986 int fd = new_file_fd();
987 if(fd < 0) {
988 dprintf("... max open files reached\n");
989 osErrno = E_TOO_MANY_OPEN_FILES;
990 return -1;
991 }
992
993 int child_inode;
994 follow_path(file, &child_inode, NULL);
995 if(child_inode >= 0) { // child is the one
996 // load the disk sector containing the inode
997 int inode_sector = INODE_TABLE_START_SECTOR+child_inode/INODES_PER_SECTOR;
998 char inode_buffer[SECTOR_SIZE];
999 if(Disk_Read(inode_sector, inode_buffer) < 0) { osErrno = E_GENERAL; return -1; }
1000 dprintf("... load inode table for inode from disk sector %d\n", inode_sector);
1001
1002 // get the inode
1003 int inode_start_entry = (inode_sector-INODE_TABLE_START_SECTOR)*INODES_PER_SECTOR;
1004 int offset = child_inode-inode_start_entry;
1005 assert(0 <= offset && offset < INODES_PER_SECTOR);
1006 inode_t* child = (inode_t*)(inode_buffer+offset*sizeof(inode_t));
1007 dprintf("... inode %d (size=%d, type=%d)\n",
1008 child_inode, child->size, child->type);
1009
1010 if(child->type != 0) {
1011 dprintf("... error: '%s' is not a file\n", file);
1012 osErrno = E_GENERAL;
1013 return -1;
1014 }
1015
1016 // initialize open file entry and return its index
1017 open_files[fd].inode = child_inode;
1018 open_files[fd].size = child->size;
1019 open_files[fd].pos = 0;
1020 return fd;
1021 } else {
1022 dprintf("... file '%s' is not found\n", file);
1023 osErrno = E_NO_SUCH_FILE;
1024 return -1;
1025 }
1026}
1027
1028int File_Read(int fd, void* buffer, int size)
1029{
1030 //check if fd is valid index
1031 if(fd < 0 || fd > MAX_OPEN_FILES){
1032 dprintf("... fd=%d out of bound", fd);
1033 osErrno = E_BAD_FD;
1034 return -1;
1035 }
1036
1037 open_file_t file = open_files[fd];
1038
1039 //check if not an open file
1040 if(file.inode <= 0){
1041 dprintf("... fd=%d not an open file\n", fd);
1042 osErrno = E_BAD_FD;
1043 return -1;
1044 }
1045 int position = file.pos;
1046 int remReadSize = 0;
1047
1048 //check if file size is empty
1049 if(file.size == 0)
1050 {
1051 //none to read
1052 return 0;
1053 }
1054
1055 //determine how many bytes to read
1056 if(file.size - position == 0)
1057 {
1058 //none to read
1059 return 0;
1060 }
1061 else{
1062 //if less than size is remaining, read only remaining
1063 //else pick size
1064 remReadSize = min(file.size - position, size);
1065
1066 }
1067 memset(buffer, 0, remReadSize);
1068
1069
1070 /***read contents of data blocks***/
1071
1072 //load file's inode disk sectors
1073 int inode = file.inode;
1074 int inode_sector = INODE_TABLE_START_SECTOR+inode/INODES_PER_SECTOR;
1075 char inode_buffer[SECTOR_SIZE];
1076 if(Disk_Read(inode_sector, inode_buffer) < 0) { osErrno = E_GENERAL; return -1; }
1077 dprintf("... load inode table for inode from disk sector %d\n", inode_sector);
1078
1079 //get inode
1080 int inode_start_entry = (inode_sector-INODE_TABLE_START_SECTOR)*INODES_PER_SECTOR;
1081 int offset = inode-inode_start_entry;
1082 assert(0 <= offset && offset < INODES_PER_SECTOR);
1083 inode_t* fileInode = (inode_t*)(inode_buffer+offset*sizeof(inode_t));
1084 dprintf("... inode %d (size=%d, type=%d)\n",
1085 inode, fileInode->size, fileInode->type);
1086
1087 //FILES_PER_SECTOR (SECTOR_SIZE/SIZEOF(open_file_t))
1088 int i = 0;
1089 //read data from given datablock pointers
1090 for(i = file.pos; i < remReadSize; i++){
1091 if(Disk_Read(fileInode->data[i], (char*)buffer+i*SECTOR_SIZE) < 0){
1092 dprintf("... error: cant read sector %d\n", fileInode->data[i]);
1093 osErrno=E_GENERAL;
1094 return -1;
1095 }
1096 }
1097
1098 File_Seek(fd, i);
1099
1100
1101 return remReadSize;
1102}
1103
1104int File_Write(int fd, void* buffer, int size)
1105{
1106 //check if fd is valid index
1107 if(fd < 0 || fd > MAX_OPEN_FILES){
1108 dprintf("... fd=%d out of bound", fd);
1109 osErrno = E_BAD_FD;
1110 return -1;
1111 }
1112
1113 open_file_t file = open_files[fd];
1114
1115 //check if not an open file
1116 if(file.inode <= 0){
1117 dprintf("... fd=%d not an open file\n", fd);
1118 osErrno = E_BAD_FD;
1119 return -1;
1120 }
1121
1122 //check if extra data doesn't go over max sectors per file
1123 if(file.pos + size > MAX_SECTORS_PER_FILE){
1124 dprintf("... fd=%d cannot add %d data sectors. No more space\n", fd, size);
1125 osErrno = E_FILE_TOO_BIG;
1126 }
1127
1128 //load file's inode disk sectors
1129 int inode = file.inode;
1130 int inode_sector = INODE_TABLE_START_SECTOR+inode/INODES_PER_SECTOR;
1131 char inode_buffer[SECTOR_SIZE];
1132 if(Disk_Read(inode_sector, inode_buffer) < 0) { osErrno = E_GENERAL; return -1; }
1133 dprintf("... load inode table for inode from disk sector %d\n", inode_sector);
1134
1135 //get inode
1136 int inode_start_entry = (inode_sector-INODE_TABLE_START_SECTOR)*INODES_PER_SECTOR;
1137 int offset = inode-inode_start_entry;
1138 assert(0 <= offset && offset < INODES_PER_SECTOR);
1139 inode_t* fileInode = (inode_t*)(inode_buffer+offset*sizeof(inode_t));
1140 dprintf("... inode %d (size=%d, type=%d)\n",
1141 inode, fileInode->size, fileInode->type);
1142
1143 //write data from after the last occupied data pointer
1144 int i = 0;
1145 for(i = file.pos; i < size; i++){
1146 if(Disk_Write(fileInode->data[i], (char*)buffer+i*SECTOR_SIZE) < 0) {
1147 dprintf("... failed to write buffer data\n");
1148 osErrno = E_GENERAL;
1149 return -1;
1150 }
1151 /***TODO: need to check if write cannot complete due to lack of space on disk. how?***/
1152 }
1153
1154 //set new read/write position
1155 File_Seek(fd, i);
1156
1157 return size;
1158}
1159
1160int File_Seek(int fd, int offset)
1161{
1162 //check if fd is valid index
1163 if(fd < 0 || fd > MAX_OPEN_FILES){
1164 dprintf("... fd=%d out of bound\n", fd);
1165 osErrno = E_BAD_FD;
1166 return -1;
1167 }
1168 //check if open file
1169 if(open_files[fd].inode <= 0) {
1170 dprintf("... fd=%d not an open file\n", fd);
1171 osErrno = E_BAD_FD;
1172 return -1;
1173 }
1174
1175 //check if offset is within bounds
1176 if(offset > open_files[fd].size || offset == -1){
1177 dprintf("... offset=%d out of bound\n", fd);
1178 osErrno = E_SEEK_OUT_OF_BOUNDS;
1179 return -1;
1180 }
1181
1182 open_files[fd].pos = offset;
1183
1184 return open_files[fd].pos;
1185}
1186
1187int File_Close(int fd)
1188{
1189 dprintf("File_Close(%d):\n", fd);
1190 if(0 > fd || fd > MAX_OPEN_FILES) {
1191 dprintf("... fd=%d out of bound\n", fd);
1192 osErrno = E_BAD_FD;
1193 return -1;
1194 }
1195 if(open_files[fd].inode <= 0) {
1196 dprintf("... fd=%d not an open file\n", fd);
1197 osErrno = E_BAD_FD;
1198 return -1;
1199 }
1200
1201
1202
1203 dprintf("... file closed successfully\n");
1204 open_files[fd].inode = 0;
1205 return 0;
1206}
1207
1208int Dir_Create(char* path)
1209{
1210 dprintf("Dir_Create('%s'):\n", path);
1211 return create_file_or_directory(1, path);
1212}
1213
1214int Dir_Unlink(char* path)
1215{
1216 // no empty path and no root directory allowed
1217 if(path==NULL) {
1218 dprintf("... error: empty path (NULL) for directory unlink");
1219 osErrno = E_GENERAL;
1220 return -1;
1221 }
1222
1223 if(strcmp(path, "/")==0) {
1224 dprintf("... error: not allowed to unlink root directory");
1225 osErrno = E_ROOT_DIR;
1226 return -1;
1227 }
1228
1229 // find parent and children (if theres any)
1230 int child_inode;
1231 int parent_inode = follow_path(path, &child_inode, NULL);
1232 if(parent_inode < 0) {
1233 dprintf("... error: directory '%s' not found\n", path);
1234 osErrno = E_NO_SUCH_DIR;
1235 return -1;
1236 }
1237
1238 int remove = remove_inode(1, parent_inode, child_inode);
1239
1240 if (remove==-1) {
1241 dprintf("... error: general error when unlinking directory\n");
1242 osErrno = E_GENERAL;
1243 return -1;
1244 } else if (remove==-3) {
1245 dprintf("... error: no directory, wrong type\n");
1246 osErrno = E_NO_SUCH_DIR;
1247 return -1;
1248 } else if (remove==-2) {
1249 dprintf("... error: directory %s not empty", path);
1250 osErrno = E_DIR_NOT_EMPTY;
1251 return -1;
1252 } else {
1253 return 0;
1254 }
1255
1256
1257}
1258
1259int Dir_Size(char* path)
1260{
1261 // no empty path allowed
1262 if(path==NULL) {
1263 dprintf("... error: empty path (NULL) given as parameter\n");
1264 osErrno = E_GENERAL;
1265 return -1;
1266 }
1267
1268 // directory has to exist
1269 int child_inode;
1270 int parent_inode = follow_path(path, &child_inode, NULL);
1271 if(parent_inode < 0) {
1272 dprintf("... error: directory '%s' not found\n", path);
1273 osErrno = E_NO_SUCH_DIR;
1274 return -1;
1275 }
1276
1277 // load the disk sector containing the child inode
1278 int inode_sector = INODE_TABLE_START_SECTOR+child_inode/INODES_PER_SECTOR;
1279 char inode_buffer[SECTOR_SIZE];
1280 if(Disk_Read(inode_sector, inode_buffer) < 0) return -1;
1281 dprintf("... load inode table for child inode from disk sector %d\n", inode_sector);
1282
1283 // get the child inode
1284 int inode_start_entry = (inode_sector-INODE_TABLE_START_SECTOR)*INODES_PER_SECTOR;
1285 int offset = child_inode-inode_start_entry;
1286 assert(0 <= offset && offset < INODES_PER_SECTOR);
1287 inode_t* child = (inode_t*)(inode_buffer+offset*sizeof(inode_t));
1288
1289 // check for type
1290 if (child->type!=1) {
1291 dprintf("... error: wrong type, path leads to file\n");
1292 osErrno = E_GENERAL;
1293 return -1;
1294 }
1295
1296 return child->size*sizeof(dirent_t);
1297}
1298
1299int Dir_Read(char* path, void* buffer, int size)
1300{
1301 int real_size = Dir_Size(path);
1302 if(real_size<0) return -1;
1303 if(real_size==0) return 0;
1304
1305 // check if size of buffer is large enough to hold all elements in the directory
1306 if (size<real_size) {
1307 osErrno=E_BUFFER_TOO_SMALL;
1308 return -1;
1309 }
1310
1311 // initialize buffer
1312 memset(buffer, 0, size);
1313
1314 // load disk sector from directory
1315 int inode;
1316 char inode_buffer[SECTOR_SIZE];
1317 int parent_inode=follow_path(path, &inode, NULL);
1318 if(parent_inode<0) return -1;
1319 int inode_sector = INODE_TABLE_START_SECTOR+inode/INODES_PER_SECTOR;
1320 if(Disk_Read(inode_sector, inode_buffer) < 0) return -1;
1321 dprintf("... load inode table for parent inode %d from disk sector %d\n",
1322 inode, inode_sector);
1323
1324 // get the parent inode
1325 int inode_start_entry = (inode_sector-INODE_TABLE_START_SECTOR)*INODES_PER_SECTOR;
1326 int offset = inode-inode_start_entry;
1327 assert(0 <= offset && offset < INODES_PER_SECTOR);
1328 inode_t* dir_inode = (inode_t*)(inode_buffer+offset*sizeof(inode_t));
1329 dprintf("... get inode %d (size=%d, type=%d)\n",
1330 inode, dir_inode->size, dir_inode->type);
1331
1332 // read the directory entries into the buffer
1333 int remainder=dir_inode->size%DIRENTS_PER_SECTOR;
1334 int group=dir_inode->size/DIRENTS_PER_SECTOR;
1335
1336 // a) completely filled sectors
1337 for(int i=0; i<group;i++) {
1338 if(Disk_Read(dir_inode->data[i], (char*)buffer+i*SECTOR_SIZE) < 0) {
1339 dprintf("... error: cant read sector %d\n", dir_inode->data[i]);
1340 osErrno=E_GENERAL;
1341 return -1;
1342 }
1343 }
1344
1345 // b) partly filled sector
1346 if(remainder) {
1347 if(Disk_Read(dir_inode->data[group], inode_buffer) < 0){
1348 dprintf("... error: cant read sector %d\n", dir_inode->data[group]);
1349 osErrno=E_GENERAL;
1350 return -1;
1351 }
1352 strncpy((char*)buffer+group*SECTOR_SIZE, inode_buffer, remainder*sizeof(dirent_t));
1353 }
1354
1355 return dir_inode->size;
1356}