terom@2: #include terom@2: #include terom@2: #include terom@2: terom@1: #include terom@1: #include terom@1: terom@6: #include "lib/log.h" terom@2: #include "lib/math.h" terom@3: #include "lib/signals.h" terom@1: #include "evfuse.h" terom@7: #include "dirbuf.h" terom@1: terom@2: const char *file_name = "hello"; terom@2: const char *file_data = "Hello World\n"; terom@2: terom@2: static struct hello { terom@1: struct event_base *ev_base; terom@1: terom@3: struct signals *signals; terom@3: terom@1: struct evfuse *ev_fuse; terom@2: terom@1: } ctx; terom@1: terom@1: void hello_init (void *userdata, struct fuse_conn_info *conn) { terom@1: INFO("[hello.init] userdata=%p, conn=%p", userdata, conn); terom@1: } terom@1: terom@1: void hello_destroy (void *userdata) { terom@1: INFO("[hello.destroy] userdata=%p", userdata); terom@1: } terom@1: terom@2: void hello_lookup (fuse_req_t req, fuse_ino_t parent, const char *name) { terom@2: struct fuse_entry_param e; terom@2: terom@2: INFO("[hello.lookup] (uid=%d, pid=%d) parent=%lu name=%s", fuse_req_ctx(req)->uid, fuse_req_ctx(req)->pid, parent, name); terom@2: terom@2: // the world is flat terom@2: if (parent != 1 || strcmp(name, file_name)) { terom@2: fuse_reply_err(req, ENOENT); terom@2: terom@2: return; terom@2: } terom@2: terom@2: // set up the entry terom@2: memset(&e, 0, sizeof(e)); terom@2: e.ino = 2; terom@2: e.attr_timeout = 1.0; terom@2: e.entry_timeout = 1.0; terom@2: e.attr.st_mode = S_IFREG | 0444; terom@2: e.attr.st_nlink = 1; terom@2: e.attr.st_size = strlen(file_data); terom@2: terom@2: // reply terom@2: fuse_reply_entry(req, &e); terom@2: } terom@2: terom@2: void hello_getattr (fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi) { terom@2: struct stat stbuf; terom@2: terom@2: INFO("[hello.getattr] (uid=%d, pid=%d) ino=%lu, fi=%p", fuse_req_ctx(req)->uid, fuse_req_ctx(req)->pid, ino, fi); terom@2: terom@2: memset(&stbuf, 0, sizeof(stbuf)); terom@2: terom@2: // the root dir, or the file? terom@2: if (ino == 1) { terom@2: stbuf.st_mode = S_IFDIR | 0555; terom@2: stbuf.st_nlink = 2; terom@2: terom@2: } else if (ino == 2) { terom@2: stbuf.st_mode = S_IFREG | 0444; terom@2: stbuf.st_nlink = 1; terom@2: stbuf.st_size = strlen(file_data); terom@2: terom@2: } else { terom@2: fuse_reply_err(req, ENOENT); terom@2: return; terom@2: } terom@2: terom@2: // reply terom@2: fuse_reply_attr(req, &stbuf, 1.0); terom@2: } terom@2: terom@2: terom@2: void hello_readdir (fuse_req_t req, fuse_ino_t ino, size_t size, off_t off, struct fuse_file_info *fi) { terom@2: int err = 0; terom@2: struct dirbuf buf; terom@2: terom@2: INFO("[hello.readdir] ino=%lu, size=%zu, off=%zu, fi=%p", ino, size, off, fi); terom@2: terom@2: // there exists only one dir terom@2: if (ino != 1) { terom@2: fuse_reply_err(req, ENOTDIR); terom@2: return; terom@2: } terom@2: terom@2: // fill in the dirbuf terom@5: if (dirbuf_init(&buf, size)) terom@2: ERROR("failed to init dirbuf"); terom@2: terom@7: err = dirbuf_add(req, off, &buf, 0, 1, ".", 1, S_IFDIR ) terom@7: || dirbuf_add(req, off, &buf, 1, 2, "..", 1, S_IFDIR ) terom@7: || dirbuf_add(req, off, &buf, 2, 3, file_name, 2, S_IFREG ); terom@5: terom@5: if (err < 0) terom@5: ERROR("failed to add dirents to buf"); terom@2: terom@2: // send it terom@7: if ((err = -dirbuf_done(req, &buf))) terom@2: EERROR(-err, "failed to send buf"); terom@2: terom@2: // success terom@2: return; terom@2: terom@2: error: terom@2: if ((err = fuse_reply_err(req, err ? err : EIO))) terom@2: EWARNING(err, "failed to send error reply"); terom@2: } terom@2: terom@4: void hello_open (fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi) { terom@4: int err = 0; terom@4: terom@4: INFO("[hello.open] ino=%lu, fi=%p, fi->flags=%08X", ino, fi, fi->flags); terom@4: terom@4: if (ino != 2) { terom@4: // must open our only file, not the dir terom@4: fuse_reply_err(req, ino == 1 ? EISDIR : ENOENT); terom@4: return; terom@4: terom@4: } else if ((fi->flags & 0x03) != O_RDONLY) { terom@4: // "permission denied" terom@4: fuse_reply_err(req, EACCES); terom@4: return; terom@4: } terom@4: terom@4: // XXX: update fi stuff? terom@4: terom@4: // open it! terom@4: if ((err = fuse_reply_open(req, fi))) terom@4: EERROR(err, "fuse_reply_open"); terom@4: terom@4: // success terom@4: return; terom@4: terom@4: error: terom@4: if ((err = fuse_reply_err(req, err ? err : EIO))) terom@4: EWARNING(err, "failed to send error reply"); terom@4: } terom@4: terom@4: void hello_read (fuse_req_t req, fuse_ino_t ino, size_t size, off_t off, struct fuse_file_info *fi) { terom@4: int err = 0; terom@4: terom@4: // fi is unused terom@4: (void) fi; terom@4: terom@4: INFO("[hello.read] ino=%lu, size=%zu, off=%zu, fi=%p", ino, size, off, fi); terom@4: terom@4: if (ino != 2) { terom@4: // EEK! terom@4: FATAL("wrong inode"); terom@4: } terom@4: terom@5: if (off >= strlen(file_data)) { terom@5: // offset is out-of-file, so return EOF terom@5: err = fuse_reply_buf(req, NULL, 0); terom@5: terom@5: } else { terom@5: // reply with the requested file data terom@5: err = fuse_reply_buf(req, file_data + off, MIN(strlen(file_data) - off, size)); terom@5: } terom@4: terom@4: // reply terom@5: if (err) terom@4: PERROR("fuse_reply_buf"); terom@4: terom@4: // success terom@4: return; terom@4: terom@4: error: terom@4: if ((err = fuse_reply_err(req, err ? err : EIO))) terom@4: EWARNING(err, "failed to send error reply"); terom@4: } terom@4: terom@6: void hello_getxattr (fuse_req_t req, fuse_ino_t ino, const char *name, size_t size) { terom@6: INFO("[hello.getxattr] ino=%lu, name=`%s', size=%zu", ino, name, size); terom@6: terom@6: fuse_reply_err(req, ENOSYS); terom@6: } terom@6: terom@1: struct fuse_lowlevel_ops hello_llops = { terom@1: .init = &hello_init, terom@1: .destroy = &hello_destroy, terom@2: terom@2: .lookup = &hello_lookup, terom@2: .getattr = &hello_getattr, terom@2: terom@4: .open = &hello_open, terom@4: terom@4: .read = &hello_read, terom@4: terom@2: .readdir = &hello_readdir, terom@6: terom@6: .getxattr = hello_getxattr, terom@1: }; terom@1: terom@1: terom@1: int main (int argc, char **argv) { terom@1: struct fuse_args fuse_args = FUSE_ARGS_INIT(argc, argv); terom@3: terom@3: // zero terom@3: memset(&ctx, 0, sizeof(ctx)); terom@1: terom@1: // init libevent terom@1: if ((ctx.ev_base = event_base_new()) == NULL) terom@3: ERROR("event_base_new"); terom@1: terom@3: // setup signals terom@3: if ((ctx.signals = signals_default(ctx.ev_base)) == NULL) terom@3: ERROR("signals_default"); terom@3: terom@1: // open fuse terom@1: if ((ctx.ev_fuse = evfuse_new(ctx.ev_base, &fuse_args, &hello_llops, &ctx)) == NULL) terom@3: ERROR("evfuse_new"); terom@1: terom@1: // run libevent terom@1: INFO("running libevent loop"); terom@1: terom@1: if (event_base_dispatch(ctx.ev_base)) terom@3: PERROR("event_base_dispatch"); terom@3: terom@3: // clean shutdown terom@1: terom@3: error : terom@1: // cleanup terom@3: if (ctx.ev_fuse) terom@3: evfuse_close(ctx.ev_fuse); terom@3: terom@3: if (ctx.signals) terom@3: signals_free(ctx.signals); terom@3: terom@3: if (ctx.ev_base) terom@3: event_base_free(ctx.ev_base); terom@3: terom@3: fuse_opt_free_args(&fuse_args); terom@1: } terom@1: