blob: 03f814c478139d8565cf1a6d442179f284229f26 [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
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) {
390 res = -ENOSYS;
391 if(f->op.getattr)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000392 res = f->op.getattr(path, &buf);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000393 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000394 }
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000395 if(res == 0) {
396 convert_stat(&buf, &arg.attr);
Miklos Szeredia181e612001-11-06 12:03:23 +0000397 arg.ino = find_node(f, in->ino, name, &arg.attr, in->unique);
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000398 }
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000399 send_reply(f, in, res, &arg, sizeof(arg));
400}
401
Miklos Szeredia181e612001-11-06 12:03:23 +0000402static void do_forget(struct fuse *f, struct fuse_in_header *in,
403 struct fuse_forget_in *arg)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000404{
Miklos Szeredi43696432001-11-18 19:15:05 +0000405 if(f->flags & FUSE_DEBUG) {
406 printf("FORGET %li/%i\n", in->ino, arg->version);
407 fflush(stdout);
408 }
Miklos Szeredia181e612001-11-06 12:03:23 +0000409 destroy_node(f, in->ino, arg->version);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000410}
411
412static void do_getattr(struct fuse *f, struct fuse_in_header *in)
413{
414 int res;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000415 char *path;
416 struct stat buf;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000417 struct fuse_getattr_out arg;
418
Miklos Szeredi5e183482001-10-31 14:52:35 +0000419 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000420 path = get_path(f, in->ino);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000421 if(path != NULL) {
422 res = -ENOSYS;
423 if(f->op.getattr)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000424 res = f->op.getattr(path, &buf);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000425 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000426 }
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000427 if(res == 0)
428 convert_stat(&buf, &arg.attr);
429
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000430 send_reply(f, in, res, &arg, sizeof(arg));
431}
432
Miklos Szeredi680a69a2001-11-16 13:31:14 +0000433static int do_chmod(struct fuse *f, const char *path, struct fuse_attr *attr)
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000434{
435 int res;
436
437 res = -ENOSYS;
438 if(f->op.chmod)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000439 res = f->op.chmod(path, attr->mode);
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000440
441 return res;
442}
443
Miklos Szeredi680a69a2001-11-16 13:31:14 +0000444static int do_chown(struct fuse *f, const char *path, struct fuse_attr *attr,
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000445 int valid)
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000446{
447 int res;
448 uid_t uid = (valid & FATTR_UID) ? attr->uid : (uid_t) -1;
449 gid_t gid = (valid & FATTR_GID) ? attr->gid : (gid_t) -1;
450
451 res = -ENOSYS;
452 if(f->op.chown)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000453 res = f->op.chown(path, uid, gid);
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000454
455 return res;
456}
457
Miklos Szeredi680a69a2001-11-16 13:31:14 +0000458static int do_truncate(struct fuse *f, const char *path,
459 struct fuse_attr *attr)
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000460{
461 int res;
462
463 res = -ENOSYS;
464 if(f->op.truncate)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000465 res = f->op.truncate(path, attr->size);
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000466
467 return res;
468}
469
Miklos Szeredi680a69a2001-11-16 13:31:14 +0000470static int do_utime(struct fuse *f, const char *path, struct fuse_attr *attr)
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000471{
472 int res;
473 struct utimbuf buf;
474 buf.actime = attr->atime;
475 buf.modtime = attr->mtime;
476 res = -ENOSYS;
477 if(f->op.utime)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000478 res = f->op.utime(path, &buf);
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000479
480 return res;
481}
482
Miklos Szeredi5e183482001-10-31 14:52:35 +0000483static void do_setattr(struct fuse *f, struct fuse_in_header *in,
484 struct fuse_setattr_in *arg)
485{
486 int res;
487 char *path;
488 int valid = arg->valid;
489 struct fuse_attr *attr = &arg->attr;
Miklos Szeredia181e612001-11-06 12:03:23 +0000490 struct fuse_setattr_out outarg;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000491
492 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000493 path = get_path(f, in->ino);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000494 if(path != NULL) {
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000495 res = -ENOSYS;
496 if(f->op.getattr) {
497 res = 0;
498 if(!res && (valid & FATTR_MODE))
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000499 res = do_chmod(f, path, attr);
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000500 if(!res && (valid & (FATTR_UID | FATTR_GID)))
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000501 res = do_chown(f, path, attr, valid);
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000502 if(!res && (valid & FATTR_SIZE))
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000503 res = do_truncate(f, path, attr);
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000504 if(!res && (valid & FATTR_UTIME))
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000505 res = do_utime(f, path, attr);
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000506 if(!res) {
507 struct stat buf;
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000508 res = f->op.getattr(path, &buf);
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000509 if(!res)
510 convert_stat(&buf, &outarg.attr);
Miklos Szeredia181e612001-11-06 12:03:23 +0000511 }
Miklos Szeredi5e183482001-10-31 14:52:35 +0000512 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000513 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000514 }
Miklos Szeredia181e612001-11-06 12:03:23 +0000515 send_reply(f, in, res, &outarg, sizeof(outarg));
Miklos Szeredi5e183482001-10-31 14:52:35 +0000516}
517
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000518static void do_readlink(struct fuse *f, struct fuse_in_header *in)
519{
520 int res;
521 char link[PATH_MAX + 1];
Miklos Szeredib483c932001-10-29 14:57:57 +0000522 char *path;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000523
Miklos Szeredi5e183482001-10-31 14:52:35 +0000524 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000525 path = get_path(f, in->ino);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000526 if(path != NULL) {
527 res = -ENOSYS;
528 if(f->op.readlink)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000529 res = f->op.readlink(path, link, sizeof(link));
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000530 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000531 }
Miklos Szeredi2df1c042001-11-06 15:07:17 +0000532 link[PATH_MAX] = '\0';
Miklos Szeredi5e183482001-10-31 14:52:35 +0000533 send_reply(f, in, res, link, !res ? strlen(link) : 0);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000534}
535
536static void do_getdir(struct fuse *f, struct fuse_in_header *in)
537{
538 int res;
539 struct fuse_getdir_out arg;
Miklos Szeredia181e612001-11-06 12:03:23 +0000540 struct fuse_dirhandle dh;
Miklos Szeredib483c932001-10-29 14:57:57 +0000541 char *path;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000542
Miklos Szeredib483c932001-10-29 14:57:57 +0000543 dh.fuse = f;
544 dh.fp = tmpfile();
545 dh.dir = in->ino;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000546 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000547 path = get_path(f, in->ino);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000548 if(path != NULL) {
549 res = -ENOSYS;
550 if(f->op.getdir)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000551 res = f->op.getdir(path, &dh, (fuse_dirfil_t) fill_dir);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000552 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000553 }
Miklos Szeredib483c932001-10-29 14:57:57 +0000554 fflush(dh.fp);
555 arg.fd = fileno(dh.fp);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000556 send_reply(f, in, res, &arg, sizeof(arg));
Miklos Szeredib483c932001-10-29 14:57:57 +0000557 fclose(dh.fp);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000558}
559
Miklos Szeredib483c932001-10-29 14:57:57 +0000560static void do_mknod(struct fuse *f, struct fuse_in_header *in,
561 struct fuse_mknod_in *inarg)
562{
563 int res;
564 char *path;
565 struct fuse_mknod_out outarg;
566 struct stat buf;
567
Miklos Szeredi5e183482001-10-31 14:52:35 +0000568 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000569 path = get_path_name(f, in->ino, inarg->name);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000570 if(path != NULL) {
571 res = -ENOSYS;
572 if(f->op.mknod && f->op.getattr) {
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000573 res = f->op.mknod(path, inarg->mode, inarg->rdev);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000574 if(res == 0)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000575 res = f->op.getattr(path, &buf);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000576 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000577 free(path);
Miklos Szeredib483c932001-10-29 14:57:57 +0000578 }
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000579 if(res == 0) {
Miklos Szeredib483c932001-10-29 14:57:57 +0000580 convert_stat(&buf, &outarg.attr);
Miklos Szeredia181e612001-11-06 12:03:23 +0000581 outarg.ino = find_node(f, in->ino, inarg->name, &outarg.attr,
582 in->unique);
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000583 }
Miklos Szeredib483c932001-10-29 14:57:57 +0000584
585 send_reply(f, in, res, &outarg, sizeof(outarg));
586}
587
588static void do_mkdir(struct fuse *f, struct fuse_in_header *in,
589 struct fuse_mkdir_in *inarg)
590{
591 int res;
592 char *path;
593
Miklos Szeredi5e183482001-10-31 14:52:35 +0000594 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000595 path = get_path_name(f, in->ino, inarg->name);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000596 if(path != NULL) {
597 res = -ENOSYS;
598 if(f->op.mkdir)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000599 res = f->op.mkdir(path, inarg->mode);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000600 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000601 }
Miklos Szeredib483c932001-10-29 14:57:57 +0000602 send_reply(f, in, res, NULL, 0);
603}
604
605static void do_remove(struct fuse *f, struct fuse_in_header *in, char *name)
606{
607 int res;
608 char *path;
609
Miklos Szeredi5e183482001-10-31 14:52:35 +0000610 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000611 path = get_path_name(f, in->ino, name);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000612 if(path != NULL) {
613 res = -ENOSYS;
614 if(in->opcode == FUSE_UNLINK) {
615 if(f->op.unlink)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000616 res = f->op.unlink(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000617 }
618 else {
619 if(f->op.rmdir)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000620 res = f->op.rmdir(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000621 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000622 free(path);
Miklos Szeredib483c932001-10-29 14:57:57 +0000623 }
Miklos Szeredi5e183482001-10-31 14:52:35 +0000624 if(res == 0)
625 remove_node(f, in->ino, name);
Miklos Szeredib483c932001-10-29 14:57:57 +0000626 send_reply(f, in, res, NULL, 0);
627}
628
629static void do_symlink(struct fuse *f, struct fuse_in_header *in, char *name,
630 char *link)
631{
632 int res;
633 char *path;
634
Miklos Szeredi5e183482001-10-31 14:52:35 +0000635 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000636 path = get_path_name(f, in->ino, name);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000637 if(path != NULL) {
638 res = -ENOSYS;
639 if(f->op.symlink)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000640 res = f->op.symlink(link, path);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000641 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000642 }
Miklos Szeredib483c932001-10-29 14:57:57 +0000643 send_reply(f, in, res, NULL, 0);
644}
645
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000646static void do_rename(struct fuse *f, struct fuse_in_header *in,
647 struct fuse_rename_in *inarg)
648{
649 int res;
650 fino_t olddir = in->ino;
651 fino_t newdir = inarg->newdir;
652 char *oldname = inarg->names;
653 char *newname = inarg->names + strlen(oldname) + 1;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000654 char *oldpath;
655 char *newpath;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000656
Miklos Szeredi5e183482001-10-31 14:52:35 +0000657 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000658 oldpath = get_path_name(f, olddir, oldname);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000659 if(oldpath != NULL) {
Miklos Szeredia181e612001-11-06 12:03:23 +0000660 newpath = get_path_name(f, newdir, newname);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000661 if(newpath != NULL) {
662 res = -ENOSYS;
663 if(f->op.rename)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000664 res = f->op.rename(oldpath, newpath);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000665 if(res == 0)
666 rename_node(f, olddir, oldname, newdir, newname);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000667 free(newpath);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000668 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000669 free(oldpath);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000670 }
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000671 send_reply(f, in, res, NULL, 0);
672}
673
674static void do_link(struct fuse *f, struct fuse_in_header *in,
Miklos Szeredi5e183482001-10-31 14:52:35 +0000675 struct fuse_link_in *arg)
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000676{
677 int res;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000678 char *oldpath;
679 char *newpath;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000680
Miklos Szeredi5e183482001-10-31 14:52:35 +0000681 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000682 oldpath = get_path(f, in->ino);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000683 if(oldpath != NULL) {
Miklos Szeredia181e612001-11-06 12:03:23 +0000684 newpath = get_path_name(f, arg->newdir, arg->name);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000685 if(newpath != NULL) {
686 res = -ENOSYS;
687 if(f->op.link)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000688 res = f->op.link(oldpath, newpath);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000689 free(newpath);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000690 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000691 free(oldpath);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000692 }
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000693 send_reply(f, in, res, NULL, 0);
694}
695
Miklos Szeredi5e183482001-10-31 14:52:35 +0000696static void do_open(struct fuse *f, struct fuse_in_header *in,
697 struct fuse_open_in *arg)
698{
699 int res;
700 char *path;
701
702 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000703 path = get_path(f, in->ino);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000704 if(path != NULL) {
705 res = -ENOSYS;
706 if(f->op.open)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000707 res = f->op.open(path, arg->flags);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000708 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000709 }
710 send_reply(f, in, res, NULL, 0);
711}
712
713static void do_read(struct fuse *f, struct fuse_in_header *in,
714 struct fuse_read_in *arg)
715{
716 int res;
717 char *path;
Miklos Szeredi43696432001-11-18 19:15:05 +0000718 char *outbuf = (char *) malloc(sizeof(struct fuse_out_header) + arg->size);
719 struct fuse_out_header *out = (struct fuse_out_header *) outbuf;
720 char *buf = outbuf + sizeof(struct fuse_out_header);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000721 size_t size;
Miklos Szeredi43696432001-11-18 19:15:05 +0000722 size_t outsize;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000723
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000724 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000725 path = get_path(f, in->ino);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000726 if(path != NULL) {
727 res = -ENOSYS;
Miklos Szeredia181e612001-11-06 12:03:23 +0000728 if(f->op.read)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000729 res = f->op.read(path, buf, arg->size, arg->offset);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000730 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000731 }
732
733 size = 0;
734 if(res > 0) {
735 size = res;
736 res = 0;
737 }
Miklos Szeredi43696432001-11-18 19:15:05 +0000738 out->unique = in->unique;
739 out->error = res;
740 outsize = sizeof(struct fuse_out_header) + size;
741
742 send_reply_raw(f, outbuf, outsize);
743 free(outbuf);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000744}
Miklos Szeredib483c932001-10-29 14:57:57 +0000745
Miklos Szeredia181e612001-11-06 12:03:23 +0000746static void do_write(struct fuse *f, struct fuse_in_header *in,
747 struct fuse_write_in *arg)
748{
749 int res;
750 char *path;
Miklos Szeredia181e612001-11-06 12:03:23 +0000751
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000752 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000753 path = get_path(f, in->ino);
754 if(path != NULL) {
755 res = -ENOSYS;
756 if(f->op.write)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000757 res = f->op.write(path, arg->buf, arg->size, arg->offset);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000758 free(path);
Miklos Szeredia181e612001-11-06 12:03:23 +0000759 }
760
761 if(res > 0) {
762 if((size_t) res != arg->size) {
763 fprintf(stderr, "short write: %u (should be %u)\n", res,
764 arg->size);
765 res = -EIO;
766 }
767 else
768 res = 0;
769 }
770
771 send_reply(f, in, res, NULL, 0);
772}
773
Miklos Szeredi43696432001-11-18 19:15:05 +0000774static void free_cmd(struct fuse_cmd *cmd)
775{
776 free(cmd->buf);
777 free(cmd);
778}
779
Miklos Szeredifff56ab2001-11-16 10:12:59 +0000780void __fuse_process_cmd(struct fuse *f, struct fuse_cmd *cmd)
Miklos Szeredia181e612001-11-06 12:03:23 +0000781{
Miklos Szeredia181e612001-11-06 12:03:23 +0000782 struct fuse_in_header *in = (struct fuse_in_header *) cmd->buf;
783 void *inarg = cmd->buf + sizeof(struct fuse_in_header);
784 size_t argsize;
Miklos Szeredia181e612001-11-06 12:03:23 +0000785
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +0000786 dec_avail(f);
Miklos Szeredi33232032001-11-19 17:55:51 +0000787
Miklos Szeredic0938ea2001-11-07 12:35:06 +0000788 if((f->flags & FUSE_DEBUG)) {
789 printf("unique: %i, opcode: %i, ino: %li, insize: %i\n", in->unique,
790 in->opcode, in->ino, cmd->buflen);
791 fflush(stdout);
792 }
Miklos Szeredia181e612001-11-06 12:03:23 +0000793
794 argsize = cmd->buflen - sizeof(struct fuse_in_header);
795
796 switch(in->opcode) {
797 case FUSE_LOOKUP:
798 do_lookup(f, in, (char *) inarg);
799 break;
800
Miklos Szeredia181e612001-11-06 12:03:23 +0000801 case FUSE_GETATTR:
802 do_getattr(f, in);
803 break;
804
805 case FUSE_SETATTR:
806 do_setattr(f, in, (struct fuse_setattr_in *) inarg);
807 break;
808
809 case FUSE_READLINK:
810 do_readlink(f, in);
811 break;
812
813 case FUSE_GETDIR:
814 do_getdir(f, in);
815 break;
816
817 case FUSE_MKNOD:
818 do_mknod(f, in, (struct fuse_mknod_in *) inarg);
819 break;
820
821 case FUSE_MKDIR:
822 do_mkdir(f, in, (struct fuse_mkdir_in *) inarg);
823 break;
824
825 case FUSE_UNLINK:
826 case FUSE_RMDIR:
827 do_remove(f, in, (char *) inarg);
828 break;
829
830 case FUSE_SYMLINK:
831 do_symlink(f, in, (char *) inarg,
832 ((char *) inarg) + strlen((char *) inarg) + 1);
833 break;
834
835 case FUSE_RENAME:
836 do_rename(f, in, (struct fuse_rename_in *) inarg);
837 break;
838
839 case FUSE_LINK:
840 do_link(f, in, (struct fuse_link_in *) inarg);
841 break;
842
843 case FUSE_OPEN:
844 do_open(f, in, (struct fuse_open_in *) inarg);
845 break;
846
847 case FUSE_READ:
848 do_read(f, in, (struct fuse_read_in *) inarg);
849 break;
850
851 case FUSE_WRITE:
852 do_write(f, in, (struct fuse_write_in *) inarg);
853 break;
854
855 default:
856 fprintf(stderr, "Operation %i not implemented\n", in->opcode);
Miklos Szeredi43696432001-11-18 19:15:05 +0000857 send_reply(f, in, -ENOSYS, NULL, 0);
Miklos Szeredia181e612001-11-06 12:03:23 +0000858 }
Miklos Szeredi43696432001-11-18 19:15:05 +0000859
860 free_cmd(cmd);
Miklos Szeredia181e612001-11-06 12:03:23 +0000861}
862
Miklos Szeredifff56ab2001-11-16 10:12:59 +0000863struct fuse_cmd *__fuse_read_cmd(struct fuse *f)
Miklos Szeredi2df1c042001-11-06 15:07:17 +0000864{
Miklos Szeredifff56ab2001-11-16 10:12:59 +0000865 ssize_t res;
Miklos Szeredifff56ab2001-11-16 10:12:59 +0000866 struct fuse_cmd *cmd;
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +0000867 struct fuse_in_header *in;
868 void *inarg;
Miklos Szeredifff56ab2001-11-16 10:12:59 +0000869
Miklos Szeredi43696432001-11-18 19:15:05 +0000870 cmd = (struct fuse_cmd *) malloc(sizeof(struct fuse_cmd));
871 cmd->buf = (char *) malloc(FUSE_MAX_IN);
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +0000872 in = (struct fuse_in_header *) cmd->buf;
873 inarg = cmd->buf + sizeof(struct fuse_in_header);
Miklos Szeredi43696432001-11-18 19:15:05 +0000874
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +0000875 do {
876 res = read(f->fd, cmd->buf, FUSE_MAX_IN);
877 if(res == -1) {
878 /* ENODEV means we got unmounted, so we silenty return failure */
879 if(errno != ENODEV) {
880 perror("fuse: reading device");
881 /* BAD... This will happen again */
882 }
883 free_cmd(cmd);
884 return NULL;
Miklos Szeredi96249982001-11-21 12:21:19 +0000885 }
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +0000886 if((size_t) res < sizeof(struct fuse_in_header)) {
887 fprintf(stderr, "short read on fuse device\n");
888 /* Cannot happen */
889 free_cmd(cmd);
890 return NULL;
891 }
892 cmd->buflen = res;
893
894 /* Forget is special, it can be done without messing with threads. */
895 if(in->opcode == FUSE_FORGET)
896 do_forget(f, in, (struct fuse_forget_in *) inarg);
897
898 } while(in->opcode == FUSE_FORGET);
899
Miklos Szeredifff56ab2001-11-16 10:12:59 +0000900 return cmd;
Miklos Szeredi2df1c042001-11-06 15:07:17 +0000901}
902
Miklos Szeredifff56ab2001-11-16 10:12:59 +0000903
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000904void fuse_loop(struct fuse *f)
905{
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000906 while(1) {
Miklos Szeredifff56ab2001-11-16 10:12:59 +0000907 struct fuse_cmd *cmd = __fuse_read_cmd(f);
908 if(cmd == NULL)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000909 exit(1);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000910
Miklos Szeredifff56ab2001-11-16 10:12:59 +0000911 __fuse_process_cmd(f, cmd);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000912 }
913}
914
Miklos Szeredi8cffdb92001-11-09 14:49:18 +0000915struct fuse *fuse_new(int fd, int flags)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000916{
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000917 struct fuse *f;
918 struct node *root;
Miklos Szeredife428122001-11-20 19:12:28 +0000919 char verstr[128];
Miklos Szeredicc8c9752001-11-21 10:03:39 +0000920 char *realver = getenv(FUSE_KERNEL_VERSION_ENV);
Miklos Szeredife428122001-11-20 19:12:28 +0000921
922 if(realver != NULL) {
923 sprintf(verstr, "%i", FUSE_KERNEL_VERSION);
924 if(strcmp(verstr, realver) != 0) {
925 fprintf(stderr,
926 "Warning: FUSE version mismatch: using %s, kernel is %s\n",
927 realver, verstr);
928 }
929 }
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000930
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000931 f = (struct fuse *) calloc(1, sizeof(struct fuse));
Miklos Szeredi2df1c042001-11-06 15:07:17 +0000932
Miklos Szeredia181e612001-11-06 12:03:23 +0000933 f->flags = flags;
Miklos Szeredi8cffdb92001-11-09 14:49:18 +0000934 f->fd = fd;
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000935 f->ctr = 0;
Miklos Szeredifff56ab2001-11-16 10:12:59 +0000936 /* FIXME: Dynamic hash table */
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000937 f->name_table_size = 14057;
938 f->name_table = (struct node **)
939 calloc(1, sizeof(struct node *) * f->name_table_size);
940 f->ino_table_size = 14057;
941 f->ino_table = (struct node **)
942 calloc(1, sizeof(struct node *) * f->ino_table_size);
Miklos Szeredia181e612001-11-06 12:03:23 +0000943 pthread_mutex_init(&f->lock, NULL);
Miklos Szeredi33232032001-11-19 17:55:51 +0000944 f->numworker = 0;
945 f->numavail = 0;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000946
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000947 root = (struct node *) calloc(1, sizeof(struct node));
Miklos Szeredi8cffdb92001-11-09 14:49:18 +0000948 root->mode = 0;
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000949 root->rdev = 0;
950 root->name = strdup("/");
951 root->parent = 0;
952 hash_ino(f, root, FUSE_ROOT_INO);
953
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000954 return f;
955}
956
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000957void fuse_set_operations(struct fuse *f, const struct fuse_operations *op)
958{
959 f->op = *op;
960}
961
962void fuse_destroy(struct fuse *f)
963{
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000964 size_t i;
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000965 for(i = 0; i < f->ino_table_size; i++) {
966 struct node *node;
967 struct node *next;
968 for(node = f->ino_table[i]; node != NULL; node = next) {
969 next = node->ino_next;
970 free_node(node);
971 }
972 }
973 free(f->ino_table);
974 free(f->name_table);
Miklos Szeredia181e612001-11-06 12:03:23 +0000975 pthread_mutex_destroy(&f->lock);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000976 free(f);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000977}