blob: fe670d8648d01a121224abc0a6e50841b09cf4f3 [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
Miklos Szeredi8b39a9f2002-10-25 12:41:16 +00005 This program can be distributed under the terms of the GNU LGPL.
6 See the file COPYING.LIB
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00007*/
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 Szeredi6bf8b682002-10-28 08:49:39 +000020#define PARAM(inarg) (((char *)(inarg)) + sizeof(*inarg))
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000021
Miklos Szeredic8ba2372002-12-10 12:26:00 +000022static const char *opname(enum fuse_opcode opcode)
23{
24 switch(opcode) {
25 case FUSE_LOOKUP: return "LOOKUP";
26 case FUSE_FORGET: return "FORGET";
27 case FUSE_GETATTR: return "GETATTR";
28 case FUSE_SETATTR: return "SETATTR";
29 case FUSE_READLINK: return "READLINK";
30 case FUSE_SYMLINK: return "SYMLINK";
31 case FUSE_GETDIR: return "GETDIR";
32 case FUSE_MKNOD: return "MKNOD";
33 case FUSE_MKDIR: return "MKDIR";
34 case FUSE_UNLINK: return "UNLINK";
35 case FUSE_RMDIR: return "RMDIR";
36 case FUSE_RENAME: return "RENAME";
37 case FUSE_LINK: return "LINK";
38 case FUSE_OPEN: return "OPEN";
39 case FUSE_READ: return "READ";
40 case FUSE_WRITE: return "WRITE";
41 case FUSE_STATFS: return "STATFS";
42 case FUSE_RELEASE: return "RELEASE";
43 default: return "???";
44 }
45}
46
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +000047static inline void inc_avail(struct fuse *f)
48{
49 pthread_mutex_lock(&f->lock);
50 f->numavail ++;
51 pthread_mutex_unlock(&f->lock);
52}
53
54static inline void dec_avail(struct fuse *f)
55{
56 pthread_mutex_lock(&f->lock);
57 f->numavail --;
58 pthread_mutex_unlock(&f->lock);
59}
60
Miklos Szeredi97c61e92001-11-07 12:09:43 +000061static struct node *__get_node(struct fuse *f, fino_t ino)
Miklos Szeredia181e612001-11-06 12:03:23 +000062{
Miklos Szeredi97c61e92001-11-07 12:09:43 +000063 size_t hash = ino % f->ino_table_size;
64 struct node *node;
65
66 for(node = f->ino_table[hash]; node != NULL; node = node->ino_next)
67 if(node->ino == ino)
68 return node;
69
70 return NULL;
Miklos Szeredia181e612001-11-06 12:03:23 +000071}
72
Miklos Szeredi97c61e92001-11-07 12:09:43 +000073static struct node *get_node(struct fuse *f, fino_t ino)
Miklos Szeredia181e612001-11-06 12:03:23 +000074{
Miklos Szeredi97c61e92001-11-07 12:09:43 +000075 struct node *node = __get_node(f, ino);
76 if(node != NULL)
77 return node;
78
79 fprintf(stderr, "fuse internal error: inode %lu not found\n", ino);
80 abort();
Miklos Szeredia181e612001-11-06 12:03:23 +000081}
82
Miklos Szeredi97c61e92001-11-07 12:09:43 +000083static void hash_ino(struct fuse *f, struct node *node, fino_t ino)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000084{
Miklos Szeredi97c61e92001-11-07 12:09:43 +000085 size_t hash = ino % f->ino_table_size;
86 node->ino = ino;
87
88 node->ino_next = f->ino_table[hash];
89 f->ino_table[hash] = node;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000090}
91
Miklos Szeredi97c61e92001-11-07 12:09:43 +000092static void unhash_ino(struct fuse *f, struct node *node)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000093{
Miklos Szeredi97c61e92001-11-07 12:09:43 +000094 size_t hash = node->ino % f->ino_table_size;
95 struct node **nodep = &f->ino_table[hash];
96
97 for(; *nodep != NULL; nodep = &(*nodep)->ino_next)
98 if(*nodep == node) {
99 *nodep = node->ino_next;
100 return;
101 }
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000102}
103
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000104static fino_t get_ino(struct node *node)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000105{
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000106 return node->ino;
107}
108
109static fino_t next_ino(struct fuse *f)
110{
111 while(f->ctr == 0 || __get_node(f, f->ctr) != NULL)
112 f->ctr++;
113
114 return f->ctr;
115}
116
117static void free_node(struct node *node)
118{
119 free(node->name);
120 free(node);
121}
122
123static unsigned int name_hash(struct fuse *f, fino_t parent, const char *name)
124{
125 unsigned int hash = *name;
126
127 if(hash)
128 for(name += 1; *name != '\0'; name++)
129 hash = (hash << 5) - hash + *name;
130
131 return (hash + parent) % f->name_table_size;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000132}
133
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000134static struct node *lookup_node(struct fuse *f, fino_t parent,
135 const char *name)
136{
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000137 size_t hash = name_hash(f, parent, name);
138 struct node *node;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000139
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000140 for(node = f->name_table[hash]; node != NULL; node = node->name_next)
141 if(node->parent == parent && strcmp(node->name, name) == 0)
142 return node;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000143
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000144 return NULL;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000145}
146
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000147static void hash_name(struct fuse *f, struct node *node, fino_t parent,
Miklos Szeredia181e612001-11-06 12:03:23 +0000148 const char *name)
Miklos Szeredi5e183482001-10-31 14:52:35 +0000149{
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000150 size_t hash = name_hash(f, parent, name);
Miklos Szeredia181e612001-11-06 12:03:23 +0000151 node->parent = parent;
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000152 node->name = strdup(name);
153 node->name_next = f->name_table[hash];
154 f->name_table[hash] = node;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000155}
156
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000157static void unhash_name(struct fuse *f, struct node *node)
Miklos Szeredia181e612001-11-06 12:03:23 +0000158{
159 if(node->name != NULL) {
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000160 size_t hash = name_hash(f, node->parent, node->name);
161 struct node **nodep = &f->name_table[hash];
162
163 for(; *nodep != NULL; nodep = &(*nodep)->name_next)
164 if(*nodep == node) {
165 *nodep = node->name_next;
166 node->name_next = NULL;
167 free(node->name);
168 node->name = NULL;
169 node->parent = 0;
170 return;
171 }
172 fprintf(stderr, "fuse internal error: unable to unhash node: %lu\n",
173 node->ino);
174 abort();
Miklos Szeredia181e612001-11-06 12:03:23 +0000175 }
176}
177
178static fino_t find_node(struct fuse *f, fino_t parent, char *name,
179 struct fuse_attr *attr, int version)
Miklos Szeredi5e183482001-10-31 14:52:35 +0000180{
181 struct node *node;
Miklos Szeredia181e612001-11-06 12:03:23 +0000182 int mode = attr->mode & S_IFMT;
183 int rdev = 0;
184
185 if(S_ISCHR(mode) || S_ISBLK(mode))
186 rdev = attr->rdev;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000187
Miklos Szeredia181e612001-11-06 12:03:23 +0000188 pthread_mutex_lock(&f->lock);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000189 node = lookup_node(f, parent, name);
190 if(node != NULL) {
Miklos Szeredia181e612001-11-06 12:03:23 +0000191 if(node->mode == mode && node->rdev == rdev)
192 goto out;
193
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000194 unhash_name(f, node);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000195 }
196
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000197 node = (struct node *) calloc(1, sizeof(struct node));
Miklos Szeredia181e612001-11-06 12:03:23 +0000198 node->mode = mode;
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000199 node->rdev = rdev;
200 hash_ino(f, node, next_ino(f));
201 hash_name(f, node, parent, name);
Miklos Szeredia181e612001-11-06 12:03:23 +0000202
203 out:
204 node->version = version;
205 pthread_mutex_unlock(&f->lock);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000206 return get_ino(node);
207}
208
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000209static char *add_name(char *buf, char *s, const char *name)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000210{
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000211 size_t len = strlen(name);
212 s -= len;
213 if(s <= buf) {
214 fprintf(stderr, "fuse: path too long: ...%s\n", s + len);
215 return NULL;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000216 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000217 strncpy(s, name, len);
218 s--;
219 *s = '/';
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000220
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000221 return s;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000222}
223
Miklos Szeredia181e612001-11-06 12:03:23 +0000224static char *get_path_name(struct fuse *f, fino_t ino, const char *name)
Miklos Szeredib483c932001-10-29 14:57:57 +0000225{
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000226 char buf[FUSE_MAX_PATH];
227 char *s = buf + FUSE_MAX_PATH - 1;
228 struct node *node;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000229
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000230 *s = '\0';
Miklos Szeredia181e612001-11-06 12:03:23 +0000231
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000232 if(name != NULL) {
233 s = add_name(buf, s, name);
234 if(s == NULL)
235 return NULL;
236 }
237
238 pthread_mutex_lock(&f->lock);
239 for(node = get_node(f, ino); node->ino != FUSE_ROOT_INO;
240 node = get_node(f, node->parent)) {
241 if(node->name == NULL) {
242 s = NULL;
243 break;
244 }
245
246 s = add_name(buf, s, node->name);
247 if(s == NULL)
248 break;
249 }
250 pthread_mutex_unlock(&f->lock);
251
252 if(s == NULL)
Miklos Szeredi5e183482001-10-31 14:52:35 +0000253 return NULL;
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000254 else if(*s == '\0')
255 return strdup("/");
256 else
257 return strdup(s);
258}
Miklos Szeredia181e612001-11-06 12:03:23 +0000259
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000260static char *get_path(struct fuse *f, fino_t ino)
261{
262 return get_path_name(f, ino, NULL);
Miklos Szeredib483c932001-10-29 14:57:57 +0000263}
264
Miklos Szeredia181e612001-11-06 12:03:23 +0000265static void destroy_node(struct fuse *f, fino_t ino, int version)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000266{
Miklos Szeredia181e612001-11-06 12:03:23 +0000267 struct node *node;
268
269 pthread_mutex_lock(&f->lock);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000270 node = get_node(f, ino);
Miklos Szeredi39f28672001-11-14 14:52:54 +0000271 if(node->version == version && ino != FUSE_ROOT_INO) {
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000272 unhash_name(f, node);
273 unhash_ino(f, node);
Miklos Szeredia181e612001-11-06 12:03:23 +0000274 free_node(node);
275 }
276 pthread_mutex_unlock(&f->lock);
277
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000278}
279
Miklos Szeredi5e183482001-10-31 14:52:35 +0000280static void remove_node(struct fuse *f, fino_t dir, const char *name)
281{
Miklos Szeredia181e612001-11-06 12:03:23 +0000282 struct node *node;
283
284 pthread_mutex_lock(&f->lock);
285 node = lookup_node(f, dir, name);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000286 if(node == NULL) {
287 fprintf(stderr, "fuse internal error: unable to remove node %lu/%s\n",
288 dir, name);
289 abort();
290 }
291 unhash_name(f, node);
Miklos Szeredia181e612001-11-06 12:03:23 +0000292 pthread_mutex_unlock(&f->lock);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000293}
294
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000295static void rename_node(struct fuse *f, fino_t olddir, const char *oldname,
296 fino_t newdir, const char *newname)
297{
Miklos Szeredia181e612001-11-06 12:03:23 +0000298 struct node *node;
299 struct node *newnode;
300
301 pthread_mutex_lock(&f->lock);
302 node = lookup_node(f, olddir, oldname);
303 newnode = lookup_node(f, newdir, newname);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000304 if(node == NULL) {
305 fprintf(stderr, "fuse internal error: unable to rename node %lu/%s\n",
306 olddir, oldname);
307 abort();
308 }
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000309
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000310 if(newnode != NULL)
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000311 unhash_name(f, newnode);
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000312
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000313 unhash_name(f, node);
314 hash_name(f, node, newdir, newname);
Miklos Szeredia181e612001-11-06 12:03:23 +0000315 pthread_mutex_unlock(&f->lock);
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000316}
317
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000318static void convert_stat(struct stat *stbuf, struct fuse_attr *attr)
319{
320 attr->mode = stbuf->st_mode;
321 attr->nlink = stbuf->st_nlink;
322 attr->uid = stbuf->st_uid;
323 attr->gid = stbuf->st_gid;
324 attr->rdev = stbuf->st_rdev;
325 attr->size = stbuf->st_size;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000326 attr->blocks = stbuf->st_blocks;
327 attr->atime = stbuf->st_atime;
328 attr->mtime = stbuf->st_mtime;
329 attr->ctime = stbuf->st_ctime;
Miklos Szeredifff56ab2001-11-16 10:12:59 +0000330 attr->_dummy = 4096;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000331}
332
Miklos Szeredia181e612001-11-06 12:03:23 +0000333static int fill_dir(struct fuse_dirhandle *dh, char *name, int type)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000334{
335 struct fuse_dirent dirent;
336 size_t reclen;
337 size_t res;
338
Miklos Szeredi43696432001-11-18 19:15:05 +0000339 dirent.ino = (unsigned long) -1;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000340 dirent.namelen = strlen(name);
341 strncpy(dirent.name, name, sizeof(dirent.name));
342 dirent.type = type;
343 reclen = FUSE_DIRENT_SIZE(&dirent);
344 res = fwrite(&dirent, reclen, 1, dh->fp);
345 if(res == 0) {
Miklos Szeredi96249982001-11-21 12:21:19 +0000346 perror("fuse: writing directory file");
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000347 return -EIO;
348 }
349 return 0;
350}
351
Miklos Szeredi43696432001-11-18 19:15:05 +0000352static void send_reply_raw(struct fuse *f, char *outbuf, size_t outsize)
353{
354 int res;
355
356 if((f->flags & FUSE_DEBUG)) {
357 struct fuse_out_header *out = (struct fuse_out_header *) outbuf;
358 printf(" unique: %i, error: %i (%s), outsize: %i\n", out->unique,
359 out->error, strerror(-out->error), outsize);
360 fflush(stdout);
361 }
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +0000362
363 /* This needs to be done before the reply because otherwise the
364 scheduler can tricks with us, and only let the counter be increased
365 long after the operation is done */
366 inc_avail(f);
367
Miklos Szeredi43696432001-11-18 19:15:05 +0000368 res = write(f->fd, outbuf, outsize);
369 if(res == -1) {
370 /* ENOENT means the operation was interrupted */
371 if(errno != ENOENT)
Miklos Szeredi96249982001-11-21 12:21:19 +0000372 perror("fuse: writing device");
Miklos Szeredi43696432001-11-18 19:15:05 +0000373 }
374}
375
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000376static void send_reply(struct fuse *f, struct fuse_in_header *in, int error,
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000377 void *arg, size_t argsize)
378{
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000379 char *outbuf;
380 size_t outsize;
381 struct fuse_out_header *out;
382
Miklos Szeredi0f48a262002-12-05 14:23:01 +0000383 if(error <= -512 || error > 0) {
384 fprintf(stderr, "fuse: bad error value: %i\n", error);
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000385 error = -ERANGE;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000386 }
387
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000388 if(error)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000389 argsize = 0;
390
391 outsize = sizeof(struct fuse_out_header) + argsize;
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000392 outbuf = (char *) malloc(outsize);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000393 out = (struct fuse_out_header *) outbuf;
Miklos Szeredi0f48a262002-12-05 14:23:01 +0000394 memset(out, 0, sizeof(struct fuse_out_header));
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000395 out->unique = in->unique;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000396 out->error = error;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000397 if(argsize != 0)
398 memcpy(outbuf + sizeof(struct fuse_out_header), arg, argsize);
399
Miklos Szeredi43696432001-11-18 19:15:05 +0000400 send_reply_raw(f, outbuf, outsize);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000401
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000402 free(outbuf);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000403}
404
405static void do_lookup(struct fuse *f, struct fuse_in_header *in, char *name)
406{
407 int res;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000408 char *path;
409 struct stat buf;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000410 struct fuse_lookup_out arg;
411
Miklos Szeredi5e183482001-10-31 14:52:35 +0000412 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000413 path = get_path_name(f, in->ino, name);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000414 if(path != NULL) {
Miklos Szeredi6ebe2342002-01-06 21:44:16 +0000415 if(f->flags & FUSE_DEBUG) {
416 printf("LOOKUP %s\n", path);
417 fflush(stdout);
418 }
Miklos Szeredi5e183482001-10-31 14:52:35 +0000419 res = -ENOSYS;
420 if(f->op.getattr)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000421 res = f->op.getattr(path, &buf);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000422 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000423 }
Miklos Szeredi0f48a262002-12-05 14:23:01 +0000424
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000425 if(res == 0) {
Miklos Szeredi0f48a262002-12-05 14:23:01 +0000426 memset(&arg, 0, sizeof(struct fuse_lookup_out));
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000427 convert_stat(&buf, &arg.attr);
Miklos Szeredia181e612001-11-06 12:03:23 +0000428 arg.ino = find_node(f, in->ino, name, &arg.attr, in->unique);
Miklos Szeredi6ebe2342002-01-06 21:44:16 +0000429 if(f->flags & FUSE_DEBUG) {
430 printf(" LOOKUP: %li\n", arg.ino);
431 fflush(stdout);
432 }
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000433 }
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000434 send_reply(f, in, res, &arg, sizeof(arg));
435}
436
Miklos Szeredia181e612001-11-06 12:03:23 +0000437static void do_forget(struct fuse *f, struct fuse_in_header *in,
438 struct fuse_forget_in *arg)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000439{
Miklos Szeredi43696432001-11-18 19:15:05 +0000440 if(f->flags & FUSE_DEBUG) {
441 printf("FORGET %li/%i\n", in->ino, arg->version);
442 fflush(stdout);
443 }
Miklos Szeredia181e612001-11-06 12:03:23 +0000444 destroy_node(f, in->ino, arg->version);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000445}
446
447static void do_getattr(struct fuse *f, struct fuse_in_header *in)
448{
449 int res;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000450 char *path;
451 struct stat buf;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000452 struct fuse_getattr_out arg;
453
Miklos Szeredi5e183482001-10-31 14:52:35 +0000454 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000455 path = get_path(f, in->ino);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000456 if(path != NULL) {
457 res = -ENOSYS;
458 if(f->op.getattr)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000459 res = f->op.getattr(path, &buf);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000460 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000461 }
Miklos Szeredi0f48a262002-12-05 14:23:01 +0000462
463 if(res == 0) {
464 memset(&arg, 0, sizeof(struct fuse_getattr_out));
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000465 convert_stat(&buf, &arg.attr);
Miklos Szeredi0f48a262002-12-05 14:23:01 +0000466 }
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000467
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000468 send_reply(f, in, res, &arg, sizeof(arg));
469}
470
Miklos Szeredi680a69a2001-11-16 13:31:14 +0000471static int do_chmod(struct fuse *f, const char *path, struct fuse_attr *attr)
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000472{
473 int res;
474
475 res = -ENOSYS;
476 if(f->op.chmod)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000477 res = f->op.chmod(path, attr->mode);
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000478
479 return res;
480}
481
Miklos Szeredi680a69a2001-11-16 13:31:14 +0000482static int do_chown(struct fuse *f, const char *path, struct fuse_attr *attr,
Miklos Szeredi2e50d432001-12-20 12:17:25 +0000483 int valid)
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000484{
485 int res;
486 uid_t uid = (valid & FATTR_UID) ? attr->uid : (uid_t) -1;
487 gid_t gid = (valid & FATTR_GID) ? attr->gid : (gid_t) -1;
488
489 res = -ENOSYS;
490 if(f->op.chown)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000491 res = f->op.chown(path, uid, gid);
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000492
493 return res;
494}
495
Miklos Szeredi680a69a2001-11-16 13:31:14 +0000496static int do_truncate(struct fuse *f, const char *path,
497 struct fuse_attr *attr)
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000498{
499 int res;
500
501 res = -ENOSYS;
502 if(f->op.truncate)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000503 res = f->op.truncate(path, attr->size);
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000504
505 return res;
506}
507
Miklos Szeredi680a69a2001-11-16 13:31:14 +0000508static int do_utime(struct fuse *f, const char *path, struct fuse_attr *attr)
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000509{
510 int res;
511 struct utimbuf buf;
512 buf.actime = attr->atime;
513 buf.modtime = attr->mtime;
514 res = -ENOSYS;
515 if(f->op.utime)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000516 res = f->op.utime(path, &buf);
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000517
518 return res;
519}
520
Miklos Szeredi5e183482001-10-31 14:52:35 +0000521static void do_setattr(struct fuse *f, struct fuse_in_header *in,
522 struct fuse_setattr_in *arg)
523{
524 int res;
525 char *path;
526 int valid = arg->valid;
527 struct fuse_attr *attr = &arg->attr;
Miklos Szeredia181e612001-11-06 12:03:23 +0000528 struct fuse_setattr_out outarg;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000529
530 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000531 path = get_path(f, in->ino);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000532 if(path != NULL) {
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000533 res = -ENOSYS;
534 if(f->op.getattr) {
535 res = 0;
536 if(!res && (valid & FATTR_MODE))
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000537 res = do_chmod(f, path, attr);
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000538 if(!res && (valid & (FATTR_UID | FATTR_GID)))
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000539 res = do_chown(f, path, attr, valid);
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000540 if(!res && (valid & FATTR_SIZE))
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000541 res = do_truncate(f, path, attr);
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000542 if(!res && (valid & FATTR_UTIME))
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000543 res = do_utime(f, path, attr);
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000544 if(!res) {
545 struct stat buf;
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000546 res = f->op.getattr(path, &buf);
Miklos Szeredi0f48a262002-12-05 14:23:01 +0000547 if(!res) {
548 memset(&outarg, 0, sizeof(struct fuse_setattr_out));
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000549 convert_stat(&buf, &outarg.attr);
Miklos Szeredi0f48a262002-12-05 14:23:01 +0000550 }
Miklos Szeredia181e612001-11-06 12:03:23 +0000551 }
Miklos Szeredi5e183482001-10-31 14:52:35 +0000552 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000553 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000554 }
Miklos Szeredia181e612001-11-06 12:03:23 +0000555 send_reply(f, in, res, &outarg, sizeof(outarg));
Miklos Szeredi5e183482001-10-31 14:52:35 +0000556}
557
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000558static void do_readlink(struct fuse *f, struct fuse_in_header *in)
559{
560 int res;
561 char link[PATH_MAX + 1];
Miklos Szeredib483c932001-10-29 14:57:57 +0000562 char *path;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000563
Miklos Szeredi5e183482001-10-31 14:52:35 +0000564 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000565 path = get_path(f, in->ino);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000566 if(path != NULL) {
567 res = -ENOSYS;
568 if(f->op.readlink)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000569 res = f->op.readlink(path, link, sizeof(link));
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000570 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000571 }
Miklos Szeredi2df1c042001-11-06 15:07:17 +0000572 link[PATH_MAX] = '\0';
Miklos Szeredi4b2bef42002-01-09 12:23:27 +0000573 send_reply(f, in, res, link, res == 0 ? strlen(link) : 0);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000574}
575
576static void do_getdir(struct fuse *f, struct fuse_in_header *in)
577{
578 int res;
579 struct fuse_getdir_out arg;
Miklos Szeredia181e612001-11-06 12:03:23 +0000580 struct fuse_dirhandle dh;
Miklos Szeredib483c932001-10-29 14:57:57 +0000581 char *path;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000582
Miklos Szeredib483c932001-10-29 14:57:57 +0000583 dh.fuse = f;
584 dh.fp = tmpfile();
585 dh.dir = in->ino;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000586 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000587 path = get_path(f, in->ino);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000588 if(path != NULL) {
589 res = -ENOSYS;
590 if(f->op.getdir)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000591 res = f->op.getdir(path, &dh, (fuse_dirfil_t) fill_dir);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000592 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000593 }
Miklos Szeredib483c932001-10-29 14:57:57 +0000594 fflush(dh.fp);
Miklos Szeredi0f48a262002-12-05 14:23:01 +0000595
596 memset(&arg, 0, sizeof(struct fuse_getdir_out));
Miklos Szeredib483c932001-10-29 14:57:57 +0000597 arg.fd = fileno(dh.fp);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000598 send_reply(f, in, res, &arg, sizeof(arg));
Miklos Szeredib483c932001-10-29 14:57:57 +0000599 fclose(dh.fp);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000600}
601
Miklos Szeredib483c932001-10-29 14:57:57 +0000602static void do_mknod(struct fuse *f, struct fuse_in_header *in,
603 struct fuse_mknod_in *inarg)
604{
605 int res;
606 char *path;
607 struct fuse_mknod_out outarg;
608 struct stat buf;
609
Miklos Szeredi5e183482001-10-31 14:52:35 +0000610 res = -ENOENT;
Miklos Szeredi6bf8b682002-10-28 08:49:39 +0000611 path = get_path_name(f, in->ino, PARAM(inarg));
Miklos Szeredi5e183482001-10-31 14:52:35 +0000612 if(path != NULL) {
613 res = -ENOSYS;
614 if(f->op.mknod && f->op.getattr) {
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000615 res = f->op.mknod(path, inarg->mode, inarg->rdev);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000616 if(res == 0)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000617 res = f->op.getattr(path, &buf);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000618 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000619 free(path);
Miklos Szeredib483c932001-10-29 14:57:57 +0000620 }
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000621 if(res == 0) {
Miklos Szeredi0f48a262002-12-05 14:23:01 +0000622 memset(&outarg, 0, sizeof(struct fuse_mknod_out));
Miklos Szeredib483c932001-10-29 14:57:57 +0000623 convert_stat(&buf, &outarg.attr);
Miklos Szeredi6bf8b682002-10-28 08:49:39 +0000624 outarg.ino = find_node(f, in->ino, PARAM(inarg), &outarg.attr,
Miklos Szeredia181e612001-11-06 12:03:23 +0000625 in->unique);
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000626 }
Miklos Szeredib483c932001-10-29 14:57:57 +0000627
628 send_reply(f, in, res, &outarg, sizeof(outarg));
629}
630
631static void do_mkdir(struct fuse *f, struct fuse_in_header *in,
632 struct fuse_mkdir_in *inarg)
633{
634 int res;
635 char *path;
636
Miklos Szeredi5e183482001-10-31 14:52:35 +0000637 res = -ENOENT;
Miklos Szeredi6bf8b682002-10-28 08:49:39 +0000638 path = get_path_name(f, in->ino, PARAM(inarg));
Miklos Szeredi5e183482001-10-31 14:52:35 +0000639 if(path != NULL) {
640 res = -ENOSYS;
641 if(f->op.mkdir)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000642 res = f->op.mkdir(path, inarg->mode);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000643 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000644 }
Miklos Szeredib483c932001-10-29 14:57:57 +0000645 send_reply(f, in, res, NULL, 0);
646}
647
648static void do_remove(struct fuse *f, struct fuse_in_header *in, char *name)
649{
650 int res;
651 char *path;
652
Miklos Szeredi5e183482001-10-31 14:52:35 +0000653 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000654 path = get_path_name(f, in->ino, name);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000655 if(path != NULL) {
656 res = -ENOSYS;
657 if(in->opcode == FUSE_UNLINK) {
658 if(f->op.unlink)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000659 res = f->op.unlink(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000660 }
661 else {
662 if(f->op.rmdir)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000663 res = f->op.rmdir(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000664 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000665 free(path);
Miklos Szeredib483c932001-10-29 14:57:57 +0000666 }
Miklos Szeredi5e183482001-10-31 14:52:35 +0000667 if(res == 0)
668 remove_node(f, in->ino, name);
Miklos Szeredib483c932001-10-29 14:57:57 +0000669 send_reply(f, in, res, NULL, 0);
670}
671
672static void do_symlink(struct fuse *f, struct fuse_in_header *in, char *name,
673 char *link)
674{
675 int res;
676 char *path;
677
Miklos Szeredi5e183482001-10-31 14:52:35 +0000678 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000679 path = get_path_name(f, in->ino, name);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000680 if(path != NULL) {
681 res = -ENOSYS;
682 if(f->op.symlink)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000683 res = f->op.symlink(link, path);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000684 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000685 }
Miklos Szeredib483c932001-10-29 14:57:57 +0000686 send_reply(f, in, res, NULL, 0);
687}
688
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000689static void do_rename(struct fuse *f, struct fuse_in_header *in,
690 struct fuse_rename_in *inarg)
691{
692 int res;
693 fino_t olddir = in->ino;
694 fino_t newdir = inarg->newdir;
Miklos Szeredi6bf8b682002-10-28 08:49:39 +0000695 char *oldname = PARAM(inarg);
696 char *newname = oldname + strlen(oldname) + 1;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000697 char *oldpath;
698 char *newpath;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000699
Miklos Szeredi5e183482001-10-31 14:52:35 +0000700 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000701 oldpath = get_path_name(f, olddir, oldname);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000702 if(oldpath != NULL) {
Miklos Szeredia181e612001-11-06 12:03:23 +0000703 newpath = get_path_name(f, newdir, newname);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000704 if(newpath != NULL) {
705 res = -ENOSYS;
706 if(f->op.rename)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000707 res = f->op.rename(oldpath, newpath);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000708 if(res == 0)
709 rename_node(f, olddir, oldname, newdir, newname);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000710 free(newpath);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000711 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000712 free(oldpath);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000713 }
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000714 send_reply(f, in, res, NULL, 0);
715}
716
717static void do_link(struct fuse *f, struct fuse_in_header *in,
Miklos Szeredi5e183482001-10-31 14:52:35 +0000718 struct fuse_link_in *arg)
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000719{
720 int res;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000721 char *oldpath;
722 char *newpath;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000723
Miklos Szeredi5e183482001-10-31 14:52:35 +0000724 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000725 oldpath = get_path(f, in->ino);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000726 if(oldpath != NULL) {
Miklos Szeredi6bf8b682002-10-28 08:49:39 +0000727 newpath = get_path_name(f, arg->newdir, PARAM(arg));
Miklos Szeredi5e183482001-10-31 14:52:35 +0000728 if(newpath != NULL) {
729 res = -ENOSYS;
730 if(f->op.link)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000731 res = f->op.link(oldpath, newpath);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000732 free(newpath);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000733 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000734 free(oldpath);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000735 }
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000736 send_reply(f, in, res, NULL, 0);
737}
738
Miklos Szeredi5e183482001-10-31 14:52:35 +0000739static void do_open(struct fuse *f, struct fuse_in_header *in,
740 struct fuse_open_in *arg)
741{
742 int res;
743 char *path;
744
745 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000746 path = get_path(f, in->ino);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000747 if(path != NULL) {
748 res = -ENOSYS;
749 if(f->op.open)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000750 res = f->op.open(path, arg->flags);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000751 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000752 }
753 send_reply(f, in, res, NULL, 0);
754}
755
Miklos Szeredic8ba2372002-12-10 12:26:00 +0000756static void do_release(struct fuse *f, struct fuse_in_header *in)
757{
Miklos Szeredic8ba2372002-12-10 12:26:00 +0000758 char *path;
759
Miklos Szeredic8ba2372002-12-10 12:26:00 +0000760 path = get_path(f, in->ino);
761 if(path != NULL) {
Miklos Szeredic8ba2372002-12-10 12:26:00 +0000762 if(f->op.release)
Miklos Szeredi383a9df2002-12-10 14:54:57 +0000763 f->op.release(path);
Miklos Szeredic8ba2372002-12-10 12:26:00 +0000764 free(path);
765 }
Miklos Szeredic8ba2372002-12-10 12:26:00 +0000766}
767
Miklos Szeredi5e183482001-10-31 14:52:35 +0000768static void do_read(struct fuse *f, struct fuse_in_header *in,
769 struct fuse_read_in *arg)
770{
771 int res;
772 char *path;
Miklos Szeredi43696432001-11-18 19:15:05 +0000773 char *outbuf = (char *) malloc(sizeof(struct fuse_out_header) + arg->size);
774 struct fuse_out_header *out = (struct fuse_out_header *) outbuf;
775 char *buf = outbuf + sizeof(struct fuse_out_header);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000776 size_t size;
Miklos Szeredi43696432001-11-18 19:15:05 +0000777 size_t outsize;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000778
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000779 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000780 path = get_path(f, in->ino);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000781 if(path != NULL) {
Miklos Szeredi6ebe2342002-01-06 21:44:16 +0000782 if(f->flags & FUSE_DEBUG) {
783 printf("READ %u bytes from %llu\n", arg->size, arg->offset);
784 fflush(stdout);
785 }
786
Miklos Szeredi5e183482001-10-31 14:52:35 +0000787 res = -ENOSYS;
Miklos Szeredia181e612001-11-06 12:03:23 +0000788 if(f->op.read)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000789 res = f->op.read(path, buf, arg->size, arg->offset);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000790 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000791 }
792
793 size = 0;
794 if(res > 0) {
795 size = res;
796 res = 0;
Miklos Szeredi6ebe2342002-01-06 21:44:16 +0000797 if(f->flags & FUSE_DEBUG) {
798 printf(" READ %u bytes\n", size);
799 fflush(stdout);
800 }
Miklos Szeredi5e183482001-10-31 14:52:35 +0000801 }
Miklos Szeredi0f48a262002-12-05 14:23:01 +0000802 memset(out, 0, sizeof(struct fuse_out_header));
Miklos Szeredi43696432001-11-18 19:15:05 +0000803 out->unique = in->unique;
804 out->error = res;
805 outsize = sizeof(struct fuse_out_header) + size;
806
807 send_reply_raw(f, outbuf, outsize);
808 free(outbuf);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000809}
Miklos Szeredib483c932001-10-29 14:57:57 +0000810
Miklos Szeredia181e612001-11-06 12:03:23 +0000811static void do_write(struct fuse *f, struct fuse_in_header *in,
812 struct fuse_write_in *arg)
813{
814 int res;
815 char *path;
Miklos Szeredia181e612001-11-06 12:03:23 +0000816
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000817 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000818 path = get_path(f, in->ino);
819 if(path != NULL) {
Miklos Szeredi6ebe2342002-01-06 21:44:16 +0000820 if(f->flags & FUSE_DEBUG) {
821 printf("WRITE %u bytes to %llu\n", arg->size, arg->offset);
822 fflush(stdout);
823 }
824
Miklos Szeredia181e612001-11-06 12:03:23 +0000825 res = -ENOSYS;
826 if(f->op.write)
Miklos Szeredi6bf8b682002-10-28 08:49:39 +0000827 res = f->op.write(path, PARAM(arg), arg->size, arg->offset);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000828 free(path);
Miklos Szeredia181e612001-11-06 12:03:23 +0000829 }
830
831 if(res > 0) {
832 if((size_t) res != arg->size) {
833 fprintf(stderr, "short write: %u (should be %u)\n", res,
834 arg->size);
835 res = -EIO;
836 }
837 else
838 res = 0;
839 }
840
841 send_reply(f, in, res, NULL, 0);
842}
843
Mark Glinesd84b39a2002-01-07 16:32:02 +0000844static void do_statfs(struct fuse *f, struct fuse_in_header *in)
845{
846 int res;
Mark Glinesd84b39a2002-01-07 16:32:02 +0000847 struct fuse_statfs_out arg;
848
849 res = -ENOSYS;
Miklos Szeredi0f48a262002-12-05 14:23:01 +0000850 if(f->op.statfs) {
851 memset(&arg, 0, sizeof(struct fuse_statfs_out));
Miklos Szeredi24ed9452002-10-07 10:24:26 +0000852 res = f->op.statfs((struct fuse_statfs *) &arg.st);
Miklos Szeredi0f48a262002-12-05 14:23:01 +0000853 }
Miklos Szeredi4b2bef42002-01-09 12:23:27 +0000854
Mark Glinesd84b39a2002-01-07 16:32:02 +0000855 send_reply(f, in, res, &arg, sizeof(arg));
856}
857
Miklos Szeredi43696432001-11-18 19:15:05 +0000858static void free_cmd(struct fuse_cmd *cmd)
859{
860 free(cmd->buf);
861 free(cmd);
862}
863
Miklos Szeredifff56ab2001-11-16 10:12:59 +0000864void __fuse_process_cmd(struct fuse *f, struct fuse_cmd *cmd)
Miklos Szeredia181e612001-11-06 12:03:23 +0000865{
Miklos Szeredia181e612001-11-06 12:03:23 +0000866 struct fuse_in_header *in = (struct fuse_in_header *) cmd->buf;
867 void *inarg = cmd->buf + sizeof(struct fuse_in_header);
868 size_t argsize;
Miklos Szeredife25def2001-12-20 15:38:05 +0000869 struct fuse_context *ctx = fuse_get_context(f);
Miklos Szeredia181e612001-11-06 12:03:23 +0000870
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +0000871 dec_avail(f);
Miklos Szeredi33232032001-11-19 17:55:51 +0000872
Miklos Szeredic0938ea2001-11-07 12:35:06 +0000873 if((f->flags & FUSE_DEBUG)) {
Miklos Szeredic8ba2372002-12-10 12:26:00 +0000874 printf("unique: %i, opcode: %s (%i), ino: %li, insize: %i\n",
875 in->unique, opname(in->opcode), in->opcode, in->ino,
876 cmd->buflen);
Miklos Szeredic0938ea2001-11-07 12:35:06 +0000877 fflush(stdout);
878 }
Miklos Szeredife25def2001-12-20 15:38:05 +0000879
880 ctx->uid = in->uid;
881 ctx->gid = in->gid;
Miklos Szeredia181e612001-11-06 12:03:23 +0000882
883 argsize = cmd->buflen - sizeof(struct fuse_in_header);
884
885 switch(in->opcode) {
886 case FUSE_LOOKUP:
887 do_lookup(f, in, (char *) inarg);
888 break;
889
Miklos Szeredia181e612001-11-06 12:03:23 +0000890 case FUSE_GETATTR:
891 do_getattr(f, in);
892 break;
893
894 case FUSE_SETATTR:
895 do_setattr(f, in, (struct fuse_setattr_in *) inarg);
896 break;
897
898 case FUSE_READLINK:
899 do_readlink(f, in);
900 break;
901
902 case FUSE_GETDIR:
903 do_getdir(f, in);
904 break;
905
906 case FUSE_MKNOD:
907 do_mknod(f, in, (struct fuse_mknod_in *) inarg);
908 break;
909
910 case FUSE_MKDIR:
911 do_mkdir(f, in, (struct fuse_mkdir_in *) inarg);
912 break;
913
914 case FUSE_UNLINK:
915 case FUSE_RMDIR:
916 do_remove(f, in, (char *) inarg);
917 break;
918
919 case FUSE_SYMLINK:
920 do_symlink(f, in, (char *) inarg,
921 ((char *) inarg) + strlen((char *) inarg) + 1);
922 break;
923
924 case FUSE_RENAME:
925 do_rename(f, in, (struct fuse_rename_in *) inarg);
926 break;
927
928 case FUSE_LINK:
929 do_link(f, in, (struct fuse_link_in *) inarg);
930 break;
931
932 case FUSE_OPEN:
933 do_open(f, in, (struct fuse_open_in *) inarg);
934 break;
935
936 case FUSE_READ:
937 do_read(f, in, (struct fuse_read_in *) inarg);
938 break;
939
940 case FUSE_WRITE:
941 do_write(f, in, (struct fuse_write_in *) inarg);
942 break;
943
Mark Glinesd84b39a2002-01-07 16:32:02 +0000944 case FUSE_STATFS:
945 do_statfs(f, in);
946 break;
947
Miklos Szeredic8ba2372002-12-10 12:26:00 +0000948 case FUSE_RELEASE:
949 do_release(f, in);
950 break;
951
Miklos Szeredia181e612001-11-06 12:03:23 +0000952 default:
953 fprintf(stderr, "Operation %i not implemented\n", in->opcode);
Miklos Szeredi43696432001-11-18 19:15:05 +0000954 send_reply(f, in, -ENOSYS, NULL, 0);
Miklos Szeredia181e612001-11-06 12:03:23 +0000955 }
Miklos Szeredi43696432001-11-18 19:15:05 +0000956
957 free_cmd(cmd);
Miklos Szeredia181e612001-11-06 12:03:23 +0000958}
959
Miklos Szeredifff56ab2001-11-16 10:12:59 +0000960struct fuse_cmd *__fuse_read_cmd(struct fuse *f)
Miklos Szeredi2df1c042001-11-06 15:07:17 +0000961{
Miklos Szeredifff56ab2001-11-16 10:12:59 +0000962 ssize_t res;
Miklos Szeredifff56ab2001-11-16 10:12:59 +0000963 struct fuse_cmd *cmd;
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +0000964 struct fuse_in_header *in;
965 void *inarg;
Miklos Szeredifff56ab2001-11-16 10:12:59 +0000966
Miklos Szeredi43696432001-11-18 19:15:05 +0000967 cmd = (struct fuse_cmd *) malloc(sizeof(struct fuse_cmd));
968 cmd->buf = (char *) malloc(FUSE_MAX_IN);
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +0000969 in = (struct fuse_in_header *) cmd->buf;
970 inarg = cmd->buf + sizeof(struct fuse_in_header);
Miklos Szeredi43696432001-11-18 19:15:05 +0000971
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +0000972 do {
973 res = read(f->fd, cmd->buf, FUSE_MAX_IN);
974 if(res == -1) {
Miklos Szeredi0f48a262002-12-05 14:23:01 +0000975 free_cmd(cmd);
976 if(errno == EINTR)
977 return NULL;
978
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +0000979 /* ENODEV means we got unmounted, so we silenty return failure */
980 if(errno != ENODEV) {
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +0000981 /* BAD... This will happen again */
Miklos Szeredi0f48a262002-12-05 14:23:01 +0000982 perror("fuse: reading device");
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +0000983 }
Miklos Szeredi0f48a262002-12-05 14:23:01 +0000984
985 fuse_exit(f);
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +0000986 return NULL;
Miklos Szeredi96249982001-11-21 12:21:19 +0000987 }
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +0000988 if((size_t) res < sizeof(struct fuse_in_header)) {
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +0000989 free_cmd(cmd);
Miklos Szeredi0f48a262002-12-05 14:23:01 +0000990 /* Cannot happen */
991 fprintf(stderr, "short read on fuse device\n");
992 fuse_exit(f);
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +0000993 return NULL;
994 }
995 cmd->buflen = res;
996
997 /* Forget is special, it can be done without messing with threads. */
998 if(in->opcode == FUSE_FORGET)
999 do_forget(f, in, (struct fuse_forget_in *) inarg);
1000
1001 } while(in->opcode == FUSE_FORGET);
1002
Miklos Szeredifff56ab2001-11-16 10:12:59 +00001003 return cmd;
Miklos Szeredi2df1c042001-11-06 15:07:17 +00001004}
1005
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001006void fuse_loop(struct fuse *f)
1007{
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001008 while(1) {
Miklos Szeredi0f48a262002-12-05 14:23:01 +00001009 struct fuse_cmd *cmd;
1010
1011 if(f->exited)
1012 return;
1013
1014 cmd = __fuse_read_cmd(f);
Miklos Szeredifff56ab2001-11-16 10:12:59 +00001015 if(cmd == NULL)
Miklos Szeredi0f48a262002-12-05 14:23:01 +00001016 continue;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001017
Miklos Szeredifff56ab2001-11-16 10:12:59 +00001018 __fuse_process_cmd(f, cmd);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001019 }
1020}
1021
Miklos Szeredi0f48a262002-12-05 14:23:01 +00001022void fuse_exit(struct fuse *f)
1023{
1024 f->exited = 1;
1025}
1026
Miklos Szeredi2e50d432001-12-20 12:17:25 +00001027struct fuse_context *fuse_get_context(struct fuse *f)
1028{
1029 if(f->getcontext)
1030 return f->getcontext(f);
1031 else
1032 return &f->context;
1033}
1034
1035struct fuse *fuse_new(int fd, int flags, const struct fuse_operations *op)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001036{
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001037 struct fuse *f;
1038 struct node *root;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001039
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001040 f = (struct fuse *) calloc(1, sizeof(struct fuse));
Miklos Szeredi2df1c042001-11-06 15:07:17 +00001041
Miklos Szeredia181e612001-11-06 12:03:23 +00001042 f->flags = flags;
Miklos Szeredi8cffdb92001-11-09 14:49:18 +00001043 f->fd = fd;
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001044 f->ctr = 0;
Miklos Szeredifff56ab2001-11-16 10:12:59 +00001045 /* FIXME: Dynamic hash table */
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001046 f->name_table_size = 14057;
1047 f->name_table = (struct node **)
1048 calloc(1, sizeof(struct node *) * f->name_table_size);
1049 f->ino_table_size = 14057;
1050 f->ino_table = (struct node **)
1051 calloc(1, sizeof(struct node *) * f->ino_table_size);
Miklos Szeredia181e612001-11-06 12:03:23 +00001052 pthread_mutex_init(&f->lock, NULL);
Miklos Szeredi33232032001-11-19 17:55:51 +00001053 f->numworker = 0;
1054 f->numavail = 0;
Miklos Szeredi2e50d432001-12-20 12:17:25 +00001055 f->op = *op;
1056 f->getcontext = NULL;
1057 f->context.uid = 0;
1058 f->context.gid = 0;
Miklos Szeredi0f48a262002-12-05 14:23:01 +00001059 f->exited = 0;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001060
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001061 root = (struct node *) calloc(1, sizeof(struct node));
Miklos Szeredi8cffdb92001-11-09 14:49:18 +00001062 root->mode = 0;
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001063 root->rdev = 0;
1064 root->name = strdup("/");
1065 root->parent = 0;
1066 hash_ino(f, root, FUSE_ROOT_INO);
1067
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001068 return f;
1069}
1070
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001071void fuse_destroy(struct fuse *f)
1072{
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001073 size_t i;
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001074 for(i = 0; i < f->ino_table_size; i++) {
1075 struct node *node;
1076 struct node *next;
1077 for(node = f->ino_table[i]; node != NULL; node = next) {
1078 next = node->ino_next;
1079 free_node(node);
1080 }
1081 }
1082 free(f->ino_table);
1083 free(f->name_table);
Miklos Szeredia181e612001-11-06 12:03:23 +00001084 pthread_mutex_destroy(&f->lock);
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001085 free(f);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001086}