#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif
#include "zvfs_hook_rw.h"
#include "zvfs_hook_init.h"
#include "zvfs_hook_reentrant.h"
#include "fs/zvfs.h"
#include "fs/zvfs_open_file.h"
#include "fs/zvfs_inode.h"
#include "proto/ipc_proto.h"
#include "spdk_engine/io_engine.h"

#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include <pthread.h>
#include <stdint.h>
#include <limits.h>
#include <unistd.h>
#include <bits/types/struct_FILE.h>

/* ------------------------------------------------------------------ */
/* 内部：read/pread 调试日志                                            */
/* ------------------------------------------------------------------ */

static int
zvfs_debug_rw_enabled(void)
{
    static int inited = 0;
    static int enabled = 0;
    const char *v;

    if (!inited) {
        v = getenv("ZVFS_DEBUG_RW");
        enabled = (v && v[0] != '\0' && strcmp(v, "0") != 0);
        inited = 1;
    }
    return enabled;
}

static int
zvfs_debug_rw_fd_match(int fd)
{
    static int inited = 0;
    static int has_filter = 0;
    static int filter_fd = -1;
    const char *v;
    char *end = NULL;
    long parsed;

    if (!inited) {
        v = getenv("ZVFS_DEBUG_RW_FD");
        if (v && v[0] != '\0') {
            parsed = strtol(v, &end, 10);
            if (end && *end == '\0' && parsed >= 0 && parsed <= INT_MAX) {
                has_filter = 1;
                filter_fd = (int)parsed;
            }
        }
        inited = 1;
    }

    if (!has_filter) {
        return 1;
    }
    return fd == filter_fd;
}

static void
zvfs_debug_rw_log(int fd, const char *fmt, ...)
{
    va_list ap;

    if (!zvfs_debug_rw_enabled() || !zvfs_debug_rw_fd_match(fd)) {
        return;
    }

    fprintf(stderr, "[zvfs][rw-dbg][pid=%d][tid=%lu][fd=%d] ",
            getpid(), (unsigned long)pthread_self(), fd);
    va_start(ap, fmt);
    vfprintf(stderr, fmt, ap);
    va_end(ap);
    fputc('\n', stderr);
}

static const char *
zvfs_debug_fd_target(int fd)
{
    static __thread char target[PATH_MAX];
    char linkpath[64];
    ssize_t n;

    if (fd < 0) {
        return "(invalid-fd)";
    }

    snprintf(linkpath, sizeof(linkpath), "/proc/self/fd/%d", fd);
    n = readlink(linkpath, target, sizeof(target) - 1);
    if (n < 0) {
        return "(unknown)";
    }
    target[n] = '\0';
    return target;
}

static uint64_t
zvfs_debug_logical_size(struct zvfs_open_file *of)
{
    uint64_t size;
    if (!of || !of->inode) {
        return 0;
    }
    pthread_mutex_lock(&of->inode->mu);
    size = of->inode->logical_size;
    pthread_mutex_unlock(&of->inode->mu);
    return size;
}

/* ------------------------------------------------------------------ */
/* 内部：单段 pread / pwrite（不修改 of->offset）                        */
/* ------------------------------------------------------------------ */

/*
 * zvfs_pread_impl
 *
 * 从 blob 的 [offset, offset+count) 读取数据到 buf。
 * 若请求范围超出 logical_size，截断到 logical_size 边界。
 * 成功返回实际读取字节数，失败返回 -1。
 */
static ssize_t
zvfs_pread_impl(struct zvfs_open_file *of,
                void *buf, size_t count, uint64_t offset)
{
    /* 持 inode->mu 读 logical_size，防止并发 write 同时修改 */
    pthread_mutex_lock(&of->inode->mu);
    uint64_t size = of->inode->logical_size;
    pthread_mutex_unlock(&of->inode->mu);

    /* offset 超出文件末尾：返回 0（EOF） */
    if (offset >= size)
        return 0;

    /* 截断读取长度到文件末尾 */
    if (offset + count > size)
        count = (size_t)(size - offset);

    if (count == 0)
        return 0;

    if (blob_read(of->handle_id, offset, buf, count) < 0) {
        errno = EIO;
        return -1;
    }

    return (ssize_t)count;
}

