blob: b809374630ea9cb02e084e23c9c4daf0f7658a2e [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 Szeredi85c74fc2001-10-28 19:44:14 +000020
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +000021static inline void inc_avail(struct fuse *f)
22{
23 pthread_mutex_lock(&f->lock);
24 f->numavail ++;
25 pthread_mutex_unlock(&f->lock);
26}
27
28static inline void dec_avail(struct fuse *f)
29{
30 pthread_mutex_lock(&f->lock);
31 f->numavail --;
32 pthread_mutex_unlock(&f->lock);
33}
34
Miklos Szeredi97c61e92001-11-07 12:09:43 +000035static struct node *__get_node(struct fuse *f, fino_t ino)
Miklos Szeredia181e612001-11-06 12:03:23 +000036{
Miklos Szeredi97c61e92001-11-07 12:09:43 +000037 size_t hash = ino % f->ino_table_size;
38 struct node *node;
39
40 for(node = f->ino_table[hash]; node != NULL; node = node->ino_next)
41 if(node->ino == ino)
42 return node;
43
44 return NULL;
Miklos Szeredia181e612001-11-06 12:03:23 +000045}
46
Miklos Szeredi97c61e92001-11-07 12:09:43 +000047static struct node *get_node(struct fuse *f, fino_t ino)
Miklos Szeredia181e612001-11-06 12:03:23 +000048{
Miklos Szeredi97c61e92001-11-07 12:09:43 +000049 struct node *node = __get_node(f, ino);
50 if(node != NULL)
51 return node;
52
53 fprintf(stderr, "fuse internal error: inode %lu not found\n", ino);
54 abort();
Miklos Szeredia181e612001-11-06 12:03:23 +000055}
56
Miklos Szeredi97c61e92001-11-07 12:09:43 +000057static void hash_ino(struct fuse *f, struct node *node, fino_t ino)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000058{
Miklos Szeredi97c61e92001-11-07 12:09:43 +000059 size_t hash = ino % f->ino_table_size;
60 node->ino = ino;
61
62 node->ino_next = f->ino_table[hash];
63 f->ino_table[hash] = node;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000064}
65
Miklos Szeredi97c61e92001-11-07 12:09:43 +000066static void unhash_ino(struct fuse *f, struct node *node)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000067{
Miklos Szeredi97c61e92001-11-07 12:09:43 +000068 size_t hash = node->ino % f->ino_table_size;
69 struct node **nodep = &f->ino_table[hash];
70
71 for(; *nodep != NULL; nodep = &(*nodep)->ino_next)
72 if(*nodep == node) {
73 *nodep = node->ino_next;
74 return;
75 }
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000076}
77
Miklos Szeredi97c61e92001-11-07 12:09:43 +000078static fino_t get_ino(struct node *node)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000079{
Miklos Szeredi97c61e92001-11-07 12:09:43 +000080 return node->ino;
81}
82
83static fino_t next_ino(struct fuse *f)
84{
85 while(f->ctr == 0 || __get_node(f, f->ctr) != NULL)
86 f->ctr++;
87
88 return f->ctr;
89}
90
91static void free_node(struct node *node)
92{
93 free(node->name);
94 free(node);
95}
96
97static unsigned int name_hash(struct fuse *f, fino_t parent, const char *name)
98{
99 unsigned int hash = *name;
100
101 if(hash)
102 for(name += 1; *name != '\0'; name++)
103 hash = (hash << 5) - hash + *name;
104
105 return (hash + parent) % f->name_table_size;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000106}
107
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000108static struct node *lookup_node(struct fuse *f, fino_t parent,
109 const char *name)
110{
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000111 size_t hash = name_hash(f, parent, name);
112 struct node *node;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000113
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000114 for(node = f->name_table[hash]; node != NULL; node = node->name_next)
115 if(node->parent == parent && strcmp(node->name, name) == 0)
116 return node;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000117
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000118 return NULL;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000119}
120
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000121static void hash_name(struct fuse *f, struct node *node, fino_t parent,
Miklos Szeredia181e612001-11-06 12:03:23 +0000122 const char *name)
Miklos Szeredi5e183482001-10-31 14:52:35 +0000123{
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000124 size_t hash = name_hash(f, parent, name);
Miklos Szeredia181e612001-11-06 12:03:23 +0000125 node->parent = parent;
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000126 node->name = strdup(name);
127 node->name_next = f->name_table[hash];
128 f->name_table[hash] = node;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000129}
130
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000131static void unhash_name(struct fuse *f, struct node *node)
Miklos Szeredia181e612001-11-06 12:03:23 +0000132{
133 if(node->name != NULL) {
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000134 size_t hash = name_hash(f, node->parent, node->name);
135 struct node **nodep = &f->name_table[hash];
136
137 for(; *nodep != NULL; nodep = &(*nodep)->name_next)
138 if(*nodep == node) {
139 *nodep = node->name_next;
140 node->name_next = NULL;
141 free(node->name);
142 node->name = NULL;
143 node->parent = 0;
144 return;
145 }
146 fprintf(stderr, "fuse internal error: unable to unhash node: %lu\n",
147 node->ino);
148 abort();
Miklos Szeredia181e612001-11-06 12:03:23 +0000149 }
150}
151
152static fino_t find_node(struct fuse *f, fino_t parent, char *name,
153 struct fuse_attr *attr, int version)
Miklos Szeredi5e183482001-10-31 14:52:35 +0000154{
155 struct node *node;
Miklos Szeredia181e612001-11-06 12:03:23 +0000156 int mode = attr->mode & S_IFMT;
157 int rdev = 0;
158
159 if(S_ISCHR(mode) || S_ISBLK(mode))
160 rdev = attr->rdev;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000161
Miklos Szeredia181e612001-11-06 12:03:23 +0000162 pthread_mutex_lock(&f->lock);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000163 node = lookup_node(f, parent, name);
164 if(node != NULL) {
Miklos Szeredia181e612001-11-06 12:03:23 +0000165 if(node->mode == mode && node->rdev == rdev)
166 goto out;
167
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000168 unhash_name(f, node);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000169 }
170
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000171 node = (struct node *) calloc(1, sizeof(struct node));
Miklos Szeredia181e612001-11-06 12:03:23 +0000172 node->mode = mode;
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000173 node->rdev = rdev;
174 hash_ino(f, node, next_ino(f));
175 hash_name(f, node, parent, name);
Miklos Szeredia181e612001-11-06 12:03:23 +0000176
177 out:
178 node->version = version;
179 pthread_mutex_unlock(&f->lock);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000180 return get_ino(node);
181}
182
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000183static char *add_name(char *buf, char *s, const char *name)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000184{
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000185 size_t len = strlen(name);
186 s -= len;
187 if(s <= buf) {
188 fprintf(stderr, "fuse: path too long: ...%s\n", s + len);
189 return NULL;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000190 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000191 strncpy(s, name, len);
192 s--;
193 *s = '/';
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000194
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000195 return s;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000196}
197
Miklos Szeredia181e612001-11-06 12:03:23 +0000198static char *get_path_name(struct fuse *f, fino_t ino, const char *name)
Miklos Szeredib483c932001-10-29 14:57:57 +0000199{
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000200 char buf[FUSE_MAX_PATH];
201 char *s = buf + FUSE_MAX_PATH - 1;
202 struct node *node;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000203
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000204 *s = '\0';
Miklos Szeredia181e612001-11-06 12:03:23 +0000205
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000206 if(name != NULL) {
207 s = add_name(buf, s, name);
208 if(s == NULL)
209 return NULL;
210 }
211
212 pthread_mutex_lock(&f->lock);
213 for(node = get_node(f, ino); node->ino != FUSE_ROOT_INO;
214 node = get_node(f, node->parent)) {
215 if(node->name == NULL) {
216 s = NULL;
217 break;
218 }
219
220 s = add_name(buf, s, node->name);
221 if(s == NULL)
222 break;
223 }
224 pthread_mutex_unlock(&f->lock);
225
226 if(s == NULL)
Miklos Szeredi5e183482001-10-31 14:52:35 +0000227 return NULL;
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000228 else if(*s == '\0')
229 return strdup("/");
230 else
231 return strdup(s);
232}
Miklos Szeredia181e612001-11-06 12:03:23 +0000233
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000234static char *get_path(struct fuse *f, fino_t ino)
235{
236 return get_path_name(f, ino, NULL);
Miklos Szeredib483c932001-10-29 14:57:57 +0000237}
238
Miklos Szeredia181e612001-11-06 12:03:23 +0000239static void destroy_node(struct fuse *f, fino_t ino, int version)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000240{
Miklos Szeredia181e612001-11-06 12:03:23 +0000241 struct node *node;
242
243 pthread_mutex_lock(&f->lock);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000244 node = get_node(f, ino);
Miklos Szeredi39f28672001-11-14 14:52:54 +0000245 if(node->version == version && ino != FUSE_ROOT_INO) {
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000246 unhash_name(f, node);
247 unhash_ino(f, node);
Miklos Szeredia181e612001-11-06 12:03:23 +0000248 free_node(node);
249 }
250 pthread_mutex_unlock(&f->lock);
251
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000252}
253
Miklos Szeredi5e183482001-10-31 14:52:35 +0000254static void remove_node(struct fuse *f, fino_t dir, const char *name)
255{
Miklos Szeredia181e612001-11-06 12:03:23 +0000256 struct node *node;
257
258 pthread_mutex_lock(&f->lock);
259 node = lookup_node(f, dir, name);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000260 if(node == NULL) {
261 fprintf(stderr, "fuse internal error: unable to remove node %lu/%s\n",
262 dir, name);
263 abort();
264 }
265 unhash_name(f, node);
Miklos Szeredia181e612001-11-06 12:03:23 +0000266 pthread_mutex_unlock(&f->lock);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000267}
268
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000269static void rename_node(struct fuse *f, fino_t olddir, const char *oldname,
270 fino_t newdir, const char *newname)
271{
Miklos Szeredia181e612001-11-06 12:03:23 +0000272 struct node *node;
273 struct node *newnode;
274
275 pthread_mutex_lock(&f->lock);
276 node = lookup_node(f, olddir, oldname);
277 newnode = lookup_node(f, newdir, newname);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000278 if(node == NULL) {
279 fprintf(stderr, "fuse internal error: unable to rename node %lu/%s\n",
280 olddir, oldname);
281 abort();
282 }
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000283
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000284 if(newnode != NULL)
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000285 unhash_name(f, newnode);
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000286
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000287 unhash_name(f, node);
288 hash_name(f, node, newdir, newname);
Miklos Szeredia181e612001-11-06 12:03:23 +0000289 pthread_mutex_unlock(&f->lock);
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000290}
291
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000292static void convert_stat(struct stat *stbuf, struct fuse_attr *attr)
293{
294 attr->mode = stbuf->st_mode;
295 attr->nlink = stbuf->st_nlink;
296 attr->uid = stbuf->st_uid;
297 attr->gid = stbuf->st_gid;
298 attr->rdev = stbuf->st_rdev;
299 attr->size = stbuf->st_size;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000300 attr->blocks = stbuf->st_blocks;
301 attr->atime = stbuf->st_atime;
302 attr->mtime = stbuf->st_mtime;
303 attr->ctime = stbuf->st_ctime;
Miklos Szeredifff56ab2001-11-16 10:12:59 +0000304 attr->_dummy = 4096;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000305}
306
Miklos Szeredia181e612001-11-06 12:03:23 +0000307static int fill_dir(struct fuse_dirhandle *dh, char *name, int type)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000308{
309 struct fuse_dirent dirent;
310 size_t reclen;
311 size_t res;
312
Miklos Szeredi43696432001-11-18 19:15:05 +0000313 dirent.ino = (unsigned long) -1;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000314 dirent.namelen = strlen(name);
315 strncpy(dirent.name, name, sizeof(dirent.name));
316 dirent.type = type;
317 reclen = FUSE_DIRENT_SIZE(&dirent);
318 res = fwrite(&dirent, reclen, 1, dh->fp);
319 if(res == 0) {
Miklos Szeredi96249982001-11-21 12:21:19 +0000320 perror("fuse: writing directory file");
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000321 return -EIO;
322 }
323 return 0;
324}
325
Miklos Szeredi43696432001-11-18 19:15:05 +0000326static void send_reply_raw(struct fuse *f, char *outbuf, size_t outsize)
327{
328 int res;
329
330 if((f->flags & FUSE_DEBUG)) {
331 struct fuse_out_header *out = (struct fuse_out_header *) outbuf;
332 printf(" unique: %i, error: %i (%s), outsize: %i\n", out->unique,
333 out->error, strerror(-out->error), outsize);
334 fflush(stdout);
335 }
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +0000336
337 /* This needs to be done before the reply because otherwise the
338 scheduler can tricks with us, and only let the counter be increased
339 long after the operation is done */
340 inc_avail(f);
341
Miklos Szeredi43696432001-11-18 19:15:05 +0000342 res = write(f->fd, outbuf, outsize);
343 if(res == -1) {
344 /* ENOENT means the operation was interrupted */
345 if(errno != ENOENT)
Miklos Szeredi96249982001-11-21 12:21:19 +0000346 perror("fuse: writing device");
Miklos Szeredi43696432001-11-18 19:15:05 +0000347 }
348}
349
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000350static void send_reply(struct fuse *f, struct fuse_in_header *in, int error,
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000351 void *arg, size_t argsize)
352{
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000353 char *outbuf;
354 size_t outsize;
355 struct fuse_out_header *out;
356
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000357 if(error > 0) {
Miklos Szeredi96249982001-11-21 12:21:19 +0000358 fprintf(stderr, "fuse: positive error code: %i\n", error);
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000359 error = -ERANGE;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000360 }
361
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000362 if(error)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000363 argsize = 0;
364
365 outsize = sizeof(struct fuse_out_header) + argsize;
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000366 outbuf = (char *) malloc(outsize);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000367 out = (struct fuse_out_header *) outbuf;
368 out->unique = in->unique;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000369 out->error = error;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000370 if(argsize != 0)
371 memcpy(outbuf + sizeof(struct fuse_out_header), arg, argsize);
372
Miklos Szeredi43696432001-11-18 19:15:05 +0000373 send_reply_raw(f, outbuf, outsize);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000374
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000375 free(outbuf);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000376}
377
378static void do_lookup(struct fuse *f, struct fuse_in_header *in, char *name)
379{
380 int res;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000381 char *path;
382 struct stat buf;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000383 struct fuse_lookup_out arg;
384
Miklos Szeredi5e183482001-10-31 14:52:35 +0000385 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000386 path = get_path_name(f, in->ino, name);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000387 if(path != NULL) {
Miklos Szeredi6ebe2342002-01-06 21:44:16 +0000388 if(f->flags & FUSE_DEBUG) {
389 printf("LOOKUP %s\n", path);
390 fflush(stdout);
391 }
Miklos Szeredi5e183482001-10-31 14:52:35 +0000392 res = -ENOSYS;
393 if(f->op.getattr)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000394 res = f->op.getattr(path, &buf);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000395 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000396 }
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000397 if(res == 0) {
398 convert_stat(&buf, &arg.attr);
Miklos Szeredia181e612001-11-06 12:03:23 +0000399 arg.ino = find_node(f, in->ino, name, &arg.attr, in->unique);
Miklos Szeredi6ebe2342002-01-06 21:44:16 +0000400 if(f->flags & FUSE_DEBUG) {
401 printf(" LOOKUP: %li\n", arg.ino);
402 fflush(stdout);
403 }
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000404 }
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000405 send_reply(f, in, res, &arg, sizeof(arg));
406}
407
Miklos Szeredia181e612001-11-06 12:03:23 +0000408static void do_forget(struct fuse *f, struct fuse_in_header *in,
409 struct fuse_forget_in *arg)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000410{
Miklos Szeredi43696432001-11-18 19:15:05 +0000411 if(f->flags & FUSE_DEBUG) {
412 printf("FORGET %li/%i\n", in->ino, arg->version);
413 fflush(stdout);
414 }
Miklos Szeredia181e612001-11-06 12:03:23 +0000415 destroy_node(f, in->ino, arg->version);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000416}
417
418static void do_getattr(struct fuse *f, struct fuse_in_header *in)
419{
420 int res;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000421 char *path;
422 struct stat buf;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000423 struct fuse_getattr_out arg;
424
Miklos Szeredi5e183482001-10-31 14:52:35 +0000425 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000426 path = get_path(f, in->ino);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000427 if(path != NULL) {
428 res = -ENOSYS;
429 if(f->op.getattr)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000430 res = f->op.getattr(path, &buf);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000431 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000432 }
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000433 if(res == 0)
434 convert_stat(&buf, &arg.attr);
435
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000436 send_reply(f, in, res, &arg, sizeof(arg));
437}
438
Miklos Szeredi680a69a2001-11-16 13:31:14 +0000439static int do_chmod(struct fuse *f, const char *path, struct fuse_attr *attr)
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000440{
441 int res;
442
443 res = -ENOSYS;
444 if(f->op.chmod)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000445 res = f->op.chmod(path, attr->mode);
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000446
447 return res;
448}
449
Miklos Szeredi680a69a2001-11-16 13:31:14 +0000450static int do_chown(struct fuse *f, const char *path, struct fuse_attr *attr,
Miklos Szeredi2e50d432001-12-20 12:17:25 +0000451 int valid)
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000452{
453 int res;
454 uid_t uid = (valid & FATTR_UID) ? attr->uid : (uid_t) -1;
455 gid_t gid = (valid & FATTR_GID) ? attr->gid : (gid_t) -1;
456
457 res = -ENOSYS;
458 if(f->op.chown)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000459 res = f->op.chown(path, uid, gid);
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000460
461 return res;
462}
463
Miklos Szeredi680a69a2001-11-16 13:31:14 +0000464static int do_truncate(struct fuse *f, const char *path,
465 struct fuse_attr *attr)
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000466{
467 int res;
468
469 res = -ENOSYS;
470 if(f->op.truncate)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000471 res = f->op.truncate(path, attr->size);
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000472
473 return res;
474}
475
Miklos Szeredi680a69a2001-11-16 13:31:14 +0000476static int do_utime(struct fuse *f, const char *path, struct fuse_attr *attr)
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000477{
478 int res;
479 struct utimbuf buf;
480 buf.actime = attr->atime;
481 buf.modtime = attr->mtime;
482 res = -ENOSYS;
483 if(f->op.utime)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000484 res = f->op.utime(path, &buf);
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000485
486 return res;
487}
488
Miklos Szeredi5e183482001-10-31 14:52:35 +0000489static void do_setattr(struct fuse *f, struct fuse_in_header *in,
490 struct fuse_setattr_in *arg)
491{
492 int res;
493 char *path;
494 int valid = arg->valid;
495 struct fuse_attr *attr = &arg->attr;
Miklos Szeredia181e612001-11-06 12:03:23 +0000496 struct fuse_setattr_out outarg;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000497
498 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000499 path = get_path(f, in->ino);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000500 if(path != NULL) {
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000501 res = -ENOSYS;
502 if(f->op.getattr) {
503 res = 0;
504 if(!res && (valid & FATTR_MODE))
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000505 res = do_chmod(f, path, attr);
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000506 if(!res && (valid & (FATTR_UID | FATTR_GID)))
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000507 res = do_chown(f, path, attr, valid);
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000508 if(!res && (valid & FATTR_SIZE))
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000509 res = do_truncate(f, path, attr);
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000510 if(!res && (valid & FATTR_UTIME))
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000511 res = do_utime(f, path, attr);
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000512 if(!res) {
513 struct stat buf;
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000514 res = f->op.getattr(path, &buf);
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000515 if(!res)
516 convert_stat(&buf, &outarg.attr);
Miklos Szeredia181e612001-11-06 12:03:23 +0000517 }
Miklos Szeredi5e183482001-10-31 14:52:35 +0000518 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000519 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000520 }
Miklos Szeredia181e612001-11-06 12:03:23 +0000521 send_reply(f, in, res, &outarg, sizeof(outarg));
Miklos Szeredi5e183482001-10-31 14:52:35 +0000522}
523
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000524static void do_readlink(struct fuse *f, struct fuse_in_header *in)
525{
526 int res;
527 char link[PATH_MAX + 1];
Miklos Szeredib483c932001-10-29 14:57:57 +0000528 char *path;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000529
Miklos Szeredi5e183482001-10-31 14:52:35 +0000530 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000531 path = get_path(f, in->ino);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000532 if(path != NULL) {
533 res = -ENOSYS;
534 if(f->op.readlink)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000535 res = f->op.readlink(path, link, sizeof(link));
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000536 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000537 }
Miklos Szeredi2df1c042001-11-06 15:07:17 +0000538 link[PATH_MAX] = '\0';
Miklos Szeredi4b2bef42002-01-09 12:23:27 +0000539 send_reply(f, in, res, link, res == 0 ? strlen(link) : 0);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000540}
541
542static void do_getdir(struct fuse *f, struct fuse_in_header *in)
543{
544 int res;
545 struct fuse_getdir_out arg;
Miklos Szeredia181e612001-11-06 12:03:23 +0000546 struct fuse_dirhandle dh;
Miklos Szeredib483c932001-10-29 14:57:57 +0000547 char *path;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000548
Miklos Szeredib483c932001-10-29 14:57:57 +0000549 dh.fuse = f;
550 dh.fp = tmpfile();
551 dh.dir = in->ino;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000552 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000553 path = get_path(f, in->ino);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000554 if(path != NULL) {
555 res = -ENOSYS;
556 if(f->op.getdir)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000557 res = f->op.getdir(path, &dh, (fuse_dirfil_t) fill_dir);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000558 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000559 }
Miklos Szeredib483c932001-10-29 14:57:57 +0000560 fflush(dh.fp);
561 arg.fd = fileno(dh.fp);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000562 send_reply(f, in, res, &arg, sizeof(arg));
Miklos Szeredib483c932001-10-29 14:57:57 +0000563 fclose(dh.fp);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000564}
565
Miklos Szeredib483c932001-10-29 14:57:57 +0000566static void do_mknod(struct fuse *f, struct fuse_in_header *in,
567 struct fuse_mknod_in *inarg)
568{
569 int res;
570 char *path;
571 struct fuse_mknod_out outarg;
572 struct stat buf;
573
Miklos Szeredi5e183482001-10-31 14:52:35 +0000574 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000575 path = get_path_name(f, in->ino, inarg->name);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000576 if(path != NULL) {
577 res = -ENOSYS;
578 if(f->op.mknod && f->op.getattr) {
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000579 res = f->op.mknod(path, inarg->mode, inarg->rdev);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000580 if(res == 0)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000581 res = f->op.getattr(path, &buf);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000582 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000583 free(path);
Miklos Szeredib483c932001-10-29 14:57:57 +0000584 }
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000585 if(res == 0) {
Miklos Szeredib483c932001-10-29 14:57:57 +0000586 convert_stat(&buf, &outarg.attr);
Miklos Szeredia181e612001-11-06 12:03:23 +0000587 outarg.ino = find_node(f, in->ino, inarg->name, &outarg.attr,
588 in->unique);
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000589 }
Miklos Szeredib483c932001-10-29 14:57:57 +0000590
591 send_reply(f, in, res, &outarg, sizeof(outarg));
592}
593
594static void do_mkdir(struct fuse *f, struct fuse_in_header *in,
595 struct fuse_mkdir_in *inarg)
596{
597 int res;
598 char *path;
599
Miklos Szeredi5e183482001-10-31 14:52:35 +0000600 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000601 path = get_path_name(f, in->ino, inarg->name);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000602 if(path != NULL) {
603 res = -ENOSYS;
604 if(f->op.mkdir)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000605 res = f->op.mkdir(path, inarg->mode);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000606 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000607 }
Miklos Szeredib483c932001-10-29 14:57:57 +0000608 send_reply(f, in, res, NULL, 0);
609}
610
611static void do_remove(struct fuse *f, struct fuse_in_header *in, char *name)
612{
613 int res;
614 char *path;
615
Miklos Szeredi5e183482001-10-31 14:52:35 +0000616 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000617 path = get_path_name(f, in->ino, name);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000618 if(path != NULL) {
619 res = -ENOSYS;
620 if(in->opcode == FUSE_UNLINK) {
621 if(f->op.unlink)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000622 res = f->op.unlink(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000623 }
624 else {
625 if(f->op.rmdir)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000626 res = f->op.rmdir(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000627 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000628 free(path);
Miklos Szeredib483c932001-10-29 14:57:57 +0000629 }
Miklos Szeredi5e183482001-10-31 14:52:35 +0000630 if(res == 0)
631 remove_node(f, in->ino, name);
Miklos Szeredib483c932001-10-29 14:57:57 +0000632 send_reply(f, in, res, NULL, 0);
633}
634
635static void do_symlink(struct fuse *f, struct fuse_in_header *in, char *name,
636 char *link)
637{
638 int res;
639 char *path;
640
Miklos Szeredi5e183482001-10-31 14:52:35 +0000641 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000642 path = get_path_name(f, in->ino, name);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000643 if(path != NULL) {
644 res = -ENOSYS;
645 if(f->op.symlink)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000646 res = f->op.symlink(link, path);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000647 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000648 }
Miklos Szeredib483c932001-10-29 14:57:57 +0000649 send_reply(f, in, res, NULL, 0);
650}
651
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000652static void do_rename(struct fuse *f, struct fuse_in_header *in,
653 struct fuse_rename_in *inarg)
654{
655 int res;
656 fino_t olddir = in->ino;
657 fino_t newdir = inarg->newdir;
658 char *oldname = inarg->names;
659 char *newname = inarg->names + strlen(oldname) + 1;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000660 char *oldpath;
661 char *newpath;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000662
Miklos Szeredi5e183482001-10-31 14:52:35 +0000663 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000664 oldpath = get_path_name(f, olddir, oldname);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000665 if(oldpath != NULL) {
Miklos Szeredia181e612001-11-06 12:03:23 +0000666 newpath = get_path_name(f, newdir, newname);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000667 if(newpath != NULL) {
668 res = -ENOSYS;
669 if(f->op.rename)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000670 res = f->op.rename(oldpath, newpath);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000671 if(res == 0)
672 rename_node(f, olddir, oldname, newdir, newname);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000673 free(newpath);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000674 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000675 free(oldpath);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000676 }
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000677 send_reply(f, in, res, NULL, 0);
678}
679
680static void do_link(struct fuse *f, struct fuse_in_header *in,
Miklos Szeredi5e183482001-10-31 14:52:35 +0000681 struct fuse_link_in *arg)
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000682{
683 int res;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000684 char *oldpath;
685 char *newpath;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000686
Miklos Szeredi5e183482001-10-31 14:52:35 +0000687 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000688 oldpath = get_path(f, in->ino);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000689 if(oldpath != NULL) {
Miklos Szeredia181e612001-11-06 12:03:23 +0000690 newpath = get_path_name(f, arg->newdir, arg->name);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000691 if(newpath != NULL) {
692 res = -ENOSYS;
693 if(f->op.link)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000694 res = f->op.link(oldpath, newpath);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000695 free(newpath);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000696 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000697 free(oldpath);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000698 }
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000699 send_reply(f, in, res, NULL, 0);
700}
701
Miklos Szeredi5e183482001-10-31 14:52:35 +0000702static void do_open(struct fuse *f, struct fuse_in_header *in,
703 struct fuse_open_in *arg)
704{
705 int res;
706 char *path;
707
708 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000709 path = get_path(f, in->ino);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000710 if(path != NULL) {
711 res = -ENOSYS;
712 if(f->op.open)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000713 res = f->op.open(path, arg->flags);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000714 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000715 }
716 send_reply(f, in, res, NULL, 0);
717}
718
719static void do_read(struct fuse *f, struct fuse_in_header *in,
720 struct fuse_read_in *arg)
721{
722 int res;
723 char *path;
Miklos Szeredi43696432001-11-18 19:15:05 +0000724 char *outbuf = (char *) malloc(sizeof(struct fuse_out_header) + arg->size);
725 struct fuse_out_header *out = (struct fuse_out_header *) outbuf;
726 char *buf = outbuf + sizeof(struct fuse_out_header);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000727 size_t size;
Miklos Szeredi43696432001-11-18 19:15:05 +0000728 size_t outsize;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000729
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000730 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000731 path = get_path(f, in->ino);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000732 if(path != NULL) {
Miklos Szeredi6ebe2342002-01-06 21:44:16 +0000733 if(f->flags & FUSE_DEBUG) {
734 printf("READ %u bytes from %llu\n", arg->size, arg->offset);
735 fflush(stdout);
736 }
737
Miklos Szeredi5e183482001-10-31 14:52:35 +0000738 res = -ENOSYS;
Miklos Szeredia181e612001-11-06 12:03:23 +0000739 if(f->op.read)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000740 res = f->op.read(path, buf, arg->size, arg->offset);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000741 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000742 }
743
744 size = 0;
745 if(res > 0) {
746 size = res;
747 res = 0;
Miklos Szeredi6ebe2342002-01-06 21:44:16 +0000748 if(f->flags & FUSE_DEBUG) {
749 printf(" READ %u bytes\n", size);
750 fflush(stdout);
751 }
Miklos Szeredi5e183482001-10-31 14:52:35 +0000752 }
Miklos Szeredi43696432001-11-18 19:15:05 +0000753 out->unique = in->unique;
754 out->error = res;
755 outsize = sizeof(struct fuse_out_header) + size;
756
757 send_reply_raw(f, outbuf, outsize);
758 free(outbuf);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000759}
Miklos Szeredib483c932001-10-29 14:57:57 +0000760
Miklos Szeredia181e612001-11-06 12:03:23 +0000761static void do_write(struct fuse *f, struct fuse_in_header *in,
762 struct fuse_write_in *arg)
763{
764 int res;
765 char *path;
Miklos Szeredia181e612001-11-06 12:03:23 +0000766
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000767 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000768 path = get_path(f, in->ino);
769 if(path != NULL) {
Miklos Szeredi6ebe2342002-01-06 21:44:16 +0000770 if(f->flags & FUSE_DEBUG) {
771 printf("WRITE %u bytes to %llu\n", arg->size, arg->offset);
772 fflush(stdout);
773 }
774
Miklos Szeredia181e612001-11-06 12:03:23 +0000775 res = -ENOSYS;
776 if(f->op.write)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000777 res = f->op.write(path, arg->buf, arg->size, arg->offset);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000778 free(path);
Miklos Szeredia181e612001-11-06 12:03:23 +0000779 }
780
781 if(res > 0) {
782 if((size_t) res != arg->size) {
783 fprintf(stderr, "short write: %u (should be %u)\n", res,
784 arg->size);
785 res = -EIO;
786 }
787 else
788 res = 0;
789 }
790
791 send_reply(f, in, res, NULL, 0);
792}
793
Mark Glinesd84b39a2002-01-07 16:32:02 +0000794static void do_statfs(struct fuse *f, struct fuse_in_header *in)
795{
796 int res;
Mark Glinesd84b39a2002-01-07 16:32:02 +0000797 struct fuse_statfs_out arg;
798
799 res = -ENOSYS;
800 if(f->op.statfs)
Miklos Szeredi24ed9452002-10-07 10:24:26 +0000801 res = f->op.statfs((struct fuse_statfs *) &arg.st);
Miklos Szeredi4b2bef42002-01-09 12:23:27 +0000802
Mark Glinesd84b39a2002-01-07 16:32:02 +0000803 send_reply(f, in, res, &arg, sizeof(arg));
804}
805
Miklos Szeredi43696432001-11-18 19:15:05 +0000806static void free_cmd(struct fuse_cmd *cmd)
807{
808 free(cmd->buf);
809 free(cmd);
810}
811
Miklos Szeredifff56ab2001-11-16 10:12:59 +0000812void __fuse_process_cmd(struct fuse *f, struct fuse_cmd *cmd)
Miklos Szeredia181e612001-11-06 12:03:23 +0000813{
Miklos Szeredia181e612001-11-06 12:03:23 +0000814 struct fuse_in_header *in = (struct fuse_in_header *) cmd->buf;
815 void *inarg = cmd->buf + sizeof(struct fuse_in_header);
816 size_t argsize;
Miklos Szeredife25def2001-12-20 15:38:05 +0000817 struct fuse_context *ctx = fuse_get_context(f);
Miklos Szeredia181e612001-11-06 12:03:23 +0000818
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +0000819 dec_avail(f);
Miklos Szeredi33232032001-11-19 17:55:51 +0000820
Miklos Szeredic0938ea2001-11-07 12:35:06 +0000821 if((f->flags & FUSE_DEBUG)) {
822 printf("unique: %i, opcode: %i, ino: %li, insize: %i\n", in->unique,
823 in->opcode, in->ino, cmd->buflen);
824 fflush(stdout);
825 }
Miklos Szeredife25def2001-12-20 15:38:05 +0000826
827 ctx->uid = in->uid;
828 ctx->gid = in->gid;
Miklos Szeredia181e612001-11-06 12:03:23 +0000829
830 argsize = cmd->buflen - sizeof(struct fuse_in_header);
831
832 switch(in->opcode) {
833 case FUSE_LOOKUP:
834 do_lookup(f, in, (char *) inarg);
835 break;
836
Miklos Szeredia181e612001-11-06 12:03:23 +0000837 case FUSE_GETATTR:
838 do_getattr(f, in);
839 break;
840
841 case FUSE_SETATTR:
842 do_setattr(f, in, (struct fuse_setattr_in *) inarg);
843 break;
844
845 case FUSE_READLINK:
846 do_readlink(f, in);
847 break;
848
849 case FUSE_GETDIR:
850 do_getdir(f, in);
851 break;
852
853 case FUSE_MKNOD:
854 do_mknod(f, in, (struct fuse_mknod_in *) inarg);
855 break;
856
857 case FUSE_MKDIR:
858 do_mkdir(f, in, (struct fuse_mkdir_in *) inarg);
859 break;
860
861 case FUSE_UNLINK:
862 case FUSE_RMDIR:
863 do_remove(f, in, (char *) inarg);
864 break;
865
866 case FUSE_SYMLINK:
867 do_symlink(f, in, (char *) inarg,
868 ((char *) inarg) + strlen((char *) inarg) + 1);
869 break;
870
871 case FUSE_RENAME:
872 do_rename(f, in, (struct fuse_rename_in *) inarg);
873 break;
874
875 case FUSE_LINK:
876 do_link(f, in, (struct fuse_link_in *) inarg);
877 break;
878
879 case FUSE_OPEN:
880 do_open(f, in, (struct fuse_open_in *) inarg);
881 break;
882
883 case FUSE_READ:
884 do_read(f, in, (struct fuse_read_in *) inarg);
885 break;
886
887 case FUSE_WRITE:
888 do_write(f, in, (struct fuse_write_in *) inarg);
889 break;
890
Mark Glinesd84b39a2002-01-07 16:32:02 +0000891 case FUSE_STATFS:
892 do_statfs(f, in);
893 break;
894
Miklos Szeredia181e612001-11-06 12:03:23 +0000895 default:
896 fprintf(stderr, "Operation %i not implemented\n", in->opcode);
Miklos Szeredi43696432001-11-18 19:15:05 +0000897 send_reply(f, in, -ENOSYS, NULL, 0);
Miklos Szeredia181e612001-11-06 12:03:23 +0000898 }
Miklos Szeredi43696432001-11-18 19:15:05 +0000899
900 free_cmd(cmd);
Miklos Szeredia181e612001-11-06 12:03:23 +0000901}
902
Miklos Szeredifff56ab2001-11-16 10:12:59 +0000903struct fuse_cmd *__fuse_read_cmd(struct fuse *f)
Miklos Szeredi2df1c042001-11-06 15:07:17 +0000904{
Miklos Szeredifff56ab2001-11-16 10:12:59 +0000905 ssize_t res;
Miklos Szeredifff56ab2001-11-16 10:12:59 +0000906 struct fuse_cmd *cmd;
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +0000907 struct fuse_in_header *in;
908 void *inarg;
Miklos Szeredifff56ab2001-11-16 10:12:59 +0000909
Miklos Szeredi43696432001-11-18 19:15:05 +0000910 cmd = (struct fuse_cmd *) malloc(sizeof(struct fuse_cmd));
911 cmd->buf = (char *) malloc(FUSE_MAX_IN);
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +0000912 in = (struct fuse_in_header *) cmd->buf;
913 inarg = cmd->buf + sizeof(struct fuse_in_header);
Miklos Szeredi43696432001-11-18 19:15:05 +0000914
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +0000915 do {
916 res = read(f->fd, cmd->buf, FUSE_MAX_IN);
917 if(res == -1) {
918 /* ENODEV means we got unmounted, so we silenty return failure */
919 if(errno != ENODEV) {
920 perror("fuse: reading device");
921 /* BAD... This will happen again */
922 }
923 free_cmd(cmd);
924 return NULL;
Miklos Szeredi96249982001-11-21 12:21:19 +0000925 }
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +0000926 if((size_t) res < sizeof(struct fuse_in_header)) {
927 fprintf(stderr, "short read on fuse device\n");
928 /* Cannot happen */
929 free_cmd(cmd);
930 return NULL;
931 }
932 cmd->buflen = res;
933
934 /* Forget is special, it can be done without messing with threads. */
935 if(in->opcode == FUSE_FORGET)
936 do_forget(f, in, (struct fuse_forget_in *) inarg);
937
938 } while(in->opcode == FUSE_FORGET);
939
Miklos Szeredifff56ab2001-11-16 10:12:59 +0000940 return cmd;
Miklos Szeredi2df1c042001-11-06 15:07:17 +0000941}
942
Miklos Szeredifff56ab2001-11-16 10:12:59 +0000943
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000944void fuse_loop(struct fuse *f)
945{
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000946 while(1) {
Miklos Szeredifff56ab2001-11-16 10:12:59 +0000947 struct fuse_cmd *cmd = __fuse_read_cmd(f);
948 if(cmd == NULL)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000949 exit(1);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000950
Miklos Szeredifff56ab2001-11-16 10:12:59 +0000951 __fuse_process_cmd(f, cmd);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000952 }
953}
954
Miklos Szeredi2e50d432001-12-20 12:17:25 +0000955struct fuse_context *fuse_get_context(struct fuse *f)
956{
957 if(f->getcontext)
958 return f->getcontext(f);
959 else
960 return &f->context;
961}
962
963struct fuse *fuse_new(int fd, int flags, const struct fuse_operations *op)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000964{
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000965 struct fuse *f;
966 struct node *root;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000967
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000968 f = (struct fuse *) calloc(1, sizeof(struct fuse));
Miklos Szeredi2df1c042001-11-06 15:07:17 +0000969
Miklos Szeredia181e612001-11-06 12:03:23 +0000970 f->flags = flags;
Miklos Szeredi8cffdb92001-11-09 14:49:18 +0000971 f->fd = fd;
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000972 f->ctr = 0;
Miklos Szeredifff56ab2001-11-16 10:12:59 +0000973 /* FIXME: Dynamic hash table */
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000974 f->name_table_size = 14057;
975 f->name_table = (struct node **)
976 calloc(1, sizeof(struct node *) * f->name_table_size);
977 f->ino_table_size = 14057;
978 f->ino_table = (struct node **)
979 calloc(1, sizeof(struct node *) * f->ino_table_size);
Miklos Szeredia181e612001-11-06 12:03:23 +0000980 pthread_mutex_init(&f->lock, NULL);
Miklos Szeredi33232032001-11-19 17:55:51 +0000981 f->numworker = 0;
982 f->numavail = 0;
Miklos Szeredi2e50d432001-12-20 12:17:25 +0000983 f->op = *op;
984 f->getcontext = NULL;
985 f->context.uid = 0;
986 f->context.gid = 0;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000987
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000988 root = (struct node *) calloc(1, sizeof(struct node));
Miklos Szeredi8cffdb92001-11-09 14:49:18 +0000989 root->mode = 0;
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000990 root->rdev = 0;
991 root->name = strdup("/");
992 root->parent = 0;
993 hash_ino(f, root, FUSE_ROOT_INO);
994
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000995 return f;
996}
997
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000998void fuse_destroy(struct fuse *f)
999{
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001000 size_t i;
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001001 for(i = 0; i < f->ino_table_size; i++) {
1002 struct node *node;
1003 struct node *next;
1004 for(node = f->ino_table[i]; node != NULL; node = next) {
1005 next = node->ino_next;
1006 free_node(node);
1007 }
1008 }
1009 free(f->ino_table);
1010 free(f->name_table);
Miklos Szeredia181e612001-11-06 12:03:23 +00001011 pthread_mutex_destroy(&f->lock);
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001012 free(f);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001013}