blob: 50ba52edae3e433eb1072c55179e61c3af28da57 [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 Szeredi97c61e92001-11-07 12:09:43 +000020static struct node *__get_node(struct fuse *f, fino_t ino)
Miklos Szeredia181e612001-11-06 12:03:23 +000021{
Miklos Szeredi97c61e92001-11-07 12:09:43 +000022 size_t hash = ino % f->ino_table_size;
23 struct node *node;
24
25 for(node = f->ino_table[hash]; node != NULL; node = node->ino_next)
26 if(node->ino == ino)
27 return node;
28
29 return NULL;
Miklos Szeredia181e612001-11-06 12:03:23 +000030}
31
Miklos Szeredi97c61e92001-11-07 12:09:43 +000032static struct node *get_node(struct fuse *f, fino_t ino)
Miklos Szeredia181e612001-11-06 12:03:23 +000033{
Miklos Szeredi97c61e92001-11-07 12:09:43 +000034 struct node *node = __get_node(f, ino);
35 if(node != NULL)
36 return node;
37
38 fprintf(stderr, "fuse internal error: inode %lu not found\n", ino);
39 abort();
Miklos Szeredia181e612001-11-06 12:03:23 +000040}
41
Miklos Szeredi97c61e92001-11-07 12:09:43 +000042static void hash_ino(struct fuse *f, struct node *node, fino_t ino)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000043{
Miklos Szeredi97c61e92001-11-07 12:09:43 +000044 size_t hash = ino % f->ino_table_size;
45 node->ino = ino;
46
47 node->ino_next = f->ino_table[hash];
48 f->ino_table[hash] = node;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000049}
50
Miklos Szeredi97c61e92001-11-07 12:09:43 +000051static void unhash_ino(struct fuse *f, struct node *node)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000052{
Miklos Szeredi97c61e92001-11-07 12:09:43 +000053 size_t hash = node->ino % f->ino_table_size;
54 struct node **nodep = &f->ino_table[hash];
55
56 for(; *nodep != NULL; nodep = &(*nodep)->ino_next)
57 if(*nodep == node) {
58 *nodep = node->ino_next;
59 return;
60 }
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000061}
62
Miklos Szeredi97c61e92001-11-07 12:09:43 +000063static fino_t get_ino(struct node *node)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000064{
Miklos Szeredi97c61e92001-11-07 12:09:43 +000065 return node->ino;
66}
67
68static fino_t next_ino(struct fuse *f)
69{
70 while(f->ctr == 0 || __get_node(f, f->ctr) != NULL)
71 f->ctr++;
72
73 return f->ctr;
74}
75
76static void free_node(struct node *node)
77{
78 free(node->name);
79 free(node);
80}
81
82static unsigned int name_hash(struct fuse *f, fino_t parent, const char *name)
83{
84 unsigned int hash = *name;
85
86 if(hash)
87 for(name += 1; *name != '\0'; name++)
88 hash = (hash << 5) - hash + *name;
89
90 return (hash + parent) % f->name_table_size;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000091}
92
Miklos Szeredi19dff1b2001-10-30 15:06:52 +000093static struct node *lookup_node(struct fuse *f, fino_t parent,
94 const char *name)
95{
Miklos Szeredi97c61e92001-11-07 12:09:43 +000096 size_t hash = name_hash(f, parent, name);
97 struct node *node;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +000098
Miklos Szeredi97c61e92001-11-07 12:09:43 +000099 for(node = f->name_table[hash]; node != NULL; node = node->name_next)
100 if(node->parent == parent && strcmp(node->name, name) == 0)
101 return node;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000102
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000103 return NULL;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000104}
105
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000106static void hash_name(struct fuse *f, struct node *node, fino_t parent,
Miklos Szeredia181e612001-11-06 12:03:23 +0000107 const char *name)
Miklos Szeredi5e183482001-10-31 14:52:35 +0000108{
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000109 size_t hash = name_hash(f, parent, name);
Miklos Szeredia181e612001-11-06 12:03:23 +0000110 node->parent = parent;
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000111 node->name = strdup(name);
112 node->name_next = f->name_table[hash];
113 f->name_table[hash] = node;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000114}
115
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000116static void unhash_name(struct fuse *f, struct node *node)
Miklos Szeredia181e612001-11-06 12:03:23 +0000117{
118 if(node->name != NULL) {
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000119 size_t hash = name_hash(f, node->parent, node->name);
120 struct node **nodep = &f->name_table[hash];
121
122 for(; *nodep != NULL; nodep = &(*nodep)->name_next)
123 if(*nodep == node) {
124 *nodep = node->name_next;
125 node->name_next = NULL;
126 free(node->name);
127 node->name = NULL;
128 node->parent = 0;
129 return;
130 }
131 fprintf(stderr, "fuse internal error: unable to unhash node: %lu\n",
132 node->ino);
133 abort();
Miklos Szeredia181e612001-11-06 12:03:23 +0000134 }
135}
136
137static fino_t find_node(struct fuse *f, fino_t parent, char *name,
138 struct fuse_attr *attr, int version)
Miklos Szeredi5e183482001-10-31 14:52:35 +0000139{
140 struct node *node;
Miklos Szeredia181e612001-11-06 12:03:23 +0000141 int mode = attr->mode & S_IFMT;
142 int rdev = 0;
143
144 if(S_ISCHR(mode) || S_ISBLK(mode))
145 rdev = attr->rdev;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000146
Miklos Szeredia181e612001-11-06 12:03:23 +0000147 pthread_mutex_lock(&f->lock);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000148 node = lookup_node(f, parent, name);
149 if(node != NULL) {
Miklos Szeredia181e612001-11-06 12:03:23 +0000150 if(node->mode == mode && node->rdev == rdev)
151 goto out;
152
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000153 unhash_name(f, node);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000154 }
155
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000156 node = (struct node *) calloc(1, sizeof(struct node));
Miklos Szeredia181e612001-11-06 12:03:23 +0000157 node->mode = mode;
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000158 node->rdev = rdev;
159 hash_ino(f, node, next_ino(f));
160 hash_name(f, node, parent, name);
Miklos Szeredia181e612001-11-06 12:03:23 +0000161
162 out:
163 node->version = version;
164 pthread_mutex_unlock(&f->lock);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000165 return get_ino(node);
166}
167
168static fino_t find_node_dir(struct fuse *f, fino_t parent, char *name)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000169{
170 struct node *node;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000171
Miklos Szeredia181e612001-11-06 12:03:23 +0000172 pthread_mutex_lock(&f->lock);
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000173 node = lookup_node(f, parent, name);
Miklos Szeredia181e612001-11-06 12:03:23 +0000174 pthread_mutex_unlock(&f->lock);
175
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000176 if(node != NULL)
177 return get_ino(node);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000178 else
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000179 return (fino_t) -1;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000180}
181
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000182static char *add_name(char *buf, char *s, const char *name)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000183{
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000184 size_t len = strlen(name);
185 s -= len;
186 if(s <= buf) {
187 fprintf(stderr, "fuse: path too long: ...%s\n", s + len);
188 return NULL;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000189 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000190 strncpy(s, name, len);
191 s--;
192 *s = '/';
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000193
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000194 return s;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000195}
196
Miklos Szeredia181e612001-11-06 12:03:23 +0000197static char *get_path_name(struct fuse *f, fino_t ino, const char *name)
Miklos Szeredib483c932001-10-29 14:57:57 +0000198{
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000199 char buf[FUSE_MAX_PATH];
200 char *s = buf + FUSE_MAX_PATH - 1;
201 struct node *node;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000202
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000203 *s = '\0';
Miklos Szeredia181e612001-11-06 12:03:23 +0000204
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000205 if(name != NULL) {
206 s = add_name(buf, s, name);
207 if(s == NULL)
208 return NULL;
209 }
210
211 pthread_mutex_lock(&f->lock);
212 for(node = get_node(f, ino); node->ino != FUSE_ROOT_INO;
213 node = get_node(f, node->parent)) {
214 if(node->name == NULL) {
215 s = NULL;
216 break;
217 }
218
219 s = add_name(buf, s, node->name);
220 if(s == NULL)
221 break;
222 }
223 pthread_mutex_unlock(&f->lock);
224
225 if(s == NULL)
Miklos Szeredi5e183482001-10-31 14:52:35 +0000226 return NULL;
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000227 else if(*s == '\0')
228 return strdup("/");
229 else
230 return strdup(s);
231}
Miklos Szeredia181e612001-11-06 12:03:23 +0000232
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000233static char *get_path(struct fuse *f, fino_t ino)
234{
235 return get_path_name(f, ino, NULL);
Miklos Szeredib483c932001-10-29 14:57:57 +0000236}
237
Miklos Szeredia181e612001-11-06 12:03:23 +0000238static void destroy_node(struct fuse *f, fino_t ino, int version)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000239{
Miklos Szeredia181e612001-11-06 12:03:23 +0000240 struct node *node;
241
242 pthread_mutex_lock(&f->lock);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000243 node = get_node(f, ino);
Miklos Szeredia181e612001-11-06 12:03:23 +0000244 if(node->version == version) {
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000245 unhash_name(f, node);
246 unhash_ino(f, node);
Miklos Szeredia181e612001-11-06 12:03:23 +0000247 free_node(node);
248 }
249 pthread_mutex_unlock(&f->lock);
250
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000251}
252
Miklos Szeredi5e183482001-10-31 14:52:35 +0000253static void remove_node(struct fuse *f, fino_t dir, const char *name)
254{
Miklos Szeredia181e612001-11-06 12:03:23 +0000255 struct node *node;
256
257 pthread_mutex_lock(&f->lock);
258 node = lookup_node(f, dir, name);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000259 if(node == NULL) {
260 fprintf(stderr, "fuse internal error: unable to remove node %lu/%s\n",
261 dir, name);
262 abort();
263 }
264 unhash_name(f, node);
Miklos Szeredia181e612001-11-06 12:03:23 +0000265 pthread_mutex_unlock(&f->lock);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000266}
267
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000268static void rename_node(struct fuse *f, fino_t olddir, const char *oldname,
269 fino_t newdir, const char *newname)
270{
Miklos Szeredia181e612001-11-06 12:03:23 +0000271 struct node *node;
272 struct node *newnode;
273
274 pthread_mutex_lock(&f->lock);
275 node = lookup_node(f, olddir, oldname);
276 newnode = lookup_node(f, newdir, newname);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000277 if(node == NULL) {
278 fprintf(stderr, "fuse internal error: unable to rename node %lu/%s\n",
279 olddir, oldname);
280 abort();
281 }
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000282
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000283 if(newnode != NULL)
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000284 unhash_name(f, newnode);
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000285
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000286 unhash_name(f, node);
287 hash_name(f, node, newdir, newname);
Miklos Szeredia181e612001-11-06 12:03:23 +0000288 pthread_mutex_unlock(&f->lock);
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000289}
290
291
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000292static void convert_stat(struct stat *stbuf, struct fuse_attr *attr)
293{
294 attr->mode = stbuf->st_mode;
295 attr->nlink = stbuf->st_nlink;
296 attr->uid = stbuf->st_uid;
297 attr->gid = stbuf->st_gid;
298 attr->rdev = stbuf->st_rdev;
299 attr->size = stbuf->st_size;
300 attr->blksize = stbuf->st_blksize;
301 attr->blocks = stbuf->st_blocks;
302 attr->atime = stbuf->st_atime;
303 attr->mtime = stbuf->st_mtime;
304 attr->ctime = stbuf->st_ctime;
305}
306
Miklos Szeredia181e612001-11-06 12:03:23 +0000307static int fill_dir(struct fuse_dirhandle *dh, char *name, int type)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000308{
309 struct fuse_dirent dirent;
310 size_t reclen;
311 size_t res;
312
Miklos Szeredi5e183482001-10-31 14:52:35 +0000313 dirent.ino = find_node_dir(dh->fuse, dh->dir, name);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000314 dirent.namelen = strlen(name);
315 strncpy(dirent.name, name, sizeof(dirent.name));
316 dirent.type = type;
317 reclen = FUSE_DIRENT_SIZE(&dirent);
318 res = fwrite(&dirent, reclen, 1, dh->fp);
319 if(res == 0) {
320 perror("writing directory file");
321 return -EIO;
322 }
323 return 0;
324}
325
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000326static void send_reply(struct fuse *f, struct fuse_in_header *in, int error,
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000327 void *arg, size_t argsize)
328{
329 int res;
330 char *outbuf;
331 size_t outsize;
332 struct fuse_out_header *out;
333
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000334 if(error > 0) {
335 fprintf(stderr, "positive error code: %i\n", error);
336 error = -ERANGE;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000337 }
338
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000339 if(error)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000340 argsize = 0;
341
342 outsize = sizeof(struct fuse_out_header) + argsize;
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000343 outbuf = (char *) malloc(outsize);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000344 out = (struct fuse_out_header *) outbuf;
345 out->unique = in->unique;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000346 out->error = error;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000347 if(argsize != 0)
348 memcpy(outbuf + sizeof(struct fuse_out_header), arg, argsize);
349
Miklos Szeredic0938ea2001-11-07 12:35:06 +0000350 if((f->flags & FUSE_DEBUG)) {
351 printf(" unique: %i, error: %i (%s), outsize: %i\n", out->unique,
352 out->error, strerror(-out->error), outsize);
353 fflush(stdout);
354 }
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000355
356 res = write(f->fd, outbuf, outsize);
357 if(res == -1)
358 perror("writing fuse device");
359
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000360 free(outbuf);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000361}
362
Miklos Szeredia181e612001-11-06 12:03:23 +0000363static void fill_cred(struct fuse_in_header *in, struct fuse_cred *cred)
364{
365 cred->uid = in->uid;
366 cred->gid = in->gid;
367}
368
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000369static void do_lookup(struct fuse *f, struct fuse_in_header *in, char *name)
370{
371 int res;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000372 char *path;
373 struct stat buf;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000374 struct fuse_lookup_out arg;
Miklos Szeredia181e612001-11-06 12:03:23 +0000375 struct fuse_cred cred;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000376
Miklos Szeredia181e612001-11-06 12:03:23 +0000377 fill_cred(in, &cred);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000378 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000379 path = get_path_name(f, in->ino, name);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000380 if(path != NULL) {
381 res = -ENOSYS;
382 if(f->op.getattr)
Miklos Szeredia181e612001-11-06 12:03:23 +0000383 res = f->op.getattr(&cred, path, &buf);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000384 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000385 }
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000386 if(res == 0) {
387 convert_stat(&buf, &arg.attr);
Miklos Szeredia181e612001-11-06 12:03:23 +0000388 arg.ino = find_node(f, in->ino, name, &arg.attr, in->unique);
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000389 }
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000390 send_reply(f, in, res, &arg, sizeof(arg));
391}
392
Miklos Szeredia181e612001-11-06 12:03:23 +0000393static void do_forget(struct fuse *f, struct fuse_in_header *in,
394 struct fuse_forget_in *arg)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000395{
Miklos Szeredia181e612001-11-06 12:03:23 +0000396 destroy_node(f, in->ino, arg->version);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000397}
398
399static void do_getattr(struct fuse *f, struct fuse_in_header *in)
400{
401 int res;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000402 char *path;
403 struct stat buf;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000404 struct fuse_getattr_out arg;
Miklos Szeredia181e612001-11-06 12:03:23 +0000405 struct fuse_cred cred;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000406
Miklos Szeredia181e612001-11-06 12:03:23 +0000407 fill_cred(in, &cred);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000408 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000409 path = get_path(f, in->ino);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000410 if(path != NULL) {
411 res = -ENOSYS;
412 if(f->op.getattr)
Miklos Szeredia181e612001-11-06 12:03:23 +0000413 res = f->op.getattr(&cred, path, &buf);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000414 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000415 }
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000416 if(res == 0)
417 convert_stat(&buf, &arg.attr);
418
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000419 send_reply(f, in, res, &arg, sizeof(arg));
420}
421
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000422int do_chmod(struct fuse *f, struct fuse_cred *cred, const char *path,
423 struct fuse_attr *attr)
424{
425 int res;
426
427 res = -ENOSYS;
428 if(f->op.chmod)
429 res = f->op.chmod(cred, path, attr->mode);
430
431 return res;
432}
433
434int do_chown(struct fuse *f, struct fuse_cred *cred, const char *path,
435 struct fuse_attr *attr, int valid)
436{
437 int res;
438 uid_t uid = (valid & FATTR_UID) ? attr->uid : (uid_t) -1;
439 gid_t gid = (valid & FATTR_GID) ? attr->gid : (gid_t) -1;
440
441 res = -ENOSYS;
442 if(f->op.chown)
443 res = f->op.chown(cred, path, uid, gid);
444
445 return res;
446}
447
448int do_truncate(struct fuse *f, struct fuse_cred *cred, const char *path,
449 struct fuse_attr *attr)
450{
451 int res;
452
453 res = -ENOSYS;
454 if(f->op.truncate)
455 res = f->op.truncate(cred, path, attr->size);
456
457 return res;
458}
459
460int do_utime(struct fuse *f, struct fuse_cred *cred, const char *path,
461 struct fuse_attr *attr)
462{
463 int res;
464 struct utimbuf buf;
465 buf.actime = attr->atime;
466 buf.modtime = attr->mtime;
467 res = -ENOSYS;
468 if(f->op.utime)
469 res = f->op.utime(cred, path, &buf);
470
471 return res;
472}
473
Miklos Szeredi5e183482001-10-31 14:52:35 +0000474static void do_setattr(struct fuse *f, struct fuse_in_header *in,
475 struct fuse_setattr_in *arg)
476{
477 int res;
478 char *path;
479 int valid = arg->valid;
480 struct fuse_attr *attr = &arg->attr;
Miklos Szeredia181e612001-11-06 12:03:23 +0000481 struct fuse_setattr_out outarg;
482 struct fuse_cred cred;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000483
Miklos Szeredia181e612001-11-06 12:03:23 +0000484 fill_cred(in, &cred);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000485 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000486 path = get_path(f, in->ino);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000487 if(path != NULL) {
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000488 res = -ENOSYS;
489 if(f->op.getattr) {
490 res = 0;
491 if(!res && (valid & FATTR_MODE))
492 res = do_chmod(f, &cred, path, attr);
493 if(!res && (valid & (FATTR_UID | FATTR_GID)))
494 res = do_chown(f, &cred, path, attr, valid);
495 if(!res && (valid & FATTR_SIZE))
496 res = do_truncate(f, &cred, path, attr);
497 if(!res && (valid & FATTR_UTIME))
498 res = do_utime(f, &cred, path, attr);
499 if(!res) {
500 struct stat buf;
501 res = f->op.getattr(&cred, path, &buf);
502 if(!res)
503 convert_stat(&buf, &outarg.attr);
Miklos Szeredia181e612001-11-06 12:03:23 +0000504 }
Miklos Szeredi5e183482001-10-31 14:52:35 +0000505 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000506 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000507 }
Miklos Szeredia181e612001-11-06 12:03:23 +0000508 send_reply(f, in, res, &outarg, sizeof(outarg));
Miklos Szeredi5e183482001-10-31 14:52:35 +0000509}
510
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000511static void do_readlink(struct fuse *f, struct fuse_in_header *in)
512{
513 int res;
514 char link[PATH_MAX + 1];
Miklos Szeredib483c932001-10-29 14:57:57 +0000515 char *path;
Miklos Szeredia181e612001-11-06 12:03:23 +0000516 struct fuse_cred cred;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000517
Miklos Szeredia181e612001-11-06 12:03:23 +0000518 fill_cred(in, &cred);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000519 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000520 path = get_path(f, in->ino);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000521 if(path != NULL) {
522 res = -ENOSYS;
523 if(f->op.readlink)
Miklos Szeredia181e612001-11-06 12:03:23 +0000524 res = f->op.readlink(&cred, path, link, sizeof(link));
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000525 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000526 }
Miklos Szeredi2df1c042001-11-06 15:07:17 +0000527 link[PATH_MAX] = '\0';
Miklos Szeredi5e183482001-10-31 14:52:35 +0000528 send_reply(f, in, res, link, !res ? strlen(link) : 0);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000529}
530
531static void do_getdir(struct fuse *f, struct fuse_in_header *in)
532{
533 int res;
534 struct fuse_getdir_out arg;
Miklos Szeredia181e612001-11-06 12:03:23 +0000535 struct fuse_dirhandle dh;
Miklos Szeredib483c932001-10-29 14:57:57 +0000536 char *path;
Miklos Szeredia181e612001-11-06 12:03:23 +0000537 struct fuse_cred cred;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000538
Miklos Szeredia181e612001-11-06 12:03:23 +0000539 fill_cred(in, &cred);
Miklos Szeredib483c932001-10-29 14:57:57 +0000540 dh.fuse = f;
541 dh.fp = tmpfile();
542 dh.dir = in->ino;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000543 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000544 path = get_path(f, in->ino);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000545 if(path != NULL) {
546 res = -ENOSYS;
547 if(f->op.getdir)
Miklos Szeredia181e612001-11-06 12:03:23 +0000548 res = f->op.getdir(&cred, path, &dh, (fuse_dirfil_t) fill_dir);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000549 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000550 }
Miklos Szeredib483c932001-10-29 14:57:57 +0000551 fflush(dh.fp);
552 arg.fd = fileno(dh.fp);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000553 send_reply(f, in, res, &arg, sizeof(arg));
Miklos Szeredib483c932001-10-29 14:57:57 +0000554 fclose(dh.fp);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000555}
556
Miklos Szeredib483c932001-10-29 14:57:57 +0000557static void do_mknod(struct fuse *f, struct fuse_in_header *in,
558 struct fuse_mknod_in *inarg)
559{
560 int res;
561 char *path;
562 struct fuse_mknod_out outarg;
563 struct stat buf;
Miklos Szeredia181e612001-11-06 12:03:23 +0000564 struct fuse_cred cred;
Miklos Szeredib483c932001-10-29 14:57:57 +0000565
Miklos Szeredia181e612001-11-06 12:03:23 +0000566 fill_cred(in, &cred);
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 Szeredia181e612001-11-06 12:03:23 +0000572 res = f->op.mknod(&cred, path, inarg->mode, inarg->rdev);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000573 if(res == 0)
Miklos Szeredia181e612001-11-06 12:03:23 +0000574 res = f->op.getattr(&cred, 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;
Miklos Szeredia181e612001-11-06 12:03:23 +0000592 struct fuse_cred cred;
Miklos Szeredib483c932001-10-29 14:57:57 +0000593
Miklos Szeredia181e612001-11-06 12:03:23 +0000594 fill_cred(in, &cred);
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, inarg->name);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000597 if(path != NULL) {
598 res = -ENOSYS;
599 if(f->op.mkdir)
Miklos Szeredia181e612001-11-06 12:03:23 +0000600 res = f->op.mkdir(&cred, path, inarg->mode);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000601 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000602 }
Miklos Szeredib483c932001-10-29 14:57:57 +0000603 send_reply(f, in, res, NULL, 0);
604}
605
606static void do_remove(struct fuse *f, struct fuse_in_header *in, char *name)
607{
608 int res;
609 char *path;
Miklos Szeredia181e612001-11-06 12:03:23 +0000610 struct fuse_cred cred;
Miklos Szeredib483c932001-10-29 14:57:57 +0000611
Miklos Szeredia181e612001-11-06 12:03:23 +0000612 fill_cred(in, &cred);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000613 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000614 path = get_path_name(f, in->ino, name);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000615 if(path != NULL) {
616 res = -ENOSYS;
617 if(in->opcode == FUSE_UNLINK) {
618 if(f->op.unlink)
Miklos Szeredia181e612001-11-06 12:03:23 +0000619 res = f->op.unlink(&cred, path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000620 }
621 else {
622 if(f->op.rmdir)
Miklos Szeredia181e612001-11-06 12:03:23 +0000623 res = f->op.rmdir(&cred, path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000624 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000625 free(path);
Miklos Szeredib483c932001-10-29 14:57:57 +0000626 }
Miklos Szeredi5e183482001-10-31 14:52:35 +0000627 if(res == 0)
628 remove_node(f, in->ino, name);
Miklos Szeredib483c932001-10-29 14:57:57 +0000629 send_reply(f, in, res, NULL, 0);
630}
631
632static void do_symlink(struct fuse *f, struct fuse_in_header *in, char *name,
633 char *link)
634{
635 int res;
636 char *path;
Miklos Szeredia181e612001-11-06 12:03:23 +0000637 struct fuse_cred cred;
Miklos Szeredib483c932001-10-29 14:57:57 +0000638
Miklos Szeredia181e612001-11-06 12:03:23 +0000639 fill_cred(in, &cred);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000640 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000641 path = get_path_name(f, in->ino, name);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000642 if(path != NULL) {
643 res = -ENOSYS;
644 if(f->op.symlink)
Miklos Szeredia181e612001-11-06 12:03:23 +0000645 res = f->op.symlink(&cred, link, path);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000646 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000647 }
Miklos Szeredib483c932001-10-29 14:57:57 +0000648 send_reply(f, in, res, NULL, 0);
649}
650
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000651static void do_rename(struct fuse *f, struct fuse_in_header *in,
652 struct fuse_rename_in *inarg)
653{
654 int res;
655 fino_t olddir = in->ino;
656 fino_t newdir = inarg->newdir;
657 char *oldname = inarg->names;
658 char *newname = inarg->names + strlen(oldname) + 1;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000659 char *oldpath;
660 char *newpath;
Miklos Szeredia181e612001-11-06 12:03:23 +0000661 struct fuse_cred cred;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000662
Miklos Szeredia181e612001-11-06 12:03:23 +0000663 fill_cred(in, &cred);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000664 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000665 oldpath = get_path_name(f, olddir, oldname);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000666 if(oldpath != NULL) {
Miklos Szeredia181e612001-11-06 12:03:23 +0000667 newpath = get_path_name(f, newdir, newname);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000668 if(newpath != NULL) {
669 res = -ENOSYS;
670 if(f->op.rename)
Miklos Szeredia181e612001-11-06 12:03:23 +0000671 res = f->op.rename(&cred, oldpath, newpath);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000672 if(res == 0)
673 rename_node(f, olddir, oldname, newdir, newname);
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
681static void do_link(struct fuse *f, struct fuse_in_header *in,
Miklos Szeredi5e183482001-10-31 14:52:35 +0000682 struct fuse_link_in *arg)
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000683{
684 int res;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000685 char *oldpath;
686 char *newpath;
Miklos Szeredia181e612001-11-06 12:03:23 +0000687 struct fuse_cred cred;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000688
Miklos Szeredia181e612001-11-06 12:03:23 +0000689 fill_cred(in, &cred);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000690 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000691 oldpath = get_path(f, in->ino);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000692 if(oldpath != NULL) {
Miklos Szeredia181e612001-11-06 12:03:23 +0000693 newpath = get_path_name(f, arg->newdir, arg->name);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000694 if(newpath != NULL) {
695 res = -ENOSYS;
696 if(f->op.link)
Miklos Szeredia181e612001-11-06 12:03:23 +0000697 res = f->op.link(&cred, oldpath, newpath);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000698 free(newpath);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000699 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000700 free(oldpath);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000701 }
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000702 send_reply(f, in, res, NULL, 0);
703}
704
Miklos Szeredi5e183482001-10-31 14:52:35 +0000705static void do_open(struct fuse *f, struct fuse_in_header *in,
706 struct fuse_open_in *arg)
707{
708 int res;
709 char *path;
Miklos Szeredia181e612001-11-06 12:03:23 +0000710 struct fuse_cred cred;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000711
Miklos Szeredia181e612001-11-06 12:03:23 +0000712 fill_cred(in, &cred);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000713 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000714 path = get_path(f, in->ino);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000715 if(path != NULL) {
716 res = -ENOSYS;
717 if(f->op.open)
Miklos Szeredia181e612001-11-06 12:03:23 +0000718 res = f->op.open(&cred, path, arg->flags);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000719 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000720 }
721 send_reply(f, in, res, NULL, 0);
722}
723
724static void do_read(struct fuse *f, struct fuse_in_header *in,
725 struct fuse_read_in *arg)
726{
727 int res;
728 char *path;
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000729 char *buf = (char *) malloc(arg->size);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000730 size_t size;
Miklos Szeredia181e612001-11-06 12:03:23 +0000731 struct fuse_cred cred;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000732
Miklos Szeredia181e612001-11-06 12:03:23 +0000733 fill_cred(in, &cred);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000734 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000735 path = get_path(f, in->ino);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000736 if(path != NULL) {
737 res = -ENOSYS;
Miklos Szeredia181e612001-11-06 12:03:23 +0000738 if(f->op.read)
739 res = f->op.read(&cred, path, buf, arg->size, arg->offset);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000740 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000741 }
742
743 size = 0;
744 if(res > 0) {
745 size = res;
746 res = 0;
747 }
748
749 send_reply(f, in, res, buf, size);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000750 free(buf);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000751}
Miklos Szeredib483c932001-10-29 14:57:57 +0000752
Miklos Szeredia181e612001-11-06 12:03:23 +0000753static void do_write(struct fuse *f, struct fuse_in_header *in,
754 struct fuse_write_in *arg)
755{
756 int res;
757 char *path;
758 struct fuse_cred cred;
759
760 fill_cred(in, &cred);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000761 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000762 path = get_path(f, in->ino);
763 if(path != NULL) {
764 res = -ENOSYS;
765 if(f->op.write)
766 res = f->op.write(&cred, path, arg->buf, arg->size, arg->offset);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000767 free(path);
Miklos Szeredia181e612001-11-06 12:03:23 +0000768 }
769
770 if(res > 0) {
771 if((size_t) res != arg->size) {
772 fprintf(stderr, "short write: %u (should be %u)\n", res,
773 arg->size);
774 res = -EIO;
775 }
776 else
777 res = 0;
778 }
779
780 send_reply(f, in, res, NULL, 0);
781}
782
783struct cmd {
784 struct fuse *f;
785 char *buf;
786 size_t buflen;
787};
788
789static void *do_command(void *data)
790{
791 struct cmd *cmd = (struct cmd *) data;
792 struct fuse_in_header *in = (struct fuse_in_header *) cmd->buf;
793 void *inarg = cmd->buf + sizeof(struct fuse_in_header);
794 size_t argsize;
795 struct fuse *f = cmd->f;
796
Miklos Szeredic0938ea2001-11-07 12:35:06 +0000797 if((f->flags & FUSE_DEBUG)) {
798 printf("unique: %i, opcode: %i, ino: %li, insize: %i\n", in->unique,
799 in->opcode, in->ino, cmd->buflen);
800 fflush(stdout);
801 }
Miklos Szeredia181e612001-11-06 12:03:23 +0000802
803 argsize = cmd->buflen - sizeof(struct fuse_in_header);
804
805 switch(in->opcode) {
806 case FUSE_LOOKUP:
807 do_lookup(f, in, (char *) inarg);
808 break;
809
810 case FUSE_FORGET:
811 do_forget(f, in, (struct fuse_forget_in *) inarg);
812 break;
813
814 case FUSE_GETATTR:
815 do_getattr(f, in);
816 break;
817
818 case FUSE_SETATTR:
819 do_setattr(f, in, (struct fuse_setattr_in *) inarg);
820 break;
821
822 case FUSE_READLINK:
823 do_readlink(f, in);
824 break;
825
826 case FUSE_GETDIR:
827 do_getdir(f, in);
828 break;
829
830 case FUSE_MKNOD:
831 do_mknod(f, in, (struct fuse_mknod_in *) inarg);
832 break;
833
834 case FUSE_MKDIR:
835 do_mkdir(f, in, (struct fuse_mkdir_in *) inarg);
836 break;
837
838 case FUSE_UNLINK:
839 case FUSE_RMDIR:
840 do_remove(f, in, (char *) inarg);
841 break;
842
843 case FUSE_SYMLINK:
844 do_symlink(f, in, (char *) inarg,
845 ((char *) inarg) + strlen((char *) inarg) + 1);
846 break;
847
848 case FUSE_RENAME:
849 do_rename(f, in, (struct fuse_rename_in *) inarg);
850 break;
851
852 case FUSE_LINK:
853 do_link(f, in, (struct fuse_link_in *) inarg);
854 break;
855
856 case FUSE_OPEN:
857 do_open(f, in, (struct fuse_open_in *) inarg);
858 break;
859
860 case FUSE_READ:
861 do_read(f, in, (struct fuse_read_in *) inarg);
862 break;
863
864 case FUSE_WRITE:
865 do_write(f, in, (struct fuse_write_in *) inarg);
866 break;
867
868 default:
869 fprintf(stderr, "Operation %i not implemented\n", in->opcode);
870 /* No need to send reply to async requests */
871 if(in->unique != 0)
872 send_reply(f, in, -ENOSYS, NULL, 0);
873 }
874
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000875 free(cmd->buf);
876 free(cmd);
Miklos Szeredia181e612001-11-06 12:03:23 +0000877
878 return NULL;
879}
880
Miklos Szeredi2df1c042001-11-06 15:07:17 +0000881/* This hack makes it possible to link FUSE with or without the
882 pthread library */
883__attribute__((weak))
884int pthread_create(pthread_t *thrid __attribute__((unused)),
885 const pthread_attr_t *attr __attribute__((unused)),
886 void *(*func)(void *) __attribute__((unused)),
887 void *arg __attribute__((unused)))
888{
889 return ENOSYS;
890}
891
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000892void fuse_loop(struct fuse *f)
893{
894 int res;
895 char inbuf[FUSE_MAX_IN];
Miklos Szeredia181e612001-11-06 12:03:23 +0000896 pthread_attr_t attr;
897 pthread_t thrid;
898
899 pthread_attr_init(&attr);
900 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000901
902 while(1) {
Miklos Szeredia181e612001-11-06 12:03:23 +0000903 struct cmd *cmd;
904
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000905 res = read(f->fd, inbuf, sizeof(inbuf));
906 if(res == -1) {
907 perror("reading fuse device");
908 continue;
909 }
Miklos Szeredia181e612001-11-06 12:03:23 +0000910 if((size_t) res < sizeof(struct fuse_in_header)) {
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000911 fprintf(stderr, "short read on fuse device\n");
912 continue;
913 }
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000914
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000915 cmd = (struct cmd *) malloc(sizeof(struct cmd));
Miklos Szeredia181e612001-11-06 12:03:23 +0000916 cmd->f = f;
917 cmd->buflen = res;
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000918 cmd->buf = (char *) malloc(cmd->buflen);
Miklos Szeredia181e612001-11-06 12:03:23 +0000919 memcpy(cmd->buf, inbuf, cmd->buflen);
920
921 if(f->flags & FUSE_MULTITHREAD) {
922 res = pthread_create(&thrid, &attr, do_command, cmd);
Miklos Szeredi2df1c042001-11-06 15:07:17 +0000923 if(res == 0)
924 continue;
925
926 fprintf(stderr, "Error creating thread: %s\n", strerror(res));
927 fprintf(stderr, "Will run in single thread mode\n");
928 f->flags &= ~FUSE_MULTITHREAD;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000929 }
Miklos Szeredi2df1c042001-11-06 15:07:17 +0000930
931 do_command(cmd);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000932 }
933}
934
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000935struct fuse *fuse_new(int flags, mode_t rootmode)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000936{
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000937 struct fuse *f;
938 struct node *root;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000939
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000940 f = (struct fuse *) calloc(1, sizeof(struct fuse));
Miklos Szeredi2df1c042001-11-06 15:07:17 +0000941
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000942 if(!rootmode)
943 rootmode = S_IFDIR;
944
945 if(!S_ISDIR(rootmode) && !S_ISREG(rootmode)) {
946 fprintf(stderr, "Invalid mode for root: 0%o\n", rootmode);
947 rootmode = S_IFDIR;
Miklos Szeredi2df1c042001-11-06 15:07:17 +0000948 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000949 rootmode &= S_IFMT;
Miklos Szeredi2df1c042001-11-06 15:07:17 +0000950
Miklos Szeredia181e612001-11-06 12:03:23 +0000951 f->flags = flags;
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000952 f->rootmode = rootmode;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000953 f->fd = -1;
Miklos Szeredi2df1c042001-11-06 15:07:17 +0000954 f->mnt = NULL;
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000955 f->ctr = 0;
956 f->name_table_size = 14057;
957 f->name_table = (struct node **)
958 calloc(1, sizeof(struct node *) * f->name_table_size);
959 f->ino_table_size = 14057;
960 f->ino_table = (struct node **)
961 calloc(1, sizeof(struct node *) * f->ino_table_size);
Miklos Szeredia181e612001-11-06 12:03:23 +0000962 pthread_mutex_init(&f->lock, NULL);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000963
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000964 root = (struct node *) calloc(1, sizeof(struct node));
965 root->mode = rootmode;
966 root->rdev = 0;
967 root->name = strdup("/");
968 root->parent = 0;
969 hash_ino(f, root, FUSE_ROOT_INO);
970
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000971 return f;
972}
973
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000974void fuse_set_operations(struct fuse *f, const struct fuse_operations *op)
975{
976 f->op = *op;
977}
978
979void fuse_destroy(struct fuse *f)
980{
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000981 size_t i;
Miklos Szeredia181e612001-11-06 12:03:23 +0000982 close(f->fd);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000983 for(i = 0; i < f->ino_table_size; i++) {
984 struct node *node;
985 struct node *next;
986 for(node = f->ino_table[i]; node != NULL; node = next) {
987 next = node->ino_next;
988 free_node(node);
989 }
990 }
991 free(f->ino_table);
992 free(f->name_table);
Miklos Szeredia181e612001-11-06 12:03:23 +0000993 pthread_mutex_destroy(&f->lock);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000994 free(f);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000995}