Filesystem benchmark
[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/50));    
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       chunmountdisk(ptr);
533     }
534     struct block * ptr=mountdisk("disk");
535     for(int i=NUMFILES; i>=0; i--) {
536       char filename[10];
537       sprintf(filename,"file_%d",i);
538       openfile(ptr,filename);
539     }
540     for(int j=0; j<6000; j++) {
541       for(int i=NUMFILES; i>=0; i--) {
542         char name[10];
543         int len=sprintf(name, "%d ",i);
544         writefile(ptr,i,name,len);
545       }
546     }
547     for(int i=NUMFILES; i>=0; i--) {
548       closefile(ptr,i);
549     }
550     for(int i=NUMFILES; i>=0; i--) {
551       char filename[10];
552       sprintf(filename,"file_%d",i);
553       openfile(ptr,filename);
554     }
555     for(int j=0;j<400;j++) {
556       for(int i=NUMFILES; i>=0; i--) {
557         int l=0;
558         char name[10];
559         int len=sprintf(name, "%d ",i);
560         readfile(ptr,i,name,len);
561         sscanf(name, "%d ", &l);
562         if (l!=i) {
563           printf("ERROR in benchmark\n");
564         }
565       }
566     }
567     for(int i=NUMFILES; i>=0; i--) {
568       closefile(ptr,i);
569     }
570     unmountdisk(ptr);
571   }
572
573   case '9': {
574     for(int i=0;i<MAXFILES;i++)
575       files[i].used=false;
576     
577     
578     struct block * ptr=mountdisk("disk");
579     
580     for(int i=0; i<NUMFILES; i++) 
581       {
582         char filename[10];
583         sprintf(filename,"file_%d", i);
584         openfile(ptr,filename);
585       }
586     
587     for(int i=0; i<NUMFILES; i++) 
588       {     
589         char buf[100];
590         sprintf(buf,"This is file_%d.", i);
591         writefile(ptr,i,buf,strlen(buf));
592       }    
593     
594     
595     createlink(ptr, "file_1", "link_1");
596     createlink(ptr, "file_1", "link_2");
597
598     removefile("file_1", ptr);
599
600     int fd = openfile(ptr, "new");
601     writefile(ptr, fd, "new", 3);
602     
603     printfile("file_1", ptr);
604     printfile("link_1", ptr);
605     printfile("link_2", ptr);
606   
607     for(int i=0; i<NUMFILES; i++)
608       closefile(ptr,i);
609     
610     
611     unmountdisk(ptr);    
612   }
613   
614   }
615 }
616
617
618
619 struct block * chmountdisk(char *filename) {
620   int fd=open(filename,O_CREAT|O_RDWR);
621   struct block *ptr=(struct block *) mmap(NULL,LENGTH,PROT_READ|PROT_WRITE|PROT_EXEC,MAP_SHARED,fd,0);
622   alloc(ptr,LENGTH);
623   return ptr;
624 }
625
626
627
628 void chunmountdisk(struct block *vptr) {
629   int val=munmap(vptr,LENGTH);
630   dealloc(vptr);
631   if (val!=0)
632     printf("Error!\n");
633 }
634
635
636
637 // mounts the disk from the file "filename"
638 struct block * mountdisk(char *filename) {
639   int fd=open(filename,O_CREAT|O_RDWR);
640   struct block *ptr=(struct block *) mmap(NULL,LENGTH,PROT_READ|PROT_WRITE|PROT_EXEC,MAP_SHARED,fd,0);
641   alloc(ptr,LENGTH);
642   // droy: debugging
643   if ((int)ptr == -1) {
644       perror("mountdisk\0");
645       exit(-1);
646   }
647
648
649   struct SuperBlock *sb=(struct SuperBlock *) &ptr[0];
650   struct GroupBlock *gb=(struct GroupBlock *) &ptr[1];
651   bbbptr=gb->BlockBitmapBlock;
652   ibbptr=gb->InodeBitmapBlock;
653   itbptr=gb->InodeTableBlock;
654   rdiptr=sb->RootDirectoryInode;
655
656   struct InodeBitmap *ibb=(struct InodeBitmap *) &ptr[ibbptr];
657   for(int i=0;i<(NUMINODES/8+1);i++)
658     ib.inode[i]=ibb->inode[i];
659
660   struct BlockBitmap *bbb=(struct BlockBitmap *) &ptr[bbbptr];
661   for(int i=0;i<(NUMBLOCK/8+1);i++)
662     bb.blocks[i]=bbb->blocks[i];
663
664   printf("Disk mounted successfully from the file %s\n", filename);
665   fflush(NULL);
666
667   return ptr;
668 }
669
670
671
672 void unmountdisk(struct block *vptr) {
673   struct InodeBitmap *ibb=(struct InodeBitmap *) &vptr[ibbptr];
674   for(int i=0;i<(NUMINODES/8+1);i++)
675     ibb->inode[i]=ib.inode[i];
676
677   struct BlockBitmap *bbb=(struct BlockBitmap *) &vptr[bbbptr];
678   for(int i=0;i<(NUMBLOCK/8+1);i++)
679     bbb->blocks[i]=bb.blocks[i];
680   int val=munmap(vptr,LENGTH);
681   dealloc(vptr);
682   if (val!=0)
683     printf("Error!\n");
684 }
685
686
687 void removefile(char *filename, struct block *ptr) {
688   struct InodeBlock * itb=(struct InodeBlock *) &ptr[itbptr];
689   for(int i=0;i<12;i++) {
690     struct DirectoryBlock *db=(struct DirectoryBlock *) &ptr[itb->entries[rdiptr].Blockptr[i]];
691     for(int j=0;j<BLOCKSIZE/128;j++) {
692       if (db->entries[j].name[0]!=0) {
693         if(strcmp(filename,db->entries[j].name)==0) {
694           /* Found file */
695           db->entries[j].name[0]=0; //Delete entry
696           int inode=db->entries[j].inodenumber;
697           db->entries[j].inodenumber=0;
698           
699           struct InodeBlock * itb=(struct InodeBlock *) &ptr[itbptr];
700           itb->entries[inode].referencecount--;
701
702           if (itb->entries[inode].referencecount==0) {
703             for(int i=0;i<((itb->entries[inode].filesize+BLOCKSIZE-1)/BLOCKSIZE);i++) {
704               int blocknum=itb->entries[inode].Blockptr[i];
705               bb.blocks[blocknum/8]^=(1<<(blocknum%8));
706             }
707             ib.inode[inode/8]^=(1<<(inode%8));
708           }
709         }
710       }
711     }
712   }
713 }
714
715
716 void createlink(struct block *ptr,char *filename, char *linkname) {
717   struct InodeBlock * itb=(struct InodeBlock *) &ptr[itbptr];
718   for(int i=0;i<12;i++) {
719     struct DirectoryBlock *db=(struct DirectoryBlock *) &ptr[itb->entries[rdiptr].Blockptr[i]];
720     for(int j=0;j<BLOCKSIZE/DIRECTORYENTRYSIZE;j++) {
721       if (db->entries[j].name[0]!=0) {
722         if(strcmp(filename,db->entries[j].name)==0) {
723           /* Found file */
724           int inode=db->entries[j].inodenumber;
725           struct InodeBlock * itb=(struct InodeBlock *) &ptr[4];
726           itb->entries[inode].referencecount++;
727           addtode(ptr, inode, linkname);
728         }
729       }
730     }
731   }
732 }
733
734
735 void closefile(struct block *ptr, int fd) {
736   struct InodeBlock * itb=(struct InodeBlock *) &ptr[4];
737   
738
739   msync(&itb->entries[fd],sizeof(DirectoryEntry),MS_SYNC);
740   files[fd].used=false;
741 }
742
743
744 bool writefile(struct block *ptr, int fd, char *s) {
745   return (writefile(ptr,fd,s,1)==1);
746 }
747
748
749 int writefile(struct block *ptr, int fd, char *s, int len) {
750   struct filedesc *tfd=&files[fd];
751   if (tfd->used==false)
752     return -1;
753   struct InodeBlock * itb=(struct InodeBlock *) &ptr[4];
754   int filelen=itb->entries[tfd->inode].filesize;
755   if ((12*BLOCKSIZE-tfd->offset)<len)
756     len=12*BLOCKSIZE-tfd->offset;
757   for(int i=0;i<len;i++) {
758     int nbuffer=tfd->offset/BLOCKSIZE;
759     int noffset=tfd->offset%BLOCKSIZE;
760     if (tfd->offset>=filelen) {
761       if (noffset==0) {
762         int bptr=getblock(ptr);
763         if (bptr==-1) {
764           if (itb->entries[files[fd].inode].filesize<files[fd].offset)
765             itb->entries[files[fd].inode].filesize=files[fd].offset; 
766           return i;
767         }
768         itb->entries[tfd->inode].Blockptr[nbuffer]=bptr;
769       }
770     }
771     int block=itb->entries[tfd->inode].Blockptr[nbuffer];
772     char *fchar=(char *)&ptr[block];
773     int tocopy=len-i;
774     if (tocopy>(BLOCKSIZE-noffset))
775       tocopy=BLOCKSIZE-noffset;
776     memcpy(&fchar[noffset],&s[i],tocopy);
777     msync(&fchar[noffset],tocopy,MS_SYNC);
778     i+=tocopy;
779     tfd->offset+=tocopy;
780   }
781   if (itb->entries[files[fd].inode].filesize<files[fd].offset)
782     itb->entries[files[fd].inode].filesize=files[fd].offset;
783   return len;
784 }
785
786
787 // reads one char from the file fd and returns it
788 char readfile(struct block *ptr, int fd) {
789   char array[1];
790   if (readfile(ptr,fd,array,1)==1)
791     return array[0];
792   else
793     return EOF;
794 }
795
796 // reads len chars from file fd (file system *ptr) and returns them in buf
797 int readfile(struct block *ptr, int fd, char *buf, int len) {
798   struct filedesc *tfd=&files[fd];
799   if (tfd->used==false)
800     return -1;
801
802   struct InodeBlock * itb=(struct InodeBlock *) &ptr[itbptr];
803   int filelen=itb->entries[tfd->inode].filesize;
804
805   // if there are fewer than len chars left, read until the end
806   if ((filelen-tfd->offset)<len)
807     len=filelen-tfd->offset;
808
809   for(int i=0;i<len;) {
810     int nbuffer=tfd->offset/BLOCKSIZE;
811     int noffset=tfd->offset%BLOCKSIZE;
812     int block=itb->entries[tfd->inode].Blockptr[nbuffer];
813     char *fchar=(char *)&ptr[block];
814     int tocopy=len-i;
815     if (tocopy>(BLOCKSIZE-noffset))
816       tocopy=BLOCKSIZE-noffset;
817     memcpy(&buf[i],&fchar[noffset],tocopy);
818     i+=tocopy;
819     tfd->offset+=tocopy;
820   }
821   return len;
822 }
823
824
825
826 int openfile(struct block *ptr, char *filename) {
827   /* Locate fd */
828   int fd=-1;
829   for(int k=0;k<MAXFILES;k++) {
830     if(!files[k].used) {
831       /* Found file */
832       fd=k;
833       files[fd].used=true;
834       break;
835     }
836   }
837   if (fd==-1) return fd;
838
839   /* Check to see if file exists*/
840   struct InodeBlock * itb=(struct InodeBlock *) &ptr[itbptr];
841   for(int i=0;i<12;i++) 
842     {
843       struct DirectoryBlock *db=(struct DirectoryBlock *) &ptr[itb->entries[rdiptr].Blockptr[i]];
844       for(int j=0;j<BLOCKSIZE/DIRECTORYENTRYSIZE;j++) 
845         {
846           if (db->entries[j].name[0]!=0) {
847             if(strcmp(filename, db->entries[j].name)==0) 
848               {
849                 files[fd].inode=db->entries[j].inodenumber;
850                 files[fd].offset=0;
851                 return fd;
852               }
853           }
854         }
855     }
856   
857   /* If file doesn't exist, create it */
858   int inode=getinode(ptr);
859   if (inode==-1) {
860     files[fd].used=false;
861     return -1;
862   }
863   itb->entries[inode].filesize=0;
864   itb->entries[inode].referencecount=1;
865   for (int i=0;i<12;i++)
866     itb->entries[inode].Blockptr[i]=0;
867
868   addtode(ptr, inode, filename);
869   files[fd].inode=inode;
870   files[fd].offset=0;
871   return fd;
872 }
873
874
875 void createfile(struct block *ptr,char *filename, char *buf,int buflen) {
876   int fd=openfile(ptr,filename);
877   writefile(ptr,fd,buf,buflen);
878   closefile(ptr,fd);
879 }
880
881
882
883 // adds a file to the directory entry
884 void addtode(struct block *ptr, int inode, char *filename) {
885   struct InodeBlock * itb=(struct InodeBlock *) &ptr[itbptr];
886   for(int i=0;i<12;i++) {
887     struct DirectoryBlock *db=(struct DirectoryBlock *) &ptr[itb->entries[rdiptr].Blockptr[i]];
888     for(int j=0;j<BLOCKSIZE/DIRECTORYENTRYSIZE;j++) {
889       if (db->entries[j].name[0]==0) {
890         /* lets finish */
891         strncpy(db->entries[j].name,filename,124);
892         db->entries[j].inodenumber=inode;
893         msync(&db->entries[j],sizeof(DirectoryEntry),MS_SYNC);
894         return;
895       }
896     }
897   }
898 }
899
900
901 // return the first free node in the InodeTable.  Marks that inode as used.
902 int getinode(struct block *ptr) {
903   for(int i=0;i<NUMINODES;i++) {
904     if (!(ib.inode[i/8]&(1<<(i%8)))) {
905       ib.inode[i/8]=ib.inode[i/8]|(1<<(i%8));
906       return i;
907     }
908   }
909   return -1;
910 }
911
912
913 int getblock(struct block * ptr) {
914   for(int i=0;i<NUMBLOCK;i++) {
915     if (!(bb.blocks[i/8]&(1<<(i%8)))) {
916       bb.blocks[i/8]=bb.blocks[i/8]|(1<<(i%8));
917       return i;
918     }
919   }
920   return -1;
921 }
922
923
924
925 void createdisk() 
926 {
927   int blocksize=BLOCKSIZE;
928   int numblocks=NUMBLOCK;
929
930   int fd=open("disk",O_CREAT|O_RDWR|O_TRUNC, S_IREAD|S_IWRITE);
931
932   // creates numblocks and initializes them with 0
933   char *buf=(char *)calloc(1,blocksize);
934   for(int i=0;i<numblocks;i++) {
935     write(fd,buf,blocksize);
936   }
937   free(buf);
938
939   // maps the file 'disk' into memory
940   void *vptr=mmap(NULL,LENGTH,PROT_READ|PROT_WRITE|PROT_EXEC,MAP_SHARED,fd,0);
941   alloc(vptr,LENGTH);
942   // added by dan roy for debugging
943   if ((int)vptr == -1) {
944       perror("createdisk()\0");
945       exit(-1);
946   }
947   // end dan roy
948
949   struct block *ptr=(struct block *)vptr;
950   {
951     struct SuperBlock * sb=(struct SuperBlock*) &ptr[0];
952     sb->FreeBlockCount=NUMBLOCK-5;
953     sb->FreeInodeCount=NUMINODES-1;
954     sb->NumberofInodes=NUMINODES;
955     sb->NumberofBlocks=NUMBLOCK;
956     sb->RootDirectoryInode=0;
957     sb->blocksize=BLOCKSIZE;
958   }
959   {
960     struct GroupBlock * gb=(struct GroupBlock *) &ptr[1];
961     gb->BlockBitmapBlock=2;
962     gb->InodeBitmapBlock=3;
963     gb->InodeTableBlock=4;
964     gb->GroupFreeBlockCount=NUMBLOCK-5;
965     gb->GroupFreeInodeCount=NUMINODES-1;
966   }
967   {
968     struct BlockBitmap * bb=(struct BlockBitmap *) &ptr[2];
969     //memset(bb, 0, sizeof(BlockBitmap));
970     for(int i=0;i<(5+12);i++) {
971         bb->blocks[i/8]=bb->blocks[i/8]|(1<<(i%8));
972     }
973   }
974   {
975     struct InodeBitmap * ib=(struct InodeBitmap *) &ptr[3];
976     //memset(ib, 0, sizeof(InodeBitmap));
977     ib->inode[0]=1;
978   }
979   {
980     struct InodeBlock * itb=(struct InodeBlock *) &ptr[4];
981
982     itb->entries[0].filesize=12*BLOCKSIZE;
983     for(int i=0;i<12;i++)
984       itb->entries[0].Blockptr[i]=i+5;  // blocks 5 to 16 are RootDirectory entries
985     itb->entries[0].referencecount=0;
986   }
987
988   int val=munmap(vptr,LENGTH);
989   dealloc(vptr);
990   if (val!=0)
991     printf("Error!\n");
992
993   printf("Disk created successfully!\n");
994 }
995
996
997 void printdirectory(struct block *ptr) 
998 {
999   struct InodeBlock *itb=(struct InodeBlock *) &ptr[itbptr];
1000   
1001   for(int i=0;i<12;i++) 
1002     {
1003       struct DirectoryBlock *db=(struct DirectoryBlock *) &ptr[itb->entries[rdiptr].Blockptr[i]];
1004
1005       for(int j=0;j<BLOCKSIZE/DIRECTORYENTRYSIZE;j++) {
1006         if (db->entries[j].name[0]!=0) 
1007           {
1008             /* lets finish */
1009             //printf("%s %d\n",db->entries[j].name, db->entries[j].inodenumber);
1010             printf("%s (inode %d) (%d bytes)\n",db->entries[j].name, db->entries[j].inodenumber, itb->entries[db->entries[j].inodenumber].filesize);
1011           }
1012       }
1013     }
1014
1015   //printf("end of printdirectory\n");
1016 }
1017
1018 // prints the contents of the file with filename "filename"
1019 void printfile(char *filename, struct block *ptr) 
1020 {
1021   printf("=== BEGIN of %s ===\n", filename);
1022   struct InodeBlock * itb=(struct InodeBlock *) &ptr[itbptr];
1023   for(int i=0;i<12;i++) {
1024     struct DirectoryBlock *db=(struct DirectoryBlock *) &ptr[itb->entries[rdiptr].Blockptr[i]];
1025     for(int j=0;j<BLOCKSIZE/DIRECTORYENTRYSIZE;j++) {
1026       if (db->entries[j].name[0]!=0) {
1027         if(strcmp(filename,db->entries[j].name)==0) {
1028           /* Found file */
1029           int inode=db->entries[j].inodenumber;
1030
1031           struct InodeBlock * itb=(struct InodeBlock *) &ptr[itbptr];
1032           for(int i=0;i<((itb->entries[inode].filesize+BLOCKSIZE-1)/BLOCKSIZE);i++) {
1033             struct block *b=&ptr[itb->entries[inode].Blockptr[i]];
1034             write(0,b,BLOCKSIZE);
1035           }
1036         }
1037       }
1038     }
1039   }
1040   printf("\n=== END of %s ===\n", filename);
1041 }
1042
1043
1044 void printinodeblock(struct block *ptr)
1045 {
1046   struct InodeBlock *itb=(struct InodeBlock *) &ptr[itbptr];  
1047
1048   for (int i=0; i<NUMINODES; i++)
1049     {
1050       Inode inode = itb->entries[i];
1051       printf("inode %d: (filesize %d), (referencecount %d)\n", i, inode.filesize, inode.referencecount);
1052     }
1053 }
1054
1055