// File: /workspace/github_c_makefile_star2_O3/kevinp89[P]Operating-System-EXT2-file-system-with-commands/ext2_restore.c
// Function: main
int main(int argc, char **argv){

    if(argc != 3){
        fprintf(stderr, "Usage: ./ext2_restore [disk] [path]\n");
        exit(1);
    }

    // Opening disk
    int fd = open(argv[1], O_RDWR);
    if (!fd) {
        fprintf(stderr, "Disk image '%s' not found.", argv[1]);
        exit(ENOENT);
    }
    // mmap the disk
    disk = mmap(NULL, 128*1024, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
    if (disk == MAP_FAILED) {
        perror("mmap");
        exit(1);
    }
    // Grabbing super block and block descriptor
    sb = (struct ext2_super_block *)(disk + 1024);
    desc = (struct ext2_group_desc *)(disk + 2*1024);
    //get the bitmap
    unsigned char *map = (unsigned char *)(disk + 1024 * desc->bg_block_bitmap);
    //get the inode map
    unsigned char *imap = (unsigned char *)(disk + 1024 * desc->bg_inode_bitmap);
    //get the parent index
    int parent_inode_index = check_parent(disk, argv[2]);
    if (parent_inode_index == -1) { // Directory not found.
        fprintf(stderr, "File does not exist.");
        exit(ENOENT);
    }

    if (argv[2][strlen(argv[2])-1] == '/') {
        fprintf(stderr, "Invalid filename.");
        exit(ENOENT);
    }
    //get the name of the file trying to restore
    char *file_name = get_last_file_name(argv[2]);

    //get the parent node
    struct ext2_inode *parent = (struct ext2_inode *)((disk + 1024 * desc->bg_inode_table) +
                                                      (sb->s_inode_size * parent_inode_index));

    /* check gaps */
    /*
     * look for any dir_entry that, when subtracting its  real space, might
     * contain another dir_entry with the original filename
     */
    int i;
    int cur_rec_len;
	char hit_name[256];
    struct ext2_dir_entry *cur_dir;
    struct ext2_dir_entry *poss_hit;
    struct ext2_inode *found_node;
    for (i = 0; parent->i_block[i] != 0; i++) {
        for (cur_rec_len = 0; cur_rec_len < EXT2_BLOCK_SIZE;) {
            cur_dir = (struct ext2_dir_entry *) (disk + (EXT2_BLOCK_SIZE *
                                                         parent->i_block[i]) +
                                                 cur_rec_len);
            if ((strcmp(cur_dir->name, ".") == 0)) {
                cur_rec_len += cur_dir->rec_len;
                continue;
            }
            int check = align(8 + cur_dir->name_len);
            if (check < cur_dir->rec_len) {
                //possible hit get the entry and check name and i_dtime.
                poss_hit = (struct ext2_dir_entry *) (disk +
						(EXT2_BLOCK_SIZE * parent->i_block[i]) +
                        ((cur_rec_len + check)));

                strcpy(hit_name, poss_hit->name);

                //check if name equal
                if (strcmp(hit_name, file_name) == 0) {
                    //check if inode isn't used up
                    if (check_node(poss_hit->inode - 1, imap)) {
                        fprintf(stderr, "Cannot restore File\n");
                        exit(1);
                    }

                    //get the inode
                    found_node = (struct ext2_inode *) 
						(disk + (1024 * desc->bg_inode_table) +
                            (sizeof(struct ext2_inode) * (poss_hit->inode-1)));

                    //check if inode has been overwritten.
                    if (found_node->i_dtime == 0) {
                        fprintf(stderr, "Cannot restore File\n");
                        exit(1);
                    }
                    //set deletion time to 0
                    found_node->i_dtime = 0;

                    //check blocks
                    int x;
                    for (x = 0; found_node->i_block[x] != 0; x++) {
                        //block was allocated
                        if (check_node(found_node->i_block[x] - 1, map)) {
                            fprintf(stderr, "Cannot restore File\n");
                            exit(1);
                        } else {
                            //block wasn't allocated, set it
                            set_node(found_node->i_block[x] - 1, map);
                            adjust_free_blocks(-1, sb, desc);
                        }
                    }
                    //mark the bit in the map
                    set_node(poss_hit->inode - 1, imap);
					adjust_free_inodes(-1, sb, desc);
					found_node->i_links_count = 1;
                    cur_dir->rec_len = check;
                    free(file_name);

                    return 0;
                }
            }
            //incr the cur len
            cur_rec_len += cur_dir->rec_len;
			memset(hit_name, 0, sizeof(hit_name));
        }
    }
    fprintf(stderr, "Cannot restore File\n");
    free(file_name);
    return 1;
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x148, %rsp            # imm = 0x148
cmpl $0x3, %edi
jne 0x1a31
movq %rsi, %rbx
movq 0x8(%rsi), %rdi
movl $0x2, %esi
xorl %eax, %eax
callq 0x10d0
testl %eax, %eax
je 0x1a36
movl $0x20000, %esi          # imm = 0x20000
xorl %edi, %edi
movl $0x3, %edx
movl $0x1, %ecx
movl %eax, %r8d
xorl %r9d, %r9d
callq 0x1070
movq %rax, 0x2949(%rip)      # 0x40a8
cmpq $-0x1, %rax
je 0x1a42
movq %rax, %r14
addq $0x400, %rax            # imm = 0x400
movq %rax, 0x2937(%rip)      # 0x40b0
leaq 0x800(%r14), %rax
movq %rax, 0x2931(%rip)      # 0x40b8
movl 0x800(%r14), %r12d
movl 0x804(%r14), %r15d
movq 0x10(%rbx), %rsi
movq %r14, %rdi
callq 0x153a
cmpl $-0x1, %eax
je 0x1a47
movl %eax, %ebp
movq 0x10(%rbx), %rbx
movq %rbx, %rdi
callq 0x1060
cmpb $0x2f, -0x1(%rbx,%rax)
je 0x1a4c
movq %rbx, %rdi
callq 0x169c
movq %rax, 0x10(%rsp)
movq 0x28d1(%rip), %rcx      # 0x40a8
movq 0x28da(%rip), %rax      # 0x40b8
movl 0x8(%rax), %eax
shll $0xa, %eax
movq %rcx, 0x8(%rsp)
movq %rax, 0x18(%rsp)
leaq (%rcx,%rax), %rdx
movq 0x28b7(%rip), %rax      # 0x40b0
movzwl 0x58(%rax), %ecx
movslq %ebp, %rax
imulq %rcx, %rax
movq %rdx, (%rsp)
movl 0x28(%rax,%rdx), %ebp
testl %ebp, %ebp
je 0x18ee
shll $0xa, %r12d
addq %r14, %r12
movq %r12, 0x20(%rsp)
shll $0xa, %r15d
addq %r14, %r15
movq %r15, 0x28(%rsp)
movq (%rsp), %rcx
addq %rcx, %rax
addq $0x28, %rax
movq %rax, 0x30(%rsp)
xorl %ecx, %ecx
leaq 0x40(%rsp), %r14
movq %rcx, 0x38(%rsp)
shll $0xa, %ebp
addq 0x8(%rsp), %rbp
xorl %r15d, %r15d
movl %r15d, %r15d
cmpb $0x2e, 0x8(%rbp,%r15)
jne 0x1866
cmpb $0x0, 0x9(%rbp,%r15)
je 0x18cd
movzbl 0x6(%rbp,%r15), %eax
leal 0x8(%rax), %ecx
movl %eax, %r13d
andl $-0x4, %r13d
addl $0xc, %r13d
testb $0x3, %al
cmovel %ecx, %r13d
movzwl 0x4(%rbp,%r15), %r12d
cmpl %r12d, %r13d
jae 0x18b0
leal (%r15,%r13), %ebx
leaq (%rbx,%rbp), %rsi
addq $0x8, %rsi
movq %r14, %rdi
callq 0x1050
movq %r14, %rdi
movq 0x10(%rsp), %rsi
callq 0x1090
testl %eax, %eax
je 0x18fd
movl $0x100, %edx            # imm = 0x100
movq %r14, %rdi
xorl %esi, %esi
callq 0x1080
addl %r12d, %r15d
cmpl $0x400, %r15d           # imm = 0x400
jb 0x1853
jmp 0x18d5
movzwl 0x4(%rbp,%r15), %r12d
jmp 0x18bf
movq 0x30(%rsp), %rax
movq 0x38(%rsp), %rcx
movl 0x4(%rax,%rcx,4), %ebp
incq %rcx
testl %ebp, %ebp
jne 0x1843
callq 0x120e
movl $0x1, %ebp
jmp 0x1a0e
addq %rbp, %rbx
movl (%rbx), %ecx
leal -0x1(%rcx), %eax
addl $0x6, %ecx
testl %eax, %eax
cmovnsl %eax, %ecx
sarl $0x3, %ecx
movslq %ecx, %rcx
movq 0x28(%rsp), %r9
movzbl (%r9,%rcx), %ecx
movl %eax, %edx
andl $0x7, %edx
btl %edx, %ecx
movq 0x20(%rsp), %r10
jb 0x1a51
movl %eax, %eax
shlq $0x7, %rax
movq (%rsp), %r11
cmpl $0x0, 0x14(%r11,%rax)
je 0x1a56
movl $0x0, 0x14(%r11,%rax)
movl 0x28(%r11,%rax), %esi
testl %esi, %esi
je 0x19c6
movq 0x18(%rsp), %rdx
addq %rax, %rdx
movq 0x8(%rsp), %rcx
addq %rcx, %rdx
addq $0x2c, %rdx
leal -0x1(%rsi), %r8d
addl $0x6, %esi
testl %r8d, %r8d
cmovnsl %r8d, %esi
sarl $0x3, %esi
movl %r8d, %ecx
andb $0x7, %cl
movl $0x1, %edi
shll %cl, %edi
movslq %esi, %rcx
movzbl (%r10,%rcx), %esi
andl $0x7, %r8d
btl %r8d, %esi
jb 0x1a2c
xorb %sil, %dil
movb %dil, (%r10,%rcx)
movq 0x2702(%rip), %rcx      # 0x40b0
movq 0x2703(%rip), %rsi      # 0x40b8
decl 0xc(%rcx)
decw 0xc(%rsi)
movl (%rdx), %esi
addq $0x4, %rdx
testl %esi, %esi
jne 0x196c
movl (%rbx), %edx
leal -0x1(%rdx), %esi
movl %esi, %ecx
andb $0x7, %cl
movl $0x1, %edi
shll %cl, %edi
addl $0x6, %edx
testl %esi, %esi
cmovnsl %esi, %edx
sarl $0x3, %edx
movslq %edx, %rcx
xorb %dil, (%r9,%rcx)
movq 0x26c0(%rip), %rcx      # 0x40b0
movq 0x26c1(%rip), %rdx      # 0x40b8
decl 0x10(%rcx)
decw 0xe(%rdx)
movw $0x1, 0x1a(%r11,%rax)
movw %r13w, 0x4(%rbp,%r15)
xorl %ebp, %ebp
movq 0x10(%rsp), %rdi
callq 0x1030
movl %ebp, %eax
addq $0x148, %rsp            # imm = 0x148
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
callq 0x11c4
callq 0x117a
addq $0x8, %rbx
movq %rbx, %rdi
callq 0x128f
callq 0x127a
callq 0x1255
callq 0x1230
callq 0x119f
callq 0x11e9