/* Test 8 -> Checks whether the read call in library
 * corrects 1 block corruptions and returns the corrected
 * blocks on multiple block read request
**/

#include <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <string.h>
#include <dlfcn.h>

void im_here(char * str) { fprintf(stderr, "I'm here: %s\n", str); 
	fflush(stderr);} 

void  print_hex(unsigned char *data, int length, char *lbl){
	int i=0;
	fprintf(stderr, "DATA ----- %08d -------- %s\n", length, lbl);
	for(i=0; i<length; i++) fprintf(stderr, "%02x ", data[i]);
	fprintf(stderr, "\nEND DATA - %08x --------\n", length);
}


int main()
{
   int fd1 = -1;
   int err;
   void * handle = NULL;
   char buf[5*4096];
   char new_buf[5*4096];
   off_t cur=0;
   int i=0;
   int data_read = 0;

    handle = dlopen("/lib/libc.so.6",  RTLD_LAZY);
    if (handle == NULL) {
	fprintf(stderr, "%s", dlerror());
	return -1;
    }
    int (*o_open)(const char *, int) = (int (*)(const char *, int)) dlsym(handle, "open");
    ssize_t (*o_read)(int, void *, size_t) = (ssize_t (*)(int, void *, size_t)) dlsym(handle, "read");
    ssize_t (*o_write)(int, void *, size_t) = (ssize_t (*)(int, void *, size_t)) dlsym(handle, "write");
    off_t (*o_lseek)(int, off_t, int) = (off_t (*)(int, off_t, int)) dlsym(handle, "lseek");
    int (*o_close)(int) = (int (*)(int)) dlsym(handle, "close");


/* Bootstrap the file with libfsprotect.c */
   fd1 = open("file5", O_RDONLY);
   if(fd1 == -1) {
         return -1;
   }
   err = close(fd1);
   if(err == -1)
        return -1;

/* Corrupt a block outside the library */
   fd1 = (*o_open)("file5", O_RDWR);  
   if(fd1 == -1) {
         return -1;
   }
   err = (*o_read)(fd1, buf, 4096);
   if(err == -1)
        return -1;
   err = (*o_read)(fd1, buf, 4096);
   if(err == -1)
        return -1;
   err = (*o_read)(fd1, buf, 5*4096);
   if(err == -1)
        return -1;
   memcpy(new_buf, buf, 5*4096);
   for(i=130; i<160; i++) {
        new_buf[i]++;
   }
   (*o_lseek)(fd1, 8192, SEEK_SET);
   err = (*o_write)(fd1, new_buf, 5*4096);
   if(err == -1)
        return -1;
   (*o_close)(fd1);

/* Re-open the file with the library. This should correct the file */
   fd1 = open("file5", O_RDONLY);
   if(fd1 == -1) {
         return -1;
   }
/* Reuse new_buf to hold the temporary data read */
/* buf[4096] still holds the correct contents of the block before corruption */
   data_read = read(fd1, new_buf, 4096);
   if(data_read != 4096) {
        goto fail;
   }
   data_read = read(fd1, new_buf, 5*4096);  /* This returned blocks should include the corrected one */
	  im_here("A27");
   if(data_read != 5*4096) {
        goto fail;
   }
	  im_here("A29");
	
	print_hex(buf+130, 30, "correct value: buf");
	print_hex(new_buf+4096+130, 30, "new value: new_buf");
/* Compare the block with previous good value */

	print_hex(buf, 4096, "correct all buf");
	print_hex(new_buf, 4096, "new value: all new_buf");
	int returned;
   if(returned = memcmp(new_buf+4096, buf, 4096)!=0)  {
   	printf("returned value from memcmp is: %d\n", returned);
        goto fail;
   }
	  im_here("A30");

pass:
   err = close(fd1);
   if(err == -1)
        return -1;

   return 0;

fail:
   close(fd1);
   return -1;


}
