blob: 88f3eae7d6d159f1cc014505d5f9ffa9a157aaf3 [file] [log] [blame]
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001/*
2 FUSE: Filesystem in Userspace
3 Copyright (C) 2001 Miklos Szeredi (mszeredi@inf.bme.hu)
4
5 This program can be distributed under the terms of the GNU GPL.
6 See the file COPYING.
7*/
8
9#include "fuse_i.h"
10#include <linux/fuse.h>
11
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 Szeredi85c74fc2001-10-28 19:44:14 +000020
Miklos Szeredicc8c9752001-11-21 10:03:39 +000021#define FUSE_KERNEL_VERSION_ENV "_FUSE_KERNEL_VERSION"
22
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +000023static inline void inc_avail(struct fuse *f)
24{
25 pthread_mutex_lock(&f->lock);
26 f->numavail ++;
27 pthread_mutex_unlock(&f->lock);
28}
29
30static inline void dec_avail(struct fuse *f)
31{
32 pthread_mutex_lock(&f->lock);
33 f->numavail --;
34 pthread_mutex_unlock(&f->lock);
35}
36
Miklos Szeredi97c61e92001-11-07 12:09:43 +000037static struct node *__get_node(struct fuse *f, fino_t ino)
Miklos Szeredia181e612001-11-06 12:03:23 +000038{
Miklos Szeredi97c61e92001-11-07 12:09:43 +000039 size_t hash = ino % f->ino_table_size;
40 struct node *node;
41
42 for(node = f->ino_table[hash]; node != NULL; node = node->ino_next)
43 if(node->ino == ino)
44 return node;
45
46 return NULL;
Miklos Szeredia181e612001-11-06 12:03:23 +000047}
48
Miklos Szeredi97c61e92001-11-07 12:09:43 +000049static struct node *get_node(struct fuse *f, fino_t ino)
Miklos Szeredia181e612001-11-06 12:03:23 +000050{
Miklos Szeredi97c61e92001-11-07 12:09:43 +000051 struct node *node = __get_node(f, ino);
52 if(node != NULL)
53 return node;
54
55 fprintf(stderr, "fuse internal error: inode %lu not found\n", ino);
56 abort();
Miklos Szeredia181e612001-11-06 12:03:23 +000057}
58
Miklos Szeredi97c61e92001-11-07 12:09:43 +000059static void hash_ino(struct fuse *f, struct node *node, fino_t ino)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000060{
Miklos Szeredi97c61e92001-11-07 12:09:43 +000061 size_t hash = ino % f->ino_table_size;
62 node->ino = ino;
63
64 node->ino_next = f->ino_table[hash];
65 f->ino_table[hash] = node;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000066}
67
Miklos Szeredi97c61e92001-11-07 12:09:43 +000068static void unhash_ino(struct fuse *f, struct node *node)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000069{
Miklos Szeredi97c61e92001-11-07 12:09:43 +000070 size_t hash = node->ino % f->ino_table_size;
71 struct node **nodep = &f->ino_table[hash];
72
73 for(; *nodep != NULL; nodep = &(*nodep)->ino_next)
74 if(*nodep == node) {
75 *nodep = node->ino_next;
76 return;
77 }
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000078}
79
Miklos Szeredi97c61e92001-11-07 12:09:43 +000080static fino_t get_ino(struct node *node)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000081{
Miklos Szeredi97c61e92001-11-07 12:09:43 +000082 return node->ino;
83}
84
85static fino_t next_ino(struct fuse *f)
86{
87 while(f->ctr == 0 || __get_node(f, f->ctr) != NULL)
88 f->ctr++;
89
90 return f->ctr;
91}
92
93static void free_node(struct node *node)
94{
95 free(node->name);
96 free(node);
97}
98
99static unsigned int name_hash(struct fuse *f, fino_t parent, const char *name)
100{
101 unsigned int hash = *name;
102
103 if(hash)
104 for(name += 1; *name != '\0'; name++)
105 hash = (hash << 5) - hash + *name;
106
107 return (hash + parent) % f->name_table_size;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000108}
109
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000110static struct node *lookup_node(struct fuse *f, fino_t parent,
111 const char *name)
112{
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000113 size_t hash = name_hash(f, parent, name);
114 struct node *node;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000115
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000116 for(node = f->name_table[hash]; node != NULL; node = node->name_next)
117 if(node->parent == parent && strcmp(node->name, name) == 0)
118 return node;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000119
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000120 return NULL;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000121}
122
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000123static void hash_name(struct fuse *f, struct node *node, fino_t parent,
Miklos Szeredia181e612001-11-06 12:03:23 +0000124 const char *name)
Miklos Szeredi5e183482001-10-31 14:52:35 +0000125{
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000126 size_t hash = name_hash(f, parent, name);
Miklos Szeredia181e612001-11-06 12:03:23 +0000127 node->parent = parent;
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000128 node->name = strdup(name);
129 node->name_next = f->name_table[hash];
130 f->name_table[hash] = node;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000131}
132
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000133static void unhash_name(struct fuse *f, struct node *node)
Miklos Szeredia181e612001-11-06 12:03:23 +0000134{
135 if(node->name != NULL) {
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000136 size_t hash = name_hash(f, node->parent, node->name);
137 struct node **nodep = &f->name_table[hash];
138
139 for(; *nodep != NULL; nodep = &(*nodep)->name_next)
140 if(*nodep == node) {
141 *nodep = node->name_next;
142 node->name_next = NULL;
143 free(node->name);
144 node->name = NULL;
145 node->parent = 0;
146 return;
147 }
148 fprintf(stderr, "fuse internal error: unable to unhash node: %lu\n",
149 node->ino);
150 abort();
Miklos Szeredia181e612001-11-06 12:03:23 +0000151 }
152}
153
154static fino_t find_node(struct fuse *f, fino_t parent, char *name,
155 struct fuse_attr *attr, int version)
Miklos Szeredi5e183482001-10-31 14:52:35 +0000156{
157 struct node *node;
Miklos Szeredia181e612001-11-06 12:03:23 +0000158 int mode = attr->mode & S_IFMT;
159 int rdev = 0;
160
161 if(S_ISCHR(mode) || S_ISBLK(mode))
162 rdev = attr->rdev;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000163
Miklos Szeredia181e612001-11-06 12:03:23 +0000164 pthread_mutex_lock(&f->lock);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000165 node = lookup_node(f, parent, name);
166 if(node != NULL) {
Miklos Szeredia181e612001-11-06 12:03:23 +0000167 if(node->mode == mode && node->rdev == rdev)
168 goto out;
169
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000170 unhash_name(f, node);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000171 }
172
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000173 node = (struct node *) calloc(1, sizeof(struct node));
Miklos Szeredia181e612001-11-06 12:03:23 +0000174 node->mode = mode;
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000175 node->rdev = rdev;
176 hash_ino(f, node, next_ino(f));
177 hash_name(f, node, parent, name);
Miklos Szeredia181e612001-11-06 12:03:23 +0000178
179 out:
180 node->version = version;
181 pthread_mutex_unlock(&f->lock);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000182 return get_ino(node);
183}
184
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000185static char *add_name(char *buf, char *s, const char *name)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000186{
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000187 size_t len = strlen(name);
188 s -= len;
189 if(s <= buf) {
190 fprintf(stderr, "fuse: path too long: ...%s\n", s + len);
191 return NULL;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000192 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000193 strncpy(s, name, len);
194 s--;
195 *s = '/';
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000196
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000197 return s;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000198}
199
Miklos Szeredia181e612001-11-06 12:03:23 +0000200static char *get_path_name(struct fuse *f, fino_t ino, const char *name)
Miklos Szeredib483c932001-10-29 14:57:57 +0000201{
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000202 char buf[FUSE_MAX_PATH];
203 char *s = buf + FUSE_MAX_PATH - 1;
204 struct node *node;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000205
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000206 *s = '\0';
Miklos Szeredia181e612001-11-06 12:03:23 +0000207
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000208 if(name != NULL) {
209 s = add_name(buf, s, name);
210 if(s == NULL)
211 return NULL;
212 }
213
214 pthread_mutex_lock(&f->lock);
215 for(node = get_node(f, ino); node->ino != FUSE_ROOT_INO;
216 node = get_node(f, node->parent)) {
217 if(node->name == NULL) {
218 s = NULL;
219 break;
220 }
221
222 s = add_name(buf, s, node->name);
223 if(s == NULL)
224 break;
225 }
226 pthread_mutex_unlock(&f->lock);
227
228 if(s == NULL)
Miklos Szeredi5e183482001-10-31 14:52:35 +0000229 return NULL;
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000230 else if(*s == '\0')
231 return strdup("/");
232 else
233 return strdup(s);
234}
Miklos Szeredia181e612001-11-06 12:03:23 +0000235
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000236static char *get_path(struct fuse *f, fino_t ino)
237{
238 return get_path_name(f, ino, NULL);
Miklos Szeredib483c932001-10-29 14:57:57 +0000239}
240
Miklos Szeredia181e612001-11-06 12:03:23 +0000241static void destroy_node(struct fuse *f, fino_t ino, int version)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000242{
Miklos Szeredia181e612001-11-06 12:03:23 +0000243 struct node *node;
244
245 pthread_mutex_lock(&f->lock);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000246 node = get_node(f, ino);
Miklos Szeredi39f28672001-11-14 14:52:54 +0000247 if(node->version == version && ino != FUSE_ROOT_INO) {
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000248 unhash_name(f, node);
249 unhash_ino(f, node);
Miklos Szeredia181e612001-11-06 12:03:23 +0000250 free_node(node);
251 }
252 pthread_mutex_unlock(&f->lock);
253
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000254}
255
Miklos Szeredi5e183482001-10-31 14:52:35 +0000256static void remove_node(struct fuse *f, fino_t dir, const char *name)
257{
Miklos Szeredia181e612001-11-06 12:03:23 +0000258 struct node *node;
259
260 pthread_mutex_lock(&f->lock);
261 node = lookup_node(f, dir, name);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000262 if(node == NULL) {
263 fprintf(stderr, "fuse internal error: unable to remove node %lu/%s\n",
264 dir, name);
265 abort();
266 }
267 unhash_name(f, node);
Miklos Szeredia181e612001-11-06 12:03:23 +0000268 pthread_mutex_unlock(&f->lock);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000269}
270
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000271static void rename_node(struct fuse *f, fino_t olddir, const char *oldname,
272 fino_t newdir, const char *newname)
273{
Miklos Szeredia181e612001-11-06 12:03:23 +0000274 struct node *node;
275 struct node *newnode;
276
277 pthread_mutex_lock(&f->lock);
278 node = lookup_node(f, olddir, oldname);
279 newnode = lookup_node(f, newdir, newname);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000280 if(node == NULL) {
281 fprintf(stderr, "fuse internal error: unable to rename node %lu/%s\n",
282 olddir, oldname);
283 abort();
284 }
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000285
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000286 if(newnode != NULL)
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000287 unhash_name(f, newnode);
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000288
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000289 unhash_name(f, node);
290 hash_name(f, node, newdir, newname);
Miklos Szeredia181e612001-11-06 12:03:23 +0000291 pthread_mutex_unlock(&f->lock);
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000292}
293
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000294static void convert_stat(struct stat *stbuf, struct fuse_attr *attr)
295{
296 attr->mode = stbuf->st_mode;
297 attr->nlink = stbuf->st_nlink;
298 attr->uid = stbuf->st_uid;
299 attr->gid = stbuf->st_gid;
300 attr->rdev = stbuf->st_rdev;
301 attr->size = stbuf->st_size;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000302 attr->blocks = stbuf->st_blocks;
303 attr->atime = stbuf->st_atime;
304 attr->mtime = stbuf->st_mtime;
305 attr->ctime = stbuf->st_ctime;
Miklos Szeredifff56ab2001-11-16 10:12:59 +0000306 attr->_dummy = 4096;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000307}
308
Mark Glinesd84b39a2002-01-07 16:32:02 +0000309static void convert_statfs(struct statfs *st, struct fuse_statfs *fst)
310{
311 fst->block_size = st->f_bsize;
312 fst->blocks = st->f_blocks;
313 fst->blocks_free = st->f_bavail;
314 fst->files = st->f_files;
315 fst->files_free = st->f_ffree;
316 fst->namelen = st->f_namelen;
317}
318
Miklos Szeredia181e612001-11-06 12:03:23 +0000319static int fill_dir(struct fuse_dirhandle *dh, char *name, int type)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000320{
321 struct fuse_dirent dirent;
322 size_t reclen;
323 size_t res;
324
Miklos Szeredi43696432001-11-18 19:15:05 +0000325 dirent.ino = (unsigned long) -1;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000326 dirent.namelen = strlen(name);
327 strncpy(dirent.name, name, sizeof(dirent.name));
328 dirent.type = type;
329 reclen = FUSE_DIRENT_SIZE(&dirent);
330 res = fwrite(&dirent, reclen, 1, dh->fp);
331 if(res == 0) {
Miklos Szeredi96249982001-11-21 12:21:19 +0000332 perror("fuse: writing directory file");
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000333 return -EIO;
334 }
335 return 0;
336}
337
Miklos Szeredi43696432001-11-18 19:15:05 +0000338static void send_reply_raw(struct fuse *f, char *outbuf, size_t outsize)
339{
340 int res;
341
342 if((f->flags & FUSE_DEBUG)) {
343 struct fuse_out_header *out = (struct fuse_out_header *) outbuf;
344 printf(" unique: %i, error: %i (%s), outsize: %i\n", out->unique,
345 out->error, strerror(-out->error), outsize);
346 fflush(stdout);
347 }
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +0000348
349 /* This needs to be done before the reply because otherwise the
350 scheduler can tricks with us, and only let the counter be increased
351 long after the operation is done */
352 inc_avail(f);
353
Miklos Szeredi43696432001-11-18 19:15:05 +0000354 res = write(f->fd, outbuf, outsize);
355 if(res == -1) {
356 /* ENOENT means the operation was interrupted */
357 if(errno != ENOENT)
Miklos Szeredi96249982001-11-21 12:21:19 +0000358 perror("fuse: writing device");
Miklos Szeredi43696432001-11-18 19:15:05 +0000359 }
360}
361
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000362static void send_reply(struct fuse *f, struct fuse_in_header *in, int error,
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000363 void *arg, size_t argsize)
364{
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000365 char *outbuf;
366 size_t outsize;
367 struct fuse_out_header *out;
368
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000369 if(error > 0) {
Miklos Szeredi96249982001-11-21 12:21:19 +0000370 fprintf(stderr, "fuse: positive error code: %i\n", error);
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000371 error = -ERANGE;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000372 }
373
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000374 if(error)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000375 argsize = 0;
376
377 outsize = sizeof(struct fuse_out_header) + argsize;
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000378 outbuf = (char *) malloc(outsize);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000379 out = (struct fuse_out_header *) outbuf;
380 out->unique = in->unique;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000381 out->error = error;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000382 if(argsize != 0)
383 memcpy(outbuf + sizeof(struct fuse_out_header), arg, argsize);
384
Miklos Szeredi43696432001-11-18 19:15:05 +0000385 send_reply_raw(f, outbuf, outsize);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000386
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000387 free(outbuf);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000388}
389
390static void do_lookup(struct fuse *f, struct fuse_in_header *in, char *name)
391{
392 int res;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000393 char *path;
394 struct stat buf;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000395 struct fuse_lookup_out arg;
396
Miklos Szeredi5e183482001-10-31 14:52:35 +0000397 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000398 path = get_path_name(f, in->ino, name);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000399 if(path != NULL) {
Miklos Szeredi6ebe2342002-01-06 21:44:16 +0000400 if(f->flags & FUSE_DEBUG) {
401 printf("LOOKUP %s\n", path);
402 fflush(stdout);
403 }
Miklos Szeredi5e183482001-10-31 14:52:35 +0000404 res = -ENOSYS;
405 if(f->op.getattr)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000406 res = f->op.getattr(path, &buf);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000407 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000408 }
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000409 if(res == 0) {
410 convert_stat(&buf, &arg.attr);
Miklos Szeredia181e612001-11-06 12:03:23 +0000411 arg.ino = find_node(f, in->ino, name, &arg.attr, in->unique);
Miklos Szeredi6ebe2342002-01-06 21:44:16 +0000412 if(f->flags & FUSE_DEBUG) {
413 printf(" LOOKUP: %li\n", arg.ino);
414 fflush(stdout);
415 }
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000416 }
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000417 send_reply(f, in, res, &arg, sizeof(arg));
418}
419
Miklos Szeredia181e612001-11-06 12:03:23 +0000420static void do_forget(struct fuse *f, struct fuse_in_header *in,
421 struct fuse_forget_in *arg)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000422{
Miklos Szeredi43696432001-11-18 19:15:05 +0000423 if(f->flags & FUSE_DEBUG) {
424 printf("FORGET %li/%i\n", in->ino, arg->version);
425 fflush(stdout);
426 }
Miklos Szeredia181e612001-11-06 12:03:23 +0000427 destroy_node(f, in->ino, arg->version);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000428}
429
430static void do_getattr(struct fuse *f, struct fuse_in_header *in)
431{
432 int res;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000433 char *path;
434 struct stat buf;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000435 struct fuse_getattr_out arg;
436
Miklos Szeredi5e183482001-10-31 14:52:35 +0000437 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000438 path = get_path(f, in->ino);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000439 if(path != NULL) {
440 res = -ENOSYS;
441 if(f->op.getattr)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000442 res = f->op.getattr(path, &buf);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000443 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000444 }
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000445 if(res == 0)
446 convert_stat(&buf, &arg.attr);
447
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000448 send_reply(f, in, res, &arg, sizeof(arg));
449}
450
Miklos Szeredi680a69a2001-11-16 13:31:14 +0000451static int do_chmod(struct fuse *f, const char *path, struct fuse_attr *attr)
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000452{
453 int res;
454
455 res = -ENOSYS;
456 if(f->op.chmod)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000457 res = f->op.chmod(path, attr->mode);
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000458
459 return res;
460}
461
Miklos Szeredi680a69a2001-11-16 13:31:14 +0000462static int do_chown(struct fuse *f, const char *path, struct fuse_attr *attr,
Miklos Szeredi2e50d432001-12-20 12:17:25 +0000463 int valid)
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000464{
465 int res;
466 uid_t uid = (valid & FATTR_UID) ? attr->uid : (uid_t) -1;
467 gid_t gid = (valid & FATTR_GID) ? attr->gid : (gid_t) -1;
468
469 res = -ENOSYS;
470 if(f->op.chown)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000471 res = f->op.chown(path, uid, gid);
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000472
473 return res;
474}
475
Miklos Szeredi680a69a2001-11-16 13:31:14 +0000476static int do_truncate(struct fuse *f, const char *path,
477 struct fuse_attr *attr)
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000478{
479 int res;
480
481 res = -ENOSYS;
482 if(f->op.truncate)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000483 res = f->op.truncate(path, attr->size);
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000484
485 return res;
486}
487
Miklos Szeredi680a69a2001-11-16 13:31:14 +0000488static int do_utime(struct fuse *f, const char *path, struct fuse_attr *attr)
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000489{
490 int res;
491 struct utimbuf buf;
492 buf.actime = attr->atime;
493 buf.modtime = attr->mtime;
494 res = -ENOSYS;
495 if(f->op.utime)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000496 res = f->op.utime(path, &buf);
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000497
498 return res;
499}
500
Miklos Szeredi5e183482001-10-31 14:52:35 +0000501static void do_setattr(struct fuse *f, struct fuse_in_header *in,
502 struct fuse_setattr_in *arg)
503{
504 int res;
505 char *path;
506 int valid = arg->valid;
507 struct fuse_attr *attr = &arg->attr;
Miklos Szeredia181e612001-11-06 12:03:23 +0000508 struct fuse_setattr_out outarg;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000509
510 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000511 path = get_path(f, in->ino);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000512 if(path != NULL) {
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000513 res = -ENOSYS;
514 if(f->op.getattr) {
515 res = 0;
516 if(!res && (valid & FATTR_MODE))
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000517 res = do_chmod(f, path, attr);
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000518 if(!res && (valid & (FATTR_UID | FATTR_GID)))
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000519 res = do_chown(f, path, attr, valid);
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000520 if(!res && (valid & FATTR_SIZE))
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000521 res = do_truncate(f, path, attr);
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000522 if(!res && (valid & FATTR_UTIME))
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000523 res = do_utime(f, path, attr);
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000524 if(!res) {
525 struct stat buf;
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000526 res = f->op.getattr(path, &buf);
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000527 if(!res)
528 convert_stat(&buf, &outarg.attr);
Miklos Szeredia181e612001-11-06 12:03:23 +0000529 }
Miklos Szeredi5e183482001-10-31 14:52:35 +0000530 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000531 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000532 }
Miklos Szeredia181e612001-11-06 12:03:23 +0000533 send_reply(f, in, res, &outarg, sizeof(outarg));
Miklos Szeredi5e183482001-10-31 14:52:35 +0000534}
535
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000536static void do_readlink(struct fuse *f, struct fuse_in_header *in)
537{
538 int res;
539 char link[PATH_MAX + 1];
Miklos Szeredib483c932001-10-29 14:57:57 +0000540 char *path;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000541
Miklos Szeredi5e183482001-10-31 14:52:35 +0000542 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000543 path = get_path(f, in->ino);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000544 if(path != NULL) {
545 res = -ENOSYS;
546 if(f->op.readlink)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000547 res = f->op.readlink(path, link, sizeof(link));
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000548 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000549 }
Miklos Szeredi2df1c042001-11-06 15:07:17 +0000550 link[PATH_MAX] = '\0';
Miklos Szeredi5e183482001-10-31 14:52:35 +0000551 send_reply(f, in, res, link, !res ? strlen(link) : 0);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000552}
553
554static void do_getdir(struct fuse *f, struct fuse_in_header *in)
555{
556 int res;
557 struct fuse_getdir_out arg;
Miklos Szeredia181e612001-11-06 12:03:23 +0000558 struct fuse_dirhandle dh;
Miklos Szeredib483c932001-10-29 14:57:57 +0000559 char *path;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000560
Miklos Szeredib483c932001-10-29 14:57:57 +0000561 dh.fuse = f;
562 dh.fp = tmpfile();
563 dh.dir = in->ino;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000564 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000565 path = get_path(f, in->ino);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000566 if(path != NULL) {
567 res = -ENOSYS;
568 if(f->op.getdir)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000569 res = f->op.getdir(path, &dh, (fuse_dirfil_t) fill_dir);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000570 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000571 }
Miklos Szeredib483c932001-10-29 14:57:57 +0000572 fflush(dh.fp);
573 arg.fd = fileno(dh.fp);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000574 send_reply(f, in, res, &arg, sizeof(arg));
Miklos Szeredib483c932001-10-29 14:57:57 +0000575 fclose(dh.fp);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000576}
577
Miklos Szeredib483c932001-10-29 14:57:57 +0000578static void do_mknod(struct fuse *f, struct fuse_in_header *in,
579 struct fuse_mknod_in *inarg)
580{
581 int res;
582 char *path;
583 struct fuse_mknod_out outarg;
584 struct stat buf;
585
Miklos Szeredi5e183482001-10-31 14:52:35 +0000586 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000587 path = get_path_name(f, in->ino, inarg->name);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000588 if(path != NULL) {
589 res = -ENOSYS;
590 if(f->op.mknod && f->op.getattr) {
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000591 res = f->op.mknod(path, inarg->mode, inarg->rdev);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000592 if(res == 0)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000593 res = f->op.getattr(path, &buf);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000594 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000595 free(path);
Miklos Szeredib483c932001-10-29 14:57:57 +0000596 }
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000597 if(res == 0) {
Miklos Szeredib483c932001-10-29 14:57:57 +0000598 convert_stat(&buf, &outarg.attr);
Miklos Szeredia181e612001-11-06 12:03:23 +0000599 outarg.ino = find_node(f, in->ino, inarg->name, &outarg.attr,
600 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 Szeredia181e612001-11-06 12:03:23 +0000613 path = get_path_name(f, in->ino, inarg->name);
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;
670 char *oldname = inarg->names;
671 char *newname = inarg->names + 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 Szeredia181e612001-11-06 12:03:23 +0000702 newpath = get_path_name(f, arg->newdir, arg->name);
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 Szeredi43696432001-11-18 19:15:05 +0000765 out->unique = in->unique;
766 out->error = res;
767 outsize = sizeof(struct fuse_out_header) + size;
768
769 send_reply_raw(f, outbuf, outsize);
770 free(outbuf);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000771}
Miklos Szeredib483c932001-10-29 14:57:57 +0000772
Miklos Szeredia181e612001-11-06 12:03:23 +0000773static void do_write(struct fuse *f, struct fuse_in_header *in,
774 struct fuse_write_in *arg)
775{
776 int res;
777 char *path;
Miklos Szeredia181e612001-11-06 12:03:23 +0000778
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000779 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000780 path = get_path(f, in->ino);
781 if(path != NULL) {
Miklos Szeredi6ebe2342002-01-06 21:44:16 +0000782 if(f->flags & FUSE_DEBUG) {
783 printf("WRITE %u bytes to %llu\n", arg->size, arg->offset);
784 fflush(stdout);
785 }
786
Miklos Szeredia181e612001-11-06 12:03:23 +0000787 res = -ENOSYS;
788 if(f->op.write)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000789 res = f->op.write(path, arg->buf, arg->size, arg->offset);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000790 free(path);
Miklos Szeredia181e612001-11-06 12:03:23 +0000791 }
792
793 if(res > 0) {
794 if((size_t) res != arg->size) {
795 fprintf(stderr, "short write: %u (should be %u)\n", res,
796 arg->size);
797 res = -EIO;
798 }
799 else
800 res = 0;
801 }
802
803 send_reply(f, in, res, NULL, 0);
804}
805
Mark Glinesd84b39a2002-01-07 16:32:02 +0000806static void do_statfs(struct fuse *f, struct fuse_in_header *in)
807{
808 int res;
809 struct statfs sbuf;
810 struct fuse_statfs_out arg;
811
812 res = -ENOSYS;
813 if(f->op.statfs)
814 res = f->op.statfs(&sbuf);
815 if(!res)
816 convert_statfs(&sbuf,&arg.st);
817 send_reply(f, in, res, &arg, sizeof(arg));
818}
819
Miklos Szeredi43696432001-11-18 19:15:05 +0000820static void free_cmd(struct fuse_cmd *cmd)
821{
822 free(cmd->buf);
823 free(cmd);
824}
825
Miklos Szeredifff56ab2001-11-16 10:12:59 +0000826void __fuse_process_cmd(struct fuse *f, struct fuse_cmd *cmd)
Miklos Szeredia181e612001-11-06 12:03:23 +0000827{
Miklos Szeredia181e612001-11-06 12:03:23 +0000828 struct fuse_in_header *in = (struct fuse_in_header *) cmd->buf;
829 void *inarg = cmd->buf + sizeof(struct fuse_in_header);
830 size_t argsize;
Miklos Szeredife25def2001-12-20 15:38:05 +0000831 struct fuse_context *ctx = fuse_get_context(f);
Miklos Szeredia181e612001-11-06 12:03:23 +0000832
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +0000833 dec_avail(f);
Miklos Szeredi33232032001-11-19 17:55:51 +0000834
Miklos Szeredic0938ea2001-11-07 12:35:06 +0000835 if((f->flags & FUSE_DEBUG)) {
836 printf("unique: %i, opcode: %i, ino: %li, insize: %i\n", in->unique,
837 in->opcode, in->ino, cmd->buflen);
838 fflush(stdout);
839 }
Miklos Szeredife25def2001-12-20 15:38:05 +0000840
841 ctx->uid = in->uid;
842 ctx->gid = in->gid;
Miklos Szeredia181e612001-11-06 12:03:23 +0000843
844 argsize = cmd->buflen - sizeof(struct fuse_in_header);
845
846 switch(in->opcode) {
847 case FUSE_LOOKUP:
848 do_lookup(f, in, (char *) inarg);
849 break;
850
Miklos Szeredia181e612001-11-06 12:03:23 +0000851 case FUSE_GETATTR:
852 do_getattr(f, in);
853 break;
854
855 case FUSE_SETATTR:
856 do_setattr(f, in, (struct fuse_setattr_in *) inarg);
857 break;
858
859 case FUSE_READLINK:
860 do_readlink(f, in);
861 break;
862
863 case FUSE_GETDIR:
864 do_getdir(f, in);
865 break;
866
867 case FUSE_MKNOD:
868 do_mknod(f, in, (struct fuse_mknod_in *) inarg);
869 break;
870
871 case FUSE_MKDIR:
872 do_mkdir(f, in, (struct fuse_mkdir_in *) inarg);
873 break;
874
875 case FUSE_UNLINK:
876 case FUSE_RMDIR:
877 do_remove(f, in, (char *) inarg);
878 break;
879
880 case FUSE_SYMLINK:
881 do_symlink(f, in, (char *) inarg,
882 ((char *) inarg) + strlen((char *) inarg) + 1);
883 break;
884
885 case FUSE_RENAME:
886 do_rename(f, in, (struct fuse_rename_in *) inarg);
887 break;
888
889 case FUSE_LINK:
890 do_link(f, in, (struct fuse_link_in *) inarg);
891 break;
892
893 case FUSE_OPEN:
894 do_open(f, in, (struct fuse_open_in *) inarg);
895 break;
896
897 case FUSE_READ:
898 do_read(f, in, (struct fuse_read_in *) inarg);
899 break;
900
901 case FUSE_WRITE:
902 do_write(f, in, (struct fuse_write_in *) inarg);
903 break;
904
Mark Glinesd84b39a2002-01-07 16:32:02 +0000905 case FUSE_STATFS:
906 do_statfs(f, in);
907 break;
908
Miklos Szeredia181e612001-11-06 12:03:23 +0000909 default:
910 fprintf(stderr, "Operation %i not implemented\n", in->opcode);
Miklos Szeredi43696432001-11-18 19:15:05 +0000911 send_reply(f, in, -ENOSYS, NULL, 0);
Miklos Szeredia181e612001-11-06 12:03:23 +0000912 }
Miklos Szeredi43696432001-11-18 19:15:05 +0000913
914 free_cmd(cmd);
Miklos Szeredia181e612001-11-06 12:03:23 +0000915}
916
Miklos Szeredifff56ab2001-11-16 10:12:59 +0000917struct fuse_cmd *__fuse_read_cmd(struct fuse *f)
Miklos Szeredi2df1c042001-11-06 15:07:17 +0000918{
Miklos Szeredifff56ab2001-11-16 10:12:59 +0000919 ssize_t res;
Miklos Szeredifff56ab2001-11-16 10:12:59 +0000920 struct fuse_cmd *cmd;
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +0000921 struct fuse_in_header *in;
922 void *inarg;
Miklos Szeredifff56ab2001-11-16 10:12:59 +0000923
Miklos Szeredi43696432001-11-18 19:15:05 +0000924 cmd = (struct fuse_cmd *) malloc(sizeof(struct fuse_cmd));
925 cmd->buf = (char *) malloc(FUSE_MAX_IN);
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +0000926 in = (struct fuse_in_header *) cmd->buf;
927 inarg = cmd->buf + sizeof(struct fuse_in_header);
Miklos Szeredi43696432001-11-18 19:15:05 +0000928
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +0000929 do {
930 res = read(f->fd, cmd->buf, FUSE_MAX_IN);
931 if(res == -1) {
932 /* ENODEV means we got unmounted, so we silenty return failure */
933 if(errno != ENODEV) {
934 perror("fuse: reading device");
935 /* BAD... This will happen again */
936 }
937 free_cmd(cmd);
938 return NULL;
Miklos Szeredi96249982001-11-21 12:21:19 +0000939 }
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +0000940 if((size_t) res < sizeof(struct fuse_in_header)) {
941 fprintf(stderr, "short read on fuse device\n");
942 /* Cannot happen */
943 free_cmd(cmd);
944 return NULL;
945 }
946 cmd->buflen = res;
947
948 /* Forget is special, it can be done without messing with threads. */
949 if(in->opcode == FUSE_FORGET)
950 do_forget(f, in, (struct fuse_forget_in *) inarg);
951
952 } while(in->opcode == FUSE_FORGET);
953
Miklos Szeredifff56ab2001-11-16 10:12:59 +0000954 return cmd;
Miklos Szeredi2df1c042001-11-06 15:07:17 +0000955}
956
Miklos Szeredifff56ab2001-11-16 10:12:59 +0000957
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000958void fuse_loop(struct fuse *f)
959{
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000960 while(1) {
Miklos Szeredifff56ab2001-11-16 10:12:59 +0000961 struct fuse_cmd *cmd = __fuse_read_cmd(f);
962 if(cmd == NULL)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000963 exit(1);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000964
Miklos Szeredifff56ab2001-11-16 10:12:59 +0000965 __fuse_process_cmd(f, cmd);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000966 }
967}
968
Miklos Szeredi2e50d432001-12-20 12:17:25 +0000969struct fuse_context *fuse_get_context(struct fuse *f)
970{
971 if(f->getcontext)
972 return f->getcontext(f);
973 else
974 return &f->context;
975}
976
977struct fuse *fuse_new(int fd, int flags, const struct fuse_operations *op)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000978{
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000979 struct fuse *f;
980 struct node *root;
Miklos Szeredife428122001-11-20 19:12:28 +0000981 char verstr[128];
Miklos Szeredicc8c9752001-11-21 10:03:39 +0000982 char *realver = getenv(FUSE_KERNEL_VERSION_ENV);
Miklos Szeredife428122001-11-20 19:12:28 +0000983
984 if(realver != NULL) {
985 sprintf(verstr, "%i", FUSE_KERNEL_VERSION);
986 if(strcmp(verstr, realver) != 0) {
987 fprintf(stderr,
988 "Warning: FUSE version mismatch: using %s, kernel is %s\n",
989 realver, verstr);
990 }
991 }
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000992
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000993 f = (struct fuse *) calloc(1, sizeof(struct fuse));
Miklos Szeredi2df1c042001-11-06 15:07:17 +0000994
Miklos Szeredia181e612001-11-06 12:03:23 +0000995 f->flags = flags;
Miklos Szeredi8cffdb92001-11-09 14:49:18 +0000996 f->fd = fd;
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000997 f->ctr = 0;
Miklos Szeredifff56ab2001-11-16 10:12:59 +0000998 /* FIXME: Dynamic hash table */
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000999 f->name_table_size = 14057;
1000 f->name_table = (struct node **)
1001 calloc(1, sizeof(struct node *) * f->name_table_size);
1002 f->ino_table_size = 14057;
1003 f->ino_table = (struct node **)
1004 calloc(1, sizeof(struct node *) * f->ino_table_size);
Miklos Szeredia181e612001-11-06 12:03:23 +00001005 pthread_mutex_init(&f->lock, NULL);
Miklos Szeredi33232032001-11-19 17:55:51 +00001006 f->numworker = 0;
1007 f->numavail = 0;
Miklos Szeredi2e50d432001-12-20 12:17:25 +00001008 f->op = *op;
1009 f->getcontext = NULL;
1010 f->context.uid = 0;
1011 f->context.gid = 0;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001012
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001013 root = (struct node *) calloc(1, sizeof(struct node));
Miklos Szeredi8cffdb92001-11-09 14:49:18 +00001014 root->mode = 0;
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001015 root->rdev = 0;
1016 root->name = strdup("/");
1017 root->parent = 0;
1018 hash_ino(f, root, FUSE_ROOT_INO);
1019
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001020 return f;
1021}
1022
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001023void fuse_destroy(struct fuse *f)
1024{
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001025 size_t i;
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001026 for(i = 0; i < f->ino_table_size; i++) {
1027 struct node *node;
1028 struct node *next;
1029 for(node = f->ino_table[i]; node != NULL; node = next) {
1030 next = node->ino_next;
1031 free_node(node);
1032 }
1033 }
1034 free(f->ino_table);
1035 free(f->name_table);
Miklos Szeredia181e612001-11-06 12:03:23 +00001036 pthread_mutex_destroy(&f->lock);
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001037 free(f);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001038}