blob: 98bab3f4cd3fc73b8af51f00a6aeb6ad5107df5d [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
Miklos Szeredia181e612001-11-06 12:03:23 +0000309static int fill_dir(struct fuse_dirhandle *dh, char *name, int type)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000310{
311 struct fuse_dirent dirent;
312 size_t reclen;
313 size_t res;
314
Miklos Szeredi43696432001-11-18 19:15:05 +0000315 dirent.ino = (unsigned long) -1;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000316 dirent.namelen = strlen(name);
317 strncpy(dirent.name, name, sizeof(dirent.name));
318 dirent.type = type;
319 reclen = FUSE_DIRENT_SIZE(&dirent);
320 res = fwrite(&dirent, reclen, 1, dh->fp);
321 if(res == 0) {
Miklos Szeredi96249982001-11-21 12:21:19 +0000322 perror("fuse: writing directory file");
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000323 return -EIO;
324 }
325 return 0;
326}
327
Miklos Szeredi43696432001-11-18 19:15:05 +0000328static void send_reply_raw(struct fuse *f, char *outbuf, size_t outsize)
329{
330 int res;
331
332 if((f->flags & FUSE_DEBUG)) {
333 struct fuse_out_header *out = (struct fuse_out_header *) outbuf;
334 printf(" unique: %i, error: %i (%s), outsize: %i\n", out->unique,
335 out->error, strerror(-out->error), outsize);
336 fflush(stdout);
337 }
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +0000338
339 /* This needs to be done before the reply because otherwise the
340 scheduler can tricks with us, and only let the counter be increased
341 long after the operation is done */
342 inc_avail(f);
343
Miklos Szeredi43696432001-11-18 19:15:05 +0000344 res = write(f->fd, outbuf, outsize);
345 if(res == -1) {
346 /* ENOENT means the operation was interrupted */
347 if(errno != ENOENT)
Miklos Szeredi96249982001-11-21 12:21:19 +0000348 perror("fuse: writing device");
Miklos Szeredi43696432001-11-18 19:15:05 +0000349 }
350}
351
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000352static void send_reply(struct fuse *f, struct fuse_in_header *in, int error,
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000353 void *arg, size_t argsize)
354{
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000355 char *outbuf;
356 size_t outsize;
357 struct fuse_out_header *out;
358
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000359 if(error > 0) {
Miklos Szeredi96249982001-11-21 12:21:19 +0000360 fprintf(stderr, "fuse: positive error code: %i\n", error);
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000361 error = -ERANGE;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000362 }
363
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000364 if(error)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000365 argsize = 0;
366
367 outsize = sizeof(struct fuse_out_header) + argsize;
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000368 outbuf = (char *) malloc(outsize);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000369 out = (struct fuse_out_header *) outbuf;
370 out->unique = in->unique;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000371 out->error = error;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000372 if(argsize != 0)
373 memcpy(outbuf + sizeof(struct fuse_out_header), arg, argsize);
374
Miklos Szeredi43696432001-11-18 19:15:05 +0000375 send_reply_raw(f, outbuf, outsize);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000376
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000377 free(outbuf);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000378}
379
380static void do_lookup(struct fuse *f, struct fuse_in_header *in, char *name)
381{
382 int res;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000383 char *path;
384 struct stat buf;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000385 struct fuse_lookup_out arg;
386
Miklos Szeredi5e183482001-10-31 14:52:35 +0000387 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000388 path = get_path_name(f, in->ino, name);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000389 if(path != NULL) {
Miklos Szeredi6ebe2342002-01-06 21:44:16 +0000390 if(f->flags & FUSE_DEBUG) {
391 printf("LOOKUP %s\n", path);
392 fflush(stdout);
393 }
Miklos Szeredi5e183482001-10-31 14:52:35 +0000394 res = -ENOSYS;
395 if(f->op.getattr)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000396 res = f->op.getattr(path, &buf);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000397 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000398 }
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000399 if(res == 0) {
400 convert_stat(&buf, &arg.attr);
Miklos Szeredia181e612001-11-06 12:03:23 +0000401 arg.ino = find_node(f, in->ino, name, &arg.attr, in->unique);
Miklos Szeredi6ebe2342002-01-06 21:44:16 +0000402 if(f->flags & FUSE_DEBUG) {
403 printf(" LOOKUP: %li\n", arg.ino);
404 fflush(stdout);
405 }
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000406 }
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000407 send_reply(f, in, res, &arg, sizeof(arg));
408}
409
Miklos Szeredia181e612001-11-06 12:03:23 +0000410static void do_forget(struct fuse *f, struct fuse_in_header *in,
411 struct fuse_forget_in *arg)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000412{
Miklos Szeredi43696432001-11-18 19:15:05 +0000413 if(f->flags & FUSE_DEBUG) {
414 printf("FORGET %li/%i\n", in->ino, arg->version);
415 fflush(stdout);
416 }
Miklos Szeredia181e612001-11-06 12:03:23 +0000417 destroy_node(f, in->ino, arg->version);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000418}
419
420static void do_getattr(struct fuse *f, struct fuse_in_header *in)
421{
422 int res;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000423 char *path;
424 struct stat buf;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000425 struct fuse_getattr_out arg;
426
Miklos Szeredi5e183482001-10-31 14:52:35 +0000427 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000428 path = get_path(f, in->ino);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000429 if(path != NULL) {
430 res = -ENOSYS;
431 if(f->op.getattr)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000432 res = f->op.getattr(path, &buf);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000433 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000434 }
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000435 if(res == 0)
436 convert_stat(&buf, &arg.attr);
437
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000438 send_reply(f, in, res, &arg, sizeof(arg));
439}
440
Miklos Szeredi680a69a2001-11-16 13:31:14 +0000441static int do_chmod(struct fuse *f, const char *path, struct fuse_attr *attr)
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000442{
443 int res;
444
445 res = -ENOSYS;
446 if(f->op.chmod)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000447 res = f->op.chmod(path, attr->mode);
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000448
449 return res;
450}
451
Miklos Szeredi680a69a2001-11-16 13:31:14 +0000452static int do_chown(struct fuse *f, const char *path, struct fuse_attr *attr,
Miklos Szeredi2e50d432001-12-20 12:17:25 +0000453 int valid)
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000454{
455 int res;
456 uid_t uid = (valid & FATTR_UID) ? attr->uid : (uid_t) -1;
457 gid_t gid = (valid & FATTR_GID) ? attr->gid : (gid_t) -1;
458
459 res = -ENOSYS;
460 if(f->op.chown)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000461 res = f->op.chown(path, uid, gid);
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000462
463 return res;
464}
465
Miklos Szeredi680a69a2001-11-16 13:31:14 +0000466static int do_truncate(struct fuse *f, const char *path,
467 struct fuse_attr *attr)
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000468{
469 int res;
470
471 res = -ENOSYS;
472 if(f->op.truncate)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000473 res = f->op.truncate(path, attr->size);
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000474
475 return res;
476}
477
Miklos Szeredi680a69a2001-11-16 13:31:14 +0000478static int do_utime(struct fuse *f, const char *path, struct fuse_attr *attr)
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000479{
480 int res;
481 struct utimbuf buf;
482 buf.actime = attr->atime;
483 buf.modtime = attr->mtime;
484 res = -ENOSYS;
485 if(f->op.utime)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000486 res = f->op.utime(path, &buf);
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000487
488 return res;
489}
490
Miklos Szeredi5e183482001-10-31 14:52:35 +0000491static void do_setattr(struct fuse *f, struct fuse_in_header *in,
492 struct fuse_setattr_in *arg)
493{
494 int res;
495 char *path;
496 int valid = arg->valid;
497 struct fuse_attr *attr = &arg->attr;
Miklos Szeredia181e612001-11-06 12:03:23 +0000498 struct fuse_setattr_out outarg;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000499
500 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000501 path = get_path(f, in->ino);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000502 if(path != NULL) {
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000503 res = -ENOSYS;
504 if(f->op.getattr) {
505 res = 0;
506 if(!res && (valid & FATTR_MODE))
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000507 res = do_chmod(f, path, attr);
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000508 if(!res && (valid & (FATTR_UID | FATTR_GID)))
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000509 res = do_chown(f, path, attr, valid);
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000510 if(!res && (valid & FATTR_SIZE))
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000511 res = do_truncate(f, path, attr);
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000512 if(!res && (valid & FATTR_UTIME))
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000513 res = do_utime(f, path, attr);
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000514 if(!res) {
515 struct stat buf;
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000516 res = f->op.getattr(path, &buf);
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000517 if(!res)
518 convert_stat(&buf, &outarg.attr);
Miklos Szeredia181e612001-11-06 12:03:23 +0000519 }
Miklos Szeredi5e183482001-10-31 14:52:35 +0000520 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000521 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000522 }
Miklos Szeredia181e612001-11-06 12:03:23 +0000523 send_reply(f, in, res, &outarg, sizeof(outarg));
Miklos Szeredi5e183482001-10-31 14:52:35 +0000524}
525
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000526static void do_readlink(struct fuse *f, struct fuse_in_header *in)
527{
528 int res;
529 char link[PATH_MAX + 1];
Miklos Szeredib483c932001-10-29 14:57:57 +0000530 char *path;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000531
Miklos Szeredi5e183482001-10-31 14:52:35 +0000532 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000533 path = get_path(f, in->ino);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000534 if(path != NULL) {
535 res = -ENOSYS;
536 if(f->op.readlink)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000537 res = f->op.readlink(path, link, sizeof(link));
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000538 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000539 }
Miklos Szeredi2df1c042001-11-06 15:07:17 +0000540 link[PATH_MAX] = '\0';
Miklos Szeredi5e183482001-10-31 14:52:35 +0000541 send_reply(f, in, res, link, !res ? strlen(link) : 0);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000542}
543
544static void do_getdir(struct fuse *f, struct fuse_in_header *in)
545{
546 int res;
547 struct fuse_getdir_out arg;
Miklos Szeredia181e612001-11-06 12:03:23 +0000548 struct fuse_dirhandle dh;
Miklos Szeredib483c932001-10-29 14:57:57 +0000549 char *path;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000550
Miklos Szeredib483c932001-10-29 14:57:57 +0000551 dh.fuse = f;
552 dh.fp = tmpfile();
553 dh.dir = in->ino;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000554 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000555 path = get_path(f, in->ino);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000556 if(path != NULL) {
557 res = -ENOSYS;
558 if(f->op.getdir)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000559 res = f->op.getdir(path, &dh, (fuse_dirfil_t) fill_dir);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000560 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000561 }
Miklos Szeredib483c932001-10-29 14:57:57 +0000562 fflush(dh.fp);
563 arg.fd = fileno(dh.fp);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000564 send_reply(f, in, res, &arg, sizeof(arg));
Miklos Szeredib483c932001-10-29 14:57:57 +0000565 fclose(dh.fp);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000566}
567
Miklos Szeredib483c932001-10-29 14:57:57 +0000568static void do_mknod(struct fuse *f, struct fuse_in_header *in,
569 struct fuse_mknod_in *inarg)
570{
571 int res;
572 char *path;
573 struct fuse_mknod_out outarg;
574 struct stat buf;
575
Miklos Szeredi5e183482001-10-31 14:52:35 +0000576 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000577 path = get_path_name(f, in->ino, inarg->name);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000578 if(path != NULL) {
579 res = -ENOSYS;
580 if(f->op.mknod && f->op.getattr) {
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000581 res = f->op.mknod(path, inarg->mode, inarg->rdev);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000582 if(res == 0)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000583 res = f->op.getattr(path, &buf);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000584 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000585 free(path);
Miklos Szeredib483c932001-10-29 14:57:57 +0000586 }
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000587 if(res == 0) {
Miklos Szeredib483c932001-10-29 14:57:57 +0000588 convert_stat(&buf, &outarg.attr);
Miklos Szeredia181e612001-11-06 12:03:23 +0000589 outarg.ino = find_node(f, in->ino, inarg->name, &outarg.attr,
590 in->unique);
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000591 }
Miklos Szeredib483c932001-10-29 14:57:57 +0000592
593 send_reply(f, in, res, &outarg, sizeof(outarg));
594}
595
596static void do_mkdir(struct fuse *f, struct fuse_in_header *in,
597 struct fuse_mkdir_in *inarg)
598{
599 int res;
600 char *path;
601
Miklos Szeredi5e183482001-10-31 14:52:35 +0000602 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000603 path = get_path_name(f, in->ino, inarg->name);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000604 if(path != NULL) {
605 res = -ENOSYS;
606 if(f->op.mkdir)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000607 res = f->op.mkdir(path, inarg->mode);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000608 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000609 }
Miklos Szeredib483c932001-10-29 14:57:57 +0000610 send_reply(f, in, res, NULL, 0);
611}
612
613static void do_remove(struct fuse *f, struct fuse_in_header *in, char *name)
614{
615 int res;
616 char *path;
617
Miklos Szeredi5e183482001-10-31 14:52:35 +0000618 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000619 path = get_path_name(f, in->ino, name);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000620 if(path != NULL) {
621 res = -ENOSYS;
622 if(in->opcode == FUSE_UNLINK) {
623 if(f->op.unlink)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000624 res = f->op.unlink(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000625 }
626 else {
627 if(f->op.rmdir)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000628 res = f->op.rmdir(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000629 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000630 free(path);
Miklos Szeredib483c932001-10-29 14:57:57 +0000631 }
Miklos Szeredi5e183482001-10-31 14:52:35 +0000632 if(res == 0)
633 remove_node(f, in->ino, name);
Miklos Szeredib483c932001-10-29 14:57:57 +0000634 send_reply(f, in, res, NULL, 0);
635}
636
637static void do_symlink(struct fuse *f, struct fuse_in_header *in, char *name,
638 char *link)
639{
640 int res;
641 char *path;
642
Miklos Szeredi5e183482001-10-31 14:52:35 +0000643 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000644 path = get_path_name(f, in->ino, name);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000645 if(path != NULL) {
646 res = -ENOSYS;
647 if(f->op.symlink)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000648 res = f->op.symlink(link, path);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000649 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000650 }
Miklos Szeredib483c932001-10-29 14:57:57 +0000651 send_reply(f, in, res, NULL, 0);
652}
653
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000654static void do_rename(struct fuse *f, struct fuse_in_header *in,
655 struct fuse_rename_in *inarg)
656{
657 int res;
658 fino_t olddir = in->ino;
659 fino_t newdir = inarg->newdir;
660 char *oldname = inarg->names;
661 char *newname = inarg->names + strlen(oldname) + 1;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000662 char *oldpath;
663 char *newpath;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000664
Miklos Szeredi5e183482001-10-31 14:52:35 +0000665 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000666 oldpath = get_path_name(f, olddir, oldname);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000667 if(oldpath != NULL) {
Miklos Szeredia181e612001-11-06 12:03:23 +0000668 newpath = get_path_name(f, newdir, newname);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000669 if(newpath != NULL) {
670 res = -ENOSYS;
671 if(f->op.rename)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000672 res = f->op.rename(oldpath, newpath);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000673 if(res == 0)
674 rename_node(f, olddir, oldname, newdir, newname);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000675 free(newpath);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000676 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000677 free(oldpath);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000678 }
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000679 send_reply(f, in, res, NULL, 0);
680}
681
682static void do_link(struct fuse *f, struct fuse_in_header *in,
Miklos Szeredi5e183482001-10-31 14:52:35 +0000683 struct fuse_link_in *arg)
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000684{
685 int res;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000686 char *oldpath;
687 char *newpath;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000688
Miklos Szeredi5e183482001-10-31 14:52:35 +0000689 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000690 oldpath = get_path(f, in->ino);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000691 if(oldpath != NULL) {
Miklos Szeredia181e612001-11-06 12:03:23 +0000692 newpath = get_path_name(f, arg->newdir, arg->name);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000693 if(newpath != NULL) {
694 res = -ENOSYS;
695 if(f->op.link)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000696 res = f->op.link(oldpath, newpath);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000697 free(newpath);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000698 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000699 free(oldpath);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000700 }
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000701 send_reply(f, in, res, NULL, 0);
702}
703
Miklos Szeredi5e183482001-10-31 14:52:35 +0000704static void do_open(struct fuse *f, struct fuse_in_header *in,
705 struct fuse_open_in *arg)
706{
707 int res;
708 char *path;
709
710 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000711 path = get_path(f, in->ino);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000712 if(path != NULL) {
713 res = -ENOSYS;
714 if(f->op.open)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000715 res = f->op.open(path, arg->flags);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000716 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000717 }
718 send_reply(f, in, res, NULL, 0);
719}
720
721static void do_read(struct fuse *f, struct fuse_in_header *in,
722 struct fuse_read_in *arg)
723{
724 int res;
725 char *path;
Miklos Szeredi43696432001-11-18 19:15:05 +0000726 char *outbuf = (char *) malloc(sizeof(struct fuse_out_header) + arg->size);
727 struct fuse_out_header *out = (struct fuse_out_header *) outbuf;
728 char *buf = outbuf + sizeof(struct fuse_out_header);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000729 size_t size;
Miklos Szeredi43696432001-11-18 19:15:05 +0000730 size_t outsize;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000731
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000732 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000733 path = get_path(f, in->ino);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000734 if(path != NULL) {
Miklos Szeredi6ebe2342002-01-06 21:44:16 +0000735 if(f->flags & FUSE_DEBUG) {
736 printf("READ %u bytes from %llu\n", arg->size, arg->offset);
737 fflush(stdout);
738 }
739
Miklos Szeredi5e183482001-10-31 14:52:35 +0000740 res = -ENOSYS;
Miklos Szeredia181e612001-11-06 12:03:23 +0000741 if(f->op.read)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000742 res = f->op.read(path, buf, arg->size, arg->offset);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000743 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000744 }
745
746 size = 0;
747 if(res > 0) {
748 size = res;
749 res = 0;
Miklos Szeredi6ebe2342002-01-06 21:44:16 +0000750 if(f->flags & FUSE_DEBUG) {
751 printf(" READ %u bytes\n", size);
752 fflush(stdout);
753 }
Miklos Szeredi5e183482001-10-31 14:52:35 +0000754 }
Miklos Szeredi43696432001-11-18 19:15:05 +0000755 out->unique = in->unique;
756 out->error = res;
757 outsize = sizeof(struct fuse_out_header) + size;
758
759 send_reply_raw(f, outbuf, outsize);
760 free(outbuf);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000761}
Miklos Szeredib483c932001-10-29 14:57:57 +0000762
Miklos Szeredia181e612001-11-06 12:03:23 +0000763static void do_write(struct fuse *f, struct fuse_in_header *in,
764 struct fuse_write_in *arg)
765{
766 int res;
767 char *path;
Miklos Szeredia181e612001-11-06 12:03:23 +0000768
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000769 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000770 path = get_path(f, in->ino);
771 if(path != NULL) {
Miklos Szeredi6ebe2342002-01-06 21:44:16 +0000772 if(f->flags & FUSE_DEBUG) {
773 printf("WRITE %u bytes to %llu\n", arg->size, arg->offset);
774 fflush(stdout);
775 }
776
Miklos Szeredia181e612001-11-06 12:03:23 +0000777 res = -ENOSYS;
778 if(f->op.write)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000779 res = f->op.write(path, arg->buf, arg->size, arg->offset);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000780 free(path);
Miklos Szeredia181e612001-11-06 12:03:23 +0000781 }
782
783 if(res > 0) {
784 if((size_t) res != arg->size) {
785 fprintf(stderr, "short write: %u (should be %u)\n", res,
786 arg->size);
787 res = -EIO;
788 }
789 else
790 res = 0;
791 }
792
793 send_reply(f, in, res, NULL, 0);
794}
795
Miklos Szeredi43696432001-11-18 19:15:05 +0000796static void free_cmd(struct fuse_cmd *cmd)
797{
798 free(cmd->buf);
799 free(cmd);
800}
801
Miklos Szeredifff56ab2001-11-16 10:12:59 +0000802void __fuse_process_cmd(struct fuse *f, struct fuse_cmd *cmd)
Miklos Szeredia181e612001-11-06 12:03:23 +0000803{
Miklos Szeredia181e612001-11-06 12:03:23 +0000804 struct fuse_in_header *in = (struct fuse_in_header *) cmd->buf;
805 void *inarg = cmd->buf + sizeof(struct fuse_in_header);
806 size_t argsize;
Miklos Szeredife25def2001-12-20 15:38:05 +0000807 struct fuse_context *ctx = fuse_get_context(f);
Miklos Szeredia181e612001-11-06 12:03:23 +0000808
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +0000809 dec_avail(f);
Miklos Szeredi33232032001-11-19 17:55:51 +0000810
Miklos Szeredic0938ea2001-11-07 12:35:06 +0000811 if((f->flags & FUSE_DEBUG)) {
812 printf("unique: %i, opcode: %i, ino: %li, insize: %i\n", in->unique,
813 in->opcode, in->ino, cmd->buflen);
814 fflush(stdout);
815 }
Miklos Szeredife25def2001-12-20 15:38:05 +0000816
817 ctx->uid = in->uid;
818 ctx->gid = in->gid;
Miklos Szeredia181e612001-11-06 12:03:23 +0000819
820 argsize = cmd->buflen - sizeof(struct fuse_in_header);
821
822 switch(in->opcode) {
823 case FUSE_LOOKUP:
824 do_lookup(f, in, (char *) inarg);
825 break;
826
Miklos Szeredia181e612001-11-06 12:03:23 +0000827 case FUSE_GETATTR:
828 do_getattr(f, in);
829 break;
830
831 case FUSE_SETATTR:
832 do_setattr(f, in, (struct fuse_setattr_in *) inarg);
833 break;
834
835 case FUSE_READLINK:
836 do_readlink(f, in);
837 break;
838
839 case FUSE_GETDIR:
840 do_getdir(f, in);
841 break;
842
843 case FUSE_MKNOD:
844 do_mknod(f, in, (struct fuse_mknod_in *) inarg);
845 break;
846
847 case FUSE_MKDIR:
848 do_mkdir(f, in, (struct fuse_mkdir_in *) inarg);
849 break;
850
851 case FUSE_UNLINK:
852 case FUSE_RMDIR:
853 do_remove(f, in, (char *) inarg);
854 break;
855
856 case FUSE_SYMLINK:
857 do_symlink(f, in, (char *) inarg,
858 ((char *) inarg) + strlen((char *) inarg) + 1);
859 break;
860
861 case FUSE_RENAME:
862 do_rename(f, in, (struct fuse_rename_in *) inarg);
863 break;
864
865 case FUSE_LINK:
866 do_link(f, in, (struct fuse_link_in *) inarg);
867 break;
868
869 case FUSE_OPEN:
870 do_open(f, in, (struct fuse_open_in *) inarg);
871 break;
872
873 case FUSE_READ:
874 do_read(f, in, (struct fuse_read_in *) inarg);
875 break;
876
877 case FUSE_WRITE:
878 do_write(f, in, (struct fuse_write_in *) inarg);
879 break;
880
881 default:
882 fprintf(stderr, "Operation %i not implemented\n", in->opcode);
Miklos Szeredi43696432001-11-18 19:15:05 +0000883 send_reply(f, in, -ENOSYS, NULL, 0);
Miklos Szeredia181e612001-11-06 12:03:23 +0000884 }
Miklos Szeredi43696432001-11-18 19:15:05 +0000885
886 free_cmd(cmd);
Miklos Szeredia181e612001-11-06 12:03:23 +0000887}
888
Miklos Szeredifff56ab2001-11-16 10:12:59 +0000889struct fuse_cmd *__fuse_read_cmd(struct fuse *f)
Miklos Szeredi2df1c042001-11-06 15:07:17 +0000890{
Miklos Szeredifff56ab2001-11-16 10:12:59 +0000891 ssize_t res;
Miklos Szeredifff56ab2001-11-16 10:12:59 +0000892 struct fuse_cmd *cmd;
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +0000893 struct fuse_in_header *in;
894 void *inarg;
Miklos Szeredifff56ab2001-11-16 10:12:59 +0000895
Miklos Szeredi43696432001-11-18 19:15:05 +0000896 cmd = (struct fuse_cmd *) malloc(sizeof(struct fuse_cmd));
897 cmd->buf = (char *) malloc(FUSE_MAX_IN);
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +0000898 in = (struct fuse_in_header *) cmd->buf;
899 inarg = cmd->buf + sizeof(struct fuse_in_header);
Miklos Szeredi43696432001-11-18 19:15:05 +0000900
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +0000901 do {
902 res = read(f->fd, cmd->buf, FUSE_MAX_IN);
903 if(res == -1) {
904 /* ENODEV means we got unmounted, so we silenty return failure */
905 if(errno != ENODEV) {
906 perror("fuse: reading device");
907 /* BAD... This will happen again */
908 }
909 free_cmd(cmd);
910 return NULL;
Miklos Szeredi96249982001-11-21 12:21:19 +0000911 }
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +0000912 if((size_t) res < sizeof(struct fuse_in_header)) {
913 fprintf(stderr, "short read on fuse device\n");
914 /* Cannot happen */
915 free_cmd(cmd);
916 return NULL;
917 }
918 cmd->buflen = res;
919
920 /* Forget is special, it can be done without messing with threads. */
921 if(in->opcode == FUSE_FORGET)
922 do_forget(f, in, (struct fuse_forget_in *) inarg);
923
924 } while(in->opcode == FUSE_FORGET);
925
Miklos Szeredifff56ab2001-11-16 10:12:59 +0000926 return cmd;
Miklos Szeredi2df1c042001-11-06 15:07:17 +0000927}
928
Miklos Szeredifff56ab2001-11-16 10:12:59 +0000929
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000930void fuse_loop(struct fuse *f)
931{
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000932 while(1) {
Miklos Szeredifff56ab2001-11-16 10:12:59 +0000933 struct fuse_cmd *cmd = __fuse_read_cmd(f);
934 if(cmd == NULL)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000935 exit(1);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000936
Miklos Szeredifff56ab2001-11-16 10:12:59 +0000937 __fuse_process_cmd(f, cmd);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000938 }
939}
940
Miklos Szeredi2e50d432001-12-20 12:17:25 +0000941struct fuse_context *fuse_get_context(struct fuse *f)
942{
943 if(f->getcontext)
944 return f->getcontext(f);
945 else
946 return &f->context;
947}
948
949struct fuse *fuse_new(int fd, int flags, const struct fuse_operations *op)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000950{
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000951 struct fuse *f;
952 struct node *root;
Miklos Szeredife428122001-11-20 19:12:28 +0000953 char verstr[128];
Miklos Szeredicc8c9752001-11-21 10:03:39 +0000954 char *realver = getenv(FUSE_KERNEL_VERSION_ENV);
Miklos Szeredife428122001-11-20 19:12:28 +0000955
956 if(realver != NULL) {
957 sprintf(verstr, "%i", FUSE_KERNEL_VERSION);
958 if(strcmp(verstr, realver) != 0) {
959 fprintf(stderr,
960 "Warning: FUSE version mismatch: using %s, kernel is %s\n",
961 realver, verstr);
962 }
963 }
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000964
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000965 f = (struct fuse *) calloc(1, sizeof(struct fuse));
Miklos Szeredi2df1c042001-11-06 15:07:17 +0000966
Miklos Szeredia181e612001-11-06 12:03:23 +0000967 f->flags = flags;
Miklos Szeredi8cffdb92001-11-09 14:49:18 +0000968 f->fd = fd;
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000969 f->ctr = 0;
Miklos Szeredifff56ab2001-11-16 10:12:59 +0000970 /* FIXME: Dynamic hash table */
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000971 f->name_table_size = 14057;
972 f->name_table = (struct node **)
973 calloc(1, sizeof(struct node *) * f->name_table_size);
974 f->ino_table_size = 14057;
975 f->ino_table = (struct node **)
976 calloc(1, sizeof(struct node *) * f->ino_table_size);
Miklos Szeredia181e612001-11-06 12:03:23 +0000977 pthread_mutex_init(&f->lock, NULL);
Miklos Szeredi33232032001-11-19 17:55:51 +0000978 f->numworker = 0;
979 f->numavail = 0;
Miklos Szeredi2e50d432001-12-20 12:17:25 +0000980 f->op = *op;
981 f->getcontext = NULL;
982 f->context.uid = 0;
983 f->context.gid = 0;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000984
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000985 root = (struct node *) calloc(1, sizeof(struct node));
Miklos Szeredi8cffdb92001-11-09 14:49:18 +0000986 root->mode = 0;
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000987 root->rdev = 0;
988 root->name = strdup("/");
989 root->parent = 0;
990 hash_ino(f, root, FUSE_ROOT_INO);
991
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000992 return f;
993}
994
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000995void fuse_destroy(struct fuse *f)
996{
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000997 size_t i;
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000998 for(i = 0; i < f->ino_table_size; i++) {
999 struct node *node;
1000 struct node *next;
1001 for(node = f->ino_table[i]; node != NULL; node = next) {
1002 next = node->ino_next;
1003 free_node(node);
1004 }
1005 }
1006 free(f->ino_table);
1007 free(f->name_table);
Miklos Szeredia181e612001-11-06 12:03:23 +00001008 pthread_mutex_destroy(&f->lock);
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001009 free(f);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001010}