// File: /workspace/github_c_makefile_star2_O2/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, %r14
cmpl $0x3, %edi
jne 0x194b
movq 0x8(%r14), %rdi
pushq $0x2
popq %rsi
xorl %eax, %eax
callq 0x10d0
testl %eax, %eax
je 0x1968
pushq $0x3
popq %rdx
pushq $0x1
popq %rbx
movl $0x20000, %esi          # imm = 0x20000
xorl %edi, %edi
movl %ebx, %ecx
movl %eax, %r8d
xorl %r9d, %r9d
callq 0x1070
movq %rax, 0x2b74(%rip)      # 0x40a8
cmpq $-0x1, %rax
je 0x1986
leaq 0x400(%rax), %rcx
movq %rcx, 0x2b64(%rip)      # 0x40b0
movq %rax, %rcx
addq $0x800, %rcx            # imm = 0x800
movq %rcx, 0x2b5b(%rip)      # 0x40b8
movq 0x10(%r14), %rsi
movq %rax, %rdi
callq 0x1389
movl %eax, -0x2c(%rbp)
cmpl $-0x1, %eax
je 0x1994
movq 0x10(%r14), %r15
movq %r15, %rdi
callq 0x1060
cmpb $0x2f, -0x1(%r15,%rax)
jne 0x1593
movb $0x0, -0x1(%r15,%rax)
movq 0x10(%r14), %r15
movq %r15, %rdi
callq 0x1060
cltq
leaq (%rax,%r15), %rsi
incq %rsi
xorl %eax, %eax
cmpb $0x2f, -0x1(%rsi)
je 0x15bf
cmpl $0xff, %eax
je 0x1914
decq %rsi
incq %rax
jmp 0x15a6
movq %rsp, %r15
addq $0xf, %rax
andq $-0x10, %rax
subq %rax, %r15
movq %r15, %rsp
movq %r15, %rdi
callq 0x1050
movq 0x2ac9(%rip), %r12      # 0x40a8
movq 0x2ad2(%rip), %r14      # 0x40b8
movl 0x8(%r14), %eax
shll $0xa, %eax
addq %r12, %rax
movq 0x2ab9(%rip), %r13      # 0x40b0
movzwl 0x58(%r13), %ecx
movslq -0x2c(%rbp), %rsi
imulq %rcx, %rsi
addq %rax, %rsi
movq %r12, %rdi
movq %rsi, -0x38(%rbp)
movq %r15, -0x40(%rbp)
movq %r15, %rdx
xorl %ecx, %ecx
callq 0x12b8
cmpl $-0x1, %eax
jne 0x19b7
movl 0x4(%r14), %eax
shll $0xa, %eax
addq %r12, %rax
movl (%r13), %ecx
cmpl $0xc, %ecx
pushq $0xb
popq %rdx
movl %edx, %r8d
cmovael %ecx, %r8d
cmpl %ecx, %edx
jae 0x165e
movl %edx, %esi
shrl $0x3, %esi
movzbl (%rax,%rsi), %esi
movl %edx, %edi
andl $0x7, %edi
btl %edi, %esi
jae 0x165b
incl %edx
jmp 0x1640
movl %edx, %r8d
cmpl %ecx, %r8d
je 0x19da
movl (%r14), %ecx
shll $0xa, %ecx
addq %rcx, %r12
movl 0x4(%r13), %ecx
cmpl $0x17, %ecx
pushq $0x16
popq %rdx
movl %edx, %r14d
cmovael %ecx, %r14d
cmpl %ecx, %edx
jae 0x16a0
movl %edx, %esi
shrl $0x3, %esi
movzbl (%r12,%rsi), %esi
movl %edx, %edi
andl $0x7, %edi
btl %edi, %esi
jae 0x169d
incl %edx
jmp 0x1681
movl %edx, %r14d
cmpl %ecx, %r14d
je 0x1938
movl %r8d, %ecx
andb $0x7, %cl
movl %ebx, %edx
shll %cl, %edx
movl %r8d, %ecx
shrl $0x3, %ecx
xorb %dl, (%rax,%rcx)
movl %r14d, %ecx
andb $0x7, %cl
shll %cl, %ebx
movl %r8d, %ecx
movl %r14d, %edx
shrl $0x3, %edx
movq %r12, -0x48(%rbp)
xorb %bl, (%r12,%rdx)
movq 0x29d4(%rip), %rax      # 0x40b0
movq 0x29d5(%rip), %rdx      # 0x40b8
movq 0xc(%rax), %xmm0
pcmpeqd %xmm1, %xmm1
paddd %xmm1, %xmm0
movq %xmm0, 0xc(%rax)
movd 0xc(%rdx), %xmm0
paddw %xmm1, %xmm0
movd %xmm0, 0xc(%rdx)
movl 0x8(%rdx), %r15d
shll $0xa, %r15d
addq 0x2996(%rip), %r15      # 0x40a8
movzwl 0x58(%rax), %r12d
imulq %rcx, %r12
movabsq $0x40000004000, %rax    # imm = 0x40000004000
movq %rax, (%r12,%r15)
xorl %ebx, %ebx
xorl %edi, %edi
movl %r8d, %r13d
callq 0x10b0
movl %r13d, %ecx
movl %eax, 0xc(%r12,%r15)
movabsq $0x2000000000000, %rax  # imm = 0x2000000000000
movq %rax, 0x14(%r12,%r15)
movl $0x2, 0x1c(%r12,%r15)
andl $0x0, 0x24(%r12,%r15)
movl %r14d, 0x28(%r12,%r15)
pxor %xmm0, %xmm0
movdqu %xmm0, 0x64(%r12,%r15)
movq -0x38(%rbp), %rdx
incw 0x1a(%rdx)
movq 0x292e(%rip), %rax      # 0x40a8
shll $0xa, %r14d
incl %ecx
movl %ecx, (%rax,%r14)
movl $0x201000c, 0x4(%rax,%r14) # imm = 0x201000C
movb $0x2e, 0x8(%rax,%r14)
movq 0x290e(%rip), %rax      # 0x40a8
movl -0x2c(%rbp), %esi
incl %esi
movl %esi, 0xc(%rax,%r14)
movl $0x20203f4, 0x10(%rax,%r14) # imm = 0x20203F4
movw $0x2e2e, 0x14(%rax,%r14) # imm = 0x2E2E
leaq 0x28(%rdx), %r14
movl %ebx, %eax
movl (%r14), %ebx
addq $0x4, %r14
testl %ebx, %ebx
jne 0x17b9
shll $0xa, %eax
movslq %eax, %rbx
addq 0x28d5(%rip), %rbx      # 0x40a8
xorl %r12d, %r12d
movq %rbx, %r13
movzwl 0x4(%r13), %eax
addl %r12d, %eax
cmpl $0x3ff, %eax            # imm = 0x3FF
ja 0x17f3
movl %eax, %r13d
addq %rbx, %r13
movl %eax, %r12d
jmp 0x17d9
movl %ecx, -0x2c(%rbp)
movzbl 0x6(%r13), %r15d
addq $0x8, %r15
movl %r15d, %eax
andl $-0x4, %eax
addl %r12d, %eax
movl $0x3fc, %ecx            # imm = 0x3FC
subl %eax, %ecx
movslq %ecx, %rax
movq %rax, -0x50(%rbp)
movq -0x40(%rbp), %rdi
callq 0x1060
addq $0x8, %rax
cmpq -0x50(%rbp), %rax
jbe 0x1861
movq 0x2880(%rip), %rax      # 0x40b0
movl 0x4(%rax), %eax
cmpl $0x17, %eax
pushq $0x16
popq %rcx
movl %ecx, %ebx
cmovael %eax, %ebx
movl -0x2c(%rbp), %edi
movq -0x48(%rbp), %r8
cmpl %eax, %ecx
jae 0x1883
movl %ecx, %edx
shrl $0x3, %edx
movzbl (%r8,%rdx), %edx
movl %ecx, %esi
andl $0x7, %esi
btl %esi, %edx
jae 0x1881
incl %ecx
jmp 0x1845
andl $-0x4, %r15d
addl $0x4, %r15d
movw %r15w, 0x4(%r13)
addl %r15d, %r12d
addq %r12, %rbx
movl $0x400, %eax            # imm = 0x400
subl %r12d, %eax
movl -0x2c(%rbp), %edi
jmp 0x18cd
movl %ecx, %ebx
cmpl %eax, %ebx
je 0x1938
movl %ebx, %ecx
andb $0x7, %cl
pushq $0x1
popq %rdx
shll %cl, %edx
movl %ebx, %eax
shrl $0x3, %eax
xorb %dl, (%r8,%rax)
movq 0x280b(%rip), %rax      # 0x40b0
movq 0x280c(%rip), %rcx      # 0x40b8
decl 0xc(%rax)
decw 0xc(%rcx)
movl %ebx, -0x4(%r14)
movq -0x38(%rbp), %rax
addl $0x2, 0x1c(%rax)
shll $0xa, %ebx
addq 0x27df(%rip), %rbx      # 0x40a8
movw $0x400, %ax             # imm = 0x400
movw %ax, 0x4(%rbx)
movl %edi, (%rbx)
movq -0x40(%rbp), %r14
movq %r14, %rdi
callq 0x1060
movb %al, 0x6(%rbx)
movb $0x2, 0x7(%rbx)
addq $0x8, %rbx
movzbl %al, %edx
movq %rbx, %rdi
movq %r14, %rsi
callq 0x1040
movq 0x27b9(%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
movq 0x26dd(%rip), %rax      # 0x3ff8
movq (%rax), %rcx
leaq 0x748(%rip), %rdi       # 0x206d
pushq $0x19
popq %rsi
pushq $0x1
popq %rdx
callq 0x1100
pushq $0x1
popq %rdi
callq 0x10f0
movq 0x26b9(%rip), %rax      # 0x3ff8
movq (%rax), %rcx
leaq 0x778(%rip), %rdi       # 0x20c1
jmp 0x1925
movq 0x26a6(%rip), %rax      # 0x3ff8
movq (%rax), %rdi
movq (%r14), %rdx
leaq 0x6bb(%rip), %rsi       # 0x201a
xorl %eax, %eax
callq 0x10a0
jmp 0x1930
movq 0x2689(%rip), %rax      # 0x3ff8
movq (%rax), %rdi
movq 0x8(%r14), %rdx
leaq 0x6b6(%rip), %rsi       # 0x2033
xorl %eax, %eax
callq 0x10a0
jmp 0x19b0
leaq 0x6c1(%rip), %rdi       # 0x204e
callq 0x10e0
jmp 0x1930
movq 0x265d(%rip), %rax      # 0x3ff8
movq (%rax), %rcx
leaq 0x6ae(%rip), %rdi       # 0x2053
pushq $0x19
popq %rsi
pushq $0x1
popq %rdx
callq 0x1100
pushq $0x2
jmp 0x1932
movq 0x263a(%rip), %rax      # 0x3ff8
movq (%rax), %rcx
leaq 0x6bf(%rip), %rdi       # 0x2087
pushq $0x1f
popq %rsi
pushq $0x1
popq %rdx
callq 0x1100
pushq $0x11
jmp 0x1932
movq 0x2617(%rip), %rax      # 0x3ff8
movq (%rax), %rcx
leaq 0x6bc(%rip), %rdi       # 0x20a7
jmp 0x1925