// File: jvanns[P]verbatim/sub/lmdb/libraries/liblmdb/mdb.c
// Function: mdb_env_copyfd1
static int ESECT
mdb_env_copyfd1(MDB_env *env, HANDLE fd)
{
	MDB_meta *mm;
	MDB_page *mp;
	mdb_copy my;
	MDB_txn *txn = NULL;
	pthread_t thr;
	int rc;

#ifdef _WIN32
	my.mc_mutex = CreateMutex(NULL, FALSE, NULL);
	my.mc_cond = CreateEvent(NULL, FALSE, FALSE, NULL);
	my.mc_wbuf[0] = _aligned_malloc(MDB_WBUF*2, env->me_os_psize);
	if (my.mc_wbuf[0] == NULL)
		return errno;
#else
	pthread_mutex_init(&my.mc_mutex, NULL);
	pthread_cond_init(&my.mc_cond, NULL);
#ifdef HAVE_MEMALIGN
	my.mc_wbuf[0] = memalign(env->me_os_psize, MDB_WBUF*2);
	if (my.mc_wbuf[0] == NULL)
		return errno;
#else
	rc = posix_memalign((void **)&my.mc_wbuf[0], env->me_os_psize, MDB_WBUF*2);
	if (rc)
		return rc;
#endif
#endif
	memset(my.mc_wbuf[0], 0, MDB_WBUF*2);
	my.mc_wbuf[1] = my.mc_wbuf[0] + MDB_WBUF;
	my.mc_wlen[0] = 0;
	my.mc_wlen[1] = 0;
	my.mc_olen[0] = 0;
	my.mc_olen[1] = 0;
	my.mc_next_pgno = NUM_METAS;
	my.mc_status = 0;
	my.mc_new = 1;
	my.mc_toggle = 0;
	my.mc_env = env;
	my.mc_fd = fd;
	THREAD_CREATE(thr, mdb_env_copythr, &my);

	rc = mdb_txn_begin(env, NULL, MDB_RDONLY, &txn);
	if (rc)
		return rc;

	mp = (MDB_page *)my.mc_wbuf[0];
	memset(mp, 0, NUM_METAS * env->me_psize);
	mp->mp_pgno = 0;
	mp->mp_flags = P_META;
	mm = (MDB_meta *)METADATA(mp);
	mdb_env_init_meta0(env, mm);
	mm->mm_address = env->me_metas[0]->mm_address;

	mp = (MDB_page *)(my.mc_wbuf[0] + env->me_psize);
	mp->mp_pgno = 1;
	mp->mp_flags = P_META;
	*(MDB_meta *)METADATA(mp) = *mm;
	mm = (MDB_meta *)METADATA(mp);

	/* Count the number of free pages, subtract from lastpg to find
	 * number of active pages
	 */
	{
		MDB_ID freecount = 0;
		MDB_cursor mc;
		MDB_val key, data;
		mdb_cursor_init(&mc, txn, FREE_DBI, NULL);
		while ((rc = mdb_cursor_get(&mc, &key, &data, MDB_NEXT)) == 0)
			freecount += *(MDB_ID *)data.mv_data;
		freecount += txn->mt_dbs[FREE_DBI].md_branch_pages +
			txn->mt_dbs[FREE_DBI].md_leaf_pages +
			txn->mt_dbs[FREE_DBI].md_overflow_pages;

		/* Set metapage 1 */
		mm->mm_last_pg = txn->mt_next_pgno - freecount - 1;
		mm->mm_dbs[MAIN_DBI] = txn->mt_dbs[MAIN_DBI];
		if (mm->mm_last_pg > NUM_METAS-1) {
			mm->mm_dbs[MAIN_DBI].md_root = mm->mm_last_pg;
			mm->mm_txnid = 1;
		} else {
			mm->mm_dbs[MAIN_DBI].md_root = P_INVALID;
		}
	}
	my.mc_wlen[0] = env->me_psize * NUM_METAS;
	my.mc_txn = txn;
	pthread_mutex_lock(&my.mc_mutex);
	while(my.mc_new)
		pthread_cond_wait(&my.mc_cond, &my.mc_mutex);
	pthread_mutex_unlock(&my.mc_mutex);
	rc = mdb_env_cwalk(&my, &txn->mt_dbs[MAIN_DBI].md_root, 0);
	if (rc == MDB_SUCCESS && my.mc_wlen[my.mc_toggle])
		rc = mdb_env_cthr_toggle(&my, 1);
	mdb_env_cthr_toggle(&my, -1);
	pthread_mutex_lock(&my.mc_mutex);
	while(my.mc_new)
		pthread_cond_wait(&my.mc_cond, &my.mc_mutex);
	pthread_mutex_unlock(&my.mc_mutex);
	THREAD_FINISH(thr);

	mdb_txn_abort(txn);
#ifdef _WIN32
	CloseHandle(my.mc_cond);
	CloseHandle(my.mc_mutex);
	_aligned_free(my.mc_wbuf[0]);
#else
	pthread_cond_destroy(&my.mc_cond);
	pthread_mutex_destroy(&my.mc_mutex);
	free(my.mc_wbuf[0]);
#endif
	return rc;
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x2a0, %rsp            # imm = 0x2A0
movq %rdi, -0x10(%rbp)
movl %esi, -0x14(%rbp)
movq $0x0, -0xe0(%rbp)
leaq -0xd8(%rbp), %rdi
xorl %eax, %eax
movl %eax, %esi
callq 0x23d0
leaq -0xd8(%rbp), %rdi
addq $0x28, %rdi
xorl %eax, %eax
movl %eax, %esi
callq 0x2240
leaq -0xd8(%rbp), %rdi
addq $0x58, %rdi
movq -0x10(%rbp), %rax
movl 0x14(%rax), %eax
movl %eax, %esi
movl $0x200000, %edx         # imm = 0x200000
callq 0x2380
movl %eax, -0xec(%rbp)
cmpl $0x0, -0xec(%rbp)
je 0x1487c
movl -0xec(%rbp), %eax
movl %eax, -0x4(%rbp)
jmp 0x14c34
movq -0x80(%rbp), %rdi
xorl %esi, %esi
movl $0x200000, %edx         # imm = 0x200000
callq 0x2180
movq -0x80(%rbp), %rax
addq $0x100000, %rax         # imm = 0x100000
movq %rax, -0x78(%rbp)
movl $0x0, -0x50(%rbp)
movl $0x0, -0x4c(%rbp)
movl $0x0, -0x48(%rbp)
movl $0x0, -0x44(%rbp)
movq $0x2, -0x40(%rbp)
movl $0x0, -0x34(%rbp)
movl $0x1, -0x30(%rbp)
movl $0x0, -0x2c(%rbp)
movq -0x10(%rbp), %rax
movq %rax, -0x60(%rbp)
movl -0x14(%rbp), %eax
movl %eax, -0x38(%rbp)
leaq -0xe8(%rbp), %rdi
xorl %eax, %eax
movl %eax, %esi
leaq 0x154d(%rip), %rdx      # 0x15e40
leaq -0xd8(%rbp), %rcx
callq 0x22a0
movq -0x10(%rbp), %rdi
xorl %eax, %eax
movl %eax, %esi
movl $0x20000, %edx          # imm = 0x20000
leaq -0xe0(%rbp), %rcx
callq 0x3a60
movl %eax, -0xec(%rbp)
cmpl $0x0, -0xec(%rbp)
je 0x14935
movl -0xec(%rbp), %eax
movl %eax, -0x4(%rbp)
jmp 0x14c34
movq -0x80(%rbp), %rax
movq %rax, -0x28(%rbp)
movq -0x28(%rbp), %rdi
movq -0x10(%rbp), %rax
movl 0x10(%rax), %eax
shll %eax
movl %eax, %eax
movl %eax, %edx
xorl %esi, %esi
callq 0x2180
movq -0x28(%rbp), %rax
movq $0x0, (%rax)
movq -0x28(%rbp), %rax
movw $0x8, 0xa(%rax)
movq -0x28(%rbp), %rax
addq $0x10, %rax
movq %rax, -0x20(%rbp)
movq -0x10(%rbp), %rdi
movq -0x20(%rbp), %rsi
callq 0x15c90
movq -0x10(%rbp), %rax
movq 0x48(%rax), %rax
movq 0x8(%rax), %rcx
movq -0x20(%rbp), %rax
movq %rcx, 0x8(%rax)
movq -0x80(%rbp), %rax
movq -0x10(%rbp), %rcx
movl 0x10(%rcx), %ecx
addq %rcx, %rax
movq %rax, -0x28(%rbp)
movq -0x28(%rbp), %rax
movq $0x1, (%rax)
movq -0x28(%rbp), %rax
movw $0x8, 0xa(%rax)
movq -0x28(%rbp), %rdi
addq $0x10, %rdi
movq -0x20(%rbp), %rsi
movl $0x88, %edx
callq 0x2230
movq -0x28(%rbp), %rax
addq $0x10, %rax
movq %rax, -0x20(%rbp)
movq $0x0, -0xf8(%rbp)
movq -0xe0(%rbp), %rsi
leaq -0x280(%rbp), %rdi
xorl %edx, %edx
xorl %eax, %eax
movl %eax, %ecx
callq 0x4d40
leaq -0x280(%rbp), %rdi
leaq -0x290(%rbp), %rsi
leaq -0x2a0(%rbp), %rdx
movl $0x8, %ecx
callq 0x8150
movl %eax, -0xec(%rbp)
cmpl $0x0, %eax
jne 0x14a48
movq -0x298(%rbp), %rax
movq (%rax), %rax
addq -0xf8(%rbp), %rax
movq %rax, -0xf8(%rbp)
jmp 0x14a04
movq -0xe0(%rbp), %rax
movq 0x58(%rax), %rax
movq 0x8(%rax), %rax
movq -0xe0(%rbp), %rcx
movq 0x58(%rcx), %rcx
addq 0x10(%rcx), %rax
movq -0xe0(%rbp), %rcx
movq 0x58(%rcx), %rcx
addq 0x18(%rcx), %rax
addq -0xf8(%rbp), %rax
movq %rax, -0xf8(%rbp)
movq -0xe0(%rbp), %rax
movq 0x10(%rax), %rcx
subq -0xf8(%rbp), %rcx
subq $0x1, %rcx
movq -0x20(%rbp), %rax
movq %rcx, 0x78(%rax)
movq -0x20(%rbp), %rdi
addq $0x18, %rdi
addq $0x30, %rdi
movq -0xe0(%rbp), %rax
movq 0x58(%rax), %rsi
addq $0x30, %rsi
movl $0x30, %edx
callq 0x2230
movq -0x20(%rbp), %rax
cmpq $0x1, 0x78(%rax)
jbe 0x14af2
movq -0x20(%rbp), %rax
movq 0x78(%rax), %rcx
movq -0x20(%rbp), %rax
movq %rcx, 0x70(%rax)
movq -0x20(%rbp), %rax
movq $0x1, 0x80(%rax)
jmp 0x14afe
movq -0x20(%rbp), %rax
movq $-0x1, 0x70(%rax)
movq -0x10(%rbp), %rax
movl 0x10(%rax), %eax
shll %eax
movl %eax, -0x50(%rbp)
movq -0xe0(%rbp), %rax
movq %rax, -0x58(%rbp)
leaq -0xd8(%rbp), %rdi
callq 0x2400
movl -0x30(%rbp), %eax
cmpl $0x0, %eax
je 0x14b42
leaq -0xd8(%rbp), %rdi
addq $0x28, %rdi
leaq -0xd8(%rbp), %rsi
callq 0x20e0
jmp 0x14b21
leaq -0xd8(%rbp), %rdi
callq 0x2250
movq -0xe0(%rbp), %rax
movq 0x58(%rax), %rsi
addq $0x30, %rsi
addq $0x28, %rsi
leaq -0xd8(%rbp), %rdi
xorl %edx, %edx
callq 0x16030
movl %eax, -0xec(%rbp)
cmpl $0x0, -0xec(%rbp)
jne 0x14ba0
movslq -0x2c(%rbp), %rax
cmpl $0x0, -0x50(%rbp,%rax,4)
je 0x14ba0
leaq -0xd8(%rbp), %rdi
movl $0x1, %esi
callq 0x169b0
movl %eax, -0xec(%rbp)
leaq -0xd8(%rbp), %rdi
movl $0xffffffff, %esi       # imm = 0xFFFFFFFF
callq 0x169b0
leaq -0xd8(%rbp), %rdi
callq 0x2400
movl -0x30(%rbp), %eax
cmpl $0x0, %eax
je 0x14bde
leaq -0xd8(%rbp), %rdi
addq $0x28, %rdi
leaq -0xd8(%rbp), %rsi
callq 0x20e0
jmp 0x14bbd
leaq -0xd8(%rbp), %rdi
callq 0x2250
movq -0xe8(%rbp), %rdi
xorl %eax, %eax
movl %eax, %esi
callq 0x23a0
movq -0xe0(%rbp), %rdi
callq 0x4310
leaq -0xd8(%rbp), %rdi
addq $0x28, %rdi
callq 0x22f0
leaq -0xd8(%rbp), %rdi
callq 0x2130
movq -0x80(%rbp), %rdi
callq 0x2030
movl -0xec(%rbp), %eax
movl %eax, -0x4(%rbp)
movl -0x4(%rbp), %eax
addq $0x2a0, %rsp            # imm = 0x2A0
popq %rbp
retq