blob: b12c58d2334fb25d90e2d4efbbcaf783176c5a9c [file] [log] [blame]
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001/*
2 FUSE: Filesystem in Userspace
3 Copyright (C) 2001 Miklos Szeredi (mszeredi@inf.bme.hu)
4
5 This program can be distributed under the terms of the GNU GPL.
6 See the file COPYING.
7*/
8
9#include "fuse_i.h"
10#include <linux/fuse.h>
11
Miklos Szeredia181e612001-11-06 12:03:23 +000012
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000013#include <string.h>
14#include <unistd.h>
15#include <errno.h>
Miklos Szeredi19dff1b2001-10-30 15:06:52 +000016#include <assert.h>
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000017
18
Miklos Szeredia181e612001-11-06 12:03:23 +000019static inline struct node *get_node(fino_t ino)
20{
21 return (struct node *) ((ino << 3) + 0x8000000);
22}
23
24static inline fino_t get_ino(struct node *node)
25{
26 return (((fino_t) node) - 0x8000000) >> 3;
27}
28
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000029static guint name_hash(const struct node *node)
30{
31 return g_str_hash(node->name) ^ node->parent;
32}
33
34static gint name_compare(const struct node *node1, const struct node *node2)
35{
36 return
37 node1->parent == node2->parent &&
38 strcmp(node1->name, node2->name) == 0;
39}
40
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000041static int free_node(struct node *node)
42{
43 g_free(node->name);
44 g_free(node);
45 return 1;
46}
47
Miklos Szeredi19dff1b2001-10-30 15:06:52 +000048static struct node *lookup_node(struct fuse *f, fino_t parent,
49 const char *name)
50{
51 struct node tmp;
52
53 tmp.name = (char *) name;
54 tmp.parent = parent;
55
56 return g_hash_table_lookup(f->nametab, &tmp);
57}
58
Miklos Szeredia181e612001-11-06 12:03:23 +000059static void hash_node(struct fuse *f, struct node *node, fino_t parent,
60 const char *name)
Miklos Szeredi5e183482001-10-31 14:52:35 +000061{
Miklos Szeredia181e612001-11-06 12:03:23 +000062 node->name = g_strdup(name);
63 node->parent = parent;
64 g_hash_table_insert(f->nametab, node, node);
Miklos Szeredi5e183482001-10-31 14:52:35 +000065}
66
Miklos Szeredia181e612001-11-06 12:03:23 +000067static void unhash_node(struct fuse *f, struct node *node)
68{
69 if(node->name != NULL) {
70 g_hash_table_remove(f->nametab, node);
71 g_free(node->name);
72 node->parent = 0;
73 node->name = NULL;
74 }
75}
76
77static fino_t find_node(struct fuse *f, fino_t parent, char *name,
78 struct fuse_attr *attr, int version)
Miklos Szeredi5e183482001-10-31 14:52:35 +000079{
80 struct node *node;
Miklos Szeredia181e612001-11-06 12:03:23 +000081 int mode = attr->mode & S_IFMT;
82 int rdev = 0;
83
84 if(S_ISCHR(mode) || S_ISBLK(mode))
85 rdev = attr->rdev;
Miklos Szeredi5e183482001-10-31 14:52:35 +000086
Miklos Szeredia181e612001-11-06 12:03:23 +000087 pthread_mutex_lock(&f->lock);
Miklos Szeredi5e183482001-10-31 14:52:35 +000088 node = lookup_node(f, parent, name);
89 if(node != NULL) {
Miklos Szeredia181e612001-11-06 12:03:23 +000090 if(node->mode == mode && node->rdev == rdev)
91 goto out;
92
Miklos Szeredi5e183482001-10-31 14:52:35 +000093 unhash_node(f, node);
94 }
95
Miklos Szeredia181e612001-11-06 12:03:23 +000096 node = g_new0(struct node, 1);
97 node->mode = mode;
98 node->rdev = rdev;
99 hash_node(f, node, parent, name);
100
101 out:
102 node->version = version;
103 pthread_mutex_unlock(&f->lock);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000104 return get_ino(node);
105}
106
107static fino_t find_node_dir(struct fuse *f, fino_t parent, char *name)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000108{
109 struct node *node;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000110
Miklos Szeredia181e612001-11-06 12:03:23 +0000111 pthread_mutex_lock(&f->lock);
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000112 node = lookup_node(f, parent, name);
Miklos Szeredia181e612001-11-06 12:03:23 +0000113 pthread_mutex_unlock(&f->lock);
114
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000115 if(node != NULL)
116 return get_ino(node);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000117 else
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000118 return (fino_t) -1;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000119}
120
Miklos Szeredia181e612001-11-06 12:03:23 +0000121static char *get_path(struct fuse *f, fino_t ino)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000122{
123 GString *s;
124 char *ss;
125
126 s = g_string_new("");
127 if(ino == FUSE_ROOT_INO)
128 g_string_prepend_c(s, '/');
129 else {
130 struct node *node;
Miklos Szeredia181e612001-11-06 12:03:23 +0000131 pthread_mutex_lock(&f->lock);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000132 for(; ino != FUSE_ROOT_INO; ino = node->parent) {
133 node = get_node(ino);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000134 if(node->name == NULL) {
Miklos Szeredia181e612001-11-06 12:03:23 +0000135 pthread_mutex_unlock(&f->lock);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000136 g_string_free(s, TRUE);
137 return NULL;
138 }
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000139 g_string_prepend(s, node->name);
140 g_string_prepend_c(s, '/');
141 }
Miklos Szeredia181e612001-11-06 12:03:23 +0000142 pthread_mutex_unlock(&f->lock);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000143 }
144
145 ss = s->str;
146 g_string_free(s, FALSE);
147
148 return ss;
149}
150
Miklos Szeredia181e612001-11-06 12:03:23 +0000151static char *get_path_name(struct fuse *f, fino_t ino, const char *name)
Miklos Szeredib483c932001-10-29 14:57:57 +0000152{
Miklos Szeredi5e183482001-10-31 14:52:35 +0000153 char *path2;
Miklos Szeredia181e612001-11-06 12:03:23 +0000154 char *path;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000155
Miklos Szeredia181e612001-11-06 12:03:23 +0000156 if(ino == FUSE_ROOT_INO)
157 return g_strconcat("/", name, NULL);
158
159 path = get_path(f, ino);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000160 if(path == NULL)
161 return NULL;
Miklos Szeredia181e612001-11-06 12:03:23 +0000162
Miklos Szeredi5e183482001-10-31 14:52:35 +0000163 path2 = g_strconcat(path, "/", name, NULL);
Miklos Szeredib483c932001-10-29 14:57:57 +0000164 g_free(path);
Miklos Szeredia181e612001-11-06 12:03:23 +0000165
Miklos Szeredib483c932001-10-29 14:57:57 +0000166 return path2;
167}
168
Miklos Szeredia181e612001-11-06 12:03:23 +0000169static void destroy_node(struct fuse *f, fino_t ino, int version)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000170{
Miklos Szeredia181e612001-11-06 12:03:23 +0000171 struct node *node;
172
173 pthread_mutex_lock(&f->lock);
174 node = get_node(ino);
175 if(node->version == version) {
176 unhash_node(f, node);
177 free_node(node);
178 }
179 pthread_mutex_unlock(&f->lock);
180
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000181}
182
Miklos Szeredi5e183482001-10-31 14:52:35 +0000183static void remove_node(struct fuse *f, fino_t dir, const char *name)
184{
Miklos Szeredia181e612001-11-06 12:03:23 +0000185 struct node *node;
186
187 pthread_mutex_lock(&f->lock);
188 node = lookup_node(f, dir, name);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000189 assert(node != NULL);
190 unhash_node(f, node);
Miklos Szeredia181e612001-11-06 12:03:23 +0000191 pthread_mutex_unlock(&f->lock);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000192}
193
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000194static void rename_node(struct fuse *f, fino_t olddir, const char *oldname,
195 fino_t newdir, const char *newname)
196{
Miklos Szeredia181e612001-11-06 12:03:23 +0000197 struct node *node;
198 struct node *newnode;
199
200 pthread_mutex_lock(&f->lock);
201 node = lookup_node(f, olddir, oldname);
202 newnode = lookup_node(f, newdir, newname);
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000203 assert(node != NULL);
204
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000205 if(newnode != NULL)
Miklos Szeredi5e183482001-10-31 14:52:35 +0000206 unhash_node(f, newnode);
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000207
Miklos Szeredia181e612001-11-06 12:03:23 +0000208 unhash_node(f, node);
209 hash_node(f, node, newdir, newname);
210 pthread_mutex_unlock(&f->lock);
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000211}
212
213
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000214static void convert_stat(struct stat *stbuf, struct fuse_attr *attr)
215{
216 attr->mode = stbuf->st_mode;
217 attr->nlink = stbuf->st_nlink;
218 attr->uid = stbuf->st_uid;
219 attr->gid = stbuf->st_gid;
220 attr->rdev = stbuf->st_rdev;
221 attr->size = stbuf->st_size;
222 attr->blksize = stbuf->st_blksize;
223 attr->blocks = stbuf->st_blocks;
224 attr->atime = stbuf->st_atime;
225 attr->mtime = stbuf->st_mtime;
226 attr->ctime = stbuf->st_ctime;
227}
228
Miklos Szeredia181e612001-11-06 12:03:23 +0000229static int fill_dir(struct fuse_dirhandle *dh, char *name, int type)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000230{
231 struct fuse_dirent dirent;
232 size_t reclen;
233 size_t res;
234
Miklos Szeredi5e183482001-10-31 14:52:35 +0000235 dirent.ino = find_node_dir(dh->fuse, dh->dir, name);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000236 dirent.namelen = strlen(name);
237 strncpy(dirent.name, name, sizeof(dirent.name));
238 dirent.type = type;
239 reclen = FUSE_DIRENT_SIZE(&dirent);
240 res = fwrite(&dirent, reclen, 1, dh->fp);
241 if(res == 0) {
242 perror("writing directory file");
243 return -EIO;
244 }
245 return 0;
246}
247
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000248static void send_reply(struct fuse *f, struct fuse_in_header *in, int error,
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000249 void *arg, size_t argsize)
250{
251 int res;
252 char *outbuf;
253 size_t outsize;
254 struct fuse_out_header *out;
255
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000256 if(error > 0) {
257 fprintf(stderr, "positive error code: %i\n", error);
258 error = -ERANGE;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000259 }
260
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000261 if(error)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000262 argsize = 0;
263
264 outsize = sizeof(struct fuse_out_header) + argsize;
265 outbuf = (char *) g_malloc(outsize);
266 out = (struct fuse_out_header *) outbuf;
267 out->unique = in->unique;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000268 out->error = error;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000269 if(argsize != 0)
270 memcpy(outbuf + sizeof(struct fuse_out_header), arg, argsize);
271
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000272 printf(" unique: %i, error: %i (%s), outsize: %i\n", out->unique,
273 out->error, strerror(-out->error), outsize);
Miklos Szeredia181e612001-11-06 12:03:23 +0000274 fflush(stdout);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000275
276 res = write(f->fd, outbuf, outsize);
277 if(res == -1)
278 perror("writing fuse device");
279
280 g_free(outbuf);
281}
282
Miklos Szeredia181e612001-11-06 12:03:23 +0000283static void fill_cred(struct fuse_in_header *in, struct fuse_cred *cred)
284{
285 cred->uid = in->uid;
286 cred->gid = in->gid;
287}
288
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000289static void do_lookup(struct fuse *f, struct fuse_in_header *in, char *name)
290{
291 int res;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000292 char *path;
293 struct stat buf;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000294 struct fuse_lookup_out arg;
Miklos Szeredia181e612001-11-06 12:03:23 +0000295 struct fuse_cred cred;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000296
Miklos Szeredia181e612001-11-06 12:03:23 +0000297 fill_cred(in, &cred);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000298 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000299 path = get_path_name(f, in->ino, name);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000300 if(path != NULL) {
301 res = -ENOSYS;
302 if(f->op.getattr)
Miklos Szeredia181e612001-11-06 12:03:23 +0000303 res = f->op.getattr(&cred, path, &buf);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000304 g_free(path);
305 }
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000306 if(res == 0) {
307 convert_stat(&buf, &arg.attr);
Miklos Szeredia181e612001-11-06 12:03:23 +0000308 arg.ino = find_node(f, in->ino, name, &arg.attr, in->unique);
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000309 }
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000310 send_reply(f, in, res, &arg, sizeof(arg));
311}
312
Miklos Szeredia181e612001-11-06 12:03:23 +0000313static void do_forget(struct fuse *f, struct fuse_in_header *in,
314 struct fuse_forget_in *arg)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000315{
Miklos Szeredia181e612001-11-06 12:03:23 +0000316 destroy_node(f, in->ino, arg->version);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000317}
318
319static void do_getattr(struct fuse *f, struct fuse_in_header *in)
320{
321 int res;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000322 char *path;
323 struct stat buf;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000324 struct fuse_getattr_out arg;
Miklos Szeredia181e612001-11-06 12:03:23 +0000325 struct fuse_cred cred;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000326
Miklos Szeredia181e612001-11-06 12:03:23 +0000327 fill_cred(in, &cred);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000328 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000329 path = get_path(f, in->ino);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000330 if(path != NULL) {
331 res = -ENOSYS;
332 if(f->op.getattr)
Miklos Szeredia181e612001-11-06 12:03:23 +0000333 res = f->op.getattr(&cred, path, &buf);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000334 g_free(path);
335 }
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000336 if(res == 0)
337 convert_stat(&buf, &arg.attr);
338
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000339 send_reply(f, in, res, &arg, sizeof(arg));
340}
341
Miklos Szeredi5e183482001-10-31 14:52:35 +0000342static void do_setattr(struct fuse *f, struct fuse_in_header *in,
343 struct fuse_setattr_in *arg)
344{
345 int res;
346 char *path;
347 int valid = arg->valid;
348 struct fuse_attr *attr = &arg->attr;
Miklos Szeredia181e612001-11-06 12:03:23 +0000349 struct fuse_setattr_out outarg;
350 struct fuse_cred cred;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000351
Miklos Szeredia181e612001-11-06 12:03:23 +0000352 fill_cred(in, &cred);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000353 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000354 path = get_path(f, in->ino);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000355 if(path != NULL) {
356 res = 0;
357 if(!res && (valid & FATTR_MODE)) {
358 res = -ENOSYS;
359 if(f->op.chmod)
Miklos Szeredia181e612001-11-06 12:03:23 +0000360 res = f->op.chmod(&cred, path, attr->mode);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000361 }
362 if(!res && (valid & (FATTR_UID | FATTR_GID))) {
363 uid_t uid = (valid & FATTR_UID) ? attr->uid : (uid_t) -1;
364 gid_t gid = (valid & FATTR_GID) ? attr->gid : (gid_t) -1;
365
366 res = -ENOSYS;
367 if(f->op.chown)
Miklos Szeredia181e612001-11-06 12:03:23 +0000368 res = f->op.chown(&cred, path, uid, gid);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000369 }
370 if(!res && (valid & FATTR_SIZE)) {
371 res = -ENOSYS;
Miklos Szeredia181e612001-11-06 12:03:23 +0000372 if(f->op.truncate && f->op.getattr) {
373 res = f->op.truncate(&cred, path, attr->size);
374 if(!res) {
375 struct stat buf;
376 res = f->op.getattr(&cred, path, &buf);
377 outarg.newsize = buf.st_size;
378 }
379 }
Miklos Szeredi5e183482001-10-31 14:52:35 +0000380 }
381 if(!res && (valid & FATTR_UTIME)) {
382 struct utimbuf buf;
383 buf.actime = attr->atime;
384 buf.modtime = attr->mtime;
385 res = -ENOSYS;
386 if(f->op.utime)
Miklos Szeredia181e612001-11-06 12:03:23 +0000387 res = f->op.utime(&cred, path, &buf);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000388 }
389 g_free(path);
390 }
Miklos Szeredia181e612001-11-06 12:03:23 +0000391 send_reply(f, in, res, &outarg, sizeof(outarg));
Miklos Szeredi5e183482001-10-31 14:52:35 +0000392}
393
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000394static void do_readlink(struct fuse *f, struct fuse_in_header *in)
395{
396 int res;
397 char link[PATH_MAX + 1];
Miklos Szeredib483c932001-10-29 14:57:57 +0000398 char *path;
Miklos Szeredia181e612001-11-06 12:03:23 +0000399 struct fuse_cred cred;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000400
Miklos Szeredia181e612001-11-06 12:03:23 +0000401 fill_cred(in, &cred);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000402 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000403 path = get_path(f, in->ino);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000404 if(path != NULL) {
405 res = -ENOSYS;
406 if(f->op.readlink)
Miklos Szeredia181e612001-11-06 12:03:23 +0000407 res = f->op.readlink(&cred, path, link, sizeof(link));
Miklos Szeredi5e183482001-10-31 14:52:35 +0000408 g_free(path);
409 }
Miklos Szeredi2df1c042001-11-06 15:07:17 +0000410 link[PATH_MAX] = '\0';
Miklos Szeredi5e183482001-10-31 14:52:35 +0000411 send_reply(f, in, res, link, !res ? strlen(link) : 0);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000412}
413
414static void do_getdir(struct fuse *f, struct fuse_in_header *in)
415{
416 int res;
417 struct fuse_getdir_out arg;
Miklos Szeredia181e612001-11-06 12:03:23 +0000418 struct fuse_dirhandle dh;
Miklos Szeredib483c932001-10-29 14:57:57 +0000419 char *path;
Miklos Szeredia181e612001-11-06 12:03:23 +0000420 struct fuse_cred cred;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000421
Miklos Szeredia181e612001-11-06 12:03:23 +0000422 fill_cred(in, &cred);
Miklos Szeredib483c932001-10-29 14:57:57 +0000423 dh.fuse = f;
424 dh.fp = tmpfile();
425 dh.dir = in->ino;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000426 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000427 path = get_path(f, in->ino);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000428 if(path != NULL) {
429 res = -ENOSYS;
430 if(f->op.getdir)
Miklos Szeredia181e612001-11-06 12:03:23 +0000431 res = f->op.getdir(&cred, path, &dh, (fuse_dirfil_t) fill_dir);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000432 g_free(path);
433 }
Miklos Szeredib483c932001-10-29 14:57:57 +0000434 fflush(dh.fp);
435 arg.fd = fileno(dh.fp);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000436 send_reply(f, in, res, &arg, sizeof(arg));
Miklos Szeredib483c932001-10-29 14:57:57 +0000437 fclose(dh.fp);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000438}
439
Miklos Szeredib483c932001-10-29 14:57:57 +0000440static void do_mknod(struct fuse *f, struct fuse_in_header *in,
441 struct fuse_mknod_in *inarg)
442{
443 int res;
444 char *path;
445 struct fuse_mknod_out outarg;
446 struct stat buf;
Miklos Szeredia181e612001-11-06 12:03:23 +0000447 struct fuse_cred cred;
Miklos Szeredib483c932001-10-29 14:57:57 +0000448
Miklos Szeredia181e612001-11-06 12:03:23 +0000449 fill_cred(in, &cred);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000450 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000451 path = get_path_name(f, in->ino, inarg->name);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000452 if(path != NULL) {
453 res = -ENOSYS;
454 if(f->op.mknod && f->op.getattr) {
Miklos Szeredia181e612001-11-06 12:03:23 +0000455 res = f->op.mknod(&cred, path, inarg->mode, inarg->rdev);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000456 if(res == 0)
Miklos Szeredia181e612001-11-06 12:03:23 +0000457 res = f->op.getattr(&cred, path, &buf);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000458 }
459 g_free(path);
Miklos Szeredib483c932001-10-29 14:57:57 +0000460 }
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000461 if(res == 0) {
Miklos Szeredib483c932001-10-29 14:57:57 +0000462 convert_stat(&buf, &outarg.attr);
Miklos Szeredia181e612001-11-06 12:03:23 +0000463 outarg.ino = find_node(f, in->ino, inarg->name, &outarg.attr,
464 in->unique);
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000465 }
Miklos Szeredib483c932001-10-29 14:57:57 +0000466
467 send_reply(f, in, res, &outarg, sizeof(outarg));
468}
469
470static void do_mkdir(struct fuse *f, struct fuse_in_header *in,
471 struct fuse_mkdir_in *inarg)
472{
473 int res;
474 char *path;
Miklos Szeredia181e612001-11-06 12:03:23 +0000475 struct fuse_cred cred;
Miklos Szeredib483c932001-10-29 14:57:57 +0000476
Miklos Szeredia181e612001-11-06 12:03:23 +0000477 fill_cred(in, &cred);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000478 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000479 path = get_path_name(f, in->ino, inarg->name);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000480 if(path != NULL) {
481 res = -ENOSYS;
482 if(f->op.mkdir)
Miklos Szeredia181e612001-11-06 12:03:23 +0000483 res = f->op.mkdir(&cred, path, inarg->mode);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000484 g_free(path);
485 }
Miklos Szeredib483c932001-10-29 14:57:57 +0000486 send_reply(f, in, res, NULL, 0);
487}
488
489static void do_remove(struct fuse *f, struct fuse_in_header *in, char *name)
490{
491 int res;
492 char *path;
Miklos Szeredia181e612001-11-06 12:03:23 +0000493 struct fuse_cred cred;
Miklos Szeredib483c932001-10-29 14:57:57 +0000494
Miklos Szeredia181e612001-11-06 12:03:23 +0000495 fill_cred(in, &cred);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000496 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000497 path = get_path_name(f, in->ino, name);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000498 if(path != NULL) {
499 res = -ENOSYS;
500 if(in->opcode == FUSE_UNLINK) {
501 if(f->op.unlink)
Miklos Szeredia181e612001-11-06 12:03:23 +0000502 res = f->op.unlink(&cred, path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000503 }
504 else {
505 if(f->op.rmdir)
Miklos Szeredia181e612001-11-06 12:03:23 +0000506 res = f->op.rmdir(&cred, path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000507 }
508 g_free(path);
Miklos Szeredib483c932001-10-29 14:57:57 +0000509 }
Miklos Szeredi5e183482001-10-31 14:52:35 +0000510 if(res == 0)
511 remove_node(f, in->ino, name);
Miklos Szeredib483c932001-10-29 14:57:57 +0000512 send_reply(f, in, res, NULL, 0);
513}
514
515static void do_symlink(struct fuse *f, struct fuse_in_header *in, char *name,
516 char *link)
517{
518 int res;
519 char *path;
Miklos Szeredia181e612001-11-06 12:03:23 +0000520 struct fuse_cred cred;
Miklos Szeredib483c932001-10-29 14:57:57 +0000521
Miklos Szeredia181e612001-11-06 12:03:23 +0000522 fill_cred(in, &cred);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000523 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000524 path = get_path_name(f, in->ino, name);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000525 if(path != NULL) {
526 res = -ENOSYS;
527 if(f->op.symlink)
Miklos Szeredia181e612001-11-06 12:03:23 +0000528 res = f->op.symlink(&cred, link, path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000529 g_free(path);
530 }
Miklos Szeredib483c932001-10-29 14:57:57 +0000531 send_reply(f, in, res, NULL, 0);
532}
533
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000534static void do_rename(struct fuse *f, struct fuse_in_header *in,
535 struct fuse_rename_in *inarg)
536{
537 int res;
538 fino_t olddir = in->ino;
539 fino_t newdir = inarg->newdir;
540 char *oldname = inarg->names;
541 char *newname = inarg->names + strlen(oldname) + 1;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000542 char *oldpath;
543 char *newpath;
Miklos Szeredia181e612001-11-06 12:03:23 +0000544 struct fuse_cred cred;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000545
Miklos Szeredia181e612001-11-06 12:03:23 +0000546 fill_cred(in, &cred);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000547 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000548 oldpath = get_path_name(f, olddir, oldname);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000549 if(oldpath != NULL) {
Miklos Szeredia181e612001-11-06 12:03:23 +0000550 newpath = get_path_name(f, newdir, newname);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000551 if(newpath != NULL) {
552 res = -ENOSYS;
553 if(f->op.rename)
Miklos Szeredia181e612001-11-06 12:03:23 +0000554 res = f->op.rename(&cred, oldpath, newpath);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000555 if(res == 0)
556 rename_node(f, olddir, oldname, newdir, newname);
557 g_free(newpath);
558 }
559 g_free(oldpath);
560 }
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000561 send_reply(f, in, res, NULL, 0);
562}
563
564static void do_link(struct fuse *f, struct fuse_in_header *in,
Miklos Szeredi5e183482001-10-31 14:52:35 +0000565 struct fuse_link_in *arg)
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000566{
567 int res;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000568 char *oldpath;
569 char *newpath;
Miklos Szeredia181e612001-11-06 12:03:23 +0000570 struct fuse_cred cred;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000571
Miklos Szeredia181e612001-11-06 12:03:23 +0000572 fill_cred(in, &cred);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000573 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000574 oldpath = get_path(f, in->ino);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000575 if(oldpath != NULL) {
Miklos Szeredia181e612001-11-06 12:03:23 +0000576 newpath = get_path_name(f, arg->newdir, arg->name);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000577 if(newpath != NULL) {
578 res = -ENOSYS;
579 if(f->op.link)
Miklos Szeredia181e612001-11-06 12:03:23 +0000580 res = f->op.link(&cred, oldpath, newpath);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000581 g_free(newpath);
582 }
583 g_free(oldpath);
584 }
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000585 send_reply(f, in, res, NULL, 0);
586}
587
Miklos Szeredi5e183482001-10-31 14:52:35 +0000588static void do_open(struct fuse *f, struct fuse_in_header *in,
589 struct fuse_open_in *arg)
590{
591 int res;
592 char *path;
Miklos Szeredia181e612001-11-06 12:03:23 +0000593 struct fuse_cred cred;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000594
Miklos Szeredia181e612001-11-06 12:03:23 +0000595 fill_cred(in, &cred);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000596 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000597 path = get_path(f, in->ino);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000598 if(path != NULL) {
599 res = -ENOSYS;
600 if(f->op.open)
Miklos Szeredia181e612001-11-06 12:03:23 +0000601 res = f->op.open(&cred, path, arg->flags);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000602 g_free(path);
603 }
604 send_reply(f, in, res, NULL, 0);
605}
606
607static void do_read(struct fuse *f, struct fuse_in_header *in,
608 struct fuse_read_in *arg)
609{
610 int res;
611 char *path;
612 char *buf = g_malloc(arg->size);
613 size_t size;
Miklos Szeredia181e612001-11-06 12:03:23 +0000614 struct fuse_cred cred;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000615
Miklos Szeredia181e612001-11-06 12:03:23 +0000616 fill_cred(in, &cred);
617 path = get_path(f, in->ino);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000618 if(path != NULL) {
619 res = -ENOSYS;
Miklos Szeredia181e612001-11-06 12:03:23 +0000620 if(f->op.read)
621 res = f->op.read(&cred, path, buf, arg->size, arg->offset);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000622 g_free(path);
623 }
624
625 size = 0;
626 if(res > 0) {
627 size = res;
628 res = 0;
629 }
630
631 send_reply(f, in, res, buf, size);
632 g_free(buf);
633}
Miklos Szeredib483c932001-10-29 14:57:57 +0000634
Miklos Szeredia181e612001-11-06 12:03:23 +0000635static void do_write(struct fuse *f, struct fuse_in_header *in,
636 struct fuse_write_in *arg)
637{
638 int res;
639 char *path;
640 struct fuse_cred cred;
641
642 fill_cred(in, &cred);
643 path = get_path(f, in->ino);
644 if(path != NULL) {
645 res = -ENOSYS;
646 if(f->op.write)
647 res = f->op.write(&cred, path, arg->buf, arg->size, arg->offset);
648 g_free(path);
649 }
650
651 if(res > 0) {
652 if((size_t) res != arg->size) {
653 fprintf(stderr, "short write: %u (should be %u)\n", res,
654 arg->size);
655 res = -EIO;
656 }
657 else
658 res = 0;
659 }
660
661 send_reply(f, in, res, NULL, 0);
662}
663
664struct cmd {
665 struct fuse *f;
666 char *buf;
667 size_t buflen;
668};
669
670static void *do_command(void *data)
671{
672 struct cmd *cmd = (struct cmd *) data;
673 struct fuse_in_header *in = (struct fuse_in_header *) cmd->buf;
674 void *inarg = cmd->buf + sizeof(struct fuse_in_header);
675 size_t argsize;
676 struct fuse *f = cmd->f;
677
678 printf("unique: %i, opcode: %i, ino: %li, insize: %i\n", in->unique,
679 in->opcode, in->ino, cmd->buflen);
680 fflush(stdout);
681
682 argsize = cmd->buflen - sizeof(struct fuse_in_header);
683
684 switch(in->opcode) {
685 case FUSE_LOOKUP:
686 do_lookup(f, in, (char *) inarg);
687 break;
688
689 case FUSE_FORGET:
690 do_forget(f, in, (struct fuse_forget_in *) inarg);
691 break;
692
693 case FUSE_GETATTR:
694 do_getattr(f, in);
695 break;
696
697 case FUSE_SETATTR:
698 do_setattr(f, in, (struct fuse_setattr_in *) inarg);
699 break;
700
701 case FUSE_READLINK:
702 do_readlink(f, in);
703 break;
704
705 case FUSE_GETDIR:
706 do_getdir(f, in);
707 break;
708
709 case FUSE_MKNOD:
710 do_mknod(f, in, (struct fuse_mknod_in *) inarg);
711 break;
712
713 case FUSE_MKDIR:
714 do_mkdir(f, in, (struct fuse_mkdir_in *) inarg);
715 break;
716
717 case FUSE_UNLINK:
718 case FUSE_RMDIR:
719 do_remove(f, in, (char *) inarg);
720 break;
721
722 case FUSE_SYMLINK:
723 do_symlink(f, in, (char *) inarg,
724 ((char *) inarg) + strlen((char *) inarg) + 1);
725 break;
726
727 case FUSE_RENAME:
728 do_rename(f, in, (struct fuse_rename_in *) inarg);
729 break;
730
731 case FUSE_LINK:
732 do_link(f, in, (struct fuse_link_in *) inarg);
733 break;
734
735 case FUSE_OPEN:
736 do_open(f, in, (struct fuse_open_in *) inarg);
737 break;
738
739 case FUSE_READ:
740 do_read(f, in, (struct fuse_read_in *) inarg);
741 break;
742
743 case FUSE_WRITE:
744 do_write(f, in, (struct fuse_write_in *) inarg);
745 break;
746
747 default:
748 fprintf(stderr, "Operation %i not implemented\n", in->opcode);
749 /* No need to send reply to async requests */
750 if(in->unique != 0)
751 send_reply(f, in, -ENOSYS, NULL, 0);
752 }
753
754 g_free(cmd->buf);
755 g_free(cmd);
756
757 return NULL;
758}
759
Miklos Szeredi2df1c042001-11-06 15:07:17 +0000760/* This hack makes it possible to link FUSE with or without the
761 pthread library */
762__attribute__((weak))
763int pthread_create(pthread_t *thrid __attribute__((unused)),
764 const pthread_attr_t *attr __attribute__((unused)),
765 void *(*func)(void *) __attribute__((unused)),
766 void *arg __attribute__((unused)))
767{
768 return ENOSYS;
769}
770
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000771void fuse_loop(struct fuse *f)
772{
773 int res;
774 char inbuf[FUSE_MAX_IN];
Miklos Szeredia181e612001-11-06 12:03:23 +0000775 pthread_attr_t attr;
776 pthread_t thrid;
777
778 pthread_attr_init(&attr);
779 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000780
781 while(1) {
Miklos Szeredia181e612001-11-06 12:03:23 +0000782 struct cmd *cmd;
783
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000784 res = read(f->fd, inbuf, sizeof(inbuf));
785 if(res == -1) {
786 perror("reading fuse device");
787 continue;
788 }
Miklos Szeredia181e612001-11-06 12:03:23 +0000789 if((size_t) res < sizeof(struct fuse_in_header)) {
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000790 fprintf(stderr, "short read on fuse device\n");
791 continue;
792 }
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000793
Miklos Szeredia181e612001-11-06 12:03:23 +0000794 cmd = g_new0(struct cmd, 1);
795 cmd->f = f;
796 cmd->buflen = res;
797 cmd->buf = g_malloc(cmd->buflen);
798 memcpy(cmd->buf, inbuf, cmd->buflen);
799
800 if(f->flags & FUSE_MULTITHREAD) {
801 res = pthread_create(&thrid, &attr, do_command, cmd);
Miklos Szeredi2df1c042001-11-06 15:07:17 +0000802 if(res == 0)
803 continue;
804
805 fprintf(stderr, "Error creating thread: %s\n", strerror(res));
806 fprintf(stderr, "Will run in single thread mode\n");
807 f->flags &= ~FUSE_MULTITHREAD;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000808 }
Miklos Szeredi2df1c042001-11-06 15:07:17 +0000809
810 do_command(cmd);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000811 }
812}
813
Miklos Szeredi2df1c042001-11-06 15:07:17 +0000814struct fuse *fuse_new(int flags, mode_t root)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000815{
816 struct fuse *f = g_new0(struct fuse, 1);
817
Miklos Szeredi2df1c042001-11-06 15:07:17 +0000818 if(!root)
819 root = S_IFDIR;
820
821 if(!S_ISDIR(root) && !S_ISREG(root)) {
822 fprintf(stderr, "Invalid mode for root: 0%o\n", root);
823 root = S_IFDIR;
824 }
825 root &= S_IFMT;
826
Miklos Szeredia181e612001-11-06 12:03:23 +0000827 f->flags = flags;
Miklos Szeredi2df1c042001-11-06 15:07:17 +0000828 f->rootmode = root;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000829 f->fd = -1;
Miklos Szeredi2df1c042001-11-06 15:07:17 +0000830 f->mnt = NULL;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000831 f->nametab = g_hash_table_new((GHashFunc) name_hash,
832 (GCompareFunc) name_compare);
Miklos Szeredia181e612001-11-06 12:03:23 +0000833 pthread_mutex_init(&f->lock, NULL);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000834
835 return f;
836}
837
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000838void fuse_set_operations(struct fuse *f, const struct fuse_operations *op)
839{
840 f->op = *op;
841}
842
843void fuse_destroy(struct fuse *f)
844{
Miklos Szeredia181e612001-11-06 12:03:23 +0000845 close(f->fd);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000846 g_hash_table_foreach_remove(f->nametab, (GHRFunc) free_node, NULL);
847 g_hash_table_destroy(f->nametab);
Miklos Szeredia181e612001-11-06 12:03:23 +0000848 pthread_mutex_destroy(&f->lock);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000849 g_free(f);
850}