b3a42b93b50523611504b3b90a88358f14293b38
[repair.git] / Repair / RepairCompiler / MCC / Runtime / danfile.cc
1 #include <sys/types.h>
2 #include <sys/stat.h>
3 #include <string.h>
4 #include <fcntl.h>
5 #include <unistd.h>
6 #include <stdlib.h>
7 #include <stdio.h>
8 #include <sys/mman.h>
9 #include <sys/time.h>
10 #include <assert.h>
11
12 #include <errno.h>
13 extern int errno;
14
15 #include "file.h"
16
17 #include "test3_aux.h"
18 #include "memory.h"
19
20 char *dstring="d\0";
21 struct filedesc files[MAXFILES];
22 struct InodeBitmap ib;
23 struct BlockBitmap bb;
24
25 int bbbptr;  // pointer to the BlockBitmap block
26 int ibbptr;  // pointer to the InodeBlock block
27 int itbptr;  // pointer to the InodeTable block
28 int rdiptr;  // pointer to the RootDirectoryInode block
29
30 struct InodeBitmap* sc_ib;
31 struct BlockBitmap* sc_bb;
32 struct InodeBlock* sc_it;
33 int sc_bbbptr;
34 int sc_ibbptr;
35 int sc_itbptr;
36 int sc_rdiptr;
37
38 #include "SimpleHash.h"
39
40 int testinode(int i) {
41     char temp;
42     assert(sc_ib);
43     temp = sc_ib->inode[i/8]&(1<<(i%8));
44     return temp == 0 ? 0 : 1;
45 }
46
47 int testblock(int i) {
48     char temp;
49     assert(sc_bb);
50     temp = sc_bb->blocks[i/8]&(1<<(i%8));
51     return temp == 0 ? 0 : 1;
52 }
53
54 unsigned long selfcheck2(struct block* d) {
55
56     struct timeval begin,end;
57     unsigned long t;
58     gettimeofday(&begin,NULL);
59
60 #include "test3.cc"
61
62     gettimeofday(&end,NULL);
63     t=(end.tv_sec-begin.tv_sec)*1000000+end.tv_usec-begin.tv_usec;
64     return t;
65 }
66
67 void selfcheck(struct block* diskptr) {
68
69     /* get time information for statistics */
70     struct timeval begin,end;
71     unsigned long t;
72     gettimeofday(&begin,NULL);
73
74     
75     /* hand written data structure consistency */
76
77     struct SuperBlock* sb = (struct SuperBlock*)&diskptr[0];
78     struct GroupBlock* gb = (struct GroupBlock*)&diskptr[1];
79     
80     int numblocks = sb->NumberofBlocks;
81     int numinodes = sb->NumberofInodes;
82
83     SimpleHash* hash_inodeof = new SimpleHash(1000); // estimation of the number of files!
84     SimpleHash* hash_contents = new SimpleHash(1000); // contents
85     SimpleList* list_inodes = new SimpleList();
86     SimpleList* list_blocks = new SimpleList();
87
88     // simple test
89
90     // check bitmap consistency with superblock, groupblock, inotetableblock
91     // inodebitmapblock, blockbitmapblock, rootidrectoryinode
92
93     sc_bbbptr = gb->BlockBitmapBlock;
94     sc_ibbptr = gb->InodeBitmapBlock;
95     sc_itbptr = gb->InodeTableBlock;
96     sc_rdiptr = sb->RootDirectoryInode;
97
98     // constraint 8: automatic...
99     // constraint 9: automatic...
100
101     // constraint 10:
102     if (sc_itbptr < numblocks) {
103         sc_it = (InodeBlock*)&diskptr[sc_itbptr];        
104     } else {
105         sc_it = NULL;
106     }
107
108     // constraint 11:
109     if (sc_ibbptr < numblocks) {
110         sc_ib = (InodeBitmap*)&diskptr[sc_ibbptr];
111     } else {
112         sc_ib = NULL;
113     }
114
115     // constraint 12:
116     if (sc_bbbptr < numblocks) {
117         sc_bb = (BlockBitmap*)&diskptr[sc_bbbptr];
118     } else {
119         sc_bb = NULL;
120     }
121
122     // rule 1
123     if (sc_bb) {
124         // constraint 3
125         assert(testblock(0)); // superblock
126         
127         // building blocks
128         list_blocks->add(0);
129     }
130
131     // rule 2
132     if (sc_bb) {
133         // constraint 3
134         assert(testblock(1)); // groupblock
135
136         // building list_blocks
137         list_blocks->add(1);
138     }
139
140     // rule 3
141     if (sc_bb) {
142         // constraint 3
143         assert(testblock(sc_itbptr));
144
145         // building list_blocks
146         list_blocks->add(sc_itbptr);
147     }
148
149     // rule 4
150     if (sc_bb) {
151         // constraint 3
152         assert(testblock(sc_ibbptr));
153
154         // building list_blocks
155         list_blocks->add(sc_ibbptr);
156     }
157
158     // rule 5
159     if (sc_bb) {
160         // constraint 3
161         assert(testblock(sc_bbbptr));
162
163         // building list_blocks
164         list_blocks->add(sc_bbbptr);
165     }
166
167     // build inodeof and contents
168     if (sb->RootDirectoryInode < numinodes) {
169         int dinode = sb->RootDirectoryInode;
170
171         // building list_inodes
172         list_inodes->add(dinode);
173
174         for (int k = 0 ; k <= 11 ; k++) {
175
176             int block = sc_it->entries[dinode].Blockptr[k];
177
178             if (block != 0) {
179                 hash_contents->add(dinode, block);
180                 list_blocks->add(block);
181             }
182             
183             if (block < numblocks) {
184
185                 DirectoryBlock* db = (DirectoryBlock*)&diskptr[block];
186
187                 for (int j = 0; j < sb->blocksize/128 ; j++) {
188
189                     DirectoryEntry* de = (DirectoryEntry*)&db->entries[j];
190
191                     if (de->inodenumber < numinodes) {
192                         // add <de, de.inodenumber> to inodeof                    
193                         hash_inodeof->add((int)de, de->inodenumber);
194                     }
195                     
196                     if (de->inodenumber < numinodes && de->inodenumber != 0) {
197                         
198                         // build list_inodes
199                         list_inodes->add(de->inodenumber);                        
200                         
201                         for (int j2 = 0 ; j2 <= 11 ; j2++) {
202                             int block2 = sc_it->entries[de->inodenumber].Blockptr[j2];
203                             if (block2 != 0) {
204                                 hash_contents->add(de->inodenumber, block2);
205                                 if (block2 < numblocks) {
206                                     list_blocks->add(block2);
207                                 }
208                             }
209                         }
210                     }
211                 }
212             }
213         }
214     }
215
216     //printf("\n");
217
218     // rule 6 and rule 11: rootdirectoryinode
219     if (sb->RootDirectoryInode < numinodes) {
220         int inode = sb->RootDirectoryInode;
221
222         // constraint 1
223         assert(testinode(inode));
224
225         int filesize = sc_it->entries[inode].filesize;
226         int contents = 0;
227         for (int j = 0; j <= 11; j++) {
228             int block2 = sc_it->entries[inode].Blockptr[j];
229             if (block2 != 0) {
230                 // TBD: needs to actual store state because
231                 // there could be duplicate numbers and they
232                 // shouldn't be double counted
233                 contents++;
234
235                 // rule 11
236                 if (block2 < numblocks) {
237                     // constraint 3
238                     assert(testblock(block2));
239                     
240                     // constraint 7
241                     //printf("%d - %d %d %d\n", inode, j, block2, hash_contents->countdata(block2));
242                     assert(hash_contents->countdata(block2)==1);
243                 }
244             }
245         }
246
247         // constraint 6
248         assert(filesize <= (contents*8192));
249
250         // constraint 5:
251         assert(sc_it->entries[inode].referencecount == hash_inodeof->countdata(inode));
252     }
253
254     // rule 14
255     if (sb->RootDirectoryInode < numinodes) {
256         int dinode = sb->RootDirectoryInode;
257
258         for (int j = 0; j < sb->blocksize/128 ; j++) {
259             for (int k = 0 ; k <= 11 ; k++) {
260                 int block = sc_it->entries[dinode].Blockptr[k];
261                 if (block < numblocks) {
262                     DirectoryBlock* db = (DirectoryBlock*)&diskptr[block];
263                     DirectoryEntry* de = (DirectoryEntry*)&db->entries[j];
264                     
265                     int inode = de->inodenumber;
266                     if (inode < numinodes && inode != 0) {
267
268                         // constraint 1
269                         assert(testinode(inode));
270                         
271                         // constraint 6
272                         int filesize = sc_it->entries[inode].filesize;
273                         int contents = 0;
274                         for (int j2 = 0; j2 <= 11; j2++) {
275                             int block2 = sc_it->entries[inode].Blockptr[j2];
276                             if (block2 != 0) {
277                                 // TBD 
278                                 contents++;
279
280                                 // rule 11
281                                 if (block2 < numblocks) {
282                                     // constraint 3
283                                     assert(testblock(block2));
284                                     
285                                     // constraint 7
286                                     assert(hash_contents->countdata(block2)==1);
287                                 }
288                             }
289                         }
290                         assert(filesize <= (contents*8192));
291
292                         // constraint 5:
293                         assert(sc_it->entries[inode].referencecount == hash_inodeof->countdata(inode));                                                
294                     }
295                 }
296             }
297         }
298     }
299
300     // to go, [7, 8 ]
301     // interesting question is going to be how to deal with 7 and 8
302     // actually it turns out that the constraints bound to rules 7 and 8 are
303     // easy... its just that creating the lists for 7 and 8 is a little tricky...
304     // 7 can easily piggyback on the creation of inodeof/contents... it fits quite 
305     // nicely into that traversal... same goes for 8
306
307     // rule 7
308     for (int i = 0 ; i < numinodes ; i++) {    
309         if (!list_inodes->contains(i)) {
310             // constraint 2
311             if (testinode(i)) {
312                 printf("<bad inode,%d>", i);
313                 assert(testinode(i)==0);
314             } 
315         } 
316     } 
317
318     // rule 8
319     for (int i = 0 ; i < numblocks ; i++) {    
320         if (!list_blocks->contains(i)) {
321             // constraint 4
322             if (testblock(i)) {
323                 printf("<bad block,%d>", i);
324                 assert(testblock(i)==0);
325             }
326
327         }
328     } 
329
330
331     gettimeofday(&end,NULL);
332     t=(end.tv_sec-begin.tv_sec)*1000000+end.tv_usec-begin.tv_usec;
333
334     printf("\npassed tests in %ld u-seconds!\n", t);
335
336
337 }
338
339
340 int main(int argc, char **argv) 
341 {
342   initializemmap();
343
344   for(int i=0;i<MAXFILES;i++)
345     files[i].used=false;
346
347
348   if (argc <= 1) {
349       printf("Filesystem Repair:\n\tusage: main [0..9]\n\n");
350       printf("\t 0 : creates disk\n");
351       printf("\t 1 : mount disk, creates files and writes test data\n");
352       printf("\t 2 : \n");
353       printf("\t 3 : inserts errors to break specs\n");
354       printf("\t 4 : \n");
355       printf("\t 5 : \n");
356       printf("\t 6 : \n");
357       printf("\t 7 : \n");
358       printf("\t 8 : \n");
359       printf("\t 9 : \n");
360       exit(-1);
361   }
362
363   switch(argv[1][0]) {
364
365   case '0': 
366     //creates a disk
367     createdisk(); 
368     return 1;
369
370
371   case '1': { 
372     /* mounts the disk, creates NUMFILES files, and writes "buf" in each file 
373        for 90 times */ 
374     struct block * ptr=mountdisk("disk");
375
376     for(int i=0; i<NUMFILES; i++) {
377       char filename[10];
378       sprintf(filename,"file_%d",i);
379       openfile(ptr,filename);
380     }    
381
382     for(int j=0; j<90; j++) {
383       for(int i=0; i<NUMFILES; i++) {
384         char *buf="01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123";
385         writefile(ptr,i,buf,122);
386       }
387     }
388
389     for(int i=0; i<NUMFILES; i++) {
390       closefile(ptr,i);
391     }
392
393     printdirectory(ptr);
394     printinodeblock(ptr);
395
396     unmountdisk(ptr);
397     break;
398   }
399
400
401   case 'r': {
402     struct block * ptr=mountdisk("disk");
403
404     printdirectory(ptr);
405     printinodeblock(ptr);
406
407     // check the DSs
408     unsigned long time = 0;
409     for (int i = 0; i < 50; i++) {
410       //      time += benchmark();
411     }
412
413     printf("\ninterpreted: %u us\n", (time/50)); 
414     
415     break;
416   }      
417
418   case 's': {
419     struct block * ptr=mountdisk("disk");
420
421     printdirectory(ptr);
422     printinodeblock(ptr);
423
424     // check the DSs
425     selfcheck(ptr);
426     
427
428     break;
429   }
430
431   case 'x': {
432     struct block * ptr=mountdisk("disk");
433
434     printdirectory(ptr);
435     printinodeblock(ptr);
436
437     // check the DSs
438     // check the DSs
439     unsigned long time = 0;
440
441     time += selfcheck2(ptr);
442     
443     printf("\ncompiled: %u us\n", (time));    
444
445     break;
446   }
447
448
449   // insert errors that break the specs
450   
451   case '5': {
452   // prints the directory structure, and prints the contents of each file
453     struct block * ptr=mountdisk("disk");
454     printdirectory(ptr);
455     for(int i=1; i<NUMFILES; i++) {
456       char filename[10];
457       sprintf(filename,"file_%d",i);
458       printfile(filename,ptr);
459     }
460     unmountdisk(ptr);
461     break;
462   }
463  
464   case '6': {
465   // the same as "case '1'" only that the files are accessed in reversed order
466     struct block * ptr=mountdisk("disk");
467     for(int i=NUMFILES; i>1; i--) {
468       char filename[10];
469       sprintf(filename,"file_%d",i);
470       openfile(ptr,filename);
471     }
472     for(int j=0; j<90; j++) {
473       for(int i=NUMFILES; i>1; i--) {
474         char *buf="01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123";
475         writefile(ptr,i,buf,122);
476       }
477     }
478     for(int i=NUMFILES; i>1; i--) {
479       closefile(ptr,i);
480     }
481     unmountdisk(ptr);
482     break;
483   }
484
485   case '7': {
486     struct block * ptr=mountdisk("disk");
487     for(int i=NUMFILES; i>=0; i--) {
488       char filename[10];
489       sprintf(filename,"file_%d",i);
490       openfile(ptr,filename);
491     }
492
493     for(int j=0;j<6000;j++) {
494       for(int i=NUMFILES; i>=0; i--) {
495         char name[10];
496         int len=sprintf(name, "%d ",i);
497         writefile(ptr,i,name,len);
498       }
499     }
500     for(int i=NUMFILES; i>=0; i--) {
501       closefile(ptr,i);
502     }
503     for(int i=NUMFILES; i>=0; i--) {
504       char filename[10];
505       sprintf(filename,"file_%d",i);
506       openfile(ptr,filename);
507     }
508
509     for(int j=0;j<400;j++) {
510       for(int i=NUMFILES; i>=0; i--) {
511         int l=0;
512         char name[10];
513         int len=sprintf(name, "%d ",i);
514         readfile(ptr,i,name,len);
515         sscanf(name, "%d ", &l);
516         if (l!=i) {
517           printf("ERROR in benchmark\n");
518         }
519       }
520     }
521     for(int i=NUMFILES; i>=0; i--) {
522       closefile(ptr,i);
523     }
524     unmountdisk(ptr);
525   }
526   break;
527
528
529   case '8': {
530     {
531       struct block * ptr=chmountdisk("disk");
532       int t=selfcheck2(ptr);
533       printf("\ncompiled: %u us\n", (t));    
534       chunmountdisk(ptr);
535     }
536     struct block * ptr=mountdisk("disk");
537     for(int i=NUMFILES; i>=0; i--) {
538       char filename[10];
539       sprintf(filename,"file_%d",i);
540       openfile(ptr,filename);
541     }
542     for(int j=0; j<6000; j++) {
543       for(int i=NUMFILES; i>=0; i--) {
544         char name[10];
545         int len=sprintf(name, "%d ",i);
546         writefile(ptr,i,name,len);
547       }
548     }
549     for(int i=NUMFILES; i>=0; i--) {
550       closefile(ptr,i);
551     }
552     for(int i=NUMFILES; i>=0; i--) {
553       char filename[10];
554       sprintf(filename,"file_%d",i);
555       openfile(ptr,filename);
556     }
557     for(int j=0;j<400;j++) {
558       for(int i=NUMFILES; i>=0; i--) {
559         int l=0;
560         char name[10];
561         int len=sprintf(name, "%d ",i);
562         readfile(ptr,i,name,len);
563         sscanf(name, "%d ", &l);
564         if (l!=i) {
565           printf("ERROR in benchmark\n");
566         }
567       }
568     }
569     for(int i=NUMFILES; i>=0; i--) {
570       closefile(ptr,i);
571     }
572     unmountdisk(ptr);
573   }
574   break;
575   case '9': {
576     for(int i=0;i<MAXFILES;i++)
577       files[i].used=false;
578     
579     
580     struct block * ptr=mountdisk("disk");
581     
582     for(int i=0; i<NUMFILES; i++) 
583       {
584         char filename[10];
585         sprintf(filename,"file_%d", i);
586         openfile(ptr,filename);
587       }
588     
589     for(int i=0; i<NUMFILES; i++) 
590       {     
591         char buf[100];
592         sprintf(buf,"This is file_%d.", i);
593         writefile(ptr,i,buf,strlen(buf));
594       }    
595     
596     
597     createlink(ptr, "file_1", "link_1");
598     createlink(ptr, "file_1", "link_2");
599
600     removefile("file_1", ptr);
601
602     int fd = openfile(ptr, "new");
603     writefile(ptr, fd, "new", 3);
604     
605     printfile("file_1", ptr);
606     printfile("link_1", ptr);
607     printfile("link_2", ptr);
608   
609     for(int i=0; i<NUMFILES; i++)
610       closefile(ptr,i);
611     
612     
613     unmountdisk(ptr);    
614   }
615   
616   }
617 }
618
619
620
621 struct block * chmountdisk(char *filename) {
622   int fd=open(filename,O_CREAT|O_RDWR);
623   struct block *ptr=(struct block *) mmap(NULL,LENGTH,PROT_READ|PROT_WRITE|PROT_EXEC,MAP_SHARED,fd,0);
624   alloc(ptr,LENGTH);
625   return ptr;
626 }
627
628
629
630 void chunmountdisk(struct block *vptr) {
631   int val=munmap(vptr,LENGTH);
632   dealloc(vptr);
633   if (val!=0)
634     printf("Error!\n");
635 }
636
637
638
639 // mounts the disk from the file "filename"
640 struct block * mountdisk(char *filename) {
641   int fd=open(filename,O_CREAT|O_RDWR);
642   struct block *ptr=(struct block *) mmap(NULL,LENGTH,PROT_READ|PROT_WRITE|PROT_EXEC,MAP_SHARED,fd,0);
643   alloc(ptr,LENGTH);
644   // droy: debugging
645   if ((int)ptr == -1) {
646       perror("mountdisk\0");
647       exit(-1);
648   }
649
650
651   struct SuperBlock *sb=(struct SuperBlock *) &ptr[0];
652   struct GroupBlock *gb=(struct GroupBlock *) &ptr[1];
653   bbbptr=gb->BlockBitmapBlock;
654   ibbptr=gb->InodeBitmapBlock;
655   itbptr=gb->InodeTableBlock;
656   rdiptr=sb->RootDirectoryInode;
657
658   struct InodeBitmap *ibb=(struct InodeBitmap *) &ptr[ibbptr];
659   for(int i=0;i<(NUMINODES/8+1);i++)
660     ib.inode[i]=ibb->inode[i];
661
662   struct BlockBitmap *bbb=(struct BlockBitmap *) &ptr[bbbptr];
663   for(int i=0;i<(NUMBLOCK/8+1);i++)
664     bb.blocks[i]=bbb->blocks[i];
665
666   printf("Disk mounted successfully from the file %s\n", filename);
667   fflush(NULL);
668
669   return ptr;
670 }
671
672
673
674 void unmountdisk(struct block *vptr) {
675   struct InodeBitmap *ibb=(struct InodeBitmap *) &vptr[ibbptr];
676   for(int i=0;i<(NUMINODES/8+1);i++)
677     ibb->inode[i]=ib.inode[i];
678
679   struct BlockBitmap *bbb=(struct BlockBitmap *) &vptr[bbbptr];
680   for(int i=0;i<(NUMBLOCK/8+1);i++)
681     bbb->blocks[i]=bb.blocks[i];
682   int val=munmap(vptr,LENGTH);
683   dealloc(vptr);
684   if (val!=0)
685     printf("Error!\n");
686 }
687
688
689 void removefile(char *filename, struct block *ptr) {
690   struct InodeBlock * itb=(struct InodeBlock *) &ptr[itbptr];
691   for(int i=0;i<12;i++) {
692     struct DirectoryBlock *db=(struct DirectoryBlock *) &ptr[itb->entries[rdiptr].Blockptr[i]];
693     for(int j=0;j<BLOCKSIZE/128;j++) {
694       if (db->entries[j].name[0]!=0) {
695         if(strcmp(filename,db->entries[j].name)==0) {
696           /* Found file */
697           db->entries[j].name[0]=0; //Delete entry
698           int inode=db->entries[j].inodenumber;
699           db->entries[j].inodenumber=0;
700           
701           struct InodeBlock * itb=(struct InodeBlock *) &ptr[itbptr];
702           itb->entries[inode].referencecount--;
703
704           if (itb->entries[inode].referencecount==0) {
705             for(int i=0;i<((itb->entries[inode].filesize+BLOCKSIZE-1)/BLOCKSIZE);i++) {
706               int blocknum=itb->entries[inode].Blockptr[i];
707               bb.blocks[blocknum/8]^=(1<<(blocknum%8));
708             }
709             ib.inode[inode/8]^=(1<<(inode%8));
710           }
711         }
712       }
713     }
714   }
715 }
716
717
718 void createlink(struct block *ptr,char *filename, char *linkname) {
719   struct InodeBlock * itb=(struct InodeBlock *) &ptr[itbptr];
720   for(int i=0;i<12;i++) {
721     struct DirectoryBlock *db=(struct DirectoryBlock *) &ptr[itb->entries[rdiptr].Blockptr[i]];
722     for(int j=0;j<BLOCKSIZE/DIRECTORYENTRYSIZE;j++) {
723       if (db->entries[j].name[0]!=0) {
724         if(strcmp(filename,db->entries[j].name)==0) {
725           /* Found file */
726           int inode=db->entries[j].inodenumber;
727           struct InodeBlock * itb=(struct InodeBlock *) &ptr[4];
728           itb->entries[inode].referencecount++;
729           addtode(ptr, inode, linkname);
730         }
731       }
732     }
733   }
734 }
735
736
737 void closefile(struct block *ptr, int fd) {
738   struct InodeBlock * itb=(struct InodeBlock *) &ptr[4];
739   
740
741   msync(&itb->entries[fd],sizeof(DirectoryEntry),MS_SYNC);
742   files[fd].used=false;
743 }
744
745
746 bool writefile(struct block *ptr, int fd, char *s) {
747   return (writefile(ptr,fd,s,1)==1);
748 }
749
750
751 int writefile(struct block *ptr, int fd, char *s, int len) {
752   struct filedesc *tfd=&files[fd];
753   if (tfd->used==false)
754     return -1;
755   struct InodeBlock * itb=(struct InodeBlock *) &ptr[4];
756   int filelen=itb->entries[tfd->inode].filesize;
757   if ((12*BLOCKSIZE-tfd->offset)<len)
758     len=12*BLOCKSIZE-tfd->offset;
759   for(int i=0;i<len;i++) {
760     int nbuffer=tfd->offset/BLOCKSIZE;
761     int noffset=tfd->offset%BLOCKSIZE;
762     if (tfd->offset>=filelen) {
763       if (noffset==0) {
764         int bptr=getblock(ptr);
765         if (bptr==-1) {
766           if (itb->entries[files[fd].inode].filesize<files[fd].offset)
767             itb->entries[files[fd].inode].filesize=files[fd].offset; 
768           return i;
769         }
770         itb->entries[tfd->inode].Blockptr[nbuffer]=bptr;
771       }
772     }
773     int block=itb->entries[tfd->inode].Blockptr[nbuffer];
774     char *fchar=(char *)&ptr[block];
775     int tocopy=len-i;
776     if (tocopy>(BLOCKSIZE-noffset))
777       tocopy=BLOCKSIZE-noffset;
778     memcpy(&fchar[noffset],&s[i],tocopy);
779     msync(&fchar[noffset],tocopy,MS_SYNC);
780     i+=tocopy;
781     tfd->offset+=tocopy;
782   }
783   if (itb->entries[files[fd].inode].filesize<files[fd].offset)
784     itb->entries[files[fd].inode].filesize=files[fd].offset;
785   return len;
786 }
787
788
789 // reads one char from the file fd and returns it
790 char readfile(struct block *ptr, int fd) {
791   char array[1];
792   if (readfile(ptr,fd,array,1)==1)
793     return array[0];
794   else
795     return EOF;
796 }
797
798 // reads len chars from file fd (file system *ptr) and returns them in buf
799 int readfile(struct block *ptr, int fd, char *buf, int len) {
800   struct filedesc *tfd=&files[fd];
801   if (tfd->used==false)
802     return -1;
803
804   struct InodeBlock * itb=(struct InodeBlock *) &ptr[itbptr];
805   int filelen=itb->entries[tfd->inode].filesize;
806
807   // if there are fewer than len chars left, read until the end
808   if ((filelen-tfd->offset)<len)
809     len=filelen-tfd->offset;
810
811   for(int i=0;i<len;) {
812     int nbuffer=tfd->offset/BLOCKSIZE;
813     int noffset=tfd->offset%BLOCKSIZE;
814     int block=itb->entries[tfd->inode].Blockptr[nbuffer];
815     char *fchar=(char *)&ptr[block];
816     int tocopy=len-i;
817     if (tocopy>(BLOCKSIZE-noffset))
818       tocopy=BLOCKSIZE-noffset;
819     memcpy(&buf[i],&fchar[noffset],tocopy);
820     i+=tocopy;
821     tfd->offset+=tocopy;
822   }
823   return len;
824 }
825
826
827
828 int openfile(struct block *ptr, char *filename) {
829   /* Locate fd */
830   int fd=-1;
831   for(int k=0;k<MAXFILES;k++) {
832     if(!files[k].used) {
833       /* Found file */
834       fd=k;
835       files[fd].used=true;
836       break;
837     }
838   }
839   if (fd==-1) return fd;
840
841   /* Check to see if file exists*/
842   struct InodeBlock * itb=(struct InodeBlock *) &ptr[itbptr];
843   for(int i=0;i<12;i++) 
844     {
845       struct DirectoryBlock *db=(struct DirectoryBlock *) &ptr[itb->entries[rdiptr].Blockptr[i]];
846       for(int j=0;j<BLOCKSIZE/DIRECTORYENTRYSIZE;j++) 
847         {
848           if (db->entries[j].name[0]!=0) {
849             if(strcmp(filename, db->entries[j].name)==0) 
850               {
851                 files[fd].inode=db->entries[j].inodenumber;
852                 files[fd].offset=0;
853                 return fd;
854               }
855           }
856         }
857     }
858   
859   /* If file doesn't exist, create it */
860   int inode=getinode(ptr);
861   if (inode==-1) {
862     files[fd].used=false;
863     return -1;
864   }
865   itb->entries[inode].filesize=0;
866   itb->entries[inode].referencecount=1;
867   for (int i=0;i<12;i++)
868     itb->entries[inode].Blockptr[i]=0;
869
870   addtode(ptr, inode, filename);
871   files[fd].inode=inode;
872   files[fd].offset=0;
873   return fd;
874 }
875
876
877 void createfile(struct block *ptr,char *filename, char *buf,int buflen) {
878   int fd=openfile(ptr,filename);
879   writefile(ptr,fd,buf,buflen);
880   closefile(ptr,fd);
881 }
882
883
884
885 // adds a file to the directory entry
886 void addtode(struct block *ptr, int inode, char *filename) {
887   struct InodeBlock * itb=(struct InodeBlock *) &ptr[itbptr];
888   for(int i=0;i<12;i++) {
889     struct DirectoryBlock *db=(struct DirectoryBlock *) &ptr[itb->entries[rdiptr].Blockptr[i]];
890     for(int j=0;j<BLOCKSIZE/DIRECTORYENTRYSIZE;j++) {
891       if (db->entries[j].name[0]==0) {
892         /* lets finish */
893         strncpy(db->entries[j].name,filename,124);
894         db->entries[j].inodenumber=inode;
895         msync(&db->entries[j],sizeof(DirectoryEntry),MS_SYNC);
896         return;
897       }
898     }
899   }
900 }
901
902
903 // return the first free node in the InodeTable.  Marks that inode as used.
904 int getinode(struct block *ptr) {
905   for(int i=0;i<NUMINODES;i++) {
906     if (!(ib.inode[i/8]&(1<<(i%8)))) {
907       ib.inode[i/8]=ib.inode[i/8]|(1<<(i%8));
908       return i;
909     }
910   }
911   return -1;
912 }
913
914
915 int getblock(struct block * ptr) {
916   for(int i=0;i<NUMBLOCK;i++) {
917     if (!(bb.blocks[i/8]&(1<<(i%8)))) {
918       bb.blocks[i/8]=bb.blocks[i/8]|(1<<(i%8));
919       return i;
920     }
921   }
922   return -1;
923 }
924
925
926
927 void createdisk() 
928 {
929   int blocksize=BLOCKSIZE;
930   int numblocks=NUMBLOCK;
931
932   int fd=open("disk",O_CREAT|O_RDWR|O_TRUNC, S_IREAD|S_IWRITE);
933
934   // creates numblocks and initializes them with 0
935   char *buf=(char *)calloc(1,blocksize);
936   for(int i=0;i<numblocks;i++) {
937     write(fd,buf,blocksize);
938   }
939   free(buf);
940
941   // maps the file 'disk' into memory
942   void *vptr=mmap(NULL,LENGTH,PROT_READ|PROT_WRITE|PROT_EXEC,MAP_SHARED,fd,0);
943   alloc(vptr,LENGTH);
944   // added by dan roy for debugging
945   if ((int)vptr == -1) {
946       perror("createdisk()\0");
947       exit(-1);
948   }
949   // end dan roy
950
951   struct block *ptr=(struct block *)vptr;
952   {
953     struct SuperBlock * sb=(struct SuperBlock*) &ptr[0];
954     sb->FreeBlockCount=NUMBLOCK-5;
955     sb->FreeInodeCount=NUMINODES-1;
956     sb->NumberofInodes=NUMINODES;
957     sb->NumberofBlocks=NUMBLOCK;
958     sb->RootDirectoryInode=0;
959     sb->blocksize=BLOCKSIZE;
960   }
961   {
962     struct GroupBlock * gb=(struct GroupBlock *) &ptr[1];
963     gb->BlockBitmapBlock=2;
964     gb->InodeBitmapBlock=3;
965     gb->InodeTableBlock=4;
966     gb->GroupFreeBlockCount=NUMBLOCK-5;
967     gb->GroupFreeInodeCount=NUMINODES-1;
968   }
969   {
970     struct BlockBitmap * bb=(struct BlockBitmap *) &ptr[2];
971     //memset(bb, 0, sizeof(BlockBitmap));
972     for(int i=0;i<(5+12);i++) {
973         bb->blocks[i/8]=bb->blocks[i/8]|(1<<(i%8));
974     }
975   }
976   {
977     struct InodeBitmap * ib=(struct InodeBitmap *) &ptr[3];
978     //memset(ib, 0, sizeof(InodeBitmap));
979     ib->inode[0]=1;
980   }
981   {
982     struct InodeBlock * itb=(struct InodeBlock *) &ptr[4];
983
984     itb->entries[0].filesize=12*BLOCKSIZE;
985     for(int i=0;i<12;i++)
986       itb->entries[0].Blockptr[i]=i+5;  // blocks 5 to 16 are RootDirectory entries
987     itb->entries[0].referencecount=0;
988   }
989
990   int val=munmap(vptr,LENGTH);
991   dealloc(vptr);
992   if (val!=0)
993     printf("Error!\n");
994
995   printf("Disk created successfully!\n");
996 }
997
998
999 void printdirectory(struct block *ptr) 
1000 {
1001   struct InodeBlock *itb=(struct InodeBlock *) &ptr[itbptr];
1002   
1003   for(int i=0;i<12;i++) 
1004     {
1005       struct DirectoryBlock *db=(struct DirectoryBlock *) &ptr[itb->entries[rdiptr].Blockptr[i]];
1006
1007       for(int j=0;j<BLOCKSIZE/DIRECTORYENTRYSIZE;j++) {
1008         if (db->entries[j].name[0]!=0) 
1009           {
1010             /* lets finish */
1011             //printf("%s %d\n",db->entries[j].name, db->entries[j].inodenumber);
1012             printf("%s (inode %d) (%d bytes)\n",db->entries[j].name, db->entries[j].inodenumber, itb->entries[db->entries[j].inodenumber].filesize);
1013           }
1014       }
1015     }
1016
1017   //printf("end of printdirectory\n");
1018 }
1019
1020 // prints the contents of the file with filename "filename"
1021 void printfile(char *filename, struct block *ptr) 
1022 {
1023   printf("=== BEGIN of %s ===\n", filename);
1024   struct InodeBlock * itb=(struct InodeBlock *) &ptr[itbptr];
1025   for(int i=0;i<12;i++) {
1026     struct DirectoryBlock *db=(struct DirectoryBlock *) &ptr[itb->entries[rdiptr].Blockptr[i]];
1027     for(int j=0;j<BLOCKSIZE/DIRECTORYENTRYSIZE;j++) {
1028       if (db->entries[j].name[0]!=0) {
1029         if(strcmp(filename,db->entries[j].name)==0) {
1030           /* Found file */
1031           int inode=db->entries[j].inodenumber;
1032
1033           struct InodeBlock * itb=(struct InodeBlock *) &ptr[itbptr];
1034           for(int i=0;i<((itb->entries[inode].filesize+BLOCKSIZE-1)/BLOCKSIZE);i++) {
1035             struct block *b=&ptr[itb->entries[inode].Blockptr[i]];
1036             write(0,b,BLOCKSIZE);
1037           }
1038         }
1039       }
1040     }
1041   }
1042   printf("\n=== END of %s ===\n", filename);
1043 }
1044
1045
1046 void printinodeblock(struct block *ptr)
1047 {
1048   struct InodeBlock *itb=(struct InodeBlock *) &ptr[itbptr];  
1049
1050   for (int i=0; i<NUMINODES; i++)
1051     {
1052       Inode inode = itb->entries[i];
1053       printf("inode %d: (filesize %d), (referencecount %d)\n", i, inode.filesize, inode.referencecount);
1054     }
1055 }
1056
1057