Files
zvfs/src/hook/zvfs_hook_init.c
2026-03-09 07:53:06 +00:00

299 lines
13 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#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;
/* 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___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;
/* ------------------------------------------------------------------ */
/* 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(real_stat, "stat");
LOAD_SYM(real_stat64, "stat64");
LOAD_SYM(real_fstat, "fstat");
LOAD_SYM(real_fstat64, "fstat64");
LOAD_SYM(real_lstat, "lstat");
LOAD_SYM(real_lstat64, "lstat64");
LOAD_SYM(real_fstatat, "fstatat");
LOAD_SYM(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___read, "__read");
LOAD_SYM_OPTIONAL(real___libc_read, "__libc_read");
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");
/* 初始化全局 fs 结构 */
zvfs_fs_init();
}
/* ------------------------------------------------------------------ */
/* 路径 / 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;
}