blob: 2e6950d7c1a98ca77cad53012d430e078751b959 [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
Miklos Szeredi8b39a9f2002-10-25 12:41:16 +00005 This program can be distributed under the terms of the GNU LGPL.
6 See the file COPYING.LIB
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00007*/
8
9#include "fuse_i.h"
10#include <linux/fuse.h>
11
12#include <string.h>
Miklos Szeredi97c61e92001-11-07 12:09:43 +000013#include <stdlib.h>
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000014#include <unistd.h>
Miklos Szeredi97c61e92001-11-07 12:09:43 +000015#include <limits.h>
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000016#include <errno.h>
Miklos Szeredi019b4e92001-12-26 18:08:09 +000017#include <sys/param.h>
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000018
Miklos Szeredi97c61e92001-11-07 12:09:43 +000019#define FUSE_MAX_PATH 4096
Miklos Szeredi6bf8b682002-10-28 08:49:39 +000020#define PARAM(inarg) (((char *)(inarg)) + sizeof(*inarg))
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000021
Miklos Szeredic8ba2372002-12-10 12:26:00 +000022static const char *opname(enum fuse_opcode opcode)
23{
24 switch(opcode) {
25 case FUSE_LOOKUP: return "LOOKUP";
26 case FUSE_FORGET: return "FORGET";
27 case FUSE_GETATTR: return "GETATTR";
28 case FUSE_SETATTR: return "SETATTR";
29 case FUSE_READLINK: return "READLINK";
30 case FUSE_SYMLINK: return "SYMLINK";
31 case FUSE_GETDIR: return "GETDIR";
32 case FUSE_MKNOD: return "MKNOD";
33 case FUSE_MKDIR: return "MKDIR";
34 case FUSE_UNLINK: return "UNLINK";
35 case FUSE_RMDIR: return "RMDIR";
36 case FUSE_RENAME: return "RENAME";
37 case FUSE_LINK: return "LINK";
38 case FUSE_OPEN: return "OPEN";
39 case FUSE_READ: return "READ";
40 case FUSE_WRITE: return "WRITE";
41 case FUSE_STATFS: return "STATFS";
42 case FUSE_RELEASE: return "RELEASE";
Miklos Szeredi5e43f2c2003-12-12 14:06:41 +000043 case FUSE_FSYNC: return "FSYNC";
Miklos Szeredic8ba2372002-12-10 12:26:00 +000044 default: return "???";
45 }
46}
47
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +000048static inline void inc_avail(struct fuse *f)
49{
50 pthread_mutex_lock(&f->lock);
51 f->numavail ++;
52 pthread_mutex_unlock(&f->lock);
53}
54
55static inline void dec_avail(struct fuse *f)
56{
57 pthread_mutex_lock(&f->lock);
58 f->numavail --;
59 pthread_mutex_unlock(&f->lock);
60}
61
Miklos Szeredi97c61e92001-11-07 12:09:43 +000062static struct node *__get_node(struct fuse *f, fino_t ino)
Miklos Szeredia181e612001-11-06 12:03:23 +000063{
Miklos Szeredi97c61e92001-11-07 12:09:43 +000064 size_t hash = ino % f->ino_table_size;
65 struct node *node;
66
67 for(node = f->ino_table[hash]; node != NULL; node = node->ino_next)
68 if(node->ino == ino)
69 return node;
70
71 return NULL;
Miklos Szeredia181e612001-11-06 12:03:23 +000072}
73
Miklos Szeredi97c61e92001-11-07 12:09:43 +000074static struct node *get_node(struct fuse *f, fino_t ino)
Miklos Szeredia181e612001-11-06 12:03:23 +000075{
Miklos Szeredi97c61e92001-11-07 12:09:43 +000076 struct node *node = __get_node(f, ino);
77 if(node != NULL)
78 return node;
79
80 fprintf(stderr, "fuse internal error: inode %lu not found\n", ino);
81 abort();
Miklos Szeredia181e612001-11-06 12:03:23 +000082}
83
Miklos Szeredi76f65782004-02-19 16:55:40 +000084static void hash_ino(struct fuse *f, struct node *node)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000085{
Miklos Szeredi76f65782004-02-19 16:55:40 +000086 size_t hash = node->ino % f->ino_table_size;
Miklos Szeredi97c61e92001-11-07 12:09:43 +000087 node->ino_next = f->ino_table[hash];
88 f->ino_table[hash] = node;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000089}
90
Miklos Szeredi97c61e92001-11-07 12:09:43 +000091static void unhash_ino(struct fuse *f, struct node *node)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000092{
Miklos Szeredi97c61e92001-11-07 12:09:43 +000093 size_t hash = node->ino % f->ino_table_size;
94 struct node **nodep = &f->ino_table[hash];
95
96 for(; *nodep != NULL; nodep = &(*nodep)->ino_next)
97 if(*nodep == node) {
98 *nodep = node->ino_next;
99 return;
100 }
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000101}
102
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000103static fino_t next_ino(struct fuse *f)
104{
Miklos Szeredi76f65782004-02-19 16:55:40 +0000105 do {
106 f->ctr++;
107 if(!f->ctr)
108 f->generation ++;
109 } while(f->ctr == 0 || __get_node(f, f->ctr) != NULL);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000110 return f->ctr;
111}
112
113static void free_node(struct node *node)
114{
115 free(node->name);
116 free(node);
117}
118
119static unsigned int name_hash(struct fuse *f, fino_t parent, const char *name)
120{
121 unsigned int hash = *name;
122
123 if(hash)
124 for(name += 1; *name != '\0'; name++)
125 hash = (hash << 5) - hash + *name;
126
127 return (hash + parent) % f->name_table_size;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000128}
129
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000130static struct node *lookup_node(struct fuse *f, fino_t parent,
131 const char *name)
132{
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000133 size_t hash = name_hash(f, parent, name);
134 struct node *node;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000135
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000136 for(node = f->name_table[hash]; node != NULL; node = node->name_next)
137 if(node->parent == parent && strcmp(node->name, name) == 0)
138 return node;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000139
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000140 return NULL;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000141}
142
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000143static void hash_name(struct fuse *f, struct node *node, fino_t parent,
Miklos Szeredia181e612001-11-06 12:03:23 +0000144 const char *name)
Miklos Szeredi5e183482001-10-31 14:52:35 +0000145{
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000146 size_t hash = name_hash(f, parent, name);
Miklos Szeredia181e612001-11-06 12:03:23 +0000147 node->parent = parent;
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000148 node->name = strdup(name);
149 node->name_next = f->name_table[hash];
150 f->name_table[hash] = node;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000151}
152
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000153static void unhash_name(struct fuse *f, struct node *node)
Miklos Szeredia181e612001-11-06 12:03:23 +0000154{
155 if(node->name != NULL) {
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000156 size_t hash = name_hash(f, node->parent, node->name);
157 struct node **nodep = &f->name_table[hash];
158
159 for(; *nodep != NULL; nodep = &(*nodep)->name_next)
160 if(*nodep == node) {
161 *nodep = node->name_next;
162 node->name_next = NULL;
163 free(node->name);
164 node->name = NULL;
165 node->parent = 0;
166 return;
167 }
168 fprintf(stderr, "fuse internal error: unable to unhash node: %lu\n",
169 node->ino);
170 abort();
Miklos Szeredia181e612001-11-06 12:03:23 +0000171 }
172}
173
Miklos Szeredi76f65782004-02-19 16:55:40 +0000174static struct node *find_node(struct fuse *f, fino_t parent, char *name,
175 struct fuse_attr *attr, int version)
Miklos Szeredi5e183482001-10-31 14:52:35 +0000176{
177 struct node *node;
Miklos Szeredia181e612001-11-06 12:03:23 +0000178 int mode = attr->mode & S_IFMT;
179 int rdev = 0;
180
181 if(S_ISCHR(mode) || S_ISBLK(mode))
182 rdev = attr->rdev;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000183
Miklos Szeredia181e612001-11-06 12:03:23 +0000184 pthread_mutex_lock(&f->lock);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000185 node = lookup_node(f, parent, name);
186 if(node != NULL) {
Miklos Szeredia181e612001-11-06 12:03:23 +0000187 if(node->mode == mode && node->rdev == rdev)
188 goto out;
189
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000190 unhash_name(f, node);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000191 }
192
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000193 node = (struct node *) calloc(1, sizeof(struct node));
Miklos Szeredia181e612001-11-06 12:03:23 +0000194 node->mode = mode;
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000195 node->rdev = rdev;
Miklos Szeredi76f65782004-02-19 16:55:40 +0000196 node->ino = next_ino(f);
197 node->generation = f->generation;
198 hash_ino(f, node);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000199 hash_name(f, node, parent, name);
Miklos Szeredia181e612001-11-06 12:03:23 +0000200
201 out:
202 node->version = version;
203 pthread_mutex_unlock(&f->lock);
Miklos Szeredi76f65782004-02-19 16:55:40 +0000204 return node;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000205}
206
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000207static char *add_name(char *buf, char *s, const char *name)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000208{
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000209 size_t len = strlen(name);
210 s -= len;
211 if(s <= buf) {
212 fprintf(stderr, "fuse: path too long: ...%s\n", s + len);
213 return NULL;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000214 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000215 strncpy(s, name, len);
216 s--;
217 *s = '/';
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000218
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000219 return s;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000220}
221
Miklos Szeredia181e612001-11-06 12:03:23 +0000222static char *get_path_name(struct fuse *f, fino_t ino, const char *name)
Miklos Szeredib483c932001-10-29 14:57:57 +0000223{
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000224 char buf[FUSE_MAX_PATH];
225 char *s = buf + FUSE_MAX_PATH - 1;
226 struct node *node;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000227
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000228 *s = '\0';
Miklos Szeredia181e612001-11-06 12:03:23 +0000229
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000230 if(name != NULL) {
231 s = add_name(buf, s, name);
232 if(s == NULL)
233 return NULL;
234 }
235
236 pthread_mutex_lock(&f->lock);
237 for(node = get_node(f, ino); node->ino != FUSE_ROOT_INO;
238 node = get_node(f, node->parent)) {
239 if(node->name == NULL) {
240 s = NULL;
241 break;
242 }
243
244 s = add_name(buf, s, node->name);
245 if(s == NULL)
246 break;
247 }
248 pthread_mutex_unlock(&f->lock);
249
250 if(s == NULL)
Miklos Szeredi5e183482001-10-31 14:52:35 +0000251 return NULL;
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000252 else if(*s == '\0')
253 return strdup("/");
254 else
255 return strdup(s);
256}
Miklos Szeredia181e612001-11-06 12:03:23 +0000257
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000258static char *get_path(struct fuse *f, fino_t ino)
259{
260 return get_path_name(f, ino, NULL);
Miklos Szeredib483c932001-10-29 14:57:57 +0000261}
262
Miklos Szeredia181e612001-11-06 12:03:23 +0000263static void destroy_node(struct fuse *f, fino_t ino, int version)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000264{
Miklos Szeredia181e612001-11-06 12:03:23 +0000265 struct node *node;
266
267 pthread_mutex_lock(&f->lock);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000268 node = get_node(f, ino);
Miklos Szeredi39f28672001-11-14 14:52:54 +0000269 if(node->version == version && ino != FUSE_ROOT_INO) {
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000270 unhash_name(f, node);
271 unhash_ino(f, node);
Miklos Szeredia181e612001-11-06 12:03:23 +0000272 free_node(node);
273 }
274 pthread_mutex_unlock(&f->lock);
275
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000276}
277
Miklos Szeredi5e183482001-10-31 14:52:35 +0000278static void remove_node(struct fuse *f, fino_t dir, const char *name)
279{
Miklos Szeredia181e612001-11-06 12:03:23 +0000280 struct node *node;
281
282 pthread_mutex_lock(&f->lock);
283 node = lookup_node(f, dir, name);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000284 if(node == NULL) {
285 fprintf(stderr, "fuse internal error: unable to remove node %lu/%s\n",
286 dir, name);
287 abort();
288 }
289 unhash_name(f, node);
Miklos Szeredia181e612001-11-06 12:03:23 +0000290 pthread_mutex_unlock(&f->lock);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000291}
292
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000293static void rename_node(struct fuse *f, fino_t olddir, const char *oldname,
294 fino_t newdir, const char *newname)
295{
Miklos Szeredia181e612001-11-06 12:03:23 +0000296 struct node *node;
297 struct node *newnode;
298
299 pthread_mutex_lock(&f->lock);
300 node = lookup_node(f, olddir, oldname);
301 newnode = lookup_node(f, newdir, newname);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000302 if(node == NULL) {
303 fprintf(stderr, "fuse internal error: unable to rename node %lu/%s\n",
304 olddir, oldname);
305 abort();
306 }
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000307
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000308 if(newnode != NULL)
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000309 unhash_name(f, newnode);
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000310
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000311 unhash_name(f, node);
312 hash_name(f, node, newdir, newname);
Miklos Szeredia181e612001-11-06 12:03:23 +0000313 pthread_mutex_unlock(&f->lock);
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000314}
315
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000316static void convert_stat(struct stat *stbuf, struct fuse_attr *attr)
317{
Miklos Szeredib5958612004-02-20 14:10:49 +0000318 attr->mode = stbuf->st_mode;
319 attr->nlink = stbuf->st_nlink;
320 attr->uid = stbuf->st_uid;
321 attr->gid = stbuf->st_gid;
322 attr->rdev = stbuf->st_rdev;
323 attr->size = stbuf->st_size;
324 attr->blocks = stbuf->st_blocks;
325 attr->atime = stbuf->st_atime;
326 attr->atimensec = stbuf->st_atim.tv_nsec;
327 attr->mtime = stbuf->st_mtime;
328 attr->mtimensec = stbuf->st_mtim.tv_nsec;
329 attr->ctime = stbuf->st_ctime;
330 attr->ctimensec = stbuf->st_ctim.tv_nsec;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000331}
332
Miklos Szeredia181e612001-11-06 12:03:23 +0000333static int fill_dir(struct fuse_dirhandle *dh, char *name, int type)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000334{
335 struct fuse_dirent dirent;
336 size_t reclen;
337 size_t res;
338
Miklos Szeredi43696432001-11-18 19:15:05 +0000339 dirent.ino = (unsigned long) -1;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000340 dirent.namelen = strlen(name);
341 strncpy(dirent.name, name, sizeof(dirent.name));
342 dirent.type = type;
343 reclen = FUSE_DIRENT_SIZE(&dirent);
344 res = fwrite(&dirent, reclen, 1, dh->fp);
345 if(res == 0) {
Miklos Szeredi96249982001-11-21 12:21:19 +0000346 perror("fuse: writing directory file");
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000347 return -EIO;
348 }
349 return 0;
350}
351
Miklos Szeredi40b9a5a2002-12-10 16:09:02 +0000352static int send_reply_raw(struct fuse *f, char *outbuf, size_t outsize)
Miklos Szeredi43696432001-11-18 19:15:05 +0000353{
354 int res;
355
356 if((f->flags & FUSE_DEBUG)) {
357 struct fuse_out_header *out = (struct fuse_out_header *) outbuf;
358 printf(" unique: %i, error: %i (%s), outsize: %i\n", out->unique,
359 out->error, strerror(-out->error), outsize);
360 fflush(stdout);
361 }
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +0000362
Miklos Szeredi4e71c9f2004-02-09 12:05:14 +0000363 /* This needs to be done before the reply, otherwise the scheduler
364 could play tricks with us, and only let the counter be increased
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +0000365 long after the operation is done */
366 inc_avail(f);
367
Miklos Szeredi43696432001-11-18 19:15:05 +0000368 res = write(f->fd, outbuf, outsize);
369 if(res == -1) {
370 /* ENOENT means the operation was interrupted */
Miklos Szeredi4e71c9f2004-02-09 12:05:14 +0000371 if(!f->exited && errno != ENOENT)
Miklos Szeredi96249982001-11-21 12:21:19 +0000372 perror("fuse: writing device");
Miklos Szeredi40b9a5a2002-12-10 16:09:02 +0000373 return -errno;
Miklos Szeredi43696432001-11-18 19:15:05 +0000374 }
Miklos Szeredi40b9a5a2002-12-10 16:09:02 +0000375 return 0;
Miklos Szeredi43696432001-11-18 19:15:05 +0000376}
377
Miklos Szeredi40b9a5a2002-12-10 16:09:02 +0000378static int send_reply(struct fuse *f, struct fuse_in_header *in, int error,
379 void *arg, size_t argsize)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000380{
Miklos Szeredi40b9a5a2002-12-10 16:09:02 +0000381 int res;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000382 char *outbuf;
383 size_t outsize;
384 struct fuse_out_header *out;
385
Miklos Szeredi0f48a262002-12-05 14:23:01 +0000386 if(error <= -512 || error > 0) {
387 fprintf(stderr, "fuse: bad error value: %i\n", error);
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000388 error = -ERANGE;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000389 }
390
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000391 if(error)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000392 argsize = 0;
393
394 outsize = sizeof(struct fuse_out_header) + argsize;
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000395 outbuf = (char *) malloc(outsize);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000396 out = (struct fuse_out_header *) outbuf;
Miklos Szeredi0f48a262002-12-05 14:23:01 +0000397 memset(out, 0, sizeof(struct fuse_out_header));
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000398 out->unique = in->unique;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000399 out->error = error;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000400 if(argsize != 0)
401 memcpy(outbuf + sizeof(struct fuse_out_header), arg, argsize);
402
Miklos Szeredi40b9a5a2002-12-10 16:09:02 +0000403 res = send_reply_raw(f, outbuf, outsize);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000404 free(outbuf);
Miklos Szeredi40b9a5a2002-12-10 16:09:02 +0000405
406 return res;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000407}
408
Miklos Szeredi76f65782004-02-19 16:55:40 +0000409static int lookup_path(struct fuse *f, fino_t ino, int version, char *name,
410 const char *path, struct fuse_lookup_out *arg)
411{
412 int res;
413 struct stat buf;
414
415 res = f->op.getattr(path, &buf);
416 if(res == 0) {
417 struct node *node;
418
419 memset(arg, 0, sizeof(struct fuse_lookup_out));
420 convert_stat(&buf, &arg->attr);
421 node = find_node(f, ino, name, &arg->attr, version);
422 arg->ino = node->ino;
423 arg->generation = node->generation;
424 if(f->flags & FUSE_DEBUG) {
425 printf(" INO: %li\n", arg->ino);
426 fflush(stdout);
427 }
428 }
429 return res;
430}
431
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000432static void do_lookup(struct fuse *f, struct fuse_in_header *in, char *name)
433{
434 int res;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000435 char *path;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000436 struct fuse_lookup_out arg;
437
Miklos Szeredi5e183482001-10-31 14:52:35 +0000438 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000439 path = get_path_name(f, in->ino, name);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000440 if(path != NULL) {
Miklos Szeredi6ebe2342002-01-06 21:44:16 +0000441 if(f->flags & FUSE_DEBUG) {
442 printf("LOOKUP %s\n", path);
443 fflush(stdout);
444 }
Miklos Szeredi5e183482001-10-31 14:52:35 +0000445 res = -ENOSYS;
446 if(f->op.getattr)
Miklos Szeredi76f65782004-02-19 16:55:40 +0000447 res = lookup_path(f, in->ino, in->unique, name, path, &arg);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000448 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000449 }
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000450 send_reply(f, in, res, &arg, sizeof(arg));
451}
452
Miklos Szeredia181e612001-11-06 12:03:23 +0000453static void do_forget(struct fuse *f, struct fuse_in_header *in,
454 struct fuse_forget_in *arg)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000455{
Miklos Szeredi43696432001-11-18 19:15:05 +0000456 if(f->flags & FUSE_DEBUG) {
457 printf("FORGET %li/%i\n", in->ino, arg->version);
458 fflush(stdout);
459 }
Miklos Szeredia181e612001-11-06 12:03:23 +0000460 destroy_node(f, in->ino, arg->version);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000461}
462
463static void do_getattr(struct fuse *f, struct fuse_in_header *in)
464{
465 int res;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000466 char *path;
467 struct stat buf;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000468 struct fuse_getattr_out arg;
469
Miklos Szeredi5e183482001-10-31 14:52:35 +0000470 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000471 path = get_path(f, in->ino);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000472 if(path != NULL) {
473 res = -ENOSYS;
474 if(f->op.getattr)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000475 res = f->op.getattr(path, &buf);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000476 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000477 }
Miklos Szeredi0f48a262002-12-05 14:23:01 +0000478
479 if(res == 0) {
480 memset(&arg, 0, sizeof(struct fuse_getattr_out));
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000481 convert_stat(&buf, &arg.attr);
Miklos Szeredi0f48a262002-12-05 14:23:01 +0000482 }
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000483
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000484 send_reply(f, in, res, &arg, sizeof(arg));
485}
486
Miklos Szeredi680a69a2001-11-16 13:31:14 +0000487static int do_chmod(struct fuse *f, const char *path, struct fuse_attr *attr)
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000488{
489 int res;
490
491 res = -ENOSYS;
492 if(f->op.chmod)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000493 res = f->op.chmod(path, attr->mode);
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000494
495 return res;
496}
497
Miklos Szeredi680a69a2001-11-16 13:31:14 +0000498static int do_chown(struct fuse *f, const char *path, struct fuse_attr *attr,
Miklos Szeredi2e50d432001-12-20 12:17:25 +0000499 int valid)
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000500{
501 int res;
502 uid_t uid = (valid & FATTR_UID) ? attr->uid : (uid_t) -1;
503 gid_t gid = (valid & FATTR_GID) ? attr->gid : (gid_t) -1;
504
505 res = -ENOSYS;
506 if(f->op.chown)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000507 res = f->op.chown(path, uid, gid);
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000508
509 return res;
510}
511
Miklos Szeredi680a69a2001-11-16 13:31:14 +0000512static int do_truncate(struct fuse *f, const char *path,
513 struct fuse_attr *attr)
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000514{
515 int res;
516
517 res = -ENOSYS;
518 if(f->op.truncate)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000519 res = f->op.truncate(path, attr->size);
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000520
521 return res;
522}
523
Miklos Szeredi680a69a2001-11-16 13:31:14 +0000524static int do_utime(struct fuse *f, const char *path, struct fuse_attr *attr)
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000525{
526 int res;
527 struct utimbuf buf;
528 buf.actime = attr->atime;
529 buf.modtime = attr->mtime;
530 res = -ENOSYS;
531 if(f->op.utime)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000532 res = f->op.utime(path, &buf);
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000533
534 return res;
535}
536
Miklos Szeredi5e183482001-10-31 14:52:35 +0000537static void do_setattr(struct fuse *f, struct fuse_in_header *in,
538 struct fuse_setattr_in *arg)
539{
540 int res;
541 char *path;
542 int valid = arg->valid;
543 struct fuse_attr *attr = &arg->attr;
Miklos Szeredia181e612001-11-06 12:03:23 +0000544 struct fuse_setattr_out outarg;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000545
546 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000547 path = get_path(f, in->ino);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000548 if(path != NULL) {
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000549 res = -ENOSYS;
550 if(f->op.getattr) {
551 res = 0;
552 if(!res && (valid & FATTR_MODE))
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000553 res = do_chmod(f, path, attr);
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000554 if(!res && (valid & (FATTR_UID | FATTR_GID)))
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000555 res = do_chown(f, path, attr, valid);
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000556 if(!res && (valid & FATTR_SIZE))
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000557 res = do_truncate(f, path, attr);
Miklos Szeredib5958612004-02-20 14:10:49 +0000558 if(!res && (valid & (FATTR_ATIME | FATTR_MTIME)) ==
559 (FATTR_ATIME | FATTR_MTIME))
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000560 res = do_utime(f, path, attr);
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000561 if(!res) {
562 struct stat buf;
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000563 res = f->op.getattr(path, &buf);
Miklos Szeredi0f48a262002-12-05 14:23:01 +0000564 if(!res) {
565 memset(&outarg, 0, sizeof(struct fuse_setattr_out));
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000566 convert_stat(&buf, &outarg.attr);
Miklos Szeredi0f48a262002-12-05 14:23:01 +0000567 }
Miklos Szeredia181e612001-11-06 12:03:23 +0000568 }
Miklos Szeredi5e183482001-10-31 14:52:35 +0000569 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000570 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000571 }
Miklos Szeredia181e612001-11-06 12:03:23 +0000572 send_reply(f, in, res, &outarg, sizeof(outarg));
Miklos Szeredi5e183482001-10-31 14:52:35 +0000573}
574
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000575static void do_readlink(struct fuse *f, struct fuse_in_header *in)
576{
577 int res;
578 char link[PATH_MAX + 1];
Miklos Szeredib483c932001-10-29 14:57:57 +0000579 char *path;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000580
Miklos Szeredi5e183482001-10-31 14:52:35 +0000581 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000582 path = get_path(f, in->ino);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000583 if(path != NULL) {
584 res = -ENOSYS;
585 if(f->op.readlink)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000586 res = f->op.readlink(path, link, sizeof(link));
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000587 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000588 }
Miklos Szeredi2df1c042001-11-06 15:07:17 +0000589 link[PATH_MAX] = '\0';
Miklos Szeredi4b2bef42002-01-09 12:23:27 +0000590 send_reply(f, in, res, link, res == 0 ? strlen(link) : 0);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000591}
592
593static void do_getdir(struct fuse *f, struct fuse_in_header *in)
594{
595 int res;
596 struct fuse_getdir_out arg;
Miklos Szeredia181e612001-11-06 12:03:23 +0000597 struct fuse_dirhandle dh;
Miklos Szeredib483c932001-10-29 14:57:57 +0000598 char *path;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000599
Miklos Szeredib483c932001-10-29 14:57:57 +0000600 dh.fuse = f;
601 dh.fp = tmpfile();
602 dh.dir = in->ino;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000603 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000604 path = get_path(f, in->ino);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000605 if(path != NULL) {
606 res = -ENOSYS;
607 if(f->op.getdir)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000608 res = f->op.getdir(path, &dh, (fuse_dirfil_t) fill_dir);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000609 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000610 }
Miklos Szeredib483c932001-10-29 14:57:57 +0000611 fflush(dh.fp);
Miklos Szeredi0f48a262002-12-05 14:23:01 +0000612
613 memset(&arg, 0, sizeof(struct fuse_getdir_out));
Miklos Szeredib483c932001-10-29 14:57:57 +0000614 arg.fd = fileno(dh.fp);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000615 send_reply(f, in, res, &arg, sizeof(arg));
Miklos Szeredib483c932001-10-29 14:57:57 +0000616 fclose(dh.fp);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000617}
618
Miklos Szeredib483c932001-10-29 14:57:57 +0000619static void do_mknod(struct fuse *f, struct fuse_in_header *in,
620 struct fuse_mknod_in *inarg)
621{
622 int res;
623 char *path;
Miklos Szeredi76f65782004-02-19 16:55:40 +0000624 char *name = PARAM(inarg);
625 struct fuse_lookup_out outarg;
Miklos Szeredib483c932001-10-29 14:57:57 +0000626
Miklos Szeredi5e183482001-10-31 14:52:35 +0000627 res = -ENOENT;
Miklos Szeredi76f65782004-02-19 16:55:40 +0000628 path = get_path_name(f, in->ino, name);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000629 if(path != NULL) {
Miklos Szeredi76f65782004-02-19 16:55:40 +0000630 if(f->flags & FUSE_DEBUG) {
631 printf("MKNOD %s\n", path);
632 fflush(stdout);
633 }
Miklos Szeredi5e183482001-10-31 14:52:35 +0000634 res = -ENOSYS;
635 if(f->op.mknod && f->op.getattr) {
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000636 res = f->op.mknod(path, inarg->mode, inarg->rdev);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000637 if(res == 0)
Miklos Szeredi76f65782004-02-19 16:55:40 +0000638 res = lookup_path(f, in->ino, in->unique, name, path, &outarg);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000639 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000640 free(path);
Miklos Szeredib483c932001-10-29 14:57:57 +0000641 }
Miklos Szeredib483c932001-10-29 14:57:57 +0000642 send_reply(f, in, res, &outarg, sizeof(outarg));
643}
644
645static void do_mkdir(struct fuse *f, struct fuse_in_header *in,
646 struct fuse_mkdir_in *inarg)
647{
648 int res;
649 char *path;
Miklos Szeredi76f65782004-02-19 16:55:40 +0000650 char *name = PARAM(inarg);
651 struct fuse_lookup_out outarg;
Miklos Szeredib483c932001-10-29 14:57:57 +0000652
Miklos Szeredi5e183482001-10-31 14:52:35 +0000653 res = -ENOENT;
Miklos Szeredi76f65782004-02-19 16:55:40 +0000654 path = get_path_name(f, in->ino, name);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000655 if(path != NULL) {
Miklos Szeredi76f65782004-02-19 16:55:40 +0000656 if(f->flags & FUSE_DEBUG) {
657 printf("MKDIR %s\n", path);
658 fflush(stdout);
659 }
Miklos Szeredi5e183482001-10-31 14:52:35 +0000660 res = -ENOSYS;
Miklos Szeredi76f65782004-02-19 16:55:40 +0000661 if(f->op.mkdir && f->op.getattr) {
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000662 res = f->op.mkdir(path, inarg->mode);
Miklos Szeredi76f65782004-02-19 16:55:40 +0000663 if(res == 0)
664 res = lookup_path(f, in->ino, in->unique, name, path, &outarg);
665 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000666 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000667 }
Miklos Szeredi76f65782004-02-19 16:55:40 +0000668 send_reply(f, in, res, &outarg, sizeof(outarg));
Miklos Szeredib483c932001-10-29 14:57:57 +0000669}
670
Miklos Szeredib5958612004-02-20 14:10:49 +0000671static void do_unlink(struct fuse *f, struct fuse_in_header *in, char *name)
Miklos Szeredib483c932001-10-29 14:57:57 +0000672{
673 int res;
674 char *path;
675
Miklos Szeredi5e183482001-10-31 14:52:35 +0000676 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000677 path = get_path_name(f, in->ino, name);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000678 if(path != NULL) {
679 res = -ENOSYS;
Miklos Szeredib5958612004-02-20 14:10:49 +0000680 if(f->op.unlink) {
681 res = f->op.unlink(path);
682 if(res == 0)
683 remove_node(f, in->ino, name);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000684 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000685 free(path);
Miklos Szeredib483c932001-10-29 14:57:57 +0000686 }
Miklos Szeredib5958612004-02-20 14:10:49 +0000687 send_reply(f, in, res, NULL, 0);
688}
689
690static void do_rmdir(struct fuse *f, struct fuse_in_header *in, char *name)
691{
692 int res;
693 char *path;
694
695 res = -ENOENT;
696 path = get_path_name(f, in->ino, name);
697 if(path != NULL) {
698 res = -ENOSYS;
699 if(f->op.rmdir) {
700 res = f->op.rmdir(path);
701 if(res == 0)
702 remove_node(f, in->ino, name);
703 }
704 free(path);
705 }
Miklos Szeredib483c932001-10-29 14:57:57 +0000706 send_reply(f, in, res, NULL, 0);
707}
708
709static void do_symlink(struct fuse *f, struct fuse_in_header *in, char *name,
710 char *link)
711{
712 int res;
713 char *path;
Miklos Szeredi76f65782004-02-19 16:55:40 +0000714 struct fuse_lookup_out outarg;
Miklos Szeredib483c932001-10-29 14:57:57 +0000715
Miklos Szeredi5e183482001-10-31 14:52:35 +0000716 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000717 path = get_path_name(f, in->ino, name);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000718 if(path != NULL) {
Miklos Szeredi76f65782004-02-19 16:55:40 +0000719 if(f->flags & FUSE_DEBUG) {
720 printf("SYMLINK %s\n", path);
721 fflush(stdout);
722 }
Miklos Szeredi5e183482001-10-31 14:52:35 +0000723 res = -ENOSYS;
Miklos Szeredi76f65782004-02-19 16:55:40 +0000724 if(f->op.symlink && f->op.getattr) {
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000725 res = f->op.symlink(link, path);
Miklos Szeredi76f65782004-02-19 16:55:40 +0000726 if(res == 0)
727 res = lookup_path(f, in->ino, in->unique, name, path, &outarg);
728 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000729 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000730 }
Miklos Szeredi76f65782004-02-19 16:55:40 +0000731 send_reply(f, in, res, &outarg, sizeof(outarg));
Miklos Szeredib483c932001-10-29 14:57:57 +0000732}
733
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000734static void do_rename(struct fuse *f, struct fuse_in_header *in,
735 struct fuse_rename_in *inarg)
736{
737 int res;
738 fino_t olddir = in->ino;
739 fino_t newdir = inarg->newdir;
Miklos Szeredi6bf8b682002-10-28 08:49:39 +0000740 char *oldname = PARAM(inarg);
741 char *newname = oldname + strlen(oldname) + 1;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000742 char *oldpath;
743 char *newpath;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000744
Miklos Szeredi5e183482001-10-31 14:52:35 +0000745 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000746 oldpath = get_path_name(f, olddir, oldname);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000747 if(oldpath != NULL) {
Miklos Szeredia181e612001-11-06 12:03:23 +0000748 newpath = get_path_name(f, newdir, newname);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000749 if(newpath != NULL) {
750 res = -ENOSYS;
751 if(f->op.rename)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000752 res = f->op.rename(oldpath, newpath);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000753 if(res == 0)
754 rename_node(f, olddir, oldname, newdir, newname);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000755 free(newpath);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000756 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000757 free(oldpath);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000758 }
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000759 send_reply(f, in, res, NULL, 0);
760}
761
762static void do_link(struct fuse *f, struct fuse_in_header *in,
Miklos Szeredi5e183482001-10-31 14:52:35 +0000763 struct fuse_link_in *arg)
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000764{
765 int res;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000766 char *oldpath;
767 char *newpath;
Miklos Szeredi76f65782004-02-19 16:55:40 +0000768 char *name = PARAM(arg);
769 struct fuse_lookup_out outarg;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000770
Miklos Szeredi5e183482001-10-31 14:52:35 +0000771 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000772 oldpath = get_path(f, in->ino);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000773 if(oldpath != NULL) {
Miklos Szeredi76f65782004-02-19 16:55:40 +0000774 newpath = get_path_name(f, arg->newdir, name);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000775 if(newpath != NULL) {
Miklos Szeredi76f65782004-02-19 16:55:40 +0000776 if(f->flags & FUSE_DEBUG) {
777 printf("LINK %s\n", newpath);
778 fflush(stdout);
779 }
Miklos Szeredi5e183482001-10-31 14:52:35 +0000780 res = -ENOSYS;
Miklos Szeredi76f65782004-02-19 16:55:40 +0000781 if(f->op.link && f->op.getattr) {
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000782 res = f->op.link(oldpath, newpath);
Miklos Szeredi76f65782004-02-19 16:55:40 +0000783 if(res == 0)
784 res = lookup_path(f, arg->newdir, in->unique, name,
785 newpath, &outarg);
786 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000787 free(newpath);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000788 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000789 free(oldpath);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000790 }
Miklos Szeredi76f65782004-02-19 16:55:40 +0000791 send_reply(f, in, res, &outarg, sizeof(outarg));
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000792}
793
Miklos Szeredi5e183482001-10-31 14:52:35 +0000794static void do_open(struct fuse *f, struct fuse_in_header *in,
795 struct fuse_open_in *arg)
796{
797 int res;
Miklos Szeredi40b9a5a2002-12-10 16:09:02 +0000798 int res2;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000799 char *path;
800
801 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000802 path = get_path(f, in->ino);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000803 if(path != NULL) {
804 res = -ENOSYS;
805 if(f->op.open)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000806 res = f->op.open(path, arg->flags);
Miklos Szeredi40b9a5a2002-12-10 16:09:02 +0000807 }
808 res2 = send_reply(f, in, res, NULL, 0);
809 if(path != NULL) {
810 /* The open syscall was interrupted, so it must be cancelled */
811 if(res == 0 && res2 == -ENOENT && f->op.release)
Miklos Szeredi9478e862002-12-11 09:50:26 +0000812 f->op.release(path, arg->flags);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000813 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000814 }
Miklos Szeredi5e183482001-10-31 14:52:35 +0000815}
816
Miklos Szeredi9478e862002-12-11 09:50:26 +0000817static void do_release(struct fuse *f, struct fuse_in_header *in,
818 struct fuse_open_in *arg)
Miklos Szeredic8ba2372002-12-10 12:26:00 +0000819{
Miklos Szeredic8ba2372002-12-10 12:26:00 +0000820 char *path;
821
Miklos Szeredic8ba2372002-12-10 12:26:00 +0000822 path = get_path(f, in->ino);
823 if(path != NULL) {
Miklos Szeredic8ba2372002-12-10 12:26:00 +0000824 if(f->op.release)
Miklos Szeredi9478e862002-12-11 09:50:26 +0000825 f->op.release(path, arg->flags);
Miklos Szeredic8ba2372002-12-10 12:26:00 +0000826 free(path);
827 }
Miklos Szeredic8ba2372002-12-10 12:26:00 +0000828}
829
Miklos Szeredi5e183482001-10-31 14:52:35 +0000830static void do_read(struct fuse *f, struct fuse_in_header *in,
831 struct fuse_read_in *arg)
832{
833 int res;
834 char *path;
Miklos Szeredi43696432001-11-18 19:15:05 +0000835 char *outbuf = (char *) malloc(sizeof(struct fuse_out_header) + arg->size);
836 struct fuse_out_header *out = (struct fuse_out_header *) outbuf;
837 char *buf = outbuf + sizeof(struct fuse_out_header);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000838 size_t size;
Miklos Szeredi43696432001-11-18 19:15:05 +0000839 size_t outsize;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000840
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000841 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000842 path = get_path(f, in->ino);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000843 if(path != NULL) {
Miklos Szeredi6ebe2342002-01-06 21:44:16 +0000844 if(f->flags & FUSE_DEBUG) {
845 printf("READ %u bytes from %llu\n", arg->size, arg->offset);
846 fflush(stdout);
847 }
848
Miklos Szeredi5e183482001-10-31 14:52:35 +0000849 res = -ENOSYS;
Miklos Szeredia181e612001-11-06 12:03:23 +0000850 if(f->op.read)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000851 res = f->op.read(path, buf, arg->size, arg->offset);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000852 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000853 }
854
855 size = 0;
856 if(res > 0) {
857 size = res;
858 res = 0;
Miklos Szeredi6ebe2342002-01-06 21:44:16 +0000859 if(f->flags & FUSE_DEBUG) {
860 printf(" READ %u bytes\n", size);
861 fflush(stdout);
862 }
Miklos Szeredi5e183482001-10-31 14:52:35 +0000863 }
Miklos Szeredi0f48a262002-12-05 14:23:01 +0000864 memset(out, 0, sizeof(struct fuse_out_header));
Miklos Szeredi43696432001-11-18 19:15:05 +0000865 out->unique = in->unique;
866 out->error = res;
867 outsize = sizeof(struct fuse_out_header) + size;
868
869 send_reply_raw(f, outbuf, outsize);
870 free(outbuf);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000871}
Miklos Szeredib483c932001-10-29 14:57:57 +0000872
Miklos Szeredia181e612001-11-06 12:03:23 +0000873static void do_write(struct fuse *f, struct fuse_in_header *in,
874 struct fuse_write_in *arg)
875{
876 int res;
877 char *path;
Miklos Szeredia181e612001-11-06 12:03:23 +0000878
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000879 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000880 path = get_path(f, in->ino);
881 if(path != NULL) {
Miklos Szeredi6ebe2342002-01-06 21:44:16 +0000882 if(f->flags & FUSE_DEBUG) {
883 printf("WRITE %u bytes to %llu\n", arg->size, arg->offset);
884 fflush(stdout);
885 }
886
Miklos Szeredia181e612001-11-06 12:03:23 +0000887 res = -ENOSYS;
888 if(f->op.write)
Miklos Szeredi6bf8b682002-10-28 08:49:39 +0000889 res = f->op.write(path, PARAM(arg), arg->size, arg->offset);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000890 free(path);
Miklos Szeredia181e612001-11-06 12:03:23 +0000891 }
892
893 if(res > 0) {
894 if((size_t) res != arg->size) {
895 fprintf(stderr, "short write: %u (should be %u)\n", res,
896 arg->size);
Miklos Szeredi0e535082003-10-13 10:08:06 +0000897 res = -EINVAL;
Miklos Szeredia181e612001-11-06 12:03:23 +0000898 }
899 else
900 res = 0;
901 }
902
903 send_reply(f, in, res, NULL, 0);
904}
905
Miklos Szeredi18e75e42004-02-19 14:23:27 +0000906static void convert_statfs(struct statfs *statfs, struct fuse_kstatfs *kstatfs)
907{
908 kstatfs->bsize = statfs->f_bsize;
909 kstatfs->blocks = statfs->f_blocks;
910 kstatfs->bfree = statfs->f_bfree;
911 kstatfs->bavail = statfs->f_bavail;
912 kstatfs->files = statfs->f_files;
913 kstatfs->ffree = statfs->f_ffree;
914 kstatfs->namelen = statfs->f_namelen;
915}
916
Mark Glinesd84b39a2002-01-07 16:32:02 +0000917static void do_statfs(struct fuse *f, struct fuse_in_header *in)
918{
919 int res;
Mark Glinesd84b39a2002-01-07 16:32:02 +0000920 struct fuse_statfs_out arg;
Miklos Szeredi18e75e42004-02-19 14:23:27 +0000921 struct statfs buf;
Mark Glinesd84b39a2002-01-07 16:32:02 +0000922
923 res = -ENOSYS;
Miklos Szeredi0f48a262002-12-05 14:23:01 +0000924 if(f->op.statfs) {
Miklos Szeredi18e75e42004-02-19 14:23:27 +0000925 res = f->op.statfs("/", &buf);
926 if(res == 0) {
927 memset(&arg, 0, sizeof(struct fuse_statfs_out));
928 convert_statfs(&buf, &arg.st);
929 }
Miklos Szeredi0f48a262002-12-05 14:23:01 +0000930 }
Miklos Szeredi4b2bef42002-01-09 12:23:27 +0000931
Mark Glinesd84b39a2002-01-07 16:32:02 +0000932 send_reply(f, in, res, &arg, sizeof(arg));
933}
934
Miklos Szeredi5e43f2c2003-12-12 14:06:41 +0000935static void do_fsync(struct fuse *f, struct fuse_in_header *in,
936 struct fuse_fsync_in *inarg)
937{
938 int res;
939 char *path;
940
941 res = -ENOENT;
942 path = get_path(f, in->ino);
943 if(path != NULL) {
944 /* fsync is not mandatory, so don't return ENOSYS */
945 res = 0;
946 if(f->op.fsync)
947 res = f->op.fsync(path, inarg->datasync);
948 free(path);
949 }
950 send_reply(f, in, res, NULL, 0);
951}
952
Miklos Szeredi43696432001-11-18 19:15:05 +0000953static void free_cmd(struct fuse_cmd *cmd)
954{
955 free(cmd->buf);
956 free(cmd);
957}
958
Miklos Szeredifff56ab2001-11-16 10:12:59 +0000959void __fuse_process_cmd(struct fuse *f, struct fuse_cmd *cmd)
Miklos Szeredia181e612001-11-06 12:03:23 +0000960{
Miklos Szeredia181e612001-11-06 12:03:23 +0000961 struct fuse_in_header *in = (struct fuse_in_header *) cmd->buf;
962 void *inarg = cmd->buf + sizeof(struct fuse_in_header);
963 size_t argsize;
Miklos Szeredife25def2001-12-20 15:38:05 +0000964 struct fuse_context *ctx = fuse_get_context(f);
Miklos Szeredia181e612001-11-06 12:03:23 +0000965
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +0000966 dec_avail(f);
Miklos Szeredi33232032001-11-19 17:55:51 +0000967
Miklos Szeredic0938ea2001-11-07 12:35:06 +0000968 if((f->flags & FUSE_DEBUG)) {
Miklos Szeredic8ba2372002-12-10 12:26:00 +0000969 printf("unique: %i, opcode: %s (%i), ino: %li, insize: %i\n",
970 in->unique, opname(in->opcode), in->opcode, in->ino,
971 cmd->buflen);
Miklos Szeredic0938ea2001-11-07 12:35:06 +0000972 fflush(stdout);
973 }
Miklos Szeredife25def2001-12-20 15:38:05 +0000974
975 ctx->uid = in->uid;
976 ctx->gid = in->gid;
Miklos Szeredia181e612001-11-06 12:03:23 +0000977
978 argsize = cmd->buflen - sizeof(struct fuse_in_header);
979
980 switch(in->opcode) {
981 case FUSE_LOOKUP:
982 do_lookup(f, in, (char *) inarg);
983 break;
984
Miklos Szeredia181e612001-11-06 12:03:23 +0000985 case FUSE_GETATTR:
986 do_getattr(f, in);
987 break;
988
989 case FUSE_SETATTR:
990 do_setattr(f, in, (struct fuse_setattr_in *) inarg);
991 break;
992
993 case FUSE_READLINK:
994 do_readlink(f, in);
995 break;
996
997 case FUSE_GETDIR:
998 do_getdir(f, in);
999 break;
1000
1001 case FUSE_MKNOD:
1002 do_mknod(f, in, (struct fuse_mknod_in *) inarg);
1003 break;
1004
1005 case FUSE_MKDIR:
1006 do_mkdir(f, in, (struct fuse_mkdir_in *) inarg);
1007 break;
1008
1009 case FUSE_UNLINK:
Miklos Szeredib5958612004-02-20 14:10:49 +00001010 do_unlink(f, in, (char *) inarg);
1011 break;
1012
Miklos Szeredia181e612001-11-06 12:03:23 +00001013 case FUSE_RMDIR:
Miklos Szeredib5958612004-02-20 14:10:49 +00001014 do_rmdir(f, in, (char *) inarg);
Miklos Szeredia181e612001-11-06 12:03:23 +00001015 break;
1016
1017 case FUSE_SYMLINK:
1018 do_symlink(f, in, (char *) inarg,
1019 ((char *) inarg) + strlen((char *) inarg) + 1);
1020 break;
1021
1022 case FUSE_RENAME:
1023 do_rename(f, in, (struct fuse_rename_in *) inarg);
1024 break;
1025
1026 case FUSE_LINK:
1027 do_link(f, in, (struct fuse_link_in *) inarg);
1028 break;
1029
1030 case FUSE_OPEN:
1031 do_open(f, in, (struct fuse_open_in *) inarg);
1032 break;
1033
Miklos Szeredi9478e862002-12-11 09:50:26 +00001034 case FUSE_RELEASE:
1035 do_release(f, in, (struct fuse_open_in *) inarg);
1036 break;
1037
Miklos Szeredia181e612001-11-06 12:03:23 +00001038 case FUSE_READ:
1039 do_read(f, in, (struct fuse_read_in *) inarg);
1040 break;
1041
1042 case FUSE_WRITE:
1043 do_write(f, in, (struct fuse_write_in *) inarg);
1044 break;
1045
Mark Glinesd84b39a2002-01-07 16:32:02 +00001046 case FUSE_STATFS:
1047 do_statfs(f, in);
1048 break;
1049
Miklos Szeredi5e43f2c2003-12-12 14:06:41 +00001050 case FUSE_FSYNC:
1051 do_fsync(f, in, (struct fuse_fsync_in *) inarg);
1052 break;
1053
Miklos Szeredia181e612001-11-06 12:03:23 +00001054 default:
Miklos Szeredi43696432001-11-18 19:15:05 +00001055 send_reply(f, in, -ENOSYS, NULL, 0);
Miklos Szeredia181e612001-11-06 12:03:23 +00001056 }
Miklos Szeredi43696432001-11-18 19:15:05 +00001057
1058 free_cmd(cmd);
Miklos Szeredia181e612001-11-06 12:03:23 +00001059}
1060
Miklos Szeredifff56ab2001-11-16 10:12:59 +00001061struct fuse_cmd *__fuse_read_cmd(struct fuse *f)
Miklos Szeredi2df1c042001-11-06 15:07:17 +00001062{
Miklos Szeredifff56ab2001-11-16 10:12:59 +00001063 ssize_t res;
Miklos Szeredifff56ab2001-11-16 10:12:59 +00001064 struct fuse_cmd *cmd;
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +00001065 struct fuse_in_header *in;
1066 void *inarg;
Miklos Szeredifff56ab2001-11-16 10:12:59 +00001067
Miklos Szeredi43696432001-11-18 19:15:05 +00001068 cmd = (struct fuse_cmd *) malloc(sizeof(struct fuse_cmd));
1069 cmd->buf = (char *) malloc(FUSE_MAX_IN);
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +00001070 in = (struct fuse_in_header *) cmd->buf;
1071 inarg = cmd->buf + sizeof(struct fuse_in_header);
Miklos Szeredi43696432001-11-18 19:15:05 +00001072
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +00001073 do {
1074 res = read(f->fd, cmd->buf, FUSE_MAX_IN);
1075 if(res == -1) {
Miklos Szeredi0f48a262002-12-05 14:23:01 +00001076 free_cmd(cmd);
Miklos Szeredi307242f2004-01-26 11:28:44 +00001077 if(f->exited || errno == EINTR)
Miklos Szeredi0f48a262002-12-05 14:23:01 +00001078 return NULL;
1079
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +00001080 /* ENODEV means we got unmounted, so we silenty return failure */
1081 if(errno != ENODEV) {
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +00001082 /* BAD... This will happen again */
Miklos Szeredi0f48a262002-12-05 14:23:01 +00001083 perror("fuse: reading device");
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +00001084 }
Miklos Szeredi0f48a262002-12-05 14:23:01 +00001085
1086 fuse_exit(f);
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +00001087 return NULL;
Miklos Szeredi96249982001-11-21 12:21:19 +00001088 }
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +00001089 if((size_t) res < sizeof(struct fuse_in_header)) {
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +00001090 free_cmd(cmd);
Miklos Szeredi0f48a262002-12-05 14:23:01 +00001091 /* Cannot happen */
1092 fprintf(stderr, "short read on fuse device\n");
1093 fuse_exit(f);
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +00001094 return NULL;
1095 }
1096 cmd->buflen = res;
1097
1098 /* Forget is special, it can be done without messing with threads. */
1099 if(in->opcode == FUSE_FORGET)
1100 do_forget(f, in, (struct fuse_forget_in *) inarg);
1101
1102 } while(in->opcode == FUSE_FORGET);
1103
Miklos Szeredifff56ab2001-11-16 10:12:59 +00001104 return cmd;
Miklos Szeredi2df1c042001-11-06 15:07:17 +00001105}
1106
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001107void fuse_loop(struct fuse *f)
1108{
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001109 while(1) {
Miklos Szeredi0f48a262002-12-05 14:23:01 +00001110 struct fuse_cmd *cmd;
1111
1112 if(f->exited)
1113 return;
1114
1115 cmd = __fuse_read_cmd(f);
Miklos Szeredifff56ab2001-11-16 10:12:59 +00001116 if(cmd == NULL)
Miklos Szeredi0f48a262002-12-05 14:23:01 +00001117 continue;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001118
Miklos Szeredifff56ab2001-11-16 10:12:59 +00001119 __fuse_process_cmd(f, cmd);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001120 }
1121}
1122
Miklos Szeredi0f48a262002-12-05 14:23:01 +00001123void fuse_exit(struct fuse *f)
1124{
1125 f->exited = 1;
1126}
1127
Miklos Szeredi2e50d432001-12-20 12:17:25 +00001128struct fuse_context *fuse_get_context(struct fuse *f)
1129{
1130 if(f->getcontext)
1131 return f->getcontext(f);
1132 else
1133 return &f->context;
1134}
1135
1136struct fuse *fuse_new(int fd, int flags, const struct fuse_operations *op)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001137{
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001138 struct fuse *f;
1139 struct node *root;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001140
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001141 f = (struct fuse *) calloc(1, sizeof(struct fuse));
Miklos Szeredi2df1c042001-11-06 15:07:17 +00001142
Miklos Szeredia181e612001-11-06 12:03:23 +00001143 f->flags = flags;
Miklos Szeredi8cffdb92001-11-09 14:49:18 +00001144 f->fd = fd;
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001145 f->ctr = 0;
Miklos Szeredi76f65782004-02-19 16:55:40 +00001146 f->generation = 0;
Miklos Szeredifff56ab2001-11-16 10:12:59 +00001147 /* FIXME: Dynamic hash table */
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001148 f->name_table_size = 14057;
1149 f->name_table = (struct node **)
1150 calloc(1, sizeof(struct node *) * f->name_table_size);
1151 f->ino_table_size = 14057;
1152 f->ino_table = (struct node **)
1153 calloc(1, sizeof(struct node *) * f->ino_table_size);
Miklos Szeredia181e612001-11-06 12:03:23 +00001154 pthread_mutex_init(&f->lock, NULL);
Miklos Szeredi33232032001-11-19 17:55:51 +00001155 f->numworker = 0;
1156 f->numavail = 0;
Miklos Szeredi2e50d432001-12-20 12:17:25 +00001157 f->op = *op;
1158 f->getcontext = NULL;
1159 f->context.uid = 0;
1160 f->context.gid = 0;
Miklos Szeredi0f48a262002-12-05 14:23:01 +00001161 f->exited = 0;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001162
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001163 root = (struct node *) calloc(1, sizeof(struct node));
Miklos Szeredi8cffdb92001-11-09 14:49:18 +00001164 root->mode = 0;
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001165 root->rdev = 0;
1166 root->name = strdup("/");
1167 root->parent = 0;
Miklos Szeredi76f65782004-02-19 16:55:40 +00001168 root->ino = FUSE_ROOT_INO;
1169 root->generation = 0;
1170 hash_ino(f, root);
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001171
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001172 return f;
1173}
1174
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001175void fuse_destroy(struct fuse *f)
1176{
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001177 size_t i;
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001178 for(i = 0; i < f->ino_table_size; i++) {
1179 struct node *node;
1180 struct node *next;
1181 for(node = f->ino_table[i]; node != NULL; node = next) {
1182 next = node->ino_next;
1183 free_node(node);
1184 }
1185 }
1186 free(f->ino_table);
1187 free(f->name_table);
Miklos Szeredia181e612001-11-06 12:03:23 +00001188 pthread_mutex_destroy(&f->lock);
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001189 free(f);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001190}