#define FUSE_USE_VERSION 26 #include #include #include #include #include #include #include #include #include "utils.h" using uint64 = uint64_t; using buf_t = std::vector; inline static std::unordered_map buffer_map; inline static std::mutex lock; inline static std::string script_path = "./main.sh"; std::atomic_uint64_t counter = 69; constexpr uint64 buf_size = 0x10000; //TODO: properly make a dir inline static std::string target_file_path = "/outfile"; //just please dont stat the file ok static int getattr_callback(const char *path, struct stat *stbuf) { std::cout << "getattr " << path << "\n"; memset(stbuf, 0, sizeof(struct stat)); bool dir = false; if( std::string(path) == "/") dir = true; stbuf->st_mode = (dir ? S_IFDIR : S_IFREG) | 0777; stbuf->st_nlink = 1; stbuf->st_size = buf_size; return 0; } static int readdir_callback(const char *path, void *buf, fuse_fill_dir_t filler, off_t offset, struct fuse_file_info *fi) { std::cerr << "readdir " << path << "\n"; if( std::string(path) != "/") return -ENOENT; filler(buf, ".", NULL, 0); filler(buf, "..", NULL, 0); filler(buf, target_file_path.c_str(), NULL, 0); return 0; } static int open_callback(const char *path, struct fuse_file_info *fi) { std::lock_guard l(lock); std::cerr << "open " << path << "\n"; if(path != target_file_path) return -ENOENT; //allocate fd fi->fh = counter++; std::string res = shexec((script_path).c_str()); //TODO: queue up file request in a worker thread //also a copy can be avoided here std::cerr << "res: " << res << "\n"; buffer_map.emplace(fi->fh, buf_t(res.begin(), res.end())); return 0; } static int read_callback(const char *path, char *buf, size_t size, off_t offset, struct fuse_file_info *fi) { std::lock_guard l(lock); std::cerr << "read " << path << "\n"; if(path != target_file_path) return -ENOENT; auto it = buffer_map.find(fi->fh); if(it == buffer_map.end()){ std::cerr << "cant find buffer mapping" << path << "\n"; return -ENOENT; } buf_t& fbuf = it->second; std::cerr << "size: " << size << " off: " << offset << "\n"; if(size + offset >= buf_size) size = buf_size - offset; //do bounds check if(size + offset >= fbuf.size()) fbuf.resize(buf_size); std::cout << fbuf.data(); //read buffer memcpy(buf, fbuf.data() + offset, size); return size; } static int truncate_callback(const char *path, off_t size) { std::cerr << "truncate " << path << "\n"; return 0; } static int write_callback(const char *path, const char *buf, size_t size, off_t offset, struct fuse_file_info *fi) { std::cerr << "write " << path << "\n"; return 0; } static int mkdir_callback(const char *path, mode_t mode) { std::cerr << "mkdir " << path << "\n"; return 0; } static int create_callback(const char *path, mode_t mode, struct fuse_file_info *) { std::cerr << "create " << path << "\n"; return 0; } static int access_callback(const char *path, int mask) { std::cerr << "access " << path << "\n"; return 0; } static int unlink_callback(const char *path) { std::cerr << "unlink " << path << "\n"; return 0; } static int rmdir_callback(const char *path) { std::cerr << "rmdir " << path << "\n"; return 0; } static struct fuse_operations fuse_operations = { .getattr = getattr_callback, .readlink = 0, .getdir = 0, .mknod = 0, .mkdir = mkdir_callback, .unlink = unlink_callback, .rmdir = rmdir_callback, .symlink = 0, .rename = 0, .link = 0, .chmod = 0, .chown = 0, .truncate = truncate_callback, .utime = 0, .open = open_callback, .read = read_callback, .write = write_callback, .statfs = 0, .flush = 0, .release = 0, .fsync = 0, .setxattr = 0, .getxattr = 0, .listxattr = 0, .removexattr = 0, .opendir = 0, .readdir = readdir_callback, .releasedir = 0, .fsyncdir = 0, .init = 0, .destroy = 0, .access = access_callback, .create = create_callback, .ftruncate = 0, .fgetattr = 0, }; int main(int argc, char *argv[]) { if(argc == 1) return -1; script_path = argv[1]; argc--; argv += 1; return fuse_main(argc, argv, &fuse_operations, NULL); }