author | Tero Marttila <terom@fixme.fi> |
Fri, 26 Sep 2008 20:11:22 +0300 | |
changeset 6 | d2036d7799fd |
parent 5 | dc86636257c2 |
child 7 | 3a603d755bcb |
permissions | -rw-r--r-- |
2 | 1 |
#include <string.h> |
2 |
#include <errno.h> |
|
3 |
#include <stdlib.h> |
|
4 |
||
1 | 5 |
#include <event2/event.h> |
6 |
#include <fuse/fuse_opt.h> |
|
7 |
||
6
d2036d7799fd
new 'simple' module, plus hello_simple
Tero Marttila <terom@fixme.fi>
parents:
5
diff
changeset
|
8 |
#include "lib/log.h" |
2 | 9 |
#include "lib/math.h" |
3 | 10 |
#include "lib/signals.h" |
1 | 11 |
#include "evfuse.h" |
12 |
||
2 | 13 |
const char *file_name = "hello"; |
14 |
const char *file_data = "Hello World\n"; |
|
15 |
||
16 |
static struct hello { |
|
1 | 17 |
struct event_base *ev_base; |
18 |
||
3 | 19 |
struct signals *signals; |
20 |
||
1 | 21 |
struct evfuse *ev_fuse; |
2 | 22 |
|
1 | 23 |
} ctx; |
24 |
||
25 |
void hello_init (void *userdata, struct fuse_conn_info *conn) { |
|
26 |
INFO("[hello.init] userdata=%p, conn=%p", userdata, conn); |
|
27 |
} |
|
28 |
||
29 |
void hello_destroy (void *userdata) { |
|
30 |
INFO("[hello.destroy] userdata=%p", userdata); |
|
31 |
} |
|
32 |
||
2 | 33 |
void hello_lookup (fuse_req_t req, fuse_ino_t parent, const char *name) { |
34 |
struct fuse_entry_param e; |
|
35 |
||
36 |
INFO("[hello.lookup] (uid=%d, pid=%d) parent=%lu name=%s", fuse_req_ctx(req)->uid, fuse_req_ctx(req)->pid, parent, name); |
|
37 |
||
38 |
// the world is flat |
|
39 |
if (parent != 1 || strcmp(name, file_name)) { |
|
40 |
fuse_reply_err(req, ENOENT); |
|
41 |
||
42 |
return; |
|
43 |
} |
|
44 |
||
45 |
// set up the entry |
|
46 |
memset(&e, 0, sizeof(e)); |
|
47 |
e.ino = 2; |
|
48 |
e.attr_timeout = 1.0; |
|
49 |
e.entry_timeout = 1.0; |
|
50 |
e.attr.st_mode = S_IFREG | 0444; |
|
51 |
e.attr.st_nlink = 1; |
|
52 |
e.attr.st_size = strlen(file_data); |
|
53 |
||
54 |
// reply |
|
55 |
fuse_reply_entry(req, &e); |
|
56 |
} |
|
57 |
||
58 |
void hello_getattr (fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi) { |
|
59 |
struct stat stbuf; |
|
60 |
||
61 |
INFO("[hello.getattr] (uid=%d, pid=%d) ino=%lu, fi=%p", fuse_req_ctx(req)->uid, fuse_req_ctx(req)->pid, ino, fi); |
|
62 |
||
63 |
memset(&stbuf, 0, sizeof(stbuf)); |
|
64 |
||
65 |
// the root dir, or the file? |
|
66 |
if (ino == 1) { |
|
67 |
stbuf.st_mode = S_IFDIR | 0555; |
|
68 |
stbuf.st_nlink = 2; |
|
69 |
||
70 |
} else if (ino == 2) { |
|
71 |
stbuf.st_mode = S_IFREG | 0444; |
|
72 |
stbuf.st_nlink = 1; |
|
73 |
stbuf.st_size = strlen(file_data); |
|
74 |
||
75 |
} else { |
|
76 |
fuse_reply_err(req, ENOENT); |
|
77 |
return; |
|
78 |
} |
|
79 |
||
80 |
// reply |
|
81 |
fuse_reply_attr(req, &stbuf, 1.0); |
|
82 |
} |
|
83 |
||
84 |
struct dirbuf { |
|
85 |
char *buf; |
|
86 |
size_t len; |
|
87 |
size_t off; |
|
88 |
}; |
|
89 |
||
5 | 90 |
static int dirbuf_init (struct dirbuf *buf, size_t req_size) { |
91 |
buf->len = req_size; |
|
2 | 92 |
buf->off = 0; |
93 |
||
94 |
// allocate the mem |
|
95 |
if ((buf->buf = malloc(buf->len)) == NULL) |
|
96 |
ERROR("malloc"); |
|
97 |
||
98 |
// ok |
|
99 |
return 0; |
|
100 |
||
101 |
error: |
|
102 |
return -1; |
|
103 |
} |
|
104 |
||
105 |
/* |
|
5 | 106 |
* Add an ent to the dirbuf. This will assume that the dirbuf is not already full |
107 |
* Returns 0 if the ent was added or skipped, -1 on error, 1 if the dirbuf is full |
|
2 | 108 |
*/ |
109 |
static int dirbuf_add (fuse_req_t req, size_t req_size, off_t req_off, struct dirbuf *buf, off_t ent_off, off_t next_off, const char *ent_name, fuse_ino_t ent_ino) { |
|
110 |
struct stat stbuf; |
|
111 |
size_t ent_size; |
|
112 |
||
5 | 113 |
INFO("\thello.dirbuf_add: req_size=%zu, req_off=%zu, buf->len=%zu, buf->off=%zu, ent_off=%zu, next_off=%zu, ent_name=`%s`, ent_ino=%lu", |
2 | 114 |
req_size, req_off, buf->len, buf->off, ent_off, next_off, ent_name, ent_ino); |
5 | 115 |
|
2 | 116 |
// skip entries as needed |
5 | 117 |
if (ent_off < req_off) |
2 | 118 |
return 0; |
119 |
||
120 |
// set ino |
|
121 |
stbuf.st_ino = ent_ino; |
|
122 |
||
123 |
// add the dirent and update dirbuf until it fits |
|
5 | 124 |
if ((ent_size = fuse_add_direntry(req, buf->buf + buf->off, buf->len - buf->off, ent_name, &stbuf, next_off)) > (buf->len - buf->off)) { |
125 |
// 'tis full |
|
126 |
return 1; |
|
2 | 127 |
|
5 | 128 |
} else { |
129 |
// it fit |
|
130 |
buf->off += ent_size; |
|
131 |
} |
|
2 | 132 |
|
133 |
// success |
|
134 |
return 0; |
|
135 |
} |
|
136 |
||
137 |
static int dirbuf_done (fuse_req_t req, struct dirbuf *buf, size_t req_size) { |
|
138 |
int err; |
|
139 |
||
140 |
// send the reply, return the error later |
|
141 |
err = fuse_reply_buf(req, buf->buf, MIN(buf->off, req_size)); |
|
142 |
||
143 |
INFO("\thello.dirbuf_done: MIN(%zu, %zu)=%zu, err=%d", buf->off, req_size, MIN(buf->off, req_size), err); |
|
144 |
||
145 |
// free the dirbuf |
|
146 |
free(buf->buf); |
|
147 |
||
148 |
// return the error code |
|
149 |
return err; |
|
150 |
} |
|
151 |
||
152 |
void hello_readdir (fuse_req_t req, fuse_ino_t ino, size_t size, off_t off, struct fuse_file_info *fi) { |
|
153 |
int err = 0; |
|
154 |
struct dirbuf buf; |
|
155 |
||
156 |
INFO("[hello.readdir] ino=%lu, size=%zu, off=%zu, fi=%p", ino, size, off, fi); |
|
157 |
||
158 |
// there exists only one dir |
|
159 |
if (ino != 1) { |
|
160 |
fuse_reply_err(req, ENOTDIR); |
|
161 |
return; |
|
162 |
} |
|
163 |
||
164 |
// fill in the dirbuf |
|
5 | 165 |
if (dirbuf_init(&buf, size)) |
2 | 166 |
ERROR("failed to init dirbuf"); |
167 |
||
5 | 168 |
err = dirbuf_add(req, size, off, &buf, 0, 1, ".", 1) |
2 | 169 |
|| dirbuf_add(req, size, off, &buf, 1, 2, "..", 1) |
5 | 170 |
|| dirbuf_add(req, size, off, &buf, 2, 3, file_name, 2); |
171 |
||
172 |
if (err < 0) |
|
173 |
ERROR("failed to add dirents to buf"); |
|
2 | 174 |
|
175 |
// send it |
|
176 |
if ((err = -dirbuf_done(req, &buf, size))) |
|
177 |
EERROR(-err, "failed to send buf"); |
|
178 |
||
179 |
// success |
|
180 |
return; |
|
181 |
||
182 |
error: |
|
183 |
if ((err = fuse_reply_err(req, err ? err : EIO))) |
|
184 |
EWARNING(err, "failed to send error reply"); |
|
185 |
} |
|
186 |
||
4 | 187 |
void hello_open (fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi) { |
188 |
int err = 0; |
|
189 |
||
190 |
INFO("[hello.open] ino=%lu, fi=%p, fi->flags=%08X", ino, fi, fi->flags); |
|
191 |
||
192 |
if (ino != 2) { |
|
193 |
// must open our only file, not the dir |
|
194 |
fuse_reply_err(req, ino == 1 ? EISDIR : ENOENT); |
|
195 |
return; |
|
196 |
||
197 |
} else if ((fi->flags & 0x03) != O_RDONLY) { |
|
198 |
// "permission denied" |
|
199 |
fuse_reply_err(req, EACCES); |
|
200 |
return; |
|
201 |
} |
|
202 |
||
203 |
// XXX: update fi stuff? |
|
204 |
||
205 |
// open it! |
|
206 |
if ((err = fuse_reply_open(req, fi))) |
|
207 |
EERROR(err, "fuse_reply_open"); |
|
208 |
||
209 |
// success |
|
210 |
return; |
|
211 |
||
212 |
error: |
|
213 |
if ((err = fuse_reply_err(req, err ? err : EIO))) |
|
214 |
EWARNING(err, "failed to send error reply"); |
|
215 |
} |
|
216 |
||
217 |
void hello_read (fuse_req_t req, fuse_ino_t ino, size_t size, off_t off, struct fuse_file_info *fi) { |
|
218 |
int err = 0; |
|
219 |
||
220 |
// fi is unused |
|
221 |
(void) fi; |
|
222 |
||
223 |
INFO("[hello.read] ino=%lu, size=%zu, off=%zu, fi=%p", ino, size, off, fi); |
|
224 |
||
225 |
if (ino != 2) { |
|
226 |
// EEK! |
|
227 |
FATAL("wrong inode"); |
|
228 |
} |
|
229 |
||
5 | 230 |
if (off >= strlen(file_data)) { |
231 |
// offset is out-of-file, so return EOF |
|
232 |
err = fuse_reply_buf(req, NULL, 0); |
|
233 |
||
234 |
} else { |
|
235 |
// reply with the requested file data |
|
236 |
err = fuse_reply_buf(req, file_data + off, MIN(strlen(file_data) - off, size)); |
|
237 |
} |
|
4 | 238 |
|
239 |
// reply |
|
5 | 240 |
if (err) |
4 | 241 |
PERROR("fuse_reply_buf"); |
242 |
||
243 |
// success |
|
244 |
return; |
|
245 |
||
246 |
error: |
|
247 |
if ((err = fuse_reply_err(req, err ? err : EIO))) |
|
248 |
EWARNING(err, "failed to send error reply"); |
|
249 |
} |
|
250 |
||
6
d2036d7799fd
new 'simple' module, plus hello_simple
Tero Marttila <terom@fixme.fi>
parents:
5
diff
changeset
|
251 |
void hello_getxattr (fuse_req_t req, fuse_ino_t ino, const char *name, size_t size) { |
d2036d7799fd
new 'simple' module, plus hello_simple
Tero Marttila <terom@fixme.fi>
parents:
5
diff
changeset
|
252 |
INFO("[hello.getxattr] ino=%lu, name=`%s', size=%zu", ino, name, size); |
d2036d7799fd
new 'simple' module, plus hello_simple
Tero Marttila <terom@fixme.fi>
parents:
5
diff
changeset
|
253 |
|
d2036d7799fd
new 'simple' module, plus hello_simple
Tero Marttila <terom@fixme.fi>
parents:
5
diff
changeset
|
254 |
fuse_reply_err(req, ENOSYS); |
d2036d7799fd
new 'simple' module, plus hello_simple
Tero Marttila <terom@fixme.fi>
parents:
5
diff
changeset
|
255 |
} |
d2036d7799fd
new 'simple' module, plus hello_simple
Tero Marttila <terom@fixme.fi>
parents:
5
diff
changeset
|
256 |
|
1 | 257 |
struct fuse_lowlevel_ops hello_llops = { |
258 |
.init = &hello_init, |
|
259 |
.destroy = &hello_destroy, |
|
2 | 260 |
|
261 |
.lookup = &hello_lookup, |
|
262 |
.getattr = &hello_getattr, |
|
263 |
||
4 | 264 |
.open = &hello_open, |
265 |
||
266 |
.read = &hello_read, |
|
267 |
||
2 | 268 |
.readdir = &hello_readdir, |
6
d2036d7799fd
new 'simple' module, plus hello_simple
Tero Marttila <terom@fixme.fi>
parents:
5
diff
changeset
|
269 |
|
d2036d7799fd
new 'simple' module, plus hello_simple
Tero Marttila <terom@fixme.fi>
parents:
5
diff
changeset
|
270 |
.getxattr = hello_getxattr, |
1 | 271 |
}; |
272 |
||
273 |
||
274 |
int main (int argc, char **argv) { |
|
275 |
struct fuse_args fuse_args = FUSE_ARGS_INIT(argc, argv); |
|
3 | 276 |
|
277 |
// zero |
|
278 |
memset(&ctx, 0, sizeof(ctx)); |
|
1 | 279 |
|
280 |
// init libevent |
|
281 |
if ((ctx.ev_base = event_base_new()) == NULL) |
|
3 | 282 |
ERROR("event_base_new"); |
1 | 283 |
|
3 | 284 |
// setup signals |
285 |
if ((ctx.signals = signals_default(ctx.ev_base)) == NULL) |
|
286 |
ERROR("signals_default"); |
|
287 |
||
1 | 288 |
// open fuse |
289 |
if ((ctx.ev_fuse = evfuse_new(ctx.ev_base, &fuse_args, &hello_llops, &ctx)) == NULL) |
|
3 | 290 |
ERROR("evfuse_new"); |
1 | 291 |
|
292 |
// run libevent |
|
293 |
INFO("running libevent loop"); |
|
294 |
||
295 |
if (event_base_dispatch(ctx.ev_base)) |
|
3 | 296 |
PERROR("event_base_dispatch"); |
297 |
||
298 |
// clean shutdown |
|
1 | 299 |
|
3 | 300 |
error : |
1 | 301 |
// cleanup |
3 | 302 |
if (ctx.ev_fuse) |
303 |
evfuse_close(ctx.ev_fuse); |
|
304 |
||
305 |
if (ctx.signals) |
|
306 |
signals_free(ctx.signals); |
|
307 |
||
308 |
if (ctx.ev_base) |
|
309 |
event_base_free(ctx.ev_base); |
|
310 |
||
311 |
fuse_opt_free_args(&fuse_args); |
|
1 | 312 |
} |
313 |