blob: ffb348934ac5edda819c1e8047c483d66beabfbc [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";
Miklos Szeredi5e43f2c2003-12-12 14:06:41 +000043 case FUSE_FSYNC: return "FSYNC";
Miklos Szeredic8ba2372002-12-10 12:26:00 +000044 default: return "???";
45 }
46}
47
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +000048static inline void inc_avail(struct fuse *f)
49{
50 pthread_mutex_lock(&f->lock);
51 f->numavail ++;
52 pthread_mutex_unlock(&f->lock);
53}
54
55static inline void dec_avail(struct fuse *f)
56{
57 pthread_mutex_lock(&f->lock);
58 f->numavail --;
59 pthread_mutex_unlock(&f->lock);
60}
61
Miklos Szeredi97c61e92001-11-07 12:09:43 +000062static struct node *__get_node(struct fuse *f, fino_t ino)
Miklos Szeredia181e612001-11-06 12:03:23 +000063{
Miklos Szeredi97c61e92001-11-07 12:09:43 +000064 size_t hash = ino % f->ino_table_size;
65 struct node *node;
66
67 for(node = f->ino_table[hash]; node != NULL; node = node->ino_next)
68 if(node->ino == ino)
69 return node;
70
71 return NULL;
Miklos Szeredia181e612001-11-06 12:03:23 +000072}
73
Miklos Szeredi97c61e92001-11-07 12:09:43 +000074static struct node *get_node(struct fuse *f, fino_t ino)
Miklos Szeredia181e612001-11-06 12:03:23 +000075{
Miklos Szeredi97c61e92001-11-07 12:09:43 +000076 struct node *node = __get_node(f, ino);
77 if(node != NULL)
78 return node;
79
80 fprintf(stderr, "fuse internal error: inode %lu not found\n", ino);
81 abort();
Miklos Szeredia181e612001-11-06 12:03:23 +000082}
83
Miklos Szeredi97c61e92001-11-07 12:09:43 +000084static void hash_ino(struct fuse *f, struct node *node, fino_t ino)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000085{
Miklos Szeredi97c61e92001-11-07 12:09:43 +000086 size_t hash = ino % f->ino_table_size;
87 node->ino = ino;
88
89 node->ino_next = f->ino_table[hash];
90 f->ino_table[hash] = node;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000091}
92
Miklos Szeredi97c61e92001-11-07 12:09:43 +000093static void unhash_ino(struct fuse *f, struct node *node)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000094{
Miklos Szeredi97c61e92001-11-07 12:09:43 +000095 size_t hash = node->ino % f->ino_table_size;
96 struct node **nodep = &f->ino_table[hash];
97
98 for(; *nodep != NULL; nodep = &(*nodep)->ino_next)
99 if(*nodep == node) {
100 *nodep = node->ino_next;
101 return;
102 }
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000103}
104
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000105static fino_t get_ino(struct node *node)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000106{
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000107 return node->ino;
108}
109
110static fino_t next_ino(struct fuse *f)
111{
Miklos Szeredif4f8b892004-01-27 17:04:59 +0000112 do f->ctr++;
113 while(f->ctr == 0 || __get_node(f, f->ctr) != NULL);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000114
115 return f->ctr;
116}
117
118static void free_node(struct node *node)
119{
120 free(node->name);
121 free(node);
122}
123
124static unsigned int name_hash(struct fuse *f, fino_t parent, const char *name)
125{
126 unsigned int hash = *name;
127
128 if(hash)
129 for(name += 1; *name != '\0'; name++)
130 hash = (hash << 5) - hash + *name;
131
132 return (hash + parent) % f->name_table_size;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000133}
134
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000135static struct node *lookup_node(struct fuse *f, fino_t parent,
136 const char *name)
137{
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000138 size_t hash = name_hash(f, parent, name);
139 struct node *node;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000140
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000141 for(node = f->name_table[hash]; node != NULL; node = node->name_next)
142 if(node->parent == parent && strcmp(node->name, name) == 0)
143 return node;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000144
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000145 return NULL;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000146}
147
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000148static void hash_name(struct fuse *f, struct node *node, fino_t parent,
Miklos Szeredia181e612001-11-06 12:03:23 +0000149 const char *name)
Miklos Szeredi5e183482001-10-31 14:52:35 +0000150{
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000151 size_t hash = name_hash(f, parent, name);
Miklos Szeredia181e612001-11-06 12:03:23 +0000152 node->parent = parent;
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000153 node->name = strdup(name);
154 node->name_next = f->name_table[hash];
155 f->name_table[hash] = node;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000156}
157
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000158static void unhash_name(struct fuse *f, struct node *node)
Miklos Szeredia181e612001-11-06 12:03:23 +0000159{
160 if(node->name != NULL) {
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000161 size_t hash = name_hash(f, node->parent, node->name);
162 struct node **nodep = &f->name_table[hash];
163
164 for(; *nodep != NULL; nodep = &(*nodep)->name_next)
165 if(*nodep == node) {
166 *nodep = node->name_next;
167 node->name_next = NULL;
168 free(node->name);
169 node->name = NULL;
170 node->parent = 0;
171 return;
172 }
173 fprintf(stderr, "fuse internal error: unable to unhash node: %lu\n",
174 node->ino);
175 abort();
Miklos Szeredia181e612001-11-06 12:03:23 +0000176 }
177}
178
179static fino_t find_node(struct fuse *f, fino_t parent, char *name,
180 struct fuse_attr *attr, int version)
Miklos Szeredi5e183482001-10-31 14:52:35 +0000181{
182 struct node *node;
Miklos Szeredia181e612001-11-06 12:03:23 +0000183 int mode = attr->mode & S_IFMT;
184 int rdev = 0;
185
186 if(S_ISCHR(mode) || S_ISBLK(mode))
187 rdev = attr->rdev;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000188
Miklos Szeredia181e612001-11-06 12:03:23 +0000189 pthread_mutex_lock(&f->lock);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000190 node = lookup_node(f, parent, name);
191 if(node != NULL) {
Miklos Szeredia181e612001-11-06 12:03:23 +0000192 if(node->mode == mode && node->rdev == rdev)
193 goto out;
194
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000195 unhash_name(f, node);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000196 }
197
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000198 node = (struct node *) calloc(1, sizeof(struct node));
Miklos Szeredia181e612001-11-06 12:03:23 +0000199 node->mode = mode;
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000200 node->rdev = rdev;
201 hash_ino(f, node, next_ino(f));
202 hash_name(f, node, parent, name);
Miklos Szeredia181e612001-11-06 12:03:23 +0000203
204 out:
205 node->version = version;
206 pthread_mutex_unlock(&f->lock);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000207 return get_ino(node);
208}
209
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000210static char *add_name(char *buf, char *s, const char *name)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000211{
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000212 size_t len = strlen(name);
213 s -= len;
214 if(s <= buf) {
215 fprintf(stderr, "fuse: path too long: ...%s\n", s + len);
216 return NULL;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000217 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000218 strncpy(s, name, len);
219 s--;
220 *s = '/';
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000221
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000222 return s;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000223}
224
Miklos Szeredia181e612001-11-06 12:03:23 +0000225static char *get_path_name(struct fuse *f, fino_t ino, const char *name)
Miklos Szeredib483c932001-10-29 14:57:57 +0000226{
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000227 char buf[FUSE_MAX_PATH];
228 char *s = buf + FUSE_MAX_PATH - 1;
229 struct node *node;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000230
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000231 *s = '\0';
Miklos Szeredia181e612001-11-06 12:03:23 +0000232
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000233 if(name != NULL) {
234 s = add_name(buf, s, name);
235 if(s == NULL)
236 return NULL;
237 }
238
239 pthread_mutex_lock(&f->lock);
240 for(node = get_node(f, ino); node->ino != FUSE_ROOT_INO;
241 node = get_node(f, node->parent)) {
242 if(node->name == NULL) {
243 s = NULL;
244 break;
245 }
246
247 s = add_name(buf, s, node->name);
248 if(s == NULL)
249 break;
250 }
251 pthread_mutex_unlock(&f->lock);
252
253 if(s == NULL)
Miklos Szeredi5e183482001-10-31 14:52:35 +0000254 return NULL;
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000255 else if(*s == '\0')
256 return strdup("/");
257 else
258 return strdup(s);
259}
Miklos Szeredia181e612001-11-06 12:03:23 +0000260
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000261static char *get_path(struct fuse *f, fino_t ino)
262{
263 return get_path_name(f, ino, NULL);
Miklos Szeredib483c932001-10-29 14:57:57 +0000264}
265
Miklos Szeredia181e612001-11-06 12:03:23 +0000266static void destroy_node(struct fuse *f, fino_t ino, int version)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000267{
Miklos Szeredia181e612001-11-06 12:03:23 +0000268 struct node *node;
269
270 pthread_mutex_lock(&f->lock);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000271 node = get_node(f, ino);
Miklos Szeredi39f28672001-11-14 14:52:54 +0000272 if(node->version == version && ino != FUSE_ROOT_INO) {
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000273 unhash_name(f, node);
274 unhash_ino(f, node);
Miklos Szeredia181e612001-11-06 12:03:23 +0000275 free_node(node);
276 }
277 pthread_mutex_unlock(&f->lock);
278
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000279}
280
Miklos Szeredi5e183482001-10-31 14:52:35 +0000281static void remove_node(struct fuse *f, fino_t dir, const char *name)
282{
Miklos Szeredia181e612001-11-06 12:03:23 +0000283 struct node *node;
284
285 pthread_mutex_lock(&f->lock);
286 node = lookup_node(f, dir, name);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000287 if(node == NULL) {
288 fprintf(stderr, "fuse internal error: unable to remove node %lu/%s\n",
289 dir, name);
290 abort();
291 }
292 unhash_name(f, node);
Miklos Szeredia181e612001-11-06 12:03:23 +0000293 pthread_mutex_unlock(&f->lock);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000294}
295
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000296static void rename_node(struct fuse *f, fino_t olddir, const char *oldname,
297 fino_t newdir, const char *newname)
298{
Miklos Szeredia181e612001-11-06 12:03:23 +0000299 struct node *node;
300 struct node *newnode;
301
302 pthread_mutex_lock(&f->lock);
303 node = lookup_node(f, olddir, oldname);
304 newnode = lookup_node(f, newdir, newname);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000305 if(node == NULL) {
306 fprintf(stderr, "fuse internal error: unable to rename node %lu/%s\n",
307 olddir, oldname);
308 abort();
309 }
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000310
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000311 if(newnode != NULL)
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000312 unhash_name(f, newnode);
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000313
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000314 unhash_name(f, node);
315 hash_name(f, node, newdir, newname);
Miklos Szeredia181e612001-11-06 12:03:23 +0000316 pthread_mutex_unlock(&f->lock);
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000317}
318
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000319static void convert_stat(struct stat *stbuf, struct fuse_attr *attr)
320{
321 attr->mode = stbuf->st_mode;
322 attr->nlink = stbuf->st_nlink;
323 attr->uid = stbuf->st_uid;
324 attr->gid = stbuf->st_gid;
325 attr->rdev = stbuf->st_rdev;
326 attr->size = stbuf->st_size;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000327 attr->blocks = stbuf->st_blocks;
328 attr->atime = stbuf->st_atime;
329 attr->mtime = stbuf->st_mtime;
330 attr->ctime = stbuf->st_ctime;
Miklos Szeredifff56ab2001-11-16 10:12:59 +0000331 attr->_dummy = 4096;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000332}
333
Miklos Szeredia181e612001-11-06 12:03:23 +0000334static int fill_dir(struct fuse_dirhandle *dh, char *name, int type)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000335{
336 struct fuse_dirent dirent;
337 size_t reclen;
338 size_t res;
339
Miklos Szeredi43696432001-11-18 19:15:05 +0000340 dirent.ino = (unsigned long) -1;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000341 dirent.namelen = strlen(name);
342 strncpy(dirent.name, name, sizeof(dirent.name));
343 dirent.type = type;
344 reclen = FUSE_DIRENT_SIZE(&dirent);
345 res = fwrite(&dirent, reclen, 1, dh->fp);
346 if(res == 0) {
Miklos Szeredi96249982001-11-21 12:21:19 +0000347 perror("fuse: writing directory file");
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000348 return -EIO;
349 }
350 return 0;
351}
352
Miklos Szeredi40b9a5a2002-12-10 16:09:02 +0000353static int send_reply_raw(struct fuse *f, char *outbuf, size_t outsize)
Miklos Szeredi43696432001-11-18 19:15:05 +0000354{
355 int res;
356
357 if((f->flags & FUSE_DEBUG)) {
358 struct fuse_out_header *out = (struct fuse_out_header *) outbuf;
359 printf(" unique: %i, error: %i (%s), outsize: %i\n", out->unique,
360 out->error, strerror(-out->error), outsize);
361 fflush(stdout);
362 }
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +0000363
Miklos Szeredi4e71c9f2004-02-09 12:05:14 +0000364 /* This needs to be done before the reply, otherwise the scheduler
365 could play tricks with us, and only let the counter be increased
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +0000366 long after the operation is done */
367 inc_avail(f);
368
Miklos Szeredi43696432001-11-18 19:15:05 +0000369 res = write(f->fd, outbuf, outsize);
370 if(res == -1) {
371 /* ENOENT means the operation was interrupted */
Miklos Szeredi4e71c9f2004-02-09 12:05:14 +0000372 if(!f->exited && errno != ENOENT)
Miklos Szeredi96249982001-11-21 12:21:19 +0000373 perror("fuse: writing device");
Miklos Szeredi40b9a5a2002-12-10 16:09:02 +0000374 return -errno;
Miklos Szeredi43696432001-11-18 19:15:05 +0000375 }
Miklos Szeredi40b9a5a2002-12-10 16:09:02 +0000376 return 0;
Miklos Szeredi43696432001-11-18 19:15:05 +0000377}
378
Miklos Szeredi40b9a5a2002-12-10 16:09:02 +0000379static int send_reply(struct fuse *f, struct fuse_in_header *in, int error,
380 void *arg, size_t argsize)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000381{
Miklos Szeredi40b9a5a2002-12-10 16:09:02 +0000382 int res;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000383 char *outbuf;
384 size_t outsize;
385 struct fuse_out_header *out;
386
Miklos Szeredi0f48a262002-12-05 14:23:01 +0000387 if(error <= -512 || error > 0) {
388 fprintf(stderr, "fuse: bad error value: %i\n", error);
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000389 error = -ERANGE;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000390 }
391
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000392 if(error)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000393 argsize = 0;
394
395 outsize = sizeof(struct fuse_out_header) + argsize;
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000396 outbuf = (char *) malloc(outsize);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000397 out = (struct fuse_out_header *) outbuf;
Miklos Szeredi0f48a262002-12-05 14:23:01 +0000398 memset(out, 0, sizeof(struct fuse_out_header));
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000399 out->unique = in->unique;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000400 out->error = error;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000401 if(argsize != 0)
402 memcpy(outbuf + sizeof(struct fuse_out_header), arg, argsize);
403
Miklos Szeredi40b9a5a2002-12-10 16:09:02 +0000404 res = send_reply_raw(f, outbuf, outsize);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000405 free(outbuf);
Miklos Szeredi40b9a5a2002-12-10 16:09:02 +0000406
407 return res;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000408}
409
410static void do_lookup(struct fuse *f, struct fuse_in_header *in, char *name)
411{
412 int res;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000413 char *path;
414 struct stat buf;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000415 struct fuse_lookup_out arg;
416
Miklos Szeredi5e183482001-10-31 14:52:35 +0000417 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000418 path = get_path_name(f, in->ino, name);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000419 if(path != NULL) {
Miklos Szeredi6ebe2342002-01-06 21:44:16 +0000420 if(f->flags & FUSE_DEBUG) {
421 printf("LOOKUP %s\n", path);
422 fflush(stdout);
423 }
Miklos Szeredi5e183482001-10-31 14:52:35 +0000424 res = -ENOSYS;
425 if(f->op.getattr)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000426 res = f->op.getattr(path, &buf);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000427 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000428 }
Miklos Szeredi0f48a262002-12-05 14:23:01 +0000429
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000430 if(res == 0) {
Miklos Szeredi0f48a262002-12-05 14:23:01 +0000431 memset(&arg, 0, sizeof(struct fuse_lookup_out));
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000432 convert_stat(&buf, &arg.attr);
Miklos Szeredia181e612001-11-06 12:03:23 +0000433 arg.ino = find_node(f, in->ino, name, &arg.attr, in->unique);
Miklos Szeredi6ebe2342002-01-06 21:44:16 +0000434 if(f->flags & FUSE_DEBUG) {
435 printf(" LOOKUP: %li\n", arg.ino);
436 fflush(stdout);
437 }
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000438 }
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000439 send_reply(f, in, res, &arg, sizeof(arg));
440}
441
Miklos Szeredia181e612001-11-06 12:03:23 +0000442static void do_forget(struct fuse *f, struct fuse_in_header *in,
443 struct fuse_forget_in *arg)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000444{
Miklos Szeredi43696432001-11-18 19:15:05 +0000445 if(f->flags & FUSE_DEBUG) {
446 printf("FORGET %li/%i\n", in->ino, arg->version);
447 fflush(stdout);
448 }
Miklos Szeredia181e612001-11-06 12:03:23 +0000449 destroy_node(f, in->ino, arg->version);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000450}
451
452static void do_getattr(struct fuse *f, struct fuse_in_header *in)
453{
454 int res;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000455 char *path;
456 struct stat buf;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000457 struct fuse_getattr_out arg;
458
Miklos Szeredi5e183482001-10-31 14:52:35 +0000459 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000460 path = get_path(f, in->ino);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000461 if(path != NULL) {
462 res = -ENOSYS;
463 if(f->op.getattr)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000464 res = f->op.getattr(path, &buf);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000465 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000466 }
Miklos Szeredi0f48a262002-12-05 14:23:01 +0000467
468 if(res == 0) {
469 memset(&arg, 0, sizeof(struct fuse_getattr_out));
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000470 convert_stat(&buf, &arg.attr);
Miklos Szeredi0f48a262002-12-05 14:23:01 +0000471 }
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000472
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000473 send_reply(f, in, res, &arg, sizeof(arg));
474}
475
Miklos Szeredi680a69a2001-11-16 13:31:14 +0000476static int do_chmod(struct fuse *f, const char *path, struct fuse_attr *attr)
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000477{
478 int res;
479
480 res = -ENOSYS;
481 if(f->op.chmod)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000482 res = f->op.chmod(path, attr->mode);
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000483
484 return res;
485}
486
Miklos Szeredi680a69a2001-11-16 13:31:14 +0000487static int do_chown(struct fuse *f, const char *path, struct fuse_attr *attr,
Miklos Szeredi2e50d432001-12-20 12:17:25 +0000488 int valid)
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000489{
490 int res;
491 uid_t uid = (valid & FATTR_UID) ? attr->uid : (uid_t) -1;
492 gid_t gid = (valid & FATTR_GID) ? attr->gid : (gid_t) -1;
493
494 res = -ENOSYS;
495 if(f->op.chown)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000496 res = f->op.chown(path, uid, gid);
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000497
498 return res;
499}
500
Miklos Szeredi680a69a2001-11-16 13:31:14 +0000501static int do_truncate(struct fuse *f, const char *path,
502 struct fuse_attr *attr)
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000503{
504 int res;
505
506 res = -ENOSYS;
507 if(f->op.truncate)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000508 res = f->op.truncate(path, attr->size);
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000509
510 return res;
511}
512
Miklos Szeredi680a69a2001-11-16 13:31:14 +0000513static int do_utime(struct fuse *f, const char *path, struct fuse_attr *attr)
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000514{
515 int res;
516 struct utimbuf buf;
517 buf.actime = attr->atime;
518 buf.modtime = attr->mtime;
519 res = -ENOSYS;
520 if(f->op.utime)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000521 res = f->op.utime(path, &buf);
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000522
523 return res;
524}
525
Miklos Szeredi5e183482001-10-31 14:52:35 +0000526static void do_setattr(struct fuse *f, struct fuse_in_header *in,
527 struct fuse_setattr_in *arg)
528{
529 int res;
530 char *path;
531 int valid = arg->valid;
532 struct fuse_attr *attr = &arg->attr;
Miklos Szeredia181e612001-11-06 12:03:23 +0000533 struct fuse_setattr_out outarg;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000534
535 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000536 path = get_path(f, in->ino);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000537 if(path != NULL) {
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000538 res = -ENOSYS;
539 if(f->op.getattr) {
540 res = 0;
541 if(!res && (valid & FATTR_MODE))
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000542 res = do_chmod(f, path, attr);
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000543 if(!res && (valid & (FATTR_UID | FATTR_GID)))
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000544 res = do_chown(f, path, attr, valid);
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000545 if(!res && (valid & FATTR_SIZE))
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000546 res = do_truncate(f, path, attr);
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000547 if(!res && (valid & FATTR_UTIME))
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000548 res = do_utime(f, path, attr);
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000549 if(!res) {
550 struct stat buf;
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000551 res = f->op.getattr(path, &buf);
Miklos Szeredi0f48a262002-12-05 14:23:01 +0000552 if(!res) {
553 memset(&outarg, 0, sizeof(struct fuse_setattr_out));
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000554 convert_stat(&buf, &outarg.attr);
Miklos Szeredi0f48a262002-12-05 14:23:01 +0000555 }
Miklos Szeredia181e612001-11-06 12:03:23 +0000556 }
Miklos Szeredi5e183482001-10-31 14:52:35 +0000557 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000558 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000559 }
Miklos Szeredia181e612001-11-06 12:03:23 +0000560 send_reply(f, in, res, &outarg, sizeof(outarg));
Miklos Szeredi5e183482001-10-31 14:52:35 +0000561}
562
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000563static void do_readlink(struct fuse *f, struct fuse_in_header *in)
564{
565 int res;
566 char link[PATH_MAX + 1];
Miklos Szeredib483c932001-10-29 14:57:57 +0000567 char *path;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000568
Miklos Szeredi5e183482001-10-31 14:52:35 +0000569 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000570 path = get_path(f, in->ino);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000571 if(path != NULL) {
572 res = -ENOSYS;
573 if(f->op.readlink)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000574 res = f->op.readlink(path, link, sizeof(link));
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000575 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000576 }
Miklos Szeredi2df1c042001-11-06 15:07:17 +0000577 link[PATH_MAX] = '\0';
Miklos Szeredi4b2bef42002-01-09 12:23:27 +0000578 send_reply(f, in, res, link, res == 0 ? strlen(link) : 0);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000579}
580
581static void do_getdir(struct fuse *f, struct fuse_in_header *in)
582{
583 int res;
584 struct fuse_getdir_out arg;
Miklos Szeredia181e612001-11-06 12:03:23 +0000585 struct fuse_dirhandle dh;
Miklos Szeredib483c932001-10-29 14:57:57 +0000586 char *path;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000587
Miklos Szeredib483c932001-10-29 14:57:57 +0000588 dh.fuse = f;
589 dh.fp = tmpfile();
590 dh.dir = in->ino;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000591 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000592 path = get_path(f, in->ino);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000593 if(path != NULL) {
594 res = -ENOSYS;
595 if(f->op.getdir)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000596 res = f->op.getdir(path, &dh, (fuse_dirfil_t) fill_dir);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000597 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000598 }
Miklos Szeredib483c932001-10-29 14:57:57 +0000599 fflush(dh.fp);
Miklos Szeredi0f48a262002-12-05 14:23:01 +0000600
601 memset(&arg, 0, sizeof(struct fuse_getdir_out));
Miklos Szeredib483c932001-10-29 14:57:57 +0000602 arg.fd = fileno(dh.fp);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000603 send_reply(f, in, res, &arg, sizeof(arg));
Miklos Szeredib483c932001-10-29 14:57:57 +0000604 fclose(dh.fp);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000605}
606
Miklos Szeredib483c932001-10-29 14:57:57 +0000607static void do_mknod(struct fuse *f, struct fuse_in_header *in,
608 struct fuse_mknod_in *inarg)
609{
610 int res;
611 char *path;
612 struct fuse_mknod_out outarg;
613 struct stat buf;
614
Miklos Szeredi5e183482001-10-31 14:52:35 +0000615 res = -ENOENT;
Miklos Szeredi6bf8b682002-10-28 08:49:39 +0000616 path = get_path_name(f, in->ino, PARAM(inarg));
Miklos Szeredi5e183482001-10-31 14:52:35 +0000617 if(path != NULL) {
618 res = -ENOSYS;
619 if(f->op.mknod && f->op.getattr) {
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000620 res = f->op.mknod(path, inarg->mode, inarg->rdev);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000621 if(res == 0)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000622 res = f->op.getattr(path, &buf);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000623 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000624 free(path);
Miklos Szeredib483c932001-10-29 14:57:57 +0000625 }
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000626 if(res == 0) {
Miklos Szeredi0f48a262002-12-05 14:23:01 +0000627 memset(&outarg, 0, sizeof(struct fuse_mknod_out));
Miklos Szeredib483c932001-10-29 14:57:57 +0000628 convert_stat(&buf, &outarg.attr);
Miklos Szeredi6bf8b682002-10-28 08:49:39 +0000629 outarg.ino = find_node(f, in->ino, PARAM(inarg), &outarg.attr,
Miklos Szeredia181e612001-11-06 12:03:23 +0000630 in->unique);
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000631 }
Miklos Szeredib483c932001-10-29 14:57:57 +0000632
633 send_reply(f, in, res, &outarg, sizeof(outarg));
634}
635
636static void do_mkdir(struct fuse *f, struct fuse_in_header *in,
637 struct fuse_mkdir_in *inarg)
638{
639 int res;
640 char *path;
641
Miklos Szeredi5e183482001-10-31 14:52:35 +0000642 res = -ENOENT;
Miklos Szeredi6bf8b682002-10-28 08:49:39 +0000643 path = get_path_name(f, in->ino, PARAM(inarg));
Miklos Szeredi5e183482001-10-31 14:52:35 +0000644 if(path != NULL) {
645 res = -ENOSYS;
646 if(f->op.mkdir)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000647 res = f->op.mkdir(path, inarg->mode);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000648 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000649 }
Miklos Szeredib483c932001-10-29 14:57:57 +0000650 send_reply(f, in, res, NULL, 0);
651}
652
653static void do_remove(struct fuse *f, struct fuse_in_header *in, char *name)
654{
655 int res;
656 char *path;
657
Miklos Szeredi5e183482001-10-31 14:52:35 +0000658 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000659 path = get_path_name(f, in->ino, name);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000660 if(path != NULL) {
661 res = -ENOSYS;
662 if(in->opcode == FUSE_UNLINK) {
663 if(f->op.unlink)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000664 res = f->op.unlink(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000665 }
666 else {
667 if(f->op.rmdir)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000668 res = f->op.rmdir(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000669 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000670 free(path);
Miklos Szeredib483c932001-10-29 14:57:57 +0000671 }
Miklos Szeredi5e183482001-10-31 14:52:35 +0000672 if(res == 0)
673 remove_node(f, in->ino, name);
Miklos Szeredib483c932001-10-29 14:57:57 +0000674 send_reply(f, in, res, NULL, 0);
675}
676
677static void do_symlink(struct fuse *f, struct fuse_in_header *in, char *name,
678 char *link)
679{
680 int res;
681 char *path;
682
Miklos Szeredi5e183482001-10-31 14:52:35 +0000683 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000684 path = get_path_name(f, in->ino, name);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000685 if(path != NULL) {
686 res = -ENOSYS;
687 if(f->op.symlink)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000688 res = f->op.symlink(link, path);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000689 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000690 }
Miklos Szeredib483c932001-10-29 14:57:57 +0000691 send_reply(f, in, res, NULL, 0);
692}
693
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000694static void do_rename(struct fuse *f, struct fuse_in_header *in,
695 struct fuse_rename_in *inarg)
696{
697 int res;
698 fino_t olddir = in->ino;
699 fino_t newdir = inarg->newdir;
Miklos Szeredi6bf8b682002-10-28 08:49:39 +0000700 char *oldname = PARAM(inarg);
701 char *newname = oldname + strlen(oldname) + 1;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000702 char *oldpath;
703 char *newpath;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000704
Miklos Szeredi5e183482001-10-31 14:52:35 +0000705 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000706 oldpath = get_path_name(f, olddir, oldname);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000707 if(oldpath != NULL) {
Miklos Szeredia181e612001-11-06 12:03:23 +0000708 newpath = get_path_name(f, newdir, newname);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000709 if(newpath != NULL) {
710 res = -ENOSYS;
711 if(f->op.rename)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000712 res = f->op.rename(oldpath, newpath);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000713 if(res == 0)
714 rename_node(f, olddir, oldname, newdir, newname);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000715 free(newpath);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000716 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000717 free(oldpath);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000718 }
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000719 send_reply(f, in, res, NULL, 0);
720}
721
722static void do_link(struct fuse *f, struct fuse_in_header *in,
Miklos Szeredi5e183482001-10-31 14:52:35 +0000723 struct fuse_link_in *arg)
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000724{
725 int res;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000726 char *oldpath;
727 char *newpath;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000728
Miklos Szeredi5e183482001-10-31 14:52:35 +0000729 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000730 oldpath = get_path(f, in->ino);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000731 if(oldpath != NULL) {
Miklos Szeredi6bf8b682002-10-28 08:49:39 +0000732 newpath = get_path_name(f, arg->newdir, PARAM(arg));
Miklos Szeredi5e183482001-10-31 14:52:35 +0000733 if(newpath != NULL) {
734 res = -ENOSYS;
735 if(f->op.link)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000736 res = f->op.link(oldpath, newpath);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000737 free(newpath);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000738 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000739 free(oldpath);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000740 }
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000741 send_reply(f, in, res, NULL, 0);
742}
743
Miklos Szeredi5e183482001-10-31 14:52:35 +0000744static void do_open(struct fuse *f, struct fuse_in_header *in,
745 struct fuse_open_in *arg)
746{
747 int res;
Miklos Szeredi40b9a5a2002-12-10 16:09:02 +0000748 int res2;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000749 char *path;
750
751 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000752 path = get_path(f, in->ino);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000753 if(path != NULL) {
754 res = -ENOSYS;
755 if(f->op.open)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000756 res = f->op.open(path, arg->flags);
Miklos Szeredi40b9a5a2002-12-10 16:09:02 +0000757 }
758 res2 = send_reply(f, in, res, NULL, 0);
759 if(path != NULL) {
760 /* The open syscall was interrupted, so it must be cancelled */
761 if(res == 0 && res2 == -ENOENT && f->op.release)
Miklos Szeredi9478e862002-12-11 09:50:26 +0000762 f->op.release(path, arg->flags);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000763 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000764 }
Miklos Szeredi5e183482001-10-31 14:52:35 +0000765}
766
Miklos Szeredi9478e862002-12-11 09:50:26 +0000767static void do_release(struct fuse *f, struct fuse_in_header *in,
768 struct fuse_open_in *arg)
Miklos Szeredic8ba2372002-12-10 12:26:00 +0000769{
Miklos Szeredic8ba2372002-12-10 12:26:00 +0000770 char *path;
771
Miklos Szeredic8ba2372002-12-10 12:26:00 +0000772 path = get_path(f, in->ino);
773 if(path != NULL) {
Miklos Szeredic8ba2372002-12-10 12:26:00 +0000774 if(f->op.release)
Miklos Szeredi9478e862002-12-11 09:50:26 +0000775 f->op.release(path, arg->flags);
Miklos Szeredic8ba2372002-12-10 12:26:00 +0000776 free(path);
777 }
Miklos Szeredic8ba2372002-12-10 12:26:00 +0000778}
779
Miklos Szeredi5e183482001-10-31 14:52:35 +0000780static void do_read(struct fuse *f, struct fuse_in_header *in,
781 struct fuse_read_in *arg)
782{
783 int res;
784 char *path;
Miklos Szeredi43696432001-11-18 19:15:05 +0000785 char *outbuf = (char *) malloc(sizeof(struct fuse_out_header) + arg->size);
786 struct fuse_out_header *out = (struct fuse_out_header *) outbuf;
787 char *buf = outbuf + sizeof(struct fuse_out_header);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000788 size_t size;
Miklos Szeredi43696432001-11-18 19:15:05 +0000789 size_t outsize;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000790
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000791 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000792 path = get_path(f, in->ino);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000793 if(path != NULL) {
Miklos Szeredi6ebe2342002-01-06 21:44:16 +0000794 if(f->flags & FUSE_DEBUG) {
795 printf("READ %u bytes from %llu\n", arg->size, arg->offset);
796 fflush(stdout);
797 }
798
Miklos Szeredi5e183482001-10-31 14:52:35 +0000799 res = -ENOSYS;
Miklos Szeredia181e612001-11-06 12:03:23 +0000800 if(f->op.read)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000801 res = f->op.read(path, buf, arg->size, arg->offset);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000802 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000803 }
804
805 size = 0;
806 if(res > 0) {
807 size = res;
808 res = 0;
Miklos Szeredi6ebe2342002-01-06 21:44:16 +0000809 if(f->flags & FUSE_DEBUG) {
810 printf(" READ %u bytes\n", size);
811 fflush(stdout);
812 }
Miklos Szeredi5e183482001-10-31 14:52:35 +0000813 }
Miklos Szeredi0f48a262002-12-05 14:23:01 +0000814 memset(out, 0, sizeof(struct fuse_out_header));
Miklos Szeredi43696432001-11-18 19:15:05 +0000815 out->unique = in->unique;
816 out->error = res;
817 outsize = sizeof(struct fuse_out_header) + size;
818
819 send_reply_raw(f, outbuf, outsize);
820 free(outbuf);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000821}
Miklos Szeredib483c932001-10-29 14:57:57 +0000822
Miklos Szeredia181e612001-11-06 12:03:23 +0000823static void do_write(struct fuse *f, struct fuse_in_header *in,
824 struct fuse_write_in *arg)
825{
826 int res;
827 char *path;
Miklos Szeredia181e612001-11-06 12:03:23 +0000828
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000829 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000830 path = get_path(f, in->ino);
831 if(path != NULL) {
Miklos Szeredi6ebe2342002-01-06 21:44:16 +0000832 if(f->flags & FUSE_DEBUG) {
833 printf("WRITE %u bytes to %llu\n", arg->size, arg->offset);
834 fflush(stdout);
835 }
836
Miklos Szeredia181e612001-11-06 12:03:23 +0000837 res = -ENOSYS;
838 if(f->op.write)
Miklos Szeredi6bf8b682002-10-28 08:49:39 +0000839 res = f->op.write(path, PARAM(arg), arg->size, arg->offset);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000840 free(path);
Miklos Szeredia181e612001-11-06 12:03:23 +0000841 }
842
843 if(res > 0) {
844 if((size_t) res != arg->size) {
845 fprintf(stderr, "short write: %u (should be %u)\n", res,
846 arg->size);
Miklos Szeredi0e535082003-10-13 10:08:06 +0000847 res = -EINVAL;
Miklos Szeredia181e612001-11-06 12:03:23 +0000848 }
849 else
850 res = 0;
851 }
852
853 send_reply(f, in, res, NULL, 0);
854}
855
Miklos Szeredi18e75e42004-02-19 14:23:27 +0000856static void convert_statfs(struct statfs *statfs, struct fuse_kstatfs *kstatfs)
857{
858 kstatfs->bsize = statfs->f_bsize;
859 kstatfs->blocks = statfs->f_blocks;
860 kstatfs->bfree = statfs->f_bfree;
861 kstatfs->bavail = statfs->f_bavail;
862 kstatfs->files = statfs->f_files;
863 kstatfs->ffree = statfs->f_ffree;
864 kstatfs->namelen = statfs->f_namelen;
865}
866
Mark Glinesd84b39a2002-01-07 16:32:02 +0000867static void do_statfs(struct fuse *f, struct fuse_in_header *in)
868{
869 int res;
Mark Glinesd84b39a2002-01-07 16:32:02 +0000870 struct fuse_statfs_out arg;
Miklos Szeredi18e75e42004-02-19 14:23:27 +0000871 struct statfs buf;
Mark Glinesd84b39a2002-01-07 16:32:02 +0000872
873 res = -ENOSYS;
Miklos Szeredi0f48a262002-12-05 14:23:01 +0000874 if(f->op.statfs) {
Miklos Szeredi18e75e42004-02-19 14:23:27 +0000875 res = f->op.statfs("/", &buf);
876 if(res == 0) {
877 memset(&arg, 0, sizeof(struct fuse_statfs_out));
878 convert_statfs(&buf, &arg.st);
879 }
Miklos Szeredi0f48a262002-12-05 14:23:01 +0000880 }
Miklos Szeredi4b2bef42002-01-09 12:23:27 +0000881
Mark Glinesd84b39a2002-01-07 16:32:02 +0000882 send_reply(f, in, res, &arg, sizeof(arg));
883}
884
Miklos Szeredi5e43f2c2003-12-12 14:06:41 +0000885static void do_fsync(struct fuse *f, struct fuse_in_header *in,
886 struct fuse_fsync_in *inarg)
887{
888 int res;
889 char *path;
890
891 res = -ENOENT;
892 path = get_path(f, in->ino);
893 if(path != NULL) {
894 /* fsync is not mandatory, so don't return ENOSYS */
895 res = 0;
896 if(f->op.fsync)
897 res = f->op.fsync(path, inarg->datasync);
898 free(path);
899 }
900 send_reply(f, in, res, NULL, 0);
901}
902
Miklos Szeredi43696432001-11-18 19:15:05 +0000903static void free_cmd(struct fuse_cmd *cmd)
904{
905 free(cmd->buf);
906 free(cmd);
907}
908
Miklos Szeredifff56ab2001-11-16 10:12:59 +0000909void __fuse_process_cmd(struct fuse *f, struct fuse_cmd *cmd)
Miklos Szeredia181e612001-11-06 12:03:23 +0000910{
Miklos Szeredia181e612001-11-06 12:03:23 +0000911 struct fuse_in_header *in = (struct fuse_in_header *) cmd->buf;
912 void *inarg = cmd->buf + sizeof(struct fuse_in_header);
913 size_t argsize;
Miklos Szeredife25def2001-12-20 15:38:05 +0000914 struct fuse_context *ctx = fuse_get_context(f);
Miklos Szeredia181e612001-11-06 12:03:23 +0000915
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +0000916 dec_avail(f);
Miklos Szeredi33232032001-11-19 17:55:51 +0000917
Miklos Szeredic0938ea2001-11-07 12:35:06 +0000918 if((f->flags & FUSE_DEBUG)) {
Miklos Szeredic8ba2372002-12-10 12:26:00 +0000919 printf("unique: %i, opcode: %s (%i), ino: %li, insize: %i\n",
920 in->unique, opname(in->opcode), in->opcode, in->ino,
921 cmd->buflen);
Miklos Szeredic0938ea2001-11-07 12:35:06 +0000922 fflush(stdout);
923 }
Miklos Szeredife25def2001-12-20 15:38:05 +0000924
925 ctx->uid = in->uid;
926 ctx->gid = in->gid;
Miklos Szeredia181e612001-11-06 12:03:23 +0000927
928 argsize = cmd->buflen - sizeof(struct fuse_in_header);
929
930 switch(in->opcode) {
931 case FUSE_LOOKUP:
932 do_lookup(f, in, (char *) inarg);
933 break;
934
Miklos Szeredia181e612001-11-06 12:03:23 +0000935 case FUSE_GETATTR:
936 do_getattr(f, in);
937 break;
938
939 case FUSE_SETATTR:
940 do_setattr(f, in, (struct fuse_setattr_in *) inarg);
941 break;
942
943 case FUSE_READLINK:
944 do_readlink(f, in);
945 break;
946
947 case FUSE_GETDIR:
948 do_getdir(f, in);
949 break;
950
951 case FUSE_MKNOD:
952 do_mknod(f, in, (struct fuse_mknod_in *) inarg);
953 break;
954
955 case FUSE_MKDIR:
956 do_mkdir(f, in, (struct fuse_mkdir_in *) inarg);
957 break;
958
959 case FUSE_UNLINK:
960 case FUSE_RMDIR:
961 do_remove(f, in, (char *) inarg);
962 break;
963
964 case FUSE_SYMLINK:
965 do_symlink(f, in, (char *) inarg,
966 ((char *) inarg) + strlen((char *) inarg) + 1);
967 break;
968
969 case FUSE_RENAME:
970 do_rename(f, in, (struct fuse_rename_in *) inarg);
971 break;
972
973 case FUSE_LINK:
974 do_link(f, in, (struct fuse_link_in *) inarg);
975 break;
976
977 case FUSE_OPEN:
978 do_open(f, in, (struct fuse_open_in *) inarg);
979 break;
980
Miklos Szeredi9478e862002-12-11 09:50:26 +0000981 case FUSE_RELEASE:
982 do_release(f, in, (struct fuse_open_in *) inarg);
983 break;
984
Miklos Szeredia181e612001-11-06 12:03:23 +0000985 case FUSE_READ:
986 do_read(f, in, (struct fuse_read_in *) inarg);
987 break;
988
989 case FUSE_WRITE:
990 do_write(f, in, (struct fuse_write_in *) inarg);
991 break;
992
Mark Glinesd84b39a2002-01-07 16:32:02 +0000993 case FUSE_STATFS:
994 do_statfs(f, in);
995 break;
996
Miklos Szeredi5e43f2c2003-12-12 14:06:41 +0000997 case FUSE_FSYNC:
998 do_fsync(f, in, (struct fuse_fsync_in *) inarg);
999 break;
1000
Miklos Szeredia181e612001-11-06 12:03:23 +00001001 default:
Miklos Szeredi43696432001-11-18 19:15:05 +00001002 send_reply(f, in, -ENOSYS, NULL, 0);
Miklos Szeredia181e612001-11-06 12:03:23 +00001003 }
Miklos Szeredi43696432001-11-18 19:15:05 +00001004
1005 free_cmd(cmd);
Miklos Szeredia181e612001-11-06 12:03:23 +00001006}
1007
Miklos Szeredifff56ab2001-11-16 10:12:59 +00001008struct fuse_cmd *__fuse_read_cmd(struct fuse *f)
Miklos Szeredi2df1c042001-11-06 15:07:17 +00001009{
Miklos Szeredifff56ab2001-11-16 10:12:59 +00001010 ssize_t res;
Miklos Szeredifff56ab2001-11-16 10:12:59 +00001011 struct fuse_cmd *cmd;
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +00001012 struct fuse_in_header *in;
1013 void *inarg;
Miklos Szeredifff56ab2001-11-16 10:12:59 +00001014
Miklos Szeredi43696432001-11-18 19:15:05 +00001015 cmd = (struct fuse_cmd *) malloc(sizeof(struct fuse_cmd));
1016 cmd->buf = (char *) malloc(FUSE_MAX_IN);
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +00001017 in = (struct fuse_in_header *) cmd->buf;
1018 inarg = cmd->buf + sizeof(struct fuse_in_header);
Miklos Szeredi43696432001-11-18 19:15:05 +00001019
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +00001020 do {
1021 res = read(f->fd, cmd->buf, FUSE_MAX_IN);
1022 if(res == -1) {
Miklos Szeredi0f48a262002-12-05 14:23:01 +00001023 free_cmd(cmd);
Miklos Szeredi307242f2004-01-26 11:28:44 +00001024 if(f->exited || errno == EINTR)
Miklos Szeredi0f48a262002-12-05 14:23:01 +00001025 return NULL;
1026
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +00001027 /* ENODEV means we got unmounted, so we silenty return failure */
1028 if(errno != ENODEV) {
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +00001029 /* BAD... This will happen again */
Miklos Szeredi0f48a262002-12-05 14:23:01 +00001030 perror("fuse: reading device");
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +00001031 }
Miklos Szeredi0f48a262002-12-05 14:23:01 +00001032
1033 fuse_exit(f);
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +00001034 return NULL;
Miklos Szeredi96249982001-11-21 12:21:19 +00001035 }
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +00001036 if((size_t) res < sizeof(struct fuse_in_header)) {
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +00001037 free_cmd(cmd);
Miklos Szeredi0f48a262002-12-05 14:23:01 +00001038 /* Cannot happen */
1039 fprintf(stderr, "short read on fuse device\n");
1040 fuse_exit(f);
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +00001041 return NULL;
1042 }
1043 cmd->buflen = res;
1044
1045 /* Forget is special, it can be done without messing with threads. */
1046 if(in->opcode == FUSE_FORGET)
1047 do_forget(f, in, (struct fuse_forget_in *) inarg);
1048
1049 } while(in->opcode == FUSE_FORGET);
1050
Miklos Szeredifff56ab2001-11-16 10:12:59 +00001051 return cmd;
Miklos Szeredi2df1c042001-11-06 15:07:17 +00001052}
1053
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001054void fuse_loop(struct fuse *f)
1055{
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001056 while(1) {
Miklos Szeredi0f48a262002-12-05 14:23:01 +00001057 struct fuse_cmd *cmd;
1058
1059 if(f->exited)
1060 return;
1061
1062 cmd = __fuse_read_cmd(f);
Miklos Szeredifff56ab2001-11-16 10:12:59 +00001063 if(cmd == NULL)
Miklos Szeredi0f48a262002-12-05 14:23:01 +00001064 continue;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001065
Miklos Szeredifff56ab2001-11-16 10:12:59 +00001066 __fuse_process_cmd(f, cmd);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001067 }
1068}
1069
Miklos Szeredi0f48a262002-12-05 14:23:01 +00001070void fuse_exit(struct fuse *f)
1071{
1072 f->exited = 1;
1073}
1074
Miklos Szeredi2e50d432001-12-20 12:17:25 +00001075struct fuse_context *fuse_get_context(struct fuse *f)
1076{
1077 if(f->getcontext)
1078 return f->getcontext(f);
1079 else
1080 return &f->context;
1081}
1082
1083struct fuse *fuse_new(int fd, int flags, const struct fuse_operations *op)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001084{
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001085 struct fuse *f;
1086 struct node *root;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001087
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001088 f = (struct fuse *) calloc(1, sizeof(struct fuse));
Miklos Szeredi2df1c042001-11-06 15:07:17 +00001089
Miklos Szeredia181e612001-11-06 12:03:23 +00001090 f->flags = flags;
Miklos Szeredi8cffdb92001-11-09 14:49:18 +00001091 f->fd = fd;
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001092 f->ctr = 0;
Miklos Szeredifff56ab2001-11-16 10:12:59 +00001093 /* FIXME: Dynamic hash table */
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001094 f->name_table_size = 14057;
1095 f->name_table = (struct node **)
1096 calloc(1, sizeof(struct node *) * f->name_table_size);
1097 f->ino_table_size = 14057;
1098 f->ino_table = (struct node **)
1099 calloc(1, sizeof(struct node *) * f->ino_table_size);
Miklos Szeredia181e612001-11-06 12:03:23 +00001100 pthread_mutex_init(&f->lock, NULL);
Miklos Szeredi33232032001-11-19 17:55:51 +00001101 f->numworker = 0;
1102 f->numavail = 0;
Miklos Szeredi2e50d432001-12-20 12:17:25 +00001103 f->op = *op;
1104 f->getcontext = NULL;
1105 f->context.uid = 0;
1106 f->context.gid = 0;
Miklos Szeredi0f48a262002-12-05 14:23:01 +00001107 f->exited = 0;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001108
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001109 root = (struct node *) calloc(1, sizeof(struct node));
Miklos Szeredi8cffdb92001-11-09 14:49:18 +00001110 root->mode = 0;
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001111 root->rdev = 0;
1112 root->name = strdup("/");
1113 root->parent = 0;
1114 hash_ino(f, root, FUSE_ROOT_INO);
1115
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001116 return f;
1117}
1118
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001119void fuse_destroy(struct fuse *f)
1120{
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001121 size_t i;
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001122 for(i = 0; i < f->ino_table_size; i++) {
1123 struct node *node;
1124 struct node *next;
1125 for(node = f->ino_table[i]; node != NULL; node = next) {
1126 next = node->ino_next;
1127 free_node(node);
1128 }
1129 }
1130 free(f->ino_table);
1131 free(f->name_table);
Miklos Szeredia181e612001-11-06 12:03:23 +00001132 pthread_mutex_destroy(&f->lock);
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001133 free(f);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001134}