/*
 * zvfs_pwrite_impl
 *
 * 将 buf 的 count 字节写入 blob 的 offset 处。
 * 若写入后末尾超过 logical_size，更新 logical_size 并同步 st_size。
 * 成功返回 count，失败返回 -1。
 */
static ssize_t
zvfs_pwrite_impl(struct zvfs_open_file *of,
                 const void *buf, size_t count, uint64_t offset)
{
    if (count == 0)
        return 0;

    uint64_t end = offset + count;

    if (blob_write_ex(of->handle_id, offset, buf, count, ZVFS_WRITE_F_AUTO_GROW) < 0) {
        return -1;
    }

    /* 更新 logical_size（持锁，inode_update_size 负责 ftruncate） */
    pthread_mutex_lock(&of->inode->mu);
    if (end > of->inode->logical_size)        /* double-check */
        inode_update_size(of->inode, of->fd, end);
    pthread_mutex_unlock(&of->inode->mu);

    return (ssize_t)count;
}

/* ------------------------------------------------------------------ */
/* 内部：iov 合并辅助                                                   */
/* ------------------------------------------------------------------ */

/*
 * iov_total_len - 计算 iovec 总字节数。
 */
static size_t
iov_total_len(const struct iovec *iov, int iovcnt)
{
    size_t total = 0;
    for (int i = 0; i < iovcnt; i++)
        total += iov[i].iov_len;
    return total;
}

/*
 * zvfs_iov_pread
 *
 * 将 iovec 合并为单次 blob_read：
 *   1. 一次 blob_read 读到临时 buf
 *   2. 按 iovec 顺序分发到各段
 *
 * 单次 SPDK I/O 比逐段提交效率高得多；
 * 堆分配代价（通常几个 page）远小于多次 SPDK 提交的开销。
 */
static ssize_t
zvfs_iov_pread(struct zvfs_open_file *of,
               const struct iovec *iov, int iovcnt, uint64_t offset)
{
    size_t total_len = iov_total_len(iov, iovcnt);
    if (total_len == 0) return 0;

    /* 截断到文件末尾 */
    pthread_mutex_lock(&of->inode->mu);
    uint64_t size = of->inode->logical_size;
    pthread_mutex_unlock(&of->inode->mu);

    if (offset >= size) return 0;
    if (offset + total_len > size)
        total_len = (size_t)(size - offset);

    /* 分配临时 buf，单次读 */
    char *tmp = malloc(total_len);
    if (!tmp) { errno = ENOMEM; return -1; }

    if (blob_read(of->handle_id, offset, tmp, total_len) < 0) {
        free(tmp);
        errno = EIO;
        return -1;
    }

    /* 分发到各 iovec 段 */
    size_t copied = 0;
    for (int i = 0; i < iovcnt && copied < total_len; i++) {
        size_t seg = iov[i].iov_len;
        if (seg == 0) continue;
        if (copied + seg > total_len) seg = total_len - copied;
        memcpy(iov[i].iov_base, tmp + copied, seg);
        copied += seg;
    }

    free(tmp);
    return (ssize_t)total_len;
}

/*
 * zvfs_iov_pwrite
 *
 * 将 iovec 合并为单次 blob_write：
 *   1. 分配临时 buf，按 iovec 顺序 memcpy 拼接
 *   2. 单次 blob_write + 一次 inode_update_size
 *
 * 避免多次 SPDK 提交和多次 ftruncate。
 */
static ssize_t
zvfs_iov_pwrite(struct zvfs_open_file *of,
                const struct iovec *iov, int iovcnt, uint64_t offset)
{
    size_t total_len = iov_total_len(iov, iovcnt);
    if (total_len == 0) return 0;

    /* 拼接到临时 buf */
    char *tmp = malloc(total_len);
    if (!tmp) { errno = ENOMEM; return -1; }

    size_t pos = 0;
    for (int i = 0; i < iovcnt; i++) {
        if (iov[i].iov_len == 0) continue;
        memcpy(tmp + pos, iov[i].iov_base, iov[i].iov_len);
        pos += iov[i].iov_len;
    }

    /* 单次写入 */
    ssize_t r = zvfs_pwrite_impl(of, tmp, total_len, offset);
    free(tmp);
    return r;
}

/* ------------------------------------------------------------------ */
/* 内部：取出 of，处理重入/非 zvfs 判断                                  */
/* ------------------------------------------------------------------ */

