· 7 years ago · Nov 21, 2018, 08:36 PM
1#include <stdio.h>
2#include <unistd.h>
3#include <string.h>
4#include <stdlib.h>
5
6#include "filesys.h"
7
8
9diskblock_t virtualDisk [MAXBLOCKS] ; // define our in-memory virtual, with MAXBLOCKS blocks
10fatentry_t FAT [MAXBLOCKS] ; // define a file allocation table with MAXBLOCKS 16-bit entries
11fatentry_t rootDirIndex = 0 ; // rootDir will be set by format
12direntry_t * currentDir = NULL ;
13fatentry_t currentDirIndex = 0 ;
14
15
16// -----------------------------------------------------------------------------
17// pre-defined
18void writedisk ( const char * filename )
19{
20 printf ( "writedisk> virtualdisk[0] = %s\n", virtualDisk[0].data ) ;
21 FILE * dest = fopen( filename, "w" ) ;
22 if ( fwrite ( virtualDisk, sizeof(virtualDisk), 1, dest ) < 0 )
23 fprintf ( stderr, "write virtual disk to disk failed\n" ) ;
24 //write( dest, virtualDisk, sizeof(virtualDisk) ) ;
25 fclose(dest) ;
26
27}
28
29void readdisk ( const char * filename )
30{
31 FILE * dest = fopen( filename, "r" ) ;
32 if ( fread ( virtualDisk, sizeof(virtualDisk), 1, dest ) < 0 )
33 fprintf ( stderr, "write virtual disk to disk failed\n" ) ;
34 //write( dest, virtualDisk, sizeof(virtualDisk) ) ;
35 fclose(dest) ;
36}
37
38// D
39void format ()
40{
41 diskblock_t block ;
42 direntry_t rootDir ;
43 int pos = 0 ;
44 int fatentry = 0 ;
45 int fatblocksneeded = (MAXBLOCKS / FATENTRYCOUNT ) ;
46
47 // prepare block 0 : fill it with '\0',
48 for (int i=0; i<BLOCKSIZE; i++)
49 block.data[i] = '\0';
50
51 // use strcpy() to copy some text to it for test purposes
52 strcpy(block.data, "CS3026 Operating Systems Assignment");
53
54 // write block 0 to virtual disk
55 memmove(virtualDisk[0].data, &block.data, BLOCKSIZE);
56
57 // prepare FAT table
58 FAT[0] = ENDOFCHAIN;
59 FAT[1] = 2;
60 FAT[2] = ENDOFCHAIN;
61 FAT[3] = ENDOFCHAIN;
62
63 for (int i=4; i<MAXBLOCKS; i++)
64 FAT[i] = UNUSED;
65
66 // write FAT blocks to virtual disk
67 copyFAT();
68
69 // prepare root directory
70 block = emptyDirBlock();
71 // write root directory block to virtual disk
72 rootDirIndex = fatblocksneeded + 1;
73 memmove(virtualDisk[rootDirIndex].data, &block.data, BLOCKSIZE);
74
75 // set current directory to be root
76 currentDirIndex = rootDirIndex;
77}
78
79// C
80MyFILE * myfopen(const char * filename, const char * mode)
81{
82 // check if we're in the correct mode
83 if (!(strcmp(mode, "r") == 0 ||
84 strcmp(mode, "w") == 0))
85 return FALSE;
86
87 // create a file,
88 MyFILE *file = malloc(sizeof(MyFILE));
89 file->pos = 0;
90 file->buffer = emptyBlock();
91
92 // assign the mode to the file r/w
93 strcpy(file->mode, mode);
94
95 // if it's for reading
96 if(strcmp(mode, "r") == 0)
97 {
98 // if file does not exist, exit
99 if(getFileLocation(filename) == FALSE)
100 exit(0);
101 // if it exists it returns the block it resides in
102 file->blockno = getFileLocation(filename);
103 return file;
104 }
105
106 // if file exists
107 if(getFileLocation(filename) != FALSE)
108 {
109 // path is the blocknumber
110 int path = getFileLocation(filename);
111
112 // if the block is smaller than root dir, in this case 3, quit
113 if(path <= BLOCKSIZE/FATENTRYCOUNT) exit(0);
114
115 // end the fat chain
116 setFatChain(path);
117 // save the fat table
118 copyFAT();
119 // empty all dir entries to "overwrite" the file
120 clearDir(filename);
121
122 // get the block o
123 int location = getUnusedDir();
124 currentDir[location].unused = FALSE;
125 }
126 // if file does not exist
127 else
128 {
129 // get the next unused block
130 int index = getUnusedBlock();
131 // innit a buffer block
132 diskblock_t block;
133 // fill in buffer block with currentDir block, should be empty/formatted
134 memmove(&block.data, virtualDisk[currentDirIndex].data, BLOCKSIZE);
135
136 // create a new entry and allocate memory for it
137 direntry_t *newEntry = calloc(1, sizeof(direntry_t));
138 // set the entry as a file
139 newEntry->isdir = FALSE;
140 newEntry->unused = FALSE;
141 newEntry->filelength = FALSE;
142 newEntry->firstblock = index;
143 // set next fat block as EOC
144 FAT[index] = ENDOFCHAIN;
145 // save fat table
146 copyFAT();
147
148 // get first unusred dir entry in the first dir block that has free entries
149 int entryNumber = getUnusedDir();
150 // set the global currentDir to the location where the file is to be created
151 currentDir = block.dir.entrylist;
152 // save the entry in the current dir the file name
153 currentDir[entryNumber] = *newEntry;
154 strcpy(currentDir[entryNumber].name, filename);
155
156 // save the buffer block to the virtual disk
157 memmove(virtualDisk[currentDirIndex].data, &block.data, BLOCKSIZE);
158 // save the blocknumber where the file is saved (starting point)
159 file->blockno = index;
160 return file;
161 }
162}
163
164void myfputc(int b, MyFILE *stream)
165{
166 // check if the mode is in reading, if yes - return
167 if (strcmp(stream->mode, "r") == FALSE)
168 return;
169
170 // if the position of the "text pointer" is equal or bigger than blocksize (1024 in this case), stops at 1024
171 if (stream->pos >= BLOCKSIZE)
172 {
173 // get the block number of the next unused block
174 int indexOfUnusedBlock = getUnusedBlock() ;
175 // change the fat table so that the block is checked as used
176 FAT[stream->blockno] = indexOfUnusedBlock ;
177 // set next block as eoc
178 FAT[indexOfUnusedBlock] = ENDOFCHAIN ;
179 // save fat table
180 copyFAT();
181
182 // reset the string stream pos/"text pointer" (kind of)
183 stream->pos = 0;
184 // save the buffer to the virtual disk (since the buffer is 1024bytes)
185 memmove(virtualDisk[stream->blockno].data, &stream->buffer.data, BLOCKSIZE);
186 // empty the buffer
187 stream->buffer = emptyBlock();
188 // assign the new unused block number to the buffer
189 stream->blockno = indexOfUnusedBlock;
190 }
191 // put the character in the buffer and increment the position of the text pointer
192 stream->buffer.data[stream->pos] = b;
193 stream->pos++;
194}
195
196int myfgetc(MyFILE *stream)
197{
198 // snapshot the block number in use
199 int index = stream->blockno;
200
201 // check if the block number is an EOC, the mode of the file is reading or the data in contains is null
202 if(index == ENDOFCHAIN
203 || strcmp(stream->mode, "r") == TRUE
204 || stream->buffer.data[index] == EOF)
205 return EOF;
206 // if it passes the if, return null
207
208 // since I couldn't figure out a way to reset the text poibter position we just check
209 // if it's a multiple of blocksize (1024) which is when we would reset it
210 if (stream->pos % BLOCKSIZE == 0)
211 {
212 // the blocknumber of the buffer is the next block in the fat table
213 stream->blockno = FAT[index];
214 // save the virtual disk block to the buffer block from which we read
215 memcpy(&stream->buffer, &virtualDisk[index], BLOCKSIZE);
216 // reset the position of the text pointer
217 stream->pos = 0;
218 }
219 // return the char and increment the text pointer
220 return stream->buffer.data[stream->pos++];
221}
222
223void myfclose(MyFILE *stream)
224{
225 // if the mode is in write
226 if(strcmp(stream->mode, "w") == 0)
227 {
228 // get the next unused block
229 int next = getUnusedBlock();
230 // set fat table block as used
231 FAT[stream->blockno] = next;
232 // move eoc to the next fat block
233 FAT[next] = ENDOFCHAIN;
234 // save fat table
235 copyFAT();
236 // save the incomplete buffer (this is because we wouldnt always have 1024 byte filled buffer blocks
237 memmove(virtualDisk[stream->blockno].data, &stream->buffer.data, BLOCKSIZE);
238 }
239}
240
241// B
242void mymkdir(char *path)
243{
244 // create buffer bock
245 diskblock_t block;
246
247 // makesure the last char is not /, can be fooled by having "folder//"
248 if(path[strlen(path)-1] == '/')
249 path[strlen(path)-1] = '\0'; //gives warning if NULL :(
250 // i've noticed thatif you make a root dir mymkdir("/") then it will crash
251
252 // set root directory if first char is root
253 if(path[0] == '/')
254 currentDirIndex = rootDirIndex;
255
256 // buffer string
257 char *b = calloc(sizeof(path), sizeof(char));
258 // delimeter
259 char *d= "/";
260 // remainder of the string
261 char *r;
262 // put the path to the buffer
263 strcpy(b, path);
264
265 // strtok gives a token if s is a string s[0] to s[x-1] if s[x] is d (or the starting point of some string d)
266 for(char *token=strtok_r(b, d, &r); token; token=strtok_r(NULL, d, &r))
267 {
268 // get block number of the directory extracted from the path
269 int location = getDir(token);
270 // if the remainder is '\0'
271 if (r == NULL)
272 {
273 // if the block number is not -1 we exit
274 if(location != EOF)
275 exit(0);
276
277 // reuse the int to get the first unused entry in the dir blocks
278 location = getUnusedDir();
279 // put the token (part of the path) as a name in the direntry
280 strcpy(currentDir[location].name, token);
281 // set dir entry properties
282 currentDir[location].isdir = TRUE;
283 currentDir[location].unused = FALSE;
284 currentDir[location].firstblock = getUnusedBlock();
285
286 // fill it up with a clear block
287 block = emptyDirBlock();
288 memmove(virtualDisk[currentDir[location].firstblock].data, &block.data, BLOCKSIZE);
289
290 // set the fat table
291 FAT[currentDir[location].firstblock] = ENDOFCHAIN;
292 copyFAT();
293 }
294 // if the remainder is not '\0', happens once we've been through all subpaths
295 else
296 {
297 // if the block number is -1
298 if(location == EOF)
299 exit(0);
300 // set the current working directory as the dir entry we're iterating through (0,1,2) in this case
301 currentDirIndex = virtualDisk[currentDirIndex].dir.entrylist[location].firstblock;
302 }
303 }
304
305}
306
307// TODO: Implement mylistdir
308char **mylistdir(char *path)
309{
310
311 // buffer string
312 char *b = calloc(sizeof(path), sizeof(path[0]));
313 // delimeter
314 char *d= "/";
315 // remainder of the string
316 char *r = calloc(MAXNAME, sizeof(char));
317
318 // copy string path to b
319 strcpy(b, path);
320
321 // if the first char from the path is /, then set current dir as root
322 if(path[0] == '/')
323 currentDirIndex = rootDirIndex;
324
325 // strtok gives a token if s is a string s[0] to s[x-1] if s[x] is d (or the starting point of some string d)
326 for(char *token=strtok_r(b, d, &r); token; token=strtok_r(NULL, d, &r))
327 {
328 // get the block number of the token
329 int location = getDir(token);
330 // if it does not exist
331 if (location == EOF)
332 exit(0);
333
334 // set the current dir index as the location inside the token
335 currentDirIndex = virtualDisk[currentDirIndex].dir.entrylist[location].firstblock;
336 }
337
338 // create a buffer block
339 diskblock_t block;
340 // set a buffer for fat
341 fatentry_t nextDir = currentDirIndex;
342
343 // set aside memory for the array that will hold dirs/files (ls) // currently one index only
344 char **result = calloc(1, sizeof(char*));
345 int index = 0;
346
347 // while the fat entry is not EOC
348 while(nextDir != ENDOFCHAIN)
349 {
350 // get that fat block and save it on the buffer block
351 memmove(&block.data, virtualDisk[nextDir].data, BLOCKSIZE);
352 // set the currentdir list to the entries of the buffer block
353 currentDir = block.dir.entrylist;
354 // iterate over the entries in the dir block
355 for(int i=0; i<block.dir.nextEntry; i++)
356 {
357 // if an entry is unused
358 if(currentDir[i].unused == FALSE)
359 {
360 // set aside memory for the list entry equiv to the filename
361 result[index] = calloc(sizeof(currentDir[i].name), sizeof(char));
362 // copy the filename and put it in the list and in the index we just allocated memory for
363 strcpy(result[index], currentDir[i].name);
364 index++;
365 // reallocate the space result takes by increasing it so it holds index+1
366 // we +1 to the memory as we want to keep one entry for an eof
367 result = realloc(result, ((1+index)*sizeof(char*)));
368 }
369 }
370 // nextdir++
371 nextDir = FAT[nextDir];
372 }
373 // set last entry as eof
374 result[index] = NULL;
375
376 // return the list of files/dirs
377 return result;
378}
379
380// A
381
382// -----------------------------------------------------------------------------
383// helper functions
384void copyFAT()
385{
386 // buffer block
387 diskblock_t block;
388 // block 1 and 2 are occupied by FAT in this case as maxblocks/fatentrycount is 2
389 for (int blockNum=1, i=0; blockNum<= (MAXBLOCKS/FATENTRYCOUNT); blockNum++)
390 {
391 for(int entry=0; entry<FATENTRYCOUNT; entry++, i++)
392 block.fat[entry] = FAT[i];
393 // save the fat block to the virtual disk
394 memmove(virtualDisk[blockNum].data, &block.data, BLOCKSIZE);
395 }
396}
397
398int getUnusedBlock()
399{
400 // i starts from 4 in this case (3 is root dir)
401 for (int i=MAXBLOCKS/FATENTRYCOUNT+2; i<MAXBLOCKS; i++)
402 if (FAT[i] == UNUSED)
403 return i;
404 // if the block is not used in the fat, return the block number and exit
405 exit(0);
406 return -1;
407}
408
409int getUnusedDir()
410{
411 // create buffer block and buffer fat entry
412 diskblock_t block;
413 fatentry_t nextDir = currentDirIndex;
414
415 // go through all dir blocks
416 while(nextDir != ENDOFCHAIN)
417 {
418 // save the current dir block to the buffer block
419 memmove(&block.data, virtualDisk[nextDir].data, BLOCKSIZE);
420 // for every dir entry in that specific dir block
421 for (int i=0; i<block.dir.nextEntry; i++)
422 {
423 // if the dir entry is unused
424 if(block.dir.entrylist[i].unused == TRUE)
425 {
426 // set that dir entry as the one to use and return its block num
427 currentDirIndex = nextDir;
428 currentDir = virtualDisk[currentDirIndex].dir.entrylist;
429 return i;
430 }
431 }
432 // checks the next block
433 nextDir = FAT[nextDir];
434 }
435 // grabs the next unused block;
436 int next = getUnusedBlock();
437 // set it in the fat table
438 FAT[currentDirIndex] = next;
439 // move the EOC fat block
440 FAT[next] = ENDOFCHAIN;
441 // save the fat table
442 copyFAT();
443
444 // clean the dir block
445 block = emptyDirBlock();
446 // set our current working directory index as that of the newly found unused block
447 currentDirIndex = next;
448 // save the buffer block to the virtual disk
449 memmove(virtualDisk[currentDirIndex].data, &block.data, BLOCKSIZE);
450 // actually "enter" the current directory based on the index
451 currentDir = virtualDisk[currentDirIndex].dir.entrylist;
452 // returns 0th entry
453 return 0;
454}
455
456int getFileLocation(const char *filename)
457{
458 // buffer dir block and buffer fat
459 diskblock_t dirBlock;
460 fatentry_t nextDir = rootDirIndex;
461
462 // while we reach the end of the fat entries
463 while(nextDir != ENDOFCHAIN)
464 {
465 // global current dir is the next fat entry
466 currentDirIndex = nextDir;
467 // grab the data from that block to our buffer
468 memmove(&dirBlock.data, virtualDisk[nextDir].data, BLOCKSIZE);
469 // current dir entry is the entries in the buffer block
470 currentDir = dirBlock.dir.entrylist;
471 // go through all buffer dir entries
472 for(int i=0; i<dirBlock.dir.nextEntry; i++)
473 {
474 // if the name of the entry is the same as the file name
475 if(strcmp(currentDir[i].name, filename) == 0)
476 return currentDir[i].firstblock;
477 // return the block where the entry is located
478 }
479 // nextDir++
480 nextDir = FAT[nextDir];
481 }
482 // file does not exist (as we cant have files in block 0/FALSE
483 return FALSE;
484}
485
486void setFatChain(int fatEntry)
487{
488 // next is the fat entry after fatEntry
489 int next = FAT[fatEntry];
490 // if the next fat entry is not eoc, recursively call endChain(fatEntry+1) //not literally fatEntry+1
491 if (next != ENDOFCHAIN) setFatChain(next);
492 // clean by overwriting the data in the vd whose fat entry is eoc using the empty block
493 memmove(virtualDisk[fatEntry].data, emptyBlock().data, BLOCKSIZE);
494 // set that fatentry as unused
495 FAT[fatEntry] = UNUSED;
496}
497
498diskblock_t emptyBlock()
499{
500 // create a block
501 diskblock_t block;
502 // set all of it's blocks as NULL
503 for(int i=0; i<BLOCKSIZE; i++)
504 block.data[i] = '\0';
505 // return the newly cleaned block
506 return block;
507}
508
509diskblock_t emptyDirBlock()
510{
511 // create a new clean block
512 diskblock_t block = emptyBlock();
513 // set it as a dir block
514 block.dir.nextEntry = FALSE;
515 block.dir.isdir = TRUE;
516
517 // create a new dir entry list
518 direntry_t cleanEntry;
519 // set all dir entries as null
520 memset(&cleanEntry, '\0', sizeof(direntry_t));
521
522 // set the entry properties
523 cleanEntry.isdir = FALSE;
524 // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! chande to false to D
525 cleanEntry.unused = TRUE;
526 // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! or just change format
527 cleanEntry.firstblock = ENDOFCHAIN;
528 cleanEntry.filelength = FALSE;
529
530 // iterate over all dir entries in the block
531 for(; block.dir.nextEntry<DIRENTRYCOUNT; block.dir.nextEntry++)
532 {
533 // set all entries as the newly created entry (clean)
534 block.dir.entrylist[block.dir.nextEntry] = cleanEntry;
535 }
536
537 // return the newly created block with clean dirs
538 return block;
539}
540
541void clearDir(const char *filename)
542{
543 // create buffer block and fat entry
544 diskblock_t dirBlock;
545 fatentry_t nextDir = rootDirIndex;
546
547 // while the fat is not eoc
548 while(nextDir != ENDOFCHAIN)
549 {
550 // set the current working directory as our buffer fat
551 currentDirIndex = nextDir;
552 // move the nextDir-th block to the buffer block
553 memmove(&dirBlock.data, virtualDisk[nextDir].data, BLOCKSIZE);
554 // set currentDir entry list as the one from the buffer block
555 currentDir = dirBlock.dir.entrylist;
556 // for all entries in the buffer block
557 for(int i=0; i<dirBlock.dir.nextEntry; i++)
558 // if the entry matches the file's name
559 if(strcmp(currentDir[i].name, filename) == 0)
560 {
561 // clean the block
562 currentDir[i].firstblock = getUnusedBlock();
563 currentDir[i].entrylength = sizeof(currentDir);
564 return;
565 }
566 // nextdir++
567 nextDir = FAT[nextDir];
568 }
569}
570
571int getDir(const char *path)
572{
573 // buffer block and fat
574 diskblock_t block;
575 fatentry_t nextDir = currentDirIndex;
576 // while the fat entry is not eoc
577 while(nextDir != ENDOFCHAIN)
578 {
579 // move the fat block from the vd to the buffer block
580 memmove(&block.data, virtualDisk[currentDirIndex].data, BLOCKSIZE);
581 // for every dir in the block
582 for(int i=0; i<block.dir.nextEntry; i++)
583 {
584 // if the string in the dir entry is the same as the path
585 if (strcmp(block.dir.entrylist[i].name, path) == 0)
586 {
587 // set currenr dir to be path
588 currentDirIndex = nextDir;
589 currentDir = block.dir.entrylist;
590 // return block number
591 return i;
592 }
593 }
594 // nextdir++
595 nextDir = FAT[nextDir];
596 }
597 return EOF;
598}
599
600void printDirList(char **dirs)
601{
602 // this is just for printing the list of dirs and make it look like ls
603 int i = 0;
604 printf("\n");
605 while(dirs[i] != '\0')
606 {
607 printf("\t%s", dirs[i]);
608 i++;
609 }
610 printf("\n\n");
611 return;
612}
613
614// -----------------------------------------------------------------------------
615// testing purposes
616void printBlock ( int blockIndex )
617{
618 printf ( "virtualdisk[%d] = %s\n", blockIndex, virtualDisk[blockIndex].data ) ;
619}