blob: 45a0dc5a40dc5a6053d8b9a12cd4846342470177 [file] [log] [blame]
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001/*
2 FUSE: Filesystem in Userspace
3 Copyright (C) 2001 Miklos Szeredi (mszeredi@inf.bme.hu)
4
5 This program can be distributed under the terms of the GNU GPL.
6 See the file COPYING.
7*/
8
9#include "fuse_i.h"
10#include <linux/fuse.h>
11
12#include <string.h>
Miklos Szeredi97c61e92001-11-07 12:09:43 +000013#include <stdlib.h>
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000014#include <unistd.h>
Miklos Szeredi97c61e92001-11-07 12:09:43 +000015#include <limits.h>
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000016#include <errno.h>
Miklos Szeredi019b4e92001-12-26 18:08:09 +000017#include <sys/param.h>
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000018
Miklos Szeredi97c61e92001-11-07 12:09:43 +000019#define FUSE_MAX_PATH 4096
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000020
Miklos Szeredicc8c9752001-11-21 10:03:39 +000021#define FUSE_KERNEL_VERSION_ENV "_FUSE_KERNEL_VERSION"
22
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +000023static inline void inc_avail(struct fuse *f)
24{
25 pthread_mutex_lock(&f->lock);
26 f->numavail ++;
27 pthread_mutex_unlock(&f->lock);
28}
29
30static inline void dec_avail(struct fuse *f)
31{
32 pthread_mutex_lock(&f->lock);
33 f->numavail --;
34 pthread_mutex_unlock(&f->lock);
35}
36
Miklos Szeredi97c61e92001-11-07 12:09:43 +000037static struct node *__get_node(struct fuse *f, fino_t ino)
Miklos Szeredia181e612001-11-06 12:03:23 +000038{
Miklos Szeredi97c61e92001-11-07 12:09:43 +000039 size_t hash = ino % f->ino_table_size;
40 struct node *node;
41
42 for(node = f->ino_table[hash]; node != NULL; node = node->ino_next)
43 if(node->ino == ino)
44 return node;
45
46 return NULL;
Miklos Szeredia181e612001-11-06 12:03:23 +000047}
48
Miklos Szeredi97c61e92001-11-07 12:09:43 +000049static struct node *get_node(struct fuse *f, fino_t ino)
Miklos Szeredia181e612001-11-06 12:03:23 +000050{
Miklos Szeredi97c61e92001-11-07 12:09:43 +000051 struct node *node = __get_node(f, ino);
52 if(node != NULL)
53 return node;
54
55 fprintf(stderr, "fuse internal error: inode %lu not found\n", ino);
56 abort();
Miklos Szeredia181e612001-11-06 12:03:23 +000057}
58
Miklos Szeredi97c61e92001-11-07 12:09:43 +000059static void hash_ino(struct fuse *f, struct node *node, fino_t ino)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000060{
Miklos Szeredi97c61e92001-11-07 12:09:43 +000061 size_t hash = ino % f->ino_table_size;
62 node->ino = ino;
63
64 node->ino_next = f->ino_table[hash];
65 f->ino_table[hash] = node;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000066}
67
Miklos Szeredi97c61e92001-11-07 12:09:43 +000068static void unhash_ino(struct fuse *f, struct node *node)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000069{
Miklos Szeredi97c61e92001-11-07 12:09:43 +000070 size_t hash = node->ino % f->ino_table_size;
71 struct node **nodep = &f->ino_table[hash];
72
73 for(; *nodep != NULL; nodep = &(*nodep)->ino_next)
74 if(*nodep == node) {
75 *nodep = node->ino_next;
76 return;
77 }
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000078}
79
Miklos Szeredi97c61e92001-11-07 12:09:43 +000080static fino_t get_ino(struct node *node)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000081{
Miklos Szeredi97c61e92001-11-07 12:09:43 +000082 return node->ino;
83}
84
85static fino_t next_ino(struct fuse *f)
86{
87 while(f->ctr == 0 || __get_node(f, f->ctr) != NULL)
88 f->ctr++;
89
90 return f->ctr;
91}
92
93static void free_node(struct node *node)
94{
95 free(node->name);
96 free(node);
97}
98
99static unsigned int name_hash(struct fuse *f, fino_t parent, const char *name)
100{
101 unsigned int hash = *name;
102
103 if(hash)
104 for(name += 1; *name != '\0'; name++)
105 hash = (hash << 5) - hash + *name;
106
107 return (hash + parent) % f->name_table_size;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000108}
109
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000110static struct node *lookup_node(struct fuse *f, fino_t parent,
111 const char *name)
112{
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000113 size_t hash = name_hash(f, parent, name);
114 struct node *node;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000115
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000116 for(node = f->name_table[hash]; node != NULL; node = node->name_next)
117 if(node->parent == parent && strcmp(node->name, name) == 0)
118 return node;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000119
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000120 return NULL;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000121}
122
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000123static void hash_name(struct fuse *f, struct node *node, fino_t parent,
Miklos Szeredia181e612001-11-06 12:03:23 +0000124 const char *name)
Miklos Szeredi5e183482001-10-31 14:52:35 +0000125{
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000126 size_t hash = name_hash(f, parent, name);
Miklos Szeredia181e612001-11-06 12:03:23 +0000127 node->parent = parent;
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000128 node->name = strdup(name);
129 node->name_next = f->name_table[hash];
130 f->name_table[hash] = node;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000131}
132
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000133static void unhash_name(struct fuse *f, struct node *node)
Miklos Szeredia181e612001-11-06 12:03:23 +0000134{
135 if(node->name != NULL) {
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000136 size_t hash = name_hash(f, node->parent, node->name);
137 struct node **nodep = &f->name_table[hash];
138
139 for(; *nodep != NULL; nodep = &(*nodep)->name_next)
140 if(*nodep == node) {
141 *nodep = node->name_next;
142 node->name_next = NULL;
143 free(node->name);
144 node->name = NULL;
145 node->parent = 0;
146 return;
147 }
148 fprintf(stderr, "fuse internal error: unable to unhash node: %lu\n",
149 node->ino);
150 abort();
Miklos Szeredia181e612001-11-06 12:03:23 +0000151 }
152}
153
154static fino_t find_node(struct fuse *f, fino_t parent, char *name,
155 struct fuse_attr *attr, int version)
Miklos Szeredi5e183482001-10-31 14:52:35 +0000156{
157 struct node *node;
Miklos Szeredia181e612001-11-06 12:03:23 +0000158 int mode = attr->mode & S_IFMT;
159 int rdev = 0;
160
161 if(S_ISCHR(mode) || S_ISBLK(mode))
162 rdev = attr->rdev;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000163
Miklos Szeredia181e612001-11-06 12:03:23 +0000164 pthread_mutex_lock(&f->lock);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000165 node = lookup_node(f, parent, name);
166 if(node != NULL) {
Miklos Szeredia181e612001-11-06 12:03:23 +0000167 if(node->mode == mode && node->rdev == rdev)
168 goto out;
169
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000170 unhash_name(f, node);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000171 }
172
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000173 node = (struct node *) calloc(1, sizeof(struct node));
Miklos Szeredia181e612001-11-06 12:03:23 +0000174 node->mode = mode;
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000175 node->rdev = rdev;
176 hash_ino(f, node, next_ino(f));
177 hash_name(f, node, parent, name);
Miklos Szeredia181e612001-11-06 12:03:23 +0000178
179 out:
180 node->version = version;
181 pthread_mutex_unlock(&f->lock);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000182 return get_ino(node);
183}
184
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000185static char *add_name(char *buf, char *s, const char *name)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000186{
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000187 size_t len = strlen(name);
188 s -= len;
189 if(s <= buf) {
190 fprintf(stderr, "fuse: path too long: ...%s\n", s + len);
191 return NULL;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000192 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000193 strncpy(s, name, len);
194 s--;
195 *s = '/';
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000196
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000197 return s;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000198}
199
Miklos Szeredia181e612001-11-06 12:03:23 +0000200static char *get_path_name(struct fuse *f, fino_t ino, const char *name)
Miklos Szeredib483c932001-10-29 14:57:57 +0000201{
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000202 char buf[FUSE_MAX_PATH];
203 char *s = buf + FUSE_MAX_PATH - 1;
204 struct node *node;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000205
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000206 *s = '\0';
Miklos Szeredia181e612001-11-06 12:03:23 +0000207
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000208 if(name != NULL) {
209 s = add_name(buf, s, name);
210 if(s == NULL)
211 return NULL;
212 }
213
214 pthread_mutex_lock(&f->lock);
215 for(node = get_node(f, ino); node->ino != FUSE_ROOT_INO;
216 node = get_node(f, node->parent)) {
217 if(node->name == NULL) {
218 s = NULL;
219 break;
220 }
221
222 s = add_name(buf, s, node->name);
223 if(s == NULL)
224 break;
225 }
226 pthread_mutex_unlock(&f->lock);
227
228 if(s == NULL)
Miklos Szeredi5e183482001-10-31 14:52:35 +0000229 return NULL;
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000230 else if(*s == '\0')
231 return strdup("/");
232 else
233 return strdup(s);
234}
Miklos Szeredia181e612001-11-06 12:03:23 +0000235
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000236static char *get_path(struct fuse *f, fino_t ino)
237{
238 return get_path_name(f, ino, NULL);
Miklos Szeredib483c932001-10-29 14:57:57 +0000239}
240
Miklos Szeredia181e612001-11-06 12:03:23 +0000241static void destroy_node(struct fuse *f, fino_t ino, int version)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000242{
Miklos Szeredia181e612001-11-06 12:03:23 +0000243 struct node *node;
244
245 pthread_mutex_lock(&f->lock);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000246 node = get_node(f, ino);
Miklos Szeredi39f28672001-11-14 14:52:54 +0000247 if(node->version == version && ino != FUSE_ROOT_INO) {
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000248 unhash_name(f, node);
249 unhash_ino(f, node);
Miklos Szeredia181e612001-11-06 12:03:23 +0000250 free_node(node);
251 }
252 pthread_mutex_unlock(&f->lock);
253
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000254}
255
Miklos Szeredi5e183482001-10-31 14:52:35 +0000256static void remove_node(struct fuse *f, fino_t dir, const char *name)
257{
Miklos Szeredia181e612001-11-06 12:03:23 +0000258 struct node *node;
259
260 pthread_mutex_lock(&f->lock);
261 node = lookup_node(f, dir, name);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000262 if(node == NULL) {
263 fprintf(stderr, "fuse internal error: unable to remove node %lu/%s\n",
264 dir, name);
265 abort();
266 }
267 unhash_name(f, node);
Miklos Szeredia181e612001-11-06 12:03:23 +0000268 pthread_mutex_unlock(&f->lock);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000269}
270
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000271static void rename_node(struct fuse *f, fino_t olddir, const char *oldname,
272 fino_t newdir, const char *newname)
273{
Miklos Szeredia181e612001-11-06 12:03:23 +0000274 struct node *node;
275 struct node *newnode;
276
277 pthread_mutex_lock(&f->lock);
278 node = lookup_node(f, olddir, oldname);
279 newnode = lookup_node(f, newdir, newname);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000280 if(node == NULL) {
281 fprintf(stderr, "fuse internal error: unable to rename node %lu/%s\n",
282 olddir, oldname);
283 abort();
284 }
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000285
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000286 if(newnode != NULL)
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000287 unhash_name(f, newnode);
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000288
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000289 unhash_name(f, node);
290 hash_name(f, node, newdir, newname);
Miklos Szeredia181e612001-11-06 12:03:23 +0000291 pthread_mutex_unlock(&f->lock);
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000292}
293
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000294static void convert_stat(struct stat *stbuf, struct fuse_attr *attr)
295{
296 attr->mode = stbuf->st_mode;
297 attr->nlink = stbuf->st_nlink;
298 attr->uid = stbuf->st_uid;
299 attr->gid = stbuf->st_gid;
300 attr->rdev = stbuf->st_rdev;
301 attr->size = stbuf->st_size;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000302 attr->blocks = stbuf->st_blocks;
303 attr->atime = stbuf->st_atime;
304 attr->mtime = stbuf->st_mtime;
305 attr->ctime = stbuf->st_ctime;
Miklos Szeredifff56ab2001-11-16 10:12:59 +0000306 attr->_dummy = 4096;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000307}
308
Miklos Szeredia181e612001-11-06 12:03:23 +0000309static int fill_dir(struct fuse_dirhandle *dh, char *name, int type)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000310{
311 struct fuse_dirent dirent;
312 size_t reclen;
313 size_t res;
314
Miklos Szeredi43696432001-11-18 19:15:05 +0000315 dirent.ino = (unsigned long) -1;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000316 dirent.namelen = strlen(name);
317 strncpy(dirent.name, name, sizeof(dirent.name));
318 dirent.type = type;
319 reclen = FUSE_DIRENT_SIZE(&dirent);
320 res = fwrite(&dirent, reclen, 1, dh->fp);
321 if(res == 0) {
Miklos Szeredi96249982001-11-21 12:21:19 +0000322 perror("fuse: writing directory file");
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000323 return -EIO;
324 }
325 return 0;
326}
327
Miklos Szeredi43696432001-11-18 19:15:05 +0000328static void send_reply_raw(struct fuse *f, char *outbuf, size_t outsize)
329{
330 int res;
331
332 if((f->flags & FUSE_DEBUG)) {
333 struct fuse_out_header *out = (struct fuse_out_header *) outbuf;
334 printf(" unique: %i, error: %i (%s), outsize: %i\n", out->unique,
335 out->error, strerror(-out->error), outsize);
336 fflush(stdout);
337 }
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +0000338
339 /* This needs to be done before the reply because otherwise the
340 scheduler can tricks with us, and only let the counter be increased
341 long after the operation is done */
342 inc_avail(f);
343
Miklos Szeredi43696432001-11-18 19:15:05 +0000344 res = write(f->fd, outbuf, outsize);
345 if(res == -1) {
346 /* ENOENT means the operation was interrupted */
347 if(errno != ENOENT)
Miklos Szeredi96249982001-11-21 12:21:19 +0000348 perror("fuse: writing device");
Miklos Szeredi43696432001-11-18 19:15:05 +0000349 }
350}
351
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000352static void send_reply(struct fuse *f, struct fuse_in_header *in, int error,
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000353 void *arg, size_t argsize)
354{
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000355 char *outbuf;
356 size_t outsize;
357 struct fuse_out_header *out;
358
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000359 if(error > 0) {
Miklos Szeredi96249982001-11-21 12:21:19 +0000360 fprintf(stderr, "fuse: positive error code: %i\n", error);
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000361 error = -ERANGE;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000362 }
363
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000364 if(error)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000365 argsize = 0;
366
367 outsize = sizeof(struct fuse_out_header) + argsize;
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000368 outbuf = (char *) malloc(outsize);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000369 out = (struct fuse_out_header *) outbuf;
370 out->unique = in->unique;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000371 out->error = error;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000372 if(argsize != 0)
373 memcpy(outbuf + sizeof(struct fuse_out_header), arg, argsize);
374
Miklos Szeredi43696432001-11-18 19:15:05 +0000375 send_reply_raw(f, outbuf, outsize);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000376
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000377 free(outbuf);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000378}
379
380static void do_lookup(struct fuse *f, struct fuse_in_header *in, char *name)
381{
382 int res;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000383 char *path;
384 struct stat buf;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000385 struct fuse_lookup_out arg;
386
Miklos Szeredi5e183482001-10-31 14:52:35 +0000387 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000388 path = get_path_name(f, in->ino, name);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000389 if(path != NULL) {
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 Szeredi2e50d432001-12-20 12:17:25 +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 Szeredife25def2001-12-20 15:38:05 +0000785 struct fuse_context *ctx = fuse_get_context(f);
Miklos Szeredia181e612001-11-06 12:03:23 +0000786
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +0000787 dec_avail(f);
Miklos Szeredi33232032001-11-19 17:55:51 +0000788
Miklos Szeredic0938ea2001-11-07 12:35:06 +0000789 if((f->flags & FUSE_DEBUG)) {
790 printf("unique: %i, opcode: %i, ino: %li, insize: %i\n", in->unique,
791 in->opcode, in->ino, cmd->buflen);
792 fflush(stdout);
793 }
Miklos Szeredife25def2001-12-20 15:38:05 +0000794
795 ctx->uid = in->uid;
796 ctx->gid = in->gid;
Miklos Szeredia181e612001-11-06 12:03:23 +0000797
798 argsize = cmd->buflen - sizeof(struct fuse_in_header);
799
800 switch(in->opcode) {
801 case FUSE_LOOKUP:
802 do_lookup(f, in, (char *) inarg);
803 break;
804
Miklos Szeredia181e612001-11-06 12:03:23 +0000805 case FUSE_GETATTR:
806 do_getattr(f, in);
807 break;
808
809 case FUSE_SETATTR:
810 do_setattr(f, in, (struct fuse_setattr_in *) inarg);
811 break;
812
813 case FUSE_READLINK:
814 do_readlink(f, in);
815 break;
816
817 case FUSE_GETDIR:
818 do_getdir(f, in);
819 break;
820
821 case FUSE_MKNOD:
822 do_mknod(f, in, (struct fuse_mknod_in *) inarg);
823 break;
824
825 case FUSE_MKDIR:
826 do_mkdir(f, in, (struct fuse_mkdir_in *) inarg);
827 break;
828
829 case FUSE_UNLINK:
830 case FUSE_RMDIR:
831 do_remove(f, in, (char *) inarg);
832 break;
833
834 case FUSE_SYMLINK:
835 do_symlink(f, in, (char *) inarg,
836 ((char *) inarg) + strlen((char *) inarg) + 1);
837 break;
838
839 case FUSE_RENAME:
840 do_rename(f, in, (struct fuse_rename_in *) inarg);
841 break;
842
843 case FUSE_LINK:
844 do_link(f, in, (struct fuse_link_in *) inarg);
845 break;
846
847 case FUSE_OPEN:
848 do_open(f, in, (struct fuse_open_in *) inarg);
849 break;
850
851 case FUSE_READ:
852 do_read(f, in, (struct fuse_read_in *) inarg);
853 break;
854
855 case FUSE_WRITE:
856 do_write(f, in, (struct fuse_write_in *) inarg);
857 break;
858
859 default:
860 fprintf(stderr, "Operation %i not implemented\n", in->opcode);
Miklos Szeredi43696432001-11-18 19:15:05 +0000861 send_reply(f, in, -ENOSYS, NULL, 0);
Miklos Szeredia181e612001-11-06 12:03:23 +0000862 }
Miklos Szeredi43696432001-11-18 19:15:05 +0000863
864 free_cmd(cmd);
Miklos Szeredia181e612001-11-06 12:03:23 +0000865}
866
Miklos Szeredifff56ab2001-11-16 10:12:59 +0000867struct fuse_cmd *__fuse_read_cmd(struct fuse *f)
Miklos Szeredi2df1c042001-11-06 15:07:17 +0000868{
Miklos Szeredifff56ab2001-11-16 10:12:59 +0000869 ssize_t res;
Miklos Szeredifff56ab2001-11-16 10:12:59 +0000870 struct fuse_cmd *cmd;
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +0000871 struct fuse_in_header *in;
872 void *inarg;
Miklos Szeredifff56ab2001-11-16 10:12:59 +0000873
Miklos Szeredi43696432001-11-18 19:15:05 +0000874 cmd = (struct fuse_cmd *) malloc(sizeof(struct fuse_cmd));
875 cmd->buf = (char *) malloc(FUSE_MAX_IN);
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +0000876 in = (struct fuse_in_header *) cmd->buf;
877 inarg = cmd->buf + sizeof(struct fuse_in_header);
Miklos Szeredi43696432001-11-18 19:15:05 +0000878
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +0000879 do {
880 res = read(f->fd, cmd->buf, FUSE_MAX_IN);
881 if(res == -1) {
882 /* ENODEV means we got unmounted, so we silenty return failure */
883 if(errno != ENODEV) {
884 perror("fuse: reading device");
885 /* BAD... This will happen again */
886 }
887 free_cmd(cmd);
888 return NULL;
Miklos Szeredi96249982001-11-21 12:21:19 +0000889 }
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +0000890 if((size_t) res < sizeof(struct fuse_in_header)) {
891 fprintf(stderr, "short read on fuse device\n");
892 /* Cannot happen */
893 free_cmd(cmd);
894 return NULL;
895 }
896 cmd->buflen = res;
897
898 /* Forget is special, it can be done without messing with threads. */
899 if(in->opcode == FUSE_FORGET)
900 do_forget(f, in, (struct fuse_forget_in *) inarg);
901
902 } while(in->opcode == FUSE_FORGET);
903
Miklos Szeredifff56ab2001-11-16 10:12:59 +0000904 return cmd;
Miklos Szeredi2df1c042001-11-06 15:07:17 +0000905}
906
Miklos Szeredifff56ab2001-11-16 10:12:59 +0000907
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000908void fuse_loop(struct fuse *f)
909{
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000910 while(1) {
Miklos Szeredifff56ab2001-11-16 10:12:59 +0000911 struct fuse_cmd *cmd = __fuse_read_cmd(f);
912 if(cmd == NULL)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000913 exit(1);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000914
Miklos Szeredifff56ab2001-11-16 10:12:59 +0000915 __fuse_process_cmd(f, cmd);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000916 }
917}
918
Miklos Szeredi2e50d432001-12-20 12:17:25 +0000919struct fuse_context *fuse_get_context(struct fuse *f)
920{
921 if(f->getcontext)
922 return f->getcontext(f);
923 else
924 return &f->context;
925}
926
927struct fuse *fuse_new(int fd, int flags, const struct fuse_operations *op)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000928{
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000929 struct fuse *f;
930 struct node *root;
Miklos Szeredife428122001-11-20 19:12:28 +0000931 char verstr[128];
Miklos Szeredicc8c9752001-11-21 10:03:39 +0000932 char *realver = getenv(FUSE_KERNEL_VERSION_ENV);
Miklos Szeredife428122001-11-20 19:12:28 +0000933
934 if(realver != NULL) {
935 sprintf(verstr, "%i", FUSE_KERNEL_VERSION);
936 if(strcmp(verstr, realver) != 0) {
937 fprintf(stderr,
938 "Warning: FUSE version mismatch: using %s, kernel is %s\n",
939 realver, verstr);
940 }
941 }
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000942
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000943 f = (struct fuse *) calloc(1, sizeof(struct fuse));
Miklos Szeredi2df1c042001-11-06 15:07:17 +0000944
Miklos Szeredia181e612001-11-06 12:03:23 +0000945 f->flags = flags;
Miklos Szeredi8cffdb92001-11-09 14:49:18 +0000946 f->fd = fd;
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000947 f->ctr = 0;
Miklos Szeredifff56ab2001-11-16 10:12:59 +0000948 /* FIXME: Dynamic hash table */
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000949 f->name_table_size = 14057;
950 f->name_table = (struct node **)
951 calloc(1, sizeof(struct node *) * f->name_table_size);
952 f->ino_table_size = 14057;
953 f->ino_table = (struct node **)
954 calloc(1, sizeof(struct node *) * f->ino_table_size);
Miklos Szeredia181e612001-11-06 12:03:23 +0000955 pthread_mutex_init(&f->lock, NULL);
Miklos Szeredi33232032001-11-19 17:55:51 +0000956 f->numworker = 0;
957 f->numavail = 0;
Miklos Szeredi2e50d432001-12-20 12:17:25 +0000958 f->op = *op;
959 f->getcontext = NULL;
960 f->context.uid = 0;
961 f->context.gid = 0;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000962
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000963 root = (struct node *) calloc(1, sizeof(struct node));
Miklos Szeredi8cffdb92001-11-09 14:49:18 +0000964 root->mode = 0;
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000965 root->rdev = 0;
966 root->name = strdup("/");
967 root->parent = 0;
968 hash_ino(f, root, FUSE_ROOT_INO);
969
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000970 return f;
971}
972
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000973void fuse_destroy(struct fuse *f)
974{
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000975 size_t i;
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000976 for(i = 0; i < f->ino_table_size; i++) {
977 struct node *node;
978 struct node *next;
979 for(node = f->ino_table[i]; node != NULL; node = next) {
980 next = node->ino_next;
981 free_node(node);
982 }
983 }
984 free(f->ino_table);
985 free(f->name_table);
Miklos Szeredia181e612001-11-06 12:03:23 +0000986 pthread_mutex_destroy(&f->lock);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000987 free(f);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000988}