blob: 49199659d60577a560741a2cdf54960d520fc4c0 [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 Szeredi40b9a5a2002-12-10 16:09:02 +0000352static int send_reply_raw(struct fuse *f, char *outbuf, size_t outsize)
Miklos Szeredi43696432001-11-18 19:15:05 +0000353{
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 Szeredi40b9a5a2002-12-10 16:09:02 +0000373 return -errno;
Miklos Szeredi43696432001-11-18 19:15:05 +0000374 }
Miklos Szeredi40b9a5a2002-12-10 16:09:02 +0000375 return 0;
Miklos Szeredi43696432001-11-18 19:15:05 +0000376}
377
Miklos Szeredi40b9a5a2002-12-10 16:09:02 +0000378static int send_reply(struct fuse *f, struct fuse_in_header *in, int error,
379 void *arg, size_t argsize)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000380{
Miklos Szeredi40b9a5a2002-12-10 16:09:02 +0000381 int res;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000382 char *outbuf;
383 size_t outsize;
384 struct fuse_out_header *out;
385
Miklos Szeredi0f48a262002-12-05 14:23:01 +0000386 if(error <= -512 || error > 0) {
387 fprintf(stderr, "fuse: bad error value: %i\n", error);
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000388 error = -ERANGE;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000389 }
390
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000391 if(error)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000392 argsize = 0;
393
394 outsize = sizeof(struct fuse_out_header) + argsize;
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000395 outbuf = (char *) malloc(outsize);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000396 out = (struct fuse_out_header *) outbuf;
Miklos Szeredi0f48a262002-12-05 14:23:01 +0000397 memset(out, 0, sizeof(struct fuse_out_header));
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000398 out->unique = in->unique;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000399 out->error = error;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000400 if(argsize != 0)
401 memcpy(outbuf + sizeof(struct fuse_out_header), arg, argsize);
402
Miklos Szeredi40b9a5a2002-12-10 16:09:02 +0000403 res = send_reply_raw(f, outbuf, outsize);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000404 free(outbuf);
Miklos Szeredi40b9a5a2002-12-10 16:09:02 +0000405
406 return res;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000407}
408
409static void do_lookup(struct fuse *f, struct fuse_in_header *in, char *name)
410{
411 int res;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000412 char *path;
413 struct stat buf;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000414 struct fuse_lookup_out arg;
415
Miklos Szeredi5e183482001-10-31 14:52:35 +0000416 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000417 path = get_path_name(f, in->ino, name);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000418 if(path != NULL) {
Miklos Szeredi6ebe2342002-01-06 21:44:16 +0000419 if(f->flags & FUSE_DEBUG) {
420 printf("LOOKUP %s\n", path);
421 fflush(stdout);
422 }
Miklos Szeredi5e183482001-10-31 14:52:35 +0000423 res = -ENOSYS;
424 if(f->op.getattr)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000425 res = f->op.getattr(path, &buf);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000426 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000427 }
Miklos Szeredi0f48a262002-12-05 14:23:01 +0000428
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000429 if(res == 0) {
Miklos Szeredi0f48a262002-12-05 14:23:01 +0000430 memset(&arg, 0, sizeof(struct fuse_lookup_out));
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000431 convert_stat(&buf, &arg.attr);
Miklos Szeredia181e612001-11-06 12:03:23 +0000432 arg.ino = find_node(f, in->ino, name, &arg.attr, in->unique);
Miklos Szeredi6ebe2342002-01-06 21:44:16 +0000433 if(f->flags & FUSE_DEBUG) {
434 printf(" LOOKUP: %li\n", arg.ino);
435 fflush(stdout);
436 }
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000437 }
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000438 send_reply(f, in, res, &arg, sizeof(arg));
439}
440
Miklos Szeredia181e612001-11-06 12:03:23 +0000441static void do_forget(struct fuse *f, struct fuse_in_header *in,
442 struct fuse_forget_in *arg)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000443{
Miklos Szeredi43696432001-11-18 19:15:05 +0000444 if(f->flags & FUSE_DEBUG) {
445 printf("FORGET %li/%i\n", in->ino, arg->version);
446 fflush(stdout);
447 }
Miklos Szeredia181e612001-11-06 12:03:23 +0000448 destroy_node(f, in->ino, arg->version);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000449}
450
451static void do_getattr(struct fuse *f, struct fuse_in_header *in)
452{
453 int res;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000454 char *path;
455 struct stat buf;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000456 struct fuse_getattr_out arg;
457
Miklos Szeredi5e183482001-10-31 14:52:35 +0000458 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000459 path = get_path(f, in->ino);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000460 if(path != NULL) {
461 res = -ENOSYS;
462 if(f->op.getattr)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000463 res = f->op.getattr(path, &buf);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000464 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000465 }
Miklos Szeredi0f48a262002-12-05 14:23:01 +0000466
467 if(res == 0) {
468 memset(&arg, 0, sizeof(struct fuse_getattr_out));
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000469 convert_stat(&buf, &arg.attr);
Miklos Szeredi0f48a262002-12-05 14:23:01 +0000470 }
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000471
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000472 send_reply(f, in, res, &arg, sizeof(arg));
473}
474
Miklos Szeredi680a69a2001-11-16 13:31:14 +0000475static int do_chmod(struct fuse *f, const char *path, struct fuse_attr *attr)
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000476{
477 int res;
478
479 res = -ENOSYS;
480 if(f->op.chmod)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000481 res = f->op.chmod(path, attr->mode);
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000482
483 return res;
484}
485
Miklos Szeredi680a69a2001-11-16 13:31:14 +0000486static int do_chown(struct fuse *f, const char *path, struct fuse_attr *attr,
Miklos Szeredi2e50d432001-12-20 12:17:25 +0000487 int valid)
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000488{
489 int res;
490 uid_t uid = (valid & FATTR_UID) ? attr->uid : (uid_t) -1;
491 gid_t gid = (valid & FATTR_GID) ? attr->gid : (gid_t) -1;
492
493 res = -ENOSYS;
494 if(f->op.chown)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000495 res = f->op.chown(path, uid, gid);
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000496
497 return res;
498}
499
Miklos Szeredi680a69a2001-11-16 13:31:14 +0000500static int do_truncate(struct fuse *f, const char *path,
501 struct fuse_attr *attr)
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000502{
503 int res;
504
505 res = -ENOSYS;
506 if(f->op.truncate)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000507 res = f->op.truncate(path, attr->size);
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000508
509 return res;
510}
511
Miklos Szeredi680a69a2001-11-16 13:31:14 +0000512static int do_utime(struct fuse *f, const char *path, struct fuse_attr *attr)
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000513{
514 int res;
515 struct utimbuf buf;
516 buf.actime = attr->atime;
517 buf.modtime = attr->mtime;
518 res = -ENOSYS;
519 if(f->op.utime)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000520 res = f->op.utime(path, &buf);
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000521
522 return res;
523}
524
Miklos Szeredi5e183482001-10-31 14:52:35 +0000525static void do_setattr(struct fuse *f, struct fuse_in_header *in,
526 struct fuse_setattr_in *arg)
527{
528 int res;
529 char *path;
530 int valid = arg->valid;
531 struct fuse_attr *attr = &arg->attr;
Miklos Szeredia181e612001-11-06 12:03:23 +0000532 struct fuse_setattr_out outarg;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000533
534 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000535 path = get_path(f, in->ino);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000536 if(path != NULL) {
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000537 res = -ENOSYS;
538 if(f->op.getattr) {
539 res = 0;
540 if(!res && (valid & FATTR_MODE))
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000541 res = do_chmod(f, path, attr);
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000542 if(!res && (valid & (FATTR_UID | FATTR_GID)))
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000543 res = do_chown(f, path, attr, valid);
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000544 if(!res && (valid & FATTR_SIZE))
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000545 res = do_truncate(f, path, attr);
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000546 if(!res && (valid & FATTR_UTIME))
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000547 res = do_utime(f, path, attr);
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000548 if(!res) {
549 struct stat buf;
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000550 res = f->op.getattr(path, &buf);
Miklos Szeredi0f48a262002-12-05 14:23:01 +0000551 if(!res) {
552 memset(&outarg, 0, sizeof(struct fuse_setattr_out));
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000553 convert_stat(&buf, &outarg.attr);
Miklos Szeredi0f48a262002-12-05 14:23:01 +0000554 }
Miklos Szeredia181e612001-11-06 12:03:23 +0000555 }
Miklos Szeredi5e183482001-10-31 14:52:35 +0000556 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000557 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000558 }
Miklos Szeredia181e612001-11-06 12:03:23 +0000559 send_reply(f, in, res, &outarg, sizeof(outarg));
Miklos Szeredi5e183482001-10-31 14:52:35 +0000560}
561
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000562static void do_readlink(struct fuse *f, struct fuse_in_header *in)
563{
564 int res;
565 char link[PATH_MAX + 1];
Miklos Szeredib483c932001-10-29 14:57:57 +0000566 char *path;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000567
Miklos Szeredi5e183482001-10-31 14:52:35 +0000568 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000569 path = get_path(f, in->ino);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000570 if(path != NULL) {
571 res = -ENOSYS;
572 if(f->op.readlink)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000573 res = f->op.readlink(path, link, sizeof(link));
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000574 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000575 }
Miklos Szeredi2df1c042001-11-06 15:07:17 +0000576 link[PATH_MAX] = '\0';
Miklos Szeredi4b2bef42002-01-09 12:23:27 +0000577 send_reply(f, in, res, link, res == 0 ? strlen(link) : 0);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000578}
579
580static void do_getdir(struct fuse *f, struct fuse_in_header *in)
581{
582 int res;
583 struct fuse_getdir_out arg;
Miklos Szeredia181e612001-11-06 12:03:23 +0000584 struct fuse_dirhandle dh;
Miklos Szeredib483c932001-10-29 14:57:57 +0000585 char *path;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000586
Miklos Szeredib483c932001-10-29 14:57:57 +0000587 dh.fuse = f;
588 dh.fp = tmpfile();
589 dh.dir = in->ino;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000590 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000591 path = get_path(f, in->ino);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000592 if(path != NULL) {
593 res = -ENOSYS;
594 if(f->op.getdir)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000595 res = f->op.getdir(path, &dh, (fuse_dirfil_t) fill_dir);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000596 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000597 }
Miklos Szeredib483c932001-10-29 14:57:57 +0000598 fflush(dh.fp);
Miklos Szeredi0f48a262002-12-05 14:23:01 +0000599
600 memset(&arg, 0, sizeof(struct fuse_getdir_out));
Miklos Szeredib483c932001-10-29 14:57:57 +0000601 arg.fd = fileno(dh.fp);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000602 send_reply(f, in, res, &arg, sizeof(arg));
Miklos Szeredib483c932001-10-29 14:57:57 +0000603 fclose(dh.fp);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000604}
605
Miklos Szeredib483c932001-10-29 14:57:57 +0000606static void do_mknod(struct fuse *f, struct fuse_in_header *in,
607 struct fuse_mknod_in *inarg)
608{
609 int res;
610 char *path;
611 struct fuse_mknod_out outarg;
612 struct stat buf;
613
Miklos Szeredi5e183482001-10-31 14:52:35 +0000614 res = -ENOENT;
Miklos Szeredi6bf8b682002-10-28 08:49:39 +0000615 path = get_path_name(f, in->ino, PARAM(inarg));
Miklos Szeredi5e183482001-10-31 14:52:35 +0000616 if(path != NULL) {
617 res = -ENOSYS;
618 if(f->op.mknod && f->op.getattr) {
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000619 res = f->op.mknod(path, inarg->mode, inarg->rdev);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000620 if(res == 0)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000621 res = f->op.getattr(path, &buf);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000622 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000623 free(path);
Miklos Szeredib483c932001-10-29 14:57:57 +0000624 }
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000625 if(res == 0) {
Miklos Szeredi0f48a262002-12-05 14:23:01 +0000626 memset(&outarg, 0, sizeof(struct fuse_mknod_out));
Miklos Szeredib483c932001-10-29 14:57:57 +0000627 convert_stat(&buf, &outarg.attr);
Miklos Szeredi6bf8b682002-10-28 08:49:39 +0000628 outarg.ino = find_node(f, in->ino, PARAM(inarg), &outarg.attr,
Miklos Szeredia181e612001-11-06 12:03:23 +0000629 in->unique);
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000630 }
Miklos Szeredib483c932001-10-29 14:57:57 +0000631
632 send_reply(f, in, res, &outarg, sizeof(outarg));
633}
634
635static void do_mkdir(struct fuse *f, struct fuse_in_header *in,
636 struct fuse_mkdir_in *inarg)
637{
638 int res;
639 char *path;
640
Miklos Szeredi5e183482001-10-31 14:52:35 +0000641 res = -ENOENT;
Miklos Szeredi6bf8b682002-10-28 08:49:39 +0000642 path = get_path_name(f, in->ino, PARAM(inarg));
Miklos Szeredi5e183482001-10-31 14:52:35 +0000643 if(path != NULL) {
644 res = -ENOSYS;
645 if(f->op.mkdir)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000646 res = f->op.mkdir(path, inarg->mode);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000647 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000648 }
Miklos Szeredib483c932001-10-29 14:57:57 +0000649 send_reply(f, in, res, NULL, 0);
650}
651
652static void do_remove(struct fuse *f, struct fuse_in_header *in, char *name)
653{
654 int res;
655 char *path;
656
Miklos Szeredi5e183482001-10-31 14:52:35 +0000657 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000658 path = get_path_name(f, in->ino, name);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000659 if(path != NULL) {
660 res = -ENOSYS;
661 if(in->opcode == FUSE_UNLINK) {
662 if(f->op.unlink)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000663 res = f->op.unlink(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000664 }
665 else {
666 if(f->op.rmdir)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000667 res = f->op.rmdir(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000668 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000669 free(path);
Miklos Szeredib483c932001-10-29 14:57:57 +0000670 }
Miklos Szeredi5e183482001-10-31 14:52:35 +0000671 if(res == 0)
672 remove_node(f, in->ino, name);
Miklos Szeredib483c932001-10-29 14:57:57 +0000673 send_reply(f, in, res, NULL, 0);
674}
675
676static void do_symlink(struct fuse *f, struct fuse_in_header *in, char *name,
677 char *link)
678{
679 int res;
680 char *path;
681
Miklos Szeredi5e183482001-10-31 14:52:35 +0000682 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000683 path = get_path_name(f, in->ino, name);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000684 if(path != NULL) {
685 res = -ENOSYS;
686 if(f->op.symlink)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000687 res = f->op.symlink(link, path);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000688 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000689 }
Miklos Szeredib483c932001-10-29 14:57:57 +0000690 send_reply(f, in, res, NULL, 0);
691}
692
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000693static void do_rename(struct fuse *f, struct fuse_in_header *in,
694 struct fuse_rename_in *inarg)
695{
696 int res;
697 fino_t olddir = in->ino;
698 fino_t newdir = inarg->newdir;
Miklos Szeredi6bf8b682002-10-28 08:49:39 +0000699 char *oldname = PARAM(inarg);
700 char *newname = oldname + strlen(oldname) + 1;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000701 char *oldpath;
702 char *newpath;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000703
Miklos Szeredi5e183482001-10-31 14:52:35 +0000704 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000705 oldpath = get_path_name(f, olddir, oldname);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000706 if(oldpath != NULL) {
Miklos Szeredia181e612001-11-06 12:03:23 +0000707 newpath = get_path_name(f, newdir, newname);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000708 if(newpath != NULL) {
709 res = -ENOSYS;
710 if(f->op.rename)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000711 res = f->op.rename(oldpath, newpath);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000712 if(res == 0)
713 rename_node(f, olddir, oldname, newdir, newname);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000714 free(newpath);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000715 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000716 free(oldpath);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000717 }
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000718 send_reply(f, in, res, NULL, 0);
719}
720
721static void do_link(struct fuse *f, struct fuse_in_header *in,
Miklos Szeredi5e183482001-10-31 14:52:35 +0000722 struct fuse_link_in *arg)
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000723{
724 int res;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000725 char *oldpath;
726 char *newpath;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000727
Miklos Szeredi5e183482001-10-31 14:52:35 +0000728 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000729 oldpath = get_path(f, in->ino);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000730 if(oldpath != NULL) {
Miklos Szeredi6bf8b682002-10-28 08:49:39 +0000731 newpath = get_path_name(f, arg->newdir, PARAM(arg));
Miklos Szeredi5e183482001-10-31 14:52:35 +0000732 if(newpath != NULL) {
733 res = -ENOSYS;
734 if(f->op.link)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000735 res = f->op.link(oldpath, newpath);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000736 free(newpath);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000737 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000738 free(oldpath);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000739 }
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000740 send_reply(f, in, res, NULL, 0);
741}
742
Miklos Szeredi5e183482001-10-31 14:52:35 +0000743static void do_open(struct fuse *f, struct fuse_in_header *in,
744 struct fuse_open_in *arg)
745{
746 int res;
Miklos Szeredi40b9a5a2002-12-10 16:09:02 +0000747 int res2;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000748 char *path;
749
750 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000751 path = get_path(f, in->ino);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000752 if(path != NULL) {
753 res = -ENOSYS;
754 if(f->op.open)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000755 res = f->op.open(path, arg->flags);
Miklos Szeredi40b9a5a2002-12-10 16:09:02 +0000756 }
757 res2 = send_reply(f, in, res, NULL, 0);
758 if(path != NULL) {
759 /* The open syscall was interrupted, so it must be cancelled */
760 if(res == 0 && res2 == -ENOENT && f->op.release)
761 f->op.release(path);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000762 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000763 }
Miklos Szeredi5e183482001-10-31 14:52:35 +0000764}
765
Miklos Szeredic8ba2372002-12-10 12:26:00 +0000766static void do_release(struct fuse *f, struct fuse_in_header *in)
767{
Miklos Szeredic8ba2372002-12-10 12:26:00 +0000768 char *path;
769
Miklos Szeredic8ba2372002-12-10 12:26:00 +0000770 path = get_path(f, in->ino);
771 if(path != NULL) {
Miklos Szeredic8ba2372002-12-10 12:26:00 +0000772 if(f->op.release)
Miklos Szeredi383a9df2002-12-10 14:54:57 +0000773 f->op.release(path);
Miklos Szeredic8ba2372002-12-10 12:26:00 +0000774 free(path);
775 }
Miklos Szeredic8ba2372002-12-10 12:26:00 +0000776}
777
Miklos Szeredi5e183482001-10-31 14:52:35 +0000778static void do_read(struct fuse *f, struct fuse_in_header *in,
779 struct fuse_read_in *arg)
780{
781 int res;
782 char *path;
Miklos Szeredi43696432001-11-18 19:15:05 +0000783 char *outbuf = (char *) malloc(sizeof(struct fuse_out_header) + arg->size);
784 struct fuse_out_header *out = (struct fuse_out_header *) outbuf;
785 char *buf = outbuf + sizeof(struct fuse_out_header);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000786 size_t size;
Miklos Szeredi43696432001-11-18 19:15:05 +0000787 size_t outsize;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000788
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000789 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000790 path = get_path(f, in->ino);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000791 if(path != NULL) {
Miklos Szeredi6ebe2342002-01-06 21:44:16 +0000792 if(f->flags & FUSE_DEBUG) {
793 printf("READ %u bytes from %llu\n", arg->size, arg->offset);
794 fflush(stdout);
795 }
796
Miklos Szeredi5e183482001-10-31 14:52:35 +0000797 res = -ENOSYS;
Miklos Szeredia181e612001-11-06 12:03:23 +0000798 if(f->op.read)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000799 res = f->op.read(path, buf, arg->size, arg->offset);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000800 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000801 }
802
803 size = 0;
804 if(res > 0) {
805 size = res;
806 res = 0;
Miklos Szeredi6ebe2342002-01-06 21:44:16 +0000807 if(f->flags & FUSE_DEBUG) {
808 printf(" READ %u bytes\n", size);
809 fflush(stdout);
810 }
Miklos Szeredi5e183482001-10-31 14:52:35 +0000811 }
Miklos Szeredi0f48a262002-12-05 14:23:01 +0000812 memset(out, 0, sizeof(struct fuse_out_header));
Miklos Szeredi43696432001-11-18 19:15:05 +0000813 out->unique = in->unique;
814 out->error = res;
815 outsize = sizeof(struct fuse_out_header) + size;
816
817 send_reply_raw(f, outbuf, outsize);
818 free(outbuf);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000819}
Miklos Szeredib483c932001-10-29 14:57:57 +0000820
Miklos Szeredia181e612001-11-06 12:03:23 +0000821static void do_write(struct fuse *f, struct fuse_in_header *in,
822 struct fuse_write_in *arg)
823{
824 int res;
825 char *path;
Miklos Szeredia181e612001-11-06 12:03:23 +0000826
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000827 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000828 path = get_path(f, in->ino);
829 if(path != NULL) {
Miklos Szeredi6ebe2342002-01-06 21:44:16 +0000830 if(f->flags & FUSE_DEBUG) {
831 printf("WRITE %u bytes to %llu\n", arg->size, arg->offset);
832 fflush(stdout);
833 }
834
Miklos Szeredia181e612001-11-06 12:03:23 +0000835 res = -ENOSYS;
836 if(f->op.write)
Miklos Szeredi6bf8b682002-10-28 08:49:39 +0000837 res = f->op.write(path, PARAM(arg), arg->size, arg->offset);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000838 free(path);
Miklos Szeredia181e612001-11-06 12:03:23 +0000839 }
840
841 if(res > 0) {
842 if((size_t) res != arg->size) {
843 fprintf(stderr, "short write: %u (should be %u)\n", res,
844 arg->size);
845 res = -EIO;
846 }
847 else
848 res = 0;
849 }
850
851 send_reply(f, in, res, NULL, 0);
852}
853
Mark Glinesd84b39a2002-01-07 16:32:02 +0000854static void do_statfs(struct fuse *f, struct fuse_in_header *in)
855{
856 int res;
Mark Glinesd84b39a2002-01-07 16:32:02 +0000857 struct fuse_statfs_out arg;
858
859 res = -ENOSYS;
Miklos Szeredi0f48a262002-12-05 14:23:01 +0000860 if(f->op.statfs) {
861 memset(&arg, 0, sizeof(struct fuse_statfs_out));
Miklos Szeredi24ed9452002-10-07 10:24:26 +0000862 res = f->op.statfs((struct fuse_statfs *) &arg.st);
Miklos Szeredi0f48a262002-12-05 14:23:01 +0000863 }
Miklos Szeredi4b2bef42002-01-09 12:23:27 +0000864
Mark Glinesd84b39a2002-01-07 16:32:02 +0000865 send_reply(f, in, res, &arg, sizeof(arg));
866}
867
Miklos Szeredi43696432001-11-18 19:15:05 +0000868static void free_cmd(struct fuse_cmd *cmd)
869{
870 free(cmd->buf);
871 free(cmd);
872}
873
Miklos Szeredifff56ab2001-11-16 10:12:59 +0000874void __fuse_process_cmd(struct fuse *f, struct fuse_cmd *cmd)
Miklos Szeredia181e612001-11-06 12:03:23 +0000875{
Miklos Szeredia181e612001-11-06 12:03:23 +0000876 struct fuse_in_header *in = (struct fuse_in_header *) cmd->buf;
877 void *inarg = cmd->buf + sizeof(struct fuse_in_header);
878 size_t argsize;
Miklos Szeredife25def2001-12-20 15:38:05 +0000879 struct fuse_context *ctx = fuse_get_context(f);
Miklos Szeredia181e612001-11-06 12:03:23 +0000880
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +0000881 dec_avail(f);
Miklos Szeredi33232032001-11-19 17:55:51 +0000882
Miklos Szeredic0938ea2001-11-07 12:35:06 +0000883 if((f->flags & FUSE_DEBUG)) {
Miklos Szeredic8ba2372002-12-10 12:26:00 +0000884 printf("unique: %i, opcode: %s (%i), ino: %li, insize: %i\n",
885 in->unique, opname(in->opcode), in->opcode, in->ino,
886 cmd->buflen);
Miklos Szeredic0938ea2001-11-07 12:35:06 +0000887 fflush(stdout);
888 }
Miklos Szeredife25def2001-12-20 15:38:05 +0000889
890 ctx->uid = in->uid;
891 ctx->gid = in->gid;
Miklos Szeredia181e612001-11-06 12:03:23 +0000892
893 argsize = cmd->buflen - sizeof(struct fuse_in_header);
894
895 switch(in->opcode) {
896 case FUSE_LOOKUP:
897 do_lookup(f, in, (char *) inarg);
898 break;
899
Miklos Szeredia181e612001-11-06 12:03:23 +0000900 case FUSE_GETATTR:
901 do_getattr(f, in);
902 break;
903
904 case FUSE_SETATTR:
905 do_setattr(f, in, (struct fuse_setattr_in *) inarg);
906 break;
907
908 case FUSE_READLINK:
909 do_readlink(f, in);
910 break;
911
912 case FUSE_GETDIR:
913 do_getdir(f, in);
914 break;
915
916 case FUSE_MKNOD:
917 do_mknod(f, in, (struct fuse_mknod_in *) inarg);
918 break;
919
920 case FUSE_MKDIR:
921 do_mkdir(f, in, (struct fuse_mkdir_in *) inarg);
922 break;
923
924 case FUSE_UNLINK:
925 case FUSE_RMDIR:
926 do_remove(f, in, (char *) inarg);
927 break;
928
929 case FUSE_SYMLINK:
930 do_symlink(f, in, (char *) inarg,
931 ((char *) inarg) + strlen((char *) inarg) + 1);
932 break;
933
934 case FUSE_RENAME:
935 do_rename(f, in, (struct fuse_rename_in *) inarg);
936 break;
937
938 case FUSE_LINK:
939 do_link(f, in, (struct fuse_link_in *) inarg);
940 break;
941
942 case FUSE_OPEN:
943 do_open(f, in, (struct fuse_open_in *) inarg);
944 break;
945
946 case FUSE_READ:
947 do_read(f, in, (struct fuse_read_in *) inarg);
948 break;
949
950 case FUSE_WRITE:
951 do_write(f, in, (struct fuse_write_in *) inarg);
952 break;
953
Mark Glinesd84b39a2002-01-07 16:32:02 +0000954 case FUSE_STATFS:
955 do_statfs(f, in);
956 break;
957
Miklos Szeredic8ba2372002-12-10 12:26:00 +0000958 case FUSE_RELEASE:
959 do_release(f, in);
960 break;
961
Miklos Szeredia181e612001-11-06 12:03:23 +0000962 default:
963 fprintf(stderr, "Operation %i not implemented\n", in->opcode);
Miklos Szeredi43696432001-11-18 19:15:05 +0000964 send_reply(f, in, -ENOSYS, NULL, 0);
Miklos Szeredia181e612001-11-06 12:03:23 +0000965 }
Miklos Szeredi43696432001-11-18 19:15:05 +0000966
967 free_cmd(cmd);
Miklos Szeredia181e612001-11-06 12:03:23 +0000968}
969
Miklos Szeredifff56ab2001-11-16 10:12:59 +0000970struct fuse_cmd *__fuse_read_cmd(struct fuse *f)
Miklos Szeredi2df1c042001-11-06 15:07:17 +0000971{
Miklos Szeredifff56ab2001-11-16 10:12:59 +0000972 ssize_t res;
Miklos Szeredifff56ab2001-11-16 10:12:59 +0000973 struct fuse_cmd *cmd;
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +0000974 struct fuse_in_header *in;
975 void *inarg;
Miklos Szeredifff56ab2001-11-16 10:12:59 +0000976
Miklos Szeredi43696432001-11-18 19:15:05 +0000977 cmd = (struct fuse_cmd *) malloc(sizeof(struct fuse_cmd));
978 cmd->buf = (char *) malloc(FUSE_MAX_IN);
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +0000979 in = (struct fuse_in_header *) cmd->buf;
980 inarg = cmd->buf + sizeof(struct fuse_in_header);
Miklos Szeredi43696432001-11-18 19:15:05 +0000981
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +0000982 do {
983 res = read(f->fd, cmd->buf, FUSE_MAX_IN);
984 if(res == -1) {
Miklos Szeredi0f48a262002-12-05 14:23:01 +0000985 free_cmd(cmd);
986 if(errno == EINTR)
987 return NULL;
988
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +0000989 /* ENODEV means we got unmounted, so we silenty return failure */
990 if(errno != ENODEV) {
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +0000991 /* BAD... This will happen again */
Miklos Szeredi0f48a262002-12-05 14:23:01 +0000992 perror("fuse: reading device");
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +0000993 }
Miklos Szeredi0f48a262002-12-05 14:23:01 +0000994
995 fuse_exit(f);
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +0000996 return NULL;
Miklos Szeredi96249982001-11-21 12:21:19 +0000997 }
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +0000998 if((size_t) res < sizeof(struct fuse_in_header)) {
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +0000999 free_cmd(cmd);
Miklos Szeredi0f48a262002-12-05 14:23:01 +00001000 /* Cannot happen */
1001 fprintf(stderr, "short read on fuse device\n");
1002 fuse_exit(f);
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +00001003 return NULL;
1004 }
1005 cmd->buflen = res;
1006
1007 /* Forget is special, it can be done without messing with threads. */
1008 if(in->opcode == FUSE_FORGET)
1009 do_forget(f, in, (struct fuse_forget_in *) inarg);
1010
1011 } while(in->opcode == FUSE_FORGET);
1012
Miklos Szeredifff56ab2001-11-16 10:12:59 +00001013 return cmd;
Miklos Szeredi2df1c042001-11-06 15:07:17 +00001014}
1015
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001016void fuse_loop(struct fuse *f)
1017{
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001018 while(1) {
Miklos Szeredi0f48a262002-12-05 14:23:01 +00001019 struct fuse_cmd *cmd;
1020
1021 if(f->exited)
1022 return;
1023
1024 cmd = __fuse_read_cmd(f);
Miklos Szeredifff56ab2001-11-16 10:12:59 +00001025 if(cmd == NULL)
Miklos Szeredi0f48a262002-12-05 14:23:01 +00001026 continue;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001027
Miklos Szeredifff56ab2001-11-16 10:12:59 +00001028 __fuse_process_cmd(f, cmd);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001029 }
1030}
1031
Miklos Szeredi0f48a262002-12-05 14:23:01 +00001032void fuse_exit(struct fuse *f)
1033{
1034 f->exited = 1;
1035}
1036
Miklos Szeredi2e50d432001-12-20 12:17:25 +00001037struct fuse_context *fuse_get_context(struct fuse *f)
1038{
1039 if(f->getcontext)
1040 return f->getcontext(f);
1041 else
1042 return &f->context;
1043}
1044
1045struct fuse *fuse_new(int fd, int flags, const struct fuse_operations *op)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001046{
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001047 struct fuse *f;
1048 struct node *root;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001049
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001050 f = (struct fuse *) calloc(1, sizeof(struct fuse));
Miklos Szeredi2df1c042001-11-06 15:07:17 +00001051
Miklos Szeredia181e612001-11-06 12:03:23 +00001052 f->flags = flags;
Miklos Szeredi8cffdb92001-11-09 14:49:18 +00001053 f->fd = fd;
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001054 f->ctr = 0;
Miklos Szeredifff56ab2001-11-16 10:12:59 +00001055 /* FIXME: Dynamic hash table */
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001056 f->name_table_size = 14057;
1057 f->name_table = (struct node **)
1058 calloc(1, sizeof(struct node *) * f->name_table_size);
1059 f->ino_table_size = 14057;
1060 f->ino_table = (struct node **)
1061 calloc(1, sizeof(struct node *) * f->ino_table_size);
Miklos Szeredia181e612001-11-06 12:03:23 +00001062 pthread_mutex_init(&f->lock, NULL);
Miklos Szeredi33232032001-11-19 17:55:51 +00001063 f->numworker = 0;
1064 f->numavail = 0;
Miklos Szeredi2e50d432001-12-20 12:17:25 +00001065 f->op = *op;
1066 f->getcontext = NULL;
1067 f->context.uid = 0;
1068 f->context.gid = 0;
Miklos Szeredi0f48a262002-12-05 14:23:01 +00001069 f->exited = 0;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001070
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001071 root = (struct node *) calloc(1, sizeof(struct node));
Miklos Szeredi8cffdb92001-11-09 14:49:18 +00001072 root->mode = 0;
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001073 root->rdev = 0;
1074 root->name = strdup("/");
1075 root->parent = 0;
1076 hash_ino(f, root, FUSE_ROOT_INO);
1077
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001078 return f;
1079}
1080
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001081void fuse_destroy(struct fuse *f)
1082{
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001083 size_t i;
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001084 for(i = 0; i < f->ino_table_size; i++) {
1085 struct node *node;
1086 struct node *next;
1087 for(node = f->ino_table[i]; node != NULL; node = next) {
1088 next = node->ino_next;
1089 free_node(node);
1090 }
1091 }
1092 free(f->ino_table);
1093 free(f->name_table);
Miklos Szeredia181e612001-11-06 12:03:23 +00001094 pthread_mutex_destroy(&f->lock);
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001095 free(f);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001096}