static inline struct zvfs_open_file *
get_of(int fd)
{
    pthread_mutex_lock(&g_fs.fd_mu);
    struct zvfs_open_file *of = openfile_lookup(fd);
    pthread_mutex_unlock(&g_fs.fd_mu);
    return of;
}

static size_t
zvfs_fread_impl(void *ptr, size_t size, size_t nmemb, FILE *stream, int unlocked)
{
    ZVFS_HOOK_ENTER();

    int fd = stream ? fileno(stream) : -1;
    int in_hook = ZVFS_IN_HOOK();
    struct zvfs_open_file *of = NULL;
    if (!in_hook && fd >= 0) {
        of = get_of(fd);
    }

    if (in_hook || fd < 0 || !of) {
        zvfs_debug_rw_log(fd,
                          "fread passthrough reason=%s unlocked=%d size=%zu nmemb=%zu target=%s",
                          in_hook ? "reentrant" : (fd < 0 ? "bad_fd" : "fd_not_zvfs"),
                          unlocked, size, nmemb, zvfs_debug_fd_target(fd));
        size_t r = 0;
        if (unlocked) {
            if (real_fread_unlocked) r = real_fread_unlocked(ptr, size, nmemb, stream);
            else if (real_fread)     r = real_fread(ptr, size, nmemb, stream);
            else errno = ENOSYS;
        } else {
            if (real_fread)          r = real_fread(ptr, size, nmemb, stream);
            else if (real_fread_unlocked) r = real_fread_unlocked(ptr, size, nmemb, stream);
            else errno = ENOSYS;
        }
        zvfs_debug_rw_log(fd,
                          "fread passthrough ret=%zu errno=%d(%s)",
                          r, errno, strerror(errno));
        ZVFS_HOOK_LEAVE();
        return r;
    }

    zvfs_debug_rw_log(fd,
                      "fread hooked unlocked=%d size=%zu nmemb=%zu offset=%lu handle_id=%lu logical_size=%lu target=%s",
                      unlocked, size, nmemb,
                      (unsigned long)of->offset, (unsigned long)of->handle_id,
                      (unsigned long)zvfs_debug_logical_size(of),
                      zvfs_debug_fd_target(fd));
    zvfs_ensure_init();

    if (size == 0 || nmemb == 0) {
        ZVFS_HOOK_LEAVE();
        return 0;
    }
    if (nmemb > SIZE_MAX / size) {
        errno = EOVERFLOW;
        ZVFS_HOOK_LEAVE();
        return 0;
    }

    size_t total = size * nmemb;
    ssize_t n = zvfs_pread_impl(of, ptr, total, of->offset);
    if (n > 0)
        of->offset += (uint64_t)n;

    /* Keep stdio state machine consistent for callers that check feof/ferror. */
    if (n < 0) {
        stream->_flags |= _IO_ERR_SEEN;
    } else if ((size_t)n < total) {
        stream->_flags |= _IO_EOF_SEEN;
    }
    zvfs_debug_rw_log(fd,
                      "fread hooked ret_bytes=%zd ret_nmemb=%zu new_offset=%lu errno=%d(%s)",
                      n, (n <= 0) ? 0 : ((size_t)n / size),
                      (unsigned long)of->offset,
                      (n < 0) ? errno : 0, (n < 0) ? strerror(errno) : "OK");
    ZVFS_HOOK_LEAVE();
    return (n <= 0) ? 0 : ((size_t)n / size);
}

static int
zvfs_vfscanf_passthrough(FILE *stream, const char *format, va_list ap, int use_isoc99)
{
    if (use_isoc99 && real___isoc99_vfscanf) {
        return real___isoc99_vfscanf(stream, format, ap);
    }
    if (real_vfscanf) {
        return real_vfscanf(stream, format, ap);
    }
    return vfscanf(stream, format, ap);
}

