// File: /workspace/github_c_makefile_star2_O1/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 $0x138, %rsp            # imm = 0x138
cmpl $0x3, %edi
jne 0x1a55
movq %rsi, %rbx
movq 0x8(%rsi), %rdi
movl $0x2, %esi
xorl %eax, %eax
callq 0x10d0
testl %eax, %eax
je 0x1a5a
movl $0x20000, %esi          # imm = 0x20000
xorl %edi, %edi
movl $0x3, %edx
movl $0x1, %ecx
movl %eax, %r8d
xorl %r9d, %r9d
callq 0x1070
movq %rax, 0x2956(%rip)      # 0x40a8
cmpq $-0x1, %rax
je 0x1a66
movq %rax, %r14
addq $0x400, %rax            # imm = 0x400
movq %rax, 0x2944(%rip)      # 0x40b0
leaq 0x800(%r14), %rax
movq %rax, 0x293e(%rip)      # 0x40b8
movl 0x800(%r14), %r12d
movl 0x804(%r14), %r15d
movq 0x10(%rbx), %rsi
movq %r14, %rdi
callq 0x153a
cmpl $-0x1, %eax
je 0x1a6b
movl %eax, %ebp
movq 0x10(%rbx), %rbx
movq %rbx, %rdi
callq 0x1060
cmpb $0x2f, -0x1(%rbx,%rax)
je 0x1a70
movq %rbx, %rdi
callq 0x168f
movq %rax, (%rsp)
movq 0x28ef(%rip), %rax      # 0x40b8
movl 0x8(%rax), %eax
shll $0xa, %eax
addq 0x28d2(%rip), %rax      # 0x40a8
movq 0x28d3(%rip), %rcx      # 0x40b0
movzwl 0x58(%rcx), %edx
movslq %ebp, %rcx
imulq %rdx, %rcx
cmpl $0x0, 0x28(%rcx,%rax)
je 0x1a22
shll $0xa, %r12d
addq %r14, %r12
shll $0xa, %r15d
addq %r14, %r15
movq %r15, 0x8(%rsp)
addq %rcx, %rax
addq $0x28, %rax
xorl %ecx, %ecx
movq %rax, 0x18(%rsp)
movq %rax, 0x10(%rsp)
movq %r12, 0x28(%rsp)
movq %rcx, 0x20(%rsp)
xorl %r13d, %r13d
movq 0x287b(%rip), %rbp      # 0x40a8
movq 0x10(%rsp), %rax
movl (%rax), %r15d
shll $0xa, %r15d
addq %rbp, %r15
movl %r13d, %eax
leaq (%r15,%rax), %rbx
leaq (%rax,%r15), %rdi
addq $0x8, %rdi
leaq 0x81c(%rip), %rsi       # 0x206e
callq 0x1090
testl %eax, %eax
je 0x18ca
movzbl 0x6(%rbx), %eax
leal 0x8(%rax), %ecx
movl %eax, %r14d
addl $0xc, %r14d
andl $-0x4, %r14d
testb $0x3, %al
cmovel %ecx, %r14d
movzwl 0x4(%rbx), %eax
cmpl %eax, %r14d
jae 0x18a7
leal (%r14,%r13), %eax
movslq %eax, %r12
leaq (%r15,%r12), %rsi
addq $0x8, %rsi
leaq 0x30(%rsp), %rdi
callq 0x1050
leaq 0x30(%rsp), %rdi
movq (%rsp), %rsi
callq 0x1090
testl %eax, %eax
je 0x18e3
movzwl 0x4(%rbx), %eax
addl %eax, %r13d
movl $0x100, %edx            # imm = 0x100
leaq 0x30(%rsp), %rdi
xorl %esi, %esi
callq 0x1080
movb $0x1, %al
testb %al, %al
jne 0x18d1
jmp 0x1a32
movzwl 0x4(%rbx), %eax
addl %eax, %r13d
cmpl $0x400, %r13d           # imm = 0x400
jl 0x1826
jmp 0x19ff
addq %r12, %r15
movl (%r15), %eax
leal -0x1(%rax), %ecx
addl $0x6, %eax
testl %ecx, %ecx
cmovnsl %ecx, %eax
sarl $0x3, %eax
cltq
movq 0x8(%rsp), %rdx
movzbl (%rdx,%rax), %eax
movl %ecx, %edx
andl $0x7, %edx
btl %edx, %eax
jb 0x1a50
movq 0x27a1(%rip), %rax      # 0x40b8
movl 0x8(%rax), %esi
shll $0xa, %esi
leaq (%rsi,%rbp), %rax
movl %ecx, %edx
shlq $0x7, %rdx
cmpl $0x0, 0x14(%rdx,%rax)
movq 0x28(%rsp), %r12
je 0x1a4b
movl $0x0, 0x14(%rax,%rdx)
movl 0x28(%rax,%rdx), %edi
testl %edi, %edi
je 0x19a3
addq %rdx, %rsi
addq %rbp, %rsi
addq $0x2c, %rsi
leal -0x1(%rdi), %ecx
addl $0x6, %edi
testl %ecx, %ecx
cmovnsl %ecx, %edi
sarl $0x3, %edi
movslq %edi, %rdi
movzbl (%r12,%rdi), %r8d
andl $0x7, %ecx
btl %ecx, %r8d
jb 0x1a46
movl $0x1, %r9d
shll %cl, %r9d
xorb %r8b, %r9b
movb %r9b, (%r12,%rdi)
movq 0x2725(%rip), %rcx      # 0x40b0
movq 0x2726(%rip), %rdi      # 0x40b8
decl 0xc(%rcx)
decw 0xc(%rdi)
movl (%rsi), %edi
addq $0x4, %rsi
testl %edi, %edi
jne 0x1951
movl (%r15), %esi
leal -0x1(%rsi), %edi
movl %edi, %ecx
andb $0x7, %cl
movl $0x1, %r8d
shll %cl, %r8d
addl $0x6, %esi
testl %edi, %edi
cmovnsl %edi, %esi
sarl $0x3, %esi
movslq %esi, %rcx
movq 0x8(%rsp), %rsi
xorb %r8b, (%rsi,%rcx)
movq 0x26db(%rip), %rcx      # 0x40b0
movq 0x26dc(%rip), %rsi      # 0x40b8
decl 0x10(%rcx)
decw 0xe(%rsi)
movw $0x1, 0x1a(%rax,%rdx)
movw %r14w, 0x4(%rbx)
movq (%rsp), %rdi
callq 0x1030
xorl %eax, %eax
jmp 0x18c1
movq 0x18(%rsp), %rax
movq 0x20(%rsp), %rcx
leaq (%rax,%rcx,4), %rax
addq $0x4, %rax
incq %rcx
movq %rax, 0x10(%rsp)
cmpl $0x0, (%rax)
jne 0x181e
movq (%rsp), %rdi
callq 0x120e
movl $0x1, %eax
jmp 0x1a34
xorl %eax, %eax
addq $0x138, %rsp            # imm = 0x138
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
callq 0x11c4
callq 0x11e9
callq 0x119f
callq 0x117a
addq $0x8, %rbx
movq %rbx, %rdi
callq 0x1297
callq 0x1282
callq 0x125d
callq 0x1238