|
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 |
|