// File: /workspace/github_c_makefile_star2_O2/kevinp89[P]Operating-System-EXT2-file-system-with-commands/ext2_checker.c
// Function: main
int main(int argc, char **argv) {
	if (argc != 2) { // Requires only one argument, an ext2 formatted disk.
		fprintf(stderr, "Usage: %s [disk]\n", argv[0]);
		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);

	int errors = 0; // Total number of errors fixed, increment for every fix.
	// Allocating the bitmaps.
	unsigned char *map = (unsigned char *)(disk + 1024 * desc->bg_block_bitmap);
	unsigned char *imap = (unsigned char *)(disk + 1024 * desc->bg_inode_bitmap);

	// Count the free blocks based on the bitmap.
	int free = sb->s_blocks_count; // Total number of blocks.
	int diff; // Value to allocate the difference if there is one.
	int i;
	for (i = 0; i < sb->s_blocks_count; i++) {
		if (check_node(i, map)) free--;
	}
	// Check free versus the counts in sb and desc.
	// Block bitmap vs superblock
	if (free != sb->s_free_blocks_count) {
		diff = abs(sb->s_free_blocks_count - free);
		printf("Fixed: superblock's free block counter was off by %d compared to the bitmap\n",
					diff);
		sb->s_free_blocks_count = free;
		errors += diff;
	}
	// Block bitmap vs group descriptor
	if (free != desc->bg_free_blocks_count) {
		diff = abs(desc->bg_free_blocks_count - free);
		printf("Fixed: block group's free block counter was off by %d compared to the bitmap\n",
					diff);
		desc->bg_free_blocks_count = free;
		errors += diff;
	}
	// Reset free for the inode bitmap, loop through.
	free = sb->s_inodes_count;
	for (i = 0; i < sb->s_inodes_count; i++) {
		if (check_node(i, imap)) free--;
	}
	// Check free versus the counts in sb and desc.
	// Inode bitmap vs superblock
	if (free != sb->s_free_inodes_count) {
		diff = abs(sb->s_free_inodes_count - free);
		printf("Fixed: superblock's free inode counter was off by %d compared to the bitmap\n",
					diff);
		sb->s_free_inodes_count = free;
		errors += diff;
	}
	// Inode bitmap vs group desc
	if (free != desc->bg_free_inodes_count) {
		diff = abs(desc->bg_free_inodes_count - free);
		printf("Fixed: block group's free inode counter was off by %d compared to the bitmap\n",
					diff);
		desc->bg_free_inodes_count = free;
		errors += diff;
	}

	// Check each directory entry for matching file type with its inode.
	// Straight from readimage to get directory blocks.
	struct ext2_inode *curinode;
	struct ext2_inode *file_node;
	for (i = 0; i < sb->s_inodes_count; i++) {
		if ((check_node(i, imap) && (i == 1 || i >= 11)) || i == 1) {
			curinode = (struct ext2_inode *)((disk + 1024 * desc->bg_inode_table) + (sb->s_inode_size * i));
			if (get_inode_type(curinode) == 'd') {
				// Looping through blocks to find ext2_dir_entry details
				unsigned int cur_rec_len;
				unsigned char file_type;
				struct ext2_dir_entry *curdir;
				int x; // Need some new loop integer since i is already in use.
				for (x = 0; curinode->i_block[x] != 0; x++) {
					for (cur_rec_len = 0; cur_rec_len < 1024; ) {
						curdir = (struct ext2_dir_entry *)(disk + (1024 * curinode->i_block[x]) + cur_rec_len);
						file_type = get_dir_type(curdir->file_type);
						file_node = (struct ext2_inode *)((disk + 1024 * desc->bg_inode_table) +
															(sb->s_inode_size * (curdir->inode-1)));
						cur_rec_len += curdir->rec_len;
						if (file_type != get_inode_type(file_node)) {
							printf("Fixed: Entry type vs inode mismatch: inode %d\n", curdir->inode);
							errors++;
							set_dir_type(curdir, get_inode_type(file_node));
						}

						// Check that the directory's inode is allocated
						if (!check_node(curdir->inode - 1, imap)) { // Inode is not allocated
							errors++;
							printf("Fixed: inode %d not marked as in-use\n", curdir->inode);
							set_node(curdir->inode-1, imap);
							adjust_free_inodes(-1, sb, desc);
						}

						// Check inodes i_dtime to be 0
						if (file_node->i_dtime != 0) {
							errors++;
							printf("Fixed: valid inode marked for deletion: %d\n", curdir->inode);
							file_node->i_dtime = 0;
						}

						// Check the directory's data blocks for allocation
						int y; // Another random counter...
						int block_counter = 0; // Counting amount of blocks not allocated.
						for (y = 0; file_node->i_block[y] != 0; y++) {
							if (!check_node(file_node->i_block[y] - 1, map)) {
								block_counter++;
								set_node(file_node->i_block[y] - 1, map);
								adjust_free_blocks(-1, sb, desc);
							}
						}
						if (block_counter > 0) {
							errors++;
							printf("Fixed: %d in-use data blocks not marked in data bitmap for inode: %d\n",
									block_counter, curdir->inode);
						}	
					}
				}
			}
		}
	}

	// Output final message
	if (errors > 0) {
		printf("%d file system inconsistencies repaired!\n", errors);
	} else {
		printf("No file system inconsistencies detected!\n");
	}
		
	return 0;
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x48, %rsp
movq %rsi, %rbx
cmpl $0x2, %edi
jne 0x19bf
movq 0x8(%rbx), %rdi
pushq $0x2
popq %rsi
xorl %eax, %eax
callq 0x10d0
testl %eax, %eax
je 0x19dc
xorl %r14d, %r14d
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, 0x2b76(%rip)      # 0x40a8
cmpq $-0x1, %rax
je 0x19fc
leaq 0x400(%rax), %rcx
movq %rcx, 0x2b66(%rip)      # 0x40b0
leaq 0x800(%rax), %r9
movq %r9, 0x2b60(%rip)       # 0x40b8
movl 0x800(%rax), %r15d
shll $0xa, %r15d
addq %rax, %r15
movl 0x804(%rax), %ebx
shll $0xa, %ebx
movq %rax, %r12
movl 0x404(%rax), %edx
movl %edx, %ebp
cmpl %r14d, %edx
je 0x159b
movl %r14d, %esi
shrl $0x3, %esi
movzbl (%r15,%rsi), %esi
movl %r14d, %edi
andl $0x7, %edi
btl %edi, %esi
sbbl $0x0, %ebp
incl %r14d
jmp 0x157a
movl 0x40c(%r12), %edx
xorl %r14d, %r14d
subl %ebp, %edx
je 0x15d6
movl %edx, %r14d
negl %r14d
cmovsl %edx, %r14d
leaq 0xa91(%rip), %rdi       # 0x204c
movl %r14d, %esi
xorl %eax, %eax
callq 0x1080
movq 0x2ae4(%rip), %rcx      # 0x40b0
movl %ebp, 0xc(%rcx)
movq 0x2ae2(%rip), %r9       # 0x40b8
movzwl 0xc(%r9), %edx
subl %ebp, %edx
je 0x1616
movl %r14d, %r13d
movl %edx, %r14d
negl %r14d
cmovsl %edx, %r14d
leaq 0xaa6(%rip), %rdi       # 0x2099
movl %r14d, %esi
xorl %eax, %eax
callq 0x1080
movq 0x2ab4(%rip), %r9       # 0x40b8
movw %bp, 0xc(%r9)
addl %r14d, %r13d
movl %r13d, %r14d
movq 0x2a9a(%rip), %rcx      # 0x40b0
addq %rbx, %r12
movl (%rcx), %edx
xorl %esi, %esi
movl %edx, %ebx
cmpl %esi, %edx
je 0x163f
movl %esi, %edi
shrl $0x3, %edi
movzbl (%r12,%rdi), %edi
movl %esi, %r8d
andl $0x7, %r8d
btl %r8d, %edi
sbbl $0x0, %ebx
incl %esi
jmp 0x161f
movl 0x10(%rcx), %ecx
subl %ebx, %ecx
je 0x167b
movl %r14d, %ebp
movl %ecx, %r14d
negl %r14d
cmovsl %ecx, %r14d
leaq 0xa8d(%rip), %rdi       # 0x20e7
movl %r14d, %esi
xorl %eax, %eax
callq 0x1080
movq 0x2a45(%rip), %rax      # 0x40b0
movl %ebx, 0x10(%rax)
addl %r14d, %ebp
movl %ebp, %r14d
movq 0x2a3d(%rip), %r9       # 0x40b8
movzwl 0xe(%r9), %eax
subl %ebx, %eax
movq %r12, 0x30(%rsp)
je 0x16b8
movl %r14d, %ebp
movl %eax, %r14d
negl %r14d
cmovsl %eax, %r14d
leaq 0xa97(%rip), %rdi       # 0x2134
movl %r14d, %esi
xorl %eax, %eax
callq 0x1080
movq 0x2a0a(%rip), %rax      # 0x40b8
movw %bx, 0xe(%rax)
addl %r14d, %ebp
movl %ebp, %r14d
pushq $0x8
popq %rbp
xorl %esi, %esi
movq 0x29ec(%rip), %rax      # 0x40b0
cmpl (%rax), %esi
jae 0x198a
movl %esi, %ecx
shrl $0x3, %ecx
movq 0x30(%rsp), %rdx
movzbl (%rdx,%rcx), %ecx
movl %esi, %edx
andl $0x7, %edx
btl %edx, %ecx
jae 0x16f9
cmpl $0x1, %esi
sete %cl
cmpl $0xb, %esi
setae %dl
orb %cl, %dl
jne 0x1702
jmp 0x1983
cmpl $0x1, %esi
jne 0x1983
movq 0x29af(%rip), %rcx      # 0x40b8
movl 0x8(%rcx), %ecx
shll $0xa, %ecx
addq 0x2992(%rip), %rcx      # 0x40a8
movzwl 0x58(%rax), %edi
movl %esi, 0x10(%rsp)
imull %esi, %edi
addq %rcx, %rdi
movq %rdi, 0x38(%rsp)
callq 0x126e
cmpb $0x64, %al
jne 0x197f
xorl %ebx, %ebx
movl 0x10(%rsp), %esi
movq 0x38(%rsp), %rax
cmpl $0x0, 0x28(%rax,%rbx,4)
je 0x1983
xorl %r13d, %r13d
movq %rbx, 0x40(%rsp)
cmpl $0x3ff, %r13d           # imm = 0x3FF
ja 0x1977
movl %r14d, 0xc(%rsp)
movq 0x293b(%rip), %rax      # 0x40a8
movq 0x38(%rsp), %rcx
movl 0x28(%rcx,%rbx,4), %esi
shll $0xa, %esi
addq %rax, %rsi
movl %r13d, 0x14(%rsp)
movl %r13d, %edi
movzbl 0x7(%rdi,%rsi), %edx
movl %edx, %ecx
shll $0x3, %ecx
movabsq $0x6c3f3f3f3f64663f, %rbx # imm = 0x6C3F3F3F3F64663F
shrq %cl, %rbx
cmpb $0x8, %dl
pushq $0x3f
popq %rcx
cmovael %ecx, %ebx
movq 0x290d(%rip), %rcx      # 0x40b8
movl 0x8(%rcx), %ecx
shll $0xa, %ecx
addq %rax, %rcx
movq 0x28f5(%rip), %rax      # 0x40b0
movzwl 0x58(%rax), %r12d
movl (%rdi,%rsi), %r13d
leal -0x1(%r13), %r14d
imull %r14d, %r12d
addq %rcx, %r12
movq %rsi, 0x20(%rsp)
movq %rdi, 0x18(%rsp)
movzwl 0x4(%rdi,%rsi), %eax
movl %eax, 0x2c(%rsp)
movq %r12, %rdi
callq 0x126e
cmpb %al, %bl
je 0x1846
leaq 0x98d(%rip), %rdi       # 0x2182
movl %r13d, %esi
xorl %eax, %eax
callq 0x1080
movq %r12, %rdi
callq 0x126e
cmpb $0x6c, %al
movl 0xc(%rsp), %ecx
je 0x1824
movzbl %al, %eax
cmpl $0x66, %eax
je 0x1820
cmpl $0x64, %eax
jne 0x1828
movb $0x2, %al
jmp 0x182a
movb $0x1, %al
jmp 0x182a
movb $0x7, %al
jmp 0x182a
xorl %eax, %eax
incl %ecx
movl %ecx, 0xc(%rsp)
movq 0x20(%rsp), %rcx
movq 0x18(%rsp), %rdx
movb %al, 0x7(%rcx,%rdx)
movl (%rcx,%rdx), %r13d
leal -0x1(%r13), %r14d
movl %r14d, %eax
cltd
idivl %ebp
cltq
movq 0x30(%rsp), %rcx
movzbl (%rcx,%rax), %eax
andl $0x7, %r14d
btl %r14d, %eax
jae 0x186b
pushq $0x1
popq %rbx
movl 0xc(%rsp), %r14d
jmp 0x18c1
movl 0xc(%rsp), %r14d
incl %r14d
leaq 0x937(%rip), %rdi       # 0x21b1
movl %r13d, %esi
xorl %eax, %eax
movq %rcx, %r13
callq 0x1080
movq 0x20(%rsp), %rax
movq 0x18(%rsp), %rcx
movl (%rax,%rcx), %eax
decl %eax
movl %eax, %ecx
andb $0x7, %cl
pushq $0x1
popq %rbx
movl %ebx, %esi
shll %cl, %esi
cltd
idivl %ebp
cltq
xorb %sil, (%r13,%rax)
movq 0x27fd(%rip), %rax      # 0x40b0
movq 0x27fe(%rip), %rcx      # 0x40b8
decl 0x10(%rax)
decw 0xe(%rcx)
movl 0x14(%rsp), %r13d
cmpl $0x0, 0x14(%r12)
je 0x18f2
incl %r14d
movq 0x20(%rsp), %rax
movq 0x18(%rsp), %rcx
movl (%rax,%rcx), %esi
leaq 0x8f2(%rip), %rdi       # 0x21d7
xorl %eax, %eax
callq 0x1080
andl $0x0, 0x14(%r12)
addl 0x2c(%rsp), %r13d
addq $0x28, %r12
xorl %esi, %esi
movl (%r12), %edi
testl %edi, %edi
je 0x1947
decl %edi
movl %edi, %eax
cltd
idivl %ebp
movl %edi, %ecx
andb $0x7, %cl
movl %ebx, %edx
shll %cl, %edx
cltq
movzbl (%r15,%rax), %ecx
andl $0x7, %edi
btl %edi, %ecx
jb 0x1941
xorb %cl, %dl
movb %dl, (%r15,%rax)
movq 0x277f(%rip), %rax      # 0x40b0
movq 0x2780(%rip), %rcx      # 0x40b8
decl 0xc(%rax)
incl %esi
decw 0xc(%rcx)
addq $0x4, %r12
jmp 0x18fd
testl %esi, %esi
movq 0x40(%rsp), %rbx
jle 0x1754
incl %r14d
movq 0x20(%rsp), %rax
movq 0x18(%rsp), %rcx
movl (%rax,%rcx), %edx
leaq 0x898(%rip), %rdi       # 0x2203
xorl %eax, %eax
callq 0x1080
jmp 0x1754
incq %rbx
jmp 0x1738
movl 0x10(%rsp), %esi
incl %esi
jmp 0x16bd
testl %r14d, %r14d
jle 0x19a2
leaq 0x8b3(%rip), %rdi       # 0x2249
movl %r14d, %esi
xorl %eax, %eax
callq 0x1080
jmp 0x19ae
leaq 0x8ca(%rip), %rdi       # 0x2273
callq 0x1060
xorl %eax, %eax
addq $0x48, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
movq 0x2632(%rip), %rax      # 0x3ff8
movq (%rax), %rdi
movq (%rbx), %rdx
leaq 0x647(%rip), %rsi       # 0x201a
xorl %eax, %eax
callq 0x10b0
jmp 0x1a08
movq 0x2615(%rip), %rax      # 0x3ff8
movq (%rax), %rdi
movq 0x8(%rbx), %rdx
leaq 0x63b(%rip), %rsi       # 0x202c
xorl %eax, %eax
callq 0x10b0
pushq $0x2
jmp 0x1a0a
leaq 0x644(%rip), %rdi       # 0x2047
callq 0x10e0
pushq $0x1
popq %rdi
callq 0x10f0