· 6 years ago · Nov 08, 2019, 06:24 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-1){ return 1; }
415
416 // Check if entries only contain allowed elements
417 for(int i=0; i < strlen(name);i++){
418 if(!(isalpha(name[i]) || isdigit(name[i]) ||
419 name[i] == '.' || name[i] == '_' || name[i] == '-' )){ return 1; }
420 }
421
422 return 0;
423}
424
425// return the child inode of the given file name 'fname' from the
426// parent inode; the parent inode is currently stored in the segment
427// of inode table in the cache (we cache only one disk sector for
428// this); once found, both cached_inode_sector and cached_inode_buffer
429// may be updated to point to the segment of inode table containing
430// the child inode; the function returns -1 if no such file is found;
431// it returns -2 is something else is wrong (such as parent is not
432// directory, or there's read error, etc.)
433static int find_child_inode(int parent_inode, char* fname,
434 int *cached_inode_sector, char* cached_inode_buffer)
435{
436 int cached_start_entry = ((*cached_inode_sector)-INODE_TABLE_START_SECTOR)*INODES_PER_SECTOR;
437 int offset = parent_inode-cached_start_entry;
438 assert(0 <= offset && offset < INODES_PER_SECTOR);
439 inode_t* parent = (inode_t*)(cached_inode_buffer+offset*sizeof(inode_t));
440 dprintf("... load parent inode: %d (size=%d, type=%d)\n",
441 parent_inode, parent->size, parent->type);
442 if(parent->type != 1) {
443 dprintf("... parent not a directory\n");
444 return -2;
445 }
446
447 int nentries = parent->size; // remaining number of directory entries
448 int idx = 0;
449 while(nentries > 0) {
450 char buf[SECTOR_SIZE]; // cached content of directory entries
451 if(Disk_Read(parent->data[idx], buf) < 0) return -2;
452 for(int i=0; i<DIRENTS_PER_SECTOR; i++) {
453 if(i>nentries) break;
454 if(!strcmp(((dirent_t*)buf)[i].fname, fname)) {
455 // found the file/directory; update inode cache
456 int child_inode = ((dirent_t*)buf)[i].inode;
457 dprintf("... found child_inode=%d\n", child_inode);
458 int sector = INODE_TABLE_START_SECTOR+child_inode/INODES_PER_SECTOR;
459 if(sector != (*cached_inode_sector)) {
460 *cached_inode_sector = sector;
461 if(Disk_Read(sector, cached_inode_buffer) < 0) return -2;
462 dprintf("... load inode table for child\n");
463 }
464 return child_inode;
465 }
466 }
467 idx++; nentries -= DIRENTS_PER_SECTOR;
468 }
469 dprintf("... could not find child inode\n");
470 return -1; // not found
471}
472
473// follow the absolute path; if successful, return the inode of the
474// parent directory immediately before the last file/directory in the
475// path; for example, for '/a/b/c/d.txt', the parent is '/a/b/c' and
476// the child is 'd.txt'; the child's inode is returned through the
477// parameter 'last_inode' and its file name is returned through the
478// parameter 'last_fname' (both are references); it's possible that
479// the last file/directory is not in its parent directory, in which
480// case, 'last_inode' points to -1; if the function returns -1, it
481// means that we cannot follow the path
482static int follow_path(char* path, int* last_inode, char* last_fname)
483{
484 if(!path) {
485 dprintf("... invalid path\n");
486 return -1;
487 }
488 if(path[0] != '/') {
489 dprintf("... '%s' not absolute path\n", path);
490 return -1;
491 }
492
493 // make a copy of the path (skip leading '/'); this is necessary
494 // since the path is going to be modified by strsep()
495 char pathstore[MAX_PATH];
496 strncpy(pathstore, path+1, MAX_PATH-1);
497 pathstore[MAX_PATH-1] = '\0'; // for safety
498 char* lpath = pathstore;
499
500 int parent_inode = -1, child_inode = 0; // start from root
501 // cache the disk sector containing the root inode
502 int cached_sector = INODE_TABLE_START_SECTOR;
503 char cached_buffer[SECTOR_SIZE];
504 if(Disk_Read(cached_sector, cached_buffer) < 0) return -1;
505 dprintf("... load inode table for root from disk sector %d\n", cached_sector);
506
507 // for each file/directory name separated by '/'
508 char* token;
509 while((token = strsep(&lpath, "/")) != NULL) {
510 dprintf("... process token: '%s'\n", token);
511 if(*token == '\0') continue; // multiple '/' ignored
512 if(illegal_filename(token)) {
513 dprintf("... illegal file name: '%s'\n", token);
514 return -1;
515 }
516 if(child_inode < 0) {
517 // regardless whether child_inode was not found previously, or
518 // there was issues related to the parent (say, not a
519 // directory), or there was a read error, we abort
520 dprintf("... parent inode can't be established\n");
521 return -1;
522 }
523 parent_inode = child_inode;
524 child_inode = find_child_inode(parent_inode, token,
525 &cached_sector, cached_buffer);
526 if(last_fname) strcpy(last_fname, token);
527 }
528 if(child_inode < -1) return -1; // if there was error, abort
529 else {
530 // there was no error, several possibilities:
531 // 1) '/': parent = -1, child = 0
532 // 2) '/valid-dirs.../last-valid-dir/not-found': parent=last-valid-dir, child=-1
533 // 3) '/valid-dirs.../last-valid-dir/found: parent=last-valid-dir, child=found
534 // in the first case, we set parent=child=0 as special case
535 if(parent_inode==-1 && child_inode==0) parent_inode = 0;
536 dprintf("... found parent_inode=%d, child_inode=%d\n", parent_inode, child_inode);
537 *last_inode = child_inode;
538 return parent_inode;
539 }
540}
541
542// add a new file or directory (determined by 'type') of given name
543// 'file' under parent directory represented by 'parent_inode'
544int add_inode(int type, int parent_inode, char* file)
545{
546 // get a new inode for child
547 int child_inode = bitmap_first_unused(INODE_BITMAP_START_SECTOR, INODE_BITMAP_SECTORS, INODE_BITMAP_SIZE);
548 if(child_inode < 0) {
549 dprintf("... error: inode table is full\n");
550 return -1;
551 }
552 dprintf("... new child inode %d\n", child_inode);
553
554 // load the disk sector containing the child inode
555 int inode_sector = INODE_TABLE_START_SECTOR+child_inode/INODES_PER_SECTOR;
556 char inode_buffer[SECTOR_SIZE];
557 if(Disk_Read(inode_sector, inode_buffer) < 0) return -1;
558 dprintf("... load inode table for child inode from disk sector %d\n", inode_sector);
559
560 // get the child inode
561 int inode_start_entry = (inode_sector-INODE_TABLE_START_SECTOR)*INODES_PER_SECTOR;
562 int offset = child_inode-inode_start_entry;
563 assert(0 <= offset && offset < INODES_PER_SECTOR);
564 inode_t* child = (inode_t*)(inode_buffer+offset*sizeof(inode_t));
565
566 // update the new child inode and write to disk
567 memset(child, 0, sizeof(inode_t));
568 child->type = type;
569 if(Disk_Write(inode_sector, inode_buffer) < 0) return -1;
570 dprintf("... update child inode %d (size=%d, type=%d), update disk sector %d\n",
571 child_inode, child->size, child->type, inode_sector);
572
573 // get the disk sector containing the parent inode
574 inode_sector = INODE_TABLE_START_SECTOR+parent_inode/INODES_PER_SECTOR;
575 if(Disk_Read(inode_sector, inode_buffer) < 0) return -1;
576 dprintf("... load inode table for parent inode %d from disk sector %d\n",
577 parent_inode, inode_sector);
578
579 // get the parent inode
580 inode_start_entry = (inode_sector-INODE_TABLE_START_SECTOR)*INODES_PER_SECTOR;
581 offset = parent_inode-inode_start_entry;
582 assert(0 <= offset && offset < INODES_PER_SECTOR);
583 inode_t* parent = (inode_t*)(inode_buffer+offset*sizeof(inode_t));
584 dprintf("... get parent inode %d (size=%d, type=%d)\n",
585 parent_inode, parent->size, parent->type);
586
587 // get the dirent sector
588 if(parent->type != 1) {
589 dprintf("... error: parent inode is not directory\n");
590 return -2; // parent not directory
591 }
592 int group = parent->size/DIRENTS_PER_SECTOR;
593 char dirent_buffer[SECTOR_SIZE];
594 if(group*DIRENTS_PER_SECTOR == parent->size) {
595 // new disk sector is needed
596 int newsec = bitmap_first_unused(SECTOR_BITMAP_START_SECTOR, SECTOR_BITMAP_SECTORS, SECTOR_BITMAP_SIZE);
597 if(newsec < 0) {
598 dprintf("... error: disk is full\n");
599 return -1;
600 }
601 parent->data[group] = newsec;
602 memset(dirent_buffer, 0, SECTOR_SIZE);
603 dprintf("... new disk sector %d for dirent group %d\n", newsec, group);
604 } else {
605 if(Disk_Read(parent->data[group], dirent_buffer) < 0)
606 return -1;
607 dprintf("... load disk sector %d for dirent group %d\n", parent->data[group], group);
608 }
609
610 // add the dirent and write to disk
611 int start_entry = group*DIRENTS_PER_SECTOR;
612 offset = parent->size-start_entry;
613 dirent_t* dirent = (dirent_t*)(dirent_buffer+offset*sizeof(dirent_t));
614 strncpy(dirent->fname, file, MAX_NAME);
615 dirent->inode = child_inode;
616 if(Disk_Write(parent->data[group], dirent_buffer) < 0) return -1;
617 dprintf("... append dirent %d (name='%s', inode=%d) to group %d, update disk sector %d\n",
618 parent->size, dirent->fname, dirent->inode, group, parent->data[group]);
619
620 // update parent inode and write to disk
621 parent->size++;
622 if(Disk_Write(inode_sector, inode_buffer) < 0) return -1;
623 dprintf("... update parent inode on disk sector %d\n", inode_sector);
624
625 return 0;
626}
627
628// used by both File_Create() and Dir_Create(); type=0 is file, type=1
629// is directory
630int create_file_or_directory(int type, char* pathname)
631{
632 int child_inode;
633 char last_fname[MAX_NAME];
634 int parent_inode = follow_path(pathname, &child_inode, last_fname);
635 if(parent_inode >= 0)
636 {
637 if(child_inode >= 0)
638 {
639 dprintf("... file/directory '%s' already exists, failed to create\n", pathname);
640 osErrno = E_CREATE;
641 return -1;
642 } else
643 {
644 if(add_inode(type, parent_inode, last_fname) >= 0)
645 {
646 dprintf("... successfully created file/directory: '%s'\n", pathname);
647 return 0;
648 }
649 else {
650 dprintf("... error: something wrong with adding child inode\n");
651 osErrno = E_CREATE;
652 return -1;
653 }
654 }
655 } else {
656 dprintf("... error: something wrong with the file/path: '%s'\n", pathname);
657 osErrno = E_CREATE;
658 return -1;
659 }
660}
661
662// remove the child from parent; the function is called by both
663// File_Unlink() and Dir_Unlink(); the function returns 0 if success,
664// -1 if general error, -2 if directory not empty, -3 if wrong type
665int remove_inode(int type, int parent_inode, int child_inode)
666{
667
668 dprintf("... remove inode %d\n", child_inode);
669
670 // load the disk sector containing the child inode
671 int inode_sector = INODE_TABLE_START_SECTOR+child_inode/INODES_PER_SECTOR;
672 char inode_buffer[SECTOR_SIZE];
673 if(Disk_Read(inode_sector, inode_buffer) < 0) return -1;
674 dprintf("... load inode table for child inode from disk sector %d\n", inode_sector);
675
676 // get the child inode
677 int inode_start_entry = (inode_sector-INODE_TABLE_START_SECTOR)*INODES_PER_SECTOR;
678 int offset = child_inode-inode_start_entry;
679 assert(0 <= offset && offset < INODES_PER_SECTOR);
680 inode_t* child = (inode_t*)(inode_buffer+offset*sizeof(inode_t));
681
682 // check for right type
683 if(child->type!=type){
684 dprintf("... error: the type parameter does not match the actual inode type\n");
685 return -3;
686 }
687
688 // check if child is non-empty directory
689 if(child->type==1 && child->size>0){
690 dprintf("... error: inode is non-empty directory\n");
691 return -2;
692 }
693
694 // get the disk sector containing the parent inode
695 inode_sector = INODE_TABLE_START_SECTOR+parent_inode/INODES_PER_SECTOR;
696 if(Disk_Read(inode_sector, inode_buffer) < 0) return -1;
697 dprintf("... load inode table for parent inode %d from disk sector %d\n",
698 parent_inode, inode_sector);
699
700 // get the parent inode
701 inode_start_entry = (inode_sector-INODE_TABLE_START_SECTOR)*INODES_PER_SECTOR;
702 offset = parent_inode-inode_start_entry;
703 assert(0 <= offset && offset < INODES_PER_SECTOR);
704 inode_t* parent = (inode_t*)(inode_buffer+offset*sizeof(inode_t));
705 dprintf("... get parent inode %d (size=%d, type=%d)\n",
706 parent_inode, parent->size, parent->type);
707
708 // check if parent is directory
709 if(parent->type != 1) {
710 dprintf("... error: parent inode is not directory\n");
711 return -3;
712 }
713
714 // check if parent is non-empty
715 if(parent->size < 1) {
716 dprintf("... error: parent directory has no entries\n");
717 return -1;
718 }
719
720 // reset bit of child inode in bitmap
721 if (bitmap_reset(INODE_BITMAP_START_SECTOR, INODE_BITMAP_SECTORS, child_inode) < 0) {
722 dprintf("... error: reset inode in bitmap unsuccessful\n");
723 return -1;
724 }
725
726 // check for remaining dirents from parent in that sector (otherwise reset sector bitmap)
727 int remainder = parent->size % DIRENTS_PER_SECTOR;
728 int group = parent->size/DIRENTS_PER_SECTOR;
729 if (remainder == 1) {
730 // disk sector has to be freed
731 if (bitmap_reset(SECTOR_BITMAP_START_SECTOR, SECTOR_BITMAP_SECTORS, parent->data[group]) < 0) {
732 dprintf("... error: free sector in bitmap unsuccessful\n");
733 return -1;
734 }
735 parent->data[group] = 0;
736 }
737
738 // delete the dirent and write to disk
739 char dirent_buffer[SECTOR_SIZE];
740 if(Disk_Read(parent->data[group], dirent_buffer) < 0) return -1;
741 dprintf("... load disk sector %d for dirent group %d\n", parent->data[group], group);
742 int start_entry = group*DIRENTS_PER_SECTOR;
743 offset = (parent->size-1)-start_entry;
744 dirent_t* dirent = (dirent_t*)(dirent_buffer+offset*sizeof(dirent_t));
745 memset(dirent->fname, 0, sizeof(dirent->fname));
746 dirent->inode = -1;
747 if(Disk_Write(parent->data[group], dirent_buffer) < 0) return -1;
748 dprintf("... delete dirent %d (inode=%d) from group %d, update disk sector %d\n",
749 parent->size, child_inode, group, parent->data[group]);
750
751 // update parent inode and write to disk
752 parent->size--;
753 if(Disk_Write(inode_sector, inode_buffer) < 0) return -1;
754 dprintf("... update parent inode on disk sector %d\n", inode_sector);
755
756 return 0;
757
758}
759
760// representing an open file
761typedef struct _open_file {
762 int inode; // pointing to the inode of the file (0 means entry not used)
763 int size; // file size cached here for convenience
764 int pos; // read/write position
765} open_file_t;
766static open_file_t open_files[MAX_OPEN_FILES];
767
768// return true if the file pointed to by inode has already been open
769int is_file_open(int inode)
770{
771 for(int i=0; i<MAX_OPEN_FILES; i++) {
772 if(open_files[i].inode == inode)
773 return 1;
774 }
775 return 0;
776}
777
778// return a new file descriptor not used; -1 if full
779int new_file_fd()
780{
781 for(int i=0; i<MAX_OPEN_FILES; i++) {
782 if(open_files[i].inode <= 0)
783 return i;
784 }
785 return -1;
786}
787
788/* end of internal helper functions, start of API functions */
789
790int FS_Boot(char* backstore_fname)
791{
792 dprintf("FS_Boot('%s'):\n", backstore_fname);
793 // initialize a new disk (this is a simulated disk)
794 if(Disk_Init() < 0) {
795 dprintf("... disk init failed\n");
796 osErrno = E_GENERAL;
797 return -1;
798 }
799 dprintf("... disk initialized\n");
800
801 // we should copy the filename down; if not, the user may change the
802 // content pointed to by 'backstore_fname' after calling this function
803 strncpy(bs_filename, backstore_fname, 1024);
804 bs_filename[1023] = '\0'; // for safety
805
806 // we first try to load disk from this file
807 if(Disk_Load(bs_filename) < 0) {
808 dprintf("... load disk from file '%s' failed\n", bs_filename);
809
810 // if we can't open the file; it means the file does not exist, we
811 // need to create a new file system on disk
812 if(diskErrno == E_OPENING_FILE) {
813 dprintf("... couldn't open file, create new file system\n");
814
815 // format superblock
816 char buf[SECTOR_SIZE];
817 memset(buf, 0, SECTOR_SIZE);
818 *(int*)buf = OS_MAGIC;
819 if(Disk_Write(SUPERBLOCK_START_SECTOR, buf) < 0) {
820 dprintf("... failed to format superblock\n");
821 osErrno = E_GENERAL;
822 return -1;
823 }
824 dprintf("... formatted superblock (sector %d)\n", SUPERBLOCK_START_SECTOR);
825
826 // format inode bitmap (reserve the first inode to root)
827 bitmap_init(INODE_BITMAP_START_SECTOR, INODE_BITMAP_SECTORS, 1);
828 dprintf("... formatted inode bitmap (start=%d, num=%d)\n",
829 (int)INODE_BITMAP_START_SECTOR, (int)INODE_BITMAP_SECTORS);
830
831 // format sector bitmap (reserve the first few sectors to
832 // superblock, inode bitmap, sector bitmap, and inode table)
833 bitmap_init(SECTOR_BITMAP_START_SECTOR, SECTOR_BITMAP_SECTORS,
834 DATABLOCK_START_SECTOR);
835 dprintf("... formatted sector bitmap (start=%d, num=%d)\n",
836 (int)SECTOR_BITMAP_START_SECTOR, (int)SECTOR_BITMAP_SECTORS);
837
838 // format inode tables
839 for(int i=0; i<INODE_TABLE_SECTORS; i++) {
840 memset(buf, 0, SECTOR_SIZE);
841 if(i==0) {
842 // the first inode table entry is the root directory
843 ((inode_t*)buf)->size = 0;
844 ((inode_t*)buf)->type = 1;
845 }
846 if(Disk_Write(INODE_TABLE_START_SECTOR+i, buf) < 0) {
847 dprintf("... failed to format inode table\n");
848 osErrno = E_GENERAL;
849 return -1;
850 }
851 }
852 dprintf("... formatted inode table (start=%d, num=%d)\n",
853 (int)INODE_TABLE_START_SECTOR, (int)INODE_TABLE_SECTORS);
854
855 // we need to synchronize the disk to the backstore file (so
856 // that we don't lose the formatted disk)
857 if(Disk_Save(bs_filename) < 0) {
858 // if can't write to file, something's wrong with the backstore
859 dprintf("... failed to save disk to file '%s'\n", bs_filename);
860 osErrno = E_GENERAL;
861 return -1;
862 } else {
863 // everything's good now, boot is successful
864 dprintf("... successfully formatted disk, boot successful\n");
865 memset(open_files, 0, MAX_OPEN_FILES*sizeof(open_file_t));
866 return 0;
867 }
868 } else {
869 // something wrong loading the file: invalid param or error reading
870 dprintf("... couldn't read file '%s', boot failed\n", bs_filename);
871 osErrno = E_GENERAL;
872 return -1;
873 }
874 } else {
875 dprintf("... load disk from file '%s' successful\n", bs_filename);
876
877 // we successfully loaded the disk, we need to do two more checks,
878 // first the file size must be exactly the size as expected (thiis
879 // supposedly should be folded in Disk_Load(); and it's not)
880 int sz = 0;
881 FILE* f = fopen(bs_filename, "r");
882 if(f) {
883 fseek(f, 0, SEEK_END);
884 sz = ftell(f);
885 fclose(f);
886 }
887 if(sz != SECTOR_SIZE*TOTAL_SECTORS) {
888 dprintf("... check size of file '%s' failed\n", bs_filename);
889 osErrno = E_GENERAL;
890 return -1;
891 }
892 dprintf("... check size of file '%s' successful\n", bs_filename);
893
894 // check magic
895 if(check_magic()) {
896 // everything's good by now, boot is successful
897 dprintf("... check magic successful\n");
898 memset(open_files, 0, MAX_OPEN_FILES*sizeof(open_file_t));
899 return 0;
900 } else {
901 // mismatched magic number
902 dprintf("... check magic failed, boot failed\n");
903 osErrno = E_GENERAL;
904 return -1;
905 }
906 }
907}
908
909int FS_Sync()
910{
911 if(Disk_Save(bs_filename) < 0) {
912 // if can't write to file, something's wrong with the backstore
913 dprintf("FS_Sync():\n... failed to save disk to file '%s'\n", bs_filename);
914 osErrno = E_GENERAL;
915 return -1;
916 } else {
917 // everything's good now, sync is successful
918 dprintf("FS_Sync():\n... successfully saved disk to file '%s'\n", bs_filename);
919 return 0;
920 }
921}
922
923int File_Create(char* file)
924{
925 dprintf("File_Create('%s'):\n", file);
926 return create_file_or_directory(0, file);
927}
928
929int File_Unlink(char* file)
930{
931 int child_inode;
932
933 int parent_inode = follow_path(file, &child_inode, NULL);
934
935
936 if(child_inode >= 0) //file exists
937 {
938 //check if file is open
939 if(is_file_open(child_inode)){
940 dprintf("... %s is an open file. Cannot unlink\n", file);
941 osErrno = E_FILE_IN_USE;
942 return -1;
943 }
944
945 int remove = remove_inode(0, parent_inode, child_inode);
946 if(remove == -1){
947 dprintf("... error: general error when unlinking file\n");
948 osErrno = E_GENERAL;
949 return -1;
950 }
951 else if(remove == -3){
952 dprintf("... error: no file, incorrect type\n");
953 osErrno = E_NO_SUCH_FILE;
954 return -1;
955 }
956 else{
957 return 0;
958 }
959
960 }
961
962 else{ //file does not exist
963 dprintf("... %s file does not exist\n", file);
964 osErrno = E_NO_SUCH_FILE;
965 return -1;
966
967 }
968}
969
970int File_Open(char* file)
971{
972 dprintf("File_Open('%s'):\n", file);
973 int fd = new_file_fd();
974 if(fd < 0) {
975 dprintf("... max open files reached\n");
976 osErrno = E_TOO_MANY_OPEN_FILES;
977 return -1;
978 }
979
980 int child_inode;
981 follow_path(file, &child_inode, NULL);
982 if(child_inode >= 0) { // child is the one
983 // load the disk sector containing the inode
984 int inode_sector = INODE_TABLE_START_SECTOR+child_inode/INODES_PER_SECTOR;
985 char inode_buffer[SECTOR_SIZE];
986 if(Disk_Read(inode_sector, inode_buffer) < 0) { osErrno = E_GENERAL; return -1; }
987 dprintf("... load inode table for inode from disk sector %d\n", inode_sector);
988
989 // get the inode
990 int inode_start_entry = (inode_sector-INODE_TABLE_START_SECTOR)*INODES_PER_SECTOR;
991 int offset = child_inode-inode_start_entry;
992 assert(0 <= offset && offset < INODES_PER_SECTOR);
993 inode_t* child = (inode_t*)(inode_buffer+offset*sizeof(inode_t));
994 dprintf("... inode %d (size=%d, type=%d)\n",
995 child_inode, child->size, child->type);
996
997 if(child->type != 0) {
998 dprintf("... error: '%s' is not a file\n", file);
999 osErrno = E_GENERAL;
1000 return -1;
1001 }
1002
1003 // initialize open file entry and return its index
1004 open_files[fd].inode = child_inode;
1005 open_files[fd].size = child->size;
1006 open_files[fd].pos = 0;
1007 return fd;
1008 } else {
1009 dprintf("... file '%s' is not found\n", file);
1010 osErrno = E_NO_SUCH_FILE;
1011 return -1;
1012 }
1013}
1014
1015int File_Read(int fd, void* buffer, int size)
1016{
1017 //check if fd is valid index
1018 if(fd < 0 || fd > MAX_OPEN_FILES){
1019 dprintf("... fd=%d out of bound", fd);
1020 osErrno = E_BAD_FD;
1021 return -1;
1022 }
1023
1024 open_file_t file = open_files[fd];
1025
1026 //check if not an open file
1027 if(file.inode <= 0){
1028 dprintf("... fd=%d not an open file\n", fd);
1029 osErrno = E_BAD_FD;
1030 return -1;
1031 }
1032 int position = file.pos;
1033 int remReadSize = 0;
1034
1035 //check if file size is empty
1036 if(file.size == 0)
1037 {
1038 //none to read
1039 return 0;
1040 }
1041
1042 //determine how many bytes to read
1043 if(file.size - position == 0)
1044 {
1045 //none to read
1046 return 0;
1047 }
1048 else{
1049 //if less than size is remaining, read only remaining
1050 //else pick size
1051 remReadSize = min(file.size - position, size);
1052
1053 }
1054 memset(buffer, 0, remReadSize);
1055
1056
1057 /***read contents of data blocks***/
1058
1059 //load file's inode disk sectors
1060 int inode = file.inode;
1061 int inode_sector = INODE_TABLE_START_SECTOR+inode/INODES_PER_SECTOR;
1062 char inode_buffer[SECTOR_SIZE];
1063 if(Disk_Read(inode_sector, inode_buffer) < 0) { osErrno = E_GENERAL; return -1; }
1064 dprintf("... load inode table for inode from disk sector %d\n", inode_sector);
1065
1066 //get inode
1067 int inode_start_entry = (inode_sector-INODE_TABLE_START_SECTOR)*INODES_PER_SECTOR;
1068 int offset = inode-inode_start_entry;
1069 assert(0 <= offset && offset < INODES_PER_SECTOR);
1070 inode_t* fileInode = (inode_t*)(inode_buffer+offset*sizeof(inode_t));
1071 dprintf("... inode %d (size=%d, type=%d)\n",
1072 inode, fileInode->size, fileInode->type);
1073
1074 //FILES_PER_SECTOR (SECTOR_SIZE/SIZEOF(open_file_t))
1075 int i = 0;
1076 //read data from given datablock pointers
1077 for(i = file.pos; i < remReadSize; i++){
1078 if(Disk_Read(fileInode->data[i], (char*)buffer+i*SECTOR_SIZE) < 0){
1079 dprintf("... error: cant read sector %d\n", fileInode->data[i]);
1080 osErrno=E_GENERAL;
1081 return -1;
1082 }
1083 }
1084
1085 File_Seek(fd, i);
1086
1087
1088 return remReadSize;
1089}
1090
1091int File_Write(int fd, void* buffer, int size)
1092{
1093 //check if fd is valid index
1094 if(fd < 0 || fd > MAX_OPEN_FILES){
1095 dprintf("... fd=%d out of bound", fd);
1096 osErrno = E_BAD_FD;
1097 return -1;
1098 }
1099
1100 open_file_t file = open_files[fd];
1101
1102 //check if not an open file
1103 if(file.inode <= 0){
1104 dprintf("... fd=%d not an open file\n", fd);
1105 osErrno = E_BAD_FD;
1106 return -1;
1107 }
1108
1109 //check if extra data doesn't go over max sectors per file
1110 if(file.pos + size > MAX_SECTORS_PER_FILE){
1111 dprintf("... fd=%d cannot add %d data sectors. No more space\n", fd, size);
1112 osErrno = E_FILE_TOO_BIG;
1113 }
1114
1115 //load file's inode disk sectors
1116 int inode = file.inode;
1117 int inode_sector = INODE_TABLE_START_SECTOR+inode/INODES_PER_SECTOR;
1118 char inode_buffer[SECTOR_SIZE];
1119 if(Disk_Read(inode_sector, inode_buffer) < 0) { osErrno = E_GENERAL; return -1; }
1120 dprintf("... load inode table for inode from disk sector %d\n", inode_sector);
1121
1122 //get inode
1123 int inode_start_entry = (inode_sector-INODE_TABLE_START_SECTOR)*INODES_PER_SECTOR;
1124 int offset = inode-inode_start_entry;
1125 assert(0 <= offset && offset < INODES_PER_SECTOR);
1126 inode_t* fileInode = (inode_t*)(inode_buffer+offset*sizeof(inode_t));
1127 dprintf("... inode %d (size=%d, type=%d)\n",
1128 inode, fileInode->size, fileInode->type);
1129
1130 //write data from after the last occupied data pointer
1131 int i = 0;
1132 for(i = file.pos; i < size; i++){
1133 if(Disk_Write(fileInode->data[i], (char*)buffer+i*SECTOR_SIZE) < 0) {
1134 dprintf("... failed to write buffer data\n");
1135 osErrno = E_GENERAL;
1136 return -1;
1137 }
1138 /***TODO: need to check if write cannot complete due to lack of space on disk. how?***/
1139 }
1140
1141 //set new read/write position
1142 File_Seek(fd, i);
1143
1144 return size;
1145}
1146
1147int File_Seek(int fd, int offset)
1148{
1149 //check if fd is valid index
1150 if(fd < 0 || fd > MAX_OPEN_FILES){
1151 dprintf("... fd=%d out of bound\n", fd);
1152 osErrno = E_BAD_FD;
1153 return -1;
1154 }
1155 //check if open file
1156 if(open_files[fd].inode <= 0) {
1157 dprintf("... fd=%d not an open file\n", fd);
1158 osErrno = E_BAD_FD;
1159 return -1;
1160 }
1161
1162 //check if offset is within bounds
1163 if(offset > open_files[fd].size || offset == -1){
1164 dprintf("... offset=%d out of bound\n", fd);
1165 osErrno = E_SEEK_OUT_OF_BOUNDS;
1166 return -1;
1167 }
1168
1169 open_files[fd].pos = offset;
1170
1171 return open_files[fd].pos;
1172}
1173
1174int File_Close(int fd)
1175{
1176 dprintf("File_Close(%d):\n", fd);
1177 if(0 > fd || fd > MAX_OPEN_FILES) {
1178 dprintf("... fd=%d out of bound\n", fd);
1179 osErrno = E_BAD_FD;
1180 return -1;
1181 }
1182 if(open_files[fd].inode <= 0) {
1183 dprintf("... fd=%d not an open file\n", fd);
1184 osErrno = E_BAD_FD;
1185 return -1;
1186 }
1187
1188
1189
1190 dprintf("... file closed successfully\n");
1191 open_files[fd].inode = 0;
1192 return 0;
1193}
1194
1195int Dir_Create(char* path)
1196{
1197 dprintf("Dir_Create('%s'):\n", path);
1198 return create_file_or_directory(1, path);
1199}
1200
1201int Dir_Unlink(char* path)
1202{
1203 // no empty path and no root directory allowed
1204 if(path==NULL) {
1205 dprintf("... error: empty path (NULL) for directory unlink");
1206 osErrno = E_GENERAL;
1207 return -1;
1208 }
1209
1210 if(strcmp(path, "/")==0) {
1211 dprintf("... error: not allowed to unlink root directory");
1212 osErrno = E_ROOT_DIR;
1213 return -1;
1214 }
1215
1216 // find parent and children (if theres any)
1217 int child_inode;
1218 int parent_inode = follow_path(path, &child_inode, NULL);
1219 if(parent_inode < 0) {
1220 dprintf("... error: directory '%s' not found\n", path);
1221 osErrno = E_NO_SUCH_DIR;
1222 return -1;
1223 }
1224
1225 int remove = remove_inode(1, parent_inode, child_inode);
1226
1227 if (remove==-1) {
1228 dprintf("... error: general error when unlinking directory\n");
1229 osErrno = E_GENERAL;
1230 return -1;
1231 } else if (remove==-3) {
1232 dprintf("... error: no directory, wrong type\n");
1233 osErrno = E_NO_SUCH_DIR;
1234 return -1;
1235 } else if (remove==-2) {
1236 dprintf("... error: directory %s not empty", path);
1237 osErrno = E_DIR_NOT_EMPTY;
1238 return -1;
1239 } else {
1240 return 0;
1241 }
1242
1243
1244}
1245
1246int Dir_Size(char* path)
1247{
1248 // no empty path allowed
1249 if(path==NULL) {
1250 dprintf("... error: empty path (NULL) given as parameter\n");
1251 osErrno = E_GENERAL;
1252 return -1;
1253 }
1254
1255 // directory has to exist
1256 int child_inode;
1257 int parent_inode = follow_path(path, &child_inode, NULL);
1258 if(parent_inode < 0) {
1259 dprintf("... error: directory '%s' not found\n", path);
1260 osErrno = E_NO_SUCH_DIR;
1261 return -1;
1262 }
1263
1264 // load the disk sector containing the child inode
1265 int inode_sector = INODE_TABLE_START_SECTOR+child_inode/INODES_PER_SECTOR;
1266 char inode_buffer[SECTOR_SIZE];
1267 if(Disk_Read(inode_sector, inode_buffer) < 0) return -1;
1268 dprintf("... load inode table for child inode from disk sector %d\n", inode_sector);
1269
1270 // get the child inode
1271 int inode_start_entry = (inode_sector-INODE_TABLE_START_SECTOR)*INODES_PER_SECTOR;
1272 int offset = child_inode-inode_start_entry;
1273 assert(0 <= offset && offset < INODES_PER_SECTOR);
1274 inode_t* child = (inode_t*)(inode_buffer+offset*sizeof(inode_t));
1275
1276 // check for type
1277 if (child->type!=1) {
1278 dprintf("... error: wrong type, path leads to file\n");
1279 osErrno = E_GENERAL;
1280 return -1;
1281 }
1282
1283 return child->size*sizeof(dirent_t);
1284}
1285
1286int Dir_Read(char* path, void* buffer, int size)
1287{
1288 int real_size = Dir_Size(path);
1289 if(real_size<0) return -1;
1290 if(real_size==0) return 0;
1291
1292 // check if size of buffer is large enough to hold all elements in the directory
1293 if (size<real_size) {
1294 osErrno=E_BUFFER_TOO_SMALL;
1295 return -1;
1296 }
1297
1298 // initialize buffer
1299 memset(buffer, 0, size);
1300
1301 // load disk sector from directory
1302 int inode;
1303 char inode_buffer[SECTOR_SIZE];
1304 int parent_inode=follow_path(path, &inode, NULL);
1305 if(parent_inode<0) return -1;
1306 int inode_sector = INODE_TABLE_START_SECTOR+inode/INODES_PER_SECTOR;
1307 if(Disk_Read(inode_sector, inode_buffer) < 0) return -1;
1308 dprintf("... load inode table for parent inode %d from disk sector %d\n",
1309 inode, inode_sector);
1310
1311 // get the parent inode
1312 int inode_start_entry = (inode_sector-INODE_TABLE_START_SECTOR)*INODES_PER_SECTOR;
1313 int offset = inode-inode_start_entry;
1314 assert(0 <= offset && offset < INODES_PER_SECTOR);
1315 inode_t* dir_inode = (inode_t*)(inode_buffer+offset*sizeof(inode_t));
1316 dprintf("... get inode %d (size=%d, type=%d)\n",
1317 inode, dir_inode->size, dir_inode->type);
1318
1319 // read the directory entries into the buffer
1320 int remainder=dir_inode->size%DIRENTS_PER_SECTOR;
1321 int group=dir_inode->size/DIRENTS_PER_SECTOR;
1322
1323 // a) completely filled sectors
1324 for(int i=0; i<group;i++) {
1325 if(Disk_Read(dir_inode->data[i], (char*)buffer+i*SECTOR_SIZE) < 0) {
1326 dprintf("... error: cant read sector %d\n", dir_inode->data[i]);
1327 osErrno=E_GENERAL;
1328 return -1;
1329 }
1330 }
1331
1332 // b) partly filled sector
1333 if(remainder) {
1334 if(Disk_Read(dir_inode->data[group], inode_buffer) < 0){
1335 dprintf("... error: cant read sector %d\n", dir_inode->data[group]);
1336 osErrno=E_GENERAL;
1337 return -1;
1338 }
1339 strncpy((char*)buffer+group*SECTOR_SIZE, inode_buffer, remainder*sizeof(dirent_t));
1340 }
1341
1342 return dir_inode->size;
1343}