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