blob: 42ab52aedfbf6d1fcdc4ff43f9985cc8896ac0df [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 Szeredi19dff1b2001-10-30 15:06:52 +0000358 if(error > 0) {
Miklos Szeredi96249982001-11-21 12:21:19 +0000359 fprintf(stderr, "fuse: positive error code: %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;
369 out->unique = in->unique;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000370 out->error = error;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000371 if(argsize != 0)
372 memcpy(outbuf + sizeof(struct fuse_out_header), arg, argsize);
373
Miklos Szeredi43696432001-11-18 19:15:05 +0000374 send_reply_raw(f, outbuf, outsize);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000375
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000376 free(outbuf);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000377}
378
379static void do_lookup(struct fuse *f, struct fuse_in_header *in, char *name)
380{
381 int res;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000382 char *path;
383 struct stat buf;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000384 struct fuse_lookup_out arg;
385
Miklos Szeredi5e183482001-10-31 14:52:35 +0000386 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000387 path = get_path_name(f, in->ino, name);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000388 if(path != NULL) {
Miklos Szeredi6ebe2342002-01-06 21:44:16 +0000389 if(f->flags & FUSE_DEBUG) {
390 printf("LOOKUP %s\n", path);
391 fflush(stdout);
392 }
Miklos Szeredi5e183482001-10-31 14:52:35 +0000393 res = -ENOSYS;
394 if(f->op.getattr)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000395 res = f->op.getattr(path, &buf);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000396 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000397 }
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000398 if(res == 0) {
399 convert_stat(&buf, &arg.attr);
Miklos Szeredia181e612001-11-06 12:03:23 +0000400 arg.ino = find_node(f, in->ino, name, &arg.attr, in->unique);
Miklos Szeredi6ebe2342002-01-06 21:44:16 +0000401 if(f->flags & FUSE_DEBUG) {
402 printf(" LOOKUP: %li\n", arg.ino);
403 fflush(stdout);
404 }
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000405 }
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000406 send_reply(f, in, res, &arg, sizeof(arg));
407}
408
Miklos Szeredia181e612001-11-06 12:03:23 +0000409static void do_forget(struct fuse *f, struct fuse_in_header *in,
410 struct fuse_forget_in *arg)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000411{
Miklos Szeredi43696432001-11-18 19:15:05 +0000412 if(f->flags & FUSE_DEBUG) {
413 printf("FORGET %li/%i\n", in->ino, arg->version);
414 fflush(stdout);
415 }
Miklos Szeredia181e612001-11-06 12:03:23 +0000416 destroy_node(f, in->ino, arg->version);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000417}
418
419static void do_getattr(struct fuse *f, struct fuse_in_header *in)
420{
421 int res;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000422 char *path;
423 struct stat buf;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000424 struct fuse_getattr_out arg;
425
Miklos Szeredi5e183482001-10-31 14:52:35 +0000426 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000427 path = get_path(f, in->ino);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000428 if(path != NULL) {
429 res = -ENOSYS;
430 if(f->op.getattr)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000431 res = f->op.getattr(path, &buf);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000432 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000433 }
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000434 if(res == 0)
435 convert_stat(&buf, &arg.attr);
436
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000437 send_reply(f, in, res, &arg, sizeof(arg));
438}
439
Miklos Szeredi680a69a2001-11-16 13:31:14 +0000440static int do_chmod(struct fuse *f, const char *path, struct fuse_attr *attr)
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000441{
442 int res;
443
444 res = -ENOSYS;
445 if(f->op.chmod)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000446 res = f->op.chmod(path, attr->mode);
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000447
448 return res;
449}
450
Miklos Szeredi680a69a2001-11-16 13:31:14 +0000451static int do_chown(struct fuse *f, const char *path, struct fuse_attr *attr,
Miklos Szeredi2e50d432001-12-20 12:17:25 +0000452 int valid)
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000453{
454 int res;
455 uid_t uid = (valid & FATTR_UID) ? attr->uid : (uid_t) -1;
456 gid_t gid = (valid & FATTR_GID) ? attr->gid : (gid_t) -1;
457
458 res = -ENOSYS;
459 if(f->op.chown)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000460 res = f->op.chown(path, uid, gid);
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000461
462 return res;
463}
464
Miklos Szeredi680a69a2001-11-16 13:31:14 +0000465static int do_truncate(struct fuse *f, const char *path,
466 struct fuse_attr *attr)
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000467{
468 int res;
469
470 res = -ENOSYS;
471 if(f->op.truncate)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000472 res = f->op.truncate(path, attr->size);
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000473
474 return res;
475}
476
Miklos Szeredi680a69a2001-11-16 13:31:14 +0000477static int do_utime(struct fuse *f, const char *path, struct fuse_attr *attr)
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000478{
479 int res;
480 struct utimbuf buf;
481 buf.actime = attr->atime;
482 buf.modtime = attr->mtime;
483 res = -ENOSYS;
484 if(f->op.utime)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000485 res = f->op.utime(path, &buf);
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000486
487 return res;
488}
489
Miklos Szeredi5e183482001-10-31 14:52:35 +0000490static void do_setattr(struct fuse *f, struct fuse_in_header *in,
491 struct fuse_setattr_in *arg)
492{
493 int res;
494 char *path;
495 int valid = arg->valid;
496 struct fuse_attr *attr = &arg->attr;
Miklos Szeredia181e612001-11-06 12:03:23 +0000497 struct fuse_setattr_out outarg;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000498
499 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000500 path = get_path(f, in->ino);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000501 if(path != NULL) {
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000502 res = -ENOSYS;
503 if(f->op.getattr) {
504 res = 0;
505 if(!res && (valid & FATTR_MODE))
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000506 res = do_chmod(f, path, attr);
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000507 if(!res && (valid & (FATTR_UID | FATTR_GID)))
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000508 res = do_chown(f, path, attr, valid);
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000509 if(!res && (valid & FATTR_SIZE))
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000510 res = do_truncate(f, path, attr);
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000511 if(!res && (valid & FATTR_UTIME))
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000512 res = do_utime(f, path, attr);
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000513 if(!res) {
514 struct stat buf;
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000515 res = f->op.getattr(path, &buf);
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000516 if(!res)
517 convert_stat(&buf, &outarg.attr);
Miklos Szeredia181e612001-11-06 12:03:23 +0000518 }
Miklos Szeredi5e183482001-10-31 14:52:35 +0000519 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000520 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000521 }
Miklos Szeredia181e612001-11-06 12:03:23 +0000522 send_reply(f, in, res, &outarg, sizeof(outarg));
Miklos Szeredi5e183482001-10-31 14:52:35 +0000523}
524
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000525static void do_readlink(struct fuse *f, struct fuse_in_header *in)
526{
527 int res;
528 char link[PATH_MAX + 1];
Miklos Szeredib483c932001-10-29 14:57:57 +0000529 char *path;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000530
Miklos Szeredi5e183482001-10-31 14:52:35 +0000531 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000532 path = get_path(f, in->ino);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000533 if(path != NULL) {
534 res = -ENOSYS;
535 if(f->op.readlink)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000536 res = f->op.readlink(path, link, sizeof(link));
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000537 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000538 }
Miklos Szeredi2df1c042001-11-06 15:07:17 +0000539 link[PATH_MAX] = '\0';
Miklos Szeredi4b2bef42002-01-09 12:23:27 +0000540 send_reply(f, in, res, link, res == 0 ? strlen(link) : 0);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000541}
542
543static void do_getdir(struct fuse *f, struct fuse_in_header *in)
544{
545 int res;
546 struct fuse_getdir_out arg;
Miklos Szeredia181e612001-11-06 12:03:23 +0000547 struct fuse_dirhandle dh;
Miklos Szeredib483c932001-10-29 14:57:57 +0000548 char *path;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000549
Miklos Szeredib483c932001-10-29 14:57:57 +0000550 dh.fuse = f;
551 dh.fp = tmpfile();
552 dh.dir = in->ino;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000553 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000554 path = get_path(f, in->ino);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000555 if(path != NULL) {
556 res = -ENOSYS;
557 if(f->op.getdir)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000558 res = f->op.getdir(path, &dh, (fuse_dirfil_t) fill_dir);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000559 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000560 }
Miklos Szeredib483c932001-10-29 14:57:57 +0000561 fflush(dh.fp);
562 arg.fd = fileno(dh.fp);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000563 send_reply(f, in, res, &arg, sizeof(arg));
Miklos Szeredib483c932001-10-29 14:57:57 +0000564 fclose(dh.fp);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000565}
566
Miklos Szeredib483c932001-10-29 14:57:57 +0000567static void do_mknod(struct fuse *f, struct fuse_in_header *in,
568 struct fuse_mknod_in *inarg)
569{
570 int res;
571 char *path;
572 struct fuse_mknod_out outarg;
573 struct stat buf;
574
Miklos Szeredi5e183482001-10-31 14:52:35 +0000575 res = -ENOENT;
Miklos Szeredi6bf8b682002-10-28 08:49:39 +0000576 path = get_path_name(f, in->ino, PARAM(inarg));
Miklos Szeredi5e183482001-10-31 14:52:35 +0000577 if(path != NULL) {
578 res = -ENOSYS;
579 if(f->op.mknod && f->op.getattr) {
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000580 res = f->op.mknod(path, inarg->mode, inarg->rdev);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000581 if(res == 0)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000582 res = f->op.getattr(path, &buf);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000583 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000584 free(path);
Miklos Szeredib483c932001-10-29 14:57:57 +0000585 }
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000586 if(res == 0) {
Miklos Szeredib483c932001-10-29 14:57:57 +0000587 convert_stat(&buf, &outarg.attr);
Miklos Szeredi6bf8b682002-10-28 08:49:39 +0000588 outarg.ino = find_node(f, in->ino, PARAM(inarg), &outarg.attr,
Miklos Szeredia181e612001-11-06 12:03:23 +0000589 in->unique);
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000590 }
Miklos Szeredib483c932001-10-29 14:57:57 +0000591
592 send_reply(f, in, res, &outarg, sizeof(outarg));
593}
594
595static void do_mkdir(struct fuse *f, struct fuse_in_header *in,
596 struct fuse_mkdir_in *inarg)
597{
598 int res;
599 char *path;
600
Miklos Szeredi5e183482001-10-31 14:52:35 +0000601 res = -ENOENT;
Miklos Szeredi6bf8b682002-10-28 08:49:39 +0000602 path = get_path_name(f, in->ino, PARAM(inarg));
Miklos Szeredi5e183482001-10-31 14:52:35 +0000603 if(path != NULL) {
604 res = -ENOSYS;
605 if(f->op.mkdir)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000606 res = f->op.mkdir(path, inarg->mode);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000607 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000608 }
Miklos Szeredib483c932001-10-29 14:57:57 +0000609 send_reply(f, in, res, NULL, 0);
610}
611
612static void do_remove(struct fuse *f, struct fuse_in_header *in, char *name)
613{
614 int res;
615 char *path;
616
Miklos Szeredi5e183482001-10-31 14:52:35 +0000617 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000618 path = get_path_name(f, in->ino, name);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000619 if(path != NULL) {
620 res = -ENOSYS;
621 if(in->opcode == FUSE_UNLINK) {
622 if(f->op.unlink)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000623 res = f->op.unlink(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000624 }
625 else {
626 if(f->op.rmdir)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000627 res = f->op.rmdir(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000628 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000629 free(path);
Miklos Szeredib483c932001-10-29 14:57:57 +0000630 }
Miklos Szeredi5e183482001-10-31 14:52:35 +0000631 if(res == 0)
632 remove_node(f, in->ino, name);
Miklos Szeredib483c932001-10-29 14:57:57 +0000633 send_reply(f, in, res, NULL, 0);
634}
635
636static void do_symlink(struct fuse *f, struct fuse_in_header *in, char *name,
637 char *link)
638{
639 int res;
640 char *path;
641
Miklos Szeredi5e183482001-10-31 14:52:35 +0000642 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000643 path = get_path_name(f, in->ino, name);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000644 if(path != NULL) {
645 res = -ENOSYS;
646 if(f->op.symlink)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000647 res = f->op.symlink(link, path);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000648 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000649 }
Miklos Szeredib483c932001-10-29 14:57:57 +0000650 send_reply(f, in, res, NULL, 0);
651}
652
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000653static void do_rename(struct fuse *f, struct fuse_in_header *in,
654 struct fuse_rename_in *inarg)
655{
656 int res;
657 fino_t olddir = in->ino;
658 fino_t newdir = inarg->newdir;
Miklos Szeredi6bf8b682002-10-28 08:49:39 +0000659 char *oldname = PARAM(inarg);
660 char *newname = oldname + strlen(oldname) + 1;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000661 char *oldpath;
662 char *newpath;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000663
Miklos Szeredi5e183482001-10-31 14:52:35 +0000664 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000665 oldpath = get_path_name(f, olddir, oldname);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000666 if(oldpath != NULL) {
Miklos Szeredia181e612001-11-06 12:03:23 +0000667 newpath = get_path_name(f, newdir, newname);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000668 if(newpath != NULL) {
669 res = -ENOSYS;
670 if(f->op.rename)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000671 res = f->op.rename(oldpath, newpath);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000672 if(res == 0)
673 rename_node(f, olddir, oldname, newdir, newname);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000674 free(newpath);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000675 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000676 free(oldpath);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000677 }
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000678 send_reply(f, in, res, NULL, 0);
679}
680
681static void do_link(struct fuse *f, struct fuse_in_header *in,
Miklos Szeredi5e183482001-10-31 14:52:35 +0000682 struct fuse_link_in *arg)
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000683{
684 int res;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000685 char *oldpath;
686 char *newpath;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000687
Miklos Szeredi5e183482001-10-31 14:52:35 +0000688 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000689 oldpath = get_path(f, in->ino);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000690 if(oldpath != NULL) {
Miklos Szeredi6bf8b682002-10-28 08:49:39 +0000691 newpath = get_path_name(f, arg->newdir, PARAM(arg));
Miklos Szeredi5e183482001-10-31 14:52:35 +0000692 if(newpath != NULL) {
693 res = -ENOSYS;
694 if(f->op.link)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000695 res = f->op.link(oldpath, newpath);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000696 free(newpath);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000697 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000698 free(oldpath);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000699 }
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000700 send_reply(f, in, res, NULL, 0);
701}
702
Miklos Szeredi5e183482001-10-31 14:52:35 +0000703static void do_open(struct fuse *f, struct fuse_in_header *in,
704 struct fuse_open_in *arg)
705{
706 int res;
707 char *path;
708
709 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000710 path = get_path(f, in->ino);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000711 if(path != NULL) {
712 res = -ENOSYS;
713 if(f->op.open)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000714 res = f->op.open(path, arg->flags);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000715 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000716 }
717 send_reply(f, in, res, NULL, 0);
718}
719
720static void do_read(struct fuse *f, struct fuse_in_header *in,
721 struct fuse_read_in *arg)
722{
723 int res;
724 char *path;
Miklos Szeredi43696432001-11-18 19:15:05 +0000725 char *outbuf = (char *) malloc(sizeof(struct fuse_out_header) + arg->size);
726 struct fuse_out_header *out = (struct fuse_out_header *) outbuf;
727 char *buf = outbuf + sizeof(struct fuse_out_header);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000728 size_t size;
Miklos Szeredi43696432001-11-18 19:15:05 +0000729 size_t outsize;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000730
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000731 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000732 path = get_path(f, in->ino);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000733 if(path != NULL) {
Miklos Szeredi6ebe2342002-01-06 21:44:16 +0000734 if(f->flags & FUSE_DEBUG) {
735 printf("READ %u bytes from %llu\n", arg->size, arg->offset);
736 fflush(stdout);
737 }
738
Miklos Szeredi5e183482001-10-31 14:52:35 +0000739 res = -ENOSYS;
Miklos Szeredia181e612001-11-06 12:03:23 +0000740 if(f->op.read)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000741 res = f->op.read(path, buf, arg->size, arg->offset);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000742 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000743 }
744
745 size = 0;
746 if(res > 0) {
747 size = res;
748 res = 0;
Miklos Szeredi6ebe2342002-01-06 21:44:16 +0000749 if(f->flags & FUSE_DEBUG) {
750 printf(" READ %u bytes\n", size);
751 fflush(stdout);
752 }
Miklos Szeredi5e183482001-10-31 14:52:35 +0000753 }
Miklos Szeredi43696432001-11-18 19:15:05 +0000754 out->unique = in->unique;
755 out->error = res;
756 outsize = sizeof(struct fuse_out_header) + size;
757
758 send_reply_raw(f, outbuf, outsize);
759 free(outbuf);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000760}
Miklos Szeredib483c932001-10-29 14:57:57 +0000761
Miklos Szeredia181e612001-11-06 12:03:23 +0000762static void do_write(struct fuse *f, struct fuse_in_header *in,
763 struct fuse_write_in *arg)
764{
765 int res;
766 char *path;
Miklos Szeredia181e612001-11-06 12:03:23 +0000767
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000768 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000769 path = get_path(f, in->ino);
770 if(path != NULL) {
Miklos Szeredi6ebe2342002-01-06 21:44:16 +0000771 if(f->flags & FUSE_DEBUG) {
772 printf("WRITE %u bytes to %llu\n", arg->size, arg->offset);
773 fflush(stdout);
774 }
775
Miklos Szeredia181e612001-11-06 12:03:23 +0000776 res = -ENOSYS;
777 if(f->op.write)
Miklos Szeredi6bf8b682002-10-28 08:49:39 +0000778 res = f->op.write(path, PARAM(arg), arg->size, arg->offset);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000779 free(path);
Miklos Szeredia181e612001-11-06 12:03:23 +0000780 }
781
782 if(res > 0) {
783 if((size_t) res != arg->size) {
784 fprintf(stderr, "short write: %u (should be %u)\n", res,
785 arg->size);
786 res = -EIO;
787 }
788 else
789 res = 0;
790 }
791
792 send_reply(f, in, res, NULL, 0);
793}
794
Mark Glinesd84b39a2002-01-07 16:32:02 +0000795static void do_statfs(struct fuse *f, struct fuse_in_header *in)
796{
797 int res;
Mark Glinesd84b39a2002-01-07 16:32:02 +0000798 struct fuse_statfs_out arg;
799
800 res = -ENOSYS;
801 if(f->op.statfs)
Miklos Szeredi24ed9452002-10-07 10:24:26 +0000802 res = f->op.statfs((struct fuse_statfs *) &arg.st);
Miklos Szeredi4b2bef42002-01-09 12:23:27 +0000803
Mark Glinesd84b39a2002-01-07 16:32:02 +0000804 send_reply(f, in, res, &arg, sizeof(arg));
805}
806
Miklos Szeredi43696432001-11-18 19:15:05 +0000807static void free_cmd(struct fuse_cmd *cmd)
808{
809 free(cmd->buf);
810 free(cmd);
811}
812
Miklos Szeredifff56ab2001-11-16 10:12:59 +0000813void __fuse_process_cmd(struct fuse *f, struct fuse_cmd *cmd)
Miklos Szeredia181e612001-11-06 12:03:23 +0000814{
Miklos Szeredia181e612001-11-06 12:03:23 +0000815 struct fuse_in_header *in = (struct fuse_in_header *) cmd->buf;
816 void *inarg = cmd->buf + sizeof(struct fuse_in_header);
817 size_t argsize;
Miklos Szeredife25def2001-12-20 15:38:05 +0000818 struct fuse_context *ctx = fuse_get_context(f);
Miklos Szeredia181e612001-11-06 12:03:23 +0000819
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +0000820 dec_avail(f);
Miklos Szeredi33232032001-11-19 17:55:51 +0000821
Miklos Szeredic0938ea2001-11-07 12:35:06 +0000822 if((f->flags & FUSE_DEBUG)) {
823 printf("unique: %i, opcode: %i, ino: %li, insize: %i\n", in->unique,
824 in->opcode, in->ino, cmd->buflen);
825 fflush(stdout);
826 }
Miklos Szeredife25def2001-12-20 15:38:05 +0000827
828 ctx->uid = in->uid;
829 ctx->gid = in->gid;
Miklos Szeredia181e612001-11-06 12:03:23 +0000830
831 argsize = cmd->buflen - sizeof(struct fuse_in_header);
832
833 switch(in->opcode) {
834 case FUSE_LOOKUP:
835 do_lookup(f, in, (char *) inarg);
836 break;
837
Miklos Szeredia181e612001-11-06 12:03:23 +0000838 case FUSE_GETATTR:
839 do_getattr(f, in);
840 break;
841
842 case FUSE_SETATTR:
843 do_setattr(f, in, (struct fuse_setattr_in *) inarg);
844 break;
845
846 case FUSE_READLINK:
847 do_readlink(f, in);
848 break;
849
850 case FUSE_GETDIR:
851 do_getdir(f, in);
852 break;
853
854 case FUSE_MKNOD:
855 do_mknod(f, in, (struct fuse_mknod_in *) inarg);
856 break;
857
858 case FUSE_MKDIR:
859 do_mkdir(f, in, (struct fuse_mkdir_in *) inarg);
860 break;
861
862 case FUSE_UNLINK:
863 case FUSE_RMDIR:
864 do_remove(f, in, (char *) inarg);
865 break;
866
867 case FUSE_SYMLINK:
868 do_symlink(f, in, (char *) inarg,
869 ((char *) inarg) + strlen((char *) inarg) + 1);
870 break;
871
872 case FUSE_RENAME:
873 do_rename(f, in, (struct fuse_rename_in *) inarg);
874 break;
875
876 case FUSE_LINK:
877 do_link(f, in, (struct fuse_link_in *) inarg);
878 break;
879
880 case FUSE_OPEN:
881 do_open(f, in, (struct fuse_open_in *) inarg);
882 break;
883
884 case FUSE_READ:
885 do_read(f, in, (struct fuse_read_in *) inarg);
886 break;
887
888 case FUSE_WRITE:
889 do_write(f, in, (struct fuse_write_in *) inarg);
890 break;
891
Mark Glinesd84b39a2002-01-07 16:32:02 +0000892 case FUSE_STATFS:
893 do_statfs(f, in);
894 break;
895
Miklos Szeredia181e612001-11-06 12:03:23 +0000896 default:
897 fprintf(stderr, "Operation %i not implemented\n", in->opcode);
Miklos Szeredi43696432001-11-18 19:15:05 +0000898 send_reply(f, in, -ENOSYS, NULL, 0);
Miklos Szeredia181e612001-11-06 12:03:23 +0000899 }
Miklos Szeredi43696432001-11-18 19:15:05 +0000900
901 free_cmd(cmd);
Miklos Szeredia181e612001-11-06 12:03:23 +0000902}
903
Miklos Szeredifff56ab2001-11-16 10:12:59 +0000904struct fuse_cmd *__fuse_read_cmd(struct fuse *f)
Miklos Szeredi2df1c042001-11-06 15:07:17 +0000905{
Miklos Szeredifff56ab2001-11-16 10:12:59 +0000906 ssize_t res;
Miklos Szeredifff56ab2001-11-16 10:12:59 +0000907 struct fuse_cmd *cmd;
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +0000908 struct fuse_in_header *in;
909 void *inarg;
Miklos Szeredifff56ab2001-11-16 10:12:59 +0000910
Miklos Szeredi43696432001-11-18 19:15:05 +0000911 cmd = (struct fuse_cmd *) malloc(sizeof(struct fuse_cmd));
912 cmd->buf = (char *) malloc(FUSE_MAX_IN);
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +0000913 in = (struct fuse_in_header *) cmd->buf;
914 inarg = cmd->buf + sizeof(struct fuse_in_header);
Miklos Szeredi43696432001-11-18 19:15:05 +0000915
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +0000916 do {
917 res = read(f->fd, cmd->buf, FUSE_MAX_IN);
918 if(res == -1) {
919 /* ENODEV means we got unmounted, so we silenty return failure */
920 if(errno != ENODEV) {
921 perror("fuse: reading device");
922 /* BAD... This will happen again */
923 }
924 free_cmd(cmd);
925 return NULL;
Miklos Szeredi96249982001-11-21 12:21:19 +0000926 }
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +0000927 if((size_t) res < sizeof(struct fuse_in_header)) {
928 fprintf(stderr, "short read on fuse device\n");
929 /* Cannot happen */
930 free_cmd(cmd);
931 return NULL;
932 }
933 cmd->buflen = res;
934
935 /* Forget is special, it can be done without messing with threads. */
936 if(in->opcode == FUSE_FORGET)
937 do_forget(f, in, (struct fuse_forget_in *) inarg);
938
939 } while(in->opcode == FUSE_FORGET);
940
Miklos Szeredifff56ab2001-11-16 10:12:59 +0000941 return cmd;
Miklos Szeredi2df1c042001-11-06 15:07:17 +0000942}
943
Miklos Szeredifff56ab2001-11-16 10:12:59 +0000944
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000945void fuse_loop(struct fuse *f)
946{
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000947 while(1) {
Miklos Szeredifff56ab2001-11-16 10:12:59 +0000948 struct fuse_cmd *cmd = __fuse_read_cmd(f);
949 if(cmd == NULL)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000950 exit(1);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000951
Miklos Szeredifff56ab2001-11-16 10:12:59 +0000952 __fuse_process_cmd(f, cmd);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000953 }
954}
955
Miklos Szeredi2e50d432001-12-20 12:17:25 +0000956struct fuse_context *fuse_get_context(struct fuse *f)
957{
958 if(f->getcontext)
959 return f->getcontext(f);
960 else
961 return &f->context;
962}
963
964struct fuse *fuse_new(int fd, int flags, const struct fuse_operations *op)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000965{
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000966 struct fuse *f;
967 struct node *root;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000968
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000969 f = (struct fuse *) calloc(1, sizeof(struct fuse));
Miklos Szeredi2df1c042001-11-06 15:07:17 +0000970
Miklos Szeredia181e612001-11-06 12:03:23 +0000971 f->flags = flags;
Miklos Szeredi8cffdb92001-11-09 14:49:18 +0000972 f->fd = fd;
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000973 f->ctr = 0;
Miklos Szeredifff56ab2001-11-16 10:12:59 +0000974 /* FIXME: Dynamic hash table */
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000975 f->name_table_size = 14057;
976 f->name_table = (struct node **)
977 calloc(1, sizeof(struct node *) * f->name_table_size);
978 f->ino_table_size = 14057;
979 f->ino_table = (struct node **)
980 calloc(1, sizeof(struct node *) * f->ino_table_size);
Miklos Szeredia181e612001-11-06 12:03:23 +0000981 pthread_mutex_init(&f->lock, NULL);
Miklos Szeredi33232032001-11-19 17:55:51 +0000982 f->numworker = 0;
983 f->numavail = 0;
Miklos Szeredi2e50d432001-12-20 12:17:25 +0000984 f->op = *op;
985 f->getcontext = NULL;
986 f->context.uid = 0;
987 f->context.gid = 0;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000988
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000989 root = (struct node *) calloc(1, sizeof(struct node));
Miklos Szeredi8cffdb92001-11-09 14:49:18 +0000990 root->mode = 0;
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000991 root->rdev = 0;
992 root->name = strdup("/");
993 root->parent = 0;
994 hash_ino(f, root, FUSE_ROOT_INO);
995
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000996 return f;
997}
998
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000999void fuse_destroy(struct fuse *f)
1000{
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001001 size_t i;
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001002 for(i = 0; i < f->ino_table_size; i++) {
1003 struct node *node;
1004 struct node *next;
1005 for(node = f->ino_table[i]; node != NULL; node = next) {
1006 next = node->ino_next;
1007 free_node(node);
1008 }
1009 }
1010 free(f->ino_table);
1011 free(f->name_table);
Miklos Szeredia181e612001-11-06 12:03:23 +00001012 pthread_mutex_destroy(&f->lock);
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001013 free(f);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001014}