#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif
#include "zvfs_hook_init.h"
#include "zvfs_hook_reentrant.h"
#include "fs/zvfs.h"
#include "fs/zvfs_open_file.h"

#include <dlfcn.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <limits.h>
#include <pthread.h>

/* ------------------------------------------------------------------ */
/* 线程局部重入计数定义                                                  */
/* ------------------------------------------------------------------ */
__thread int _zvfs_hook_depth = 0;

/* ------------------------------------------------------------------ */
/* zvfs 挂载点                                                          */
/* ------------------------------------------------------------------ */
#define ZVFS_MOUNT_PREFIX      "/zvfs"
#define ZVFS_MOUNT_PREFIX_LEN  5          /* strlen("/zvfs") */

/* ------------------------------------------------------------------ */
/* real_* 函数指针定义                                                  */
/* ------------------------------------------------------------------ */

/* open / close / dup */
int   (*real_open)(const char *, int, ...)       = NULL;
int   (*real_open64)(const char *, int, ...)     = NULL;
int   (*real_openat)(int, const char *, int, ...) = NULL;
int   (*real_openat64)(int, const char *, int, ...) = NULL;
int   (*real_creat)(const char *, mode_t)        = NULL;
int   (*real_creat64)(const char *, mode_t)      = NULL;
int   (*real_close)(int)                         = NULL;
int   (*real_close_range)(unsigned, unsigned, unsigned) = NULL;
int   (*real_dup)(int)                           = NULL;
int   (*real_dup2)(int, int)                     = NULL;
int   (*real_dup3)(int, int, int)                = NULL;

/* read */
ssize_t (*real_read)(int, void *, size_t)                              = NULL;
ssize_t (*real_pread)(int, void *, size_t, off_t)                      = NULL;
ssize_t (*real_pread64)(int, void *, size_t, off_t)                    = NULL;
ssize_t (*real_readv)(int, const struct iovec *, int)                  = NULL;
ssize_t (*real_preadv)(int, const struct iovec *, int, off_t)          = NULL;
ssize_t (*real_preadv64)(int, const struct iovec *, int, off_t)        = NULL;
ssize_t (*real_preadv2)(int, const struct iovec *, int, off_t, int)    = NULL;

/* write */
ssize_t (*real_write)(int, const void *, size_t)                       = NULL;
ssize_t (*real_pwrite)(int, const void *, size_t, off_t)               = NULL;
ssize_t (*real_pwrite64)(int, const void *, size_t, off_t)             = NULL;
ssize_t (*real_writev)(int, const struct iovec *, int)                 = NULL;
ssize_t (*real_pwritev)(int, const struct iovec *, int, off_t)         = NULL;
ssize_t (*real_pwritev64)(int, const struct iovec *, int, off_t)       = NULL;
ssize_t (*real_pwritev2)(int, const struct iovec *, int, off_t, int)   = NULL;

/* lseek / truncate / fallocate */
off_t  (*real_lseek)(int, off_t, int)                 = NULL;
off_t  (*real_lseek64)(int, off_t, int)               = NULL;
int    (*real_truncate)(const char *, off_t)           = NULL;
int    (*real_truncate64)(const char *, off_t)         = NULL;
int    (*real_ftruncate)(int, off_t)                   = NULL;
int    (*real_ftruncate64)(int, off_t)                 = NULL;
int    (*real_fallocate)(int, int, off_t, off_t)       = NULL;
int    (*real_posix_fallocate)(int, off_t, off_t)      = NULL;

/* stat */
int    (*real_stat)(const char *, struct stat *)                       = NULL;
int    (*real_stat64)(const char *, struct stat64 *)                   = NULL;
int    (*real_fstat)(int, struct stat *)                               = NULL;
int    (*real_fstat64)(int, struct stat64 *)                           = NULL;
int    (*real_lstat)(const char *, struct stat *)                      = NULL;
int    (*real_lstat64)(const char *, struct stat64 *)                  = NULL;
int    (*real_fstatat)(int, const char *, struct stat *, int)          = NULL;
int    (*real_fstatat64)(int, const char *, struct stat64 *, int)      = NULL;
int    (*real_statx)(int, const char *, int, unsigned int,
                     struct statx *)                                   = NULL;
