// File: /workspace/github_c_makefile_star2_O0/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
movq %rsp, %rbp
subq $0x180, %rsp            # imm = 0x180
movl $0x0, -0x4(%rbp)
movl %edi, -0x8(%rbp)
movq %rsi, -0x10(%rbp)
cmpl $0x3, -0x8(%rbp)
je 0x18c1
movq 0x2752(%rip), %rax      # 0x3ff8
movq (%rax), %rdi
leaq 0x780(%rip), %rsi       # 0x2030
movb $0x0, %al
callq 0x10a0
movl $0x1, %edi
callq 0x10f0
movq -0x10(%rbp), %rax
movq 0x8(%rax), %rdi
movl $0x2, %esi
movb $0x0, %al
callq 0x10d0
movl %eax, -0x14(%rbp)
cmpl $0x0, -0x14(%rbp)
jne 0x1908
movq 0x2713(%rip), %rax      # 0x3ff8
movq (%rax), %rdi
movq -0x10(%rbp), %rax
movq 0x8(%rax), %rdx
leaq 0x75e(%rip), %rsi       # 0x2055
movb $0x0, %al
callq 0x10a0
movl $0x2, %edi
callq 0x10f0
movl -0x14(%rbp), %r8d
xorl %eax, %eax
movl %eax, %r9d
movl $0x20000, %esi          # imm = 0x20000
movl $0x3, %edx
movl $0x1, %ecx
movq %r9, %rdi
callq 0x1070
movq %rax, 0x2771(%rip)      # 0x40a0
movq $-0x1, %rax
cmpq %rax, 0x2763(%rip)      # 0x40a0
jne 0x1955
leaq 0x72a(%rip), %rdi       # 0x2070
callq 0x10e0
movl $0x1, %edi
callq 0x10f0
movq 0x2744(%rip), %rax      # 0x40a0
addq $0x400, %rax            # imm = 0x400
movq %rax, 0x273f(%rip)      # 0x40a8
movq 0x2730(%rip), %rax      # 0x40a0
addq $0x800, %rax            # imm = 0x800
movq %rax, 0x2733(%rip)      # 0x40b0
movq 0x271c(%rip), %rax      # 0x40a0
movq 0x2725(%rip), %rcx      # 0x40b0
movl (%rcx), %ecx
shll $0xa, %ecx
movl %ecx, %ecx
addq %rcx, %rax
movq %rax, -0x20(%rbp)
movq 0x2700(%rip), %rax      # 0x40a0
movq 0x2709(%rip), %rcx      # 0x40b0
movl 0x4(%rcx), %ecx
shll $0xa, %ecx
movl %ecx, %ecx
addq %rcx, %rax
movq %rax, -0x28(%rbp)
movq 0x26e3(%rip), %rdi      # 0x40a0
movq -0x10(%rbp), %rax
movq 0x10(%rax), %rsi
callq 0x1510
movl %eax, -0x2c(%rbp)
cmpl $-0x1, -0x2c(%rbp)
jne 0x19f5
movq 0x261e(%rip), %rax      # 0x3ff8
movq (%rax), %rdi
leaq 0x691(%rip), %rsi       # 0x2075
movb $0x0, %al
callq 0x10a0
movl $0x2, %edi
callq 0x10f0
movq -0x10(%rbp), %rax
movq 0x10(%rax), %rax
movq %rax, -0x178(%rbp)
movq -0x10(%rbp), %rax
movq 0x10(%rax), %rdi
callq 0x1060
movq %rax, %rcx
movq -0x178(%rbp), %rax
subq $0x1, %rcx
movsbl (%rax,%rcx), %eax
cmpl $0x2f, %eax
jne 0x1a4a
movq 0x25c9(%rip), %rax      # 0x3ff8
movq (%rax), %rdi
leaq 0x651(%rip), %rsi       # 0x208a
movb $0x0, %al
callq 0x10a0
movl $0x2, %edi
callq 0x10f0
movq -0x10(%rbp), %rax
movq 0x10(%rax), %rdi
callq 0x1790
movq %rax, -0x38(%rbp)
movq 0x263e(%rip), %rax      # 0x40a0
movq 0x2647(%rip), %rcx      # 0x40b0
movl 0x8(%rcx), %ecx
shll $0xa, %ecx
movl %ecx, %ecx
addq %rcx, %rax
movq 0x262d(%rip), %rcx      # 0x40a8
movzwl 0x58(%rcx), %ecx
imull -0x2c(%rbp), %ecx
movslq %ecx, %rcx
addq %rcx, %rax
movq %rax, -0x40(%rbp)
movl $0x0, -0x44(%rbp)
movq -0x40(%rbp), %rax
movslq -0x44(%rbp), %rcx
cmpl $0x0, 0x28(%rax,%rcx,4)
je 0x1da3
movl $0x0, -0x48(%rbp)
cmpl $0x400, -0x48(%rbp)     # imm = 0x400
jge 0x1d93
movq 0x25de(%rip), %rax      # 0x40a0
movq -0x40(%rbp), %rcx
movslq -0x44(%rbp), %rdx
movl 0x28(%rcx,%rdx,4), %ecx
shll $0xa, %ecx
movl %ecx, %ecx
addq %rcx, %rax
movslq -0x48(%rbp), %rcx
addq %rcx, %rax
movq %rax, -0x158(%rbp)
movq -0x158(%rbp), %rdi
addq $0x8, %rdi
leaq 0x578(%rip), %rsi       # 0x206e
callq 0x1090
cmpl $0x0, %eax
jne 0x1b13
movq -0x158(%rbp), %rax
movzwl 0x4(%rax), %eax
addl -0x48(%rbp), %eax
movl %eax, -0x48(%rbp)
jmp 0x1aae
movq -0x158(%rbp), %rax
movzbl 0x6(%rax), %edi
addl $0x8, %edi
callq 0x1750
movl %eax, -0x16c(%rbp)
movl -0x16c(%rbp), %eax
movq -0x158(%rbp), %rcx
movzwl 0x4(%rcx), %ecx
cmpl %ecx, %eax
jge 0x1d6a
movq 0x2554(%rip), %rax      # 0x40a0
movq -0x40(%rbp), %rcx
movslq -0x44(%rbp), %rdx
movl 0x28(%rcx,%rdx,4), %ecx
shll $0xa, %ecx
movl %ecx, %ecx
addq %rcx, %rax
movl -0x48(%rbp), %ecx
addl -0x16c(%rbp), %ecx
movslq %ecx, %rcx
addq %rcx, %rax
movq %rax, -0x160(%rbp)
leaq -0x150(%rbp), %rdi
movq -0x160(%rbp), %rsi
addq $0x8, %rsi
callq 0x1050
leaq -0x150(%rbp), %rdi
movq -0x38(%rbp), %rsi
callq 0x1090
cmpl $0x0, %eax
jne 0x1d68
movq -0x160(%rbp), %rax
movl (%rax), %edi
subl $0x1, %edi
movq -0x28(%rbp), %rsi
callq 0x1210
cmpl $0x0, %eax
je 0x1be2
movq 0x2431(%rip), %rax      # 0x3ff8
movq (%rax), %rdi
leaq 0x4cb(%rip), %rsi       # 0x209c
movb $0x0, %al
callq 0x10a0
movl $0x1, %edi
callq 0x10f0
movq 0x24b7(%rip), %rax      # 0x40a0
movq 0x24c0(%rip), %rcx      # 0x40b0
movl 0x8(%rcx), %ecx
shll $0xa, %ecx
movl %ecx, %ecx
addq %rcx, %rax
movq -0x160(%rbp), %rcx
movl (%rcx), %ecx
subl $0x1, %ecx
movl %ecx, %ecx
shlq $0x7, %rcx
addq %rcx, %rax
movq %rax, -0x168(%rbp)
movq -0x168(%rbp), %rax
cmpl $0x0, 0x14(%rax)
jne 0x1c46
movq 0x23cd(%rip), %rax      # 0x3ff8
movq (%rax), %rdi
leaq 0x467(%rip), %rsi       # 0x209c
movb $0x0, %al
callq 0x10a0
movl $0x1, %edi
callq 0x10f0
movq -0x168(%rbp), %rax
movl $0x0, 0x14(%rax)
movl $0x0, -0x170(%rbp)
movq -0x168(%rbp), %rax
movslq -0x170(%rbp), %rcx
cmpl $0x0, 0x28(%rax,%rcx,4)
je 0x1d08
movq -0x168(%rbp), %rax
movslq -0x170(%rbp), %rcx
movl 0x28(%rax,%rcx,4), %edi
subl $0x1, %edi
movq -0x20(%rbp), %rsi
callq 0x1210
cmpl $0x0, %eax
je 0x1cbc
movq 0x2357(%rip), %rax      # 0x3ff8
movq (%rax), %rdi
leaq 0x3f1(%rip), %rsi       # 0x209c
movb $0x0, %al
callq 0x10a0
movl $0x1, %edi
callq 0x10f0
movq -0x168(%rbp), %rax
movslq -0x170(%rbp), %rcx
movl 0x28(%rax,%rcx,4), %edi
subl $0x1, %edi
movq -0x20(%rbp), %rsi
callq 0x1260
movq 0x23c7(%rip), %rsi      # 0x40a8
movq 0x23c8(%rip), %rdx      # 0x40b0
movl $0xffffffff, %edi       # imm = 0xFFFFFFFF
callq 0x16f0
jmp 0x1cf4
movl -0x170(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x170(%rbp)
jmp 0x1c5e
movq -0x160(%rbp), %rax
movl (%rax), %edi
subl $0x1, %edi
movq -0x28(%rbp), %rsi
callq 0x1260
movq 0x2384(%rip), %rsi      # 0x40a8
movq 0x2385(%rip), %rdx      # 0x40b0
movl $0xffffffff, %edi       # imm = 0xFFFFFFFF
callq 0x1720
movq -0x168(%rbp), %rax
movw $0x1, 0x1a(%rax)
movl -0x16c(%rbp), %eax
movw %ax, %cx
movq -0x158(%rbp), %rax
movw %cx, 0x4(%rax)
movq -0x38(%rbp), %rdi
callq 0x1030
movl $0x0, -0x4(%rbp)
jmp 0x1dcb
jmp 0x1d6a
movq -0x158(%rbp), %rax
movzwl 0x4(%rax), %eax
addl -0x48(%rbp), %eax
movl %eax, -0x48(%rbp)
leaq -0x150(%rbp), %rdi
xorl %esi, %esi
movl $0x100, %edx            # imm = 0x100
callq 0x1080
jmp 0x1aae
jmp 0x1d95
movl -0x44(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x44(%rbp)
jmp 0x1a94
movq 0x224e(%rip), %rax      # 0x3ff8
movq (%rax), %rdi
leaq 0x2e8(%rip), %rsi       # 0x209c
movb $0x0, %al
callq 0x10a0
movq -0x38(%rbp), %rdi
callq 0x1030
movl $0x1, -0x4(%rbp)
movl -0x4(%rbp), %eax
addq $0x180, %rsp            # imm = 0x180
popq %rbp
retq