// File: /workspace/github_c_makefile_star2_O0/sheheryarbutt[P]Ext2-File-System/ext2_cp.c
// Function: main
int main(int argc, char **argv) {
	unsigned char data[EXT2_BLOCK_SIZE];
	FILE * source;
	struct stat source_stat;


    if(argc != 4) {
        fprintf(stderr, "Usage: ext2_cp <image file name> <source path> <dest path>\n");
        exit(1);
    }
    int fd = open(argv[1], O_RDWR);

    disk = mmap(NULL, 128 * 1024, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
    if(disk == MAP_FAILED) {
	perror("mmap");
	exit(1);
    }
    // setting global vars
   	sb = (struct ext2_super_block *)(disk + EXT2_BLOCK_SIZE);
    gd = (struct ext2_group_desc *)(disk + (2*EXT2_BLOCK_SIZE));
	inode_table = (struct ext2_inode *)(disk + (5*EXT2_BLOCK_SIZE));

	char * path= argv[2];
	char * dest= argv[3];


	source = fopen(path,"rb");

	if (source==NULL){
		// source path does not exist
		fprintf(stderr, "ERROR: %s\n", strerror(ENOENT));     
		exit(ENOENT);
	}

	if(lstat(path,&source_stat)<0){
		fclose(source);
		fprintf(stderr, "ERROR: %s\n", strerror(EXIT_FAILURE));     
		exit(EXIT_FAILURE);
	}

	// need for pathTraversal function
	unsigned int * parent_block= malloc(sizeof(unsigned int *));

	int dest_inode=pathTraversal(dest,disk,parent_block);

	if (dest_inode!=0){
		// already file/directory exist in destination path
		free(parent_block);
		fclose(source);
		fprintf(stderr, "ERROR: %s\n", strerror(EEXIST));     
		exit(EEXIST);
	}
	
	char *name;

	free(parent_block);

	char *cpyPath=malloc((unsigned int)strlen(dest) + 1);
	strcpy(cpyPath,dest);

	parent_block= malloc(sizeof(unsigned int *));
	
	name=basename(cpyPath);
	if (strlen(name)>EXT2_NAME_LEN){
		fclose(source);
		fprintf(stderr, "ERROR: %s\n", strerror(ENAMETOOLONG));     
		exit(ENAMETOOLONG);
	}

	dest[strlen(dest)-(strlen(name))]='\0';

	dest_inode=pathTraversal(dest,disk,parent_block);
	free(parent_block);

	if (dest_inode==0){
		//destination path does not exist
		fclose(source);
		fprintf(stderr, "ERROR: %s\n", strerror(ENOENT));     
		exit(ENOENT);
	}

	int source_size = (int)source_stat.st_size;
 	int blocks_needed = ceil((double)source_size/EXT2_BLOCK_SIZE);
	//no space to copy file

	if ((gd->bg_free_blocks_count<1+blocks_needed) || (gd->bg_free_inodes_count<1) ){
		fclose(source);
		fprintf(stderr, "ERROR: %s\n", strerror(ENOSPC));     
		exit(ENOSPC);
	}
		//can only copy regular files
	if(!(S_ISREG(source_stat.st_mode))){
		fclose(source);
		fprintf(stderr, "ERROR: %s\n", strerror(EPERM));     
		exit(EPERM);
	}
	else {
			// inode for new file and datablock for dir entry for new file
		int avail_ib;
		avail_ib= set_avail_ib();
		int avail_db;
		avail_db= set_avail_db();
			//find next block pointer to use for new dir entry
		int block_pointer=0; 
		while(inode_table[dest_inode-1].i_block[block_pointer]!=0){
			block_pointer++;
		}
			//update dir info
		inode_table[dest_inode-1].i_block[block_pointer]=avail_db;
		inode_table[dest_inode-1].i_blocks+=2;
		inode_table[dest_inode-1].i_size+=EXT2_BLOCK_SIZE;
			//create dir entry for new file
		create_entry((EXT2_BLOCK_SIZE*avail_db),(unsigned int)avail_ib,(unsigned short)EXT2_BLOCK_SIZE,(unsigned char)strlen(name),(unsigned char)EXT2_FT_REG_FILE,name);

			// copy data from source file into new datablocks

		unsigned int * blocks=malloc(sizeof(unsigned int)*15);
		int read_so_far;
		for (int i=0;i<12;i++){

			if (blocks_needed!=0){
				int new_db = set_avail_db();
				blocks[i]=new_db;
				read_so_far = fread(data, 1, EXT2_BLOCK_SIZE, source);
				memcpy(disk+(EXT2_BLOCK_SIZE*new_db),data,read_so_far);
				blocks_needed--;
			}else{
				blocks[i]=0;
			}

		}
			// copy data from source file using indirection
		if (blocks_needed!=0){
			int indirect_block = set_avail_db();
				// new indirect block pointer for new file
			unsigned int * block_num_table = malloc(EXT2_BLOCK_SIZE);

			for(int i=0;i<(EXT2_BLOCK_SIZE/sizeof(unsigned int));i++){ 
				if (blocks_needed != 0){
					unsigned int new_db = (unsigned int)set_avail_db();
					read_so_far = fread(data, 1, EXT2_BLOCK_SIZE, source);
					memcpy(disk+(EXT2_BLOCK_SIZE*new_db),data,read_so_far);
					block_num_table[i] =(unsigned int)new_db;
					blocks_needed--;

				}else{
					block_num_table[i]=(unsigned int)0;
				}
			}
				// store block array at indirect block pointer for new file
			memcpy(disk+(EXT2_BLOCK_SIZE*indirect_block),block_num_table,EXT2_BLOCK_SIZE);
			blocks[12]=indirect_block;

		}
			// create inode for new file
		fclose(source);
		blocks_needed = ceil((double)source_size/EXT2_BLOCK_SIZE);

		create_inode(avail_ib,EXT2_S_IFREG,source_size,1,blocks_needed*2,blocks);

	}
	return 0;
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x570, %rsp            # imm = 0x570
movl $0x0, -0x4(%rbp)
movl %edi, -0x8(%rbp)
movq %rsi, -0x10(%rbp)
cmpl $0x4, -0x8(%rbp)
je 0x12b1
movq 0x3d62(%rip), %rax      # 0x4ff8
movq (%rax), %rdi
leaq 0x1d70(%rip), %rsi      # 0x3010
movb $0x0, %al
callq 0x10c0
movl $0x1, %edi
callq 0x1140
movq -0x10(%rbp), %rax
movq 0x8(%rax), %rdi
movl $0x2, %esi
movb $0x0, %al
callq 0x1110
movl %eax, -0x4ac(%rbp)
movl -0x4ac(%rbp), %r8d
xorl %eax, %eax
movl %eax, %r9d
movl $0x20000, %esi          # imm = 0x20000
movl $0x3, %edx
movl $0x1, %ecx
movq %r9, %rdi
callq 0x1090
movq %rax, 0x3ddb(%rip)      # 0x50d0
movq $-0x1, %rax
cmpq %rax, 0x3dcd(%rip)      # 0x50d0
jne 0x131b
leaq 0x1d40(%rip), %rdi      # 0x304c
callq 0x1130
movl $0x1, %edi
callq 0x1140
movq 0x3dae(%rip), %rax      # 0x50d0
addq $0x400, %rax            # imm = 0x400
movq %rax, 0x3da9(%rip)      # 0x50d8
movq 0x3d9a(%rip), %rax      # 0x50d0
addq $0x800, %rax            # imm = 0x800
movq %rax, 0x3d9d(%rip)      # 0x50e0
movq 0x3d86(%rip), %rax      # 0x50d0
addq $0x1400, %rax           # imm = 0x1400
movq %rax, 0x3d91(%rip)      # 0x50e8
movq -0x10(%rbp), %rax
movq 0x10(%rax), %rax
movq %rax, -0x4b8(%rbp)
movq -0x10(%rbp), %rax
movq 0x18(%rax), %rax
movq %rax, -0x4c0(%rbp)
movq -0x4b8(%rbp), %rdi
leaq 0x1cce(%rip), %rsi      # 0x3051
callq 0x1120
movq %rax, -0x418(%rbp)
cmpq $0x0, -0x418(%rbp)
jne 0x13d6
movq 0x3c58(%rip), %rax      # 0x4ff8
movq (%rax), %rax
movq %rax, -0x528(%rbp)
movl $0x2, %edi
callq 0x1150
movq -0x528(%rbp), %rdi
movq %rax, %rdx
leaq 0x1c8f(%rip), %rsi      # 0x3054
movb $0x0, %al
callq 0x10c0
movl $0x2, %edi
callq 0x1140
movq -0x4b8(%rbp), %rdi
leaq -0x4a8(%rbp), %rsi
callq 0x10a0
cmpl $0x0, %eax
jge 0x1437
movq -0x418(%rbp), %rdi
callq 0x1070
movq 0x3bf7(%rip), %rax      # 0x4ff8
movq (%rax), %rax
movq %rax, -0x530(%rbp)
movl $0x1, %edi
callq 0x1150
movq -0x530(%rbp), %rdi
movq %rax, %rdx
leaq 0x1c2e(%rip), %rsi      # 0x3054
movb $0x0, %al
callq 0x10c0
movl $0x1, %edi
callq 0x1140
movl $0x8, %edi
callq 0x1100
movq %rax, -0x4c8(%rbp)
movq -0x4c0(%rbp), %rdi
movq 0x3c7a(%rip), %rsi      # 0x50d0
movq -0x4c8(%rbp), %rdx
callq 0x1cb0
movl %eax, -0x4cc(%rbp)
cmpl $0x0, -0x4cc(%rbp)
je 0x14c6
movq -0x4c8(%rbp), %rdi
callq 0x1030
movq -0x418(%rbp), %rdi
callq 0x1070
movq 0x3b68(%rip), %rax      # 0x4ff8
movq (%rax), %rax
movq %rax, -0x538(%rbp)
movl $0x11, %edi
callq 0x1150
movq -0x538(%rbp), %rdi
movq %rax, %rdx
leaq 0x1b9f(%rip), %rsi      # 0x3054
movb $0x0, %al
callq 0x10c0
movl $0x11, %edi
callq 0x1140
movq -0x4c8(%rbp), %rdi
callq 0x1030
movq -0x4c0(%rbp), %rdi
callq 0x1080
addl $0x1, %eax
movl %eax, %eax
movl %eax, %edi
callq 0x1100
movq %rax, -0x4e0(%rbp)
movq -0x4e0(%rbp), %rdi
movq -0x4c0(%rbp), %rsi
callq 0x1050
movl $0x8, %edi
callq 0x1100
movq %rax, -0x4c8(%rbp)
movq -0x4e0(%rbp), %rdi
callq 0x10e0
movq %rax, -0x4d8(%rbp)
movq -0x4d8(%rbp), %rdi
callq 0x1080
cmpq $0xff, %rax
jbe 0x1585
movq -0x418(%rbp), %rdi
callq 0x1070
movq 0x3aa9(%rip), %rax      # 0x4ff8
movq (%rax), %rax
movq %rax, -0x540(%rbp)
movl $0x24, %edi
callq 0x1150
movq -0x540(%rbp), %rdi
movq %rax, %rdx
leaq 0x1ae0(%rip), %rsi      # 0x3054
movb $0x0, %al
callq 0x10c0
movl $0x24, %edi
callq 0x1140
movq -0x4c0(%rbp), %rax
movq %rax, -0x548(%rbp)
movq -0x4c0(%rbp), %rdi
callq 0x1080
movq %rax, -0x550(%rbp)
movq -0x4d8(%rbp), %rdi
callq 0x1080
movq -0x550(%rbp), %rcx
movq %rax, %rdx
movq -0x548(%rbp), %rax
subq %rdx, %rcx
movb $0x0, (%rax,%rcx)
movq -0x4c0(%rbp), %rdi
movq 0x3af8(%rip), %rsi      # 0x50d0
movq -0x4c8(%rbp), %rdx
callq 0x1cb0
movl %eax, -0x4cc(%rbp)
movq -0x4c8(%rbp), %rdi
callq 0x1030
cmpl $0x0, -0x4cc(%rbp)
jne 0x1648
movq -0x418(%rbp), %rdi
callq 0x1070
movq 0x39e6(%rip), %rax      # 0x4ff8
movq (%rax), %rax
movq %rax, -0x558(%rbp)
movl $0x2, %edi
callq 0x1150
movq -0x558(%rbp), %rdi
movq %rax, %rdx
leaq 0x1a1d(%rip), %rsi      # 0x3054
movb $0x0, %al
callq 0x10c0
movl $0x2, %edi
callq 0x1140
movq -0x478(%rbp), %rax
movl %eax, -0x4e4(%rbp)
cvtsi2sdl -0x4e4(%rbp), %xmm0
movsd 0x19a3(%rip), %xmm1     # 0x3008
divsd %xmm1, %xmm0
callq 0x1160
cvttsd2si %xmm0, %eax
movl %eax, -0x4e8(%rbp)
movq 0x3a61(%rip), %rax      # 0x50e0
movzwl 0xc(%rax), %eax
movl -0x4e8(%rbp), %ecx
addl $0x1, %ecx
cmpl %ecx, %eax
jl 0x16a0
movq 0x3a49(%rip), %rax      # 0x50e0
movzwl 0xe(%rax), %eax
cmpl $0x1, %eax
jge 0x16e9
movq -0x418(%rbp), %rdi
callq 0x1070
movq 0x3945(%rip), %rax      # 0x4ff8
movq (%rax), %rax
movq %rax, -0x560(%rbp)
movl $0x1c, %edi
callq 0x1150
movq -0x560(%rbp), %rdi
movq %rax, %rdx
leaq 0x197c(%rip), %rsi      # 0x3054
movb $0x0, %al
callq 0x10c0
movl $0x1c, %edi
callq 0x1140
movl -0x490(%rbp), %eax
andl $0xf000, %eax           # imm = 0xF000
cmpl $0x8000, %eax           # imm = 0x8000
je 0x1744
movq -0x418(%rbp), %rdi
callq 0x1070
movq 0x38ea(%rip), %rax      # 0x4ff8
movq (%rax), %rax
movq %rax, -0x568(%rbp)
movl $0x1, %edi
callq 0x1150
movq -0x568(%rbp), %rdi
movq %rax, %rdx
leaq 0x1921(%rip), %rsi      # 0x3054
movb $0x0, %al
callq 0x10c0
movl $0x1, %edi
callq 0x1140
movb $0x0, %al
callq 0x2140
movl %eax, -0x4ec(%rbp)
movb $0x0, %al
callq 0x2060
movl %eax, -0x4f0(%rbp)
movl $0x0, -0x4f4(%rbp)
movq 0x3979(%rip), %rax      # 0x50e8
movl -0x4cc(%rbp), %ecx
subl $0x1, %ecx
movslq %ecx, %rcx
shlq $0x7, %rcx
addq %rcx, %rax
movslq -0x4f4(%rbp), %rcx
cmpl $0x0, 0x28(%rax,%rcx,4)
je 0x17a1
movl -0x4f4(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x4f4(%rbp)
jmp 0x1768
movl -0x4f0(%rbp), %edx
movq 0x393a(%rip), %rax      # 0x50e8
movl -0x4cc(%rbp), %ecx
subl $0x1, %ecx
movslq %ecx, %rcx
shlq $0x7, %rcx
addq %rcx, %rax
movslq -0x4f4(%rbp), %rcx
movl %edx, 0x28(%rax,%rcx,4)
movq 0x3915(%rip), %rax      # 0x50e8
movl -0x4cc(%rbp), %ecx
subl $0x1, %ecx
movslq %ecx, %rcx
shlq $0x7, %rcx
addq %rcx, %rax
movl 0x1c(%rax), %ecx
addl $0x2, %ecx
movl %ecx, 0x1c(%rax)
movq 0x38f2(%rip), %rax      # 0x50e8
movl -0x4cc(%rbp), %ecx
subl $0x1, %ecx
movslq %ecx, %rcx
shlq $0x7, %rcx
addq %rcx, %rax
movl 0x4(%rax), %ecx
addl $0x400, %ecx            # imm = 0x400
movl %ecx, 0x4(%rax)
movl -0x4f0(%rbp), %eax
shll $0xa, %eax
movl %eax, -0x570(%rbp)
movl -0x4ec(%rbp), %eax
movl %eax, -0x56c(%rbp)
movq -0x4d8(%rbp), %rdi
callq 0x1080
movl -0x570(%rbp), %edi
movl -0x56c(%rbp), %esi
movq -0x4d8(%rbp), %r9
movl $0x400, %edx            # imm = 0x400
movl $0x1, %r8d
movzbl %al, %ecx
callq 0x2320
movl $0x3c, %edi
callq 0x1100
movq %rax, -0x500(%rbp)
movl $0x0, -0x508(%rbp)
cmpl $0xc, -0x508(%rbp)
jge 0x1942
cmpl $0x0, -0x4e8(%rbp)
je 0x1917
movb $0x0, %al
callq 0x2060
movl %eax, -0x50c(%rbp)
movl -0x50c(%rbp), %edx
movq -0x500(%rbp), %rax
movslq -0x508(%rbp), %rcx
movl %edx, (%rax,%rcx,4)
leaq -0x410(%rbp), %rdi
movq -0x418(%rbp), %rcx
movl $0x1, %esi
movl $0x400, %edx            # imm = 0x400
callq 0x1060
movl %eax, -0x504(%rbp)
movq 0x37eb(%rip), %rdi      # 0x50d0
movl -0x50c(%rbp), %eax
shll $0xa, %eax
cltq
addq %rax, %rdi
leaq -0x410(%rbp), %rsi
movslq -0x504(%rbp), %rdx
callq 0x10d0
movl -0x4e8(%rbp), %eax
addl $-0x1, %eax
movl %eax, -0x4e8(%rbp)
jmp 0x192c
movq -0x500(%rbp), %rax
movslq -0x508(%rbp), %rcx
movl $0x0, (%rax,%rcx,4)
jmp 0x192e
movl -0x508(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x508(%rbp)
jmp 0x187d
cmpl $0x0, -0x4e8(%rbp)
je 0x1a78
movb $0x0, %al
callq 0x2060
movl %eax, -0x510(%rbp)
movl $0x400, %edi            # imm = 0x400
callq 0x1100
movq %rax, -0x518(%rbp)
movl $0x0, -0x51c(%rbp)
movslq -0x51c(%rbp), %rax
cmpq $0x100, %rax            # imm = 0x100
jae 0x1a42
cmpl $0x0, -0x4e8(%rbp)
je 0x1a17
movb $0x0, %al
callq 0x2060
movl %eax, -0x520(%rbp)
leaq -0x410(%rbp), %rdi
movq -0x418(%rbp), %rcx
movl $0x1, %esi
movl $0x400, %edx            # imm = 0x400
callq 0x1060
movl %eax, -0x504(%rbp)
movq 0x3702(%rip), %rdi      # 0x50d0
movl -0x520(%rbp), %eax
shll $0xa, %eax
movl %eax, %eax
addq %rax, %rdi
leaq -0x410(%rbp), %rsi
movslq -0x504(%rbp), %rdx
callq 0x10d0
movl -0x520(%rbp), %edx
movq -0x518(%rbp), %rax
movslq -0x51c(%rbp), %rcx
movl %edx, (%rax,%rcx,4)
movl -0x4e8(%rbp), %eax
addl $-0x1, %eax
movl %eax, -0x4e8(%rbp)
jmp 0x1a2c
movq -0x518(%rbp), %rax
movslq -0x51c(%rbp), %rcx
movl $0x0, (%rax,%rcx,4)
jmp 0x1a2e
movl -0x51c(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x51c(%rbp)
jmp 0x1977
movq 0x3687(%rip), %rdi      # 0x50d0
movl -0x510(%rbp), %eax
shll $0xa, %eax
cltq
addq %rax, %rdi
movq -0x518(%rbp), %rsi
movl $0x400, %edx            # imm = 0x400
callq 0x10d0
movl -0x510(%rbp), %ecx
movq -0x500(%rbp), %rax
movl %ecx, 0x30(%rax)
movq -0x418(%rbp), %rdi
callq 0x1070
cvtsi2sdl -0x4e4(%rbp), %xmm0
movsd 0x1574(%rip), %xmm1     # 0x3008
divsd %xmm1, %xmm0
callq 0x1160
cvttsd2si %xmm0, %eax
movl %eax, -0x4e8(%rbp)
movl -0x4ec(%rbp), %edi
movl -0x4e4(%rbp), %edx
movl -0x4e8(%rbp), %eax
shll %eax
movq -0x500(%rbp), %r9
movl $0x8000, %esi           # imm = 0x8000
movl $0x1, %ecx
movzwl %ax, %r8d
callq 0x21e0
xorl %eax, %eax
addq $0x570, %rsp            # imm = 0x570
popq %rbp
retq