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