blob: d382707a33695d7c2baac8c60e09ede12563b47d [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{
112 while(f->ctr == 0 || __get_node(f, f->ctr) != NULL)
113 f->ctr++;
114
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
364 /* This needs to be done before the reply because otherwise the
365 scheduler can tricks with us, and only let the counter be increased
366 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 */
372 if(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
Mark Glinesd84b39a2002-01-07 16:32:02 +0000856static void do_statfs(struct fuse *f, struct fuse_in_header *in)
857{
858 int res;
Mark Glinesd84b39a2002-01-07 16:32:02 +0000859 struct fuse_statfs_out arg;
860
861 res = -ENOSYS;
Miklos Szeredi0f48a262002-12-05 14:23:01 +0000862 if(f->op.statfs) {
863 memset(&arg, 0, sizeof(struct fuse_statfs_out));
Miklos Szeredi24ed9452002-10-07 10:24:26 +0000864 res = f->op.statfs((struct fuse_statfs *) &arg.st);
Miklos Szeredi0f48a262002-12-05 14:23:01 +0000865 }
Miklos Szeredi4b2bef42002-01-09 12:23:27 +0000866
Mark Glinesd84b39a2002-01-07 16:32:02 +0000867 send_reply(f, in, res, &arg, sizeof(arg));
868}
869
Miklos Szeredi5e43f2c2003-12-12 14:06:41 +0000870static void do_fsync(struct fuse *f, struct fuse_in_header *in,
871 struct fuse_fsync_in *inarg)
872{
873 int res;
874 char *path;
875
876 res = -ENOENT;
877 path = get_path(f, in->ino);
878 if(path != NULL) {
879 /* fsync is not mandatory, so don't return ENOSYS */
880 res = 0;
881 if(f->op.fsync)
882 res = f->op.fsync(path, inarg->datasync);
883 free(path);
884 }
885 send_reply(f, in, res, NULL, 0);
886}
887
Miklos Szeredi43696432001-11-18 19:15:05 +0000888static void free_cmd(struct fuse_cmd *cmd)
889{
890 free(cmd->buf);
891 free(cmd);
892}
893
Miklos Szeredifff56ab2001-11-16 10:12:59 +0000894void __fuse_process_cmd(struct fuse *f, struct fuse_cmd *cmd)
Miklos Szeredia181e612001-11-06 12:03:23 +0000895{
Miklos Szeredia181e612001-11-06 12:03:23 +0000896 struct fuse_in_header *in = (struct fuse_in_header *) cmd->buf;
897 void *inarg = cmd->buf + sizeof(struct fuse_in_header);
898 size_t argsize;
Miklos Szeredife25def2001-12-20 15:38:05 +0000899 struct fuse_context *ctx = fuse_get_context(f);
Miklos Szeredia181e612001-11-06 12:03:23 +0000900
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +0000901 dec_avail(f);
Miklos Szeredi33232032001-11-19 17:55:51 +0000902
Miklos Szeredic0938ea2001-11-07 12:35:06 +0000903 if((f->flags & FUSE_DEBUG)) {
Miklos Szeredic8ba2372002-12-10 12:26:00 +0000904 printf("unique: %i, opcode: %s (%i), ino: %li, insize: %i\n",
905 in->unique, opname(in->opcode), in->opcode, in->ino,
906 cmd->buflen);
Miklos Szeredic0938ea2001-11-07 12:35:06 +0000907 fflush(stdout);
908 }
Miklos Szeredife25def2001-12-20 15:38:05 +0000909
910 ctx->uid = in->uid;
911 ctx->gid = in->gid;
Miklos Szeredia181e612001-11-06 12:03:23 +0000912
913 argsize = cmd->buflen - sizeof(struct fuse_in_header);
914
915 switch(in->opcode) {
916 case FUSE_LOOKUP:
917 do_lookup(f, in, (char *) inarg);
918 break;
919
Miklos Szeredia181e612001-11-06 12:03:23 +0000920 case FUSE_GETATTR:
921 do_getattr(f, in);
922 break;
923
924 case FUSE_SETATTR:
925 do_setattr(f, in, (struct fuse_setattr_in *) inarg);
926 break;
927
928 case FUSE_READLINK:
929 do_readlink(f, in);
930 break;
931
932 case FUSE_GETDIR:
933 do_getdir(f, in);
934 break;
935
936 case FUSE_MKNOD:
937 do_mknod(f, in, (struct fuse_mknod_in *) inarg);
938 break;
939
940 case FUSE_MKDIR:
941 do_mkdir(f, in, (struct fuse_mkdir_in *) inarg);
942 break;
943
944 case FUSE_UNLINK:
945 case FUSE_RMDIR:
946 do_remove(f, in, (char *) inarg);
947 break;
948
949 case FUSE_SYMLINK:
950 do_symlink(f, in, (char *) inarg,
951 ((char *) inarg) + strlen((char *) inarg) + 1);
952 break;
953
954 case FUSE_RENAME:
955 do_rename(f, in, (struct fuse_rename_in *) inarg);
956 break;
957
958 case FUSE_LINK:
959 do_link(f, in, (struct fuse_link_in *) inarg);
960 break;
961
962 case FUSE_OPEN:
963 do_open(f, in, (struct fuse_open_in *) inarg);
964 break;
965
Miklos Szeredi9478e862002-12-11 09:50:26 +0000966 case FUSE_RELEASE:
967 do_release(f, in, (struct fuse_open_in *) inarg);
968 break;
969
Miklos Szeredia181e612001-11-06 12:03:23 +0000970 case FUSE_READ:
971 do_read(f, in, (struct fuse_read_in *) inarg);
972 break;
973
974 case FUSE_WRITE:
975 do_write(f, in, (struct fuse_write_in *) inarg);
976 break;
977
Mark Glinesd84b39a2002-01-07 16:32:02 +0000978 case FUSE_STATFS:
979 do_statfs(f, in);
980 break;
981
Miklos Szeredi5e43f2c2003-12-12 14:06:41 +0000982 case FUSE_FSYNC:
983 do_fsync(f, in, (struct fuse_fsync_in *) inarg);
984 break;
985
Miklos Szeredia181e612001-11-06 12:03:23 +0000986 default:
Miklos Szeredi43696432001-11-18 19:15:05 +0000987 send_reply(f, in, -ENOSYS, NULL, 0);
Miklos Szeredia181e612001-11-06 12:03:23 +0000988 }
Miklos Szeredi43696432001-11-18 19:15:05 +0000989
990 free_cmd(cmd);
Miklos Szeredia181e612001-11-06 12:03:23 +0000991}
992
Miklos Szeredifff56ab2001-11-16 10:12:59 +0000993struct fuse_cmd *__fuse_read_cmd(struct fuse *f)
Miklos Szeredi2df1c042001-11-06 15:07:17 +0000994{
Miklos Szeredifff56ab2001-11-16 10:12:59 +0000995 ssize_t res;
Miklos Szeredifff56ab2001-11-16 10:12:59 +0000996 struct fuse_cmd *cmd;
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +0000997 struct fuse_in_header *in;
998 void *inarg;
Miklos Szeredifff56ab2001-11-16 10:12:59 +0000999
Miklos Szeredi43696432001-11-18 19:15:05 +00001000 cmd = (struct fuse_cmd *) malloc(sizeof(struct fuse_cmd));
1001 cmd->buf = (char *) malloc(FUSE_MAX_IN);
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +00001002 in = (struct fuse_in_header *) cmd->buf;
1003 inarg = cmd->buf + sizeof(struct fuse_in_header);
Miklos Szeredi43696432001-11-18 19:15:05 +00001004
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +00001005 do {
1006 res = read(f->fd, cmd->buf, FUSE_MAX_IN);
1007 if(res == -1) {
Miklos Szeredi0f48a262002-12-05 14:23:01 +00001008 free_cmd(cmd);
1009 if(errno == EINTR)
1010 return NULL;
1011
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +00001012 /* ENODEV means we got unmounted, so we silenty return failure */
1013 if(errno != ENODEV) {
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +00001014 /* BAD... This will happen again */
Miklos Szeredi0f48a262002-12-05 14:23:01 +00001015 perror("fuse: reading device");
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +00001016 }
Miklos Szeredi0f48a262002-12-05 14:23:01 +00001017
1018 fuse_exit(f);
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +00001019 return NULL;
Miklos Szeredi96249982001-11-21 12:21:19 +00001020 }
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +00001021 if((size_t) res < sizeof(struct fuse_in_header)) {
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +00001022 free_cmd(cmd);
Miklos Szeredi0f48a262002-12-05 14:23:01 +00001023 /* Cannot happen */
1024 fprintf(stderr, "short read on fuse device\n");
1025 fuse_exit(f);
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +00001026 return NULL;
1027 }
1028 cmd->buflen = res;
1029
1030 /* Forget is special, it can be done without messing with threads. */
1031 if(in->opcode == FUSE_FORGET)
1032 do_forget(f, in, (struct fuse_forget_in *) inarg);
1033
1034 } while(in->opcode == FUSE_FORGET);
1035
Miklos Szeredifff56ab2001-11-16 10:12:59 +00001036 return cmd;
Miklos Szeredi2df1c042001-11-06 15:07:17 +00001037}
1038
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001039void fuse_loop(struct fuse *f)
1040{
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001041 while(1) {
Miklos Szeredi0f48a262002-12-05 14:23:01 +00001042 struct fuse_cmd *cmd;
1043
1044 if(f->exited)
1045 return;
1046
1047 cmd = __fuse_read_cmd(f);
Miklos Szeredifff56ab2001-11-16 10:12:59 +00001048 if(cmd == NULL)
Miklos Szeredi0f48a262002-12-05 14:23:01 +00001049 continue;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001050
Miklos Szeredifff56ab2001-11-16 10:12:59 +00001051 __fuse_process_cmd(f, cmd);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001052 }
1053}
1054
Miklos Szeredi0f48a262002-12-05 14:23:01 +00001055void fuse_exit(struct fuse *f)
1056{
1057 f->exited = 1;
1058}
1059
Miklos Szeredi2e50d432001-12-20 12:17:25 +00001060struct fuse_context *fuse_get_context(struct fuse *f)
1061{
1062 if(f->getcontext)
1063 return f->getcontext(f);
1064 else
1065 return &f->context;
1066}
1067
1068struct fuse *fuse_new(int fd, int flags, const struct fuse_operations *op)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001069{
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001070 struct fuse *f;
1071 struct node *root;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001072
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001073 f = (struct fuse *) calloc(1, sizeof(struct fuse));
Miklos Szeredi2df1c042001-11-06 15:07:17 +00001074
Miklos Szeredia181e612001-11-06 12:03:23 +00001075 f->flags = flags;
Miklos Szeredi8cffdb92001-11-09 14:49:18 +00001076 f->fd = fd;
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001077 f->ctr = 0;
Miklos Szeredifff56ab2001-11-16 10:12:59 +00001078 /* FIXME: Dynamic hash table */
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001079 f->name_table_size = 14057;
1080 f->name_table = (struct node **)
1081 calloc(1, sizeof(struct node *) * f->name_table_size);
1082 f->ino_table_size = 14057;
1083 f->ino_table = (struct node **)
1084 calloc(1, sizeof(struct node *) * f->ino_table_size);
Miklos Szeredia181e612001-11-06 12:03:23 +00001085 pthread_mutex_init(&f->lock, NULL);
Miklos Szeredi33232032001-11-19 17:55:51 +00001086 f->numworker = 0;
1087 f->numavail = 0;
Miklos Szeredi2e50d432001-12-20 12:17:25 +00001088 f->op = *op;
1089 f->getcontext = NULL;
1090 f->context.uid = 0;
1091 f->context.gid = 0;
Miklos Szeredi0f48a262002-12-05 14:23:01 +00001092 f->exited = 0;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001093
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001094 root = (struct node *) calloc(1, sizeof(struct node));
Miklos Szeredi8cffdb92001-11-09 14:49:18 +00001095 root->mode = 0;
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001096 root->rdev = 0;
1097 root->name = strdup("/");
1098 root->parent = 0;
1099 hash_ino(f, root, FUSE_ROOT_INO);
1100
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001101 return f;
1102}
1103
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001104void fuse_destroy(struct fuse *f)
1105{
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001106 size_t i;
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001107 for(i = 0; i < f->ino_table_size; i++) {
1108 struct node *node;
1109 struct node *next;
1110 for(node = f->ino_table[i]; node != NULL; node = next) {
1111 next = node->ino_next;
1112 free_node(node);
1113 }
1114 }
1115 free(f->ino_table);
1116 free(f->name_table);
Miklos Szeredia181e612001-11-06 12:03:23 +00001117 pthread_mutex_destroy(&f->lock);
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001118 free(f);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001119}