/* Test 13 -> Checks whether the write call in library
* corrects 1 block corruptions
**/

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

int fill_random(char *buf)
{
    int i;
    for(i=0; i<4096; i++) {
         buf[i] = 'a' + random() % 26;
    }
}


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[4096];
	char new_buf[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");
	im_here("A 0");

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

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

	/* Re-open the file with the library. This should correct the file */
	fd1 = open("file5", O_RDWR);
	im_here("A 13");
	if(fd1 == -1) {
		return -1;
	im_here("A 14");
	}
	/* Reuse new_buf to hold the temporary data read */
	/* Do a write to see if it corrects the file */
	fill_random(new_buf);
	im_here("A 15");
	data_read = write(fd1, new_buf, 4096);
	im_here("A 16");
	if(data_read != 4096) {
	im_here("A 17");
		close(fd1);
		return -1;
	}
	fill_random(new_buf);
	im_here("A 18");
	data_read = write(fd1, new_buf, 4096);
	im_here("A 19");
	if(data_read != 4096) {
	im_here("A 20");
		close(fd1);
		return -1;
	}
	err = close(fd1);
	im_here("A 21");
	if(err == -1)
		return -1;
	im_here("A 22");

	/* Check whether the file was corrected by reading outside the library */
	fd1 = (*o_open)("file5", O_RDONLY);  
	im_here("A 23");
	if(fd1 == -1) {
		return -1;
	}
	(*o_lseek)(fd1, 8192, 0);
	im_here("A 24");
	err = (*o_read)(fd1, new_buf, 4096);
	im_here("A 25");
	if(err == -1)
		return -1;
	print_hex(buf, 130, "correct thing");
	print_hex(new_buf, 130, "new  thing");
	im_here("A 28");
	if(memcmp(new_buf, buf, 4096)!=0)
		goto fail;
	im_here("A 27");

pass:
	(*o_close)(fd1);
	return 0;

fail:
	(*o_close)(fd1);
	return -1;

}
