blob: 1a11ae63fba5c9759b482a93da7e212f2b11a086 [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 Szeredi99ddf0e2001-11-25 17:19:59 +000022static inline void inc_avail(struct fuse *f)
23{
24 pthread_mutex_lock(&f->lock);
25 f->numavail ++;
26 pthread_mutex_unlock(&f->lock);
27}
28
29static inline void dec_avail(struct fuse *f)
30{
31 pthread_mutex_lock(&f->lock);
32 f->numavail --;
33 pthread_mutex_unlock(&f->lock);
34}
35
Miklos Szeredi97c61e92001-11-07 12:09:43 +000036static struct node *__get_node(struct fuse *f, fino_t ino)
Miklos Szeredia181e612001-11-06 12:03:23 +000037{
Miklos Szeredi97c61e92001-11-07 12:09:43 +000038 size_t hash = ino % f->ino_table_size;
39 struct node *node;
40
41 for(node = f->ino_table[hash]; node != NULL; node = node->ino_next)
42 if(node->ino == ino)
43 return node;
44
45 return NULL;
Miklos Szeredia181e612001-11-06 12:03:23 +000046}
47
Miklos Szeredi97c61e92001-11-07 12:09:43 +000048static struct node *get_node(struct fuse *f, fino_t ino)
Miklos Szeredia181e612001-11-06 12:03:23 +000049{
Miklos Szeredi97c61e92001-11-07 12:09:43 +000050 struct node *node = __get_node(f, ino);
51 if(node != NULL)
52 return node;
53
54 fprintf(stderr, "fuse internal error: inode %lu not found\n", ino);
55 abort();
Miklos Szeredia181e612001-11-06 12:03:23 +000056}
57
Miklos Szeredi97c61e92001-11-07 12:09:43 +000058static void hash_ino(struct fuse *f, struct node *node, fino_t ino)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000059{
Miklos Szeredi97c61e92001-11-07 12:09:43 +000060 size_t hash = ino % f->ino_table_size;
61 node->ino = ino;
62
63 node->ino_next = f->ino_table[hash];
64 f->ino_table[hash] = node;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000065}
66
Miklos Szeredi97c61e92001-11-07 12:09:43 +000067static void unhash_ino(struct fuse *f, struct node *node)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000068{
Miklos Szeredi97c61e92001-11-07 12:09:43 +000069 size_t hash = node->ino % f->ino_table_size;
70 struct node **nodep = &f->ino_table[hash];
71
72 for(; *nodep != NULL; nodep = &(*nodep)->ino_next)
73 if(*nodep == node) {
74 *nodep = node->ino_next;
75 return;
76 }
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000077}
78
Miklos Szeredi97c61e92001-11-07 12:09:43 +000079static fino_t get_ino(struct node *node)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000080{
Miklos Szeredi97c61e92001-11-07 12:09:43 +000081 return node->ino;
82}
83
84static fino_t next_ino(struct fuse *f)
85{
86 while(f->ctr == 0 || __get_node(f, f->ctr) != NULL)
87 f->ctr++;
88
89 return f->ctr;
90}
91
92static void free_node(struct node *node)
93{
94 free(node->name);
95 free(node);
96}
97
98static unsigned int name_hash(struct fuse *f, fino_t parent, const char *name)
99{
100 unsigned int hash = *name;
101
102 if(hash)
103 for(name += 1; *name != '\0'; name++)
104 hash = (hash << 5) - hash + *name;
105
106 return (hash + parent) % f->name_table_size;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000107}
108
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000109static struct node *lookup_node(struct fuse *f, fino_t parent,
110 const char *name)
111{
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000112 size_t hash = name_hash(f, parent, name);
113 struct node *node;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000114
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000115 for(node = f->name_table[hash]; node != NULL; node = node->name_next)
116 if(node->parent == parent && strcmp(node->name, name) == 0)
117 return node;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000118
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000119 return NULL;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000120}
121
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000122static void hash_name(struct fuse *f, struct node *node, fino_t parent,
Miklos Szeredia181e612001-11-06 12:03:23 +0000123 const char *name)
Miklos Szeredi5e183482001-10-31 14:52:35 +0000124{
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000125 size_t hash = name_hash(f, parent, name);
Miklos Szeredia181e612001-11-06 12:03:23 +0000126 node->parent = parent;
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000127 node->name = strdup(name);
128 node->name_next = f->name_table[hash];
129 f->name_table[hash] = node;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000130}
131
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000132static void unhash_name(struct fuse *f, struct node *node)
Miklos Szeredia181e612001-11-06 12:03:23 +0000133{
134 if(node->name != NULL) {
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000135 size_t hash = name_hash(f, node->parent, node->name);
136 struct node **nodep = &f->name_table[hash];
137
138 for(; *nodep != NULL; nodep = &(*nodep)->name_next)
139 if(*nodep == node) {
140 *nodep = node->name_next;
141 node->name_next = NULL;
142 free(node->name);
143 node->name = NULL;
144 node->parent = 0;
145 return;
146 }
147 fprintf(stderr, "fuse internal error: unable to unhash node: %lu\n",
148 node->ino);
149 abort();
Miklos Szeredia181e612001-11-06 12:03:23 +0000150 }
151}
152
153static fino_t find_node(struct fuse *f, fino_t parent, char *name,
154 struct fuse_attr *attr, int version)
Miklos Szeredi5e183482001-10-31 14:52:35 +0000155{
156 struct node *node;
Miklos Szeredia181e612001-11-06 12:03:23 +0000157 int mode = attr->mode & S_IFMT;
158 int rdev = 0;
159
160 if(S_ISCHR(mode) || S_ISBLK(mode))
161 rdev = attr->rdev;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000162
Miklos Szeredia181e612001-11-06 12:03:23 +0000163 pthread_mutex_lock(&f->lock);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000164 node = lookup_node(f, parent, name);
165 if(node != NULL) {
Miklos Szeredia181e612001-11-06 12:03:23 +0000166 if(node->mode == mode && node->rdev == rdev)
167 goto out;
168
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000169 unhash_name(f, node);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000170 }
171
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000172 node = (struct node *) calloc(1, sizeof(struct node));
Miklos Szeredia181e612001-11-06 12:03:23 +0000173 node->mode = mode;
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000174 node->rdev = rdev;
175 hash_ino(f, node, next_ino(f));
176 hash_name(f, node, parent, name);
Miklos Szeredia181e612001-11-06 12:03:23 +0000177
178 out:
179 node->version = version;
180 pthread_mutex_unlock(&f->lock);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000181 return get_ino(node);
182}
183
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000184static char *add_name(char *buf, char *s, const char *name)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000185{
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000186 size_t len = strlen(name);
187 s -= len;
188 if(s <= buf) {
189 fprintf(stderr, "fuse: path too long: ...%s\n", s + len);
190 return NULL;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000191 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000192 strncpy(s, name, len);
193 s--;
194 *s = '/';
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000195
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000196 return s;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000197}
198
Miklos Szeredia181e612001-11-06 12:03:23 +0000199static char *get_path_name(struct fuse *f, fino_t ino, const char *name)
Miklos Szeredib483c932001-10-29 14:57:57 +0000200{
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000201 char buf[FUSE_MAX_PATH];
202 char *s = buf + FUSE_MAX_PATH - 1;
203 struct node *node;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000204
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000205 *s = '\0';
Miklos Szeredia181e612001-11-06 12:03:23 +0000206
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000207 if(name != NULL) {
208 s = add_name(buf, s, name);
209 if(s == NULL)
210 return NULL;
211 }
212
213 pthread_mutex_lock(&f->lock);
214 for(node = get_node(f, ino); node->ino != FUSE_ROOT_INO;
215 node = get_node(f, node->parent)) {
216 if(node->name == NULL) {
217 s = NULL;
218 break;
219 }
220
221 s = add_name(buf, s, node->name);
222 if(s == NULL)
223 break;
224 }
225 pthread_mutex_unlock(&f->lock);
226
227 if(s == NULL)
Miklos Szeredi5e183482001-10-31 14:52:35 +0000228 return NULL;
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000229 else if(*s == '\0')
230 return strdup("/");
231 else
232 return strdup(s);
233}
Miklos Szeredia181e612001-11-06 12:03:23 +0000234
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000235static char *get_path(struct fuse *f, fino_t ino)
236{
237 return get_path_name(f, ino, NULL);
Miklos Szeredib483c932001-10-29 14:57:57 +0000238}
239
Miklos Szeredia181e612001-11-06 12:03:23 +0000240static void destroy_node(struct fuse *f, fino_t ino, int version)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000241{
Miklos Szeredia181e612001-11-06 12:03:23 +0000242 struct node *node;
243
244 pthread_mutex_lock(&f->lock);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000245 node = get_node(f, ino);
Miklos Szeredi39f28672001-11-14 14:52:54 +0000246 if(node->version == version && ino != FUSE_ROOT_INO) {
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000247 unhash_name(f, node);
248 unhash_ino(f, node);
Miklos Szeredia181e612001-11-06 12:03:23 +0000249 free_node(node);
250 }
251 pthread_mutex_unlock(&f->lock);
252
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000253}
254
Miklos Szeredi5e183482001-10-31 14:52:35 +0000255static void remove_node(struct fuse *f, fino_t dir, const char *name)
256{
Miklos Szeredia181e612001-11-06 12:03:23 +0000257 struct node *node;
258
259 pthread_mutex_lock(&f->lock);
260 node = lookup_node(f, dir, name);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000261 if(node == NULL) {
262 fprintf(stderr, "fuse internal error: unable to remove node %lu/%s\n",
263 dir, name);
264 abort();
265 }
266 unhash_name(f, node);
Miklos Szeredia181e612001-11-06 12:03:23 +0000267 pthread_mutex_unlock(&f->lock);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000268}
269
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000270static void rename_node(struct fuse *f, fino_t olddir, const char *oldname,
271 fino_t newdir, const char *newname)
272{
Miklos Szeredia181e612001-11-06 12:03:23 +0000273 struct node *node;
274 struct node *newnode;
275
276 pthread_mutex_lock(&f->lock);
277 node = lookup_node(f, olddir, oldname);
278 newnode = lookup_node(f, newdir, newname);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000279 if(node == NULL) {
280 fprintf(stderr, "fuse internal error: unable to rename node %lu/%s\n",
281 olddir, oldname);
282 abort();
283 }
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000284
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000285 if(newnode != NULL)
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000286 unhash_name(f, newnode);
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000287
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000288 unhash_name(f, node);
289 hash_name(f, node, newdir, newname);
Miklos Szeredia181e612001-11-06 12:03:23 +0000290 pthread_mutex_unlock(&f->lock);
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000291}
292
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000293static void convert_stat(struct stat *stbuf, struct fuse_attr *attr)
294{
295 attr->mode = stbuf->st_mode;
296 attr->nlink = stbuf->st_nlink;
297 attr->uid = stbuf->st_uid;
298 attr->gid = stbuf->st_gid;
299 attr->rdev = stbuf->st_rdev;
300 attr->size = stbuf->st_size;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000301 attr->blocks = stbuf->st_blocks;
302 attr->atime = stbuf->st_atime;
303 attr->mtime = stbuf->st_mtime;
304 attr->ctime = stbuf->st_ctime;
Miklos Szeredifff56ab2001-11-16 10:12:59 +0000305 attr->_dummy = 4096;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000306}
307
Miklos Szeredia181e612001-11-06 12:03:23 +0000308static int fill_dir(struct fuse_dirhandle *dh, char *name, int type)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000309{
310 struct fuse_dirent dirent;
311 size_t reclen;
312 size_t res;
313
Miklos Szeredi43696432001-11-18 19:15:05 +0000314 dirent.ino = (unsigned long) -1;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000315 dirent.namelen = strlen(name);
316 strncpy(dirent.name, name, sizeof(dirent.name));
317 dirent.type = type;
318 reclen = FUSE_DIRENT_SIZE(&dirent);
319 res = fwrite(&dirent, reclen, 1, dh->fp);
320 if(res == 0) {
Miklos Szeredi96249982001-11-21 12:21:19 +0000321 perror("fuse: writing directory file");
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000322 return -EIO;
323 }
324 return 0;
325}
326
Miklos Szeredi43696432001-11-18 19:15:05 +0000327static void send_reply_raw(struct fuse *f, char *outbuf, size_t outsize)
328{
329 int res;
330
331 if((f->flags & FUSE_DEBUG)) {
332 struct fuse_out_header *out = (struct fuse_out_header *) outbuf;
333 printf(" unique: %i, error: %i (%s), outsize: %i\n", out->unique,
334 out->error, strerror(-out->error), outsize);
335 fflush(stdout);
336 }
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +0000337
338 /* This needs to be done before the reply because otherwise the
339 scheduler can tricks with us, and only let the counter be increased
340 long after the operation is done */
341 inc_avail(f);
342
Miklos Szeredi43696432001-11-18 19:15:05 +0000343 res = write(f->fd, outbuf, outsize);
344 if(res == -1) {
345 /* ENOENT means the operation was interrupted */
346 if(errno != ENOENT)
Miklos Szeredi96249982001-11-21 12:21:19 +0000347 perror("fuse: writing device");
Miklos Szeredi43696432001-11-18 19:15:05 +0000348 }
349}
350
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000351static void send_reply(struct fuse *f, struct fuse_in_header *in, int error,
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000352 void *arg, size_t argsize)
353{
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000354 char *outbuf;
355 size_t outsize;
356 struct fuse_out_header *out;
357
Miklos Szeredi0f48a262002-12-05 14:23:01 +0000358 if(error <= -512 || error > 0) {
359 fprintf(stderr, "fuse: bad error value: %i\n", error);
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000360 error = -ERANGE;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000361 }
362
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000363 if(error)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000364 argsize = 0;
365
366 outsize = sizeof(struct fuse_out_header) + argsize;
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000367 outbuf = (char *) malloc(outsize);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000368 out = (struct fuse_out_header *) outbuf;
Miklos Szeredi0f48a262002-12-05 14:23:01 +0000369 memset(out, 0, sizeof(struct fuse_out_header));
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000370 out->unique = in->unique;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000371 out->error = error;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000372 if(argsize != 0)
373 memcpy(outbuf + sizeof(struct fuse_out_header), arg, argsize);
374
Miklos Szeredi43696432001-11-18 19:15:05 +0000375 send_reply_raw(f, outbuf, outsize);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000376
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000377 free(outbuf);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000378}
379
380static void do_lookup(struct fuse *f, struct fuse_in_header *in, char *name)
381{
382 int res;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000383 char *path;
384 struct stat buf;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000385 struct fuse_lookup_out arg;
386
Miklos Szeredi5e183482001-10-31 14:52:35 +0000387 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000388 path = get_path_name(f, in->ino, name);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000389 if(path != NULL) {
Miklos Szeredi6ebe2342002-01-06 21:44:16 +0000390 if(f->flags & FUSE_DEBUG) {
391 printf("LOOKUP %s\n", path);
392 fflush(stdout);
393 }
Miklos Szeredi5e183482001-10-31 14:52:35 +0000394 res = -ENOSYS;
395 if(f->op.getattr)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000396 res = f->op.getattr(path, &buf);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000397 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000398 }
Miklos Szeredi0f48a262002-12-05 14:23:01 +0000399
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000400 if(res == 0) {
Miklos Szeredi0f48a262002-12-05 14:23:01 +0000401 memset(&arg, 0, sizeof(struct fuse_lookup_out));
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000402 convert_stat(&buf, &arg.attr);
Miklos Szeredia181e612001-11-06 12:03:23 +0000403 arg.ino = find_node(f, in->ino, name, &arg.attr, in->unique);
Miklos Szeredi6ebe2342002-01-06 21:44:16 +0000404 if(f->flags & FUSE_DEBUG) {
405 printf(" LOOKUP: %li\n", arg.ino);
406 fflush(stdout);
407 }
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000408 }
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000409 send_reply(f, in, res, &arg, sizeof(arg));
410}
411
Miklos Szeredia181e612001-11-06 12:03:23 +0000412static void do_forget(struct fuse *f, struct fuse_in_header *in,
413 struct fuse_forget_in *arg)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000414{
Miklos Szeredi43696432001-11-18 19:15:05 +0000415 if(f->flags & FUSE_DEBUG) {
416 printf("FORGET %li/%i\n", in->ino, arg->version);
417 fflush(stdout);
418 }
Miklos Szeredia181e612001-11-06 12:03:23 +0000419 destroy_node(f, in->ino, arg->version);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000420}
421
422static void do_getattr(struct fuse *f, struct fuse_in_header *in)
423{
424 int res;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000425 char *path;
426 struct stat buf;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000427 struct fuse_getattr_out arg;
428
Miklos Szeredi5e183482001-10-31 14:52:35 +0000429 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000430 path = get_path(f, in->ino);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000431 if(path != NULL) {
432 res = -ENOSYS;
433 if(f->op.getattr)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000434 res = f->op.getattr(path, &buf);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000435 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000436 }
Miklos Szeredi0f48a262002-12-05 14:23:01 +0000437
438 if(res == 0) {
439 memset(&arg, 0, sizeof(struct fuse_getattr_out));
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000440 convert_stat(&buf, &arg.attr);
Miklos Szeredi0f48a262002-12-05 14:23:01 +0000441 }
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000442
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000443 send_reply(f, in, res, &arg, sizeof(arg));
444}
445
Miklos Szeredi680a69a2001-11-16 13:31:14 +0000446static int do_chmod(struct fuse *f, const char *path, struct fuse_attr *attr)
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000447{
448 int res;
449
450 res = -ENOSYS;
451 if(f->op.chmod)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000452 res = f->op.chmod(path, attr->mode);
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000453
454 return res;
455}
456
Miklos Szeredi680a69a2001-11-16 13:31:14 +0000457static int do_chown(struct fuse *f, const char *path, struct fuse_attr *attr,
Miklos Szeredi2e50d432001-12-20 12:17:25 +0000458 int valid)
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000459{
460 int res;
461 uid_t uid = (valid & FATTR_UID) ? attr->uid : (uid_t) -1;
462 gid_t gid = (valid & FATTR_GID) ? attr->gid : (gid_t) -1;
463
464 res = -ENOSYS;
465 if(f->op.chown)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000466 res = f->op.chown(path, uid, gid);
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000467
468 return res;
469}
470
Miklos Szeredi680a69a2001-11-16 13:31:14 +0000471static int do_truncate(struct fuse *f, const char *path,
472 struct fuse_attr *attr)
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000473{
474 int res;
475
476 res = -ENOSYS;
477 if(f->op.truncate)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000478 res = f->op.truncate(path, attr->size);
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000479
480 return res;
481}
482
Miklos Szeredi680a69a2001-11-16 13:31:14 +0000483static int do_utime(struct fuse *f, const char *path, struct fuse_attr *attr)
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000484{
485 int res;
486 struct utimbuf buf;
487 buf.actime = attr->atime;
488 buf.modtime = attr->mtime;
489 res = -ENOSYS;
490 if(f->op.utime)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000491 res = f->op.utime(path, &buf);
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000492
493 return res;
494}
495
Miklos Szeredi5e183482001-10-31 14:52:35 +0000496static void do_setattr(struct fuse *f, struct fuse_in_header *in,
497 struct fuse_setattr_in *arg)
498{
499 int res;
500 char *path;
501 int valid = arg->valid;
502 struct fuse_attr *attr = &arg->attr;
Miklos Szeredia181e612001-11-06 12:03:23 +0000503 struct fuse_setattr_out outarg;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000504
505 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000506 path = get_path(f, in->ino);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000507 if(path != NULL) {
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000508 res = -ENOSYS;
509 if(f->op.getattr) {
510 res = 0;
511 if(!res && (valid & FATTR_MODE))
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000512 res = do_chmod(f, path, attr);
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000513 if(!res && (valid & (FATTR_UID | FATTR_GID)))
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000514 res = do_chown(f, path, attr, valid);
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000515 if(!res && (valid & FATTR_SIZE))
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000516 res = do_truncate(f, path, attr);
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000517 if(!res && (valid & FATTR_UTIME))
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000518 res = do_utime(f, path, attr);
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000519 if(!res) {
520 struct stat buf;
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000521 res = f->op.getattr(path, &buf);
Miklos Szeredi0f48a262002-12-05 14:23:01 +0000522 if(!res) {
523 memset(&outarg, 0, sizeof(struct fuse_setattr_out));
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000524 convert_stat(&buf, &outarg.attr);
Miklos Szeredi0f48a262002-12-05 14:23:01 +0000525 }
Miklos Szeredia181e612001-11-06 12:03:23 +0000526 }
Miklos Szeredi5e183482001-10-31 14:52:35 +0000527 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000528 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000529 }
Miklos Szeredia181e612001-11-06 12:03:23 +0000530 send_reply(f, in, res, &outarg, sizeof(outarg));
Miklos Szeredi5e183482001-10-31 14:52:35 +0000531}
532
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000533static void do_readlink(struct fuse *f, struct fuse_in_header *in)
534{
535 int res;
536 char link[PATH_MAX + 1];
Miklos Szeredib483c932001-10-29 14:57:57 +0000537 char *path;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000538
Miklos Szeredi5e183482001-10-31 14:52:35 +0000539 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000540 path = get_path(f, in->ino);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000541 if(path != NULL) {
542 res = -ENOSYS;
543 if(f->op.readlink)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000544 res = f->op.readlink(path, link, sizeof(link));
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000545 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000546 }
Miklos Szeredi2df1c042001-11-06 15:07:17 +0000547 link[PATH_MAX] = '\0';
Miklos Szeredi4b2bef42002-01-09 12:23:27 +0000548 send_reply(f, in, res, link, res == 0 ? strlen(link) : 0);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000549}
550
551static void do_getdir(struct fuse *f, struct fuse_in_header *in)
552{
553 int res;
554 struct fuse_getdir_out arg;
Miklos Szeredia181e612001-11-06 12:03:23 +0000555 struct fuse_dirhandle dh;
Miklos Szeredib483c932001-10-29 14:57:57 +0000556 char *path;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000557
Miklos Szeredib483c932001-10-29 14:57:57 +0000558 dh.fuse = f;
559 dh.fp = tmpfile();
560 dh.dir = in->ino;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000561 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000562 path = get_path(f, in->ino);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000563 if(path != NULL) {
564 res = -ENOSYS;
565 if(f->op.getdir)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000566 res = f->op.getdir(path, &dh, (fuse_dirfil_t) fill_dir);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000567 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000568 }
Miklos Szeredib483c932001-10-29 14:57:57 +0000569 fflush(dh.fp);
Miklos Szeredi0f48a262002-12-05 14:23:01 +0000570
571 memset(&arg, 0, sizeof(struct fuse_getdir_out));
Miklos Szeredib483c932001-10-29 14:57:57 +0000572 arg.fd = fileno(dh.fp);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000573 send_reply(f, in, res, &arg, sizeof(arg));
Miklos Szeredib483c932001-10-29 14:57:57 +0000574 fclose(dh.fp);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000575}
576
Miklos Szeredib483c932001-10-29 14:57:57 +0000577static void do_mknod(struct fuse *f, struct fuse_in_header *in,
578 struct fuse_mknod_in *inarg)
579{
580 int res;
581 char *path;
582 struct fuse_mknod_out outarg;
583 struct stat buf;
584
Miklos Szeredi5e183482001-10-31 14:52:35 +0000585 res = -ENOENT;
Miklos Szeredi6bf8b682002-10-28 08:49:39 +0000586 path = get_path_name(f, in->ino, PARAM(inarg));
Miklos Szeredi5e183482001-10-31 14:52:35 +0000587 if(path != NULL) {
588 res = -ENOSYS;
589 if(f->op.mknod && f->op.getattr) {
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000590 res = f->op.mknod(path, inarg->mode, inarg->rdev);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000591 if(res == 0)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000592 res = f->op.getattr(path, &buf);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000593 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000594 free(path);
Miklos Szeredib483c932001-10-29 14:57:57 +0000595 }
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000596 if(res == 0) {
Miklos Szeredi0f48a262002-12-05 14:23:01 +0000597 memset(&outarg, 0, sizeof(struct fuse_mknod_out));
Miklos Szeredib483c932001-10-29 14:57:57 +0000598 convert_stat(&buf, &outarg.attr);
Miklos Szeredi6bf8b682002-10-28 08:49:39 +0000599 outarg.ino = find_node(f, in->ino, PARAM(inarg), &outarg.attr,
Miklos Szeredia181e612001-11-06 12:03:23 +0000600 in->unique);
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000601 }
Miklos Szeredib483c932001-10-29 14:57:57 +0000602
603 send_reply(f, in, res, &outarg, sizeof(outarg));
604}
605
606static void do_mkdir(struct fuse *f, struct fuse_in_header *in,
607 struct fuse_mkdir_in *inarg)
608{
609 int res;
610 char *path;
611
Miklos Szeredi5e183482001-10-31 14:52:35 +0000612 res = -ENOENT;
Miklos Szeredi6bf8b682002-10-28 08:49:39 +0000613 path = get_path_name(f, in->ino, PARAM(inarg));
Miklos Szeredi5e183482001-10-31 14:52:35 +0000614 if(path != NULL) {
615 res = -ENOSYS;
616 if(f->op.mkdir)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000617 res = f->op.mkdir(path, inarg->mode);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000618 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000619 }
Miklos Szeredib483c932001-10-29 14:57:57 +0000620 send_reply(f, in, res, NULL, 0);
621}
622
623static void do_remove(struct fuse *f, struct fuse_in_header *in, char *name)
624{
625 int res;
626 char *path;
627
Miklos Szeredi5e183482001-10-31 14:52:35 +0000628 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000629 path = get_path_name(f, in->ino, name);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000630 if(path != NULL) {
631 res = -ENOSYS;
632 if(in->opcode == FUSE_UNLINK) {
633 if(f->op.unlink)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000634 res = f->op.unlink(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000635 }
636 else {
637 if(f->op.rmdir)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000638 res = f->op.rmdir(path);
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 Szeredi5e183482001-10-31 14:52:35 +0000642 if(res == 0)
643 remove_node(f, in->ino, name);
Miklos Szeredib483c932001-10-29 14:57:57 +0000644 send_reply(f, in, res, NULL, 0);
645}
646
647static void do_symlink(struct fuse *f, struct fuse_in_header *in, char *name,
648 char *link)
649{
650 int res;
651 char *path;
652
Miklos Szeredi5e183482001-10-31 14:52:35 +0000653 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000654 path = get_path_name(f, in->ino, name);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000655 if(path != NULL) {
656 res = -ENOSYS;
657 if(f->op.symlink)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000658 res = f->op.symlink(link, path);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000659 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000660 }
Miklos Szeredib483c932001-10-29 14:57:57 +0000661 send_reply(f, in, res, NULL, 0);
662}
663
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000664static void do_rename(struct fuse *f, struct fuse_in_header *in,
665 struct fuse_rename_in *inarg)
666{
667 int res;
668 fino_t olddir = in->ino;
669 fino_t newdir = inarg->newdir;
Miklos Szeredi6bf8b682002-10-28 08:49:39 +0000670 char *oldname = PARAM(inarg);
671 char *newname = oldname + strlen(oldname) + 1;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000672 char *oldpath;
673 char *newpath;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000674
Miklos Szeredi5e183482001-10-31 14:52:35 +0000675 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000676 oldpath = get_path_name(f, olddir, oldname);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000677 if(oldpath != NULL) {
Miklos Szeredia181e612001-11-06 12:03:23 +0000678 newpath = get_path_name(f, newdir, newname);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000679 if(newpath != NULL) {
680 res = -ENOSYS;
681 if(f->op.rename)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000682 res = f->op.rename(oldpath, newpath);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000683 if(res == 0)
684 rename_node(f, olddir, oldname, newdir, newname);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000685 free(newpath);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000686 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000687 free(oldpath);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000688 }
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000689 send_reply(f, in, res, NULL, 0);
690}
691
692static void do_link(struct fuse *f, struct fuse_in_header *in,
Miklos Szeredi5e183482001-10-31 14:52:35 +0000693 struct fuse_link_in *arg)
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000694{
695 int res;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000696 char *oldpath;
697 char *newpath;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000698
Miklos Szeredi5e183482001-10-31 14:52:35 +0000699 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000700 oldpath = get_path(f, in->ino);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000701 if(oldpath != NULL) {
Miklos Szeredi6bf8b682002-10-28 08:49:39 +0000702 newpath = get_path_name(f, arg->newdir, PARAM(arg));
Miklos Szeredi5e183482001-10-31 14:52:35 +0000703 if(newpath != NULL) {
704 res = -ENOSYS;
705 if(f->op.link)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000706 res = f->op.link(oldpath, newpath);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000707 free(newpath);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000708 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000709 free(oldpath);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000710 }
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000711 send_reply(f, in, res, NULL, 0);
712}
713
Miklos Szeredi5e183482001-10-31 14:52:35 +0000714static void do_open(struct fuse *f, struct fuse_in_header *in,
715 struct fuse_open_in *arg)
716{
717 int res;
718 char *path;
719
720 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000721 path = get_path(f, in->ino);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000722 if(path != NULL) {
723 res = -ENOSYS;
724 if(f->op.open)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000725 res = f->op.open(path, arg->flags);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000726 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000727 }
728 send_reply(f, in, res, NULL, 0);
729}
730
731static void do_read(struct fuse *f, struct fuse_in_header *in,
732 struct fuse_read_in *arg)
733{
734 int res;
735 char *path;
Miklos Szeredi43696432001-11-18 19:15:05 +0000736 char *outbuf = (char *) malloc(sizeof(struct fuse_out_header) + arg->size);
737 struct fuse_out_header *out = (struct fuse_out_header *) outbuf;
738 char *buf = outbuf + sizeof(struct fuse_out_header);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000739 size_t size;
Miklos Szeredi43696432001-11-18 19:15:05 +0000740 size_t outsize;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000741
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000742 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000743 path = get_path(f, in->ino);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000744 if(path != NULL) {
Miklos Szeredi6ebe2342002-01-06 21:44:16 +0000745 if(f->flags & FUSE_DEBUG) {
746 printf("READ %u bytes from %llu\n", arg->size, arg->offset);
747 fflush(stdout);
748 }
749
Miklos Szeredi5e183482001-10-31 14:52:35 +0000750 res = -ENOSYS;
Miklos Szeredia181e612001-11-06 12:03:23 +0000751 if(f->op.read)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000752 res = f->op.read(path, buf, arg->size, arg->offset);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000753 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000754 }
755
756 size = 0;
757 if(res > 0) {
758 size = res;
759 res = 0;
Miklos Szeredi6ebe2342002-01-06 21:44:16 +0000760 if(f->flags & FUSE_DEBUG) {
761 printf(" READ %u bytes\n", size);
762 fflush(stdout);
763 }
Miklos Szeredi5e183482001-10-31 14:52:35 +0000764 }
Miklos Szeredi0f48a262002-12-05 14:23:01 +0000765 memset(out, 0, sizeof(struct fuse_out_header));
Miklos Szeredi43696432001-11-18 19:15:05 +0000766 out->unique = in->unique;
767 out->error = res;
768 outsize = sizeof(struct fuse_out_header) + size;
769
770 send_reply_raw(f, outbuf, outsize);
771 free(outbuf);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000772}
Miklos Szeredib483c932001-10-29 14:57:57 +0000773
Miklos Szeredia181e612001-11-06 12:03:23 +0000774static void do_write(struct fuse *f, struct fuse_in_header *in,
775 struct fuse_write_in *arg)
776{
777 int res;
778 char *path;
Miklos Szeredia181e612001-11-06 12:03:23 +0000779
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000780 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000781 path = get_path(f, in->ino);
782 if(path != NULL) {
Miklos Szeredi6ebe2342002-01-06 21:44:16 +0000783 if(f->flags & FUSE_DEBUG) {
784 printf("WRITE %u bytes to %llu\n", arg->size, arg->offset);
785 fflush(stdout);
786 }
787
Miklos Szeredia181e612001-11-06 12:03:23 +0000788 res = -ENOSYS;
789 if(f->op.write)
Miklos Szeredi6bf8b682002-10-28 08:49:39 +0000790 res = f->op.write(path, PARAM(arg), arg->size, arg->offset);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000791 free(path);
Miklos Szeredia181e612001-11-06 12:03:23 +0000792 }
793
794 if(res > 0) {
795 if((size_t) res != arg->size) {
796 fprintf(stderr, "short write: %u (should be %u)\n", res,
797 arg->size);
798 res = -EIO;
799 }
800 else
801 res = 0;
802 }
803
804 send_reply(f, in, res, NULL, 0);
805}
806
Mark Glinesd84b39a2002-01-07 16:32:02 +0000807static void do_statfs(struct fuse *f, struct fuse_in_header *in)
808{
809 int res;
Mark Glinesd84b39a2002-01-07 16:32:02 +0000810 struct fuse_statfs_out arg;
811
812 res = -ENOSYS;
Miklos Szeredi0f48a262002-12-05 14:23:01 +0000813 if(f->op.statfs) {
814 memset(&arg, 0, sizeof(struct fuse_statfs_out));
Miklos Szeredi24ed9452002-10-07 10:24:26 +0000815 res = f->op.statfs((struct fuse_statfs *) &arg.st);
Miklos Szeredi0f48a262002-12-05 14:23:01 +0000816 }
Miklos Szeredi4b2bef42002-01-09 12:23:27 +0000817
Mark Glinesd84b39a2002-01-07 16:32:02 +0000818 send_reply(f, in, res, &arg, sizeof(arg));
819}
820
Miklos Szeredi43696432001-11-18 19:15:05 +0000821static void free_cmd(struct fuse_cmd *cmd)
822{
823 free(cmd->buf);
824 free(cmd);
825}
826
Miklos Szeredifff56ab2001-11-16 10:12:59 +0000827void __fuse_process_cmd(struct fuse *f, struct fuse_cmd *cmd)
Miklos Szeredia181e612001-11-06 12:03:23 +0000828{
Miklos Szeredia181e612001-11-06 12:03:23 +0000829 struct fuse_in_header *in = (struct fuse_in_header *) cmd->buf;
830 void *inarg = cmd->buf + sizeof(struct fuse_in_header);
831 size_t argsize;
Miklos Szeredife25def2001-12-20 15:38:05 +0000832 struct fuse_context *ctx = fuse_get_context(f);
Miklos Szeredia181e612001-11-06 12:03:23 +0000833
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +0000834 dec_avail(f);
Miklos Szeredi33232032001-11-19 17:55:51 +0000835
Miklos Szeredic0938ea2001-11-07 12:35:06 +0000836 if((f->flags & FUSE_DEBUG)) {
837 printf("unique: %i, opcode: %i, ino: %li, insize: %i\n", in->unique,
838 in->opcode, in->ino, cmd->buflen);
839 fflush(stdout);
840 }
Miklos Szeredife25def2001-12-20 15:38:05 +0000841
842 ctx->uid = in->uid;
843 ctx->gid = in->gid;
Miklos Szeredia181e612001-11-06 12:03:23 +0000844
845 argsize = cmd->buflen - sizeof(struct fuse_in_header);
846
847 switch(in->opcode) {
848 case FUSE_LOOKUP:
849 do_lookup(f, in, (char *) inarg);
850 break;
851
Miklos Szeredia181e612001-11-06 12:03:23 +0000852 case FUSE_GETATTR:
853 do_getattr(f, in);
854 break;
855
856 case FUSE_SETATTR:
857 do_setattr(f, in, (struct fuse_setattr_in *) inarg);
858 break;
859
860 case FUSE_READLINK:
861 do_readlink(f, in);
862 break;
863
864 case FUSE_GETDIR:
865 do_getdir(f, in);
866 break;
867
868 case FUSE_MKNOD:
869 do_mknod(f, in, (struct fuse_mknod_in *) inarg);
870 break;
871
872 case FUSE_MKDIR:
873 do_mkdir(f, in, (struct fuse_mkdir_in *) inarg);
874 break;
875
876 case FUSE_UNLINK:
877 case FUSE_RMDIR:
878 do_remove(f, in, (char *) inarg);
879 break;
880
881 case FUSE_SYMLINK:
882 do_symlink(f, in, (char *) inarg,
883 ((char *) inarg) + strlen((char *) inarg) + 1);
884 break;
885
886 case FUSE_RENAME:
887 do_rename(f, in, (struct fuse_rename_in *) inarg);
888 break;
889
890 case FUSE_LINK:
891 do_link(f, in, (struct fuse_link_in *) inarg);
892 break;
893
894 case FUSE_OPEN:
895 do_open(f, in, (struct fuse_open_in *) inarg);
896 break;
897
898 case FUSE_READ:
899 do_read(f, in, (struct fuse_read_in *) inarg);
900 break;
901
902 case FUSE_WRITE:
903 do_write(f, in, (struct fuse_write_in *) inarg);
904 break;
905
Mark Glinesd84b39a2002-01-07 16:32:02 +0000906 case FUSE_STATFS:
907 do_statfs(f, in);
908 break;
909
Miklos Szeredia181e612001-11-06 12:03:23 +0000910 default:
911 fprintf(stderr, "Operation %i not implemented\n", in->opcode);
Miklos Szeredi43696432001-11-18 19:15:05 +0000912 send_reply(f, in, -ENOSYS, NULL, 0);
Miklos Szeredia181e612001-11-06 12:03:23 +0000913 }
Miklos Szeredi43696432001-11-18 19:15:05 +0000914
915 free_cmd(cmd);
Miklos Szeredia181e612001-11-06 12:03:23 +0000916}
917
Miklos Szeredifff56ab2001-11-16 10:12:59 +0000918struct fuse_cmd *__fuse_read_cmd(struct fuse *f)
Miklos Szeredi2df1c042001-11-06 15:07:17 +0000919{
Miklos Szeredifff56ab2001-11-16 10:12:59 +0000920 ssize_t res;
Miklos Szeredifff56ab2001-11-16 10:12:59 +0000921 struct fuse_cmd *cmd;
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +0000922 struct fuse_in_header *in;
923 void *inarg;
Miklos Szeredifff56ab2001-11-16 10:12:59 +0000924
Miklos Szeredi43696432001-11-18 19:15:05 +0000925 cmd = (struct fuse_cmd *) malloc(sizeof(struct fuse_cmd));
926 cmd->buf = (char *) malloc(FUSE_MAX_IN);
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +0000927 in = (struct fuse_in_header *) cmd->buf;
928 inarg = cmd->buf + sizeof(struct fuse_in_header);
Miklos Szeredi43696432001-11-18 19:15:05 +0000929
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +0000930 do {
931 res = read(f->fd, cmd->buf, FUSE_MAX_IN);
932 if(res == -1) {
Miklos Szeredi0f48a262002-12-05 14:23:01 +0000933 free_cmd(cmd);
934 if(errno == EINTR)
935 return NULL;
936
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +0000937 /* ENODEV means we got unmounted, so we silenty return failure */
938 if(errno != ENODEV) {
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +0000939 /* BAD... This will happen again */
Miklos Szeredi0f48a262002-12-05 14:23:01 +0000940 perror("fuse: reading device");
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +0000941 }
Miklos Szeredi0f48a262002-12-05 14:23:01 +0000942
943 fuse_exit(f);
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +0000944 return NULL;
Miklos Szeredi96249982001-11-21 12:21:19 +0000945 }
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +0000946 if((size_t) res < sizeof(struct fuse_in_header)) {
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +0000947 free_cmd(cmd);
Miklos Szeredi0f48a262002-12-05 14:23:01 +0000948 /* Cannot happen */
949 fprintf(stderr, "short read on fuse device\n");
950 fuse_exit(f);
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +0000951 return NULL;
952 }
953 cmd->buflen = res;
954
955 /* Forget is special, it can be done without messing with threads. */
956 if(in->opcode == FUSE_FORGET)
957 do_forget(f, in, (struct fuse_forget_in *) inarg);
958
959 } while(in->opcode == FUSE_FORGET);
960
Miklos Szeredifff56ab2001-11-16 10:12:59 +0000961 return cmd;
Miklos Szeredi2df1c042001-11-06 15:07:17 +0000962}
963
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000964void fuse_loop(struct fuse *f)
965{
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000966 while(1) {
Miklos Szeredi0f48a262002-12-05 14:23:01 +0000967 struct fuse_cmd *cmd;
968
969 if(f->exited)
970 return;
971
972 cmd = __fuse_read_cmd(f);
Miklos Szeredifff56ab2001-11-16 10:12:59 +0000973 if(cmd == NULL)
Miklos Szeredi0f48a262002-12-05 14:23:01 +0000974 continue;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000975
Miklos Szeredifff56ab2001-11-16 10:12:59 +0000976 __fuse_process_cmd(f, cmd);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000977 }
978}
979
Miklos Szeredi0f48a262002-12-05 14:23:01 +0000980void fuse_exit(struct fuse *f)
981{
982 f->exited = 1;
983}
984
Miklos Szeredi2e50d432001-12-20 12:17:25 +0000985struct fuse_context *fuse_get_context(struct fuse *f)
986{
987 if(f->getcontext)
988 return f->getcontext(f);
989 else
990 return &f->context;
991}
992
993struct fuse *fuse_new(int fd, int flags, const struct fuse_operations *op)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000994{
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000995 struct fuse *f;
996 struct node *root;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000997
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000998 f = (struct fuse *) calloc(1, sizeof(struct fuse));
Miklos Szeredi2df1c042001-11-06 15:07:17 +0000999
Miklos Szeredia181e612001-11-06 12:03:23 +00001000 f->flags = flags;
Miklos Szeredi8cffdb92001-11-09 14:49:18 +00001001 f->fd = fd;
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001002 f->ctr = 0;
Miklos Szeredifff56ab2001-11-16 10:12:59 +00001003 /* FIXME: Dynamic hash table */
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001004 f->name_table_size = 14057;
1005 f->name_table = (struct node **)
1006 calloc(1, sizeof(struct node *) * f->name_table_size);
1007 f->ino_table_size = 14057;
1008 f->ino_table = (struct node **)
1009 calloc(1, sizeof(struct node *) * f->ino_table_size);
Miklos Szeredia181e612001-11-06 12:03:23 +00001010 pthread_mutex_init(&f->lock, NULL);
Miklos Szeredi33232032001-11-19 17:55:51 +00001011 f->numworker = 0;
1012 f->numavail = 0;
Miklos Szeredi2e50d432001-12-20 12:17:25 +00001013 f->op = *op;
1014 f->getcontext = NULL;
1015 f->context.uid = 0;
1016 f->context.gid = 0;
Miklos Szeredi0f48a262002-12-05 14:23:01 +00001017 f->exited = 0;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001018
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001019 root = (struct node *) calloc(1, sizeof(struct node));
Miklos Szeredi8cffdb92001-11-09 14:49:18 +00001020 root->mode = 0;
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001021 root->rdev = 0;
1022 root->name = strdup("/");
1023 root->parent = 0;
1024 hash_ino(f, root, FUSE_ROOT_INO);
1025
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001026 return f;
1027}
1028
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001029void fuse_destroy(struct fuse *f)
1030{
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001031 size_t i;
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001032 for(i = 0; i < f->ino_table_size; i++) {
1033 struct node *node;
1034 struct node *next;
1035 for(node = f->ino_table[i]; node != NULL; node = next) {
1036 next = node->ino_next;
1037 free_node(node);
1038 }
1039 }
1040 free(f->ino_table);
1041 free(f->name_table);
Miklos Szeredia181e612001-11-06 12:03:23 +00001042 pthread_mutex_destroy(&f->lock);
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001043 free(f);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001044}