static int
zvfs_vfscanf_impl(FILE *stream, const char *format, va_list ap, int use_isoc99)
{
    ZVFS_HOOK_ENTER();

    int fd = stream ? fileno(stream) : -1;
    int in_hook = ZVFS_IN_HOOK();
    struct zvfs_open_file *of = NULL;
    int ret = EOF;

    if (!in_hook && fd >= 0) {
        of = get_of(fd);
    }

    if (in_hook || fd < 0 || !of) {
        zvfs_debug_rw_log(fd,
                          "fscanf passthrough reason=%s isoc99=%d format=%s target=%s",
                          in_hook ? "reentrant" : (fd < 0 ? "bad_fd" : "fd_not_zvfs"),
                          use_isoc99, format ? format : "(null)", zvfs_debug_fd_target(fd));
        ret = zvfs_vfscanf_passthrough(stream, format, ap, use_isoc99);
        zvfs_debug_rw_log(fd, "fscanf passthrough ret=%d errno=%d(%s)",
                          ret, errno, strerror(errno));
        ZVFS_HOOK_LEAVE();
        return ret;
    }

    zvfs_ensure_init();

    if (!format) {
        errno = EINVAL;
        stream->_flags |= _IO_ERR_SEEN;
        ZVFS_HOOK_LEAVE();
        return EOF;
    }

    uint64_t cur_off = of->offset;
    uint64_t logical_size = zvfs_debug_logical_size(of);
    uint64_t remain64 = (cur_off < logical_size) ? (logical_size - cur_off) : 0;
    if (remain64 == 0) {
        stream->_flags |= _IO_EOF_SEEN;
        ZVFS_HOOK_LEAVE();
        return EOF;
    }
    if (remain64 > (uint64_t)(SIZE_MAX - 1)) {
        /* 防止超大文件触发巨量分配，退回 libc 路径。 */
        ret = zvfs_vfscanf_passthrough(stream, format, ap, use_isoc99);
        ZVFS_HOOK_LEAVE();
        return ret;
    }

    size_t remain = (size_t)remain64;
    char *buf = (char *)malloc(remain + 1);
    if (!buf) {
        errno = ENOMEM;
        stream->_flags |= _IO_ERR_SEEN;
        ZVFS_HOOK_LEAVE();
        return EOF;
    }

    ssize_t n = zvfs_pread_impl(of, buf, remain, cur_off);
    if (n < 0) {
        free(buf);
        stream->_flags |= _IO_ERR_SEEN;
        ZVFS_HOOK_LEAVE();
        return EOF;
    }
    if (n == 0) {
        free(buf);
        stream->_flags |= _IO_EOF_SEEN;
        ZVFS_HOOK_LEAVE();
        return EOF;
    }
    buf[n] = '\0';

    FILE *mem = fmemopen(buf, (size_t)n, "r");
    if (!mem) {
        int saved = errno;
        free(buf);
        errno = saved;
        stream->_flags |= _IO_ERR_SEEN;
        ZVFS_HOOK_LEAVE();
        return EOF;
    }

    zvfs_debug_rw_log(fd,
                      "fscanf hooked isoc99=%d format=%s offset=%lu logical_size=%lu target=%s",
                      use_isoc99, format,
                      (unsigned long)cur_off, (unsigned long)logical_size,
                      zvfs_debug_fd_target(fd));

    ret = zvfs_vfscanf_passthrough(mem, format, ap, use_isoc99);
    long consumed = ftell(mem);
    if (consumed > 0) {
        of->offset = cur_off + (uint64_t)consumed;
    }

    fclose(mem);
    free(buf);

    if (ret == EOF && consumed <= 0) {
        stream->_flags |= _IO_EOF_SEEN;
    }

    zvfs_debug_rw_log(fd,
                      "fscanf hooked ret=%d consumed=%ld new_offset=%lu errno=%d(%s)",
                      ret, consumed, (unsigned long)of->offset, errno, strerror(errno));
    ZVFS_HOOK_LEAVE();
    return ret;
}

#ifdef fscanf
#undef fscanf
#endif
int fscanf(FILE *stream, const char *format, ...)
{
    va_list ap;
    va_start(ap, format);
    int ret = zvfs_vfscanf_impl(stream, format, ap, 1);
    va_end(ap);
    return ret;
}

/* ------------------------------------------------------------------ */
/* read                                                                 */
/* ------------------------------------------------------------------ */

