blob: 079220a0eafa2837ffd2b623c7eb04d3ad488c8d [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{
318 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;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000324 attr->blocks = stbuf->st_blocks;
325 attr->atime = stbuf->st_atime;
326 attr->mtime = stbuf->st_mtime;
327 attr->ctime = stbuf->st_ctime;
Miklos Szeredifff56ab2001-11-16 10:12:59 +0000328 attr->_dummy = 4096;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000329}
330
Miklos Szeredia181e612001-11-06 12:03:23 +0000331static int fill_dir(struct fuse_dirhandle *dh, char *name, int type)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000332{
333 struct fuse_dirent dirent;
334 size_t reclen;
335 size_t res;
336
Miklos Szeredi43696432001-11-18 19:15:05 +0000337 dirent.ino = (unsigned long) -1;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000338 dirent.namelen = strlen(name);
339 strncpy(dirent.name, name, sizeof(dirent.name));
340 dirent.type = type;
341 reclen = FUSE_DIRENT_SIZE(&dirent);
342 res = fwrite(&dirent, reclen, 1, dh->fp);
343 if(res == 0) {
Miklos Szeredi96249982001-11-21 12:21:19 +0000344 perror("fuse: writing directory file");
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000345 return -EIO;
346 }
347 return 0;
348}
349
Miklos Szeredi40b9a5a2002-12-10 16:09:02 +0000350static int send_reply_raw(struct fuse *f, char *outbuf, size_t outsize)
Miklos Szeredi43696432001-11-18 19:15:05 +0000351{
352 int res;
353
354 if((f->flags & FUSE_DEBUG)) {
355 struct fuse_out_header *out = (struct fuse_out_header *) outbuf;
356 printf(" unique: %i, error: %i (%s), outsize: %i\n", out->unique,
357 out->error, strerror(-out->error), outsize);
358 fflush(stdout);
359 }
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +0000360
Miklos Szeredi4e71c9f2004-02-09 12:05:14 +0000361 /* This needs to be done before the reply, otherwise the scheduler
362 could play tricks with us, and only let the counter be increased
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +0000363 long after the operation is done */
364 inc_avail(f);
365
Miklos Szeredi43696432001-11-18 19:15:05 +0000366 res = write(f->fd, outbuf, outsize);
367 if(res == -1) {
368 /* ENOENT means the operation was interrupted */
Miklos Szeredi4e71c9f2004-02-09 12:05:14 +0000369 if(!f->exited && errno != ENOENT)
Miklos Szeredi96249982001-11-21 12:21:19 +0000370 perror("fuse: writing device");
Miklos Szeredi40b9a5a2002-12-10 16:09:02 +0000371 return -errno;
Miklos Szeredi43696432001-11-18 19:15:05 +0000372 }
Miklos Szeredi40b9a5a2002-12-10 16:09:02 +0000373 return 0;
Miklos Szeredi43696432001-11-18 19:15:05 +0000374}
375
Miklos Szeredi40b9a5a2002-12-10 16:09:02 +0000376static int send_reply(struct fuse *f, struct fuse_in_header *in, int error,
377 void *arg, size_t argsize)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000378{
Miklos Szeredi40b9a5a2002-12-10 16:09:02 +0000379 int res;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000380 char *outbuf;
381 size_t outsize;
382 struct fuse_out_header *out;
383
Miklos Szeredi0f48a262002-12-05 14:23:01 +0000384 if(error <= -512 || error > 0) {
385 fprintf(stderr, "fuse: bad error value: %i\n", error);
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000386 error = -ERANGE;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000387 }
388
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000389 if(error)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000390 argsize = 0;
391
392 outsize = sizeof(struct fuse_out_header) + argsize;
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000393 outbuf = (char *) malloc(outsize);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000394 out = (struct fuse_out_header *) outbuf;
Miklos Szeredi0f48a262002-12-05 14:23:01 +0000395 memset(out, 0, sizeof(struct fuse_out_header));
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000396 out->unique = in->unique;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000397 out->error = error;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000398 if(argsize != 0)
399 memcpy(outbuf + sizeof(struct fuse_out_header), arg, argsize);
400
Miklos Szeredi40b9a5a2002-12-10 16:09:02 +0000401 res = send_reply_raw(f, outbuf, outsize);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000402 free(outbuf);
Miklos Szeredi40b9a5a2002-12-10 16:09:02 +0000403
404 return res;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000405}
406
Miklos Szeredi76f65782004-02-19 16:55:40 +0000407static int lookup_path(struct fuse *f, fino_t ino, int version, char *name,
408 const char *path, struct fuse_lookup_out *arg)
409{
410 int res;
411 struct stat buf;
412
413 res = f->op.getattr(path, &buf);
414 if(res == 0) {
415 struct node *node;
416
417 memset(arg, 0, sizeof(struct fuse_lookup_out));
418 convert_stat(&buf, &arg->attr);
419 node = find_node(f, ino, name, &arg->attr, version);
420 arg->ino = node->ino;
421 arg->generation = node->generation;
422 if(f->flags & FUSE_DEBUG) {
423 printf(" INO: %li\n", arg->ino);
424 fflush(stdout);
425 }
426 }
427 return res;
428}
429
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000430static void do_lookup(struct fuse *f, struct fuse_in_header *in, char *name)
431{
432 int res;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000433 char *path;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000434 struct fuse_lookup_out arg;
435
Miklos Szeredi5e183482001-10-31 14:52:35 +0000436 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000437 path = get_path_name(f, in->ino, name);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000438 if(path != NULL) {
Miklos Szeredi6ebe2342002-01-06 21:44:16 +0000439 if(f->flags & FUSE_DEBUG) {
440 printf("LOOKUP %s\n", path);
441 fflush(stdout);
442 }
Miklos Szeredi5e183482001-10-31 14:52:35 +0000443 res = -ENOSYS;
444 if(f->op.getattr)
Miklos Szeredi76f65782004-02-19 16:55:40 +0000445 res = lookup_path(f, in->ino, in->unique, name, path, &arg);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000446 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000447 }
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000448 send_reply(f, in, res, &arg, sizeof(arg));
449}
450
Miklos Szeredia181e612001-11-06 12:03:23 +0000451static void do_forget(struct fuse *f, struct fuse_in_header *in,
452 struct fuse_forget_in *arg)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000453{
Miklos Szeredi43696432001-11-18 19:15:05 +0000454 if(f->flags & FUSE_DEBUG) {
455 printf("FORGET %li/%i\n", in->ino, arg->version);
456 fflush(stdout);
457 }
Miklos Szeredia181e612001-11-06 12:03:23 +0000458 destroy_node(f, in->ino, arg->version);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000459}
460
461static void do_getattr(struct fuse *f, struct fuse_in_header *in)
462{
463 int res;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000464 char *path;
465 struct stat buf;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000466 struct fuse_getattr_out arg;
467
Miklos Szeredi5e183482001-10-31 14:52:35 +0000468 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000469 path = get_path(f, in->ino);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000470 if(path != NULL) {
471 res = -ENOSYS;
472 if(f->op.getattr)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000473 res = f->op.getattr(path, &buf);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000474 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000475 }
Miklos Szeredi0f48a262002-12-05 14:23:01 +0000476
477 if(res == 0) {
478 memset(&arg, 0, sizeof(struct fuse_getattr_out));
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000479 convert_stat(&buf, &arg.attr);
Miklos Szeredi0f48a262002-12-05 14:23:01 +0000480 }
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000481
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000482 send_reply(f, in, res, &arg, sizeof(arg));
483}
484
Miklos Szeredi680a69a2001-11-16 13:31:14 +0000485static int do_chmod(struct fuse *f, const char *path, struct fuse_attr *attr)
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000486{
487 int res;
488
489 res = -ENOSYS;
490 if(f->op.chmod)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000491 res = f->op.chmod(path, attr->mode);
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000492
493 return res;
494}
495
Miklos Szeredi680a69a2001-11-16 13:31:14 +0000496static int do_chown(struct fuse *f, const char *path, struct fuse_attr *attr,
Miklos Szeredi2e50d432001-12-20 12:17:25 +0000497 int valid)
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000498{
499 int res;
500 uid_t uid = (valid & FATTR_UID) ? attr->uid : (uid_t) -1;
501 gid_t gid = (valid & FATTR_GID) ? attr->gid : (gid_t) -1;
502
503 res = -ENOSYS;
504 if(f->op.chown)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000505 res = f->op.chown(path, uid, gid);
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000506
507 return res;
508}
509
Miklos Szeredi680a69a2001-11-16 13:31:14 +0000510static int do_truncate(struct fuse *f, const char *path,
511 struct fuse_attr *attr)
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000512{
513 int res;
514
515 res = -ENOSYS;
516 if(f->op.truncate)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000517 res = f->op.truncate(path, attr->size);
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000518
519 return res;
520}
521
Miklos Szeredi680a69a2001-11-16 13:31:14 +0000522static int do_utime(struct fuse *f, const char *path, struct fuse_attr *attr)
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000523{
524 int res;
525 struct utimbuf buf;
526 buf.actime = attr->atime;
527 buf.modtime = attr->mtime;
528 res = -ENOSYS;
529 if(f->op.utime)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000530 res = f->op.utime(path, &buf);
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000531
532 return res;
533}
534
Miklos Szeredi5e183482001-10-31 14:52:35 +0000535static void do_setattr(struct fuse *f, struct fuse_in_header *in,
536 struct fuse_setattr_in *arg)
537{
538 int res;
539 char *path;
540 int valid = arg->valid;
541 struct fuse_attr *attr = &arg->attr;
Miklos Szeredia181e612001-11-06 12:03:23 +0000542 struct fuse_setattr_out outarg;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000543
544 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000545 path = get_path(f, in->ino);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000546 if(path != NULL) {
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000547 res = -ENOSYS;
548 if(f->op.getattr) {
549 res = 0;
550 if(!res && (valid & FATTR_MODE))
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000551 res = do_chmod(f, path, attr);
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000552 if(!res && (valid & (FATTR_UID | FATTR_GID)))
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000553 res = do_chown(f, path, attr, valid);
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000554 if(!res && (valid & FATTR_SIZE))
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000555 res = do_truncate(f, path, attr);
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000556 if(!res && (valid & FATTR_UTIME))
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000557 res = do_utime(f, path, attr);
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000558 if(!res) {
559 struct stat buf;
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000560 res = f->op.getattr(path, &buf);
Miklos Szeredi0f48a262002-12-05 14:23:01 +0000561 if(!res) {
562 memset(&outarg, 0, sizeof(struct fuse_setattr_out));
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000563 convert_stat(&buf, &outarg.attr);
Miklos Szeredi0f48a262002-12-05 14:23:01 +0000564 }
Miklos Szeredia181e612001-11-06 12:03:23 +0000565 }
Miklos Szeredi5e183482001-10-31 14:52:35 +0000566 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000567 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000568 }
Miklos Szeredia181e612001-11-06 12:03:23 +0000569 send_reply(f, in, res, &outarg, sizeof(outarg));
Miklos Szeredi5e183482001-10-31 14:52:35 +0000570}
571
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000572static void do_readlink(struct fuse *f, struct fuse_in_header *in)
573{
574 int res;
575 char link[PATH_MAX + 1];
Miklos Szeredib483c932001-10-29 14:57:57 +0000576 char *path;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000577
Miklos Szeredi5e183482001-10-31 14:52:35 +0000578 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000579 path = get_path(f, in->ino);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000580 if(path != NULL) {
581 res = -ENOSYS;
582 if(f->op.readlink)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000583 res = f->op.readlink(path, link, sizeof(link));
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000584 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000585 }
Miklos Szeredi2df1c042001-11-06 15:07:17 +0000586 link[PATH_MAX] = '\0';
Miklos Szeredi4b2bef42002-01-09 12:23:27 +0000587 send_reply(f, in, res, link, res == 0 ? strlen(link) : 0);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000588}
589
590static void do_getdir(struct fuse *f, struct fuse_in_header *in)
591{
592 int res;
593 struct fuse_getdir_out arg;
Miklos Szeredia181e612001-11-06 12:03:23 +0000594 struct fuse_dirhandle dh;
Miklos Szeredib483c932001-10-29 14:57:57 +0000595 char *path;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000596
Miklos Szeredib483c932001-10-29 14:57:57 +0000597 dh.fuse = f;
598 dh.fp = tmpfile();
599 dh.dir = in->ino;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000600 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000601 path = get_path(f, in->ino);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000602 if(path != NULL) {
603 res = -ENOSYS;
604 if(f->op.getdir)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000605 res = f->op.getdir(path, &dh, (fuse_dirfil_t) fill_dir);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000606 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000607 }
Miklos Szeredib483c932001-10-29 14:57:57 +0000608 fflush(dh.fp);
Miklos Szeredi0f48a262002-12-05 14:23:01 +0000609
610 memset(&arg, 0, sizeof(struct fuse_getdir_out));
Miklos Szeredib483c932001-10-29 14:57:57 +0000611 arg.fd = fileno(dh.fp);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000612 send_reply(f, in, res, &arg, sizeof(arg));
Miklos Szeredib483c932001-10-29 14:57:57 +0000613 fclose(dh.fp);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000614}
615
Miklos Szeredib483c932001-10-29 14:57:57 +0000616static void do_mknod(struct fuse *f, struct fuse_in_header *in,
617 struct fuse_mknod_in *inarg)
618{
619 int res;
620 char *path;
Miklos Szeredi76f65782004-02-19 16:55:40 +0000621 char *name = PARAM(inarg);
622 struct fuse_lookup_out outarg;
Miklos Szeredib483c932001-10-29 14:57:57 +0000623
Miklos Szeredi5e183482001-10-31 14:52:35 +0000624 res = -ENOENT;
Miklos Szeredi76f65782004-02-19 16:55:40 +0000625 path = get_path_name(f, in->ino, name);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000626 if(path != NULL) {
Miklos Szeredi76f65782004-02-19 16:55:40 +0000627 if(f->flags & FUSE_DEBUG) {
628 printf("MKNOD %s\n", path);
629 fflush(stdout);
630 }
Miklos Szeredi5e183482001-10-31 14:52:35 +0000631 res = -ENOSYS;
632 if(f->op.mknod && f->op.getattr) {
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000633 res = f->op.mknod(path, inarg->mode, inarg->rdev);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000634 if(res == 0)
Miklos Szeredi76f65782004-02-19 16:55:40 +0000635 res = lookup_path(f, in->ino, in->unique, name, path, &outarg);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000636 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000637 free(path);
Miklos Szeredib483c932001-10-29 14:57:57 +0000638 }
Miklos Szeredib483c932001-10-29 14:57:57 +0000639 send_reply(f, in, res, &outarg, sizeof(outarg));
640}
641
642static void do_mkdir(struct fuse *f, struct fuse_in_header *in,
643 struct fuse_mkdir_in *inarg)
644{
645 int res;
646 char *path;
Miklos Szeredi76f65782004-02-19 16:55:40 +0000647 char *name = PARAM(inarg);
648 struct fuse_lookup_out outarg;
Miklos Szeredib483c932001-10-29 14:57:57 +0000649
Miklos Szeredi5e183482001-10-31 14:52:35 +0000650 res = -ENOENT;
Miklos Szeredi76f65782004-02-19 16:55:40 +0000651 path = get_path_name(f, in->ino, name);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000652 if(path != NULL) {
Miklos Szeredi76f65782004-02-19 16:55:40 +0000653 if(f->flags & FUSE_DEBUG) {
654 printf("MKDIR %s\n", path);
655 fflush(stdout);
656 }
Miklos Szeredi5e183482001-10-31 14:52:35 +0000657 res = -ENOSYS;
Miklos Szeredi76f65782004-02-19 16:55:40 +0000658 if(f->op.mkdir && f->op.getattr) {
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000659 res = f->op.mkdir(path, inarg->mode);
Miklos Szeredi76f65782004-02-19 16:55:40 +0000660 if(res == 0)
661 res = lookup_path(f, in->ino, in->unique, name, path, &outarg);
662 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000663 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000664 }
Miklos Szeredi76f65782004-02-19 16:55:40 +0000665 send_reply(f, in, res, &outarg, sizeof(outarg));
Miklos Szeredib483c932001-10-29 14:57:57 +0000666}
667
668static void do_remove(struct fuse *f, struct fuse_in_header *in, char *name)
669{
670 int res;
671 char *path;
672
Miklos Szeredi5e183482001-10-31 14:52:35 +0000673 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000674 path = get_path_name(f, in->ino, name);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000675 if(path != NULL) {
676 res = -ENOSYS;
677 if(in->opcode == FUSE_UNLINK) {
678 if(f->op.unlink)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000679 res = f->op.unlink(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000680 }
681 else {
682 if(f->op.rmdir)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000683 res = f->op.rmdir(path);
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 Szeredi5e183482001-10-31 14:52:35 +0000687 if(res == 0)
688 remove_node(f, in->ino, name);
Miklos Szeredib483c932001-10-29 14:57:57 +0000689 send_reply(f, in, res, NULL, 0);
690}
691
692static void do_symlink(struct fuse *f, struct fuse_in_header *in, char *name,
693 char *link)
694{
695 int res;
696 char *path;
Miklos Szeredi76f65782004-02-19 16:55:40 +0000697 struct fuse_lookup_out outarg;
Miklos Szeredib483c932001-10-29 14:57:57 +0000698
Miklos Szeredi5e183482001-10-31 14:52:35 +0000699 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000700 path = get_path_name(f, in->ino, name);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000701 if(path != NULL) {
Miklos Szeredi76f65782004-02-19 16:55:40 +0000702 if(f->flags & FUSE_DEBUG) {
703 printf("SYMLINK %s\n", path);
704 fflush(stdout);
705 }
Miklos Szeredi5e183482001-10-31 14:52:35 +0000706 res = -ENOSYS;
Miklos Szeredi76f65782004-02-19 16:55:40 +0000707 if(f->op.symlink && f->op.getattr) {
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000708 res = f->op.symlink(link, path);
Miklos Szeredi76f65782004-02-19 16:55:40 +0000709 if(res == 0)
710 res = lookup_path(f, in->ino, in->unique, name, path, &outarg);
711 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000712 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000713 }
Miklos Szeredi76f65782004-02-19 16:55:40 +0000714 send_reply(f, in, res, &outarg, sizeof(outarg));
Miklos Szeredib483c932001-10-29 14:57:57 +0000715}
716
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000717static void do_rename(struct fuse *f, struct fuse_in_header *in,
718 struct fuse_rename_in *inarg)
719{
720 int res;
721 fino_t olddir = in->ino;
722 fino_t newdir = inarg->newdir;
Miklos Szeredi6bf8b682002-10-28 08:49:39 +0000723 char *oldname = PARAM(inarg);
724 char *newname = oldname + strlen(oldname) + 1;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000725 char *oldpath;
726 char *newpath;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000727
Miklos Szeredi5e183482001-10-31 14:52:35 +0000728 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000729 oldpath = get_path_name(f, olddir, oldname);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000730 if(oldpath != NULL) {
Miklos Szeredia181e612001-11-06 12:03:23 +0000731 newpath = get_path_name(f, newdir, newname);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000732 if(newpath != NULL) {
733 res = -ENOSYS;
734 if(f->op.rename)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000735 res = f->op.rename(oldpath, newpath);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000736 if(res == 0)
737 rename_node(f, olddir, oldname, newdir, newname);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000738 free(newpath);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000739 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000740 free(oldpath);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000741 }
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000742 send_reply(f, in, res, NULL, 0);
743}
744
745static void do_link(struct fuse *f, struct fuse_in_header *in,
Miklos Szeredi5e183482001-10-31 14:52:35 +0000746 struct fuse_link_in *arg)
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000747{
748 int res;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000749 char *oldpath;
750 char *newpath;
Miklos Szeredi76f65782004-02-19 16:55:40 +0000751 char *name = PARAM(arg);
752 struct fuse_lookup_out outarg;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000753
Miklos Szeredi5e183482001-10-31 14:52:35 +0000754 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000755 oldpath = get_path(f, in->ino);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000756 if(oldpath != NULL) {
Miklos Szeredi76f65782004-02-19 16:55:40 +0000757 newpath = get_path_name(f, arg->newdir, name);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000758 if(newpath != NULL) {
Miklos Szeredi76f65782004-02-19 16:55:40 +0000759 if(f->flags & FUSE_DEBUG) {
760 printf("LINK %s\n", newpath);
761 fflush(stdout);
762 }
Miklos Szeredi5e183482001-10-31 14:52:35 +0000763 res = -ENOSYS;
Miklos Szeredi76f65782004-02-19 16:55:40 +0000764 if(f->op.link && f->op.getattr) {
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000765 res = f->op.link(oldpath, newpath);
Miklos Szeredi76f65782004-02-19 16:55:40 +0000766 if(res == 0)
767 res = lookup_path(f, arg->newdir, in->unique, name,
768 newpath, &outarg);
769 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000770 free(newpath);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000771 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000772 free(oldpath);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000773 }
Miklos Szeredi76f65782004-02-19 16:55:40 +0000774 send_reply(f, in, res, &outarg, sizeof(outarg));
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000775}
776
Miklos Szeredi5e183482001-10-31 14:52:35 +0000777static void do_open(struct fuse *f, struct fuse_in_header *in,
778 struct fuse_open_in *arg)
779{
780 int res;
Miklos Szeredi40b9a5a2002-12-10 16:09:02 +0000781 int res2;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000782 char *path;
783
784 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000785 path = get_path(f, in->ino);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000786 if(path != NULL) {
787 res = -ENOSYS;
788 if(f->op.open)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000789 res = f->op.open(path, arg->flags);
Miklos Szeredi40b9a5a2002-12-10 16:09:02 +0000790 }
791 res2 = send_reply(f, in, res, NULL, 0);
792 if(path != NULL) {
793 /* The open syscall was interrupted, so it must be cancelled */
794 if(res == 0 && res2 == -ENOENT && f->op.release)
Miklos Szeredi9478e862002-12-11 09:50:26 +0000795 f->op.release(path, arg->flags);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000796 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000797 }
Miklos Szeredi5e183482001-10-31 14:52:35 +0000798}
799
Miklos Szeredi9478e862002-12-11 09:50:26 +0000800static void do_release(struct fuse *f, struct fuse_in_header *in,
801 struct fuse_open_in *arg)
Miklos Szeredic8ba2372002-12-10 12:26:00 +0000802{
Miklos Szeredic8ba2372002-12-10 12:26:00 +0000803 char *path;
804
Miklos Szeredic8ba2372002-12-10 12:26:00 +0000805 path = get_path(f, in->ino);
806 if(path != NULL) {
Miklos Szeredic8ba2372002-12-10 12:26:00 +0000807 if(f->op.release)
Miklos Szeredi9478e862002-12-11 09:50:26 +0000808 f->op.release(path, arg->flags);
Miklos Szeredic8ba2372002-12-10 12:26:00 +0000809 free(path);
810 }
Miklos Szeredic8ba2372002-12-10 12:26:00 +0000811}
812
Miklos Szeredi5e183482001-10-31 14:52:35 +0000813static void do_read(struct fuse *f, struct fuse_in_header *in,
814 struct fuse_read_in *arg)
815{
816 int res;
817 char *path;
Miklos Szeredi43696432001-11-18 19:15:05 +0000818 char *outbuf = (char *) malloc(sizeof(struct fuse_out_header) + arg->size);
819 struct fuse_out_header *out = (struct fuse_out_header *) outbuf;
820 char *buf = outbuf + sizeof(struct fuse_out_header);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000821 size_t size;
Miklos Szeredi43696432001-11-18 19:15:05 +0000822 size_t outsize;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000823
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000824 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000825 path = get_path(f, in->ino);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000826 if(path != NULL) {
Miklos Szeredi6ebe2342002-01-06 21:44:16 +0000827 if(f->flags & FUSE_DEBUG) {
828 printf("READ %u bytes from %llu\n", arg->size, arg->offset);
829 fflush(stdout);
830 }
831
Miklos Szeredi5e183482001-10-31 14:52:35 +0000832 res = -ENOSYS;
Miklos Szeredia181e612001-11-06 12:03:23 +0000833 if(f->op.read)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000834 res = f->op.read(path, buf, arg->size, arg->offset);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000835 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000836 }
837
838 size = 0;
839 if(res > 0) {
840 size = res;
841 res = 0;
Miklos Szeredi6ebe2342002-01-06 21:44:16 +0000842 if(f->flags & FUSE_DEBUG) {
843 printf(" READ %u bytes\n", size);
844 fflush(stdout);
845 }
Miklos Szeredi5e183482001-10-31 14:52:35 +0000846 }
Miklos Szeredi0f48a262002-12-05 14:23:01 +0000847 memset(out, 0, sizeof(struct fuse_out_header));
Miklos Szeredi43696432001-11-18 19:15:05 +0000848 out->unique = in->unique;
849 out->error = res;
850 outsize = sizeof(struct fuse_out_header) + size;
851
852 send_reply_raw(f, outbuf, outsize);
853 free(outbuf);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000854}
Miklos Szeredib483c932001-10-29 14:57:57 +0000855
Miklos Szeredia181e612001-11-06 12:03:23 +0000856static void do_write(struct fuse *f, struct fuse_in_header *in,
857 struct fuse_write_in *arg)
858{
859 int res;
860 char *path;
Miklos Szeredia181e612001-11-06 12:03:23 +0000861
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000862 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000863 path = get_path(f, in->ino);
864 if(path != NULL) {
Miklos Szeredi6ebe2342002-01-06 21:44:16 +0000865 if(f->flags & FUSE_DEBUG) {
866 printf("WRITE %u bytes to %llu\n", arg->size, arg->offset);
867 fflush(stdout);
868 }
869
Miklos Szeredia181e612001-11-06 12:03:23 +0000870 res = -ENOSYS;
871 if(f->op.write)
Miklos Szeredi6bf8b682002-10-28 08:49:39 +0000872 res = f->op.write(path, PARAM(arg), arg->size, arg->offset);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000873 free(path);
Miklos Szeredia181e612001-11-06 12:03:23 +0000874 }
875
876 if(res > 0) {
877 if((size_t) res != arg->size) {
878 fprintf(stderr, "short write: %u (should be %u)\n", res,
879 arg->size);
Miklos Szeredi0e535082003-10-13 10:08:06 +0000880 res = -EINVAL;
Miklos Szeredia181e612001-11-06 12:03:23 +0000881 }
882 else
883 res = 0;
884 }
885
886 send_reply(f, in, res, NULL, 0);
887}
888
Miklos Szeredi18e75e42004-02-19 14:23:27 +0000889static void convert_statfs(struct statfs *statfs, struct fuse_kstatfs *kstatfs)
890{
891 kstatfs->bsize = statfs->f_bsize;
892 kstatfs->blocks = statfs->f_blocks;
893 kstatfs->bfree = statfs->f_bfree;
894 kstatfs->bavail = statfs->f_bavail;
895 kstatfs->files = statfs->f_files;
896 kstatfs->ffree = statfs->f_ffree;
897 kstatfs->namelen = statfs->f_namelen;
898}
899
Mark Glinesd84b39a2002-01-07 16:32:02 +0000900static void do_statfs(struct fuse *f, struct fuse_in_header *in)
901{
902 int res;
Mark Glinesd84b39a2002-01-07 16:32:02 +0000903 struct fuse_statfs_out arg;
Miklos Szeredi18e75e42004-02-19 14:23:27 +0000904 struct statfs buf;
Mark Glinesd84b39a2002-01-07 16:32:02 +0000905
906 res = -ENOSYS;
Miklos Szeredi0f48a262002-12-05 14:23:01 +0000907 if(f->op.statfs) {
Miklos Szeredi18e75e42004-02-19 14:23:27 +0000908 res = f->op.statfs("/", &buf);
909 if(res == 0) {
910 memset(&arg, 0, sizeof(struct fuse_statfs_out));
911 convert_statfs(&buf, &arg.st);
912 }
Miklos Szeredi0f48a262002-12-05 14:23:01 +0000913 }
Miklos Szeredi4b2bef42002-01-09 12:23:27 +0000914
Mark Glinesd84b39a2002-01-07 16:32:02 +0000915 send_reply(f, in, res, &arg, sizeof(arg));
916}
917
Miklos Szeredi5e43f2c2003-12-12 14:06:41 +0000918static void do_fsync(struct fuse *f, struct fuse_in_header *in,
919 struct fuse_fsync_in *inarg)
920{
921 int res;
922 char *path;
923
924 res = -ENOENT;
925 path = get_path(f, in->ino);
926 if(path != NULL) {
927 /* fsync is not mandatory, so don't return ENOSYS */
928 res = 0;
929 if(f->op.fsync)
930 res = f->op.fsync(path, inarg->datasync);
931 free(path);
932 }
933 send_reply(f, in, res, NULL, 0);
934}
935
Miklos Szeredi43696432001-11-18 19:15:05 +0000936static void free_cmd(struct fuse_cmd *cmd)
937{
938 free(cmd->buf);
939 free(cmd);
940}
941
Miklos Szeredifff56ab2001-11-16 10:12:59 +0000942void __fuse_process_cmd(struct fuse *f, struct fuse_cmd *cmd)
Miklos Szeredia181e612001-11-06 12:03:23 +0000943{
Miklos Szeredia181e612001-11-06 12:03:23 +0000944 struct fuse_in_header *in = (struct fuse_in_header *) cmd->buf;
945 void *inarg = cmd->buf + sizeof(struct fuse_in_header);
946 size_t argsize;
Miklos Szeredife25def2001-12-20 15:38:05 +0000947 struct fuse_context *ctx = fuse_get_context(f);
Miklos Szeredia181e612001-11-06 12:03:23 +0000948
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +0000949 dec_avail(f);
Miklos Szeredi33232032001-11-19 17:55:51 +0000950
Miklos Szeredic0938ea2001-11-07 12:35:06 +0000951 if((f->flags & FUSE_DEBUG)) {
Miklos Szeredic8ba2372002-12-10 12:26:00 +0000952 printf("unique: %i, opcode: %s (%i), ino: %li, insize: %i\n",
953 in->unique, opname(in->opcode), in->opcode, in->ino,
954 cmd->buflen);
Miklos Szeredic0938ea2001-11-07 12:35:06 +0000955 fflush(stdout);
956 }
Miklos Szeredife25def2001-12-20 15:38:05 +0000957
958 ctx->uid = in->uid;
959 ctx->gid = in->gid;
Miklos Szeredia181e612001-11-06 12:03:23 +0000960
961 argsize = cmd->buflen - sizeof(struct fuse_in_header);
962
963 switch(in->opcode) {
964 case FUSE_LOOKUP:
965 do_lookup(f, in, (char *) inarg);
966 break;
967
Miklos Szeredia181e612001-11-06 12:03:23 +0000968 case FUSE_GETATTR:
969 do_getattr(f, in);
970 break;
971
972 case FUSE_SETATTR:
973 do_setattr(f, in, (struct fuse_setattr_in *) inarg);
974 break;
975
976 case FUSE_READLINK:
977 do_readlink(f, in);
978 break;
979
980 case FUSE_GETDIR:
981 do_getdir(f, in);
982 break;
983
984 case FUSE_MKNOD:
985 do_mknod(f, in, (struct fuse_mknod_in *) inarg);
986 break;
987
988 case FUSE_MKDIR:
989 do_mkdir(f, in, (struct fuse_mkdir_in *) inarg);
990 break;
991
992 case FUSE_UNLINK:
993 case FUSE_RMDIR:
994 do_remove(f, in, (char *) inarg);
995 break;
996
997 case FUSE_SYMLINK:
998 do_symlink(f, in, (char *) inarg,
999 ((char *) inarg) + strlen((char *) inarg) + 1);
1000 break;
1001
1002 case FUSE_RENAME:
1003 do_rename(f, in, (struct fuse_rename_in *) inarg);
1004 break;
1005
1006 case FUSE_LINK:
1007 do_link(f, in, (struct fuse_link_in *) inarg);
1008 break;
1009
1010 case FUSE_OPEN:
1011 do_open(f, in, (struct fuse_open_in *) inarg);
1012 break;
1013
Miklos Szeredi9478e862002-12-11 09:50:26 +00001014 case FUSE_RELEASE:
1015 do_release(f, in, (struct fuse_open_in *) inarg);
1016 break;
1017
Miklos Szeredia181e612001-11-06 12:03:23 +00001018 case FUSE_READ:
1019 do_read(f, in, (struct fuse_read_in *) inarg);
1020 break;
1021
1022 case FUSE_WRITE:
1023 do_write(f, in, (struct fuse_write_in *) inarg);
1024 break;
1025
Mark Glinesd84b39a2002-01-07 16:32:02 +00001026 case FUSE_STATFS:
1027 do_statfs(f, in);
1028 break;
1029
Miklos Szeredi5e43f2c2003-12-12 14:06:41 +00001030 case FUSE_FSYNC:
1031 do_fsync(f, in, (struct fuse_fsync_in *) inarg);
1032 break;
1033
Miklos Szeredia181e612001-11-06 12:03:23 +00001034 default:
Miklos Szeredi43696432001-11-18 19:15:05 +00001035 send_reply(f, in, -ENOSYS, NULL, 0);
Miklos Szeredia181e612001-11-06 12:03:23 +00001036 }
Miklos Szeredi43696432001-11-18 19:15:05 +00001037
1038 free_cmd(cmd);
Miklos Szeredia181e612001-11-06 12:03:23 +00001039}
1040
Miklos Szeredifff56ab2001-11-16 10:12:59 +00001041struct fuse_cmd *__fuse_read_cmd(struct fuse *f)
Miklos Szeredi2df1c042001-11-06 15:07:17 +00001042{
Miklos Szeredifff56ab2001-11-16 10:12:59 +00001043 ssize_t res;
Miklos Szeredifff56ab2001-11-16 10:12:59 +00001044 struct fuse_cmd *cmd;
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +00001045 struct fuse_in_header *in;
1046 void *inarg;
Miklos Szeredifff56ab2001-11-16 10:12:59 +00001047
Miklos Szeredi43696432001-11-18 19:15:05 +00001048 cmd = (struct fuse_cmd *) malloc(sizeof(struct fuse_cmd));
1049 cmd->buf = (char *) malloc(FUSE_MAX_IN);
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +00001050 in = (struct fuse_in_header *) cmd->buf;
1051 inarg = cmd->buf + sizeof(struct fuse_in_header);
Miklos Szeredi43696432001-11-18 19:15:05 +00001052
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +00001053 do {
1054 res = read(f->fd, cmd->buf, FUSE_MAX_IN);
1055 if(res == -1) {
Miklos Szeredi0f48a262002-12-05 14:23:01 +00001056 free_cmd(cmd);
Miklos Szeredi307242f2004-01-26 11:28:44 +00001057 if(f->exited || errno == EINTR)
Miklos Szeredi0f48a262002-12-05 14:23:01 +00001058 return NULL;
1059
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +00001060 /* ENODEV means we got unmounted, so we silenty return failure */
1061 if(errno != ENODEV) {
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +00001062 /* BAD... This will happen again */
Miklos Szeredi0f48a262002-12-05 14:23:01 +00001063 perror("fuse: reading device");
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +00001064 }
Miklos Szeredi0f48a262002-12-05 14:23:01 +00001065
1066 fuse_exit(f);
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +00001067 return NULL;
Miklos Szeredi96249982001-11-21 12:21:19 +00001068 }
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +00001069 if((size_t) res < sizeof(struct fuse_in_header)) {
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +00001070 free_cmd(cmd);
Miklos Szeredi0f48a262002-12-05 14:23:01 +00001071 /* Cannot happen */
1072 fprintf(stderr, "short read on fuse device\n");
1073 fuse_exit(f);
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +00001074 return NULL;
1075 }
1076 cmd->buflen = res;
1077
1078 /* Forget is special, it can be done without messing with threads. */
1079 if(in->opcode == FUSE_FORGET)
1080 do_forget(f, in, (struct fuse_forget_in *) inarg);
1081
1082 } while(in->opcode == FUSE_FORGET);
1083
Miklos Szeredifff56ab2001-11-16 10:12:59 +00001084 return cmd;
Miklos Szeredi2df1c042001-11-06 15:07:17 +00001085}
1086
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001087void fuse_loop(struct fuse *f)
1088{
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001089 while(1) {
Miklos Szeredi0f48a262002-12-05 14:23:01 +00001090 struct fuse_cmd *cmd;
1091
1092 if(f->exited)
1093 return;
1094
1095 cmd = __fuse_read_cmd(f);
Miklos Szeredifff56ab2001-11-16 10:12:59 +00001096 if(cmd == NULL)
Miklos Szeredi0f48a262002-12-05 14:23:01 +00001097 continue;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001098
Miklos Szeredifff56ab2001-11-16 10:12:59 +00001099 __fuse_process_cmd(f, cmd);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001100 }
1101}
1102
Miklos Szeredi0f48a262002-12-05 14:23:01 +00001103void fuse_exit(struct fuse *f)
1104{
1105 f->exited = 1;
1106}
1107
Miklos Szeredi2e50d432001-12-20 12:17:25 +00001108struct fuse_context *fuse_get_context(struct fuse *f)
1109{
1110 if(f->getcontext)
1111 return f->getcontext(f);
1112 else
1113 return &f->context;
1114}
1115
1116struct fuse *fuse_new(int fd, int flags, const struct fuse_operations *op)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001117{
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001118 struct fuse *f;
1119 struct node *root;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001120
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001121 f = (struct fuse *) calloc(1, sizeof(struct fuse));
Miklos Szeredi2df1c042001-11-06 15:07:17 +00001122
Miklos Szeredia181e612001-11-06 12:03:23 +00001123 f->flags = flags;
Miklos Szeredi8cffdb92001-11-09 14:49:18 +00001124 f->fd = fd;
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001125 f->ctr = 0;
Miklos Szeredi76f65782004-02-19 16:55:40 +00001126 f->generation = 0;
Miklos Szeredifff56ab2001-11-16 10:12:59 +00001127 /* FIXME: Dynamic hash table */
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001128 f->name_table_size = 14057;
1129 f->name_table = (struct node **)
1130 calloc(1, sizeof(struct node *) * f->name_table_size);
1131 f->ino_table_size = 14057;
1132 f->ino_table = (struct node **)
1133 calloc(1, sizeof(struct node *) * f->ino_table_size);
Miklos Szeredia181e612001-11-06 12:03:23 +00001134 pthread_mutex_init(&f->lock, NULL);
Miklos Szeredi33232032001-11-19 17:55:51 +00001135 f->numworker = 0;
1136 f->numavail = 0;
Miklos Szeredi2e50d432001-12-20 12:17:25 +00001137 f->op = *op;
1138 f->getcontext = NULL;
1139 f->context.uid = 0;
1140 f->context.gid = 0;
Miklos Szeredi0f48a262002-12-05 14:23:01 +00001141 f->exited = 0;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001142
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001143 root = (struct node *) calloc(1, sizeof(struct node));
Miklos Szeredi8cffdb92001-11-09 14:49:18 +00001144 root->mode = 0;
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001145 root->rdev = 0;
1146 root->name = strdup("/");
1147 root->parent = 0;
Miklos Szeredi76f65782004-02-19 16:55:40 +00001148 root->ino = FUSE_ROOT_INO;
1149 root->generation = 0;
1150 hash_ino(f, root);
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001151
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001152 return f;
1153}
1154
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001155void fuse_destroy(struct fuse *f)
1156{
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001157 size_t i;
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001158 for(i = 0; i < f->ino_table_size; i++) {
1159 struct node *node;
1160 struct node *next;
1161 for(node = f->ino_table[i]; node != NULL; node = next) {
1162 next = node->ino_next;
1163 free_node(node);
1164 }
1165 }
1166 free(f->ino_table);
1167 free(f->name_table);
Miklos Szeredia181e612001-11-06 12:03:23 +00001168 pthread_mutex_destroy(&f->lock);
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001169 free(f);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001170}