src/hello.c
changeset 56 9dfc861273e5
parent 42 40a3b13ffc9d
child 57 527d23bf6441
equal deleted inserted replaced
42:40a3b13ffc9d 56:9dfc861273e5
     1 #include <string.h>
       
     2 #include <errno.h>
       
     3 #include <stdlib.h>
       
     4 
       
     5 #include <event2/event.h>
       
     6 #include <fuse/fuse_opt.h>
       
     7 
       
     8 #include "lib/log.h"
       
     9 #include "lib/math.h"
       
    10 #include "lib/signals.h"
       
    11 #include "evfuse.h"
       
    12 #include "dirbuf.h"
       
    13 
       
    14 const char *file_name = "hello";
       
    15 const char *file_data = "Hello World\n";
       
    16 
       
    17 static struct hello {
       
    18     struct event_base *ev_base;
       
    19 
       
    20     struct signals *signals;
       
    21 
       
    22     struct evfuse *ev_fuse;
       
    23 
       
    24 } ctx;
       
    25 
       
    26 void hello_init (void *userdata, struct fuse_conn_info *conn) {
       
    27     INFO("[hello.init] userdata=%p, conn=%p", userdata, conn);
       
    28 }
       
    29 
       
    30 void hello_destroy (void *userdata) {
       
    31     INFO("[hello.destroy] userdata=%p", userdata);
       
    32 }
       
    33 
       
    34 void hello_lookup (fuse_req_t req, fuse_ino_t parent, const char *name) {
       
    35     struct fuse_entry_param e;
       
    36 
       
    37     INFO("[hello.lookup] (uid=%d, pid=%d) parent=%lu name=%s", fuse_req_ctx(req)->uid, fuse_req_ctx(req)->pid, parent, name);
       
    38 
       
    39     // the world is flat
       
    40     if (parent != 1 || strcmp(name, file_name)) {
       
    41         fuse_reply_err(req, ENOENT);
       
    42 
       
    43         return;
       
    44     }
       
    45     
       
    46     // set up the entry
       
    47     memset(&e, 0, sizeof(e));
       
    48     e.ino = 2;
       
    49     e.attr_timeout = 1.0;
       
    50     e.entry_timeout = 1.0;
       
    51     e.attr.st_mode = S_IFREG | 0444;
       
    52     e.attr.st_nlink = 1;
       
    53     e.attr.st_size = strlen(file_data);
       
    54 
       
    55     // reply
       
    56     fuse_reply_entry(req, &e);
       
    57 }
       
    58 
       
    59 void hello_getattr (fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi) {
       
    60     struct stat stbuf;
       
    61 
       
    62     INFO("[hello.getattr] (uid=%d, pid=%d) ino=%lu, fi=%p", fuse_req_ctx(req)->uid, fuse_req_ctx(req)->pid, ino, fi);
       
    63 
       
    64     memset(&stbuf, 0, sizeof(stbuf));
       
    65     
       
    66     // the root dir, or the file?
       
    67     if (ino == 1) {
       
    68         stbuf.st_mode = S_IFDIR | 0555;
       
    69         stbuf.st_nlink = 2;
       
    70 
       
    71     } else if (ino == 2) {
       
    72         stbuf.st_mode = S_IFREG | 0444;
       
    73         stbuf.st_nlink = 1;
       
    74         stbuf.st_size = strlen(file_data);
       
    75 
       
    76     } else {
       
    77         fuse_reply_err(req, ENOENT);
       
    78         return;
       
    79     }
       
    80     
       
    81     // reply
       
    82     fuse_reply_attr(req, &stbuf, 1.0);
       
    83 }
       
    84 
       
    85 
       
    86 void hello_readdir (fuse_req_t req, fuse_ino_t ino, size_t size, off_t off, struct fuse_file_info *fi) {
       
    87     int err = 0;
       
    88     struct dirbuf buf;
       
    89 
       
    90     INFO("[hello.readdir] ino=%lu, size=%zu, off=%zu, fi=%p", ino, size, off, fi);
       
    91 
       
    92     // there exists only one dir
       
    93     if (ino != 1) {
       
    94         fuse_reply_err(req, ENOTDIR);
       
    95         return;
       
    96     }
       
    97 
       
    98     // fill in the dirbuf
       
    99     if (dirbuf_init(&buf, size, off))
       
   100         ERROR("failed to init dirbuf");
       
   101 
       
   102     err =   dirbuf_add(req, &buf, 0, 1,  ".",        1,    S_IFDIR )
       
   103         ||  dirbuf_add(req, &buf, 1, 2,  "..",       1,    S_IFDIR )
       
   104         ||  dirbuf_add(req, &buf, 2, 3,  file_name,  2,    S_IFREG );
       
   105 
       
   106     if (err < 0)
       
   107         ERROR("failed to add dirents to buf");
       
   108     
       
   109     // send it
       
   110     if ((err = -dirbuf_done(req, &buf)))
       
   111         EERROR(-err, "failed to send buf");
       
   112 
       
   113     // success
       
   114     return;
       
   115 
       
   116 error:
       
   117     if ((err = fuse_reply_err(req, err ? err : EIO)))
       
   118         EWARNING(err, "failed to send error reply");
       
   119 }
       
   120 
       
   121 void hello_open (fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi) {
       
   122     int err = 0;
       
   123 
       
   124     INFO("[hello.open] ino=%lu, fi=%p, fi->flags=%08X", ino, fi, fi->flags);
       
   125 
       
   126     if (ino != 2) {
       
   127         // must open our only file, not the dir
       
   128         fuse_reply_err(req, ino == 1 ? EISDIR : ENOENT);
       
   129         return;
       
   130 
       
   131     } else if ((fi->flags & 0x03) != O_RDONLY) {
       
   132         // "permission denied"
       
   133         fuse_reply_err(req, EACCES);
       
   134         return;
       
   135     }
       
   136 
       
   137     // XXX: update fi stuff?
       
   138 
       
   139     // open it!
       
   140     if ((err = fuse_reply_open(req, fi)))
       
   141         EERROR(err, "fuse_reply_open");
       
   142 
       
   143     // success
       
   144     return;
       
   145 
       
   146 error:
       
   147     if ((err = fuse_reply_err(req, err ? err : EIO)))
       
   148         EWARNING(err, "failed to send error reply");
       
   149 }
       
   150 
       
   151 void hello_read (fuse_req_t req, fuse_ino_t ino, size_t size, off_t off, struct fuse_file_info *fi) {
       
   152     int err = 0;
       
   153 
       
   154     // fi is unused
       
   155     (void) fi;
       
   156 
       
   157     INFO("[hello.read] ino=%lu, size=%zu, off=%zu, fi=%p", ino, size, off, fi);
       
   158 
       
   159     if (ino != 2) {
       
   160         // EEK!
       
   161         FATAL("wrong inode");
       
   162     }
       
   163     
       
   164     if (off >= strlen(file_data)) {
       
   165         // offset is out-of-file, so return EOF
       
   166         err = fuse_reply_buf(req, NULL, 0);
       
   167 
       
   168     } else {
       
   169         // reply with the requested file data
       
   170         err = fuse_reply_buf(req, file_data + off, MIN(strlen(file_data) - off, size));
       
   171     }
       
   172 
       
   173     // reply
       
   174     if (err)
       
   175         PERROR("fuse_reply_buf");
       
   176     
       
   177     // success
       
   178     return;
       
   179 
       
   180 error:
       
   181     if ((err = fuse_reply_err(req, err ? err : EIO)))
       
   182         EWARNING(err, "failed to send error reply");
       
   183 }
       
   184 
       
   185 void hello_getxattr (fuse_req_t req, fuse_ino_t ino, const char *name, size_t size) {
       
   186     INFO("[hello.getxattr] ino=%lu, name=`%s', size=%zu", ino, name, size);
       
   187 
       
   188     fuse_reply_err(req, ENOSYS);
       
   189 }
       
   190 
       
   191 struct fuse_lowlevel_ops hello_llops = {
       
   192     .init = &hello_init,
       
   193     .destroy = &hello_destroy,
       
   194 
       
   195     .lookup = &hello_lookup,
       
   196     .getattr = &hello_getattr,
       
   197 
       
   198     .open = &hello_open,
       
   199 
       
   200     .read = &hello_read,
       
   201 
       
   202     .readdir = &hello_readdir,
       
   203 
       
   204     .getxattr = hello_getxattr,
       
   205 };
       
   206 
       
   207 
       
   208 int main (int argc, char **argv) {
       
   209     struct fuse_args fuse_args = FUSE_ARGS_INIT(argc, argv);
       
   210     
       
   211     // zero
       
   212     memset(&ctx, 0, sizeof(ctx));
       
   213 
       
   214     // init libevent
       
   215     if ((ctx.ev_base = event_base_new()) == NULL)
       
   216         ERROR("event_base_new");
       
   217     
       
   218     // setup signals
       
   219     if ((ctx.signals = signals_default(ctx.ev_base)) == NULL)
       
   220         ERROR("signals_default");
       
   221 
       
   222     // open fuse
       
   223     if ((ctx.ev_fuse = evfuse_new(ctx.ev_base, &fuse_args, &hello_llops, &ctx)) == NULL)
       
   224         ERROR("evfuse_new");
       
   225 
       
   226     // run libevent
       
   227     INFO("running libevent loop");
       
   228 
       
   229     if (event_base_dispatch(ctx.ev_base))
       
   230         PERROR("event_base_dispatch");
       
   231     
       
   232     // clean shutdown
       
   233 
       
   234 error :
       
   235     // cleanup
       
   236     if (ctx.ev_fuse)
       
   237         evfuse_free(ctx.ev_fuse);
       
   238     
       
   239     if (ctx.signals)
       
   240         signals_free(ctx.signals);
       
   241 
       
   242     if (ctx.ev_base)
       
   243         event_base_free(ctx.ev_base);
       
   244     
       
   245     fuse_opt_free_args(&fuse_args);
       
   246 }
       
   247