// File: /workspace/github_c_makefile_star2_O1/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 0x1ae7
movq 0x8(%rbx), %rdi
movl $0x2, %esi
xorl %eax, %eax
callq 0x10d0
testl %eax, %eax
je 0x1aef
movl $0x20000, %esi          # imm = 0x20000
xorl %edi, %edi
movl $0x3, %edx
movl $0x1, %ecx
movl %eax, %r8d
xorl %r9d, %r9d
callq 0x1070
movq %rax, 0x2ad8(%rip)      # 0x40a8
cmpq $-0x1, %rax
je 0x1afb
movq %rax, %r15
addq $0x400, %rax            # imm = 0x400
movq %rax, 0x2ac6(%rip)      # 0x40b0
leaq 0x800(%r15), %rax
movq %rax, 0x2ac0(%rip)      # 0x40b8
movl 0x800(%r15), %r14d
shll $0xa, %r14d
addq %r15, %r14
movl 0x804(%r15), %ebx
movl 0x404(%r15), %eax
testl %eax, %eax
je 0x1639
xorl %ecx, %ecx
movl %eax, %ebp
movl %ecx, %edx
shrl $0x3, %edx
movzbl (%r14,%rdx), %edx
movl %ecx, %esi
andl $0x7, %esi
btl %esi, %edx
sbbl $0x0, %ebp
incl %ecx
cmpl %ecx, %eax
jne 0x161c
jmp 0x163b
movl %eax, %ebp
shll $0xa, %ebx
movl 0x40c(%r15), %eax
xorl %r13d, %r13d
subl %ebp, %eax
je 0x166e
movl %eax, %esi
negl %esi
cmovsl %eax, %esi
leaq 0x9f2(%rip), %rdi       # 0x204c
movl %esi, %r13d
xorl %eax, %eax
callq 0x1080
movq 0x2a45(%rip), %rax      # 0x40b0
movl %ebp, 0xc(%rax)
movq 0x2a43(%rip), %rax      # 0x40b8
movzwl 0xc(%rax), %eax
subl %ebp, %eax
je 0x16ac
movq %r15, %r12
movl %eax, %r15d
negl %r15d
cmovsl %eax, %r15d
leaq 0xa08(%rip), %rdi       # 0x2099
movl %r15d, %esi
xorl %eax, %eax
callq 0x1080
movq 0x2a16(%rip), %rax      # 0x40b8
movw %bp, 0xc(%rax)
addl %r15d, %r13d
movq %r12, %r15
addq %rbx, %r15
movq 0x29fa(%rip), %rax      # 0x40b0
movl (%rax), %ecx
testl %ecx, %ecx
je 0x16dd
xorl %edx, %edx
movl %ecx, %ebx
movl %edx, %esi
shrl $0x3, %esi
movzbl (%r15,%rsi), %esi
movl %edx, %edi
andl $0x7, %edi
btl %edi, %esi
sbbl $0x0, %ebx
incl %edx
cmpl %edx, %ecx
jne 0x16c0
jmp 0x16df
movl %ecx, %ebx
movl 0x10(%rax), %eax
subl %ebx, %eax
movq %r15, (%rsp)
je 0x1712
movl %eax, %r15d
negl %r15d
cmovsl %eax, %r15d
leaq 0x9ec(%rip), %rdi       # 0x20e7
movl %r15d, %esi
xorl %eax, %eax
callq 0x1080
movq 0x29a4(%rip), %rax      # 0x40b0
movl %ebx, 0x10(%rax)
addl %r15d, %r13d
movq 0x299f(%rip), %rax      # 0x40b8
movzwl 0xe(%rax), %eax
subl %ebx, %eax
jne 0x172a
movq (%rsp), %rdx
movl %r13d, %ebx
jmp 0x175a
movl %eax, %r15d
negl %r15d
cmovsl %eax, %r15d
leaq 0x9f9(%rip), %rdi       # 0x2134
movl %r15d, %esi
xorl %eax, %eax
callq 0x1080
movq 0x296c(%rip), %rax      # 0x40b8
movw %bx, 0xe(%rax)
movl %r13d, %ebx
addl %r15d, %ebx
movq (%rsp), %rdx
movq 0x294f(%rip), %rax      # 0x40b0
cmpl $0x0, (%rax)
je 0x1ab4
xorl %r15d, %r15d
movl %r15d, %ecx
shrl $0x3, %ecx
movzbl (%rdx,%rcx), %ecx
movl %r15d, %edx
andl $0x7, %edx
btl %edx, %ecx
jae 0x1799
cmpl $0x1, %r15d
sete %cl
cmpl $0xb, %r15d
setae %dl
orb %cl, %dl
jne 0x17a3
jmp 0x1a9d
cmpl $0x1, %r15d
jne 0x1a9d
movq 0x290e(%rip), %rcx      # 0x40b8
movl 0x8(%rcx), %edx
shll $0xa, %edx
addq 0x28f1(%rip), %rdx      # 0x40a8
movzwl 0x58(%rax), %ecx
movl %r15d, %eax
imulq %rcx, %rax
movzwl (%rax,%rdx), %ecx
andl $0xf000, %ecx           # imm = 0xF000
cmpl $0x4000, %ecx           # imm = 0x4000
jne 0x1a9d
addq %rax, %rdx
cmpl $0x0, 0x28(%rdx)
je 0x1a9d
addq $0x28, %rdx
movq $0x0, 0x20(%rsp)
movq %rdx, 0x30(%rsp)
movl %r15d, 0x14(%rsp)
movq %rdx, 0x28(%rsp)
xorl %ecx, %ecx
movq 0x289e(%rip), %r8       # 0x40a8
movq 0x30(%rsp), %rax
movl (%rax), %r13d
shll $0xa, %r13d
addq %r8, %r13
movl %ecx, 0x1c(%rsp)
movl %ecx, %edi
movzbl 0x7(%rdi,%r13), %edx
movl %edx, %ecx
shll $0x3, %ecx
movabsq $0x6c3f3f3f3f64663f, %rax # imm = 0x6C3F3F3F3F64663F
shrq %cl, %rax
cmpb $0x8, %dl
movl $0x3f, %ecx
cmovael %ecx, %eax
movq 0x286f(%rip), %rcx      # 0x40b8
movl 0x8(%rcx), %edx
shll $0xa, %edx
leaq (%r8,%rdx), %r12
movq 0x2856(%rip), %rcx      # 0x40b0
movzwl 0x58(%rcx), %ecx
movl (%rdi,%r13), %esi
leal -0x1(%rsi), %ebp
imull %ecx, %ebp
movzwl (%rbp,%r12), %ecx
andl $0xf000, %ecx           # imm = 0xF000
cmpl $0xa000, %ecx           # imm = 0xA000
movq %r8, 0x40(%rsp)
movq %rdx, 0x38(%rsp)
je 0x189e
cmpl $0x8000, %ecx           # imm = 0x8000
je 0x189a
cmpl $0x4000, %ecx           # imm = 0x4000
jne 0x18a2
movb $0x64, %cl
jmp 0x18a4
movb $0x66, %cl
jmp 0x18a4
movb $0x6c, %cl
jmp 0x18a4
movb $0x3f, %cl
movzwl 0x4(%rdi,%r13), %r15d
cmpb %cl, %al
movq %rdi, 0x8(%rsp)
movl %r15d, 0x18(%rsp)
jne 0x18bd
movl %ebx, %r15d
jmp 0x192b
leaq 0x8be(%rip), %rdi       # 0x2182
xorl %eax, %eax
callq 0x1080
movzwl (%r12,%rbp), %eax
andl $0xf000, %eax           # imm = 0xF000
cmpl $0xa000, %eax           # imm = 0xA000
je 0x18f7
cmpl $0x8000, %eax           # imm = 0x8000
movq 0x8(%rsp), %rdi
je 0x18f3
cmpl $0x4000, %eax           # imm = 0x4000
jne 0x1900
movb $0x64, %al
jmp 0x1902
movb $0x66, %al
jmp 0x1902
movb $0x6c, %al
movq 0x8(%rsp), %rdi
jmp 0x1902
movb $0x3f, %al
cmpb $0x6c, %al
je 0x191b
movzbl %al, %eax
cmpl $0x66, %eax
je 0x1917
cmpl $0x64, %eax
jne 0x191f
movb $0x2, %al
jmp 0x1921
movb $0x1, %al
jmp 0x1921
movb $0x7, %al
jmp 0x1921
xorl %eax, %eax
incl %ebx
movl %ebx, %r15d
movb %al, 0x7(%r13,%rdi)
movl (%r13,%rdi), %esi
leal -0x1(%rsi), %eax
leal 0x6(%rsi), %ecx
testl %eax, %eax
cmovnsl %eax, %ecx
sarl $0x3, %ecx
movslq %ecx, %rcx
movq (%rsp), %rbx
movzbl (%rbx,%rcx), %ecx
andl $0x7, %eax
btl %eax, %ecx
jb 0x19a1
incl %r15d
leaq 0x856(%rip), %rdi       # 0x21b1
xorl %eax, %eax
callq 0x1080
movq 0x8(%rsp), %rdi
movl (%r13,%rdi), %eax
leal -0x1(%rax), %edx
movl %edx, %ecx
andb $0x7, %cl
movl $0x1, %esi
shll %cl, %esi
addl $0x6, %eax
testl %edx, %edx
cmovnsl %edx, %eax
sarl $0x3, %eax
cltq
xorb %sil, (%rbx,%rax)
movq 0x271d(%rip), %rax      # 0x40b0
movq 0x271e(%rip), %rcx      # 0x40b8
decl 0x10(%rax)
decw 0xe(%rcx)
cmpl $0x0, 0x14(%r12,%rbp)
je 0x19cc
movl %r15d, %ebx
incl %ebx
movl (%r13,%rdi), %esi
leaq 0x81d(%rip), %rdi       # 0x21d7
xorl %eax, %eax
callq 0x1080
movl $0x0, 0x14(%r12,%rbp)
jmp 0x19cf
movl %r15d, %ebx
movl 0x28(%r12,%rbp), %edx
testl %edx, %edx
movl 0x14(%rsp), %r15d
je 0x1a41
addq 0x38(%rsp), %rbp
movq 0x40(%rsp), %rax
addq %rbp, %rax
addq $0x2c, %rax
xorl %esi, %esi
leal -0x1(%rdx), %ecx
addl $0x6, %edx
testl %ecx, %ecx
cmovnsl %ecx, %edx
sarl $0x3, %edx
movslq %edx, %rdx
movzbl (%r14,%rdx), %edi
andl $0x7, %ecx
btl %ecx, %edi
jb 0x1a35
movl $0x1, %r8d
shll %cl, %r8d
xorb %dil, %r8b
movb %r8b, (%r14,%rdx)
movq 0x268b(%rip), %rcx      # 0x40b0
movq 0x268c(%rip), %rdx      # 0x40b8
decl 0xc(%rcx)
incl %esi
decw 0xc(%rdx)
movl (%rax), %edx
addq $0x4, %rax
testl %edx, %edx
jne 0x19f0
jmp 0x1a43
xorl %esi, %esi
testl %esi, %esi
jle 0x1a61
incl %ebx
movq 0x8(%rsp), %rax
movl (%r13,%rax), %edx
leaq 0x7a9(%rip), %rdi       # 0x2203
xorl %eax, %eax
callq 0x1080
movq 0x28(%rsp), %rdx
movl 0x1c(%rsp), %ecx
addl 0x18(%rsp), %ecx
cmpl $0x400, %ecx            # imm = 0x400
jb 0x1803
movq 0x20(%rsp), %rax
leaq (%rdx,%rax,4), %rcx
addq $0x4, %rcx
incq %rax
movq %rax, 0x20(%rsp)
movq %rcx, 0x30(%rsp)
cmpl $0x0, (%rcx)
jne 0x1801
incl %r15d
movq 0x2609(%rip), %rax      # 0x40b0
cmpl (%rax), %r15d
movq (%rsp), %rdx
jb 0x176d
testl %ebx, %ebx
jle 0x1aca
leaq 0x78a(%rip), %rdi       # 0x2249
movl %ebx, %esi
xorl %eax, %eax
callq 0x1080
jmp 0x1ad6
leaq 0x7a2(%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 %rbx, %rdi
callq 0x1155
addq $0x8, %rbx
movq %rbx, %rdi
callq 0x1191
callq 0x117c