ssize_t
read(int fd, void *buf, size_t count)
{
    ZVFS_HOOK_ENTER();

    int in_hook = ZVFS_IN_HOOK();
    struct zvfs_open_file *of = get_of(fd);

    if (!of) {
        zvfs_debug_rw_log(fd,
                          "read passthrough reason=%s count=%zu target=%s",
                          in_hook ? "reentrant_fd_not_zvfs" : "fd_not_zvfs",
                          count, zvfs_debug_fd_target(fd));
        ssize_t r = real_read(fd, buf, count);
        zvfs_debug_rw_log(fd,
                          "read passthrough ret=%zd errno=%d(%s)",
                          r, (r < 0) ? errno : 0, (r < 0) ? strerror(errno) : "OK");
        ZVFS_HOOK_LEAVE();
        return r;
    }

    zvfs_debug_rw_log(fd,
                      "read hooked count=%zu offset=%lu handle_id=%lu logical_size=%lu target=%s",
                      count, (unsigned long)of->offset,
                      (unsigned long)of->handle_id,
                      (unsigned long)zvfs_debug_logical_size(of),
                      zvfs_debug_fd_target(fd));
    zvfs_ensure_init();

    ssize_t r = zvfs_pread_impl(of, buf, count, of->offset);
    if (r > 0)
        of->offset += (uint64_t)r;
    zvfs_debug_rw_log(fd,
                      "read hooked ret=%zd new_offset=%lu errno=%d(%s)",
                      r, (unsigned long)of->offset,
                      (r < 0) ? errno : 0, (r < 0) ? strerror(errno) : "OK");

    ZVFS_HOOK_LEAVE();
    return r;
}

ssize_t __read(int fd, void *buf, size_t count)       { return read(fd, buf, count); }
ssize_t __libc_read(int fd, void *buf, size_t count)  { return read(fd, buf, count); }
ssize_t __read_nocancel(int fd, void *buf, size_t count) { return read(fd, buf, count); }
ssize_t __read_chk(int fd, void *buf, size_t count, size_t buflen)
{
    if (count > buflen) {
        errno = ERANGE;
        return -1;
    }
    return read(fd, buf, count);
}

/* ------------------------------------------------------------------ */
/* pread / pread64                                                      */
/* ------------------------------------------------------------------ */

ssize_t
pread(int fd, void *buf, size_t count, off_t offset)
{
    ZVFS_HOOK_ENTER();

    int in_hook = ZVFS_IN_HOOK();
    struct zvfs_open_file *of = get_of(fd);

    if (!of) {
        zvfs_debug_rw_log(fd,
                          "pread passthrough reason=%s count=%zu offset=%lld target=%s",
                          in_hook ? "reentrant_fd_not_zvfs" : "fd_not_zvfs",
                          count, (long long)offset, zvfs_debug_fd_target(fd));
        ssize_t r = real_pread(fd, buf, count, offset);
        zvfs_debug_rw_log(fd,
                          "pread passthrough ret=%zd errno=%d(%s)",
                          r, (r < 0) ? errno : 0, (r < 0) ? strerror(errno) : "OK");
        ZVFS_HOOK_LEAVE();
        return r;
    }

    zvfs_debug_rw_log(fd,
                      "pread hooked count=%zu offset=%lld handle_id=%lu logical_size=%lu target=%s",
                      count, (long long)offset,
                      (unsigned long)of->handle_id,
                      (unsigned long)zvfs_debug_logical_size(of),
                      zvfs_debug_fd_target(fd));
    zvfs_ensure_init();

    ssize_t r = zvfs_pread_impl(of, buf, count, (uint64_t)offset);
    zvfs_debug_rw_log(fd,
                      "pread hooked ret=%zd errno=%d(%s)",
                      r, (r < 0) ? errno : 0, (r < 0) ? strerror(errno) : "OK");
    ZVFS_HOOK_LEAVE();
    return r;
}

ssize_t pread64(int fd, void *buf, size_t count, off_t offset)
{
    return pread(fd, buf, count, offset);
}

ssize_t __pread64(int fd, void *buf, size_t count, off_t offset)
{
    return pread(fd, buf, count, offset);
}

ssize_t __libc_pread(int fd, void *buf, size_t count, off_t offset)
{
    return pread(fd, buf, count, offset);
}

ssize_t __pread64_nocancel(int fd, void *buf, size_t count, off_t offset)
{
    return pread(fd, buf, count, offset);
}

ssize_t __pread_chk(int fd, void *buf, size_t count, off_t offset, size_t buflen)
{
    if (count > buflen) {
        errno = ERANGE;
        return -1;
    }
    return pread(fd, buf, count, offset);
}

ssize_t __pread64_chk(int fd, void *buf, size_t count, off_t offset, size_t buflen)
{
    if (count > buflen) {
        errno = ERANGE;
        return -1;
    }
    return pread(fd, buf, count, offset);
}

