· 6 years ago · Nov 27, 2019, 09:30 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 <malloc.h>
8#include "LibDisk.h"
9#include "LibFS.h"
10
11// set to 1 to have detailed debug print-outs and 0 to have none
12#define FSDEBUG 1
13
14#if FSDEBUG
15#define dprintf printf
16#else
17#define dprintf noprintf
18void noprintf(char* str, ...) {}
19#endif
20
21// the file system partitions the disk into five parts:
22
23// 1. the superblock (one sector), which contains a magic number at
24// its first four bytes (integer)
25#define SUPERBLOCK_START_SECTOR 0
26
27// the magic number chosen for our file system
28#define OS_MAGIC 0xdeadbeef
29
30// 2. the inode bitmap (one or more sectors), which indicates whether
31// the particular entry in the inode table (#4) is currently in use
32#define INODE_BITMAP_START_SECTOR 1
33
34// the total number of bytes and sectors needed for the inode bitmap;
35// we use one bit for each inode (whether it's a file or directory) to
36// indicate whether the particular inode in the inode table is in use
37#define INODE_BITMAP_SIZE ((MAX_FILES+7)/8)
38#define INODE_BITMAP_SECTORS ((INODE_BITMAP_SIZE+SECTOR_SIZE-1)/SECTOR_SIZE)
39
40// 3. the sector bitmap (one or more sectors), which indicates whether
41// the particular sector in the disk is currently in use
42#define SECTOR_BITMAP_START_SECTOR (INODE_BITMAP_START_SECTOR+INODE_BITMAP_SECTORS)
43
44// the total number of bytes and sectors needed for the data block
45// bitmap (we call it the sector bitmap); we use one bit for each
46// sector of the disk to indicate whether the sector is in use or not
47#define SECTOR_BITMAP_SIZE ((TOTAL_SECTORS+7)/8)
48#define SECTOR_BITMAP_SECTORS ((SECTOR_BITMAP_SIZE+SECTOR_SIZE-1)/SECTOR_SIZE)
49
50// 4. the inode table (one or more sectors), which contains the inodes
51// stored consecutively
52#define INODE_TABLE_START_SECTOR (SECTOR_BITMAP_START_SECTOR+SECTOR_BITMAP_SECTORS)
53
54// an inode is used to represent each file or directory; the data
55// structure supposedly contains all necessary information about the
56// corresponding file or directory
57typedef struct _inode {
58 int size; // the size of the file or number of directory entries
59 int type; // 0 means regular file; 1 means directory
60 int data[MAX_SECTORS_PER_FILE]; // indices to sectors containing data blocks
61} inode_t;
62
63// the inode structures are stored consecutively and yet they don't
64// straddle accross the sector boundaries; that is, there may be
65// fragmentation towards the end of each sector used by the inode
66// table; each entry of the inode table is an inode structure; there
67// are as many entries in the table as the number of files allowed in
68// the system; the inode bitmap (#2) indicates whether the entries are
69// current in use or not
70#define INODES_PER_SECTOR (SECTOR_SIZE/sizeof(inode_t))
71#define INODE_TABLE_SECTORS ((MAX_FILES+INODES_PER_SECTOR-1)/INODES_PER_SECTOR)
72
73// 5. the data blocks; all the rest sectors are reserved for data
74// blocks for the content of files and directories
75#define DATABLOCK_START_SECTOR (INODE_TABLE_START_SECTOR+INODE_TABLE_SECTORS)
76
77// other file related definitions
78
79// max length of a path is 256 bytes (including the ending null)
80#define MAX_PATH 256
81
82// max length of a filename is 16 bytes (including the ending null)
83#define MAX_NAME 16
84
85// max number of open files is 256
86#define MAX_OPEN_FILES 256
87
88// each directory entry represents a file/directory in the parent
89// directory, and consists of a file/directory name (less than 16
90// bytes) and an integer inode number
91typedef struct _dirent {
92 char fname[MAX_NAME]; // name of the file
93 int inode; // inode of the file
94} dirent_t;
95
96// the number of directory entries that can be contained in a sector
97#define DIRENTS_PER_SECTOR (SECTOR_SIZE/sizeof(dirent_t))
98
99// global errno value here
100int osErrno;
101
102// the name of the disk backstore file (with which the file system is booted)
103static char bs_filename[1024];
104
105/* the following functions are internal helper functions */
106//find min
107int min(int num1, int num2){
108 return (num1 > num2) ? num2 : num1;
109}
110
111// check magic number in the superblock; return 1 if OK, and 0 if not
112static int check_magic()
113{
114 char buf[SECTOR_SIZE];
115 if(Disk_Read(SUPERBLOCK_START_SECTOR, buf) < 0)
116 return 0;
117 if(*(int*)buf == OS_MAGIC) return 1;
118 else return 0;
119}
120
121#define CHARBITS (8) //number of bits in a char
122
123/*
124 The following functions were created by ehenl001@fiu to for bit manipulation
125*/
126static void set_bit(char *bitmap, int index)
127{
128 ( bitmap[(index/CHARBITS)] |= (1UL << (index % CHARBITS)));
129}
130
131static void clear_bit(char *bitmap, int index)
132{
133 ( bitmap[(index/CHARBITS)] &= ~(1UL << (index % CHARBITS)));
134}
135
136static int test_bit(char *bitmap, int index)
137{
138 return ( bitmap[(index/CHARBITS)] & (1UL << (index % CHARBITS))) > 0;
139}
140
141void yellow(){printf("\033[0;33m");};
142void boldYellow(){printf("\033[1m\033[33m");};
143void blue(){printf("\033[0;34m");};
144void boldBlue(){printf("\033[1m\033[34m");};
145void green(){printf("\033[0;32m");};
146void boldGreen(){printf("\033[1m\033[32m");};
147void red(){printf("\033[0;31m");}
148void boldRed(){printf("\033[1m\033[31m");};
149void reset(){printf("\033[0m");};
150// initialize a bitmap with 'num' sectors starting from 'start'
151// sector; all bits should be set to zero except that the first
152// 'nbits' number of bits are set to one
153// type for inode bitmap sector = 0
154// type for sector bitmap sector = 1
155static void bitmap_init(int start, int num, int nbits, int type)
156{
157 /* YOUR CODE */
158 green();
159 dprintf("bitmap_init(%d, %d, %d)\n",start, num, nbits);
160 reset();
161
162 //create bitmap with size of arry of chars neccessary to support num bits
163 char *bitmap;
164
165 //if type then bitmap sector, else inode sector, assign size appropriately
166 int size = -1;
167 if(type){
168 size = SECTOR_BITMAP_SIZE;
169 }else{
170 size = INODE_BITMAP_SIZE;
171 }
172 //allocate the neccessary bytes for the num size bitmap
173 bitmap = (char *)calloc(size, sizeof(char));
174
175 //initialize all bits to 0 (clear all bits)
176 for (int i = 0; i < num; i++)
177 {
178 clear_bit(bitmap,i);
179 }
180
181 //for nbits set the bit (bit = 1)
182 for (int i = 0; i < nbits; i++)
183 {
184 set_bit(bitmap,i);
185 }
186
187 //set the bits of the sector that thec current bitmap occupies
188 for(int i = start; i < start + num; i++) set_bit(bitmap, i);
189
190 // check if bitmap will fit in one sector (SECTOR_SIZE > size(bitmap))
191 if(SECTOR_SIZE >= size)
192 {
193
194 if(Disk_Write(start, bitmap)<0)
195 {
196 green();
197 dprintf("---> Error initializing bitmap, func=bitmap_init\n");
198 reset();
199 }
200 else{
201 green();
202 dprintf("---> bitmap wrote to disk successfully using 1 sector to store, func=bitmap_init\n");
203 reset();
204 }
205
206
207 }
208 else
209 {
210 int toXfr = size;//track total bytes to write to disk
211 int numBytes = 0;
212 int i = -1;
213 int numSectorUsed = 0;
214
215 for (i = 0; i<= size; i+=SECTOR_SIZE)
216 {
217 char buff[SECTOR_SIZE];
218 if(toXfr>SECTOR_SIZE)
219 {
220 numBytes = SECTOR_SIZE;
221 }
222 else
223 {
224 numBytes = toXfr;
225 }
226 //copy to buff numBytes of bitmap
227 if( memcpy(buff, &bitmap[i], numBytes)==NULL){dprintf("error with bitmap copy\n");}
228
229 if(Disk_Write(start++, buff)<0)
230 {
231 green();
232 dprintf("---> Error initializing bitmap\n");
233 reset();
234 }
235 numSectorUsed +=1;
236 bzero(buff, SECTOR_SIZE);
237 toXfr = toXfr - numBytes;//update number of bytes remaining to write to disk
238
239 }
240 green();
241 dprintf("---> bitmap written to disk using %d sectors to store on disk, func=bitmap_init\n", numSectorUsed);
242 reset();
243 }
244 free(bitmap);
245 green();
246 dprintf("---> mem freed for bitmap, func=bitmap_init\n");
247 reset();
248}
249
250// set the first unused bit from a bitmap of 'nbits' bits (flip the
251// first zero appeared in the bitmap to one) and return its location;
252// return -1 if the bitmap is already full (no more zeros)
253static int bitmap_first_unused(int start, int num, int nbits)
254{
255 /* YOUR CODE */
256
257 green();
258 dprintf("bitmap_first_unused(%d, %d, %d)\n", start, num, nbits);
259 reset();
260 int numSec = num;
261 int found = 0;
262 int firstUnused = -1;
263
264 //determine number of bytes needed to represent bitmap with nbits
265 int bmpARRLen = nbits;
266 int currSec = start;
267
268 //get number of bits represented by bmp
269 int bits;
270 if (start == INODE_BITMAP_START_SECTOR){
271 bits = 1000;
272 }else{
273 bits = 10000;
274 }
275
276 //prep bitmap array
277 char *bitmap;
278 bitmap = (char*)calloc(bmpARRLen, sizeof(char));
279 bzero(bitmap,bmpARRLen);
280
281 int index = 0; //track index in bmp where next chunk from buff will be stored
282 int numBytes = bmpARRLen; //track remaining bytes to be copied to form complete bitmap
283 int bytesToCopy = -1;
284 int indexCount = 0;
285
286 //read bitmap from disk
287 for(int i = 0; i < numSec; i++)
288 {
289 char buff[SECTOR_SIZE];
290 //read each sector and build full bitmap
291 if(Disk_Read(currSec, buff) < 0) return -1;
292 //copy buff to bitmap
293 index = SECTOR_SIZE * i;
294
295 if(numBytes<=SECTOR_SIZE)
296 {
297 bytesToCopy = numBytes;
298 }
299 else
300 {
301 bytesToCopy = SECTOR_SIZE;
302 numBytes -= SECTOR_SIZE;
303 }
304
305 for(int j = 0; j<numBytes; j++){
306 bitmap[indexCount++] = buff[j];
307 }
308 bzero(buff, SECTOR_SIZE);
309 currSec++;
310 }
311
312 //search for first bit equal to 0
313 for(int i =0; i < bits; i++)
314 {
315 //if equal to 0 set bit and return i
316 if (test_bit(bitmap, i) == 0)
317 {
318 //set ith bit to 1
319 green();
320 dprintf("---> attempting to set bit %d\n", i);
321 reset();
322 set_bit(bitmap, i);
323 found = 1;
324 firstUnused = i;
325 }
326 if(found) break;
327 }
328 //write new bit map to disk
329 numBytes = bmpARRLen;
330 currSec = start;
331 index = 0;
332 for(int i = 0; i < numSec; i++)
333 {
334 char buff[SECTOR_SIZE];
335 //update index, beginning of next section of bitmap to copy
336 index = SECTOR_SIZE * i;
337 //check if remaining bytes to be copied (numBytes) is less than sector size
338 if(numBytes <= SECTOR_SIZE)
339 {
340 bytesToCopy = numBytes;
341 }
342 else
343 {
344 bytesToCopy = SECTOR_SIZE;
345 }
346 //copy from bitmap to buff
347 memcpy(buff, &bitmap[index], bytesToCopy);
348 //write to currSec full bitmap or part of full bitmap
349 if(Disk_Write(currSec, buff) < 0) return -1;
350
351 currSec++;
352
353 bzero(buff, SECTOR_SIZE);
354 //update remaining number of bytes needing to be written to disk
355 numBytes -= bytesToCopy;
356 }
357 //free allocated memory of bitmap
358 free(bitmap);
359 //check if bitmap corrupted
360 if(found ==0 && start==SECTOR_BITMAP_START_SECTOR){
361 green();
362 dprintf("---> error bitmap corrupted superblock sector found as first unused\n");
363 reset();
364 return -1;
365 }
366
367 //if unused is found return its index, else return -1
368 if(found)
369 {
370 green();
371 dprintf("---> found first unused bit in nbytes=%d bmp at index=%d\n", nbits, firstUnused);
372 reset();
373 return firstUnused;
374 }
375 else
376 {
377 green();
378 dprintf("---> unused bit NOT FOUND in nbytes=%d bmp\n", nbits);
379 reset();
380 return -1;
381 }
382}
383
384// reset the i-th bit of a bitmap with 'num' sectors starting from
385// 'start' sector; return 0 if successful, -1 otherwise
386// reset the i-th bit of a bitmap with 'num' sectors starting from
387// 'start' sector; return 0 if successful, -1 otherwise
388static int bitmap_reset(int start, int num, int ibit)
389{
390 /* YOUR CODE */
391 green();
392 dprintf("bitmap_reset(%d, %d, %d)\n", start, num, ibit);
393 reset();
394 if((start==SECTOR_BITMAP_START_SECTOR) && ((ibit == 0)||(ibit == 1) ||(ibit == 2) || (ibit == 3)||(ibit == 4))){
395 green();
396 dprintf("---> error attempting to over critical sector=%d\n", ibit);
397 dprintf("---> exiting bitmap_reset UNSUCCESSFULLY\n");
398 reset();
399 return -1;
400 }
401 int numSec = num;
402 //determine number of bytes needed to represent bitmap with nbits
403 int bmpARRLen = -1;
404 if (start == INODE_BITMAP_START_SECTOR){
405 bmpARRLen = INODE_BITMAP_SIZE;
406 }else{
407 bmpARRLen = SECTOR_BITMAP_SIZE;
408 }
409 int currSec = start;
410
411 //prep bitmap array
412 char *bitmap;
413 bitmap = (char*)calloc(bmpARRLen, sizeof(char));
414 bzero(bitmap,bmpARRLen);
415
416 int index = 0; //track index in bmp where next chunk from buff will be stored
417 int numBytes = bmpARRLen; //track remaining bytes to be copied to form complete bitmap
418 int bytesToCopy = -1;
419 int indexCount = 0;
420
421 //read bitmap from disk
422 for(int i = 0; i < numSec; i++)
423 {
424 char buff[SECTOR_SIZE];
425 //read each sector and build full bitmap
426 if(Disk_Read(currSec, buff) < 0) return -1;
427 //copy buff to bitmap
428 index = SECTOR_SIZE * i;
429 if(numBytes<=SECTOR_SIZE)
430 {
431 bytesToCopy = numBytes;
432 }
433 else
434 {
435 bytesToCopy = SECTOR_SIZE;
436 numBytes -= SECTOR_SIZE;
437 }
438
439 for(int j = 0; j<numBytes; j++){
440 bitmap[indexCount++] = buff[j];
441 }
442 bzero(buff, SECTOR_SIZE);
443 currSec++;
444 }
445 //checkt if ibit already clear if not clear
446 if(test_bit(bitmap, ibit) == 0){
447 green();
448 dprintf("---> error bit already clear\n");
449 reset();
450 return -1;
451 }else{
452 clear_bit(bitmap, ibit);
453 }
454 //write new bit map to disk
455 numBytes = bmpARRLen;
456 currSec = start;
457 index = 0;
458 for(int i = 0; i < numSec; i++)
459 {
460 char buff[SECTOR_SIZE];
461 //update index, beginning of next section of bitmap to copy
462 index = SECTOR_SIZE * i;
463 //check if remaining bytes to be copied (numBytes) is less than sector size
464 if(numBytes <= SECTOR_SIZE)
465 {
466 bytesToCopy = numBytes;
467 }
468 else
469 {
470 bytesToCopy = SECTOR_SIZE;
471 }
472 //copy from bitmap to buff
473 memcpy(buff, &bitmap[index], bytesToCopy);
474 //write to currSec full bitmap or part of full bitmap
475 if(Disk_Write(currSec, buff) < 0) return -1;
476 currSec++;
477
478 bzero(buff, SECTOR_SIZE);
479 //update remaining number of bytes needing to be written to disk
480 numBytes -= bytesToCopy;
481 }
482 //free allocated memory of bitmap
483 free(bitmap);
484
485 green();
486 dprintf("---> bitmap_reset COMPLETED SUCCESSFULLY\n");
487 reset();
488 return 0;
489}
490// return 1 if the file name is illegal; otherwise, return 0; legal
491// characters for a file name include letters (case sensitive),
492// numbers, dots, dashes, and underscores; and a legal file name
493// should not be more than MAX_NAME-1 in length
494static int illegal_filename(char* name)
495{
496 // Check if name is non empty or too long
497 if(name==NULL || strlen(name)==0 || strlen(name)>=MAX_NAME)
498 {
499 dprintf("... Filename is null or too long: %s\n", name);
500 return 1;
501 }
502
503 // Check if entries only contain allowed elements
504 for(int i=0; i < strlen(name);i++){
505 if(!(isalpha(name[i]) || isdigit(name[i]) ||
506 name[i] == '.' || name[i] == '_' || name[i] == '-' || name[i] == '/'))
507 {
508 dprintf("... Invalid characters in filename: %s\n", name);
509 return 1; }
510 }
511
512 return 0;
513}
514
515// return the child inode of the given file name 'fname' from the
516// parent inode; the parent inode is currently stored in the segment
517// of inode table in the cache (we cache only one disk sector for
518// this); once found, both cached_inode_sector and cached_inode_buffer
519// may be updated to point to the segment of inode table containing
520// the child inode; the function returns -1 if no such file is found;
521// it returns -2 is something else is wrong (such as parent is not
522// directory, or there's read error, etc.)
523static int find_child_inode(int parent_inode, char* fname,
524 int *cached_inode_sector, char* cached_inode_buffer)
525{
526 int cached_start_entry = ((*cached_inode_sector)-INODE_TABLE_START_SECTOR)*INODES_PER_SECTOR;
527 int offset = parent_inode-cached_start_entry;
528 assert(0 <= offset && offset < INODES_PER_SECTOR);
529 inode_t* parent = (inode_t*)(cached_inode_buffer+offset*sizeof(inode_t));
530 dprintf("... load parent inode: %d (size=%d, type=%d)\n",
531 parent_inode, parent->size, parent->type);
532 if(parent->type != 1) {
533 dprintf("... parent not a directory\n");
534 return -2;
535 }
536
537 int nentries = parent->size; // remaining number of directory entries
538 int idx = 0;
539 while(nentries > 0) {
540 char buf[SECTOR_SIZE]; // cached content of directory entries
541 if(Disk_Read(parent->data[idx], buf) < 0) return -2;
542 for(int i=0; i<DIRENTS_PER_SECTOR; i++) {
543 if(i>nentries) break;
544 if(!strcmp(((dirent_t*)buf)[i].fname, fname)) {
545 // found the file/directory; update inode cache
546 int child_inode = ((dirent_t*)buf)[i].inode;
547 dprintf("... found child_inode=%d\n", child_inode);
548 int sector = INODE_TABLE_START_SECTOR+child_inode/INODES_PER_SECTOR;
549 if(sector != (*cached_inode_sector)) {
550 *cached_inode_sector = sector;
551 if(Disk_Read(sector, cached_inode_buffer) < 0) return -2;
552 dprintf("... load inode table for child\n");
553 }
554 return child_inode;
555 }
556 }
557 idx++; nentries -= DIRENTS_PER_SECTOR;
558 }
559 dprintf("... could not find child inode\n");
560 return -1; // not found
561}
562
563// follow the absolute path; if successful, return the inode of the
564// parent directory immediately before the last file/directory in the
565// path; for example, for '/a/b/c/d.txt', the parent is '/a/b/c' and
566// the child is 'd.txt'; the child's inode is returned through the
567// parameter 'last_inode' and its file name is returned through the
568// parameter 'last_fname' (both are references); it's possible that
569// the last file/directory is not in its parent directory, in which
570// case, 'last_inode' points to -1; if the function returns -1, it
571// means that we cannot follow the path
572static int follow_path(char* path, int* last_inode, char* last_fname)
573{
574 if(!path) {
575 dprintf("... invalid path\n");
576 return -1;
577 }
578 if(path[0] != '/') {
579 dprintf("... '%s' not absolute path\n", path);
580 return -1;
581 }
582
583 // make a copy of the path (skip leading '/'); this is necessary
584 // since the path is going to be modified by strsep()
585 char pathstore[MAX_PATH];
586 strncpy(pathstore, path+1, MAX_PATH-1);
587 pathstore[MAX_PATH-1] = '\0'; // for safety
588 char* lpath = pathstore;
589
590 int parent_inode = -1, child_inode = 0; // start from root
591 // cache the disk sector containing the root inode
592 int cached_sector = INODE_TABLE_START_SECTOR;
593 char cached_buffer[SECTOR_SIZE];
594 if(Disk_Read(cached_sector, cached_buffer) < 0) return -1;
595 dprintf("... load inode table for root from disk sector %d\n", cached_sector);
596
597 // for each file/directory name separated by '/'
598 char* token;
599 while((token = strsep(&lpath, "/")) != NULL) {
600 dprintf("... process token: '%s'\n", token);
601 if(*token == '\0') continue; // multiple '/' ignored
602 if(illegal_filename(token)) {
603 dprintf("... illegal file name: '%s'\n", token);
604 return -1;
605 }
606 if(child_inode < 0) {
607 // regardless whether child_inode was not found previously, or
608 // there was issues related to the parent (say, not a
609 // directory), or there was a read error, we abort
610 dprintf("... parent inode can't be established\n");
611 return -1;
612 }
613 parent_inode = child_inode;
614 child_inode = find_child_inode(parent_inode, token,
615 &cached_sector, cached_buffer);
616 if(last_fname) strcpy(last_fname, token);
617 }
618 if(child_inode < -1) return -1; // if there was error, abort
619 else {
620 // there was no error, several possibilities:
621 // 1) '/': parent = -1, child = 0
622 // 2) '/valid-dirs.../last-valid-dir/not-found': parent=last-valid-dir, child=-1
623 // 3) '/valid-dirs.../last-valid-dir/found: parent=last-valid-dir, child=found
624 // in the first case, we set parent=child=0 as special case
625 if(parent_inode==-1 && child_inode==0) parent_inode = 0;
626 dprintf("... found parent_inode=%d, child_inode=%d\n", parent_inode, child_inode);
627 *last_inode = child_inode;
628 return parent_inode;
629 }
630}
631
632// add a new file or directory (determined by 'type') of given name
633// 'file' under parent directory represented by 'parent_inode'
634int add_inode(int type, int parent_inode, char* file)
635{
636 // get a new inode for child
637 int child_inode = bitmap_first_unused(INODE_BITMAP_START_SECTOR, INODE_BITMAP_SECTORS, INODE_BITMAP_SIZE);
638 if(child_inode < 0) {
639 dprintf("... error: inode table is full\n");
640 return -1;
641 }
642 dprintf("... new child inode %d\n", child_inode);
643
644 // load the disk sector containing the child inode
645 int inode_sector = INODE_TABLE_START_SECTOR+child_inode/INODES_PER_SECTOR;
646 char inode_buffer[SECTOR_SIZE];
647 if(Disk_Read(inode_sector, inode_buffer) < 0) return -1;
648 dprintf("... load inode table for child inode from disk sector %d\n", inode_sector);
649
650 // get the child inode
651 int inode_start_entry = (inode_sector-INODE_TABLE_START_SECTOR)*INODES_PER_SECTOR;
652 int offset = child_inode-inode_start_entry;
653 assert(0 <= offset && offset < INODES_PER_SECTOR);
654 inode_t* child = (inode_t*)(inode_buffer+offset*sizeof(inode_t));
655
656 // update the new child inode and write to disk
657 memset(child, 0, sizeof(inode_t));
658 child->type = type;
659 if(Disk_Write(inode_sector, inode_buffer) < 0) return -1;
660 dprintf("... update child inode %d (size=%d, type=%d), update disk sector %d\n",
661 child_inode, child->size, child->type, inode_sector);
662
663 // get the disk sector containing the parent inode
664 inode_sector = INODE_TABLE_START_SECTOR+parent_inode/INODES_PER_SECTOR;
665 if(Disk_Read(inode_sector, inode_buffer) < 0) return -1;
666 dprintf("... load inode table for parent inode %d from disk sector %d\n",
667 parent_inode, inode_sector);
668
669 // get the parent inode
670 inode_start_entry = (inode_sector-INODE_TABLE_START_SECTOR)*INODES_PER_SECTOR;
671 offset = parent_inode-inode_start_entry;
672 assert(0 <= offset && offset < INODES_PER_SECTOR);
673 inode_t* parent = (inode_t*)(inode_buffer+offset*sizeof(inode_t));
674 dprintf("... get parent inode %d (size=%d, type=%d)\n",
675 parent_inode, parent->size, parent->type);
676
677 // get the dirent sector
678 if(parent->type != 1) {
679 dprintf("... error: parent inode is not directory\n");
680 return -2; // parent not directory
681 }
682 int group = parent->size/DIRENTS_PER_SECTOR;
683 //check if group has reach max sectors per directory and abort if true
684 if (group >= MAX_SECTORS_PER_FILE){
685 printf("... all sectors of parent director is filled\n");
686 return -1;
687 }
688 char dirent_buffer[SECTOR_SIZE];
689 if(group*DIRENTS_PER_SECTOR == parent->size) {
690 // new disk sector is needed
691 int newsec = bitmap_first_unused(SECTOR_BITMAP_START_SECTOR, SECTOR_BITMAP_SECTORS, SECTOR_BITMAP_SIZE);
692 if(group == MAX_SECTORS_PER_FILE-1){
693 dprintf(".... error: all sectors referenced in data attribute of parent inode fully occupied. Parent size: %d\n", parent->size);
694 return -1;
695 }
696 if(newsec < 0) {
697 dprintf("... error: disk is full\n");
698 return -1;
699 }
700 parent->data[group] = newsec;
701 memset(dirent_buffer, 0, SECTOR_SIZE);
702 dprintf("... new disk sector %d for dirent group %d\n", newsec, group);
703 } else {
704 if(Disk_Read(parent->data[group], dirent_buffer) < 0)
705 return -1;
706 dprintf("... load disk sector %d for dirent group %d\n", parent->data[group], group);
707 }
708
709 // add the dirent and write to disk
710 int start_entry = group*DIRENTS_PER_SECTOR;
711 offset = parent->size-start_entry;
712 dirent_t* dirent = (dirent_t*)(dirent_buffer+offset*sizeof(dirent_t));
713 strncpy(dirent->fname, file, MAX_NAME);
714 dirent->inode = child_inode;
715 if(Disk_Write(parent->data[group], dirent_buffer) < 0) return -1;
716 dprintf("... append dirent %d (name='%s', inode=%d) to group %d, update disk sector %d\n",
717 parent->size, dirent->fname, dirent->inode, group, parent->data[group]);
718
719 // update parent inode and write to disk
720 parent->size++;
721 dprintf("... updating parent inode size: %d", parent->size);
722 if(Disk_Write(inode_sector, inode_buffer) < 0) return -1;
723 dprintf("... update parent inode on disk sector %d\n", inode_sector);
724
725 return 0;
726}
727
728// used by both File_Create() and Dir_Create(); type=0 is file, type=1
729// is directory
730int create_file_or_directory(int type, char* pathname)
731{
732 int child_inode;
733 char last_fname[MAX_NAME];
734 int parent_inode = follow_path(pathname, &child_inode, last_fname);
735 if(parent_inode >= 0)
736 {
737 if(child_inode >= 0)
738 {
739 dprintf("... file/directory '%s' already exists, failed to create\n", pathname);
740 osErrno = E_CREATE;
741 return -1;
742 } else
743 {
744 if(add_inode(type, parent_inode, last_fname) >= 0)
745 {
746 dprintf("... successfully created file/directory: '%s'\n", pathname);
747 return 0;
748 }
749 else {
750 dprintf("... error: something wrong with adding child inode\n");
751 osErrno = E_CREATE;
752 return -1;
753 }
754 }
755 } else {
756 dprintf("... error: something wrong with the file/path: '%s'\n", pathname);
757 osErrno = E_CREATE;
758 return -1;
759 }
760}
761
762// remove the child from parent; the function is called by both
763// File_Unlink() and Dir_Unlink(); the function returns 0 if success,
764// -1 if general error, -2 if directory not empty, -3 if wrong type
765int remove_inode(int type, int parent_inode, int child_inode)
766{
767
768 dprintf("... remove inode %d\n", child_inode);
769
770 // load the disk sector containing the child inode
771 int inode_sector = INODE_TABLE_START_SECTOR+child_inode/INODES_PER_SECTOR;
772 char inode_buffer[SECTOR_SIZE];
773 if(Disk_Read(inode_sector, inode_buffer) < 0) return -1;
774 dprintf("... load inode table for child inode from disk sector %d\n", inode_sector);
775
776 // get the child inode
777 int inode_start_entry = (inode_sector-INODE_TABLE_START_SECTOR)*INODES_PER_SECTOR;
778 int offset = child_inode-inode_start_entry;
779 assert(0 <= offset && offset < INODES_PER_SECTOR);
780 inode_t* child = (inode_t*)(inode_buffer+offset*sizeof(inode_t));
781
782 // check for right type
783 if(child->type!=type){
784 dprintf("... error: the type parameter does not match the actual inode type\n");
785 return -3;
786 }
787
788 // check if child is non-empty directory
789 if(child->type==1 && child->size>0){
790 dprintf("... error: inode is non-empty directory\n");
791 return -2;
792 }
793
794 // reset data blocks of file
795 if(type==0){
796
797 /**
798 * DEBUGGING PRINT
799 */
800 dprintf("Inode size: %d, data sector 0: %d\n", child->size, child->data[0]);
801
802 char data_buffer[SECTOR_SIZE];
803 int sectors = child->size/SECTOR_SIZE+(child->size%SECTOR_SIZE != 0 ? 1 : 0);
804 for(int i=0; i<sectors; i++){
805 if(Disk_Read(child->data[i], data_buffer) < 0) return -1;
806 dprintf("... delete contents of file with inode %d from sector %d\n",
807 child_inode, child->data[i]);
808 bzero(data_buffer, SECTOR_SIZE);
809 if(Disk_Write(child->data[i], data_buffer) < 0) return -1;
810 if (bitmap_reset(SECTOR_BITMAP_START_SECTOR, SECTOR_BITMAP_SECTORS, child->data[i]) < 0) {
811 dprintf("... error: free sector occupied by file in sector bitmap unsuccessful\n");
812 return -1;
813 }
814 }
815
816 }
817
818 // delete the child inode
819 memset(child, 0, sizeof(inode_t));
820 if(Disk_Write(inode_sector, inode_buffer) < 0) return -1;
821 dprintf("... delete inode %d, update disk sector %d\n",
822 child_inode, inode_sector);
823
824 // get the disk sector containing the parent inode
825 inode_sector = INODE_TABLE_START_SECTOR+parent_inode/INODES_PER_SECTOR;
826 if(Disk_Read(inode_sector, inode_buffer) < 0) return -1;
827 dprintf("... load inode table for parent inode %d from disk sector %d\n",
828 parent_inode, inode_sector);
829
830 // get the parent inode
831 inode_start_entry = (inode_sector-INODE_TABLE_START_SECTOR)*INODES_PER_SECTOR;
832 offset = parent_inode-inode_start_entry;
833 assert(0 <= offset && offset < INODES_PER_SECTOR);
834 inode_t* parent = (inode_t*)(inode_buffer+offset*sizeof(inode_t));
835 dprintf("... get parent inode %d (size=%d, type=%d)\n",
836 parent_inode, parent->size, parent->type);
837
838 // check if parent is directory
839 if(parent->type != 1) {
840 dprintf("... error: parent inode is not directory\n");
841 return -3;
842 }
843
844 // check if parent is non-empty
845 if(parent->size < 1) {
846 dprintf("... error: parent directory has no entries\n");
847 return -1;
848 }
849
850 // reset bit of child inode in bitmap
851 if (bitmap_reset(INODE_BITMAP_START_SECTOR, INODE_BITMAP_SECTORS, child_inode) < 0) {
852 dprintf("... error: reset inode in bitmap unsuccessful\n");
853 return -1;
854 }
855
856 int remainder = parent->size % DIRENTS_PER_SECTOR;
857 int group = (parent->size)/DIRENTS_PER_SECTOR;
858 char dirent_buffer[SECTOR_SIZE];
859 dirent_t* dirent;
860 int counter = 0;
861 int found = 0;
862
863 // search for the dirent in every group
864 for(int i = 0; i<=group; i++){
865
866 if(Disk_Read(parent->data[i], dirent_buffer) < 0) return -1;
867 dprintf("... search for child in disk sector %d for dirent group %d\n", parent->data[i], i);
868
869 for(int j=0; j<DIRENTS_PER_SECTOR; j++){
870 counter ++;
871 dirent = (dirent_t*)(dirent_buffer+j*sizeof(dirent_t));
872 if(counter < parent->size && (!found)) {
873
874 // Case 1: Child node found and last dirent in the same sector
875 if(dirent->inode == child_inode && i == group) {
876 dirent_t* last_dirent = (dirent_t*)(dirent_buffer+(remainder-1)*sizeof(dirent_t));
877 memcpy(dirent, last_dirent, sizeof(dirent_t));
878 memset(last_dirent, 0, sizeof(dirent_t));
879 if(Disk_Write(parent->data[i], dirent_buffer) < 0) return -1;
880 dprintf("... delete dirent (inode=%d) from group %d, update disk sector %d\n",
881 child_inode, i, parent->data[i]);
882 found=1;
883
884 // Case 2: Child node found, but last dirent in other sector
885 } else if(dirent->inode == child_inode) {
886 char last_dirent_buffer[SECTOR_SIZE];
887 if(Disk_Read(parent->data[group], last_dirent_buffer) < 0) return -1;
888 dprintf("... load last dirent from parent %d in disk sector %d for dirent group %d\n",
889 parent_inode, parent->data[group], group);
890 dirent_t* last_dirent = (dirent_t*)(last_dirent_buffer+(remainder-1)*sizeof(dirent_t));
891 memcpy(dirent, last_dirent, sizeof(dirent_t));
892 memset(last_dirent, 0, sizeof(dirent_t));
893 if(Disk_Write(parent->data[i], dirent_buffer) < 0) return -1;
894 dprintf("...delete dirent (inode=%d) from group %d, update disk sector %d\n",
895 child_inode, i, parent->data[i]);
896 if(Disk_Write(parent->data[group], last_dirent_buffer) < 0) return -1;
897 dprintf("...copy last dirent with inode %d into group %d, update disk sector %d\n",
898 dirent->inode, group-1, parent->data[group]);
899 found=1;
900 }
901
902 } else if(!found) {
903
904 // Case 3: Child found and last dirent from parent
905 if(dirent->inode == child_inode) {
906 memset(dirent, 0, sizeof(dirent_t));
907 if(Disk_Write(parent->data[i], dirent_buffer) < 0) return -1;
908 dprintf("... delete dirent (inode=%d) from group %d, update disk sector %d\n",
909 child_inode, group, parent->data[i]);
910 found=1;
911
912 // Case 4: Child node not found, and reached last dirent from parent
913 } else if(counter >= parent->size) {
914 dprintf("Counter: %d, Parent size: %d\n", counter, parent->size);
915 dprintf("... error: child inode could not be found in parent directory\n");
916 return -1;
917 }
918 }
919 }
920 }
921
922 // check for remaining dirents from parent in that sector (otherwise reset sector bitmap)
923 if (remainder == 1) {
924 // disk sector has to be freed
925 if(parent->data[group] == 0){dprintf("... parent->data[group]=%d\n", parent->data[group]);}
926 if (bitmap_reset(SECTOR_BITMAP_START_SECTOR, SECTOR_BITMAP_SECTORS, parent->data[group]) < 0) {
927 dprintf("... error: free sector in bitmap unsuccessful\n");
928 return -1;
929 }
930 parent->data[group] = 0;
931 }
932
933 // update parent inode and write to disk
934 parent->size--;
935 if(Disk_Write(inode_sector, inode_buffer) < 0) return -1;
936 dprintf("... update parent inode on disk sector %d\n", inode_sector);
937
938 return 0;
939}
940
941// representing an open file
942typedef struct _open_file {
943 int inode; // pointing to the inode of the file (0 means entry not used)
944 int size; // file size cached here for convenience
945 int pos; // read/write position within the data array
946 int posByte; //starting byte to read from
947} open_file_t;
948static open_file_t open_files[MAX_OPEN_FILES];
949
950// return true if the file pointed to by inode has already been open
951int is_file_open(int inode)
952{
953 for(int i=0; i<MAX_OPEN_FILES; i++) {
954 if(open_files[i].inode == inode)
955 return 1;
956 }
957 return 0;
958}
959
960// return a new file descriptor not used; -1 if full
961int new_file_fd()
962{
963 for(int i=0; i<MAX_OPEN_FILES; i++) {
964 if(open_files[i].inode <= 0)
965 return i;
966 }
967 return -1;
968}
969
970/* end of internal helper functions, start of API functions */
971
972int FS_Boot(char* backstore_fname)
973{
974 dprintf("FS_Boot('%s'):\n", backstore_fname);
975 // initialize a new disk (this is a simulated disk)
976 if(Disk_Init() < 0) {
977 dprintf("... disk init failed\n");
978 osErrno = E_GENERAL;
979 return -1;
980 }
981 dprintf("... disk initialized\n");
982
983 // we should copy the filename down; if not, the user may change the
984 // content pointed to by 'backstore_fname' after calling this function
985 strncpy(bs_filename, backstore_fname, 1024);
986 bs_filename[1023] = '\0'; // for safety
987
988 // we first try to load disk from this file
989 if(Disk_Load(bs_filename) < 0) {
990 dprintf("... load disk from file '%s' failed\n", bs_filename);
991
992 // if we can't open the file; it means the file does not exist, we
993 // need to create a new file system on disk
994 if(diskErrno == E_OPENING_FILE) {
995 dprintf("... couldn't open file, create new file system\n");
996
997 // format superblock
998 char buf[SECTOR_SIZE];
999 memset(buf, 0, SECTOR_SIZE);
1000 *(int*)buf = OS_MAGIC;
1001 if(Disk_Write(SUPERBLOCK_START_SECTOR, buf) < 0) {
1002 dprintf("... failed to format superblock\n");
1003 osErrno = E_GENERAL;
1004 return -1;
1005 }
1006 dprintf("... formatted superblock (sector %d)\n", SUPERBLOCK_START_SECTOR);
1007
1008 // format inode bitmap (reserve the first inode to root)
1009 //type for inode bitmap sector = 0
1010 dprintf("... calling bitmap int for inode bitmap with start=%d, num=%d, nbits=1\n",
1011 INODE_BITMAP_START_SECTOR, INODE_BITMAP_SECTORS);
1012 bitmap_init(INODE_BITMAP_START_SECTOR, INODE_BITMAP_SECTORS, 1, 0);
1013 dprintf("... formatted inode bitmap (start=%d, num=%d)\n",
1014 (int)INODE_BITMAP_START_SECTOR, (int)INODE_BITMAP_SECTORS);
1015
1016 // format sector bitmap (reserve the first few sectors to
1017 // superblock, inode bitmap, sector bitmap, and inode table)
1018 //type for sector bitmap = 1
1019 dprintf("... calling bitmap int for sector bitmap with start=%d, num=%d, nbits=%ld\n",
1020 SECTOR_BITMAP_START_SECTOR, SECTOR_BITMAP_SECTORS, DATABLOCK_START_SECTOR);
1021 bitmap_init(SECTOR_BITMAP_START_SECTOR, SECTOR_BITMAP_SECTORS,
1022 DATABLOCK_START_SECTOR, 1);
1023 dprintf("... formatted sector bitmap (start=%d, num=%d)\n",
1024 (int)SECTOR_BITMAP_START_SECTOR, (int)SECTOR_BITMAP_SECTORS);
1025
1026 // format inode tables
1027 for(int i=0; i<INODE_TABLE_SECTORS; i++) {
1028 memset(buf, 0, SECTOR_SIZE);
1029 if(i==0) {
1030 // the first inode table entry is the root directory
1031 ((inode_t*)buf)->size = 0;
1032 ((inode_t*)buf)->type = 1;
1033 }
1034 if(Disk_Write(INODE_TABLE_START_SECTOR+i, buf) < 0) {
1035 dprintf("... failed to format inode table\n");
1036 osErrno = E_GENERAL;
1037 return -1;
1038 }
1039 }
1040 dprintf("... formatted inode table (start=%d, num=%d)\n",
1041 (int)INODE_TABLE_START_SECTOR, (int)INODE_TABLE_SECTORS);
1042
1043 // we need to synchronize the disk to the backstore file (so
1044 // that we don't lose the formatted disk)
1045 if(Disk_Save(bs_filename) < 0) {
1046 // if can't write to file, something's wrong with the backstore
1047 dprintf("... failed to save disk to file '%s'\n", bs_filename);
1048 osErrno = E_GENERAL;
1049 return -1;
1050 } else {
1051 // everything's good now, boot is successful
1052 dprintf("... successfully formatted disk, boot successful\n");
1053 memset(open_files, 0, MAX_OPEN_FILES*sizeof(open_file_t));
1054 return 0;
1055 }
1056 } else {
1057 // something wrong loading the file: invalid param or error reading
1058 dprintf("... couldn't read file '%s', boot failed\n", bs_filename);
1059 osErrno = E_GENERAL;
1060 return -1;
1061 }
1062 } else {
1063 dprintf("... load disk from file '%s' successful\n", bs_filename);
1064
1065 // we successfully loaded the disk, we need to do two more checks,
1066 // first the file size must be exactly the size as expected (thiis
1067 // supposedly should be folded in Disk_Load(); and it's not)
1068 int sz = 0;
1069 FILE* f = fopen(bs_filename, "r");
1070 if(f) {
1071 fseek(f, 0, SEEK_END);
1072 sz = ftell(f);
1073 fclose(f);
1074 }
1075 if(sz != SECTOR_SIZE*TOTAL_SECTORS) {
1076 dprintf("... check size of file '%s' failed\n", bs_filename);
1077 osErrno = E_GENERAL;
1078 return -1;
1079 }
1080 dprintf("... check size of file '%s' successful\n", bs_filename);
1081
1082 // check magic
1083 if(check_magic()) {
1084 // everything's good by now, boot is successful
1085 dprintf("... check magic successful\n");
1086 memset(open_files, 0, MAX_OPEN_FILES*sizeof(open_file_t));
1087 return 0;
1088 } else {
1089 // mismatched magic number
1090 dprintf("... check magic failed, boot failed\n");
1091 osErrno = E_GENERAL;
1092 return -1;
1093 }
1094 }
1095}
1096
1097int FS_Sync()
1098{
1099 dprintf("FS_Sync():\n");
1100 if(Disk_Save(bs_filename) < 0) {
1101 // if can't write to file, something's wrong with the backstore
1102 dprintf("FS_Sync():\n... failed to save disk to file '%s'\n", bs_filename);
1103 osErrno = E_GENERAL;
1104 return -1;
1105 } else {
1106 // everything's good now, sync is successful
1107 dprintf("FS_Sync():\n... successfully saved disk to file '%s'\n", bs_filename);
1108 return 0;
1109 }
1110}
1111
1112int File_Create(char* file)
1113{
1114 dprintf("File_Create('%s'):\n", file);
1115 return create_file_or_directory(0, file);
1116}
1117
1118//TODO: check if really remove the data blocks
1119int File_Unlink(char* file)
1120{
1121 dprintf("File_Unlink('%s'):\n", file);
1122 int child_inode;
1123
1124 int parent_inode = follow_path(file, &child_inode, NULL);
1125
1126
1127 if(child_inode >= 0) //file exists
1128 {
1129 //check if file is open
1130 if(is_file_open(child_inode)){
1131 dprintf("... %s is an open file. Cannot unlink\n", file);
1132 osErrno = E_FILE_IN_USE;
1133 return -1;
1134 }
1135
1136
1137 int remove = remove_inode(0, parent_inode, child_inode);
1138 if(remove == -1){
1139 dprintf("... error: general error when unlinking file\n");
1140 osErrno = E_GENERAL;
1141 return -1;
1142 }
1143 else if(remove == -3){
1144 dprintf("... error: no file, incorrect type\n");
1145 osErrno = E_NO_SUCH_FILE;
1146 return -1;
1147 }
1148 else{
1149 return 0;
1150 }
1151
1152 }
1153
1154 else{ //file does not exist
1155 dprintf("... %s file does not exist\n", file);
1156 osErrno = E_NO_SUCH_FILE;
1157 return -1;
1158
1159 }
1160}
1161
1162int File_Open(char* file)
1163{
1164 dprintf("File_Open('%s'):\n", file);
1165
1166 int fd = new_file_fd();
1167
1168 if(fd < 0) {
1169 dprintf("... max open files reached\n");
1170 osErrno = E_TOO_MANY_OPEN_FILES;
1171 return -1;
1172 }
1173
1174 int child_inode;
1175 follow_path(file, &child_inode, NULL);
1176
1177 if(child_inode >= 0) { // child is the one, file exists
1178 //check if file is already open
1179 if(is_file_open(child_inode)){
1180 dprintf("... error: %s is an open file already.\n", file);
1181 osErrno = E_FILE_IN_USE;
1182 return -1;
1183 }
1184 // load the disk sector containing the inode
1185 int inode_sector = INODE_TABLE_START_SECTOR+child_inode/INODES_PER_SECTOR;
1186 char inode_buffer[SECTOR_SIZE];
1187 if(Disk_Read(inode_sector, inode_buffer) < 0) { osErrno = E_GENERAL; return -1; }
1188 dprintf("... load inode table for inode from disk sector %d\n", inode_sector);
1189
1190 // get the inode
1191 int inode_start_entry = (inode_sector-INODE_TABLE_START_SECTOR)*INODES_PER_SECTOR;
1192 int offset = child_inode-inode_start_entry;
1193 assert(0 <= offset && offset < INODES_PER_SECTOR);
1194 inode_t* child = (inode_t*)(inode_buffer+offset*sizeof(inode_t));
1195 dprintf("... inode %d (size=%d, type=%d)\n",
1196 child_inode, child->size, child->type);
1197
1198 if(child->type != 0) {
1199 dprintf("... error: '%s' is not a file\n", file);
1200 osErrno = E_GENERAL;
1201 return -1;
1202 }
1203
1204 // initialize open file entry and return its index
1205 open_files[fd].inode = child_inode;
1206 open_files[fd].size = child->size;
1207 open_files[fd].pos = 0;
1208 open_files[fd].posByte = 0;
1209
1210
1211
1212
1213 return fd;
1214 } else {
1215 dprintf("... file '%s' is not found\n", file);
1216 osErrno = E_NO_SUCH_FILE;
1217 return -1;
1218 }
1219}
1220
1221//helper function
1222//ask user if they wish to read remaining data in file
1223//Action 1: Do not read remaining data
1224//Action 2: Read initial requested and remaining data
1225int readRemaining(int fd){
1226 int action = 0;
1227 do{
1228 printf("File of fd=%d still has remaining data left to read.\n"
1229 "Do you wish to:\n"
1230 "1. not read the remaining data?\n"
1231 "2. read the initial requested and remaining data?\n"
1232 "Please input 1 or 2 as your desired action.\n", fd);
1233
1234 scanf("%d", &action);
1235 }while(action != 1 && action != 2);
1236
1237 return action;
1238}
1239
1240//Case 1: Size to read is bigger than actual size -> read only the total amount
1241//Case 2: Size to read is less than actual size ->
1242// ask if user wants to read the size given or
1243// if user wants to read the remaining as well
1244//Case 3: Size to read is equal to actual size -> read the given size
1245int File_Read(int fd, void* buffer, int size)
1246{
1247 boldBlue();
1248 dprintf("File_Read(%d, buffer, %d):\n", fd, size);
1249 reset();
1250
1251 //check if fd is valid index
1252 if(fd < 0 || fd > MAX_OPEN_FILES){
1253 blue();
1254 dprintf("... fd=%d out of bound", fd);
1255 reset();
1256 osErrno = E_BAD_FD;
1257 return -1;
1258 }
1259
1260 open_file_t file = open_files[fd];
1261
1262 //check if not an open file
1263 if(file.inode <= 0){
1264 blue();
1265 dprintf("... fd=%d not an open file\n", fd);
1266 reset();
1267 osErrno = E_BAD_FD;
1268 return -1;
1269 }
1270
1271
1272 //check if file size is empty
1273 if(file.size == 0)
1274 {
1275 //none to read
1276 blue();
1277 dprintf("... file fd=%d is empty\n", fd);
1278 reset();
1279 return 0;
1280 }
1281
1282 /***determine how many sectors can actually be read***/
1283
1284 //none to read, position at end of file
1285 if(file.size - ((file.pos+1)*SECTOR_SIZE-(SECTOR_SIZE-file.posByte)) == 0)
1286 {
1287 blue();
1288 dprintf("... file fd=%d is at end of file\n", fd);
1289 reset();
1290 return 0;
1291 }
1292 //something to read
1293 //remaining file size left to read
1294 int remFileSize = file.size - ((file.pos+1)*SECTOR_SIZE-(SECTOR_SIZE-file.posByte));
1295 int sectorsToRead = 0;
1296
1297 int sizeToRead = 0;
1298
1299 /***ask user if to read initial amount or also the remaining***/
1300 /*
1301 if(remFileSize > size && readRemaining(fd) == 2){
1302 sizeToRead = remFileSize;
1303 }
1304 else{*/
1305 sizeToRead = min(remFileSize,size);
1306
1307
1308 //if less than size is remaining, read only remaining
1309 //else pick initial given size to read
1310
1311
1312 //if posByte is at part of current sector
1313 if(file.posByte != 0){
1314 sectorsToRead++;//read only one sector
1315 if(SECTOR_SIZE - file.posByte < sizeToRead){//need to read more sectors
1316 int remSize = sizeToRead - (SECTOR_SIZE - file.posByte);
1317 sectorsToRead += remSize/SECTOR_SIZE;
1318
1319 //check for remainder
1320 if(remSize%SECTOR_SIZE){
1321 sectorsToRead++;
1322 }
1323 }
1324 }
1325 else{//if posByte is at beginning of a sector
1326 sectorsToRead = sizeToRead/SECTOR_SIZE;
1327
1328 //check remainder
1329 if(sizeToRead%SECTOR_SIZE){
1330 sectorsToRead++;
1331 }
1332 }
1333
1334 blue();
1335 dprintf("... sectors to read=%d with size to read=%d of file size=%d at data[%d] at byte position=%d\n",
1336 sectorsToRead, sizeToRead, file.size, file.pos, file.posByte);
1337 reset();
1338
1339 /***get file inode***/
1340
1341 //load file's inode disk sectors
1342 int inode = file.inode;
1343 int inode_sector = INODE_TABLE_START_SECTOR+inode/INODES_PER_SECTOR;
1344 char inode_buffer[SECTOR_SIZE];
1345 if(Disk_Read(inode_sector, inode_buffer) < 0) { osErrno = E_GENERAL; return -1; }
1346
1347 blue();
1348 dprintf("... load inode table for inode from disk sector %d\n", inode_sector);
1349 reset();
1350
1351 //get inode
1352 int inode_start_entry = (inode_sector-INODE_TABLE_START_SECTOR)*INODES_PER_SECTOR;
1353 int offset = inode-inode_start_entry;
1354 assert(0 <= offset && offset < INODES_PER_SECTOR);
1355 inode_t* fileInode = (inode_t*)(inode_buffer+offset*sizeof(inode_t));
1356
1357 blue();
1358 dprintf("... inode %d (size=%d, type=%d)\n",
1359 inode, fileInode->size, fileInode->type);
1360 reset();
1361
1362 int position = file.pos;
1363
1364 /***read contents of data blocks***/
1365
1366 //temp buffer to read entire sector in
1367 char tempBuff[SECTOR_SIZE];
1368 memset(buffer,0,sizeToRead);
1369
1370 //will position buffer ptr to next available space to copy data into
1371 int ctrSize = 0;
1372 for(int i = 0; i < sectorsToRead; i++){
1373 bzero(tempBuff, SECTOR_SIZE);
1374
1375 if(Disk_Read(fileInode->data[position], tempBuff) < 0){
1376 blue();
1377 dprintf("... error: can't read sector %d\n", fileInode->data[position]);
1378 reset();
1379 osErrno=E_GENERAL;
1380 return -1;
1381 }
1382
1383 blue();
1384 dprintf("... Reading data[%d]=%d at positionByte=%d\n",
1385 position, fileInode->data[position], file.posByte);
1386 reset();
1387
1388 int currBytes = 0; //keep track of what's currently read from sector
1389
1390 if(file.posByte != 0){//starting out at arbitrary point in currsector
1391 currBytes = SECTOR_SIZE - file.posByte;
1392 }
1393 else if(i == sectorsToRead - 1){//at last sector to read from
1394 currBytes = sizeToRead - ctrSize;
1395 }
1396 else{//full sectors
1397 currBytes = SECTOR_SIZE;
1398 }
1399
1400 blue();
1401 dprintf("... Copying data of %d bytes at %d into buffer ptr at %d\n",
1402 currBytes, file.posByte, ctrSize);
1403 reset();
1404
1405 //copy what's needed into buffer from buff
1406 memcpy(buffer+ctrSize, tempBuff+file.posByte, currBytes);
1407
1408 ctrSize += currBytes;
1409
1410 //specify new byte position if didn't read the entire last sector
1411 if(i == sectorsToRead - 1 && file.posByte + currBytes < SECTOR_SIZE){
1412 file.posByte = currBytes;
1413 }
1414 else{//new byte position and block position if read entire sectors
1415 position++;
1416 file.posByte = 0;
1417 }
1418
1419
1420 }
1421
1422
1423 //set new read/write position and new posbyte to read at
1424 open_files[fd].pos = position;
1425 open_files[fd].posByte = file.posByte;
1426
1427 blue();
1428 dprintf("... file=%d is now at pos=%d with byte pos=%d\n", fd, open_files[fd].pos, open_files[fd].posByte);
1429
1430 dprintf("... successfully read %d sectors with size=%d\n", sectorsToRead, sizeToRead);
1431 reset();
1432
1433 return sizeToRead;
1434
1435}
1436
1437//helper function
1438//gets user input on what action to take related to overwriting a file
1439//when the file recently opens and is non-empty
1440int toOverwriteOrNot(int fd){
1441 int action = 0;
1442 do{
1443 printf("File of fd=%d is non-empty. Do you\n"
1444 "1. wish to overwrite from position 0 (will delete entire file's contents)?\n"
1445 "2. wish to append data from first empty position?\n"
1446 "3. wish to not overwrite?\n"
1447 "Please input 1, 2 or 3 indicating your desired action.\n", fd);
1448
1449 scanf("%d", &action);
1450 }while(action != 1 && action != 2 && action != 3);
1451
1452 return action;
1453}
1454
1455int ifWriteRem(int fd, int size, int sizeRem){
1456 int action = 0;
1457
1458 do{
1459 printf("File of fd=%d cannot write requested size=%d bytes. It has a space of size=%d bytes remaining. Do you\n"
1460 "1. wish to write %d bytes from data given?\n"
1461 "2. wish to not write at all?\n"
1462 "Please input 1 or 2 indicating your desired actions.\n", fd, size, sizeRem, sizeRem);
1463 scanf("%d", &action);
1464 }while(action != 1 && action != 2);
1465
1466 return action;
1467}
1468
1469//case 1: file_write first called on empty file -> no checks, write into file
1470//case 2: file_write first called on a recently opened non-empty file
1471// -> check if user wishes to overwrite
1472// if 1 -> overwrite from given position
1473// if 2 -> write only from the first empty position
1474// if 3 -> do not overwrite
1475int File_Write(int fd, void* buffer, int size)
1476{
1477 boldBlue();
1478 printf("File_Write(%d, buffer, %d):\n",fd, size);
1479 reset();
1480
1481 //check if fd is valid index
1482 if(fd < 0 || fd > MAX_OPEN_FILES){
1483 blue();
1484 dprintf("... error: fd=%d out of bound\n", fd);
1485 reset();
1486 osErrno = E_BAD_FD;
1487 return -1;
1488 }
1489
1490 open_file_t file = open_files[fd];
1491
1492 //check if not an open file
1493 if(file.inode <= 0){
1494 blue();
1495 dprintf("... error: fd=%d not an open file\n", fd);
1496 reset();
1497 osErrno = E_BAD_FD;
1498 return -1;
1499 }
1500
1501 //check if file size is full
1502 if(file.size == MAX_SECTORS_PER_FILE*SECTOR_SIZE)
1503 {
1504 blue();
1505 dprintf("... error: file fd=%d is full\n", fd);
1506 reset();
1507 osErrno = E_FILE_TOO_BIG;
1508 return 0;
1509 }
1510
1511 //load file's inode disk sectors
1512 int inode = file.inode;
1513 int inode_sector = INODE_TABLE_START_SECTOR+inode/INODES_PER_SECTOR;
1514 char inode_buffer[SECTOR_SIZE];
1515 if(Disk_Read(inode_sector, inode_buffer) < 0) { osErrno = E_GENERAL; return -1; }
1516
1517 blue();
1518 dprintf("... load inode table for inode from disk sector %d\n", inode_sector);
1519 reset();
1520
1521 //get inode
1522 int inode_start_entry = (inode_sector-INODE_TABLE_START_SECTOR)*INODES_PER_SECTOR;
1523 int offset = inode-inode_start_entry;
1524 assert(0 <= offset && offset < INODES_PER_SECTOR);
1525 inode_t* fileInode = (inode_t*)(inode_buffer+offset*sizeof(inode_t));
1526 blue();
1527 dprintf("... inode %d (size=%d, type=%d)\n",
1528 inode, fileInode->size, fileInode->type);
1529 reset();
1530
1531 /***check if user wishes to overwrite or not***/
1532
1533 //write data from after the given data pointer
1534 int position = file.pos;
1535 int action = 0;
1536 int positionByte = file.posByte;
1537
1538 //check cases for potential overwriting:
1539 //if recently opened file is non-empty
1540 //if current pointer is at arbitrary point within file contents
1541 if(file.size - ((file.pos+1)*SECTOR_SIZE-(SECTOR_SIZE-file.posByte)) != 0){
1542 //check if user wishes to overwrite
1543 action = toOverwriteOrNot(fd);
1544 if(action == 3){
1545 blue();
1546 printf("... User wishes to not overwrite already existing file. No write done\n");
1547 reset();
1548 return 0;
1549 }
1550 else if(action == 2){ //write only from the first empty position
1551 position = file.size/SECTOR_SIZE;
1552 positionByte = 0;
1553
1554 if(file.size%SECTOR_SIZE){
1555 positionByte = file.size%SECTOR_SIZE;
1556 }
1557 blue();
1558 dprintf("... User wishes to write from first empty byte position=%d in block position=%d with file size=%d\n",
1559 positionByte, position, file.size);
1560 reset();
1561 }
1562 else{//wishes to overwrite. delete file contents
1563 int pos = 0;
1564 char dataBuffer[SECTOR_SIZE];
1565 bzero(dataBuffer, SECTOR_SIZE);
1566 while(fileInode->data[pos] != 0){
1567 // disk sector has to be freed
1568 if(Disk_Write(fileInode->data[pos], dataBuffer) < 0) return -1;
1569 if (bitmap_reset(SECTOR_BITMAP_START_SECTOR, SECTOR_BITMAP_SECTORS, fileInode->data[pos]) < 0) {
1570 blue();
1571 dprintf("... error: free sector occupied by file in sector bitmap unsuccessful\n");
1572 reset();
1573 return -1;
1574 }
1575 pos++;
1576 }
1577 position = 0;
1578 positionByte = 0;
1579 file.size = 0;
1580 fileInode->size = 0;
1581 blue();
1582 dprintf("... User wishes to overwrite entire file. Starting at block position=%d with file size=%d\n",
1583 position, file.size);
1584 reset();
1585 }
1586 }
1587
1588 int sizeToWrite = size;
1589
1590 //check if the rem space left is less than size to write
1591 if(SECTOR_SIZE*MAX_SECTORS_PER_FILE - file.size < size){
1592 blue();
1593 dprintf("... error: fd=%d of size=%d at block position=%d at byte position=%d cannot add size=%d bytes.\n"
1594 "Ask user what they want to do\n", fd, file.size, position, positionByte, size, sizeToWrite);
1595 reset();
1596 if(ifWriteRem(fd) == 1){
1597 sizeToWrite = SECTOR_SIZE*MAX_SECTORS_PER_FILE - file.size;
1598 blue();
1599 dprintf("... User chose to write only %d bytes to file=%d\n", sizeToWrite, fd);
1600 reset();
1601 }
1602 else{
1603 blue();
1604 dprintf("... User chose to not write remaining %d bytes. Ending call\n", SECTOR_SIZE*MAX_SECTORS_PER_FILE - file.size);
1605 osErrno = E_FILE_TOO_BIG;
1606 return 0;
1607 }
1608 }
1609
1610 /***determine how many sectors need to be written in***/
1611
1612 int sectorsToWrite = 0;
1613
1614 if(positionByte != 0){//if posByte is at part of current sector
1615 sectorsToWrite++;
1616 if(SECTOR_SIZE - positionByte < sizeToWrite){//need to write more sectors
1617 int remSize = sizeToWrite - (SECTOR_SIZE - positionByte);
1618 sectorsToWrite += remSize/SECTOR_SIZE;
1619
1620 //check for remainder
1621 if(remSize%SECTOR_SIZE){
1622 sectorsToWrite++;
1623 }
1624 }
1625 }
1626 else{//if posByte is at beginning of a sector
1627 sectorsToWrite = sizeToWrite/SECTOR_SIZE;
1628
1629 //check remainder
1630 if(sizeToWrite%SECTOR_SIZE){
1631 sectorsToWrite++;
1632 }
1633 }
1634
1635 blue();
1636 dprintf("... extra sectors needed=%d for fd=%d at data[%d] at byte position=%d\n", sectorsToWrite,
1637 fd, position, positionByte);
1638 reset();
1639
1640 /***write into data blocks***/
1641
1642 char tempBuff[SECTOR_SIZE];
1643 int ctrSize = 0;
1644 for(int i = 0; i < sectorsToWrite; i++){
1645 //find first sector to use if starting at new position
1646 int newsec = 0;
1647 if(positionByte == 0){
1648 newsec = bitmap_first_unused(SECTOR_BITMAP_START_SECTOR, SECTOR_BITMAP_SECTORS, SECTOR_BITMAP_SIZE);
1649
1650 //check if space exists on disk for write
1651 if(newsec < 0){
1652 blue();
1653 dprintf("... error: no space on disk, write cannot complete\n");
1654 reset();
1655 osErrno = E_NO_SPACE;
1656 return -1;
1657 }
1658 fileInode->data[position] = newsec;
1659 }
1660
1661 bzero(tempBuff, SECTOR_SIZE);
1662 if(Disk_Read(fileInode->data[position], tempBuff) < 0){
1663 blue();
1664 dprintf("... error: can't read sector %d\n", fileInode->data[position]);
1665 reset();
1666 osErrno=E_GENERAL;
1667 return -1;
1668 }
1669
1670 blue();
1671 dprintf("... going to write into disk in sector %d\n", newsec);
1672 reset();
1673
1674 int currBytes = 0; //keep track of what's currently needed to extract from buffer
1675
1676 if(positionByte != 0){//starting out at arbitrary point in currsector
1677 currBytes = SECTOR_SIZE - positionByte;
1678 }
1679 else if(i == sectorsToWrite - 1){//at last sector to write into
1680 currBytes = sizeToWrite - ctrSize;
1681 }
1682 else{//full sectors
1683 currBytes = SECTOR_SIZE;
1684 }
1685
1686 blue();
1687 dprintf("... copying data %d bytes from ptr position %d in buffer into tempbuff at position %d\n",
1688 currBytes, ctrSize, positionByte);
1689 reset();
1690
1691 //copy what's needed from buffer into tempbuff
1692 memcpy(tempBuff+positionByte, buffer+ctrSize, currBytes);
1693
1694 ctrSize += currBytes;//where to next extract from buffer
1695
1696 if(Disk_Write(fileInode->data[position], tempBuff) < 0) {
1697 blue();
1698 dprintf("... error: failed to write buffer data\n");
1699 reset();
1700 osErrno = E_GENERAL;
1701 return -1;
1702 }
1703 blue();
1704 dprintf("... Writing data[%d]=%d\n", position, fileInode->data[position]);
1705 reset();
1706
1707 //specify new byte position if didn't read the entire last sector
1708 if(i == sectorsToWrite - 1 && positionByte + currBytes < SECTOR_SIZE){
1709 positionByte = currBytes;
1710 }
1711 else{//new byte position and block position if read entire sectors
1712 position++;
1713 positionByte = 0;
1714 }
1715 }
1716
1717 /***update file and file inode***/
1718
1719 //update file and inode size
1720 open_files[fd].size = file.size + sizeToWrite;
1721 open_files[fd].pos = position;
1722 open_files[fd].posByte = positionByte;
1723
1724 //set new inode size
1725 fileInode->size = open_files[fd].size;
1726
1727
1728 //write to disk the updated inode
1729 if(Disk_Write(inode_sector, inode_buffer) < 0) return -1;
1730 blue();
1731 dprintf("... update child inode %d (size=%d, type=%d), update disk sector %d\n",
1732 inode, fileInode->size, fileInode->type, inode_sector);
1733
1734 dprintf("... file=%d is now at block pos=%d and byte position=%d with size=%d\n",
1735 fd, open_files[fd].pos, open_files[fd].posByte, open_files[fd].size);
1736 reset();
1737 return sizeToWrite;
1738}
1739int File_Seek(int fd, int offset)
1740{
1741 dprintf("File_Seek(%d, %d):\n", fd, offset);
1742 //check if fd is valid index
1743 if(fd < 0 || fd > MAX_OPEN_FILES){
1744 dprintf("... error: fd=%d out of bound\n", fd);
1745 osErrno = E_BAD_FD;
1746 return -1;
1747 }
1748 //check if open file
1749 if(open_files[fd].inode <= 0) {
1750 dprintf("... error: fd=%d not an open file\n", fd);
1751 osErrno = E_BAD_FD;
1752 return -1;
1753 }
1754
1755 //check if offset is within bounds
1756 if(offset > open_files[fd].size || offset == -1){
1757 dprintf("... error: offset=%d out of bound\n", fd);
1758 osErrno = E_SEEK_OUT_OF_BOUNDS;
1759 return -1;
1760 }
1761
1762 open_files[fd].pos = offset/SECTOR_SIZE + (offset%SECTOR_SIZE != 0 ? 0 : 1);
1763 open_files[fd].posByte = offset%SECTOR_SIZE;
1764
1765 return open_files[fd].pos;
1766}
1767
1768int File_Close(int fd)
1769{
1770 dprintf("File_Close(%d):\n", fd);
1771 if(0 > fd || fd > MAX_OPEN_FILES) {
1772 dprintf("... error: fd=%d out of bound\n", fd);
1773 osErrno = E_BAD_FD;
1774 return -1;
1775 }
1776 if(open_files[fd].inode <= 0) {
1777 dprintf("... error: fd=%d not an open file\n", fd);
1778 osErrno = E_BAD_FD;
1779 return -1;
1780 }
1781
1782
1783
1784 dprintf("... file closed successfully\n");
1785 open_files[fd].inode = 0;
1786 return 0;
1787}
1788
1789int Dir_Create(char* path)
1790{
1791 dprintf("Dir_Create('%s'):\n", path);
1792 return create_file_or_directory(1, path);
1793}
1794
1795int Dir_Unlink(char* path)
1796{
1797 dprintf("Dir_Unlink('%s'):\n", path);
1798 // no empty path and no root directory allowed
1799 if(path==NULL) {
1800 dprintf("... error: empty path (NULL) for directory unlink");
1801 osErrno = E_GENERAL;
1802 return -1;
1803 }
1804
1805 if(strcmp(path, "/")==0) {
1806 dprintf("... error: not allowed to unlink root directory");
1807 osErrno = E_ROOT_DIR;
1808 return -1;
1809 }
1810
1811 // find parent and children (if theres any)
1812 int child_inode;
1813 int parent_inode = follow_path(path, &child_inode, NULL);
1814 if(parent_inode < 0) {
1815 dprintf("... error: directory '%s' not found\n", path);
1816 osErrno = E_NO_SUCH_DIR;
1817 return -1;
1818 }
1819
1820 int remove = remove_inode(1, parent_inode, child_inode);
1821
1822 if (remove==-1) {
1823 dprintf("... error: general error when unlinking directory\n");
1824 osErrno = E_GENERAL;
1825 return -1;
1826 } else if (remove==-3) {
1827 dprintf("... error: no directory, wrong type\n");
1828 osErrno = E_NO_SUCH_DIR;
1829 return -1;
1830 } else if (remove==-2) {
1831 dprintf("... error: directory %s not empty", path);
1832 osErrno = E_DIR_NOT_EMPTY;
1833 return -1;
1834 } else {
1835 return 0;
1836 }
1837
1838
1839}
1840
1841int Dir_Size(char* path)
1842{
1843 dprintf("Dir_Size('%s'):\n", path);
1844 // no empty path allowed
1845 if(path==NULL) {
1846 dprintf("... error: empty path (NULL) given as parameter\n");
1847 osErrno = E_GENERAL;
1848 return -1;
1849 }
1850
1851 // directory has to exist
1852 int child_inode;
1853 int parent_inode = follow_path(path, &child_inode, NULL);
1854 if(parent_inode < 0) {
1855 dprintf("... error: directory '%s' not found\n", path);
1856 osErrno = E_NO_SUCH_DIR;
1857 return -1;
1858 }
1859
1860 // load the disk sector containing the child inode
1861 int inode_sector = INODE_TABLE_START_SECTOR+child_inode/INODES_PER_SECTOR;
1862 char inode_buffer[SECTOR_SIZE];
1863 if(Disk_Read(inode_sector, inode_buffer) < 0) return -1;
1864 dprintf("... load inode table for child inode from disk sector %d\n", inode_sector);
1865
1866 // get the child inode
1867 int inode_start_entry = (inode_sector-INODE_TABLE_START_SECTOR)*INODES_PER_SECTOR;
1868 int offset = child_inode-inode_start_entry;
1869 assert(0 <= offset && offset < INODES_PER_SECTOR);
1870 inode_t* child = (inode_t*)(inode_buffer+offset*sizeof(inode_t));
1871
1872 // check for type
1873 if (child->type!=1) {
1874 dprintf("... error: wrong type, path leads to file\n");
1875 osErrno = E_GENERAL;
1876 return -1;
1877 }
1878
1879 return child->size*sizeof(dirent_t);
1880}
1881
1882int Dir_Read(char* path, void* buffer, int size)
1883{
1884 dprintf("Dir_Read('%s', buffer, %d):\n", path, size);
1885
1886 // no empty path allowed
1887 if(path==NULL) {
1888 dprintf("... error: empty path (NULL) given as parameter\n");
1889 osErrno = E_GENERAL;
1890 return -1;
1891 }
1892
1893 // directory has to exist
1894 int inode;
1895 int parent_inode = follow_path(path, &inode, NULL);
1896 if(parent_inode < 0) {
1897 dprintf("... error: directory '%s' not found\n", path);
1898 osErrno = E_NO_SUCH_DIR;
1899 return -1;
1900 }
1901
1902 // check if size parameter matches the actual directory size
1903 int act_size = Dir_Size(path);
1904 if (size>act_size) {
1905 dprintf("... error: size parameter %d does not match actual directory size of %d bytes.\n",
1906 size, act_size);
1907 osErrno=E_GENERAL;
1908 return -1;
1909 }
1910
1911 // check if size of buffer is large enough to hold all elements in the directory
1912 int buf_size = (int)malloc_usable_size(buffer);
1913 if (size>buf_size) {
1914 dprintf("... error: buffer provided has size %d, but %d bytes required\n",
1915 buf_size, size);
1916 osErrno=E_BUFFER_TOO_SMALL;
1917 return -1;
1918 }
1919
1920 // initialize buffer
1921 bzero(buffer, size);
1922
1923 // load disk sector from directory
1924 char inode_buffer[SECTOR_SIZE];
1925 int inode_sector = INODE_TABLE_START_SECTOR+inode/INODES_PER_SECTOR;
1926 if(Disk_Read(inode_sector, inode_buffer) < 0) return -1;
1927 dprintf("... load inode table for parent inode %d from disk sector %d\n",
1928 inode, inode_sector);
1929
1930 // get the directory inode
1931 int inode_start_entry = (inode_sector-INODE_TABLE_START_SECTOR)*INODES_PER_SECTOR;
1932 int offset = inode-inode_start_entry;
1933 assert(0 <= offset && offset < INODES_PER_SECTOR);
1934 inode_t* dir_inode = (inode_t*)(inode_buffer+offset*sizeof(inode_t));
1935 dprintf("... get inode %d (size=%d, type=%d)\n",
1936 inode, dir_inode->size, dir_inode->type);
1937
1938 // read the directory entries into the buffer
1939 int remainder=dir_inode->size%DIRENTS_PER_SECTOR;
1940 int group=dir_inode->size/DIRENTS_PER_SECTOR;
1941 int buf_offset = (int)(SECTOR_SIZE-SECTOR_SIZE%sizeof(dirent_t));
1942
1943 // a) completely filled sectors
1944 for(int i=0; i<group;i++) {
1945 if(Disk_Read(dir_inode->data[i], buffer+i*buf_offset) < 0) {
1946 dprintf("... error: cant read sector %d\n", dir_inode->data[i]);
1947 osErrno=E_GENERAL;
1948 return -1;
1949 }
1950 }
1951
1952 // b) partly filled sector
1953 if(remainder) {
1954 char buff[SECTOR_SIZE];
1955 if(Disk_Read(dir_inode->data[group], buff) < 0){
1956 dprintf("... error: cant read sector %d\n", dir_inode->data[group]);
1957 osErrno=E_GENERAL;
1958 return -1;
1959 }
1960
1961 memcpy(buffer+group*buf_offset, buff, remainder*sizeof(dirent_t));
1962
1963 }
1964
1965 return dir_inode->size;
1966}