// File: davmac314[P]dinit/src/includes/dinit-util.h
// Function: open_with_dir(char const*, char const*, int)
inline std::pair<int,int> open_with_dir(const char *dirname, const char *basename,
        int resolve_fd = AT_FDCWD) noexcept
{
    // For a file /x/y/z, if the final component 'z' is a link to /a/b/c, then the real parent
    // directory is /a/b (not /x/y).

    // This vector is used as backing for the next path if we need to "recurse" (i.e. if we need
    // to manually follow a symlink).
    std::vector<char> path_vec;

    // Whether to close resolve_fd after use (initially false because it is supplied by caller,
    // and we don't want to close the caller's fd):
    bool close_resolve_fd = false;

    long link_resolve_times = sysconf(_SC_SYMLOOP_MAX);

    // strip the basename and open as a directory
    #ifdef O_SEARCH
        constexpr int dir_search_flag = O_SEARCH;
    #else
        // O_SEARCH is not available on Linux
        constexpr int dir_search_flag = O_PATH;
    #endif

    begin:

    if (*dirname == '\0') {
        dirname = ".";
    }

    int parent_dir_fd = bp_sys::openat(resolve_fd, dirname, dir_search_flag | O_DIRECTORY);
    if (close_resolve_fd) bp_sys::close(resolve_fd);
    if (parent_dir_fd == -1) {
        return {-1, errno};
    }

    // open the final file (basename) without following symlinks
    int file_fd = bp_sys::openat(parent_dir_fd, basename, O_RDONLY | O_NOFOLLOW);
    if (file_fd == -1) {
        if (errno == ELOOP) {
            // It's a symlink
            if (link_resolve_times == 0) {
                // We've tried to resolve as many as the system normally would, so give up.
                bp_sys::close(parent_dir_fd);
                return {-1, ELOOP};
            }

            link_resolve_times--;

            // read the next path
            auto link_path_r = readlink_at_str(parent_dir_fd, basename);
            if (!link_path_r.first) {
                // If EINVAL, it's supposedly not a symbolic link. Maybe it changed out from
                // underneath us. The risk of handling this by looping back and trying as a file
                // again seems greater than the risk that this will actually happen, so let's not
                // worry about it, and just error out now:
                bp_sys::close(parent_dir_fd);
                return {-1, errno};
            }

            // Ok, we successfully read the link target. We need to extract the parent directory
            // name and base name, and then we'll jump back to 'begin' to iterate:
            path_vec = std::move(link_path_r.second);
            char *path = path_vec.data();
            dirname = path;
            basename = base_name(dirname);
            if (basename == dirname) {
                dirname = "";
            }
            else if (*basename == '\0') {
                bp_sys::close(parent_dir_fd);
                return {-1, ENOENT};
            }
            else {
                string_view path_ish {path, (size_t)(basename - path)};
                string_view parent_path_v = parent_path(path_ish);
                if (parent_path_v.length() == 1) {
                    // Parent path must be '/'. Inserting nul might overwrite base name string,
                    // so we need a separate string:
                    dirname = "/";
                }
                else if (parent_path_v.empty()) {
                    dirname = "";
                }
                else {
                    path[parent_path_v.length()] = '\0';
                }
            }

            resolve_fd = parent_dir_fd;
            close_resolve_fd = true;
            goto begin;
        }

        // Other errors: bail out
        bp_sys::close(parent_dir_fd);
        return {-1, errno};
    }

    return {parent_dir_fd, file_fd};
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x100, %rsp            # imm = 0x100
movq %rdi, -0x10(%rbp)
movq %rsi, -0x18(%rbp)
movl %edx, -0x1c(%rbp)
leaq -0x38(%rbp), %rdi
callq 0x15780
movb $0x0, -0x39(%rbp)
movl $0xad, %edi
callq 0x52a0
movq %rax, -0x48(%rbp)
movl $0x200000, -0x4c(%rbp)  # imm = 0x200000
movq -0x10(%rbp), %rax
movsbl (%rax), %eax
cmpl $0x0, %eax
jne 0x138bf
leaq 0x108d1(%rip), %rax     # 0x2418c
movq %rax, -0x10(%rbp)
movl -0x1c(%rbp), %edi
movq -0x10(%rbp), %rsi
xorl %eax, %eax
movl $0x210000, %edx         # imm = 0x210000
callq 0x5730
movl %eax, -0xd8(%rbp)
jmp 0x138da
movl -0xd8(%rbp), %eax
movl %eax, -0x50(%rbp)
testb $0x1, -0x39(%rbp)
je 0x138f5
movl -0x1c(%rbp), %edi
callq 0x5770
jmp 0x138f3
jmp 0x138f5
cmpl $-0x1, -0x50(%rbp)
jne 0x13925
movl $0xffffffff, -0x54(%rbp) # imm = 0xFFFFFFFF
callq 0x5050
movq %rax, %rdx
leaq -0x8(%rbp), %rdi
leaq -0x54(%rbp), %rsi
callq 0x157a0
jmp 0x13919
movl $0x1, -0x58(%rbp)
jmp 0x13bf5
movl -0x50(%rbp), %edi
movq -0x18(%rbp), %rsi
xorl %eax, %eax
movl $0x20000, %edx          # imm = 0x20000
callq 0x5730
movl %eax, -0xdc(%rbp)
jmp 0x13940
movl -0xdc(%rbp), %eax
movl %eax, -0x5c(%rbp)
cmpl $-0x1, -0x5c(%rbp)
jne 0x13bdb
callq 0x5050
cmpl $0x28, (%rax)
jne 0x13ba4
cmpq $0x0, -0x48(%rbp)
jne 0x1399f
movl -0x50(%rbp), %edi
callq 0x5770
jmp 0x13972
movl $0xffffffff, -0x60(%rbp) # imm = 0xFFFFFFFF
movl $0x28, -0x64(%rbp)
leaq -0x8(%rbp), %rdi
leaq -0x60(%rbp), %rsi
leaq -0x64(%rbp), %rdx
callq 0x157d0
jmp 0x13993
movl $0x1, -0x58(%rbp)
jmp 0x13bf5
movq -0x48(%rbp), %rax
addq $-0x1, %rax
movq %rax, -0x48(%rbp)
movl -0x50(%rbp), %esi
movq -0x18(%rbp), %rdx
leaq -0x88(%rbp), %rdi
callq 0x15800
testb $0x1, -0x88(%rbp)
jne 0x13a01
movl -0x50(%rbp), %edi
callq 0x5770
jmp 0x139d1
movl $0xffffffff, -0x8c(%rbp) # imm = 0xFFFFFFFF
callq 0x5050
movq %rax, %rdx
leaq -0x8(%rbp), %rdi
leaq -0x8c(%rbp), %rsi
callq 0x157a0
jmp 0x139f5
movl $0x1, -0x58(%rbp)
jmp 0x13b8a
leaq -0x88(%rbp), %rsi
addq $0x8, %rsi
leaq -0x38(%rbp), %rdi
callq 0x15b70
leaq -0x38(%rbp), %rdi
callq 0x15ba0
movq %rax, -0x98(%rbp)
movq -0x98(%rbp), %rax
movq %rax, -0x10(%rbp)
movq -0x10(%rbp), %rdi
callq 0x15bc0
movq %rax, -0x18(%rbp)
movq -0x18(%rbp), %rax
cmpq -0x10(%rbp), %rax
jne 0x13a57
leaq 0x11068(%rip), %rax     # 0x24ab6
movq %rax, -0x10(%rbp)
jmp 0x13b79
movq -0x18(%rbp), %rax
movsbl (%rax), %eax
cmpl $0x0, %eax
jne 0x13aa6
movl -0x50(%rbp), %edi
callq 0x5770
jmp 0x13a6d
movl $0xffffffff, -0x9c(%rbp) # imm = 0xFFFFFFFF
movl $0x2, -0xa0(%rbp)
leaq -0x8(%rbp), %rdi
leaq -0x9c(%rbp), %rsi
leaq -0xa0(%rbp), %rdx
callq 0x157d0
jmp 0x13a9a
movl $0x1, -0x58(%rbp)
jmp 0x13b8a
movq -0x98(%rbp), %rsi
movq -0x18(%rbp), %rdx
subq %rsi, %rdx
leaq -0xb0(%rbp), %rdi
callq 0x15c10
movups -0xb0(%rbp), %xmm0
movaps %xmm0, -0xd0(%rbp)
movq -0xd0(%rbp), %rdi
movq -0xc8(%rbp), %rsi
callq 0x14160
movq %rdx, -0xf0(%rbp)
movq %rax, -0xe8(%rbp)
jmp 0x13af1
movq -0xf0(%rbp), %rax
movq -0xe8(%rbp), %rcx
movq %rcx, -0xc0(%rbp)
movq %rax, -0xb8(%rbp)
leaq -0xc0(%rbp), %rdi
callq 0x15c40
cmpq $0x1, %rax
jne 0x13b2c
leaq 0x1110a(%rip), %rax     # 0x24c30
movq %rax, -0x10(%rbp)
jmp 0x13b75
leaq -0xc0(%rbp), %rdi
callq 0x15c60
testb $0x1, %al
jne 0x13b3e
jmp 0x13b4b
leaq 0x10f71(%rip), %rax     # 0x24ab6
movq %rax, -0x10(%rbp)
jmp 0x13b73
movq -0x98(%rbp), %rax
movq %rax, -0xf8(%rbp)
leaq -0xc0(%rbp), %rdi
callq 0x15c40
movq %rax, %rcx
movq -0xf8(%rbp), %rax
movb $0x0, (%rax,%rcx)
jmp 0x13b75
jmp 0x13b77
jmp 0x13b79
movl -0x50(%rbp), %eax
movl %eax, -0x1c(%rbp)
movb $0x1, -0x39(%rbp)
movl $0x2, -0x58(%rbp)
leaq -0x88(%rbp), %rdi
callq 0x15c80
movl -0x58(%rbp), %eax
subl $0x2, %eax
je 0x138a8
jmp 0x13bf5
movl -0x50(%rbp), %edi
callq 0x5770
jmp 0x13bae
movl $0xffffffff, -0xd4(%rbp) # imm = 0xFFFFFFFF
callq 0x5050
movq %rax, %rdx
leaq -0x8(%rbp), %rdi
leaq -0xd4(%rbp), %rsi
callq 0x157a0
jmp 0x13bd2
movl $0x1, -0x58(%rbp)
jmp 0x13bf5
leaq -0x8(%rbp), %rdi
leaq -0x50(%rbp), %rsi
leaq -0x5c(%rbp), %rdx
callq 0x15ca0
jmp 0x13bee
movl $0x1, -0x58(%rbp)
leaq -0x38(%rbp), %rdi
callq 0x15cd0
movq -0x8(%rbp), %rax
addq $0x100, %rsp            # imm = 0x100
popq %rbp
retq
movq %rax, %rdi
callq 0x103e0
nopw %cs:(%rax,%rax)
nopl (%rax)