size_t fread_unlocked(void *ptr, size_t size, size_t nmemb, FILE *stream)
{
    return zvfs_fread_impl(ptr, size, nmemb, stream, 1);
}

size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream)
{
    return zvfs_fread_impl(ptr, size, nmemb, stream, 0);
}

/* ------------------------------------------------------------------ */
/* readv / preadv / preadv64 / preadv2                                  */
/* ------------------------------------------------------------------ */

ssize_t
readv(int fd, const struct iovec *iov, int iovcnt)
{
    ZVFS_HOOK_ENTER();

    struct zvfs_open_file *of = NULL;
    if (ZVFS_IN_HOOK() || !(of = get_of(fd))) {
        ssize_t r = real_readv(fd, iov, iovcnt);
        ZVFS_HOOK_LEAVE();
        return r;
    }

    zvfs_ensure_init();

    ssize_t r = zvfs_iov_pread(of, iov, iovcnt, of->offset);
    if (r > 0)
        of->offset += (uint64_t)r;

    ZVFS_HOOK_LEAVE();
    return r;
}

ssize_t
preadv(int fd, const struct iovec *iov, int iovcnt, off_t offset)
{
    ZVFS_HOOK_ENTER();

    struct zvfs_open_file *of = NULL;
    if (ZVFS_IN_HOOK() || !(of = get_of(fd))) {
        ssize_t r = real_preadv(fd, iov, iovcnt, offset);
        ZVFS_HOOK_LEAVE();
        return r;
    }

    zvfs_ensure_init();

    ssize_t r = zvfs_iov_pread(of, iov, iovcnt, (uint64_t)offset);
    ZVFS_HOOK_LEAVE();
    return r;
}

ssize_t preadv64(int fd, const struct iovec *iov, int iovcnt, off_t offset)
{
    return preadv(fd, iov, iovcnt, offset);
}

ssize_t
preadv2(int fd, const struct iovec *iov, int iovcnt, off_t offset, int flags)
{
    ZVFS_HOOK_ENTER();

    struct zvfs_open_file *of = NULL;
    if (ZVFS_IN_HOOK() || !(of = get_of(fd))) {
        ssize_t r = real_preadv2
            ? real_preadv2(fd, iov, iovcnt, offset, flags)
            : (errno = ENOSYS, (ssize_t)-1);
        ZVFS_HOOK_LEAVE();
        return r;
    }

    zvfs_ensure_init();

    /*
     * RWF_NOWAIT：zvfs 无阻塞 I/O 概念，blob_read 总是同步返回，
     * 忽略该 flag，按普通 preadv 处理。
     * RWF_HIPRI / RWF_DSYNC / RWF_SYNC：同上，忽略。
     */
    uint64_t off = (offset == (off_t)-1) ? of->offset : (uint64_t)offset;
    ssize_t r = zvfs_iov_pread(of, iov, iovcnt, off);
    if (offset == (off_t)-1 && r > 0)
        of->offset += (uint64_t)r;

    ZVFS_HOOK_LEAVE();
    return r;
}

/* ------------------------------------------------------------------ */
/* write                                                                */
/* ------------------------------------------------------------------ */

ssize_t
write(int fd, const void *buf, size_t count)
{
    ZVFS_HOOK_ENTER();

    struct zvfs_open_file *of = NULL;
    if (ZVFS_IN_HOOK() || !(of = get_of(fd))) {
        ssize_t r = real_write(fd, buf, count);
        ZVFS_HOOK_LEAVE();
        return r;
    }

    zvfs_ensure_init();

    uint64_t write_off;

    if (of->flags & O_APPEND) {
        /* O_APPEND：每次写入位置 = 当前 logical_size。 */
        pthread_mutex_lock(&of->inode->mu);
        write_off = of->inode->logical_size;    /* 重新取，防止 TOCTOU */
        pthread_mutex_unlock(&of->inode->mu);

        ssize_t r = zvfs_pwrite_impl(of, buf, count, write_off);
        if (r > 0)
            of->offset = write_off + (uint64_t)r;
        ZVFS_HOOK_LEAVE();
        return r;

    } else {
        write_off = of->offset;
        ssize_t r = zvfs_pwrite_impl(of, buf, count, write_off);
        if (r > 0)
            of->offset += (uint64_t)r;
        ZVFS_HOOK_LEAVE();
        return r;
    }
}

