// File: /workspace/github_c_makefile_star2_O1/kevinp89[P]Operating-System-EXT2-file-system-with-commands/ext2_mkdir.c
// Function: main
int main(int argc, char **argv) {
	// We need two arguments, so argc must be 3.
	if (argc != 3) {
		fprintf(stderr, "Usage: %s [disk] [path]\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);
	// Getting the parent inode index
	int parent_inode_index = check_parent(disk, argv[2]);
	if (parent_inode_index == -1) { // Directory not found.
		fprintf(stderr, "Directory does not exist.");
		exit(ENOENT);
	}
	// Get new dir name
	int i;
	int dir_len = 0;
	if (argv[2][strlen(argv[2]) -1] == '/') argv[2][strlen(argv[2])-1] = '\0';
	for (i = strlen(argv[2]); argv[2][i] != '/'; i--) {
		dir_len++;
		if (dir_len > 255) {
			fprintf(stderr, "Directory name too large.");
			exit(1);
		}
	}
	char new_dir[dir_len];
	strcpy(new_dir, argv[2] + i + 1);
	// Check that there aren't any files with that name.
	struct ext2_inode *parent = (struct ext2_inode *)((disk + 1024 * desc->bg_inode_table) +
		   											(sb->s_inode_size * parent_inode_index));
	if (search_directories(disk, parent, new_dir, 0) != -1) {
		fprintf(stderr, "Directory name already in use.\n");
		exit(EEXIST);
	}
	// Finding a free inode and allocating (set to 1)
	unsigned char *imap = (unsigned char *)(disk + 1024 * desc->bg_inode_bitmap);
	int inode;
	for (inode = 11; inode < sb->s_inodes_count; inode++) {
		if (check_node(inode, imap) == 0) {
			break;
		}
	}
	if (inode == sb->s_inodes_count) { // Maximum reached, no more inodes
		fprintf(stderr, "No more inodes available.");
		exit(1);
	}
	// Finding a free block and allocating (set to 1)
	unsigned char *bmap = (unsigned char *)(disk + 1024 * desc->bg_block_bitmap);
	int bnode;
	for (bnode = 22; bnode < sb->s_blocks_count; bnode++) {
		if (check_node(bnode, bmap) == 0) {
			break;
		}
	}
	if (bnode == sb->s_blocks_count) {
		fprintf(stderr, "No more blocks available.");
		exit(1);
	}
	// Actual allocation.
	set_node(inode, imap);
	set_node(bnode, bmap);
	adjust_free_blocks(-1, sb, desc);
	adjust_free_inodes(-1, sb, desc);
	// Writing data to the ext2_inode struct in the inode index.
	struct ext2_inode *new_inode = (struct ext2_inode *)((disk + 1024 * desc->bg_inode_table)
														 + (sb->s_inode_size * (inode)));
	new_inode->i_mode = EXT2_S_IFDIR;
	new_inode->i_uid = 0;
	new_inode->i_size = 1024;
	new_inode->i_ctime = (unsigned int) time(0);
	new_inode->i_dtime = 0;
	new_inode->i_gid = 0;
	new_inode->i_blocks = 2;
	new_inode->osd1 = 0;
	new_inode->i_block[0] = bnode;
	new_inode->i_generation = 0;
	new_inode->i_file_acl = 0;
	new_inode->i_dir_acl = 0;
	new_inode->i_faddr = 0;
	new_inode->i_links_count = 2; // Itself and from parent.
	parent->i_links_count++; // Parent gets one more link from parent dir in new directory.
	// Adding self and parent directories to allocated block.
	struct ext2_dir_entry *self = (struct ext2_dir_entry *)(disk + (1024 * bnode));
	self->inode = inode + 1; // the variable inode is the index, not actual inode.
	self->rec_len = 12; // self rec-len is always 12
	self->name_len = 1; // length of . is 1
	self->file_type = EXT2_FT_DIR;
	strncpy(self->name, ".", 1);
	struct ext2_dir_entry *par = (struct ext2_dir_entry *)(disk + (1024 * bnode) + self->rec_len);
	par->inode = parent_inode_index + 1;
	par->rec_len = 1024 - 12; // Fill in the rest of the 1024 bytes of space
	par->name_len = 2; // length of .. is 2
	par->file_type = EXT2_FT_DIR;
	strncpy(par->name, "..", 2);
	// Adding new inode/directory entry into the parent block.
	int par_block_index = 0;
	for (i = 0; parent->i_block[i] != 0; i++) {
		par_block_index = parent->i_block[i];
	}
	int total_rec_len;
	struct ext2_dir_entry *curdir = (struct ext2_dir_entry *)(disk + (1024 * par_block_index));
	// When this for loop exits, curdir should be the last directory 
	for (total_rec_len = 0; total_rec_len + curdir->rec_len < 1024; ) {
		total_rec_len += curdir->rec_len;
		curdir = (struct ext2_dir_entry *)(disk + (1024 * par_block_index) + total_rec_len);
	}
	// Check there's enough space to place the new dir entry in the current block
	// Reuse total_rec_len to find remaining bytes if curdir was reduced to proper size
	struct ext2_dir_entry *newdir;
	int remaining_rec_len = sizeof(curdir) + curdir->name_len; // Actual size of curdir
	remaining_rec_len += 4 - (remaining_rec_len % 4); // Add padding
	remaining_rec_len = 1024 - remaining_rec_len - total_rec_len; // Remaining space
	if (remaining_rec_len < (8 + strlen(new_dir))) { // Not enough space
		// Allocate new block
		int newblock;
		for (newblock = 22; newblock < sb->s_blocks_count; newblock++) {
			if (check_node(newblock, bmap) == 0) {
				break;
			}
		}
		if (newblock == sb->s_blocks_count) {
			fprintf(stderr, "No more blocks available.");
			exit(1);
		}
		set_node(newblock, bmap);
		adjust_free_blocks(-1, sb, desc);
		parent->i_block[i] = newblock; // i should still hold the first block space unused by parent
		parent->i_blocks += 2; // One more block being added
		newdir = (struct ext2_dir_entry *)(disk + (1024 * newblock));
		newdir->rec_len = 1024; // Takes up the whole of the new block.
	} else { // Enough space
		// Change curdir, add new directory
		curdir->rec_len = sizeof(curdir) + curdir->name_len;
		curdir->rec_len += 4 - (curdir->rec_len % 4);
		total_rec_len += curdir->rec_len;
		newdir = (struct ext2_dir_entry *)(disk + (1024 * par_block_index) + total_rec_len);
		newdir->rec_len = 1024 - total_rec_len; // Takes up the rest of the block.
	}
	newdir->inode = inode + 1;
	newdir->name_len = strlen(new_dir);
	newdir->file_type = EXT2_FT_DIR;
	strncpy(newdir->name, new_dir, newdir->name_len);

	// Done with the directories, minor upkeep
	desc->bg_used_dirs_count++;
	return 0;
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x28, %rsp
movq %rsi, %rbx
cmpl $0x3, %edi
jne 0x1ab8
movq 0x8(%rbx), %rdi
movl $0x2, %esi
xorl %eax, %eax
callq 0x10d0
testl %eax, %eax
je 0x1ac0
movl $0x20000, %esi          # imm = 0x20000
xorl %edi, %edi
movl $0x3, %edx
movl $0x1, %ecx
movl %eax, %r8d
xorl %r9d, %r9d
callq 0x1070
movq %rax, 0x29f5(%rip)      # 0x40a8
cmpq $-0x1, %rax
je 0x1acc
leaq 0x400(%rax), %rcx
movq %rcx, 0x29e5(%rip)      # 0x40b0
movq %rax, %rcx
addq $0x800, %rcx            # imm = 0x800
movq %rcx, 0x29dc(%rip)      # 0x40b8
movq 0x10(%rbx), %rsi
movq %rax, %rdi
callq 0x151a
cmpl $-0x1, %eax
je 0x1ad1
movl %eax, %r13d
movq 0x10(%rbx), %r14
movq %r14, %rdi
callq 0x1060
cmpb $0x2f, -0x1(%r14,%rax)
jne 0x170e
movb $0x0, -0x1(%r14,%rax)
movq 0x10(%rbx), %r14
movq %r14, %rdi
callq 0x1060
movslq %eax, %rcx
cmpb $0x2f, (%r14,%rcx)
jne 0x1728
xorl %eax, %eax
jmp 0x174a
movslq %eax, %rdx
xorl %eax, %eax
cmpl $0xff, %eax
je 0x1ab3
leaq -0x1(%rdx), %rcx
incq %rax
cmpb $0x2f, -0x1(%r14,%rdx)
movq %rcx, %rdx
jne 0x172d
movq %rsp, %r15
addq $0xf, %rax
andq $-0x10, %rax
subq %rax, %r15
movq %r15, %rsp
leaq (%r14,%rcx), %rsi
incq %rsi
movq %r15, %rdi
callq 0x1050
movq 0x2937(%rip), %r14      # 0x40a8
movq 0x2940(%rip), %rbx      # 0x40b8
movl 0x8(%rbx), %eax
shll $0xa, %eax
addq %r14, %rax
movq 0x2928(%rip), %r12      # 0x40b0
movzwl 0x58(%r12), %ecx
movl %r13d, -0x30(%rbp)
movslq %r13d, %rsi
imulq %rcx, %rsi
addq %rax, %rsi
movq %r14, %rdi
movq %rsi, -0x38(%rbp)
movq %r15, -0x40(%rbp)
movq %r15, %rdx
xorl %ecx, %ecx
callq 0x1432
cmpl $-0x1, %eax
jne 0x1ad6
movl 0x4(%rbx), %eax
shll $0xa, %eax
addq %r14, %rax
movl (%r12), %ecx
movl $0xb, %r13d
cmpl $0xc, %ecx
jb 0x17f2
movl %r13d, %edx
shrl $0x3, %edx
movzbl (%rax,%rdx), %edx
movl %r13d, %esi
andl $0x7, %esi
btl %esi, %edx
jae 0x17f2
incl %r13d
cmpl %r13d, %ecx
jne 0x17d2
movl %ecx, %r13d
cmpl %ecx, %r13d
je 0x1adb
movl (%rbx), %ecx
shll $0xa, %ecx
addq %rcx, %r14
movl 0x4(%r12), %ecx
movl $0x16, %ebx
cmpl $0x17, %ecx
jb 0x1833
movl $0x16, %ebx
movl %ebx, %edx
shrl $0x3, %edx
movzbl (%r14,%rdx), %edx
movl %ebx, %esi
andl $0x7, %esi
btl %esi, %edx
jae 0x1833
incl %ebx
cmpl %ebx, %ecx
jne 0x1817
movl %ecx, %ebx
cmpl %ecx, %ebx
je 0x1ae0
movl %r13d, %ecx
andb $0x7, %cl
movl $0x1, %edx
shll %cl, %edx
movl %r13d, %ecx
shrl $0x3, %ecx
xorb %dl, (%rax,%rcx)
movl $0x1, %eax
movl %ebx, %ecx
andb $0x7, %cl
shll %cl, %eax
movl %ebx, %ecx
shrl $0x3, %ecx
movq %r14, -0x50(%rbp)
xorb %al, (%r14,%rcx)
movq 0x283f(%rip), %rax      # 0x40b0
movq 0x2840(%rip), %rcx      # 0x40b8
decl 0xc(%rax)
decw 0xc(%rcx)
decl 0x10(%rax)
movl %r13d, %edx
decw 0xe(%rcx)
movl 0x8(%rcx), %r15d
shll $0xa, %r15d
addq 0x2810(%rip), %r15      # 0x40a8
movzwl 0x58(%rax), %r12d
imulq %rdx, %r12
movabsq $0x40000004000, %rax    # imm = 0x40000004000
movq %rax, (%r12,%r15)
xorl %r14d, %r14d
xorl %edi, %edi
callq 0x10b0
movl %eax, 0xc(%r12,%r15)
movabsq $0x2000000000000, %rax  # imm = 0x2000000000000
movq %rax, 0x14(%r12,%r15)
movl $0x2, 0x1c(%r12,%r15)
movl $0x0, 0x24(%r12,%r15)
movl %ebx, 0x28(%r12,%r15)
xorps %xmm0, %xmm0
movups %xmm0, 0x64(%r12,%r15)
movq -0x38(%rbp), %rcx
incw 0x1a(%rcx)
movq 0x27ac(%rip), %rax      # 0x40a8
shll $0xa, %ebx
incl %r13d
movl %r13d, (%rax,%rbx)
movl $0x201000c, 0x4(%rax,%rbx) # imm = 0x201000C
movb $0x2e, 0x8(%rax,%rbx)
movq 0x278e(%rip), %rax      # 0x40a8
movl -0x30(%rbp), %edx
incl %edx
movl %edx, 0xc(%rax,%rbx)
movl $0x20203f4, 0x10(%rax,%rbx) # imm = 0x20203F4
movw $0x2e2e, 0x14(%rax,%rbx) # imm = 0x2E2E
leaq 0x28(%rcx), %rbx
movl %r14d, %eax
movl (%rbx), %r14d
addq $0x4, %rbx
testl %r14d, %r14d
jne 0x1936
movq 0x275c(%rip), %rcx      # 0x40a8
cltq
shlq $0xa, %rax
leaq (%rcx,%rax), %r14
movzwl 0x4(%rcx,%rax), %eax
xorl %r15d, %r15d
movq %r14, %r12
cmpl $0x3ff, %eax            # imm = 0x3FF
ja 0x1981
movl %eax, %r15d
movl %eax, %r12d
movzwl 0x4(%r14,%r12), %eax
addl %r15d, %eax
cmpl $0x400, %eax            # imm = 0x400
jb 0x1968
addq %r14, %r12
movzbl 0x6(%r12), %eax
addq $0x8, %rax
movq %rax, -0x48(%rbp)
andl $-0x4, %eax
addl %r15d, %eax
movl $0x3fc, %ecx            # imm = 0x3FC
subl %eax, %ecx
movslq %ecx, %rax
movq %rax, -0x30(%rbp)
movq -0x40(%rbp), %rdi
callq 0x1060
addq $0x8, %rax
cmpq -0x30(%rbp), %rax
jbe 0x1a4a
movq 0x26ef(%rip), %rax      # 0x40b0
movl 0x4(%rax), %eax
movl $0x16, %r14d
cmpl $0x17, %eax
movq -0x50(%rbp), %rsi
jb 0x19f9
movl $0x16, %r14d
movl %r14d, %ecx
shrl $0x3, %ecx
movzbl (%rsi,%rcx), %ecx
movl %r14d, %edx
andl $0x7, %edx
btl %edx, %ecx
jae 0x19f9
incl %r14d
cmpl %r14d, %eax
jne 0x19d9
movl %eax, %r14d
cmpl %eax, %r14d
je 0x1ae5
movl %r14d, %ecx
andb $0x7, %cl
movl $0x1, %eax
shll %cl, %eax
movl %r14d, %ecx
shrl $0x3, %ecx
xorb %al, (%rsi,%rcx)
movq 0x2691(%rip), %rax      # 0x40b0
movq 0x2692(%rip), %rcx      # 0x40b8
decl 0xc(%rax)
decw 0xc(%rcx)
movl %r14d, -0x4(%rbx)
movq -0x38(%rbp), %rax
addl $0x2, 0x1c(%rax)
shll $0xa, %r14d
addq 0x2664(%rip), %r14      # 0x40a8
movw $0x400, %ax             # imm = 0x400
jmp 0x1a68
movq -0x48(%rbp), %rax
andl $-0x4, %eax
addl $0x4, %eax
movw %ax, 0x4(%r12)
addl %eax, %r15d
addq %r15, %r14
movl $0x400, %eax            # imm = 0x400
subl %r15d, %eax
movw %ax, 0x4(%r14)
movl %r13d, (%r14)
movq -0x40(%rbp), %rbx
movq %rbx, %rdi
callq 0x1060
movb %al, 0x6(%r14)
movb $0x2, 0x7(%r14)
addq $0x8, %r14
movzbl %al, %edx
movq %r14, %rdi
movq %rbx, %rsi
callq 0x1040
movq 0x261a(%rip), %rax      # 0x40b8
incw 0x10(%rax)
xorl %eax, %eax
leaq -0x28(%rbp), %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
callq 0x117c
movq %rbx, %rdi
callq 0x1155
addq $0x8, %rbx
movq %rbx, %rdi
callq 0x126f
callq 0x125a
callq 0x1235
callq 0x11a1
callq 0x1210
callq 0x11eb
callq 0x11c6