// File: /workspace/github_c_makefile_star2_O0/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
movq %rsp, %rbp
subq $0x70, %rsp
movl $0x0, -0x4(%rbp)
movl %edi, -0x8(%rbp)
movq %rsi, -0x10(%rbp)
cmpl $0x2, -0x8(%rbp)
je 0x1785
movq 0x2895(%rip), %rax      # 0x3ff8
movq (%rax), %rdi
movq -0x10(%rbp), %rax
movq (%rax), %rdx
leaq 0x8a6(%rip), %rsi       # 0x201a
movb $0x0, %al
callq 0x10a0
movl $0x1, %edi
callq 0x10e0
movq -0x10(%rbp), %rax
movq 0x8(%rax), %rdi
movl $0x2, %esi
movb $0x0, %al
callq 0x10c0
movl %eax, -0x14(%rbp)
cmpl $0x0, -0x14(%rbp)
jne 0x17cc
movq 0x284f(%rip), %rax      # 0x3ff8
movq (%rax), %rdi
movq -0x10(%rbp), %rax
movq 0x8(%rax), %rdx
leaq 0x871(%rip), %rsi       # 0x202c
movb $0x0, %al
callq 0x10a0
movl $0x2, %edi
callq 0x10e0
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 0x1060
movq %rax, 0x28a5(%rip)      # 0x4098
movq $-0x1, %rax
cmpq %rax, 0x2897(%rip)      # 0x4098
jne 0x1819
leaq 0x83d(%rip), %rdi       # 0x2047
callq 0x10d0
movl $0x1, %edi
callq 0x10e0
movq 0x2878(%rip), %rax      # 0x4098
addq $0x400, %rax            # imm = 0x400
movq %rax, 0x2873(%rip)      # 0x40a0
movq 0x2864(%rip), %rax      # 0x4098
addq $0x800, %rax            # imm = 0x800
movq %rax, 0x2867(%rip)      # 0x40a8
movl $0x0, -0x18(%rbp)
movq 0x2849(%rip), %rax      # 0x4098
movq 0x2852(%rip), %rcx      # 0x40a8
movl (%rcx), %ecx
shll $0xa, %ecx
movl %ecx, %ecx
addq %rcx, %rax
movq %rax, -0x20(%rbp)
movq 0x282d(%rip), %rax      # 0x4098
movq 0x2836(%rip), %rcx      # 0x40a8
movl 0x4(%rcx), %ecx
shll $0xa, %ecx
movl %ecx, %ecx
addq %rcx, %rax
movq %rax, -0x28(%rbp)
movq 0x2818(%rip), %rax      # 0x40a0
movl 0x4(%rax), %eax
movl %eax, -0x2c(%rbp)
movl $0x0, -0x34(%rbp)
movl -0x34(%rbp), %eax
movq 0x2801(%rip), %rcx      # 0x40a0
cmpl 0x4(%rcx), %eax
jae 0x18cb
movl -0x34(%rbp), %edi
movq -0x20(%rbp), %rsi
callq 0x1200
cmpl $0x0, %eax
je 0x18be
movl -0x2c(%rbp), %eax
addl $-0x1, %eax
movl %eax, -0x2c(%rbp)
jmp 0x18c0
movl -0x34(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x34(%rbp)
jmp 0x1895
movl -0x2c(%rbp), %eax
movq 0x27cb(%rip), %rcx      # 0x40a0
cmpl 0xc(%rcx), %eax
je 0x1918
movq 0x27bf(%rip), %rax      # 0x40a0
movl 0xc(%rax), %eax
subl -0x2c(%rbp), %eax
movl %eax, %ecx
negl %ecx
cmovnsl %ecx, %eax
movl %eax, -0x30(%rbp)
movl -0x30(%rbp), %esi
leaq 0x751(%rip), %rdi       # 0x204c
movb $0x0, %al
callq 0x1070
movl -0x2c(%rbp), %ecx
movq 0x2794(%rip), %rax      # 0x40a0
movl %ecx, 0xc(%rax)
movl -0x30(%rbp), %eax
addl -0x18(%rbp), %eax
movl %eax, -0x18(%rbp)
movl -0x2c(%rbp), %eax
movq 0x2786(%rip), %rcx      # 0x40a8
movzwl 0xc(%rcx), %ecx
cmpl %ecx, %eax
je 0x196d
movq 0x2777(%rip), %rax      # 0x40a8
movzwl 0xc(%rax), %eax
subl -0x2c(%rbp), %eax
movl %eax, %ecx
negl %ecx
cmovnsl %ecx, %eax
movl %eax, -0x30(%rbp)
movl -0x30(%rbp), %esi
leaq 0x74d(%rip), %rdi       # 0x2099
movb $0x0, %al
callq 0x1070
movl -0x2c(%rbp), %eax
movw %ax, %cx
movq 0x2748(%rip), %rax      # 0x40a8
movw %cx, 0xc(%rax)
movl -0x30(%rbp), %eax
addl -0x18(%rbp), %eax
movl %eax, -0x18(%rbp)
movq 0x272c(%rip), %rax      # 0x40a0
movl (%rax), %eax
movl %eax, -0x2c(%rbp)
movl $0x0, -0x34(%rbp)
movl -0x34(%rbp), %eax
movq 0x2716(%rip), %rcx      # 0x40a0
cmpl (%rcx), %eax
jae 0x19b5
movl -0x34(%rbp), %edi
movq -0x28(%rbp), %rsi
callq 0x1200
cmpl $0x0, %eax
je 0x19a8
movl -0x2c(%rbp), %eax
addl $-0x1, %eax
movl %eax, -0x2c(%rbp)
jmp 0x19aa
movl -0x34(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x34(%rbp)
jmp 0x1980
movl -0x2c(%rbp), %eax
movq 0x26e1(%rip), %rcx      # 0x40a0
cmpl 0x10(%rcx), %eax
je 0x1a02
movq 0x26d5(%rip), %rax      # 0x40a0
movl 0x10(%rax), %eax
subl -0x2c(%rbp), %eax
movl %eax, %ecx
negl %ecx
cmovnsl %ecx, %eax
movl %eax, -0x30(%rbp)
movl -0x30(%rbp), %esi
leaq 0x702(%rip), %rdi       # 0x20e7
movb $0x0, %al
callq 0x1070
movl -0x2c(%rbp), %ecx
movq 0x26aa(%rip), %rax      # 0x40a0
movl %ecx, 0x10(%rax)
movl -0x30(%rbp), %eax
addl -0x18(%rbp), %eax
movl %eax, -0x18(%rbp)
movl -0x2c(%rbp), %eax
movq 0x269c(%rip), %rcx      # 0x40a8
movzwl 0xe(%rcx), %ecx
cmpl %ecx, %eax
je 0x1a57
movq 0x268d(%rip), %rax      # 0x40a8
movzwl 0xe(%rax), %eax
subl -0x2c(%rbp), %eax
movl %eax, %ecx
negl %ecx
cmovnsl %ecx, %eax
movl %eax, -0x30(%rbp)
movl -0x30(%rbp), %esi
leaq 0x6fe(%rip), %rdi       # 0x2134
movb $0x0, %al
callq 0x1070
movl -0x2c(%rbp), %eax
movw %ax, %cx
movq 0x265e(%rip), %rax      # 0x40a8
movw %cx, 0xe(%rax)
movl -0x30(%rbp), %eax
addl -0x18(%rbp), %eax
movl %eax, -0x18(%rbp)
movl $0x0, -0x34(%rbp)
movl -0x34(%rbp), %eax
movq 0x2638(%rip), %rcx      # 0x40a0
cmpl (%rcx), %eax
jae 0x1d3d
movl -0x34(%rbp), %edi
movq -0x28(%rbp), %rsi
callq 0x1200
cmpl $0x0, %eax
je 0x1a8d
cmpl $0x1, -0x34(%rbp)
je 0x1a97
cmpl $0xb, -0x34(%rbp)
jge 0x1a97
cmpl $0x1, -0x34(%rbp)
jne 0x1d2d
movq 0x25fa(%rip), %rax      # 0x4098
movq 0x2603(%rip), %rcx      # 0x40a8
movl 0x8(%rcx), %ecx
shll $0xa, %ecx
movl %ecx, %ecx
addq %rcx, %rax
movq 0x25e9(%rip), %rcx      # 0x40a0
movzwl 0x58(%rcx), %ecx
imull -0x34(%rbp), %ecx
movslq %ecx, %rcx
addq %rcx, %rax
movq %rax, -0x40(%rbp)
movq -0x40(%rbp), %rdi
callq 0x12e0
movzbl %al, %eax
cmpl $0x64, %eax
jne 0x1d2b
movl $0x0, -0x5c(%rbp)
movq -0x40(%rbp), %rax
movslq -0x5c(%rbp), %rcx
cmpl $0x0, 0x28(%rax,%rcx,4)
je 0x1d29
movl $0x0, -0x4c(%rbp)
cmpl $0x400, -0x4c(%rbp)     # imm = 0x400
jae 0x1d19
movq 0x2585(%rip), %rax      # 0x4098
movq -0x40(%rbp), %rcx
movslq -0x5c(%rbp), %rdx
movl 0x28(%rcx,%rdx,4), %ecx
shll $0xa, %ecx
movl %ecx, %ecx
addq %rcx, %rax
movl -0x4c(%rbp), %ecx
addq %rcx, %rax
movq %rax, -0x58(%rbp)
movq -0x58(%rbp), %rax
movzbl 0x7(%rax), %edi
callq 0x12a0
movb %al, -0x4d(%rbp)
movq 0x2550(%rip), %rax      # 0x4098
movq 0x2559(%rip), %rcx      # 0x40a8
movl 0x8(%rcx), %ecx
shll $0xa, %ecx
movl %ecx, %ecx
addq %rcx, %rax
movq 0x253f(%rip), %rcx      # 0x40a0
movzwl 0x58(%rcx), %ecx
movq -0x58(%rbp), %rdx
movl (%rdx), %edx
subl $0x1, %edx
imull %edx, %ecx
movl %ecx, %ecx
addq %rcx, %rax
movq %rax, -0x48(%rbp)
movq -0x58(%rbp), %rax
movzwl 0x4(%rax), %eax
addl -0x4c(%rbp), %eax
movl %eax, -0x4c(%rbp)
movzbl -0x4d(%rbp), %eax
movl %eax, -0x68(%rbp)
movq -0x48(%rbp), %rdi
callq 0x12e0
movb %al, %cl
movl -0x68(%rbp), %eax
movzbl %cl, %ecx
cmpl %ecx, %eax
je 0x1bde
movq -0x58(%rbp), %rax
movl (%rax), %esi
leaq 0x5d1(%rip), %rdi       # 0x2182
movb $0x0, %al
callq 0x1070
movl -0x18(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x18(%rbp)
movq -0x58(%rbp), %rax
movq %rax, -0x70(%rbp)
movq -0x48(%rbp), %rdi
callq 0x12e0
movq -0x70(%rbp), %rdi
movzbl %al, %esi
callq 0x1340
movq -0x58(%rbp), %rax
movl (%rax), %edi
subl $0x1, %edi
movq -0x28(%rbp), %rsi
callq 0x1200
cmpl $0x0, %eax
jne 0x1c3c
movl -0x18(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x18(%rbp)
movq -0x58(%rbp), %rax
movl (%rax), %esi
leaq 0x5a6(%rip), %rdi       # 0x21b1
movb $0x0, %al
callq 0x1070
movq -0x58(%rbp), %rax
movl (%rax), %edi
subl $0x1, %edi
movq -0x28(%rbp), %rsi
callq 0x1250
movq 0x2475(%rip), %rsi      # 0x40a0
movq 0x2476(%rip), %rdx      # 0x40a8
movl $0xffffffff, %edi       # imm = 0xFFFFFFFF
callq 0x1710
movq -0x48(%rbp), %rax
cmpl $0x0, 0x14(%rax)
je 0x1c6e
movl -0x18(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x18(%rbp)
movq -0x58(%rbp), %rax
movl (%rax), %esi
leaq 0x57b(%rip), %rdi       # 0x21d7
movb $0x0, %al
callq 0x1070
movq -0x48(%rbp), %rax
movl $0x0, 0x14(%rax)
movl $0x0, -0x64(%rbp)
movl $0x0, -0x60(%rbp)
movq -0x48(%rbp), %rax
movslq -0x60(%rbp), %rcx
cmpl $0x0, 0x28(%rax,%rcx,4)
je 0x1cee
movq -0x48(%rbp), %rax
movslq -0x60(%rbp), %rcx
movl 0x28(%rax,%rcx,4), %edi
subl $0x1, %edi
movq -0x20(%rbp), %rsi
callq 0x1200
cmpl $0x0, %eax
jne 0x1ce1
movl -0x64(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x64(%rbp)
movq -0x48(%rbp), %rax
movslq -0x60(%rbp), %rcx
movl 0x28(%rax,%rcx,4), %edi
subl $0x1, %edi
movq -0x20(%rbp), %rsi
callq 0x1250
movq 0x23d0(%rip), %rsi      # 0x40a0
movq 0x23d1(%rip), %rdx      # 0x40a8
movl $0xffffffff, %edi       # imm = 0xFFFFFFFF
callq 0x16e0
jmp 0x1ce3
movl -0x60(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x60(%rbp)
jmp 0x1c7c
cmpl $0x0, -0x64(%rbp)
jle 0x1d14
movl -0x18(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x18(%rbp)
movl -0x64(%rbp), %esi
movq -0x58(%rbp), %rax
movl (%rax), %edx
leaq 0x4f6(%rip), %rdi       # 0x2203
movb $0x0, %al
callq 0x1070
jmp 0x1aff
jmp 0x1d1b
movl -0x5c(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x5c(%rbp)
jmp 0x1ae5
jmp 0x1d2b
jmp 0x1d2d
jmp 0x1d2f
movl -0x34(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x34(%rbp)
jmp 0x1a5e
cmpl $0x0, -0x18(%rbp)
jle 0x1d56
movl -0x18(%rbp), %esi
leaq 0x4fc(%rip), %rdi       # 0x2249
movb $0x0, %al
callq 0x1070
jmp 0x1d64
leaq 0x516(%rip), %rdi       # 0x2273
movb $0x0, %al
callq 0x1070
xorl %eax, %eax
addq $0x70, %rsp
popq %rbp
retq