// File: /workspace/github_c_makefile_star2_O1/albertito[P]libjio/libjio/trans.c
// Function: jtrans_rollback
ssize_t jtrans_rollback(struct jtrans *ts)
{
	ssize_t rv;
	struct jtrans *newts;
	struct operation *op, *curop, *lop;

	newts = jtrans_new(ts->fs, 0);
	if (newts == NULL)
		return -1;

	newts->flags = ts->flags;
	newts->numops_r = 0;
	newts->numops_w = 0;
	newts->len_w = 0;

	if (ts->op == NULL || ts->flags & J_NOROLLBACK) {
		rv = -1;
		goto exit;
	}

	/* find the last operation */
	for (op = ts->op; op->next != NULL; op = op->next)
		;

	/* and traverse the list backwards, skipping read operations */
	for ( ; op != NULL; op = op->prev) {
		if (op->direction == D_READ)
			continue;

		/* if we extended the data in the previous transaction, we
		 * should truncate it back */
		/* DANGEROUS: this is one of the main reasons why rollbacking
		 * is dangerous and should only be done with extreme caution:
		 * if for some reason, after the previous transacton, we have
		 * extended the file further, this will cut it back to what it
		 * was; read the docs for more detail */
		if (op->plen < op->len) {
			rv = ftruncate(ts->fs->fd, op->offset + op->plen);
			if (rv != 0)
				goto exit;
		}

		/* manually add the operation to the new transaction */
		curop = malloc(sizeof(struct operation));
		if (curop == NULL) {
			rv = -1;
			goto exit;
		}

		curop->offset = op->offset;
		curop->len = op->plen;
		curop->buf = op->pdata;
		curop->plen = op->plen;
		curop->pdata = op->pdata;
		curop->direction = op->direction;
		curop->locked = 0;

		newts->numops_w++;
		newts->len_w += curop->len;

		/* add the new transaction to the list */
		if (newts->op == NULL) {
			newts->op = curop;
			curop->prev = NULL;
			curop->next = NULL;
		} else {
			for (lop = newts->op; lop->next != NULL; lop = lop->next)
				;
			lop->next = curop;
			curop->prev = lop;
			curop->next = NULL;
		}
	}

	rv = jtrans_commit(newts);

exit:
	/* Free the transaction, taking care to set buf to NULL first since
	 * points to the same address as pdata, which would otherwise make
	 * jtrans_free() attempt to free it twice. We leave the data at
	 * curop->pdata since it is freed unconditionally, while the action
	 * on curop->buf depends on the direction of the transaction. */
	for (curop = newts->op; curop != NULL; curop = curop->next) {
		curop->buf = NULL;
	}
	jtrans_free(newts);

	return rv;
}

// Assembly:
pushq %r15
pushq %r14
pushq %r12
pushq %rbx
pushq %rax
movq %rdi, %r15
movq (%rdi), %rdi
xorl %esi, %esi
callq 0x20d0
testq %rax, %rax
je 0x3387
movq %rax, %rbx
movl 0xc(%r15), %eax
movl %eax, 0xc(%rbx)
xorps %xmm0, %xmm0
movups %xmm0, 0x10(%rbx)
movq 0x48(%r15), %rax
movq $-0x1, %r14
testq %rax, %rax
je 0x3393
testb $0x2, 0xc(%r15)
jne 0x3393
movq %rax, %r12
movq 0x40(%rax), %rax
testq %rax, %rax
jne 0x32b4
cmpl $0x1, 0x20(%r12)
je 0x336c
movq 0x28(%r12), %rsi
cmpq 0x10(%r12), %rsi
jae 0x32ef
movq (%r15), %rax
movl (%rax), %edi
addq 0x8(%r12), %rsi
callq 0x21d0
testl %eax, %eax
jne 0x3390
movl $0x48, %edi
callq 0x2390
testq %rax, %rax
je 0x3393
movq 0x8(%r12), %rcx
movq %rcx, 0x8(%rax)
movq 0x28(%r12), %rcx
movq %rcx, 0x10(%rax)
movq 0x30(%r12), %rdx
movq %rdx, 0x18(%rax)
movq %rcx, 0x28(%rax)
movq %rdx, 0x30(%rax)
movl 0x20(%r12), %edx
movl %edx, 0x20(%rax)
movl $0x0, (%rax)
incl 0x14(%rbx)
addq %rcx, 0x18(%rbx)
movq 0x48(%rbx), %rcx
testq %rcx, %rcx
je 0x3361
movq %rcx, %rdx
movq 0x40(%rcx), %rcx
testq %rcx, %rcx
jne 0x3343
movq %rax, 0x40(%rdx)
movq %rdx, 0x38(%rax)
movq $0x0, 0x40(%rax)
jmp 0x336c
movq %rax, 0x48(%rbx)
xorps %xmm0, %xmm0
movups %xmm0, 0x38(%rax)
movq 0x38(%r12), %r12
testq %r12, %r12
jne 0x32c0
movq %rbx, %rdi
callq 0x24d0
movq %rax, %r14
jmp 0x3393
movq $-0x1, %r14
jmp 0x33b2
movslq %eax, %r14
movq 0x48(%rbx), %rax
testq %rax, %rax
je 0x33aa
movq $0x0, 0x18(%rax)
movq 0x40(%rax), %rax
jmp 0x3397
movq %rbx, %rdi
callq 0x2170
movq %r14, %rax
addq $0x8, %rsp
popq %rbx
popq %r12
popq %r14
popq %r15
retq