int    (*real___xstat)(int, const char *, struct stat *)               = NULL;
int    (*real___xstat64)(int, const char *, struct stat64 *)           = NULL;
int    (*real___fxstat)(int, int, struct stat *)                       = NULL;
int    (*real___fxstat64)(int, int, struct stat64 *)                   = NULL;
int    (*real___lxstat)(int, const char *, struct stat *)              = NULL;
int    (*real___lxstat64)(int, const char *, struct stat64 *)          = NULL;
int    (*real___fxstatat)(int, int, const char *, struct stat *, int)  = NULL;
int    (*real___fxstatat64)(int, int, const char *, struct stat64 *,
                             int)                                      = NULL;

/* sync */
int    (*real_fsync)(int)                                              = NULL;
int    (*real_fdatasync)(int)                                          = NULL;
int    (*real_sync_file_range)(int, off_t, off_t, unsigned int)        = NULL;

/* fcntl / ioctl */
int    (*real_fcntl)(int, int, ...)                                    = NULL;
int    (*real_fcntl64)(int, int, ...)                                  = NULL;
int    (*real_ioctl)(int, unsigned long, ...)                          = NULL;

/* 目录 */
int    (*real_unlink)(const char *)                                    = NULL;
int    (*real_unlinkat)(int, const char *, int)                        = NULL;
int    (*real_rename)(const char *, const char *)                      = NULL;
int    (*real_renameat)(int, const char *, int, const char *)          = NULL;
int    (*real_renameat2)(int, const char *, int, const char *,
                          unsigned int)                                = NULL;

/* mmap */
void  *(*real_mmap)(void *, size_t, int, int, int, off_t)             = NULL;
void  *(*real_mmap64)(void *, size_t, int, int, int, off_t)           = NULL;
int    (*real_munmap)(void *, size_t)                                  = NULL;
int    (*real_msync)(void *, size_t, int)                              = NULL;

/* fork */
pid_t  (*real_fork)(void)                                              = NULL;
pid_t  (*real_vfork)(void)                                             = NULL;

/* glibc 别名 */
int     (*real___open)(const char *, int, ...)                         = NULL;
int     (*real___open64)(const char *, int, ...)                       = NULL;
int     (*real___libc_open)(const char *, int, ...)                    = NULL;
ssize_t (*real___read)(int, void *, size_t)                            = NULL;
ssize_t (*real___libc_read)(int, void *, size_t)                       = NULL;
ssize_t (*real___read_nocancel)(int, void *, size_t)                   = NULL;
ssize_t (*real___pread64)(int, void *, size_t, off_t)                  = NULL;
ssize_t (*real___libc_pread)(int, void *, size_t, off_t)               = NULL;
ssize_t (*real___pread64_nocancel)(int, void *, size_t, off_t)         = NULL;
ssize_t (*real___read_chk)(int, void *, size_t, size_t)                = NULL;
ssize_t (*real___pread_chk)(int, void *, size_t, off_t, size_t)        = NULL;
ssize_t (*real___pread64_chk)(int, void *, size_t, off_t, size_t)      = NULL;
ssize_t (*real___write)(int, const void *, size_t)                     = NULL;
ssize_t (*real___libc_write)(int, const void *, size_t)                = NULL;
int     (*real___close)(int)                                           = NULL;
int     (*real___libc_close)(int)                                      = NULL;
size_t  (*real_fread_unlocked)(void *, size_t, size_t, FILE *)         = NULL;
size_t  (*real_fread)(void *, size_t, size_t, FILE *)                  = NULL;
int     (*real_vfscanf)(FILE *, const char *, va_list)                 = NULL;
int     (*real___isoc99_vfscanf)(FILE *, const char *, va_list)        = NULL;
FILE   *(*real_fopen)(const char *, const char *)                      = NULL;
FILE   *(*real_fopen64)(const char *, const char *)                    = NULL;
FILE   *(*real_fdopen)(int, const char *)                              = NULL;

