blob: 255a24b3293dc23c38f9da1561ae33fbe120eb51 [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 Szeredi254d5ed2004-03-02 11:11:24 +000022#define ENTRY_REVALIDATE_TIME 1 /* sec */
23#define ATTR_REVALIDATE_TIME 1 /* sec */
24
Miklos Szeredic8ba2372002-12-10 12:26:00 +000025static const char *opname(enum fuse_opcode opcode)
26{
27 switch(opcode) {
Miklos Szeredi3ed84232004-03-30 15:17:26 +000028 case FUSE_LOOKUP: return "LOOKUP";
29 case FUSE_FORGET: return "FORGET";
30 case FUSE_GETATTR: return "GETATTR";
31 case FUSE_SETATTR: return "SETATTR";
32 case FUSE_READLINK: return "READLINK";
33 case FUSE_SYMLINK: return "SYMLINK";
34 case FUSE_GETDIR: return "GETDIR";
35 case FUSE_MKNOD: return "MKNOD";
36 case FUSE_MKDIR: return "MKDIR";
37 case FUSE_UNLINK: return "UNLINK";
38 case FUSE_RMDIR: return "RMDIR";
39 case FUSE_RENAME: return "RENAME";
40 case FUSE_LINK: return "LINK";
41 case FUSE_OPEN: return "OPEN";
42 case FUSE_READ: return "READ";
43 case FUSE_WRITE: return "WRITE";
44 case FUSE_STATFS: return "STATFS";
Miklos Szeredi99f20742004-05-19 08:01:10 +000045 case FUSE_FLUSH: return "FLUSH";
Miklos Szeredi3ed84232004-03-30 15:17:26 +000046 case FUSE_RELEASE: return "RELEASE";
47 case FUSE_FSYNC: return "FSYNC";
48 case FUSE_SETXATTR: return "SETXATTR";
49 case FUSE_GETXATTR: return "GETXATTR";
50 case FUSE_LISTXATTR: return "LISTXATTR";
51 case FUSE_REMOVEXATTR: return "REMOVEXATTR";
Miklos Szeredi99f20742004-05-19 08:01:10 +000052 default: return "???";
Miklos Szeredic8ba2372002-12-10 12:26:00 +000053 }
54}
55
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +000056static inline void inc_avail(struct fuse *f)
57{
58 pthread_mutex_lock(&f->lock);
59 f->numavail ++;
60 pthread_mutex_unlock(&f->lock);
61}
62
63static inline void dec_avail(struct fuse *f)
64{
65 pthread_mutex_lock(&f->lock);
66 f->numavail --;
67 pthread_mutex_unlock(&f->lock);
68}
69
Miklos Szeredi97c61e92001-11-07 12:09:43 +000070static struct node *__get_node(struct fuse *f, fino_t ino)
Miklos Szeredia181e612001-11-06 12:03:23 +000071{
Miklos Szeredi97c61e92001-11-07 12:09:43 +000072 size_t hash = ino % f->ino_table_size;
73 struct node *node;
74
75 for(node = f->ino_table[hash]; node != NULL; node = node->ino_next)
76 if(node->ino == ino)
77 return node;
78
79 return NULL;
Miklos Szeredia181e612001-11-06 12:03:23 +000080}
81
Miklos Szeredi97c61e92001-11-07 12:09:43 +000082static struct node *get_node(struct fuse *f, fino_t ino)
Miklos Szeredia181e612001-11-06 12:03:23 +000083{
Miklos Szeredi97c61e92001-11-07 12:09:43 +000084 struct node *node = __get_node(f, ino);
85 if(node != NULL)
86 return node;
87
88 fprintf(stderr, "fuse internal error: inode %lu not found\n", ino);
89 abort();
Miklos Szeredia181e612001-11-06 12:03:23 +000090}
91
Miklos Szeredi76f65782004-02-19 16:55:40 +000092static void hash_ino(struct fuse *f, struct node *node)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000093{
Miklos Szeredi76f65782004-02-19 16:55:40 +000094 size_t hash = node->ino % f->ino_table_size;
Miklos Szeredi97c61e92001-11-07 12:09:43 +000095 node->ino_next = f->ino_table[hash];
96 f->ino_table[hash] = node;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000097}
98
Miklos Szeredi97c61e92001-11-07 12:09:43 +000099static void unhash_ino(struct fuse *f, struct node *node)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000100{
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000101 size_t hash = node->ino % f->ino_table_size;
102 struct node **nodep = &f->ino_table[hash];
103
104 for(; *nodep != NULL; nodep = &(*nodep)->ino_next)
105 if(*nodep == node) {
106 *nodep = node->ino_next;
107 return;
108 }
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000109}
110
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000111static fino_t next_ino(struct fuse *f)
112{
Miklos Szeredi76f65782004-02-19 16:55:40 +0000113 do {
114 f->ctr++;
115 if(!f->ctr)
116 f->generation ++;
117 } while(f->ctr == 0 || __get_node(f, f->ctr) != NULL);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000118 return f->ctr;
119}
120
121static void free_node(struct node *node)
122{
123 free(node->name);
124 free(node);
125}
126
127static unsigned int name_hash(struct fuse *f, fino_t parent, const char *name)
128{
129 unsigned int hash = *name;
130
131 if(hash)
132 for(name += 1; *name != '\0'; name++)
133 hash = (hash << 5) - hash + *name;
134
135 return (hash + parent) % f->name_table_size;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000136}
137
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000138static struct node *lookup_node(struct fuse *f, fino_t parent,
139 const char *name)
140{
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000141 size_t hash = name_hash(f, parent, name);
142 struct node *node;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000143
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000144 for(node = f->name_table[hash]; node != NULL; node = node->name_next)
145 if(node->parent == parent && strcmp(node->name, name) == 0)
146 return node;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000147
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000148 return NULL;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000149}
150
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000151static void hash_name(struct fuse *f, struct node *node, fino_t parent,
Miklos Szeredia181e612001-11-06 12:03:23 +0000152 const char *name)
Miklos Szeredi5e183482001-10-31 14:52:35 +0000153{
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000154 size_t hash = name_hash(f, parent, name);
Miklos Szeredia181e612001-11-06 12:03:23 +0000155 node->parent = parent;
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000156 node->name = strdup(name);
157 node->name_next = f->name_table[hash];
158 f->name_table[hash] = node;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000159}
160
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000161static void unhash_name(struct fuse *f, struct node *node)
Miklos Szeredia181e612001-11-06 12:03:23 +0000162{
163 if(node->name != NULL) {
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000164 size_t hash = name_hash(f, node->parent, node->name);
165 struct node **nodep = &f->name_table[hash];
166
167 for(; *nodep != NULL; nodep = &(*nodep)->name_next)
168 if(*nodep == node) {
169 *nodep = node->name_next;
170 node->name_next = NULL;
171 free(node->name);
172 node->name = NULL;
173 node->parent = 0;
174 return;
175 }
176 fprintf(stderr, "fuse internal error: unable to unhash node: %lu\n",
177 node->ino);
178 abort();
Miklos Szeredia181e612001-11-06 12:03:23 +0000179 }
180}
181
Miklos Szeredi76f65782004-02-19 16:55:40 +0000182static struct node *find_node(struct fuse *f, fino_t parent, char *name,
183 struct fuse_attr *attr, int version)
Miklos Szeredi5e183482001-10-31 14:52:35 +0000184{
185 struct node *node;
Miklos Szeredia181e612001-11-06 12:03:23 +0000186 int mode = attr->mode & S_IFMT;
187 int rdev = 0;
188
189 if(S_ISCHR(mode) || S_ISBLK(mode))
190 rdev = attr->rdev;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000191
Miklos Szeredia181e612001-11-06 12:03:23 +0000192 pthread_mutex_lock(&f->lock);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000193 node = lookup_node(f, parent, name);
194 if(node != NULL) {
Miklos Szeredia181e612001-11-06 12:03:23 +0000195 if(node->mode == mode && node->rdev == rdev)
196 goto out;
197
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000198 unhash_name(f, node);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000199 }
200
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000201 node = (struct node *) calloc(1, sizeof(struct node));
Miklos Szeredia181e612001-11-06 12:03:23 +0000202 node->mode = mode;
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000203 node->rdev = rdev;
Miklos Szeredi76f65782004-02-19 16:55:40 +0000204 node->ino = next_ino(f);
205 node->generation = f->generation;
206 hash_ino(f, node);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000207 hash_name(f, node, parent, name);
Miklos Szeredia181e612001-11-06 12:03:23 +0000208
209 out:
210 node->version = version;
211 pthread_mutex_unlock(&f->lock);
Miklos Szeredi76f65782004-02-19 16:55:40 +0000212 return node;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000213}
214
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000215static char *add_name(char *buf, char *s, const char *name)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000216{
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000217 size_t len = strlen(name);
218 s -= len;
219 if(s <= buf) {
220 fprintf(stderr, "fuse: path too long: ...%s\n", s + len);
221 return NULL;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000222 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000223 strncpy(s, name, len);
224 s--;
225 *s = '/';
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000226
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000227 return s;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000228}
229
Miklos Szeredia181e612001-11-06 12:03:23 +0000230static char *get_path_name(struct fuse *f, fino_t ino, const char *name)
Miklos Szeredib483c932001-10-29 14:57:57 +0000231{
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000232 char buf[FUSE_MAX_PATH];
233 char *s = buf + FUSE_MAX_PATH - 1;
234 struct node *node;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000235
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000236 *s = '\0';
Miklos Szeredia181e612001-11-06 12:03:23 +0000237
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000238 if(name != NULL) {
239 s = add_name(buf, s, name);
240 if(s == NULL)
241 return NULL;
242 }
243
244 pthread_mutex_lock(&f->lock);
245 for(node = get_node(f, ino); node->ino != FUSE_ROOT_INO;
246 node = get_node(f, node->parent)) {
247 if(node->name == NULL) {
248 s = NULL;
249 break;
250 }
251
252 s = add_name(buf, s, node->name);
253 if(s == NULL)
254 break;
255 }
256 pthread_mutex_unlock(&f->lock);
257
258 if(s == NULL)
Miklos Szeredi5e183482001-10-31 14:52:35 +0000259 return NULL;
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000260 else if(*s == '\0')
261 return strdup("/");
262 else
263 return strdup(s);
264}
Miklos Szeredia181e612001-11-06 12:03:23 +0000265
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000266static char *get_path(struct fuse *f, fino_t ino)
267{
268 return get_path_name(f, ino, NULL);
Miklos Szeredib483c932001-10-29 14:57:57 +0000269}
270
Miklos Szeredia181e612001-11-06 12:03:23 +0000271static void destroy_node(struct fuse *f, fino_t ino, int version)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000272{
Miklos Szeredia181e612001-11-06 12:03:23 +0000273 struct node *node;
274
275 pthread_mutex_lock(&f->lock);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000276 node = get_node(f, ino);
Miklos Szeredi39f28672001-11-14 14:52:54 +0000277 if(node->version == version && ino != FUSE_ROOT_INO) {
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000278 unhash_name(f, node);
279 unhash_ino(f, node);
Miklos Szeredia181e612001-11-06 12:03:23 +0000280 free_node(node);
281 }
282 pthread_mutex_unlock(&f->lock);
283
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000284}
285
Miklos Szeredi5e183482001-10-31 14:52:35 +0000286static void remove_node(struct fuse *f, fino_t dir, const char *name)
287{
Miklos Szeredia181e612001-11-06 12:03:23 +0000288 struct node *node;
289
290 pthread_mutex_lock(&f->lock);
291 node = lookup_node(f, dir, name);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000292 if(node == NULL) {
293 fprintf(stderr, "fuse internal error: unable to remove node %lu/%s\n",
294 dir, name);
295 abort();
296 }
297 unhash_name(f, node);
Miklos Szeredia181e612001-11-06 12:03:23 +0000298 pthread_mutex_unlock(&f->lock);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000299}
300
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000301static void rename_node(struct fuse *f, fino_t olddir, const char *oldname,
302 fino_t newdir, const char *newname)
303{
Miklos Szeredia181e612001-11-06 12:03:23 +0000304 struct node *node;
305 struct node *newnode;
306
307 pthread_mutex_lock(&f->lock);
308 node = lookup_node(f, olddir, oldname);
309 newnode = lookup_node(f, newdir, newname);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000310 if(node == NULL) {
311 fprintf(stderr, "fuse internal error: unable to rename node %lu/%s\n",
312 olddir, oldname);
313 abort();
314 }
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000315
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000316 if(newnode != NULL)
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000317 unhash_name(f, newnode);
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000318
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000319 unhash_name(f, node);
320 hash_name(f, node, newdir, newname);
Miklos Szeredia181e612001-11-06 12:03:23 +0000321 pthread_mutex_unlock(&f->lock);
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000322}
323
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000324static void convert_stat(struct stat *stbuf, struct fuse_attr *attr)
325{
Miklos Szeredib5958612004-02-20 14:10:49 +0000326 attr->mode = stbuf->st_mode;
327 attr->nlink = stbuf->st_nlink;
328 attr->uid = stbuf->st_uid;
329 attr->gid = stbuf->st_gid;
330 attr->rdev = stbuf->st_rdev;
331 attr->size = stbuf->st_size;
332 attr->blocks = stbuf->st_blocks;
333 attr->atime = stbuf->st_atime;
334 attr->atimensec = stbuf->st_atim.tv_nsec;
335 attr->mtime = stbuf->st_mtime;
336 attr->mtimensec = stbuf->st_mtim.tv_nsec;
337 attr->ctime = stbuf->st_ctime;
338 attr->ctimensec = stbuf->st_ctim.tv_nsec;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000339}
340
Miklos Szeredia181e612001-11-06 12:03:23 +0000341static int fill_dir(struct fuse_dirhandle *dh, char *name, int type)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000342{
343 struct fuse_dirent dirent;
344 size_t reclen;
345 size_t res;
346
Miklos Szeredi43696432001-11-18 19:15:05 +0000347 dirent.ino = (unsigned long) -1;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000348 dirent.namelen = strlen(name);
349 strncpy(dirent.name, name, sizeof(dirent.name));
350 dirent.type = type;
351 reclen = FUSE_DIRENT_SIZE(&dirent);
352 res = fwrite(&dirent, reclen, 1, dh->fp);
353 if(res == 0) {
Miklos Szeredi96249982001-11-21 12:21:19 +0000354 perror("fuse: writing directory file");
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000355 return -EIO;
356 }
357 return 0;
358}
359
Miklos Szeredi40b9a5a2002-12-10 16:09:02 +0000360static int send_reply_raw(struct fuse *f, char *outbuf, size_t outsize)
Miklos Szeredi43696432001-11-18 19:15:05 +0000361{
362 int res;
363
364 if((f->flags & FUSE_DEBUG)) {
365 struct fuse_out_header *out = (struct fuse_out_header *) outbuf;
366 printf(" unique: %i, error: %i (%s), outsize: %i\n", out->unique,
367 out->error, strerror(-out->error), outsize);
368 fflush(stdout);
369 }
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +0000370
Miklos Szeredi4e71c9f2004-02-09 12:05:14 +0000371 /* This needs to be done before the reply, otherwise the scheduler
372 could play tricks with us, and only let the counter be increased
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +0000373 long after the operation is done */
374 inc_avail(f);
375
Miklos Szeredi43696432001-11-18 19:15:05 +0000376 res = write(f->fd, outbuf, outsize);
377 if(res == -1) {
378 /* ENOENT means the operation was interrupted */
Miklos Szeredi4e71c9f2004-02-09 12:05:14 +0000379 if(!f->exited && errno != ENOENT)
Miklos Szeredi96249982001-11-21 12:21:19 +0000380 perror("fuse: writing device");
Miklos Szeredi40b9a5a2002-12-10 16:09:02 +0000381 return -errno;
Miklos Szeredi43696432001-11-18 19:15:05 +0000382 }
Miklos Szeredi40b9a5a2002-12-10 16:09:02 +0000383 return 0;
Miklos Szeredi43696432001-11-18 19:15:05 +0000384}
385
Miklos Szeredi40b9a5a2002-12-10 16:09:02 +0000386static int send_reply(struct fuse *f, struct fuse_in_header *in, int error,
387 void *arg, size_t argsize)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000388{
Miklos Szeredi40b9a5a2002-12-10 16:09:02 +0000389 int res;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000390 char *outbuf;
391 size_t outsize;
392 struct fuse_out_header *out;
393
Miklos Szeredi03cebae2004-03-31 10:19:18 +0000394 if(error <= -1000 || error > 0) {
Miklos Szeredi0f48a262002-12-05 14:23:01 +0000395 fprintf(stderr, "fuse: bad error value: %i\n", error);
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000396 error = -ERANGE;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000397 }
398
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000399 if(error)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000400 argsize = 0;
401
402 outsize = sizeof(struct fuse_out_header) + argsize;
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000403 outbuf = (char *) malloc(outsize);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000404 out = (struct fuse_out_header *) outbuf;
Miklos Szeredi0f48a262002-12-05 14:23:01 +0000405 memset(out, 0, sizeof(struct fuse_out_header));
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000406 out->unique = in->unique;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000407 out->error = error;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000408 if(argsize != 0)
409 memcpy(outbuf + sizeof(struct fuse_out_header), arg, argsize);
410
Miklos Szeredi40b9a5a2002-12-10 16:09:02 +0000411 res = send_reply_raw(f, outbuf, outsize);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000412 free(outbuf);
Miklos Szeredi40b9a5a2002-12-10 16:09:02 +0000413
414 return res;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000415}
416
Miklos Szeredi76f65782004-02-19 16:55:40 +0000417static int lookup_path(struct fuse *f, fino_t ino, int version, char *name,
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000418 const char *path, struct fuse_entry_out *arg)
Miklos Szeredi76f65782004-02-19 16:55:40 +0000419{
420 int res;
421 struct stat buf;
422
423 res = f->op.getattr(path, &buf);
424 if(res == 0) {
425 struct node *node;
426
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000427 memset(arg, 0, sizeof(struct fuse_entry_out));
Miklos Szeredi76f65782004-02-19 16:55:40 +0000428 convert_stat(&buf, &arg->attr);
429 node = find_node(f, ino, name, &arg->attr, version);
430 arg->ino = node->ino;
431 arg->generation = node->generation;
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000432 arg->entry_valid = ENTRY_REVALIDATE_TIME;
433 arg->entry_valid_nsec = 0;
434 arg->attr_valid = ATTR_REVALIDATE_TIME;
435 arg->attr_valid_nsec = 0;
Miklos Szeredi76f65782004-02-19 16:55:40 +0000436 if(f->flags & FUSE_DEBUG) {
437 printf(" INO: %li\n", arg->ino);
438 fflush(stdout);
439 }
440 }
441 return res;
442}
443
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000444static void do_lookup(struct fuse *f, struct fuse_in_header *in, char *name)
445{
446 int res;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000447 char *path;
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000448 struct fuse_entry_out arg;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000449
Miklos Szeredi5e183482001-10-31 14:52:35 +0000450 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000451 path = get_path_name(f, in->ino, name);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000452 if(path != NULL) {
Miklos Szeredi6ebe2342002-01-06 21:44:16 +0000453 if(f->flags & FUSE_DEBUG) {
454 printf("LOOKUP %s\n", path);
455 fflush(stdout);
456 }
Miklos Szeredi5e183482001-10-31 14:52:35 +0000457 res = -ENOSYS;
458 if(f->op.getattr)
Miklos Szeredi76f65782004-02-19 16:55:40 +0000459 res = lookup_path(f, in->ino, in->unique, name, path, &arg);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000460 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000461 }
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000462 send_reply(f, in, res, &arg, sizeof(arg));
463}
464
Miklos Szeredia181e612001-11-06 12:03:23 +0000465static void do_forget(struct fuse *f, struct fuse_in_header *in,
466 struct fuse_forget_in *arg)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000467{
Miklos Szeredi43696432001-11-18 19:15:05 +0000468 if(f->flags & FUSE_DEBUG) {
469 printf("FORGET %li/%i\n", in->ino, arg->version);
470 fflush(stdout);
471 }
Miklos Szeredia181e612001-11-06 12:03:23 +0000472 destroy_node(f, in->ino, arg->version);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000473}
474
475static void do_getattr(struct fuse *f, struct fuse_in_header *in)
476{
477 int res;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000478 char *path;
479 struct stat buf;
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000480 struct fuse_attr_out arg;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000481
Miklos Szeredi5e183482001-10-31 14:52:35 +0000482 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000483 path = get_path(f, in->ino);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000484 if(path != NULL) {
485 res = -ENOSYS;
486 if(f->op.getattr)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000487 res = f->op.getattr(path, &buf);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000488 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000489 }
Miklos Szeredi0f48a262002-12-05 14:23:01 +0000490
491 if(res == 0) {
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000492 memset(&arg, 0, sizeof(struct fuse_attr_out));
493 arg.attr_valid = ATTR_REVALIDATE_TIME;
494 arg.attr_valid_nsec = 0;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000495 convert_stat(&buf, &arg.attr);
Miklos Szeredi0f48a262002-12-05 14:23:01 +0000496 }
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000497
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000498 send_reply(f, in, res, &arg, sizeof(arg));
499}
500
Miklos Szeredi680a69a2001-11-16 13:31:14 +0000501static int do_chmod(struct fuse *f, const char *path, struct fuse_attr *attr)
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000502{
503 int res;
504
505 res = -ENOSYS;
506 if(f->op.chmod)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000507 res = f->op.chmod(path, attr->mode);
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000508
509 return res;
510}
511
Miklos Szeredi680a69a2001-11-16 13:31:14 +0000512static int do_chown(struct fuse *f, const char *path, struct fuse_attr *attr,
Miklos Szeredi2e50d432001-12-20 12:17:25 +0000513 int valid)
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000514{
515 int res;
516 uid_t uid = (valid & FATTR_UID) ? attr->uid : (uid_t) -1;
517 gid_t gid = (valid & FATTR_GID) ? attr->gid : (gid_t) -1;
518
519 res = -ENOSYS;
520 if(f->op.chown)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000521 res = f->op.chown(path, uid, gid);
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000522
523 return res;
524}
525
Miklos Szeredi680a69a2001-11-16 13:31:14 +0000526static int do_truncate(struct fuse *f, const char *path,
527 struct fuse_attr *attr)
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000528{
529 int res;
530
531 res = -ENOSYS;
532 if(f->op.truncate)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000533 res = f->op.truncate(path, attr->size);
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000534
535 return res;
536}
537
Miklos Szeredi680a69a2001-11-16 13:31:14 +0000538static int do_utime(struct fuse *f, const char *path, struct fuse_attr *attr)
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000539{
540 int res;
541 struct utimbuf buf;
542 buf.actime = attr->atime;
543 buf.modtime = attr->mtime;
544 res = -ENOSYS;
545 if(f->op.utime)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000546 res = f->op.utime(path, &buf);
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000547
548 return res;
549}
550
Miklos Szeredi5e183482001-10-31 14:52:35 +0000551static void do_setattr(struct fuse *f, struct fuse_in_header *in,
552 struct fuse_setattr_in *arg)
553{
554 int res;
555 char *path;
556 int valid = arg->valid;
557 struct fuse_attr *attr = &arg->attr;
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000558 struct fuse_attr_out outarg;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000559
560 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000561 path = get_path(f, in->ino);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000562 if(path != NULL) {
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000563 res = -ENOSYS;
564 if(f->op.getattr) {
565 res = 0;
566 if(!res && (valid & FATTR_MODE))
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000567 res = do_chmod(f, path, attr);
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000568 if(!res && (valid & (FATTR_UID | FATTR_GID)))
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000569 res = do_chown(f, path, attr, valid);
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000570 if(!res && (valid & FATTR_SIZE))
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000571 res = do_truncate(f, path, attr);
Miklos Szeredib5958612004-02-20 14:10:49 +0000572 if(!res && (valid & (FATTR_ATIME | FATTR_MTIME)) ==
573 (FATTR_ATIME | FATTR_MTIME))
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000574 res = do_utime(f, path, attr);
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000575 if(!res) {
576 struct stat buf;
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000577 res = f->op.getattr(path, &buf);
Miklos Szeredi0f48a262002-12-05 14:23:01 +0000578 if(!res) {
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000579 memset(&outarg, 0, sizeof(struct fuse_attr_out));
580 outarg.attr_valid = ATTR_REVALIDATE_TIME;
581 outarg.attr_valid_nsec = 0;
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000582 convert_stat(&buf, &outarg.attr);
Miklos Szeredi0f48a262002-12-05 14:23:01 +0000583 }
Miklos Szeredia181e612001-11-06 12:03:23 +0000584 }
Miklos Szeredi5e183482001-10-31 14:52:35 +0000585 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000586 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000587 }
Miklos Szeredia181e612001-11-06 12:03:23 +0000588 send_reply(f, in, res, &outarg, sizeof(outarg));
Miklos Szeredi5e183482001-10-31 14:52:35 +0000589}
590
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000591static void do_readlink(struct fuse *f, struct fuse_in_header *in)
592{
593 int res;
594 char link[PATH_MAX + 1];
Miklos Szeredib483c932001-10-29 14:57:57 +0000595 char *path;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000596
Miklos Szeredi5e183482001-10-31 14:52:35 +0000597 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000598 path = get_path(f, in->ino);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000599 if(path != NULL) {
600 res = -ENOSYS;
601 if(f->op.readlink)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000602 res = f->op.readlink(path, link, sizeof(link));
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000603 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000604 }
Miklos Szeredi2df1c042001-11-06 15:07:17 +0000605 link[PATH_MAX] = '\0';
Miklos Szeredi4b2bef42002-01-09 12:23:27 +0000606 send_reply(f, in, res, link, res == 0 ? strlen(link) : 0);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000607}
608
609static void do_getdir(struct fuse *f, struct fuse_in_header *in)
610{
611 int res;
612 struct fuse_getdir_out arg;
Miklos Szeredia181e612001-11-06 12:03:23 +0000613 struct fuse_dirhandle dh;
Miklos Szeredib483c932001-10-29 14:57:57 +0000614 char *path;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000615
Miklos Szeredib483c932001-10-29 14:57:57 +0000616 dh.fuse = f;
617 dh.fp = tmpfile();
618 dh.dir = in->ino;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000619 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000620 path = get_path(f, in->ino);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000621 if(path != NULL) {
622 res = -ENOSYS;
623 if(f->op.getdir)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000624 res = f->op.getdir(path, &dh, (fuse_dirfil_t) fill_dir);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000625 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000626 }
Miklos Szeredib483c932001-10-29 14:57:57 +0000627 fflush(dh.fp);
Miklos Szeredi0f48a262002-12-05 14:23:01 +0000628
629 memset(&arg, 0, sizeof(struct fuse_getdir_out));
Miklos Szeredib483c932001-10-29 14:57:57 +0000630 arg.fd = fileno(dh.fp);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000631 send_reply(f, in, res, &arg, sizeof(arg));
Miklos Szeredib483c932001-10-29 14:57:57 +0000632 fclose(dh.fp);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000633}
634
Miklos Szeredib483c932001-10-29 14:57:57 +0000635static void do_mknod(struct fuse *f, struct fuse_in_header *in,
636 struct fuse_mknod_in *inarg)
637{
638 int res;
639 char *path;
Miklos Szeredi76f65782004-02-19 16:55:40 +0000640 char *name = PARAM(inarg);
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000641 struct fuse_entry_out outarg;
Miklos Szeredib483c932001-10-29 14:57:57 +0000642
Miklos Szeredi5e183482001-10-31 14:52:35 +0000643 res = -ENOENT;
Miklos Szeredi76f65782004-02-19 16:55:40 +0000644 path = get_path_name(f, in->ino, name);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000645 if(path != NULL) {
Miklos Szeredi76f65782004-02-19 16:55:40 +0000646 if(f->flags & FUSE_DEBUG) {
647 printf("MKNOD %s\n", path);
648 fflush(stdout);
649 }
Miklos Szeredi5e183482001-10-31 14:52:35 +0000650 res = -ENOSYS;
651 if(f->op.mknod && f->op.getattr) {
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000652 res = f->op.mknod(path, inarg->mode, inarg->rdev);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000653 if(res == 0)
Miklos Szeredi76f65782004-02-19 16:55:40 +0000654 res = lookup_path(f, in->ino, in->unique, name, path, &outarg);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000655 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000656 free(path);
Miklos Szeredib483c932001-10-29 14:57:57 +0000657 }
Miklos Szeredib483c932001-10-29 14:57:57 +0000658 send_reply(f, in, res, &outarg, sizeof(outarg));
659}
660
661static void do_mkdir(struct fuse *f, struct fuse_in_header *in,
662 struct fuse_mkdir_in *inarg)
663{
664 int res;
665 char *path;
Miklos Szeredi76f65782004-02-19 16:55:40 +0000666 char *name = PARAM(inarg);
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000667 struct fuse_entry_out outarg;
Miklos Szeredib483c932001-10-29 14:57:57 +0000668
Miklos Szeredi5e183482001-10-31 14:52:35 +0000669 res = -ENOENT;
Miklos Szeredi76f65782004-02-19 16:55:40 +0000670 path = get_path_name(f, in->ino, name);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000671 if(path != NULL) {
Miklos Szeredi76f65782004-02-19 16:55:40 +0000672 if(f->flags & FUSE_DEBUG) {
673 printf("MKDIR %s\n", path);
674 fflush(stdout);
675 }
Miklos Szeredi5e183482001-10-31 14:52:35 +0000676 res = -ENOSYS;
Miklos Szeredi76f65782004-02-19 16:55:40 +0000677 if(f->op.mkdir && f->op.getattr) {
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000678 res = f->op.mkdir(path, inarg->mode);
Miklos Szeredi76f65782004-02-19 16:55:40 +0000679 if(res == 0)
680 res = lookup_path(f, in->ino, in->unique, name, path, &outarg);
681 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000682 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000683 }
Miklos Szeredi76f65782004-02-19 16:55:40 +0000684 send_reply(f, in, res, &outarg, sizeof(outarg));
Miklos Szeredib483c932001-10-29 14:57:57 +0000685}
686
Miklos Szeredib5958612004-02-20 14:10:49 +0000687static void do_unlink(struct fuse *f, struct fuse_in_header *in, char *name)
Miklos Szeredib483c932001-10-29 14:57:57 +0000688{
689 int res;
690 char *path;
691
Miklos Szeredi5e183482001-10-31 14:52:35 +0000692 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000693 path = get_path_name(f, in->ino, name);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000694 if(path != NULL) {
695 res = -ENOSYS;
Miklos Szeredib5958612004-02-20 14:10:49 +0000696 if(f->op.unlink) {
697 res = f->op.unlink(path);
698 if(res == 0)
699 remove_node(f, in->ino, name);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000700 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000701 free(path);
Miklos Szeredib483c932001-10-29 14:57:57 +0000702 }
Miklos Szeredib5958612004-02-20 14:10:49 +0000703 send_reply(f, in, res, NULL, 0);
704}
705
706static void do_rmdir(struct fuse *f, struct fuse_in_header *in, char *name)
707{
708 int res;
709 char *path;
710
711 res = -ENOENT;
712 path = get_path_name(f, in->ino, name);
713 if(path != NULL) {
714 res = -ENOSYS;
715 if(f->op.rmdir) {
716 res = f->op.rmdir(path);
717 if(res == 0)
718 remove_node(f, in->ino, name);
719 }
720 free(path);
721 }
Miklos Szeredib483c932001-10-29 14:57:57 +0000722 send_reply(f, in, res, NULL, 0);
723}
724
725static void do_symlink(struct fuse *f, struct fuse_in_header *in, char *name,
726 char *link)
727{
728 int res;
729 char *path;
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000730 struct fuse_entry_out outarg;
Miklos Szeredib483c932001-10-29 14:57:57 +0000731
Miklos Szeredi5e183482001-10-31 14:52:35 +0000732 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000733 path = get_path_name(f, in->ino, name);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000734 if(path != NULL) {
Miklos Szeredi76f65782004-02-19 16:55:40 +0000735 if(f->flags & FUSE_DEBUG) {
736 printf("SYMLINK %s\n", path);
737 fflush(stdout);
738 }
Miklos Szeredi5e183482001-10-31 14:52:35 +0000739 res = -ENOSYS;
Miklos Szeredi76f65782004-02-19 16:55:40 +0000740 if(f->op.symlink && f->op.getattr) {
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000741 res = f->op.symlink(link, path);
Miklos Szeredi76f65782004-02-19 16:55:40 +0000742 if(res == 0)
743 res = lookup_path(f, in->ino, in->unique, name, path, &outarg);
744 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000745 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000746 }
Miklos Szeredi76f65782004-02-19 16:55:40 +0000747 send_reply(f, in, res, &outarg, sizeof(outarg));
Miklos Szeredib483c932001-10-29 14:57:57 +0000748}
749
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000750static void do_rename(struct fuse *f, struct fuse_in_header *in,
751 struct fuse_rename_in *inarg)
752{
753 int res;
754 fino_t olddir = in->ino;
755 fino_t newdir = inarg->newdir;
Miklos Szeredi6bf8b682002-10-28 08:49:39 +0000756 char *oldname = PARAM(inarg);
757 char *newname = oldname + strlen(oldname) + 1;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000758 char *oldpath;
759 char *newpath;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000760
Miklos Szeredi5e183482001-10-31 14:52:35 +0000761 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000762 oldpath = get_path_name(f, olddir, oldname);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000763 if(oldpath != NULL) {
Miklos Szeredia181e612001-11-06 12:03:23 +0000764 newpath = get_path_name(f, newdir, newname);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000765 if(newpath != NULL) {
766 res = -ENOSYS;
767 if(f->op.rename)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000768 res = f->op.rename(oldpath, newpath);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000769 if(res == 0)
770 rename_node(f, olddir, oldname, newdir, newname);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000771 free(newpath);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000772 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000773 free(oldpath);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000774 }
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000775 send_reply(f, in, res, NULL, 0);
776}
777
778static void do_link(struct fuse *f, struct fuse_in_header *in,
Miklos Szeredi5e183482001-10-31 14:52:35 +0000779 struct fuse_link_in *arg)
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000780{
781 int res;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000782 char *oldpath;
783 char *newpath;
Miklos Szeredi76f65782004-02-19 16:55:40 +0000784 char *name = PARAM(arg);
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000785 struct fuse_entry_out outarg;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000786
Miklos Szeredi5e183482001-10-31 14:52:35 +0000787 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000788 oldpath = get_path(f, in->ino);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000789 if(oldpath != NULL) {
Miklos Szeredi76f65782004-02-19 16:55:40 +0000790 newpath = get_path_name(f, arg->newdir, name);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000791 if(newpath != NULL) {
Miklos Szeredi76f65782004-02-19 16:55:40 +0000792 if(f->flags & FUSE_DEBUG) {
793 printf("LINK %s\n", newpath);
794 fflush(stdout);
795 }
Miklos Szeredi5e183482001-10-31 14:52:35 +0000796 res = -ENOSYS;
Miklos Szeredi76f65782004-02-19 16:55:40 +0000797 if(f->op.link && f->op.getattr) {
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000798 res = f->op.link(oldpath, newpath);
Miklos Szeredi76f65782004-02-19 16:55:40 +0000799 if(res == 0)
800 res = lookup_path(f, arg->newdir, in->unique, name,
801 newpath, &outarg);
802 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000803 free(newpath);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000804 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000805 free(oldpath);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000806 }
Miklos Szeredi76f65782004-02-19 16:55:40 +0000807 send_reply(f, in, res, &outarg, sizeof(outarg));
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000808}
809
Miklos Szeredi5e183482001-10-31 14:52:35 +0000810static void do_open(struct fuse *f, struct fuse_in_header *in,
811 struct fuse_open_in *arg)
812{
813 int res;
Miklos Szeredi40b9a5a2002-12-10 16:09:02 +0000814 int res2;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000815 char *path;
816
817 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000818 path = get_path(f, in->ino);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000819 if(path != NULL) {
820 res = -ENOSYS;
821 if(f->op.open)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000822 res = f->op.open(path, arg->flags);
Miklos Szeredi40b9a5a2002-12-10 16:09:02 +0000823 }
824 res2 = send_reply(f, in, res, NULL, 0);
825 if(path != NULL) {
826 /* The open syscall was interrupted, so it must be cancelled */
827 if(res == 0 && res2 == -ENOENT && f->op.release)
Miklos Szeredi9478e862002-12-11 09:50:26 +0000828 f->op.release(path, arg->flags);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000829 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000830 }
Miklos Szeredi5e183482001-10-31 14:52:35 +0000831}
832
Miklos Szeredie2e4ac22004-05-18 08:45:28 +0000833static void do_flush(struct fuse *f, struct fuse_in_header *in)
834{
835 char *path;
836 int res;
837
838 res = -ENOENT;
839 path = get_path(f, in->ino);
840 if(path != NULL) {
841 res = -ENOSYS;
842 if(f->op.flush)
843 res = f->op.flush(path);
844 free(path);
845 }
846 send_reply(f, in, res, NULL, 0);
847}
848
Miklos Szeredi9478e862002-12-11 09:50:26 +0000849static void do_release(struct fuse *f, struct fuse_in_header *in,
850 struct fuse_open_in *arg)
Miklos Szeredic8ba2372002-12-10 12:26:00 +0000851{
Miklos Szeredic8ba2372002-12-10 12:26:00 +0000852 char *path;
853
Miklos Szeredic8ba2372002-12-10 12:26:00 +0000854 path = get_path(f, in->ino);
855 if(path != NULL) {
Miklos Szeredic8ba2372002-12-10 12:26:00 +0000856 if(f->op.release)
Miklos Szeredi9478e862002-12-11 09:50:26 +0000857 f->op.release(path, arg->flags);
Miklos Szeredic8ba2372002-12-10 12:26:00 +0000858 free(path);
859 }
Miklos Szeredic8ba2372002-12-10 12:26:00 +0000860}
861
Miklos Szeredi5e183482001-10-31 14:52:35 +0000862static void do_read(struct fuse *f, struct fuse_in_header *in,
863 struct fuse_read_in *arg)
864{
865 int res;
866 char *path;
Miklos Szeredi43696432001-11-18 19:15:05 +0000867 char *outbuf = (char *) malloc(sizeof(struct fuse_out_header) + arg->size);
868 struct fuse_out_header *out = (struct fuse_out_header *) outbuf;
869 char *buf = outbuf + sizeof(struct fuse_out_header);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000870 size_t size;
Miklos Szeredi43696432001-11-18 19:15:05 +0000871 size_t outsize;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000872
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000873 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000874 path = get_path(f, in->ino);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000875 if(path != NULL) {
Miklos Szeredi6ebe2342002-01-06 21:44:16 +0000876 if(f->flags & FUSE_DEBUG) {
877 printf("READ %u bytes from %llu\n", arg->size, arg->offset);
878 fflush(stdout);
879 }
880
Miklos Szeredi5e183482001-10-31 14:52:35 +0000881 res = -ENOSYS;
Miklos Szeredia181e612001-11-06 12:03:23 +0000882 if(f->op.read)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000883 res = f->op.read(path, buf, arg->size, arg->offset);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000884 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000885 }
886
887 size = 0;
888 if(res > 0) {
889 size = res;
890 res = 0;
Miklos Szeredi6ebe2342002-01-06 21:44:16 +0000891 if(f->flags & FUSE_DEBUG) {
892 printf(" READ %u bytes\n", size);
893 fflush(stdout);
894 }
Miklos Szeredi5e183482001-10-31 14:52:35 +0000895 }
Miklos Szeredi0f48a262002-12-05 14:23:01 +0000896 memset(out, 0, sizeof(struct fuse_out_header));
Miklos Szeredi43696432001-11-18 19:15:05 +0000897 out->unique = in->unique;
898 out->error = res;
899 outsize = sizeof(struct fuse_out_header) + size;
900
901 send_reply_raw(f, outbuf, outsize);
902 free(outbuf);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000903}
Miklos Szeredib483c932001-10-29 14:57:57 +0000904
Miklos Szeredia181e612001-11-06 12:03:23 +0000905static void do_write(struct fuse *f, struct fuse_in_header *in,
906 struct fuse_write_in *arg)
907{
908 int res;
909 char *path;
Miklos Szeredia181e612001-11-06 12:03:23 +0000910
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000911 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000912 path = get_path(f, in->ino);
913 if(path != NULL) {
Miklos Szeredi6ebe2342002-01-06 21:44:16 +0000914 if(f->flags & FUSE_DEBUG) {
915 printf("WRITE %u bytes to %llu\n", arg->size, arg->offset);
916 fflush(stdout);
917 }
918
Miklos Szeredia181e612001-11-06 12:03:23 +0000919 res = -ENOSYS;
920 if(f->op.write)
Miklos Szeredi6bf8b682002-10-28 08:49:39 +0000921 res = f->op.write(path, PARAM(arg), arg->size, arg->offset);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000922 free(path);
Miklos Szeredia181e612001-11-06 12:03:23 +0000923 }
924
925 if(res > 0) {
926 if((size_t) res != arg->size) {
927 fprintf(stderr, "short write: %u (should be %u)\n", res,
928 arg->size);
Miklos Szeredi0e535082003-10-13 10:08:06 +0000929 res = -EINVAL;
Miklos Szeredia181e612001-11-06 12:03:23 +0000930 }
931 else
932 res = 0;
933 }
934
935 send_reply(f, in, res, NULL, 0);
936}
937
Miklos Szeredi77f39942004-03-25 11:17:52 +0000938static int default_statfs(struct statfs *buf)
939{
940 buf->f_namelen = 255;
941 buf->f_bsize = 512;
942 return 0;
943}
944
Miklos Szeredi18e75e42004-02-19 14:23:27 +0000945static void convert_statfs(struct statfs *statfs, struct fuse_kstatfs *kstatfs)
946{
947 kstatfs->bsize = statfs->f_bsize;
948 kstatfs->blocks = statfs->f_blocks;
949 kstatfs->bfree = statfs->f_bfree;
950 kstatfs->bavail = statfs->f_bavail;
951 kstatfs->files = statfs->f_files;
952 kstatfs->ffree = statfs->f_ffree;
953 kstatfs->namelen = statfs->f_namelen;
954}
955
Mark Glinesd84b39a2002-01-07 16:32:02 +0000956static void do_statfs(struct fuse *f, struct fuse_in_header *in)
957{
958 int res;
Mark Glinesd84b39a2002-01-07 16:32:02 +0000959 struct fuse_statfs_out arg;
Miklos Szeredi18e75e42004-02-19 14:23:27 +0000960 struct statfs buf;
Mark Glinesd84b39a2002-01-07 16:32:02 +0000961
Miklos Szeredi77f39942004-03-25 11:17:52 +0000962 memset(&buf, 0, sizeof(struct statfs));
963 if(f->op.statfs)
Miklos Szeredi18e75e42004-02-19 14:23:27 +0000964 res = f->op.statfs("/", &buf);
Miklos Szeredi77f39942004-03-25 11:17:52 +0000965 else
966 res = default_statfs(&buf);
967
968 if(res == 0)
969 convert_statfs(&buf, &arg.st);
Miklos Szeredi4b2bef42002-01-09 12:23:27 +0000970
Mark Glinesd84b39a2002-01-07 16:32:02 +0000971 send_reply(f, in, res, &arg, sizeof(arg));
972}
973
Miklos Szeredi5e43f2c2003-12-12 14:06:41 +0000974static void do_fsync(struct fuse *f, struct fuse_in_header *in,
975 struct fuse_fsync_in *inarg)
976{
977 int res;
978 char *path;
979
980 res = -ENOENT;
981 path = get_path(f, in->ino);
982 if(path != NULL) {
983 /* fsync is not mandatory, so don't return ENOSYS */
984 res = 0;
985 if(f->op.fsync)
986 res = f->op.fsync(path, inarg->datasync);
987 free(path);
988 }
989 send_reply(f, in, res, NULL, 0);
990}
991
Miklos Szeredi3ed84232004-03-30 15:17:26 +0000992static void do_setxattr(struct fuse *f, struct fuse_in_header *in,
993 struct fuse_setxattr_in *arg)
994{
995 int res;
996 char *path;
997 char *name = PARAM(arg);
998 unsigned char *value = name + strlen(name) + 1;
999
1000 res = -ENOENT;
1001 path = get_path(f, in->ino);
1002 if (path != NULL) {
1003 res = -EOPNOTSUPP; /* or is it ENOTSUPP ??? */
1004 if (f->op.setxattr)
1005 res = f->op.setxattr(path, name, value, arg->size, arg->flags);
1006 free(path);
1007 }
1008 send_reply(f, in, res, NULL, 0);
1009}
1010
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001011static int common_getxattr(struct fuse *f, struct fuse_in_header *in,
1012 const char *name, char *value, size_t size)
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001013{
1014 int res;
1015 char *path;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001016
1017 res = -ENOENT;
1018 path = get_path(f, in->ino);
1019 if (path != NULL) {
1020 res = -EOPNOTSUPP; /* or is it ENOTSUPP ??? */
1021 if (f->op.getxattr)
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001022 res = f->op.getxattr(path, name, value, size);
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001023 free(path);
1024 }
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001025 return res;
1026}
1027
1028static void do_getxattr_read(struct fuse *f, struct fuse_in_header *in,
1029 const char *name, size_t size)
1030{
1031 int res;
1032 char *outbuf = (char *) malloc(sizeof(struct fuse_out_header) + size);
1033 struct fuse_out_header *out = (struct fuse_out_header *) outbuf;
1034 char *value = outbuf + sizeof(struct fuse_out_header);
1035
1036 res = common_getxattr(f, in, name, value, size);
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001037 size = 0;
1038 if(res > 0) {
1039 size = res;
1040 res = 0;
1041 }
1042 memset(out, 0, sizeof(struct fuse_out_header));
1043 out->unique = in->unique;
1044 out->error = res;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001045
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001046 send_reply_raw(f, outbuf, sizeof(struct fuse_out_header) + size);
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001047 free(outbuf);
1048}
1049
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001050static void do_getxattr_size(struct fuse *f, struct fuse_in_header *in,
1051 const char *name)
1052{
1053 int res;
1054 struct fuse_getxattr_out arg;
1055
1056 res = common_getxattr(f, in, name, NULL, 0);
1057 if(res >= 0) {
1058 arg.size = res;
1059 res = 0;
1060 }
1061 send_reply(f, in, res, &arg, sizeof(arg));
1062}
1063
1064static void do_getxattr(struct fuse *f, struct fuse_in_header *in,
1065 struct fuse_getxattr_in *arg)
1066{
1067 char *name = PARAM(arg);
1068
1069 if(arg->size)
1070 do_getxattr_read(f, in, name, arg->size);
1071 else
1072 do_getxattr_size(f, in, name);
1073}
1074
1075static int common_listxattr(struct fuse *f, struct fuse_in_header *in,
1076 char *list, size_t size)
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001077{
1078 int res;
1079 char *path;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001080
1081 res = -ENOENT;
1082 path = get_path(f, in->ino);
1083 if (path != NULL) {
1084 res = -EOPNOTSUPP; /* or is it ENOTSUPP ??? */
1085 if (f->op.listxattr)
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001086 res = f->op.listxattr(path, list, size);
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001087 free(path);
1088 }
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001089 return res;
1090}
1091
1092static void do_listxattr_read(struct fuse *f, struct fuse_in_header *in,
1093 size_t size)
1094{
1095 int res;
1096 char *outbuf = (char *) malloc(sizeof(struct fuse_out_header) + size);
1097 struct fuse_out_header *out = (struct fuse_out_header *) outbuf;
1098 char *list = outbuf + sizeof(struct fuse_out_header);
1099
1100 res = common_listxattr(f, in, list, size);
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001101 size = 0;
1102 if(res > 0) {
1103 size = res;
1104 res = 0;
1105 }
1106 memset(out, 0, sizeof(struct fuse_out_header));
1107 out->unique = in->unique;
1108 out->error = res;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001109
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001110 send_reply_raw(f, outbuf, sizeof(struct fuse_out_header) + size);
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001111 free(outbuf);
1112}
1113
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001114static void do_listxattr_size(struct fuse *f, struct fuse_in_header *in)
1115{
1116 int res;
1117 struct fuse_getxattr_out arg;
1118
1119 res = common_listxattr(f, in, NULL, 0);
1120 if (res >= 0) {
1121 arg.size = res;
1122 res = 0;
1123 }
1124 send_reply(f, in, res, &arg, sizeof(arg));
1125}
1126
1127static void do_listxattr(struct fuse *f, struct fuse_in_header *in,
1128 struct fuse_getxattr_in *arg)
1129{
1130 if(arg->size)
1131 do_listxattr_read(f, in, arg->size);
1132 else
1133 do_listxattr_size(f, in);
1134}
1135
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001136static void do_removexattr(struct fuse *f, struct fuse_in_header *in,
1137 char *name)
1138{
1139 int res;
1140 char *path;
1141
1142 res = -ENOENT;
1143 path = get_path(f, in->ino);
1144 if (path != NULL) {
1145 res = -EOPNOTSUPP; /* or is it ENOTSUPP ??? */
1146 if (f->op.removexattr)
1147 res = f->op.removexattr(path, name);
1148 free(path);
1149 }
1150 send_reply(f, in, res, NULL, 0);
1151}
1152
1153
Miklos Szeredi43696432001-11-18 19:15:05 +00001154static void free_cmd(struct fuse_cmd *cmd)
1155{
1156 free(cmd->buf);
1157 free(cmd);
1158}
1159
Miklos Szeredifff56ab2001-11-16 10:12:59 +00001160void __fuse_process_cmd(struct fuse *f, struct fuse_cmd *cmd)
Miklos Szeredia181e612001-11-06 12:03:23 +00001161{
Miklos Szeredia181e612001-11-06 12:03:23 +00001162 struct fuse_in_header *in = (struct fuse_in_header *) cmd->buf;
1163 void *inarg = cmd->buf + sizeof(struct fuse_in_header);
1164 size_t argsize;
Miklos Szeredife25def2001-12-20 15:38:05 +00001165 struct fuse_context *ctx = fuse_get_context(f);
Miklos Szeredia181e612001-11-06 12:03:23 +00001166
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +00001167 dec_avail(f);
Miklos Szeredi33232032001-11-19 17:55:51 +00001168
Miklos Szeredic0938ea2001-11-07 12:35:06 +00001169 if((f->flags & FUSE_DEBUG)) {
Miklos Szeredic8ba2372002-12-10 12:26:00 +00001170 printf("unique: %i, opcode: %s (%i), ino: %li, insize: %i\n",
1171 in->unique, opname(in->opcode), in->opcode, in->ino,
1172 cmd->buflen);
Miklos Szeredic0938ea2001-11-07 12:35:06 +00001173 fflush(stdout);
1174 }
Miklos Szeredife25def2001-12-20 15:38:05 +00001175
1176 ctx->uid = in->uid;
1177 ctx->gid = in->gid;
Miklos Szeredia181e612001-11-06 12:03:23 +00001178
1179 argsize = cmd->buflen - sizeof(struct fuse_in_header);
1180
1181 switch(in->opcode) {
1182 case FUSE_LOOKUP:
1183 do_lookup(f, in, (char *) inarg);
1184 break;
1185
Miklos Szeredia181e612001-11-06 12:03:23 +00001186 case FUSE_GETATTR:
1187 do_getattr(f, in);
1188 break;
1189
1190 case FUSE_SETATTR:
1191 do_setattr(f, in, (struct fuse_setattr_in *) inarg);
1192 break;
1193
1194 case FUSE_READLINK:
1195 do_readlink(f, in);
1196 break;
1197
1198 case FUSE_GETDIR:
1199 do_getdir(f, in);
1200 break;
1201
1202 case FUSE_MKNOD:
1203 do_mknod(f, in, (struct fuse_mknod_in *) inarg);
1204 break;
1205
1206 case FUSE_MKDIR:
1207 do_mkdir(f, in, (struct fuse_mkdir_in *) inarg);
1208 break;
1209
1210 case FUSE_UNLINK:
Miklos Szeredib5958612004-02-20 14:10:49 +00001211 do_unlink(f, in, (char *) inarg);
1212 break;
1213
Miklos Szeredia181e612001-11-06 12:03:23 +00001214 case FUSE_RMDIR:
Miklos Szeredib5958612004-02-20 14:10:49 +00001215 do_rmdir(f, in, (char *) inarg);
Miklos Szeredia181e612001-11-06 12:03:23 +00001216 break;
1217
1218 case FUSE_SYMLINK:
1219 do_symlink(f, in, (char *) inarg,
1220 ((char *) inarg) + strlen((char *) inarg) + 1);
1221 break;
1222
1223 case FUSE_RENAME:
1224 do_rename(f, in, (struct fuse_rename_in *) inarg);
1225 break;
1226
1227 case FUSE_LINK:
1228 do_link(f, in, (struct fuse_link_in *) inarg);
1229 break;
1230
1231 case FUSE_OPEN:
1232 do_open(f, in, (struct fuse_open_in *) inarg);
1233 break;
1234
Miklos Szeredie2e4ac22004-05-18 08:45:28 +00001235 case FUSE_FLUSH:
1236 do_flush(f, in);
1237 break;
1238
Miklos Szeredi9478e862002-12-11 09:50:26 +00001239 case FUSE_RELEASE:
1240 do_release(f, in, (struct fuse_open_in *) inarg);
1241 break;
1242
Miklos Szeredia181e612001-11-06 12:03:23 +00001243 case FUSE_READ:
1244 do_read(f, in, (struct fuse_read_in *) inarg);
1245 break;
1246
1247 case FUSE_WRITE:
1248 do_write(f, in, (struct fuse_write_in *) inarg);
1249 break;
1250
Mark Glinesd84b39a2002-01-07 16:32:02 +00001251 case FUSE_STATFS:
1252 do_statfs(f, in);
1253 break;
1254
Miklos Szeredi5e43f2c2003-12-12 14:06:41 +00001255 case FUSE_FSYNC:
1256 do_fsync(f, in, (struct fuse_fsync_in *) inarg);
1257 break;
1258
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001259 case FUSE_SETXATTR:
1260 do_setxattr(f, in, (struct fuse_setxattr_in *) inarg);
1261 break;
1262
1263 case FUSE_GETXATTR:
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001264 do_getxattr(f, in, (struct fuse_getxattr_in *) inarg);
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001265 break;
1266
1267 case FUSE_LISTXATTR:
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001268 do_listxattr(f, in, (struct fuse_getxattr_in *) inarg);
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001269 break;
1270
1271 case FUSE_REMOVEXATTR:
1272 do_removexattr(f, in, (char *) inarg);
1273 break;
1274
Miklos Szeredia181e612001-11-06 12:03:23 +00001275 default:
Miklos Szeredi43696432001-11-18 19:15:05 +00001276 send_reply(f, in, -ENOSYS, NULL, 0);
Miklos Szeredia181e612001-11-06 12:03:23 +00001277 }
Miklos Szeredi43696432001-11-18 19:15:05 +00001278
1279 free_cmd(cmd);
Miklos Szeredia181e612001-11-06 12:03:23 +00001280}
1281
Miklos Szeredifff56ab2001-11-16 10:12:59 +00001282struct fuse_cmd *__fuse_read_cmd(struct fuse *f)
Miklos Szeredi2df1c042001-11-06 15:07:17 +00001283{
Miklos Szeredifff56ab2001-11-16 10:12:59 +00001284 ssize_t res;
Miklos Szeredifff56ab2001-11-16 10:12:59 +00001285 struct fuse_cmd *cmd;
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +00001286 struct fuse_in_header *in;
1287 void *inarg;
Miklos Szeredifff56ab2001-11-16 10:12:59 +00001288
Miklos Szeredi43696432001-11-18 19:15:05 +00001289 cmd = (struct fuse_cmd *) malloc(sizeof(struct fuse_cmd));
1290 cmd->buf = (char *) malloc(FUSE_MAX_IN);
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +00001291 in = (struct fuse_in_header *) cmd->buf;
1292 inarg = cmd->buf + sizeof(struct fuse_in_header);
Miklos Szeredi43696432001-11-18 19:15:05 +00001293
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +00001294 do {
1295 res = read(f->fd, cmd->buf, FUSE_MAX_IN);
1296 if(res == -1) {
Miklos Szeredi0f48a262002-12-05 14:23:01 +00001297 free_cmd(cmd);
Miklos Szeredi307242f2004-01-26 11:28:44 +00001298 if(f->exited || errno == EINTR)
Miklos Szeredi0f48a262002-12-05 14:23:01 +00001299 return NULL;
1300
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +00001301 /* ENODEV means we got unmounted, so we silenty return failure */
1302 if(errno != ENODEV) {
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +00001303 /* BAD... This will happen again */
Miklos Szeredi0f48a262002-12-05 14:23:01 +00001304 perror("fuse: reading device");
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +00001305 }
Miklos Szeredi0f48a262002-12-05 14:23:01 +00001306
1307 fuse_exit(f);
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +00001308 return NULL;
Miklos Szeredi96249982001-11-21 12:21:19 +00001309 }
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +00001310 if((size_t) res < sizeof(struct fuse_in_header)) {
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +00001311 free_cmd(cmd);
Miklos Szeredi0f48a262002-12-05 14:23:01 +00001312 /* Cannot happen */
1313 fprintf(stderr, "short read on fuse device\n");
1314 fuse_exit(f);
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +00001315 return NULL;
1316 }
1317 cmd->buflen = res;
1318
1319 /* Forget is special, it can be done without messing with threads. */
1320 if(in->opcode == FUSE_FORGET)
1321 do_forget(f, in, (struct fuse_forget_in *) inarg);
1322
1323 } while(in->opcode == FUSE_FORGET);
1324
Miklos Szeredifff56ab2001-11-16 10:12:59 +00001325 return cmd;
Miklos Szeredi2df1c042001-11-06 15:07:17 +00001326}
1327
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001328void fuse_loop(struct fuse *f)
1329{
Miklos Szeredic40748a2004-02-20 16:38:45 +00001330 if(f == NULL)
1331 return;
1332
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001333 while(1) {
Miklos Szeredi0f48a262002-12-05 14:23:01 +00001334 struct fuse_cmd *cmd;
1335
1336 if(f->exited)
1337 return;
1338
1339 cmd = __fuse_read_cmd(f);
Miklos Szeredifff56ab2001-11-16 10:12:59 +00001340 if(cmd == NULL)
Miklos Szeredi0f48a262002-12-05 14:23:01 +00001341 continue;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001342
Miklos Szeredifff56ab2001-11-16 10:12:59 +00001343 __fuse_process_cmd(f, cmd);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001344 }
1345}
1346
Miklos Szeredi0f48a262002-12-05 14:23:01 +00001347void fuse_exit(struct fuse *f)
1348{
1349 f->exited = 1;
1350}
1351
Miklos Szeredi2e50d432001-12-20 12:17:25 +00001352struct fuse_context *fuse_get_context(struct fuse *f)
1353{
1354 if(f->getcontext)
1355 return f->getcontext(f);
1356 else
1357 return &f->context;
1358}
1359
Miklos Szeredic40748a2004-02-20 16:38:45 +00001360static int check_version(struct fuse *f)
1361{
1362 int res;
1363 FILE *vf = fopen(FUSE_VERSION_FILE, "r");
1364 if(vf == NULL) {
1365 fprintf(stderr, "fuse: kernel interface too old, need >= %i.%i\n",
1366 FUSE_KERNEL_VERSION, FUSE_KERNEL_MINOR_VERSION);
1367 return -1;
1368 }
1369 res = fscanf(vf, "%i.%i", &f->majorver, &f->minorver);
1370 fclose(vf);
1371 if(res != 2) {
1372 fprintf(stderr, "fuse: error reading %s\n", FUSE_VERSION_FILE);
1373 return -1;
1374 }
1375 if(f->majorver != FUSE_KERNEL_VERSION) {
1376 fprintf(stderr, "fuse: bad kernel interface major version: needs %i\n",
1377 FUSE_KERNEL_VERSION);
1378 return -1;
1379 }
1380 if(f->minorver < FUSE_KERNEL_MINOR_VERSION) {
1381 fprintf(stderr, "fuse: kernel interface too old: need >= %i.%i",
1382 FUSE_KERNEL_VERSION, FUSE_KERNEL_MINOR_VERSION);
1383 return -1;
1384 }
1385
1386 return 0;
1387}
1388
Miklos Szeredi2e50d432001-12-20 12:17:25 +00001389struct fuse *fuse_new(int fd, int flags, const struct fuse_operations *op)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001390{
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001391 struct fuse *f;
1392 struct node *root;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001393
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001394 f = (struct fuse *) calloc(1, sizeof(struct fuse));
Miklos Szeredi2df1c042001-11-06 15:07:17 +00001395
Miklos Szeredic40748a2004-02-20 16:38:45 +00001396 if(check_version(f) == -1) {
1397 free(f);
1398 return NULL;
1399 }
1400
Miklos Szeredia181e612001-11-06 12:03:23 +00001401 f->flags = flags;
Miklos Szeredi8cffdb92001-11-09 14:49:18 +00001402 f->fd = fd;
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001403 f->ctr = 0;
Miklos Szeredi76f65782004-02-19 16:55:40 +00001404 f->generation = 0;
Miklos Szeredifff56ab2001-11-16 10:12:59 +00001405 /* FIXME: Dynamic hash table */
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001406 f->name_table_size = 14057;
1407 f->name_table = (struct node **)
1408 calloc(1, sizeof(struct node *) * f->name_table_size);
1409 f->ino_table_size = 14057;
1410 f->ino_table = (struct node **)
1411 calloc(1, sizeof(struct node *) * f->ino_table_size);
Miklos Szeredia181e612001-11-06 12:03:23 +00001412 pthread_mutex_init(&f->lock, NULL);
Miklos Szeredi33232032001-11-19 17:55:51 +00001413 f->numworker = 0;
1414 f->numavail = 0;
Miklos Szeredi2e50d432001-12-20 12:17:25 +00001415 f->op = *op;
1416 f->getcontext = NULL;
1417 f->context.uid = 0;
1418 f->context.gid = 0;
Miklos Szeredi0f48a262002-12-05 14:23:01 +00001419 f->exited = 0;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001420
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001421 root = (struct node *) calloc(1, sizeof(struct node));
Miklos Szeredi8cffdb92001-11-09 14:49:18 +00001422 root->mode = 0;
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001423 root->rdev = 0;
1424 root->name = strdup("/");
1425 root->parent = 0;
Miklos Szeredi76f65782004-02-19 16:55:40 +00001426 root->ino = FUSE_ROOT_INO;
1427 root->generation = 0;
1428 hash_ino(f, root);
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001429
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001430 return f;
1431}
1432
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001433void fuse_destroy(struct fuse *f)
1434{
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001435 size_t i;
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001436 for(i = 0; i < f->ino_table_size; i++) {
1437 struct node *node;
1438 struct node *next;
1439 for(node = f->ino_table[i]; node != NULL; node = next) {
1440 next = node->ino_next;
1441 free_node(node);
1442 }
1443 }
1444 free(f->ino_table);
1445 free(f->name_table);
Miklos Szeredia181e612001-11-06 12:03:23 +00001446 pthread_mutex_destroy(&f->lock);
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001447 free(f);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001448}