// File: /workspace/github_c_makefile_star2_O2/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 0x188b
movq %rsi, %r14
movq 0x8(%rsi), %rdi
pushq $0x2
popq %rsi
xorl %eax, %eax
callq 0x10d0
testl %eax, %eax
je 0x18a0
pushq $0x3
popq %rdx
pushq $0x1
popq %rcx
movl $0x20000, %esi          # imm = 0x20000
xorl %edi, %edi
movl %eax, %r8d
xorl %r9d, %r9d
callq 0x1070
movq %rax, 0x2aef(%rip)      # 0x40a8
cmpq $-0x1, %rax
je 0x18be
movq %rax, %r15
addq $0x400, %rax            # imm = 0x400
movq %rax, 0x2add(%rip)      # 0x40b0
leaq 0x800(%r15), %rax
movq %rax, 0x2ad7(%rip)      # 0x40b8
movl 0x800(%r15), %r12d
movl 0x804(%r15), %ebx
movq 0x10(%r14), %rsi
movq %r15, %rdi
callq 0x1389
cmpl $-0x1, %eax
je 0x18cc
movl %eax, %ebp
movq 0x10(%r14), %r14
movq %r14, %rdi
callq 0x1060
cmpb $0x2f, -0x1(%r14,%rax)
je 0x18e1
shll $0xa, %r12d
addq %r15, %r12
movq %r12, 0x18(%rsp)
shll $0xa, %ebx
addq %r15, %rbx
movq %rbx, 0x20(%rsp)
movq %r14, %rdi
callq 0x14f5
movq %rax, (%rsp)
movq 0x2a60(%rip), %rcx      # 0x40a8
movq 0x2a69(%rip), %rax      # 0x40b8
movl 0x8(%rax), %edx
shll $0xa, %edx
movq %rcx, 0x28(%rsp)
addq %rcx, %rdx
movq 0x2a4c(%rip), %rax      # 0x40b0
movzwl 0x58(%rax), %eax
movslq %ebp, %rcx
imulq %rax, %rcx
leaq (%rcx,%rdx), %rax
addq $0x28, %rax
movq %rax, 0x30(%rsp)
xorl %ecx, %ecx
movq %rdx, 0x10(%rsp)
movq 0x30(%rsp), %rax
movl (%rax,%rcx,4), %r14d
testl %r14d, %r14d
je 0x1846
movq %rcx, 0x38(%rsp)
shll $0xa, %r14d
addq 0x28(%rsp), %r14
xorl %r13d, %r13d
movq %r14, 0x8(%rsp)
cmpl $0x3ff, %r13d           # imm = 0x3FF
ja 0x173b
movl %r13d, %r12d
cmpb $0x2e, 0x8(%r14,%r12)
jne 0x16cb
cmpb $0x0, 0x9(%r14,%r12)
je 0x1733
movzbl 0x6(%r14,%r12), %eax
leal 0x8(%rax), %ecx
movl %eax, %ebx
andl $-0x4, %ebx
addl $0xc, %ebx
testb $0x3, %al
cmovel %ecx, %ebx
movzwl 0x4(%r14,%r12), %r15d
cmpl %r15d, %ebx
jae 0x171a
leal (%rbx,%r13), %ebp
leaq (%r14,%rbp), %rsi
addq $0x8, %rsi
leaq 0x40(%rsp), %r14
movq %r14, %rdi
callq 0x1050
movq %r14, %rdi
movq 0x8(%rsp), %r14
movq (%rsp), %rsi
callq 0x1090
testl %eax, %eax
je 0x1748
movl $0x100, %edx            # imm = 0x100
leaq 0x40(%rsp), %rdi
xorl %esi, %esi
callq 0x1080
addl %r15d, %r13d
jmp 0x16ab
movzwl 0x4(%r14,%r12), %r15d
jmp 0x172b
movq 0x38(%rsp), %rcx
incq %rcx
jmp 0x1683
addq %r14, %rbp
movl (%rbp), %ecx
decl %ecx
pushq $0x8
popq %rdi
movl %ecx, %eax
cltd
idivl %edi
cltq
movq 0x20(%rsp), %r10
movzbl (%r10,%rax), %eax
movl %ecx, %edx
andl $0x7, %edx
btl %edx, %eax
jb 0x1867
movl %ecx, %eax
shlq $0x7, %rax
movq 0x10(%rsp), %r15
cmpl $0x0, 0x14(%r15,%rax)
pushq $0x1
popq %r9
movq 0x18(%rsp), %r11
je 0x1867
addq %rax, %r15
andl $0x0, 0x14(%r15)
leaq 0x28(%r15), %r8
movl (%r8), %esi
testl %esi, %esi
je 0x17ea
decl %esi
movl %esi, %eax
cltd
idivl %edi
movl %esi, %ecx
andb $0x7, %cl
movl %r9d, %edx
shll %cl, %edx
cltq
movzbl (%r11,%rax), %ecx
andl $0x7, %esi
btl %esi, %ecx
jb 0x1867
xorb %cl, %dl
movb %dl, (%r11,%rax)
movq 0x28da(%rip), %rax      # 0x40b0
movq 0x28db(%rip), %rcx      # 0x40b8
decl 0xc(%rax)
decw 0xc(%rcx)
addq $0x4, %r8
jmp 0x179e
movl (%rbp), %eax
decl %eax
movl %eax, %ecx
andb $0x7, %cl
shll %cl, %r9d
cltd
idivl %edi
cltq
xorb %r9b, (%r10,%rax)
movq 0x28a9(%rip), %rax      # 0x40b0
movq 0x28aa(%rip), %rcx      # 0x40b8
decl 0x10(%rax)
decw 0xe(%rcx)
movw $0x1, 0x1a(%r15)
movq 0x8(%rsp), %rax
movw %bx, 0x4(%rax,%r12)
xorl %ebx, %ebx
movq (%rsp), %rdi
callq 0x1030
movl %ebx, %eax
addq $0x148, %rsp            # imm = 0x148
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
movq 0x27ab(%rip), %rax      # 0x3ff8
movq (%rax), %rcx
leaq 0x845(%rip), %rdi       # 0x209c
pushq $0x14
popq %rsi
pushq $0x1
popq %rdx
callq 0x1100
pushq $0x1
popq %rbx
jmp 0x1829
movq 0x278a(%rip), %rax      # 0x3ff8
movq (%rax), %rcx
leaq 0x824(%rip), %rdi       # 0x209c
pushq $0x14
popq %rsi
pushq $0x1
popq %rdx
callq 0x1100
pushq $0x1
popq %rdi
callq 0x10f0
movq 0x2766(%rip), %rax      # 0x3ff8
movq (%rax), %rcx
leaq 0x794(%rip), %rdi       # 0x2030
pushq $0x24
jmp 0x187a
movq 0x2751(%rip), %rax      # 0x3ff8
movq (%rax), %rdi
movq 0x8(%r14), %rdx
leaq 0x7a0(%rip), %rsi       # 0x2055
xorl %eax, %eax
callq 0x10a0
jmp 0x18fd
leaq 0x7ab(%rip), %rdi       # 0x2070
callq 0x10e0
jmp 0x1883
movq 0x2725(%rip), %rax      # 0x3ff8
movq (%rax), %rcx
leaq 0x798(%rip), %rdi       # 0x2075
pushq $0x14
jmp 0x18f4
movq 0x2710(%rip), %rax      # 0x3ff8
movq (%rax), %rcx
leaq 0x798(%rip), %rdi       # 0x208a
pushq $0x11
popq %rsi
pushq $0x1
popq %rdx
callq 0x1100
pushq $0x2
jmp 0x1885