/* ------------------------------------------------------------------ */
/* dlsym 辅助宏                                                         */
/* ------------------------------------------------------------------ */

/*
 * 找不到符号时不 fatal：部分 glibc 内部别名在某些发行版上可能不存在，
 * 置 NULL 后 hook 函数里做 NULL 检查再回退即可。
 */
#define LOAD_SYM(var, name) \
    do { \
        (var) = dlsym(RTLD_NEXT, (name)); \
        if (!(var)) \
            fprintf(stderr, "[zvfs] WARNING: dlsym(%s) = NULL\n", (name)); \
    } while (0)

#define LOAD_SYM_OPTIONAL(var, name) \
    do { (var) = dlsym(RTLD_NEXT, (name)); } while (0)

/* ------------------------------------------------------------------ */
/* 初始化                                                               */
/* ------------------------------------------------------------------ */

__attribute__((constructor))
void zvfs_hook_init(void)
{
    /* 必须存在的符号 */
    LOAD_SYM(real_open,          "open");
    LOAD_SYM(real_open64,        "open64");
    LOAD_SYM(real_openat,        "openat");
    LOAD_SYM(real_openat64,      "openat64");
    LOAD_SYM(real_creat,         "creat");
    LOAD_SYM(real_creat64,       "creat64");
    LOAD_SYM(real_close,         "close");
    LOAD_SYM(real_dup,           "dup");
    LOAD_SYM(real_dup2,          "dup2");
    LOAD_SYM(real_dup3,          "dup3");

    LOAD_SYM(real_read,          "read");
    LOAD_SYM(real_pread,         "pread");
    LOAD_SYM(real_pread64,       "pread64");
    LOAD_SYM(real_readv,         "readv");
    LOAD_SYM(real_preadv,        "preadv");
    LOAD_SYM(real_preadv64,      "preadv64");
    LOAD_SYM(real_write,         "write");
    LOAD_SYM(real_pwrite,        "pwrite");
    LOAD_SYM(real_pwrite64,      "pwrite64");
    LOAD_SYM(real_writev,        "writev");
    LOAD_SYM(real_pwritev,       "pwritev");
    LOAD_SYM(real_pwritev64,     "pwritev64");

    LOAD_SYM(real_lseek,         "lseek");
    LOAD_SYM(real_lseek64,       "lseek64");
    LOAD_SYM(real_truncate,      "truncate");
    LOAD_SYM(real_truncate64,    "truncate64");
    LOAD_SYM(real_ftruncate,     "ftruncate");
    LOAD_SYM(real_ftruncate64,   "ftruncate64");
    LOAD_SYM(real_fallocate,     "fallocate");
    LOAD_SYM(real_posix_fallocate,"posix_fallocate");

    LOAD_SYM_OPTIONAL(real_stat,      "stat");
    LOAD_SYM_OPTIONAL(real_stat64,    "stat64");
    LOAD_SYM_OPTIONAL(real_fstat,     "fstat");
    LOAD_SYM_OPTIONAL(real_fstat64,   "fstat64");
    LOAD_SYM_OPTIONAL(real_lstat,     "lstat");
    LOAD_SYM_OPTIONAL(real_lstat64,   "lstat64");
    LOAD_SYM_OPTIONAL(real_fstatat,   "fstatat");
    LOAD_SYM_OPTIONAL(real_fstatat64, "fstatat64");
    LOAD_SYM(real_fsync,         "fsync");
    LOAD_SYM(real_fdatasync,     "fdatasync");
    LOAD_SYM(real_fcntl,         "fcntl");
    LOAD_SYM(real_fcntl64,       "fcntl64");
    LOAD_SYM(real_ioctl,         "ioctl");

    LOAD_SYM(real_unlink,        "unlink");
    LOAD_SYM(real_unlinkat,      "unlinkat");
    LOAD_SYM(real_rename,        "rename");
    LOAD_SYM(real_renameat,      "renameat");
    LOAD_SYM(real_mmap,          "mmap");
    LOAD_SYM(real_mmap64,        "mmap64");
    LOAD_SYM(real_munmap,        "munmap");
    LOAD_SYM(real_msync,         "msync");
    LOAD_SYM(real_fork,          "fork");
    LOAD_SYM(real_vfork,         "vfork");

    /* 可选符号：glibc 内部别名，不一定存在 */
    LOAD_SYM_OPTIONAL(real_close_range,    "close_range");
    LOAD_SYM_OPTIONAL(real_preadv2,        "preadv2");
    LOAD_SYM_OPTIONAL(real_pwritev2,       "pwritev2");
    LOAD_SYM_OPTIONAL(real_statx,          "statx");
    LOAD_SYM_OPTIONAL(real_sync_file_range,"sync_file_range");
    LOAD_SYM_OPTIONAL(real_renameat2,      "renameat2");
    LOAD_SYM_OPTIONAL(real___open,         "__open");
    LOAD_SYM_OPTIONAL(real___open64,       "__open64");
    LOAD_SYM_OPTIONAL(real___libc_open,    "__libc_open");
    LOAD_SYM_OPTIONAL(real___xstat,        "__xstat");
    LOAD_SYM_OPTIONAL(real___xstat64,      "__xstat64");
    LOAD_SYM_OPTIONAL(real___fxstat,       "__fxstat");
    LOAD_SYM_OPTIONAL(real___fxstat64,     "__fxstat64");
    LOAD_SYM_OPTIONAL(real___lxstat,       "__lxstat");
    LOAD_SYM_OPTIONAL(real___lxstat64,     "__lxstat64");
    LOAD_SYM_OPTIONAL(real___fxstatat,     "__fxstatat");
    LOAD_SYM_OPTIONAL(real___fxstatat64,   "__fxstatat64");
    LOAD_SYM_OPTIONAL(real___read,         "__read");
    LOAD_SYM_OPTIONAL(real___libc_read,    "__libc_read");
    LOAD_SYM_OPTIONAL(real___read_nocancel, "__read_nocancel");
    LOAD_SYM_OPTIONAL(real___pread64,      "__pread64");
    LOAD_SYM_OPTIONAL(real___libc_pread,   "__libc_pread");
    LOAD_SYM_OPTIONAL(real___pread64_nocancel, "__pread64_nocancel");
    LOAD_SYM_OPTIONAL(real___read_chk,     "__read_chk");
    LOAD_SYM_OPTIONAL(real___pread_chk,    "__pread_chk");
    LOAD_SYM_OPTIONAL(real___pread64_chk,  "__pread64_chk");
    LOAD_SYM_OPTIONAL(real___write,        "__write");
    LOAD_SYM_OPTIONAL(real___libc_write,   "__libc_write");
    LOAD_SYM_OPTIONAL(real___close,        "__close");
    LOAD_SYM_OPTIONAL(real___libc_close,   "__libc_close");
    LOAD_SYM_OPTIONAL(real_fread_unlocked, "fread_unlocked");
    LOAD_SYM_OPTIONAL(real_fread,          "fread");
    LOAD_SYM_OPTIONAL(real_vfscanf,        "vfscanf");
    LOAD_SYM_OPTIONAL(real___isoc99_vfscanf, "__isoc99_vfscanf");
    LOAD_SYM_OPTIONAL(real_fopen,          "fopen");
    LOAD_SYM_OPTIONAL(real_fopen64,        "fopen64");
    LOAD_SYM_OPTIONAL(real_fdopen,         "fdopen");

    /* 初始化全局 fs 结构 */
    zvfs_fs_init();
}

