commit ed021c06799779bbd030ae5e44c8b224057991d6 Author: dasha_uwu Date: Sun Aug 3 02:24:47 2025 +0500 initial commit diff --git a/condviewfs.c b/condviewfs.c new file mode 100644 index 0000000..6a61b73 --- /dev/null +++ b/condviewfs.c @@ -0,0 +1,254 @@ +#define _GNU_SOURCE + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define FUSE_USE_VERSION 317 + +#include + +static char *progname; +static int fd1, fd2; + +static int get_fd() { + pid_t pid = fork(); + if (pid == -1) { + perror("fork"); + exit(1); + } + if (pid == 0) { + execl(progname, progname, (char *) NULL); + + exit(2); + } + + int wstatus; + if (waitpid(pid, &wstatus, 0) == -1) { + perror("waitpid"); + exit(1); + } + + int code = WEXITSTATUS(wstatus); + if (code == 0) return fd1; + if (code == 1) return fd2; + + return -1; +} + +static int condviewfs_open(const char *name, struct fuse_file_info *fi) { + int dirfd = get_fd(); + if (dirfd == -1) + return -ENOLINK; + + int fd = openat(dirfd, &name[1], fi->flags); + if (fd < 0) + return -errno; + + fi->fh = (uint64_t)fd; + return 0; +} + +static int condviewfs_close(const char *name, struct fuse_file_info *fi) { + if (close((int)fi->fh)) + return -errno; + + return 0; +} + +static int condviewfs_getattr(const char *name, + struct stat *stbuf, + struct fuse_file_info *fi) { + int dirfd = get_fd(); + if (dirfd == -1) + return -ENOLINK; + + int ret; + + if (fi) + ret = fstat((int)fi->fh, stbuf); + else + ret = fstatat(dirfd, + &name[1], + stbuf, + AT_EMPTY_PATH | AT_SYMLINK_NOFOLLOW); + + if (ret < 0) + return -errno; + + return 0; +} + +static int condviewfs_access(const char *name, int mask) { + int dirfd = get_fd(); + if (dirfd == -1) + return -ENOLINK; + + if ((name[0] != '/') || (name[1] != '\0')) + ++name; + + if (faccessat(dirfd, name, mask, AT_SYMLINK_NOFOLLOW) < 0) + return -errno; + + return 0; +} + +static int condviewfs_read(const char *path, + char *buf, + size_t size, + off_t off, + struct fuse_file_info *fi) { + ssize_t out; + + out = pread((int)fi->fh, buf, size > INT_MAX ? INT_MAX : size, off); + if (out < 0) + return -errno; + + return (int)out; +} + +static int condviewfs_opendir(const char *name, struct fuse_file_info *fi) { + DIR *dirp; + int dirfd = get_fd(); + if (dirfd == -1) + return -ENOLINK; + + int fd, err; + + if ((name[0] == '/') && (name[1] == '\0')) + fd = dup(dirfd); + else + fd = openat(dirfd, &name[1], O_DIRECTORY); + + if (fd < 0) + return -errno; + + dirp = fdopendir(fd); + if (!dirp) { + err = -errno; + close(fd); + return err; + } + + fi->fh = (uint64_t)dirp; + return 0; +} + +static int condviewfs_closedir(const char *name, struct fuse_file_info *fi) { + if (closedir((DIR *)(uintptr_t)fi->fh) < 0) + return -errno; + + return 0; +} + +static int condviewfs_readdir(const char *path, + void *buf, + fuse_fill_dir_t filler, + off_t offset, + struct fuse_file_info *fi, + enum fuse_readdir_flags flags) { + int dirfd = get_fd(); + if (dirfd == -1) + return -ENOLINK; + + DIR *dirp = (DIR *)(uintptr_t)fi->fh; + + if (offset == 0) + rewinddir(dirp); + + struct stat stbuf; + struct dirent *dent; + while (1) { + errno = 0; + dent = readdir(dirp); + if (!dent) { + if (errno == 0) + break; + return -errno; + } + + if (fstatat(dirfd, + dent->d_name, + &stbuf, + AT_EMPTY_PATH | AT_SYMLINK_NOFOLLOW) < 0) + return -errno; + + if (filler(buf, dent->d_name, &stbuf, 0, FUSE_FILL_DIR_DEFAULTS) == 1) { + return -errno; + } + } + + return 0; +} + +static int condviewfs_readlink(const char *name, char *buf, size_t size) { + int dirfd = get_fd(); + if (dirfd == -1) + return -ENOLINK; + + ssize_t len; + + len = readlinkat(dirfd, + &name[1], + buf, + size - 1); + if (len < 0) + return -errno; + + buf[len] = '\0'; + return 0; +} + +static struct fuse_operations condviewfs_oper = { + .open = condviewfs_open, + .release = condviewfs_close, + + .read = condviewfs_read, + + .getattr = condviewfs_getattr, + .access = condviewfs_access, + + .opendir = condviewfs_opendir, + .releasedir = condviewfs_closedir, + .readdir = condviewfs_readdir, + + .readlink = condviewfs_readlink, +}; + +int main(int argc, char *argv[]) { + char *fuse_argv[5]; + + if (argc != 5) { + fprintf(stderr, "Usage: %s target dir1 dir2 prog\n", argv[0]); + exit(-1); + } + + fd1 = open(argv[2], O_DIRECTORY); + if (fd1 < 0) { + perror("open dir1") + exit(-1); + } + + fd2 = open(argv[3], O_DIRECTORY); + if (fd2 < 0) { + perror("open dir2") + exit(-1); + } + + progname = argv[4]; + + fuse_argv[0] = argv[0]; + fuse_argv[1] = argv[1]; + fuse_argv[2] = "-oallow_other,default_permissions"; + fuse_argv[3] = "-f"; + fuse_argv[4] = NULL; + return fuse_main(4, fuse_argv, &condviewfs_oper, NULL); +}