blob: ab10df5973c2a905747979c60de3d764d348aa60 [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 Szeredi97c61e92001-11-07 12:09:43 +000022static struct node *__get_node(struct fuse *f, fino_t ino)
Miklos Szeredia181e612001-11-06 12:03:23 +000023{
Miklos Szeredi97c61e92001-11-07 12:09:43 +000024 size_t hash = ino % f->ino_table_size;
25 struct node *node;
26
27 for(node = f->ino_table[hash]; node != NULL; node = node->ino_next)
28 if(node->ino == ino)
29 return node;
30
31 return NULL;
Miklos Szeredia181e612001-11-06 12:03:23 +000032}
33
Miklos Szeredi97c61e92001-11-07 12:09:43 +000034static struct node *get_node(struct fuse *f, fino_t ino)
Miklos Szeredia181e612001-11-06 12:03:23 +000035{
Miklos Szeredi97c61e92001-11-07 12:09:43 +000036 struct node *node = __get_node(f, ino);
37 if(node != NULL)
38 return node;
39
40 fprintf(stderr, "fuse internal error: inode %lu not found\n", ino);
41 abort();
Miklos Szeredia181e612001-11-06 12:03:23 +000042}
43
Miklos Szeredi97c61e92001-11-07 12:09:43 +000044static void hash_ino(struct fuse *f, struct node *node, fino_t ino)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000045{
Miklos Szeredi97c61e92001-11-07 12:09:43 +000046 size_t hash = ino % f->ino_table_size;
47 node->ino = ino;
48
49 node->ino_next = f->ino_table[hash];
50 f->ino_table[hash] = node;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000051}
52
Miklos Szeredi97c61e92001-11-07 12:09:43 +000053static void unhash_ino(struct fuse *f, struct node *node)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000054{
Miklos Szeredi97c61e92001-11-07 12:09:43 +000055 size_t hash = node->ino % f->ino_table_size;
56 struct node **nodep = &f->ino_table[hash];
57
58 for(; *nodep != NULL; nodep = &(*nodep)->ino_next)
59 if(*nodep == node) {
60 *nodep = node->ino_next;
61 return;
62 }
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000063}
64
Miklos Szeredi97c61e92001-11-07 12:09:43 +000065static fino_t get_ino(struct node *node)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000066{
Miklos Szeredi97c61e92001-11-07 12:09:43 +000067 return node->ino;
68}
69
70static fino_t next_ino(struct fuse *f)
71{
72 while(f->ctr == 0 || __get_node(f, f->ctr) != NULL)
73 f->ctr++;
74
75 return f->ctr;
76}
77
78static void free_node(struct node *node)
79{
80 free(node->name);
81 free(node);
82}
83
84static unsigned int name_hash(struct fuse *f, fino_t parent, const char *name)
85{
86 unsigned int hash = *name;
87
88 if(hash)
89 for(name += 1; *name != '\0'; name++)
90 hash = (hash << 5) - hash + *name;
91
92 return (hash + parent) % f->name_table_size;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000093}
94
Miklos Szeredi19dff1b2001-10-30 15:06:52 +000095static struct node *lookup_node(struct fuse *f, fino_t parent,
96 const char *name)
97{
Miklos Szeredi97c61e92001-11-07 12:09:43 +000098 size_t hash = name_hash(f, parent, name);
99 struct node *node;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000100
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000101 for(node = f->name_table[hash]; node != NULL; node = node->name_next)
102 if(node->parent == parent && strcmp(node->name, name) == 0)
103 return node;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000104
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000105 return NULL;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000106}
107
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000108static void hash_name(struct fuse *f, struct node *node, fino_t parent,
Miklos Szeredia181e612001-11-06 12:03:23 +0000109 const char *name)
Miklos Szeredi5e183482001-10-31 14:52:35 +0000110{
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000111 size_t hash = name_hash(f, parent, name);
Miklos Szeredia181e612001-11-06 12:03:23 +0000112 node->parent = parent;
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000113 node->name = strdup(name);
114 node->name_next = f->name_table[hash];
115 f->name_table[hash] = node;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000116}
117
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000118static void unhash_name(struct fuse *f, struct node *node)
Miklos Szeredia181e612001-11-06 12:03:23 +0000119{
120 if(node->name != NULL) {
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000121 size_t hash = name_hash(f, node->parent, node->name);
122 struct node **nodep = &f->name_table[hash];
123
124 for(; *nodep != NULL; nodep = &(*nodep)->name_next)
125 if(*nodep == node) {
126 *nodep = node->name_next;
127 node->name_next = NULL;
128 free(node->name);
129 node->name = NULL;
130 node->parent = 0;
131 return;
132 }
133 fprintf(stderr, "fuse internal error: unable to unhash node: %lu\n",
134 node->ino);
135 abort();
Miklos Szeredia181e612001-11-06 12:03:23 +0000136 }
137}
138
139static fino_t find_node(struct fuse *f, fino_t parent, char *name,
140 struct fuse_attr *attr, int version)
Miklos Szeredi5e183482001-10-31 14:52:35 +0000141{
142 struct node *node;
Miklos Szeredia181e612001-11-06 12:03:23 +0000143 int mode = attr->mode & S_IFMT;
144 int rdev = 0;
145
146 if(S_ISCHR(mode) || S_ISBLK(mode))
147 rdev = attr->rdev;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000148
Miklos Szeredia181e612001-11-06 12:03:23 +0000149 pthread_mutex_lock(&f->lock);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000150 node = lookup_node(f, parent, name);
151 if(node != NULL) {
Miklos Szeredia181e612001-11-06 12:03:23 +0000152 if(node->mode == mode && node->rdev == rdev)
153 goto out;
154
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000155 unhash_name(f, node);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000156 }
157
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000158 node = (struct node *) calloc(1, sizeof(struct node));
Miklos Szeredia181e612001-11-06 12:03:23 +0000159 node->mode = mode;
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000160 node->rdev = rdev;
161 hash_ino(f, node, next_ino(f));
162 hash_name(f, node, parent, name);
Miklos Szeredia181e612001-11-06 12:03:23 +0000163
164 out:
165 node->version = version;
166 pthread_mutex_unlock(&f->lock);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000167 return get_ino(node);
168}
169
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000170static char *add_name(char *buf, char *s, const char *name)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000171{
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000172 size_t len = strlen(name);
173 s -= len;
174 if(s <= buf) {
175 fprintf(stderr, "fuse: path too long: ...%s\n", s + len);
176 return NULL;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000177 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000178 strncpy(s, name, len);
179 s--;
180 *s = '/';
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000181
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000182 return s;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000183}
184
Miklos Szeredia181e612001-11-06 12:03:23 +0000185static char *get_path_name(struct fuse *f, fino_t ino, const char *name)
Miklos Szeredib483c932001-10-29 14:57:57 +0000186{
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000187 char buf[FUSE_MAX_PATH];
188 char *s = buf + FUSE_MAX_PATH - 1;
189 struct node *node;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000190
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000191 *s = '\0';
Miklos Szeredia181e612001-11-06 12:03:23 +0000192
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000193 if(name != NULL) {
194 s = add_name(buf, s, name);
195 if(s == NULL)
196 return NULL;
197 }
198
199 pthread_mutex_lock(&f->lock);
200 for(node = get_node(f, ino); node->ino != FUSE_ROOT_INO;
201 node = get_node(f, node->parent)) {
202 if(node->name == NULL) {
203 s = NULL;
204 break;
205 }
206
207 s = add_name(buf, s, node->name);
208 if(s == NULL)
209 break;
210 }
211 pthread_mutex_unlock(&f->lock);
212
213 if(s == NULL)
Miklos Szeredi5e183482001-10-31 14:52:35 +0000214 return NULL;
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000215 else if(*s == '\0')
216 return strdup("/");
217 else
218 return strdup(s);
219}
Miklos Szeredia181e612001-11-06 12:03:23 +0000220
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000221static char *get_path(struct fuse *f, fino_t ino)
222{
223 return get_path_name(f, ino, NULL);
Miklos Szeredib483c932001-10-29 14:57:57 +0000224}
225
Miklos Szeredia181e612001-11-06 12:03:23 +0000226static void destroy_node(struct fuse *f, fino_t ino, int version)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000227{
Miklos Szeredia181e612001-11-06 12:03:23 +0000228 struct node *node;
229
230 pthread_mutex_lock(&f->lock);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000231 node = get_node(f, ino);
Miklos Szeredi39f28672001-11-14 14:52:54 +0000232 if(node->version == version && ino != FUSE_ROOT_INO) {
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000233 unhash_name(f, node);
234 unhash_ino(f, node);
Miklos Szeredia181e612001-11-06 12:03:23 +0000235 free_node(node);
236 }
237 pthread_mutex_unlock(&f->lock);
238
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000239}
240
Miklos Szeredi5e183482001-10-31 14:52:35 +0000241static void remove_node(struct fuse *f, fino_t dir, const char *name)
242{
Miklos Szeredia181e612001-11-06 12:03:23 +0000243 struct node *node;
244
245 pthread_mutex_lock(&f->lock);
246 node = lookup_node(f, dir, name);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000247 if(node == NULL) {
248 fprintf(stderr, "fuse internal error: unable to remove node %lu/%s\n",
249 dir, name);
250 abort();
251 }
252 unhash_name(f, node);
Miklos Szeredia181e612001-11-06 12:03:23 +0000253 pthread_mutex_unlock(&f->lock);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000254}
255
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000256static void rename_node(struct fuse *f, fino_t olddir, const char *oldname,
257 fino_t newdir, const char *newname)
258{
Miklos Szeredia181e612001-11-06 12:03:23 +0000259 struct node *node;
260 struct node *newnode;
261
262 pthread_mutex_lock(&f->lock);
263 node = lookup_node(f, olddir, oldname);
264 newnode = lookup_node(f, newdir, newname);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000265 if(node == NULL) {
266 fprintf(stderr, "fuse internal error: unable to rename node %lu/%s\n",
267 olddir, oldname);
268 abort();
269 }
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000270
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000271 if(newnode != NULL)
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000272 unhash_name(f, newnode);
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000273
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000274 unhash_name(f, node);
275 hash_name(f, node, newdir, newname);
Miklos Szeredia181e612001-11-06 12:03:23 +0000276 pthread_mutex_unlock(&f->lock);
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000277}
278
279
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000280static void convert_stat(struct stat *stbuf, struct fuse_attr *attr)
281{
282 attr->mode = stbuf->st_mode;
283 attr->nlink = stbuf->st_nlink;
284 attr->uid = stbuf->st_uid;
285 attr->gid = stbuf->st_gid;
286 attr->rdev = stbuf->st_rdev;
287 attr->size = stbuf->st_size;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000288 attr->blocks = stbuf->st_blocks;
289 attr->atime = stbuf->st_atime;
290 attr->mtime = stbuf->st_mtime;
291 attr->ctime = stbuf->st_ctime;
Miklos Szeredifff56ab2001-11-16 10:12:59 +0000292 attr->_dummy = 4096;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000293}
294
Miklos Szeredia181e612001-11-06 12:03:23 +0000295static int fill_dir(struct fuse_dirhandle *dh, char *name, int type)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000296{
297 struct fuse_dirent dirent;
298 size_t reclen;
299 size_t res;
300
Miklos Szeredi43696432001-11-18 19:15:05 +0000301 dirent.ino = (unsigned long) -1;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000302 dirent.namelen = strlen(name);
303 strncpy(dirent.name, name, sizeof(dirent.name));
304 dirent.type = type;
305 reclen = FUSE_DIRENT_SIZE(&dirent);
306 res = fwrite(&dirent, reclen, 1, dh->fp);
307 if(res == 0) {
Miklos Szeredi96249982001-11-21 12:21:19 +0000308 perror("fuse: writing directory file");
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000309 return -EIO;
310 }
311 return 0;
312}
313
Miklos Szeredi43696432001-11-18 19:15:05 +0000314static void send_reply_raw(struct fuse *f, char *outbuf, size_t outsize)
315{
316 int res;
317
318 if((f->flags & FUSE_DEBUG)) {
319 struct fuse_out_header *out = (struct fuse_out_header *) outbuf;
320 printf(" unique: %i, error: %i (%s), outsize: %i\n", out->unique,
321 out->error, strerror(-out->error), outsize);
322 fflush(stdout);
323 }
Miklos Szeredi33232032001-11-19 17:55:51 +0000324
325 pthread_mutex_lock(&f->lock);
326 f->numavail ++;
327 pthread_mutex_unlock(&f->lock);
328
Miklos Szeredi43696432001-11-18 19:15:05 +0000329 res = write(f->fd, outbuf, outsize);
330 if(res == -1) {
331 /* ENOENT means the operation was interrupted */
332 if(errno != ENOENT)
Miklos Szeredi96249982001-11-21 12:21:19 +0000333 perror("fuse: writing device");
Miklos Szeredi43696432001-11-18 19:15:05 +0000334 }
335}
336
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000337static void send_reply(struct fuse *f, struct fuse_in_header *in, int error,
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000338 void *arg, size_t argsize)
339{
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000340 char *outbuf;
341 size_t outsize;
342 struct fuse_out_header *out;
343
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000344 if(error > 0) {
Miklos Szeredi96249982001-11-21 12:21:19 +0000345 fprintf(stderr, "fuse: positive error code: %i\n", error);
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000346 error = -ERANGE;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000347 }
348
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000349 if(error)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000350 argsize = 0;
351
352 outsize = sizeof(struct fuse_out_header) + argsize;
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000353 outbuf = (char *) malloc(outsize);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000354 out = (struct fuse_out_header *) outbuf;
355 out->unique = in->unique;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000356 out->error = error;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000357 if(argsize != 0)
358 memcpy(outbuf + sizeof(struct fuse_out_header), arg, argsize);
359
Miklos Szeredi43696432001-11-18 19:15:05 +0000360 send_reply_raw(f, outbuf, outsize);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000361
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000362 free(outbuf);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000363}
364
365static void do_lookup(struct fuse *f, struct fuse_in_header *in, char *name)
366{
367 int res;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000368 char *path;
369 struct stat buf;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000370 struct fuse_lookup_out arg;
371
Miklos Szeredi5e183482001-10-31 14:52:35 +0000372 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000373 path = get_path_name(f, in->ino, name);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000374 if(path != NULL) {
375 res = -ENOSYS;
376 if(f->op.getattr)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000377 res = f->op.getattr(path, &buf);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000378 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000379 }
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000380 if(res == 0) {
381 convert_stat(&buf, &arg.attr);
Miklos Szeredia181e612001-11-06 12:03:23 +0000382 arg.ino = find_node(f, in->ino, name, &arg.attr, in->unique);
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000383 }
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000384 send_reply(f, in, res, &arg, sizeof(arg));
385}
386
Miklos Szeredia181e612001-11-06 12:03:23 +0000387static void do_forget(struct fuse *f, struct fuse_in_header *in,
388 struct fuse_forget_in *arg)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000389{
Miklos Szeredi43696432001-11-18 19:15:05 +0000390 if(f->flags & FUSE_DEBUG) {
391 printf("FORGET %li/%i\n", in->ino, arg->version);
392 fflush(stdout);
393 }
Miklos Szeredia181e612001-11-06 12:03:23 +0000394 destroy_node(f, in->ino, arg->version);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000395}
396
397static void do_getattr(struct fuse *f, struct fuse_in_header *in)
398{
399 int res;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000400 char *path;
401 struct stat buf;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000402 struct fuse_getattr_out arg;
403
Miklos Szeredi5e183482001-10-31 14:52:35 +0000404 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000405 path = get_path(f, in->ino);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000406 if(path != NULL) {
407 res = -ENOSYS;
408 if(f->op.getattr)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000409 res = f->op.getattr(path, &buf);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000410 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000411 }
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000412 if(res == 0)
413 convert_stat(&buf, &arg.attr);
414
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000415 send_reply(f, in, res, &arg, sizeof(arg));
416}
417
Miklos Szeredi680a69a2001-11-16 13:31:14 +0000418static int do_chmod(struct fuse *f, const char *path, struct fuse_attr *attr)
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000419{
420 int res;
421
422 res = -ENOSYS;
423 if(f->op.chmod)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000424 res = f->op.chmod(path, attr->mode);
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000425
426 return res;
427}
428
Miklos Szeredi680a69a2001-11-16 13:31:14 +0000429static int do_chown(struct fuse *f, const char *path, struct fuse_attr *attr,
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000430 int valid)
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000431{
432 int res;
433 uid_t uid = (valid & FATTR_UID) ? attr->uid : (uid_t) -1;
434 gid_t gid = (valid & FATTR_GID) ? attr->gid : (gid_t) -1;
435
436 res = -ENOSYS;
437 if(f->op.chown)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000438 res = f->op.chown(path, uid, gid);
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000439
440 return res;
441}
442
Miklos Szeredi680a69a2001-11-16 13:31:14 +0000443static int do_truncate(struct fuse *f, const char *path,
444 struct fuse_attr *attr)
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000445{
446 int res;
447
448 res = -ENOSYS;
449 if(f->op.truncate)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000450 res = f->op.truncate(path, attr->size);
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000451
452 return res;
453}
454
Miklos Szeredi680a69a2001-11-16 13:31:14 +0000455static int do_utime(struct fuse *f, const char *path, struct fuse_attr *attr)
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000456{
457 int res;
458 struct utimbuf buf;
459 buf.actime = attr->atime;
460 buf.modtime = attr->mtime;
461 res = -ENOSYS;
462 if(f->op.utime)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000463 res = f->op.utime(path, &buf);
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000464
465 return res;
466}
467
Miklos Szeredi5e183482001-10-31 14:52:35 +0000468static void do_setattr(struct fuse *f, struct fuse_in_header *in,
469 struct fuse_setattr_in *arg)
470{
471 int res;
472 char *path;
473 int valid = arg->valid;
474 struct fuse_attr *attr = &arg->attr;
Miklos Szeredia181e612001-11-06 12:03:23 +0000475 struct fuse_setattr_out outarg;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000476
477 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000478 path = get_path(f, in->ino);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000479 if(path != NULL) {
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000480 res = -ENOSYS;
481 if(f->op.getattr) {
482 res = 0;
483 if(!res && (valid & FATTR_MODE))
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000484 res = do_chmod(f, path, attr);
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000485 if(!res && (valid & (FATTR_UID | FATTR_GID)))
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000486 res = do_chown(f, path, attr, valid);
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000487 if(!res && (valid & FATTR_SIZE))
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000488 res = do_truncate(f, path, attr);
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000489 if(!res && (valid & FATTR_UTIME))
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000490 res = do_utime(f, path, attr);
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000491 if(!res) {
492 struct stat buf;
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000493 res = f->op.getattr(path, &buf);
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000494 if(!res)
495 convert_stat(&buf, &outarg.attr);
Miklos Szeredia181e612001-11-06 12:03:23 +0000496 }
Miklos Szeredi5e183482001-10-31 14:52:35 +0000497 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000498 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000499 }
Miklos Szeredia181e612001-11-06 12:03:23 +0000500 send_reply(f, in, res, &outarg, sizeof(outarg));
Miklos Szeredi5e183482001-10-31 14:52:35 +0000501}
502
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000503static void do_readlink(struct fuse *f, struct fuse_in_header *in)
504{
505 int res;
506 char link[PATH_MAX + 1];
Miklos Szeredib483c932001-10-29 14:57:57 +0000507 char *path;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000508
Miklos Szeredi5e183482001-10-31 14:52:35 +0000509 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000510 path = get_path(f, in->ino);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000511 if(path != NULL) {
512 res = -ENOSYS;
513 if(f->op.readlink)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000514 res = f->op.readlink(path, link, sizeof(link));
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000515 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000516 }
Miklos Szeredi2df1c042001-11-06 15:07:17 +0000517 link[PATH_MAX] = '\0';
Miklos Szeredi5e183482001-10-31 14:52:35 +0000518 send_reply(f, in, res, link, !res ? strlen(link) : 0);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000519}
520
521static void do_getdir(struct fuse *f, struct fuse_in_header *in)
522{
523 int res;
524 struct fuse_getdir_out arg;
Miklos Szeredia181e612001-11-06 12:03:23 +0000525 struct fuse_dirhandle dh;
Miklos Szeredib483c932001-10-29 14:57:57 +0000526 char *path;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000527
Miklos Szeredib483c932001-10-29 14:57:57 +0000528 dh.fuse = f;
529 dh.fp = tmpfile();
530 dh.dir = in->ino;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000531 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000532 path = get_path(f, in->ino);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000533 if(path != NULL) {
534 res = -ENOSYS;
535 if(f->op.getdir)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000536 res = f->op.getdir(path, &dh, (fuse_dirfil_t) fill_dir);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000537 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000538 }
Miklos Szeredib483c932001-10-29 14:57:57 +0000539 fflush(dh.fp);
540 arg.fd = fileno(dh.fp);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000541 send_reply(f, in, res, &arg, sizeof(arg));
Miklos Szeredib483c932001-10-29 14:57:57 +0000542 fclose(dh.fp);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000543}
544
Miklos Szeredib483c932001-10-29 14:57:57 +0000545static void do_mknod(struct fuse *f, struct fuse_in_header *in,
546 struct fuse_mknod_in *inarg)
547{
548 int res;
549 char *path;
550 struct fuse_mknod_out outarg;
551 struct stat buf;
552
Miklos Szeredi5e183482001-10-31 14:52:35 +0000553 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000554 path = get_path_name(f, in->ino, inarg->name);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000555 if(path != NULL) {
556 res = -ENOSYS;
557 if(f->op.mknod && f->op.getattr) {
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000558 res = f->op.mknod(path, inarg->mode, inarg->rdev);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000559 if(res == 0)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000560 res = f->op.getattr(path, &buf);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000561 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000562 free(path);
Miklos Szeredib483c932001-10-29 14:57:57 +0000563 }
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000564 if(res == 0) {
Miklos Szeredib483c932001-10-29 14:57:57 +0000565 convert_stat(&buf, &outarg.attr);
Miklos Szeredia181e612001-11-06 12:03:23 +0000566 outarg.ino = find_node(f, in->ino, inarg->name, &outarg.attr,
567 in->unique);
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000568 }
Miklos Szeredib483c932001-10-29 14:57:57 +0000569
570 send_reply(f, in, res, &outarg, sizeof(outarg));
571}
572
573static void do_mkdir(struct fuse *f, struct fuse_in_header *in,
574 struct fuse_mkdir_in *inarg)
575{
576 int res;
577 char *path;
578
Miklos Szeredi5e183482001-10-31 14:52:35 +0000579 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000580 path = get_path_name(f, in->ino, inarg->name);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000581 if(path != NULL) {
582 res = -ENOSYS;
583 if(f->op.mkdir)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000584 res = f->op.mkdir(path, inarg->mode);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000585 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000586 }
Miklos Szeredib483c932001-10-29 14:57:57 +0000587 send_reply(f, in, res, NULL, 0);
588}
589
590static void do_remove(struct fuse *f, struct fuse_in_header *in, char *name)
591{
592 int res;
593 char *path;
594
Miklos Szeredi5e183482001-10-31 14:52:35 +0000595 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000596 path = get_path_name(f, in->ino, name);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000597 if(path != NULL) {
598 res = -ENOSYS;
599 if(in->opcode == FUSE_UNLINK) {
600 if(f->op.unlink)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000601 res = f->op.unlink(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000602 }
603 else {
604 if(f->op.rmdir)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000605 res = f->op.rmdir(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000606 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000607 free(path);
Miklos Szeredib483c932001-10-29 14:57:57 +0000608 }
Miklos Szeredi5e183482001-10-31 14:52:35 +0000609 if(res == 0)
610 remove_node(f, in->ino, name);
Miklos Szeredib483c932001-10-29 14:57:57 +0000611 send_reply(f, in, res, NULL, 0);
612}
613
614static void do_symlink(struct fuse *f, struct fuse_in_header *in, char *name,
615 char *link)
616{
617 int res;
618 char *path;
619
Miklos Szeredi5e183482001-10-31 14:52:35 +0000620 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000621 path = get_path_name(f, in->ino, name);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000622 if(path != NULL) {
623 res = -ENOSYS;
624 if(f->op.symlink)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000625 res = f->op.symlink(link, path);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000626 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000627 }
Miklos Szeredib483c932001-10-29 14:57:57 +0000628 send_reply(f, in, res, NULL, 0);
629}
630
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000631static void do_rename(struct fuse *f, struct fuse_in_header *in,
632 struct fuse_rename_in *inarg)
633{
634 int res;
635 fino_t olddir = in->ino;
636 fino_t newdir = inarg->newdir;
637 char *oldname = inarg->names;
638 char *newname = inarg->names + strlen(oldname) + 1;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000639 char *oldpath;
640 char *newpath;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000641
Miklos Szeredi5e183482001-10-31 14:52:35 +0000642 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000643 oldpath = get_path_name(f, olddir, oldname);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000644 if(oldpath != NULL) {
Miklos Szeredia181e612001-11-06 12:03:23 +0000645 newpath = get_path_name(f, newdir, newname);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000646 if(newpath != NULL) {
647 res = -ENOSYS;
648 if(f->op.rename)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000649 res = f->op.rename(oldpath, newpath);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000650 if(res == 0)
651 rename_node(f, olddir, oldname, newdir, newname);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000652 free(newpath);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000653 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000654 free(oldpath);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000655 }
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000656 send_reply(f, in, res, NULL, 0);
657}
658
659static void do_link(struct fuse *f, struct fuse_in_header *in,
Miklos Szeredi5e183482001-10-31 14:52:35 +0000660 struct fuse_link_in *arg)
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000661{
662 int res;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000663 char *oldpath;
664 char *newpath;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000665
Miklos Szeredi5e183482001-10-31 14:52:35 +0000666 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000667 oldpath = get_path(f, in->ino);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000668 if(oldpath != NULL) {
Miklos Szeredia181e612001-11-06 12:03:23 +0000669 newpath = get_path_name(f, arg->newdir, arg->name);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000670 if(newpath != NULL) {
671 res = -ENOSYS;
672 if(f->op.link)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000673 res = f->op.link(oldpath, newpath);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000674 free(newpath);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000675 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000676 free(oldpath);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000677 }
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000678 send_reply(f, in, res, NULL, 0);
679}
680
Miklos Szeredi5e183482001-10-31 14:52:35 +0000681static void do_open(struct fuse *f, struct fuse_in_header *in,
682 struct fuse_open_in *arg)
683{
684 int res;
685 char *path;
686
687 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000688 path = get_path(f, in->ino);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000689 if(path != NULL) {
690 res = -ENOSYS;
691 if(f->op.open)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000692 res = f->op.open(path, arg->flags);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000693 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000694 }
695 send_reply(f, in, res, NULL, 0);
696}
697
698static void do_read(struct fuse *f, struct fuse_in_header *in,
699 struct fuse_read_in *arg)
700{
701 int res;
702 char *path;
Miklos Szeredi43696432001-11-18 19:15:05 +0000703 char *outbuf = (char *) malloc(sizeof(struct fuse_out_header) + arg->size);
704 struct fuse_out_header *out = (struct fuse_out_header *) outbuf;
705 char *buf = outbuf + sizeof(struct fuse_out_header);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000706 size_t size;
Miklos Szeredi43696432001-11-18 19:15:05 +0000707 size_t outsize;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000708
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000709 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000710 path = get_path(f, in->ino);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000711 if(path != NULL) {
712 res = -ENOSYS;
Miklos Szeredia181e612001-11-06 12:03:23 +0000713 if(f->op.read)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000714 res = f->op.read(path, buf, arg->size, arg->offset);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000715 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000716 }
717
718 size = 0;
719 if(res > 0) {
720 size = res;
721 res = 0;
722 }
Miklos Szeredi43696432001-11-18 19:15:05 +0000723 out->unique = in->unique;
724 out->error = res;
725 outsize = sizeof(struct fuse_out_header) + size;
726
727 send_reply_raw(f, outbuf, outsize);
728 free(outbuf);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000729}
Miklos Szeredib483c932001-10-29 14:57:57 +0000730
Miklos Szeredia181e612001-11-06 12:03:23 +0000731static void do_write(struct fuse *f, struct fuse_in_header *in,
732 struct fuse_write_in *arg)
733{
734 int res;
735 char *path;
Miklos Szeredia181e612001-11-06 12:03:23 +0000736
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000737 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000738 path = get_path(f, in->ino);
739 if(path != NULL) {
740 res = -ENOSYS;
741 if(f->op.write)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000742 res = f->op.write(path, arg->buf, arg->size, arg->offset);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000743 free(path);
Miklos Szeredia181e612001-11-06 12:03:23 +0000744 }
745
746 if(res > 0) {
747 if((size_t) res != arg->size) {
748 fprintf(stderr, "short write: %u (should be %u)\n", res,
749 arg->size);
750 res = -EIO;
751 }
752 else
753 res = 0;
754 }
755
756 send_reply(f, in, res, NULL, 0);
757}
758
Miklos Szeredi43696432001-11-18 19:15:05 +0000759static void free_cmd(struct fuse_cmd *cmd)
760{
761 free(cmd->buf);
762 free(cmd);
763}
764
Miklos Szeredifff56ab2001-11-16 10:12:59 +0000765void __fuse_process_cmd(struct fuse *f, struct fuse_cmd *cmd)
Miklos Szeredia181e612001-11-06 12:03:23 +0000766{
Miklos Szeredia181e612001-11-06 12:03:23 +0000767 struct fuse_in_header *in = (struct fuse_in_header *) cmd->buf;
768 void *inarg = cmd->buf + sizeof(struct fuse_in_header);
769 size_t argsize;
Miklos Szeredia181e612001-11-06 12:03:23 +0000770
Miklos Szeredi33232032001-11-19 17:55:51 +0000771 pthread_mutex_lock(&f->lock);
772 f->numavail --;
773 pthread_mutex_unlock(&f->lock);
774
Miklos Szeredic0938ea2001-11-07 12:35:06 +0000775 if((f->flags & FUSE_DEBUG)) {
776 printf("unique: %i, opcode: %i, ino: %li, insize: %i\n", in->unique,
777 in->opcode, in->ino, cmd->buflen);
778 fflush(stdout);
779 }
Miklos Szeredia181e612001-11-06 12:03:23 +0000780
781 argsize = cmd->buflen - sizeof(struct fuse_in_header);
782
783 switch(in->opcode) {
784 case FUSE_LOOKUP:
785 do_lookup(f, in, (char *) inarg);
786 break;
787
Miklos Szeredife428122001-11-20 19:12:28 +0000788 case FUSE_FORGET:
789 do_forget(f, in, (struct fuse_forget_in *) inarg);
790 break;
791
Miklos Szeredia181e612001-11-06 12:03:23 +0000792 case FUSE_GETATTR:
793 do_getattr(f, in);
794 break;
795
796 case FUSE_SETATTR:
797 do_setattr(f, in, (struct fuse_setattr_in *) inarg);
798 break;
799
800 case FUSE_READLINK:
801 do_readlink(f, in);
802 break;
803
804 case FUSE_GETDIR:
805 do_getdir(f, in);
806 break;
807
808 case FUSE_MKNOD:
809 do_mknod(f, in, (struct fuse_mknod_in *) inarg);
810 break;
811
812 case FUSE_MKDIR:
813 do_mkdir(f, in, (struct fuse_mkdir_in *) inarg);
814 break;
815
816 case FUSE_UNLINK:
817 case FUSE_RMDIR:
818 do_remove(f, in, (char *) inarg);
819 break;
820
821 case FUSE_SYMLINK:
822 do_symlink(f, in, (char *) inarg,
823 ((char *) inarg) + strlen((char *) inarg) + 1);
824 break;
825
826 case FUSE_RENAME:
827 do_rename(f, in, (struct fuse_rename_in *) inarg);
828 break;
829
830 case FUSE_LINK:
831 do_link(f, in, (struct fuse_link_in *) inarg);
832 break;
833
834 case FUSE_OPEN:
835 do_open(f, in, (struct fuse_open_in *) inarg);
836 break;
837
838 case FUSE_READ:
839 do_read(f, in, (struct fuse_read_in *) inarg);
840 break;
841
842 case FUSE_WRITE:
843 do_write(f, in, (struct fuse_write_in *) inarg);
844 break;
845
846 default:
847 fprintf(stderr, "Operation %i not implemented\n", in->opcode);
Miklos Szeredi43696432001-11-18 19:15:05 +0000848 send_reply(f, in, -ENOSYS, NULL, 0);
Miklos Szeredia181e612001-11-06 12:03:23 +0000849 }
Miklos Szeredi43696432001-11-18 19:15:05 +0000850
851 free_cmd(cmd);
Miklos Szeredia181e612001-11-06 12:03:23 +0000852}
853
Miklos Szeredifff56ab2001-11-16 10:12:59 +0000854struct fuse_cmd *__fuse_read_cmd(struct fuse *f)
Miklos Szeredi2df1c042001-11-06 15:07:17 +0000855{
Miklos Szeredifff56ab2001-11-16 10:12:59 +0000856 ssize_t res;
Miklos Szeredifff56ab2001-11-16 10:12:59 +0000857 struct fuse_cmd *cmd;
Miklos Szeredifff56ab2001-11-16 10:12:59 +0000858
Miklos Szeredi43696432001-11-18 19:15:05 +0000859 cmd = (struct fuse_cmd *) malloc(sizeof(struct fuse_cmd));
860 cmd->buf = (char *) malloc(FUSE_MAX_IN);
861
Miklos Szeredife428122001-11-20 19:12:28 +0000862 res = read(f->fd, cmd->buf, FUSE_MAX_IN);
863 if(res == -1) {
Miklos Szeredi96249982001-11-21 12:21:19 +0000864 /* ENODEV means we got unmounted, so we silenty return failure */
865 if(errno != ENODEV) {
866 perror("fuse: reading device");
867 /* BAD... This will happen again */
868 }
Miklos Szeredife428122001-11-20 19:12:28 +0000869 free_cmd(cmd);
870 return NULL;
871 }
872 if((size_t) res < sizeof(struct fuse_in_header)) {
873 fprintf(stderr, "short read on fuse device\n");
874 /* Cannot happen */
875 free_cmd(cmd);
876 return NULL;
877 }
878 cmd->buflen = res;
Miklos Szeredifff56ab2001-11-16 10:12:59 +0000879 return cmd;
Miklos Szeredi2df1c042001-11-06 15:07:17 +0000880}
881
Miklos Szeredifff56ab2001-11-16 10:12:59 +0000882
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000883void fuse_loop(struct fuse *f)
884{
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000885 while(1) {
Miklos Szeredifff56ab2001-11-16 10:12:59 +0000886 struct fuse_cmd *cmd = __fuse_read_cmd(f);
887 if(cmd == NULL)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000888 exit(1);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000889
Miklos Szeredifff56ab2001-11-16 10:12:59 +0000890 __fuse_process_cmd(f, cmd);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000891 }
892}
893
Miklos Szeredi8cffdb92001-11-09 14:49:18 +0000894struct fuse *fuse_new(int fd, int flags)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000895{
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000896 struct fuse *f;
897 struct node *root;
Miklos Szeredife428122001-11-20 19:12:28 +0000898 char verstr[128];
Miklos Szeredicc8c9752001-11-21 10:03:39 +0000899 char *realver = getenv(FUSE_KERNEL_VERSION_ENV);
Miklos Szeredife428122001-11-20 19:12:28 +0000900
901 if(realver != NULL) {
902 sprintf(verstr, "%i", FUSE_KERNEL_VERSION);
903 if(strcmp(verstr, realver) != 0) {
904 fprintf(stderr,
905 "Warning: FUSE version mismatch: using %s, kernel is %s\n",
906 realver, verstr);
907 }
908 }
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000909
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000910 f = (struct fuse *) calloc(1, sizeof(struct fuse));
Miklos Szeredi2df1c042001-11-06 15:07:17 +0000911
Miklos Szeredia181e612001-11-06 12:03:23 +0000912 f->flags = flags;
Miklos Szeredi8cffdb92001-11-09 14:49:18 +0000913 f->fd = fd;
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000914 f->ctr = 0;
Miklos Szeredifff56ab2001-11-16 10:12:59 +0000915 /* FIXME: Dynamic hash table */
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000916 f->name_table_size = 14057;
917 f->name_table = (struct node **)
918 calloc(1, sizeof(struct node *) * f->name_table_size);
919 f->ino_table_size = 14057;
920 f->ino_table = (struct node **)
921 calloc(1, sizeof(struct node *) * f->ino_table_size);
Miklos Szeredia181e612001-11-06 12:03:23 +0000922 pthread_mutex_init(&f->lock, NULL);
Miklos Szeredi33232032001-11-19 17:55:51 +0000923 f->numworker = 0;
924 f->numavail = 0;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000925
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000926 root = (struct node *) calloc(1, sizeof(struct node));
Miklos Szeredi8cffdb92001-11-09 14:49:18 +0000927 root->mode = 0;
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000928 root->rdev = 0;
929 root->name = strdup("/");
930 root->parent = 0;
931 hash_ino(f, root, FUSE_ROOT_INO);
932
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000933 return f;
934}
935
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000936void fuse_set_operations(struct fuse *f, const struct fuse_operations *op)
937{
938 f->op = *op;
939}
940
941void fuse_destroy(struct fuse *f)
942{
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000943 size_t i;
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000944 for(i = 0; i < f->ino_table_size; i++) {
945 struct node *node;
946 struct node *next;
947 for(node = f->ino_table[i]; node != NULL; node = next) {
948 next = node->ino_next;
949 free_node(node);
950 }
951 }
952 free(f->ino_table);
953 free(f->name_table);
Miklos Szeredia181e612001-11-06 12:03:23 +0000954 pthread_mutex_destroy(&f->lock);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000955 free(f);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000956}