#ifndef _STAT_VER
#define _STAT_VER 0
#endif

int
zvfs_real_stat(const char *path, struct stat *buf)
{
    if (real_stat) return real_stat(path, buf);
    if (real___xstat) return real___xstat(_STAT_VER, path, buf);
    errno = ENOSYS;
    return -1;
}

int
zvfs_real_stat64(const char *path, struct stat64 *buf)
{
    if (real_stat64) return real_stat64(path, buf);
    if (real___xstat64) return real___xstat64(_STAT_VER, path, buf);
    errno = ENOSYS;
    return -1;
}

int
zvfs_real_fstat(int fd, struct stat *buf)
{
    if (real_fstat) return real_fstat(fd, buf);
    if (real___fxstat) return real___fxstat(_STAT_VER, fd, buf);
    errno = ENOSYS;
    return -1;
}

int
zvfs_real_fstat64(int fd, struct stat64 *buf)
{
    if (real_fstat64) return real_fstat64(fd, buf);
    if (real___fxstat64) return real___fxstat64(_STAT_VER, fd, buf);
    errno = ENOSYS;
    return -1;
}

int
zvfs_real_lstat(const char *path, struct stat *buf)
{
    if (real_lstat) return real_lstat(path, buf);
    if (real___lxstat) return real___lxstat(_STAT_VER, path, buf);
    errno = ENOSYS;
    return -1;
}

