blob: 0a0b40a521860c513c431610d039d934f70558e2 [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>
17
Miklos Szeredi97c61e92001-11-07 12:09:43 +000018#define FUSE_MAX_PATH 4096
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000019
Miklos Szeredicc8c9752001-11-21 10:03:39 +000020#define FUSE_KERNEL_VERSION_ENV "_FUSE_KERNEL_VERSION"
21
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +000022static inline void inc_avail(struct fuse *f)
23{
24 pthread_mutex_lock(&f->lock);
25 f->numavail ++;
26 pthread_mutex_unlock(&f->lock);
27}
28
29static inline void dec_avail(struct fuse *f)
30{
31 pthread_mutex_lock(&f->lock);
32 f->numavail --;
33 pthread_mutex_unlock(&f->lock);
34}
35
Miklos Szeredi97c61e92001-11-07 12:09:43 +000036static struct node *__get_node(struct fuse *f, fino_t ino)
Miklos Szeredia181e612001-11-06 12:03:23 +000037{
Miklos Szeredi97c61e92001-11-07 12:09:43 +000038 size_t hash = ino % f->ino_table_size;
39 struct node *node;
40
41 for(node = f->ino_table[hash]; node != NULL; node = node->ino_next)
42 if(node->ino == ino)
43 return node;
44
45 return NULL;
Miklos Szeredia181e612001-11-06 12:03:23 +000046}
47
Miklos Szeredi97c61e92001-11-07 12:09:43 +000048static struct node *get_node(struct fuse *f, fino_t ino)
Miklos Szeredia181e612001-11-06 12:03:23 +000049{
Miklos Szeredi97c61e92001-11-07 12:09:43 +000050 struct node *node = __get_node(f, ino);
51 if(node != NULL)
52 return node;
53
54 fprintf(stderr, "fuse internal error: inode %lu not found\n", ino);
55 abort();
Miklos Szeredia181e612001-11-06 12:03:23 +000056}
57
Miklos Szeredi97c61e92001-11-07 12:09:43 +000058static void hash_ino(struct fuse *f, struct node *node, fino_t ino)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000059{
Miklos Szeredi97c61e92001-11-07 12:09:43 +000060 size_t hash = ino % f->ino_table_size;
61 node->ino = ino;
62
63 node->ino_next = f->ino_table[hash];
64 f->ino_table[hash] = node;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000065}
66
Miklos Szeredi97c61e92001-11-07 12:09:43 +000067static void unhash_ino(struct fuse *f, struct node *node)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000068{
Miklos Szeredi97c61e92001-11-07 12:09:43 +000069 size_t hash = node->ino % f->ino_table_size;
70 struct node **nodep = &f->ino_table[hash];
71
72 for(; *nodep != NULL; nodep = &(*nodep)->ino_next)
73 if(*nodep == node) {
74 *nodep = node->ino_next;
75 return;
76 }
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000077}
78
Miklos Szeredi97c61e92001-11-07 12:09:43 +000079static fino_t get_ino(struct node *node)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000080{
Miklos Szeredi97c61e92001-11-07 12:09:43 +000081 return node->ino;
82}
83
84static fino_t next_ino(struct fuse *f)
85{
86 while(f->ctr == 0 || __get_node(f, f->ctr) != NULL)
87 f->ctr++;
88
89 return f->ctr;
90}
91
92static void free_node(struct node *node)
93{
94 free(node->name);
95 free(node);
96}
97
98static unsigned int name_hash(struct fuse *f, fino_t parent, const char *name)
99{
100 unsigned int hash = *name;
101
102 if(hash)
103 for(name += 1; *name != '\0'; name++)
104 hash = (hash << 5) - hash + *name;
105
106 return (hash + parent) % f->name_table_size;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000107}
108
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000109static struct node *lookup_node(struct fuse *f, fino_t parent,
110 const char *name)
111{
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000112 size_t hash = name_hash(f, parent, name);
113 struct node *node;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000114
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000115 for(node = f->name_table[hash]; node != NULL; node = node->name_next)
116 if(node->parent == parent && strcmp(node->name, name) == 0)
117 return node;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000118
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000119 return NULL;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000120}
121
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000122static void hash_name(struct fuse *f, struct node *node, fino_t parent,
Miklos Szeredia181e612001-11-06 12:03:23 +0000123 const char *name)
Miklos Szeredi5e183482001-10-31 14:52:35 +0000124{
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000125 size_t hash = name_hash(f, parent, name);
Miklos Szeredia181e612001-11-06 12:03:23 +0000126 node->parent = parent;
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000127 node->name = strdup(name);
128 node->name_next = f->name_table[hash];
129 f->name_table[hash] = node;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000130}
131
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000132static void unhash_name(struct fuse *f, struct node *node)
Miklos Szeredia181e612001-11-06 12:03:23 +0000133{
134 if(node->name != NULL) {
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000135 size_t hash = name_hash(f, node->parent, node->name);
136 struct node **nodep = &f->name_table[hash];
137
138 for(; *nodep != NULL; nodep = &(*nodep)->name_next)
139 if(*nodep == node) {
140 *nodep = node->name_next;
141 node->name_next = NULL;
142 free(node->name);
143 node->name = NULL;
144 node->parent = 0;
145 return;
146 }
147 fprintf(stderr, "fuse internal error: unable to unhash node: %lu\n",
148 node->ino);
149 abort();
Miklos Szeredia181e612001-11-06 12:03:23 +0000150 }
151}
152
153static fino_t find_node(struct fuse *f, fino_t parent, char *name,
154 struct fuse_attr *attr, int version)
Miklos Szeredi5e183482001-10-31 14:52:35 +0000155{
156 struct node *node;
Miklos Szeredia181e612001-11-06 12:03:23 +0000157 int mode = attr->mode & S_IFMT;
158 int rdev = 0;
159
160 if(S_ISCHR(mode) || S_ISBLK(mode))
161 rdev = attr->rdev;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000162
Miklos Szeredia181e612001-11-06 12:03:23 +0000163 pthread_mutex_lock(&f->lock);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000164 node = lookup_node(f, parent, name);
165 if(node != NULL) {
Miklos Szeredia181e612001-11-06 12:03:23 +0000166 if(node->mode == mode && node->rdev == rdev)
167 goto out;
168
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000169 unhash_name(f, node);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000170 }
171
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000172 node = (struct node *) calloc(1, sizeof(struct node));
Miklos Szeredia181e612001-11-06 12:03:23 +0000173 node->mode = mode;
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000174 node->rdev = rdev;
175 hash_ino(f, node, next_ino(f));
176 hash_name(f, node, parent, name);
Miklos Szeredia181e612001-11-06 12:03:23 +0000177
178 out:
179 node->version = version;
180 pthread_mutex_unlock(&f->lock);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000181 return get_ino(node);
182}
183
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000184static char *add_name(char *buf, char *s, const char *name)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000185{
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000186 size_t len = strlen(name);
187 s -= len;
188 if(s <= buf) {
189 fprintf(stderr, "fuse: path too long: ...%s\n", s + len);
190 return NULL;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000191 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000192 strncpy(s, name, len);
193 s--;
194 *s = '/';
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000195
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000196 return s;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000197}
198
Miklos Szeredia181e612001-11-06 12:03:23 +0000199static char *get_path_name(struct fuse *f, fino_t ino, const char *name)
Miklos Szeredib483c932001-10-29 14:57:57 +0000200{
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000201 char buf[FUSE_MAX_PATH];
202 char *s = buf + FUSE_MAX_PATH - 1;
203 struct node *node;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000204
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000205 *s = '\0';
Miklos Szeredia181e612001-11-06 12:03:23 +0000206
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000207 if(name != NULL) {
208 s = add_name(buf, s, name);
209 if(s == NULL)
210 return NULL;
211 }
212
213 pthread_mutex_lock(&f->lock);
214 for(node = get_node(f, ino); node->ino != FUSE_ROOT_INO;
215 node = get_node(f, node->parent)) {
216 if(node->name == NULL) {
217 s = NULL;
218 break;
219 }
220
221 s = add_name(buf, s, node->name);
222 if(s == NULL)
223 break;
224 }
225 pthread_mutex_unlock(&f->lock);
226
227 if(s == NULL)
Miklos Szeredi5e183482001-10-31 14:52:35 +0000228 return NULL;
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000229 else if(*s == '\0')
230 return strdup("/");
231 else
232 return strdup(s);
233}
Miklos Szeredia181e612001-11-06 12:03:23 +0000234
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000235static char *get_path(struct fuse *f, fino_t ino)
236{
237 return get_path_name(f, ino, NULL);
Miklos Szeredib483c932001-10-29 14:57:57 +0000238}
239
Miklos Szeredia181e612001-11-06 12:03:23 +0000240static void destroy_node(struct fuse *f, fino_t ino, int version)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000241{
Miklos Szeredia181e612001-11-06 12:03:23 +0000242 struct node *node;
243
244 pthread_mutex_lock(&f->lock);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000245 node = get_node(f, ino);
Miklos Szeredi39f28672001-11-14 14:52:54 +0000246 if(node->version == version && ino != FUSE_ROOT_INO) {
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000247 unhash_name(f, node);
248 unhash_ino(f, node);
Miklos Szeredia181e612001-11-06 12:03:23 +0000249 free_node(node);
250 }
251 pthread_mutex_unlock(&f->lock);
252
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000253}
254
Miklos Szeredi5e183482001-10-31 14:52:35 +0000255static void remove_node(struct fuse *f, fino_t dir, const char *name)
256{
Miklos Szeredia181e612001-11-06 12:03:23 +0000257 struct node *node;
258
259 pthread_mutex_lock(&f->lock);
260 node = lookup_node(f, dir, name);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000261 if(node == NULL) {
262 fprintf(stderr, "fuse internal error: unable to remove node %lu/%s\n",
263 dir, name);
264 abort();
265 }
266 unhash_name(f, node);
Miklos Szeredia181e612001-11-06 12:03:23 +0000267 pthread_mutex_unlock(&f->lock);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000268}
269
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000270static void rename_node(struct fuse *f, fino_t olddir, const char *oldname,
271 fino_t newdir, const char *newname)
272{
Miklos Szeredia181e612001-11-06 12:03:23 +0000273 struct node *node;
274 struct node *newnode;
275
276 pthread_mutex_lock(&f->lock);
277 node = lookup_node(f, olddir, oldname);
278 newnode = lookup_node(f, newdir, newname);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000279 if(node == NULL) {
280 fprintf(stderr, "fuse internal error: unable to rename node %lu/%s\n",
281 olddir, oldname);
282 abort();
283 }
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000284
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000285 if(newnode != NULL)
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000286 unhash_name(f, newnode);
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000287
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000288 unhash_name(f, node);
289 hash_name(f, node, newdir, newname);
Miklos Szeredia181e612001-11-06 12:03:23 +0000290 pthread_mutex_unlock(&f->lock);
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000291}
292
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000293static void convert_stat(struct stat *stbuf, struct fuse_attr *attr)
294{
295 attr->mode = stbuf->st_mode;
296 attr->nlink = stbuf->st_nlink;
297 attr->uid = stbuf->st_uid;
298 attr->gid = stbuf->st_gid;
299 attr->rdev = stbuf->st_rdev;
300 attr->size = stbuf->st_size;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000301 attr->blocks = stbuf->st_blocks;
302 attr->atime = stbuf->st_atime;
303 attr->mtime = stbuf->st_mtime;
304 attr->ctime = stbuf->st_ctime;
Miklos Szeredifff56ab2001-11-16 10:12:59 +0000305 attr->_dummy = 4096;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000306}
307
Miklos Szeredia181e612001-11-06 12:03:23 +0000308static int fill_dir(struct fuse_dirhandle *dh, char *name, int type)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000309{
310 struct fuse_dirent dirent;
311 size_t reclen;
312 size_t res;
313
Miklos Szeredi43696432001-11-18 19:15:05 +0000314 dirent.ino = (unsigned long) -1;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000315 dirent.namelen = strlen(name);
316 strncpy(dirent.name, name, sizeof(dirent.name));
317 dirent.type = type;
318 reclen = FUSE_DIRENT_SIZE(&dirent);
319 res = fwrite(&dirent, reclen, 1, dh->fp);
320 if(res == 0) {
Miklos Szeredi96249982001-11-21 12:21:19 +0000321 perror("fuse: writing directory file");
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000322 return -EIO;
323 }
324 return 0;
325}
326
Miklos Szeredi43696432001-11-18 19:15:05 +0000327static void send_reply_raw(struct fuse *f, char *outbuf, size_t outsize)
328{
329 int res;
330
331 if((f->flags & FUSE_DEBUG)) {
332 struct fuse_out_header *out = (struct fuse_out_header *) outbuf;
333 printf(" unique: %i, error: %i (%s), outsize: %i\n", out->unique,
334 out->error, strerror(-out->error), outsize);
335 fflush(stdout);
336 }
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +0000337
338 /* This needs to be done before the reply because otherwise the
339 scheduler can tricks with us, and only let the counter be increased
340 long after the operation is done */
341 inc_avail(f);
342
Miklos Szeredi43696432001-11-18 19:15:05 +0000343 res = write(f->fd, outbuf, outsize);
344 if(res == -1) {
345 /* ENOENT means the operation was interrupted */
346 if(errno != ENOENT)
Miklos Szeredi96249982001-11-21 12:21:19 +0000347 perror("fuse: writing device");
Miklos Szeredi43696432001-11-18 19:15:05 +0000348 }
349}
350
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000351static void send_reply(struct fuse *f, struct fuse_in_header *in, int error,
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000352 void *arg, size_t argsize)
353{
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000354 char *outbuf;
355 size_t outsize;
356 struct fuse_out_header *out;
357
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000358 if(error > 0) {
Miklos Szeredi96249982001-11-21 12:21:19 +0000359 fprintf(stderr, "fuse: positive error code: %i\n", error);
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000360 error = -ERANGE;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000361 }
362
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000363 if(error)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000364 argsize = 0;
365
366 outsize = sizeof(struct fuse_out_header) + argsize;
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000367 outbuf = (char *) malloc(outsize);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000368 out = (struct fuse_out_header *) outbuf;
369 out->unique = in->unique;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000370 out->error = error;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000371 if(argsize != 0)
372 memcpy(outbuf + sizeof(struct fuse_out_header), arg, argsize);
373
Miklos Szeredi43696432001-11-18 19:15:05 +0000374 send_reply_raw(f, outbuf, outsize);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000375
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000376 free(outbuf);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000377}
378
379static void do_lookup(struct fuse *f, struct fuse_in_header *in, char *name)
380{
381 int res;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000382 char *path;
383 struct stat buf;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000384 struct fuse_lookup_out arg;
385
Miklos Szeredi5e183482001-10-31 14:52:35 +0000386 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000387 path = get_path_name(f, in->ino, name);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000388 if(path != NULL) {
389 res = -ENOSYS;
390 if(f->op.getattr)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000391 res = f->op.getattr(path, &buf);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000392 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000393 }
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000394 if(res == 0) {
395 convert_stat(&buf, &arg.attr);
Miklos Szeredia181e612001-11-06 12:03:23 +0000396 arg.ino = find_node(f, in->ino, name, &arg.attr, in->unique);
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000397 }
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000398 send_reply(f, in, res, &arg, sizeof(arg));
399}
400
Miklos Szeredia181e612001-11-06 12:03:23 +0000401static void do_forget(struct fuse *f, struct fuse_in_header *in,
402 struct fuse_forget_in *arg)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000403{
Miklos Szeredi43696432001-11-18 19:15:05 +0000404 if(f->flags & FUSE_DEBUG) {
405 printf("FORGET %li/%i\n", in->ino, arg->version);
406 fflush(stdout);
407 }
Miklos Szeredia181e612001-11-06 12:03:23 +0000408 destroy_node(f, in->ino, arg->version);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000409}
410
411static void do_getattr(struct fuse *f, struct fuse_in_header *in)
412{
413 int res;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000414 char *path;
415 struct stat buf;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000416 struct fuse_getattr_out arg;
417
Miklos Szeredi5e183482001-10-31 14:52:35 +0000418 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000419 path = get_path(f, in->ino);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000420 if(path != NULL) {
421 res = -ENOSYS;
422 if(f->op.getattr)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000423 res = f->op.getattr(path, &buf);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000424 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000425 }
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000426 if(res == 0)
427 convert_stat(&buf, &arg.attr);
428
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000429 send_reply(f, in, res, &arg, sizeof(arg));
430}
431
Miklos Szeredi680a69a2001-11-16 13:31:14 +0000432static int do_chmod(struct fuse *f, const char *path, struct fuse_attr *attr)
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000433{
434 int res;
435
436 res = -ENOSYS;
437 if(f->op.chmod)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000438 res = f->op.chmod(path, attr->mode);
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000439
440 return res;
441}
442
Miklos Szeredi680a69a2001-11-16 13:31:14 +0000443static int do_chown(struct fuse *f, const char *path, struct fuse_attr *attr,
Miklos Szeredi2e50d432001-12-20 12:17:25 +0000444 int valid)
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000445{
446 int res;
447 uid_t uid = (valid & FATTR_UID) ? attr->uid : (uid_t) -1;
448 gid_t gid = (valid & FATTR_GID) ? attr->gid : (gid_t) -1;
449
450 res = -ENOSYS;
451 if(f->op.chown)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000452 res = f->op.chown(path, uid, gid);
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000453
454 return res;
455}
456
Miklos Szeredi680a69a2001-11-16 13:31:14 +0000457static int do_truncate(struct fuse *f, const char *path,
458 struct fuse_attr *attr)
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000459{
460 int res;
461
462 res = -ENOSYS;
463 if(f->op.truncate)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000464 res = f->op.truncate(path, attr->size);
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000465
466 return res;
467}
468
Miklos Szeredi680a69a2001-11-16 13:31:14 +0000469static int do_utime(struct fuse *f, const char *path, struct fuse_attr *attr)
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000470{
471 int res;
472 struct utimbuf buf;
473 buf.actime = attr->atime;
474 buf.modtime = attr->mtime;
475 res = -ENOSYS;
476 if(f->op.utime)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000477 res = f->op.utime(path, &buf);
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000478
479 return res;
480}
481
Miklos Szeredi5e183482001-10-31 14:52:35 +0000482static void do_setattr(struct fuse *f, struct fuse_in_header *in,
483 struct fuse_setattr_in *arg)
484{
485 int res;
486 char *path;
487 int valid = arg->valid;
488 struct fuse_attr *attr = &arg->attr;
Miklos Szeredia181e612001-11-06 12:03:23 +0000489 struct fuse_setattr_out outarg;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000490
491 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000492 path = get_path(f, in->ino);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000493 if(path != NULL) {
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000494 res = -ENOSYS;
495 if(f->op.getattr) {
496 res = 0;
497 if(!res && (valid & FATTR_MODE))
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000498 res = do_chmod(f, path, attr);
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000499 if(!res && (valid & (FATTR_UID | FATTR_GID)))
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000500 res = do_chown(f, path, attr, valid);
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000501 if(!res && (valid & FATTR_SIZE))
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000502 res = do_truncate(f, path, attr);
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000503 if(!res && (valid & FATTR_UTIME))
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000504 res = do_utime(f, path, attr);
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000505 if(!res) {
506 struct stat buf;
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000507 res = f->op.getattr(path, &buf);
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000508 if(!res)
509 convert_stat(&buf, &outarg.attr);
Miklos Szeredia181e612001-11-06 12:03:23 +0000510 }
Miklos Szeredi5e183482001-10-31 14:52:35 +0000511 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000512 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000513 }
Miklos Szeredia181e612001-11-06 12:03:23 +0000514 send_reply(f, in, res, &outarg, sizeof(outarg));
Miklos Szeredi5e183482001-10-31 14:52:35 +0000515}
516
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000517static void do_readlink(struct fuse *f, struct fuse_in_header *in)
518{
519 int res;
520 char link[PATH_MAX + 1];
Miklos Szeredib483c932001-10-29 14:57:57 +0000521 char *path;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000522
Miklos Szeredi5e183482001-10-31 14:52:35 +0000523 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000524 path = get_path(f, in->ino);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000525 if(path != NULL) {
526 res = -ENOSYS;
527 if(f->op.readlink)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000528 res = f->op.readlink(path, link, sizeof(link));
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000529 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000530 }
Miklos Szeredi2df1c042001-11-06 15:07:17 +0000531 link[PATH_MAX] = '\0';
Miklos Szeredi5e183482001-10-31 14:52:35 +0000532 send_reply(f, in, res, link, !res ? strlen(link) : 0);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000533}
534
535static void do_getdir(struct fuse *f, struct fuse_in_header *in)
536{
537 int res;
538 struct fuse_getdir_out arg;
Miklos Szeredia181e612001-11-06 12:03:23 +0000539 struct fuse_dirhandle dh;
Miklos Szeredib483c932001-10-29 14:57:57 +0000540 char *path;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000541
Miklos Szeredib483c932001-10-29 14:57:57 +0000542 dh.fuse = f;
543 dh.fp = tmpfile();
544 dh.dir = in->ino;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000545 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000546 path = get_path(f, in->ino);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000547 if(path != NULL) {
548 res = -ENOSYS;
549 if(f->op.getdir)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000550 res = f->op.getdir(path, &dh, (fuse_dirfil_t) fill_dir);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000551 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000552 }
Miklos Szeredib483c932001-10-29 14:57:57 +0000553 fflush(dh.fp);
554 arg.fd = fileno(dh.fp);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000555 send_reply(f, in, res, &arg, sizeof(arg));
Miklos Szeredib483c932001-10-29 14:57:57 +0000556 fclose(dh.fp);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000557}
558
Miklos Szeredib483c932001-10-29 14:57:57 +0000559static void do_mknod(struct fuse *f, struct fuse_in_header *in,
560 struct fuse_mknod_in *inarg)
561{
562 int res;
563 char *path;
564 struct fuse_mknod_out outarg;
565 struct stat buf;
566
Miklos Szeredi5e183482001-10-31 14:52:35 +0000567 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000568 path = get_path_name(f, in->ino, inarg->name);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000569 if(path != NULL) {
570 res = -ENOSYS;
571 if(f->op.mknod && f->op.getattr) {
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000572 res = f->op.mknod(path, inarg->mode, inarg->rdev);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000573 if(res == 0)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000574 res = f->op.getattr(path, &buf);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000575 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000576 free(path);
Miklos Szeredib483c932001-10-29 14:57:57 +0000577 }
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000578 if(res == 0) {
Miklos Szeredib483c932001-10-29 14:57:57 +0000579 convert_stat(&buf, &outarg.attr);
Miklos Szeredia181e612001-11-06 12:03:23 +0000580 outarg.ino = find_node(f, in->ino, inarg->name, &outarg.attr,
581 in->unique);
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000582 }
Miklos Szeredib483c932001-10-29 14:57:57 +0000583
584 send_reply(f, in, res, &outarg, sizeof(outarg));
585}
586
587static void do_mkdir(struct fuse *f, struct fuse_in_header *in,
588 struct fuse_mkdir_in *inarg)
589{
590 int res;
591 char *path;
592
Miklos Szeredi5e183482001-10-31 14:52:35 +0000593 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000594 path = get_path_name(f, in->ino, inarg->name);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000595 if(path != NULL) {
596 res = -ENOSYS;
597 if(f->op.mkdir)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000598 res = f->op.mkdir(path, inarg->mode);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000599 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000600 }
Miklos Szeredib483c932001-10-29 14:57:57 +0000601 send_reply(f, in, res, NULL, 0);
602}
603
604static void do_remove(struct fuse *f, struct fuse_in_header *in, char *name)
605{
606 int res;
607 char *path;
608
Miklos Szeredi5e183482001-10-31 14:52:35 +0000609 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000610 path = get_path_name(f, in->ino, name);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000611 if(path != NULL) {
612 res = -ENOSYS;
613 if(in->opcode == FUSE_UNLINK) {
614 if(f->op.unlink)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000615 res = f->op.unlink(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000616 }
617 else {
618 if(f->op.rmdir)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000619 res = f->op.rmdir(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000620 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000621 free(path);
Miklos Szeredib483c932001-10-29 14:57:57 +0000622 }
Miklos Szeredi5e183482001-10-31 14:52:35 +0000623 if(res == 0)
624 remove_node(f, in->ino, name);
Miklos Szeredib483c932001-10-29 14:57:57 +0000625 send_reply(f, in, res, NULL, 0);
626}
627
628static void do_symlink(struct fuse *f, struct fuse_in_header *in, char *name,
629 char *link)
630{
631 int res;
632 char *path;
633
Miklos Szeredi5e183482001-10-31 14:52:35 +0000634 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000635 path = get_path_name(f, in->ino, name);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000636 if(path != NULL) {
637 res = -ENOSYS;
638 if(f->op.symlink)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000639 res = f->op.symlink(link, path);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000640 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000641 }
Miklos Szeredib483c932001-10-29 14:57:57 +0000642 send_reply(f, in, res, NULL, 0);
643}
644
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000645static void do_rename(struct fuse *f, struct fuse_in_header *in,
646 struct fuse_rename_in *inarg)
647{
648 int res;
649 fino_t olddir = in->ino;
650 fino_t newdir = inarg->newdir;
651 char *oldname = inarg->names;
652 char *newname = inarg->names + strlen(oldname) + 1;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000653 char *oldpath;
654 char *newpath;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000655
Miklos Szeredi5e183482001-10-31 14:52:35 +0000656 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000657 oldpath = get_path_name(f, olddir, oldname);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000658 if(oldpath != NULL) {
Miklos Szeredia181e612001-11-06 12:03:23 +0000659 newpath = get_path_name(f, newdir, newname);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000660 if(newpath != NULL) {
661 res = -ENOSYS;
662 if(f->op.rename)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000663 res = f->op.rename(oldpath, newpath);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000664 if(res == 0)
665 rename_node(f, olddir, oldname, newdir, newname);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000666 free(newpath);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000667 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000668 free(oldpath);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000669 }
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000670 send_reply(f, in, res, NULL, 0);
671}
672
673static void do_link(struct fuse *f, struct fuse_in_header *in,
Miklos Szeredi5e183482001-10-31 14:52:35 +0000674 struct fuse_link_in *arg)
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000675{
676 int res;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000677 char *oldpath;
678 char *newpath;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000679
Miklos Szeredi5e183482001-10-31 14:52:35 +0000680 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000681 oldpath = get_path(f, in->ino);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000682 if(oldpath != NULL) {
Miklos Szeredia181e612001-11-06 12:03:23 +0000683 newpath = get_path_name(f, arg->newdir, arg->name);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000684 if(newpath != NULL) {
685 res = -ENOSYS;
686 if(f->op.link)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000687 res = f->op.link(oldpath, newpath);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000688 free(newpath);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000689 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000690 free(oldpath);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000691 }
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000692 send_reply(f, in, res, NULL, 0);
693}
694
Miklos Szeredi5e183482001-10-31 14:52:35 +0000695static void do_open(struct fuse *f, struct fuse_in_header *in,
696 struct fuse_open_in *arg)
697{
698 int res;
699 char *path;
700
701 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000702 path = get_path(f, in->ino);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000703 if(path != NULL) {
704 res = -ENOSYS;
705 if(f->op.open)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000706 res = f->op.open(path, arg->flags);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000707 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000708 }
709 send_reply(f, in, res, NULL, 0);
710}
711
712static void do_read(struct fuse *f, struct fuse_in_header *in,
713 struct fuse_read_in *arg)
714{
715 int res;
716 char *path;
Miklos Szeredi43696432001-11-18 19:15:05 +0000717 char *outbuf = (char *) malloc(sizeof(struct fuse_out_header) + arg->size);
718 struct fuse_out_header *out = (struct fuse_out_header *) outbuf;
719 char *buf = outbuf + sizeof(struct fuse_out_header);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000720 size_t size;
Miklos Szeredi43696432001-11-18 19:15:05 +0000721 size_t outsize;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000722
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000723 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000724 path = get_path(f, in->ino);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000725 if(path != NULL) {
726 res = -ENOSYS;
Miklos Szeredia181e612001-11-06 12:03:23 +0000727 if(f->op.read)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000728 res = f->op.read(path, buf, arg->size, arg->offset);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000729 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000730 }
731
732 size = 0;
733 if(res > 0) {
734 size = res;
735 res = 0;
736 }
Miklos Szeredi43696432001-11-18 19:15:05 +0000737 out->unique = in->unique;
738 out->error = res;
739 outsize = sizeof(struct fuse_out_header) + size;
740
741 send_reply_raw(f, outbuf, outsize);
742 free(outbuf);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000743}
Miklos Szeredib483c932001-10-29 14:57:57 +0000744
Miklos Szeredia181e612001-11-06 12:03:23 +0000745static void do_write(struct fuse *f, struct fuse_in_header *in,
746 struct fuse_write_in *arg)
747{
748 int res;
749 char *path;
Miklos Szeredia181e612001-11-06 12:03:23 +0000750
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000751 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000752 path = get_path(f, in->ino);
753 if(path != NULL) {
754 res = -ENOSYS;
755 if(f->op.write)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000756 res = f->op.write(path, arg->buf, arg->size, arg->offset);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000757 free(path);
Miklos Szeredia181e612001-11-06 12:03:23 +0000758 }
759
760 if(res > 0) {
761 if((size_t) res != arg->size) {
762 fprintf(stderr, "short write: %u (should be %u)\n", res,
763 arg->size);
764 res = -EIO;
765 }
766 else
767 res = 0;
768 }
769
770 send_reply(f, in, res, NULL, 0);
771}
772
Miklos Szeredi43696432001-11-18 19:15:05 +0000773static void free_cmd(struct fuse_cmd *cmd)
774{
775 free(cmd->buf);
776 free(cmd);
777}
778
Miklos Szeredifff56ab2001-11-16 10:12:59 +0000779void __fuse_process_cmd(struct fuse *f, struct fuse_cmd *cmd)
Miklos Szeredia181e612001-11-06 12:03:23 +0000780{
Miklos Szeredia181e612001-11-06 12:03:23 +0000781 struct fuse_in_header *in = (struct fuse_in_header *) cmd->buf;
782 void *inarg = cmd->buf + sizeof(struct fuse_in_header);
783 size_t argsize;
Miklos Szeredia181e612001-11-06 12:03:23 +0000784
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +0000785 dec_avail(f);
Miklos Szeredi33232032001-11-19 17:55:51 +0000786
Miklos Szeredic0938ea2001-11-07 12:35:06 +0000787 if((f->flags & FUSE_DEBUG)) {
788 printf("unique: %i, opcode: %i, ino: %li, insize: %i\n", in->unique,
789 in->opcode, in->ino, cmd->buflen);
790 fflush(stdout);
791 }
Miklos Szeredia181e612001-11-06 12:03:23 +0000792
793 argsize = cmd->buflen - sizeof(struct fuse_in_header);
794
795 switch(in->opcode) {
796 case FUSE_LOOKUP:
797 do_lookup(f, in, (char *) inarg);
798 break;
799
Miklos Szeredia181e612001-11-06 12:03:23 +0000800 case FUSE_GETATTR:
801 do_getattr(f, in);
802 break;
803
804 case FUSE_SETATTR:
805 do_setattr(f, in, (struct fuse_setattr_in *) inarg);
806 break;
807
808 case FUSE_READLINK:
809 do_readlink(f, in);
810 break;
811
812 case FUSE_GETDIR:
813 do_getdir(f, in);
814 break;
815
816 case FUSE_MKNOD:
817 do_mknod(f, in, (struct fuse_mknod_in *) inarg);
818 break;
819
820 case FUSE_MKDIR:
821 do_mkdir(f, in, (struct fuse_mkdir_in *) inarg);
822 break;
823
824 case FUSE_UNLINK:
825 case FUSE_RMDIR:
826 do_remove(f, in, (char *) inarg);
827 break;
828
829 case FUSE_SYMLINK:
830 do_symlink(f, in, (char *) inarg,
831 ((char *) inarg) + strlen((char *) inarg) + 1);
832 break;
833
834 case FUSE_RENAME:
835 do_rename(f, in, (struct fuse_rename_in *) inarg);
836 break;
837
838 case FUSE_LINK:
839 do_link(f, in, (struct fuse_link_in *) inarg);
840 break;
841
842 case FUSE_OPEN:
843 do_open(f, in, (struct fuse_open_in *) inarg);
844 break;
845
846 case FUSE_READ:
847 do_read(f, in, (struct fuse_read_in *) inarg);
848 break;
849
850 case FUSE_WRITE:
851 do_write(f, in, (struct fuse_write_in *) inarg);
852 break;
853
854 default:
855 fprintf(stderr, "Operation %i not implemented\n", in->opcode);
Miklos Szeredi43696432001-11-18 19:15:05 +0000856 send_reply(f, in, -ENOSYS, NULL, 0);
Miklos Szeredia181e612001-11-06 12:03:23 +0000857 }
Miklos Szeredi43696432001-11-18 19:15:05 +0000858
859 free_cmd(cmd);
Miklos Szeredia181e612001-11-06 12:03:23 +0000860}
861
Miklos Szeredifff56ab2001-11-16 10:12:59 +0000862struct fuse_cmd *__fuse_read_cmd(struct fuse *f)
Miklos Szeredi2df1c042001-11-06 15:07:17 +0000863{
Miklos Szeredifff56ab2001-11-16 10:12:59 +0000864 ssize_t res;
Miklos Szeredifff56ab2001-11-16 10:12:59 +0000865 struct fuse_cmd *cmd;
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +0000866 struct fuse_in_header *in;
867 void *inarg;
Miklos Szeredifff56ab2001-11-16 10:12:59 +0000868
Miklos Szeredi43696432001-11-18 19:15:05 +0000869 cmd = (struct fuse_cmd *) malloc(sizeof(struct fuse_cmd));
870 cmd->buf = (char *) malloc(FUSE_MAX_IN);
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +0000871 in = (struct fuse_in_header *) cmd->buf;
872 inarg = cmd->buf + sizeof(struct fuse_in_header);
Miklos Szeredi43696432001-11-18 19:15:05 +0000873
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +0000874 do {
875 res = read(f->fd, cmd->buf, FUSE_MAX_IN);
876 if(res == -1) {
877 /* ENODEV means we got unmounted, so we silenty return failure */
878 if(errno != ENODEV) {
879 perror("fuse: reading device");
880 /* BAD... This will happen again */
881 }
882 free_cmd(cmd);
883 return NULL;
Miklos Szeredi96249982001-11-21 12:21:19 +0000884 }
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +0000885 if((size_t) res < sizeof(struct fuse_in_header)) {
886 fprintf(stderr, "short read on fuse device\n");
887 /* Cannot happen */
888 free_cmd(cmd);
889 return NULL;
890 }
891 cmd->buflen = res;
892
893 /* Forget is special, it can be done without messing with threads. */
894 if(in->opcode == FUSE_FORGET)
895 do_forget(f, in, (struct fuse_forget_in *) inarg);
896
897 } while(in->opcode == FUSE_FORGET);
898
Miklos Szeredifff56ab2001-11-16 10:12:59 +0000899 return cmd;
Miklos Szeredi2df1c042001-11-06 15:07:17 +0000900}
901
Miklos Szeredifff56ab2001-11-16 10:12:59 +0000902
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000903void fuse_loop(struct fuse *f)
904{
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000905 while(1) {
Miklos Szeredifff56ab2001-11-16 10:12:59 +0000906 struct fuse_cmd *cmd = __fuse_read_cmd(f);
907 if(cmd == NULL)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000908 exit(1);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000909
Miklos Szeredifff56ab2001-11-16 10:12:59 +0000910 __fuse_process_cmd(f, cmd);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000911 }
912}
913
Miklos Szeredi2e50d432001-12-20 12:17:25 +0000914struct fuse_context *fuse_get_context(struct fuse *f)
915{
916 if(f->getcontext)
917 return f->getcontext(f);
918 else
919 return &f->context;
920}
921
922struct fuse *fuse_new(int fd, int flags, const struct fuse_operations *op)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000923{
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000924 struct fuse *f;
925 struct node *root;
Miklos Szeredife428122001-11-20 19:12:28 +0000926 char verstr[128];
Miklos Szeredicc8c9752001-11-21 10:03:39 +0000927 char *realver = getenv(FUSE_KERNEL_VERSION_ENV);
Miklos Szeredife428122001-11-20 19:12:28 +0000928
929 if(realver != NULL) {
930 sprintf(verstr, "%i", FUSE_KERNEL_VERSION);
931 if(strcmp(verstr, realver) != 0) {
932 fprintf(stderr,
933 "Warning: FUSE version mismatch: using %s, kernel is %s\n",
934 realver, verstr);
935 }
936 }
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000937
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000938 f = (struct fuse *) calloc(1, sizeof(struct fuse));
Miklos Szeredi2df1c042001-11-06 15:07:17 +0000939
Miklos Szeredia181e612001-11-06 12:03:23 +0000940 f->flags = flags;
Miklos Szeredi8cffdb92001-11-09 14:49:18 +0000941 f->fd = fd;
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000942 f->ctr = 0;
Miklos Szeredifff56ab2001-11-16 10:12:59 +0000943 /* FIXME: Dynamic hash table */
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000944 f->name_table_size = 14057;
945 f->name_table = (struct node **)
946 calloc(1, sizeof(struct node *) * f->name_table_size);
947 f->ino_table_size = 14057;
948 f->ino_table = (struct node **)
949 calloc(1, sizeof(struct node *) * f->ino_table_size);
Miklos Szeredia181e612001-11-06 12:03:23 +0000950 pthread_mutex_init(&f->lock, NULL);
Miklos Szeredi33232032001-11-19 17:55:51 +0000951 f->numworker = 0;
952 f->numavail = 0;
Miklos Szeredi2e50d432001-12-20 12:17:25 +0000953 f->op = *op;
954 f->getcontext = NULL;
955 f->context.uid = 0;
956 f->context.gid = 0;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000957
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000958 root = (struct node *) calloc(1, sizeof(struct node));
Miklos Szeredi8cffdb92001-11-09 14:49:18 +0000959 root->mode = 0;
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000960 root->rdev = 0;
961 root->name = strdup("/");
962 root->parent = 0;
963 hash_ino(f, root, FUSE_ROOT_INO);
964
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000965 return f;
966}
967
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000968void fuse_destroy(struct fuse *f)
969{
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000970 size_t i;
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000971 for(i = 0; i < f->ino_table_size; i++) {
972 struct node *node;
973 struct node *next;
974 for(node = f->ino_table[i]; node != NULL; node = next) {
975 next = node->ino_next;
976 free_node(node);
977 }
978 }
979 free(f->ino_table);
980 free(f->name_table);
Miklos Szeredia181e612001-11-06 12:03:23 +0000981 pthread_mutex_destroy(&f->lock);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000982 free(f);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000983}