ssize_t __write(int fd, const void *buf, size_t count)      { return write(fd, buf, count); }
ssize_t __libc_write(int fd, const void *buf, size_t count) { return write(fd, buf, count); }

/* ------------------------------------------------------------------ */
/* pwrite / pwrite64                                                    */
/* ------------------------------------------------------------------ */

ssize_t
pwrite(int fd, const void *buf, size_t count, off_t offset)
{
    ZVFS_HOOK_ENTER();

    struct zvfs_open_file *of = NULL;
    if (ZVFS_IN_HOOK() || !(of = get_of(fd))) {
        ssize_t r = real_pwrite(fd, buf, count, offset);
        ZVFS_HOOK_LEAVE();
        return r;
    }

    zvfs_ensure_init();

    /*
     * POSIX：pwrite 忽略 O_APPEND，始终写到指定 offset。
     */
    ssize_t r = zvfs_pwrite_impl(of, buf, count, (uint64_t)offset);
    ZVFS_HOOK_LEAVE();
    return r;
}

ssize_t pwrite64(int fd, const void *buf, size_t count, off_t offset)
{
    return pwrite(fd, buf, count, offset);
}

/* ------------------------------------------------------------------ */
/* writev / pwritev / pwritev64 / pwritev2                              */
/* ------------------------------------------------------------------ */

ssize_t
writev(int fd, const struct iovec *iov, int iovcnt)
{
    ZVFS_HOOK_ENTER();

    struct zvfs_open_file *of = NULL;
    if (ZVFS_IN_HOOK() || !(of = get_of(fd))) {
        ssize_t r = real_writev(fd, iov, iovcnt);
        ZVFS_HOOK_LEAVE();
        return r;
    }

    zvfs_ensure_init();

    ssize_t r;
    if (of->flags & O_APPEND) {
        /* O_APPEND + writev：以当前 logical_size 作为写入起点。 */
        pthread_mutex_lock(&of->inode->mu);
        uint64_t write_off = of->inode->logical_size;
        pthread_mutex_unlock(&of->inode->mu);

        r = zvfs_iov_pwrite(of, iov, iovcnt, write_off);
        if (r > 0)
            of->offset = write_off + (uint64_t)r;
    } else {
        r = zvfs_iov_pwrite(of, iov, iovcnt, of->offset);
        if (r > 0) of->offset += (uint64_t)r;
    }

    ZVFS_HOOK_LEAVE();
    return r;
}

ssize_t
pwritev(int fd, const struct iovec *iov, int iovcnt, off_t offset)
{
    ZVFS_HOOK_ENTER();

    struct zvfs_open_file *of = NULL;
    if (ZVFS_IN_HOOK() || !(of = get_of(fd))) {
        ssize_t r = real_pwritev(fd, iov, iovcnt, offset);
        ZVFS_HOOK_LEAVE();
        return r;
    }

    zvfs_ensure_init();

    ssize_t r = zvfs_iov_pwrite(of, iov, iovcnt, (uint64_t)offset);
    ZVFS_HOOK_LEAVE();
    return r;
}

ssize_t pwritev64(int fd, const struct iovec *iov, int iovcnt, off_t offset)
{
    return pwritev(fd, iov, iovcnt, offset);
}

ssize_t
pwritev2(int fd, const struct iovec *iov, int iovcnt, off_t offset, int flags)
{
    ZVFS_HOOK_ENTER();

    struct zvfs_open_file *of = NULL;
    if (ZVFS_IN_HOOK() || !(of = get_of(fd))) {
        ssize_t r = real_pwritev2
            ? real_pwritev2(fd, iov, iovcnt, offset, flags)
            : (errno = ENOSYS, (ssize_t)-1);
        ZVFS_HOOK_LEAVE();
        return r;
    }

    zvfs_ensure_init();

    /* flags（RWF_SYNC/RWF_DSYNC/RWF_APPEND 等）：
     * zvfs 无缓冲区，所有写均同步落盘，忽略 flags。
     * offset == -1：使用并更新 of->offset。              */
    uint64_t off = (offset == (off_t)-1) ? of->offset : (uint64_t)offset;
    ssize_t r = zvfs_iov_pwrite(of, iov, iovcnt, off);
    if (offset == (off_t)-1 && r > 0)
        of->offset += (uint64_t)r;

    ZVFS_HOOK_LEAVE();
    return r;
}