int
zvfs_real_lstat64(const char *path, struct stat64 *buf)
{
    if (real_lstat64) return real_lstat64(path, buf);
    if (real___lxstat64) return real___lxstat64(_STAT_VER, path, buf);
    errno = ENOSYS;
    return -1;
}

int
zvfs_real_fstatat(int dirfd, const char *path, struct stat *buf, int flags)
{
    if (real_fstatat) return real_fstatat(dirfd, path, buf, flags);
    if (real___fxstatat) return real___fxstatat(_STAT_VER, dirfd, path, buf, flags);
    errno = ENOSYS;
    return -1;
}

int
zvfs_real_fstatat64(int dirfd, const char *path, struct stat64 *buf, int flags)
{
    if (real_fstatat64) return real_fstatat64(dirfd, path, buf, flags);
    if (real___fxstatat64) return real___fxstatat64(_STAT_VER, dirfd, path, buf, flags);
    errno = ENOSYS;
    return -1;
}

/* ------------------------------------------------------------------ */
/* 路径 / fd 判断                                                       */
/* ------------------------------------------------------------------ */

int
zvfs_is_zvfs_path(const char *path)
{
    if (!path)
        return 0;
    /* 路径必须以 /zvfs 开头，且后一个字符是 '/' 或 '\0' */
    if (strncmp(path, ZVFS_MOUNT_PREFIX, ZVFS_MOUNT_PREFIX_LEN) != 0)
        return 0;
    char next = path[ZVFS_MOUNT_PREFIX_LEN];
    return (next == '/' || next == '\0');
}

int
zvfs_is_zvfs_fd(int fd)
{
    if (fd < 0)
        return 0;
    pthread_mutex_lock(&g_fs.fd_mu);
    struct zvfs_open_file *of = openfile_lookup(fd);
    pthread_mutex_unlock(&g_fs.fd_mu);
    return (of != NULL);
}

/* ------------------------------------------------------------------ */
/* dirfd + 相对路径 → 绝对路径                                          */
/* ------------------------------------------------------------------ */

int
zvfs_resolve_atpath(int dirfd, const char *path, char *buf, size_t bufsz)
{
    /* 绝对路径：直接拷贝 */
    if (path && path[0] == '/') {
        if (strlen(path) >= bufsz) {
            errno = ENAMETOOLONG;
            return -1;
        }
        strncpy(buf, path, bufsz);
        buf[bufsz - 1] = '\0';
        return 0;
    }

    /* AT_FDCWD：以当前工作目录为基准 */
    if (dirfd == AT_FDCWD) {
        if (!getcwd(buf, bufsz)) return -1;
    } else {
        /* 通过 /proc/self/fd/<dirfd> 读出目录的绝对路径 */
        char proc_path[64];
        snprintf(proc_path, sizeof(proc_path), "/proc/self/fd/%d", dirfd);
        ssize_t len = readlink(proc_path, buf, bufsz - 1);
        if (len < 0) return -1;
        buf[len] = '\0';
    }

    /* 拼接 path */
    size_t dir_len = strlen(buf);
    size_t path_len = path ? strlen(path) : 0;
    if (dir_len + 1 + path_len >= bufsz) {
        errno = ENAMETOOLONG;
        return -1;
    }
    if (path_len > 0) {
        buf[dir_len] = '/';
        memcpy(buf + dir_len + 1, path, path_len + 1);
    }
    return 0;
}
