#define _GNU_SOURCE

#include <dlfcn.h>
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>

static int path_is_scoped(const char *path, int directory_fd) {
    const char *scope = getenv("MAPTOOLS_DRVFS_ROOT");
    char candidate[PATH_MAX];
    char resolved[PATH_MAX];
    size_t scope_length;

    if (scope == NULL || scope[0] == '\0' || path == NULL || path[0] == '\0') {
        return 0;
    }

    if (path[0] == '/') {
        if (snprintf(candidate, sizeof(candidate), "%s", path) >= (int)sizeof(candidate)) {
            return 0;
        }
    } else {
        char base[PATH_MAX];
        if (directory_fd == AT_FDCWD) {
            if (getcwd(base, sizeof(base)) == NULL) {
                return 0;
            }
        } else {
            char descriptor[64];
            ssize_t length;
            if (snprintf(descriptor, sizeof(descriptor), "/proc/self/fd/%d", directory_fd) >= (int)sizeof(descriptor)) {
                return 0;
            }
            length = readlink(descriptor, base, sizeof(base) - 1);
            if (length < 0) {
                return 0;
            }
            base[length] = '\0';
        }
        if (snprintf(candidate, sizeof(candidate), "%s/%s", base, path) >= (int)sizeof(candidate)) {
            return 0;
        }
    }

    if (realpath(candidate, resolved) == NULL) {
        return 0;
    }
    scope_length = strlen(scope);
    return strncmp(resolved, scope, scope_length) == 0 &&
           (resolved[scope_length] == '\0' || resolved[scope_length] == '/');
}

static int descriptor_is_scoped(int file_descriptor) {
    char descriptor[64];
    char target[PATH_MAX];
    ssize_t length;

    if (snprintf(descriptor, sizeof(descriptor), "/proc/self/fd/%d", file_descriptor) >= (int)sizeof(descriptor)) {
        return 0;
    }
    length = readlink(descriptor, target, sizeof(target) - 1);
    if (length < 0) {
        return 0;
    }
    target[length] = '\0';
    return path_is_scoped(target, AT_FDCWD);
}

int chmod(const char *path, mode_t mode) {
    static int (*real_chmod)(const char *, mode_t);
    int previous_errno = errno;
    int result;

    if (real_chmod == NULL) {
        real_chmod = dlsym(RTLD_NEXT, "chmod");
    }
    result = real_chmod(path, mode);
    if (result == -1 && errno == EPERM && path_is_scoped(path, AT_FDCWD)) {
        errno = previous_errno;
        return 0;
    }
    return result;
}

int fchmod(int file_descriptor, mode_t mode) {
    static int (*real_fchmod)(int, mode_t);
    int previous_errno = errno;
    int result;

    if (real_fchmod == NULL) {
        real_fchmod = dlsym(RTLD_NEXT, "fchmod");
    }
    result = real_fchmod(file_descriptor, mode);
    if (result == -1 && errno == EPERM && descriptor_is_scoped(file_descriptor)) {
        errno = previous_errno;
        return 0;
    }
    return result;
}

int fchmodat(int directory_fd, const char *path, mode_t mode, int flags) {
    static int (*real_fchmodat)(int, const char *, mode_t, int);
    int previous_errno = errno;
    int result;

    if (real_fchmodat == NULL) {
        real_fchmodat = dlsym(RTLD_NEXT, "fchmodat");
    }
    result = real_fchmodat(directory_fd, path, mode, flags);
    if (result == -1 && errno == EPERM && path_is_scoped(path, directory_fd)) {
        errno = previous_errno;
        return 0;
    }
    return result;
}
