blob: 77532a43067c165e44ea7bdd6e4e2880f8c43886 [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";
45 case FUSE_RELEASE: return "RELEASE";
46 case FUSE_FSYNC: return "FSYNC";
47 case FUSE_SETXATTR: return "SETXATTR";
48 case FUSE_GETXATTR: return "GETXATTR";
49 case FUSE_LISTXATTR: return "LISTXATTR";
50 case FUSE_REMOVEXATTR: return "REMOVEXATTR";
Miklos Szeredic8ba2372002-12-10 12:26:00 +000051 default: return "???";
52 }
53}
54
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +000055static inline void inc_avail(struct fuse *f)
56{
57 pthread_mutex_lock(&f->lock);
58 f->numavail ++;
59 pthread_mutex_unlock(&f->lock);
60}
61
62static inline void dec_avail(struct fuse *f)
63{
64 pthread_mutex_lock(&f->lock);
65 f->numavail --;
66 pthread_mutex_unlock(&f->lock);
67}
68
Miklos Szeredi97c61e92001-11-07 12:09:43 +000069static struct node *__get_node(struct fuse *f, fino_t ino)
Miklos Szeredia181e612001-11-06 12:03:23 +000070{
Miklos Szeredi97c61e92001-11-07 12:09:43 +000071 size_t hash = ino % f->ino_table_size;
72 struct node *node;
73
74 for(node = f->ino_table[hash]; node != NULL; node = node->ino_next)
75 if(node->ino == ino)
76 return node;
77
78 return NULL;
Miklos Szeredia181e612001-11-06 12:03:23 +000079}
80
Miklos Szeredi97c61e92001-11-07 12:09:43 +000081static struct node *get_node(struct fuse *f, fino_t ino)
Miklos Szeredia181e612001-11-06 12:03:23 +000082{
Miklos Szeredi97c61e92001-11-07 12:09:43 +000083 struct node *node = __get_node(f, ino);
84 if(node != NULL)
85 return node;
86
87 fprintf(stderr, "fuse internal error: inode %lu not found\n", ino);
88 abort();
Miklos Szeredia181e612001-11-06 12:03:23 +000089}
90
Miklos Szeredi76f65782004-02-19 16:55:40 +000091static void hash_ino(struct fuse *f, struct node *node)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000092{
Miklos Szeredi76f65782004-02-19 16:55:40 +000093 size_t hash = node->ino % f->ino_table_size;
Miklos Szeredi97c61e92001-11-07 12:09:43 +000094 node->ino_next = f->ino_table[hash];
95 f->ino_table[hash] = node;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000096}
97
Miklos Szeredi97c61e92001-11-07 12:09:43 +000098static void unhash_ino(struct fuse *f, struct node *node)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000099{
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000100 size_t hash = node->ino % f->ino_table_size;
101 struct node **nodep = &f->ino_table[hash];
102
103 for(; *nodep != NULL; nodep = &(*nodep)->ino_next)
104 if(*nodep == node) {
105 *nodep = node->ino_next;
106 return;
107 }
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000108}
109
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000110static fino_t next_ino(struct fuse *f)
111{
Miklos Szeredi76f65782004-02-19 16:55:40 +0000112 do {
113 f->ctr++;
114 if(!f->ctr)
115 f->generation ++;
116 } while(f->ctr == 0 || __get_node(f, f->ctr) != NULL);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000117 return f->ctr;
118}
119
120static void free_node(struct node *node)
121{
122 free(node->name);
123 free(node);
124}
125
126static unsigned int name_hash(struct fuse *f, fino_t parent, const char *name)
127{
128 unsigned int hash = *name;
129
130 if(hash)
131 for(name += 1; *name != '\0'; name++)
132 hash = (hash << 5) - hash + *name;
133
134 return (hash + parent) % f->name_table_size;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000135}
136
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000137static struct node *lookup_node(struct fuse *f, fino_t parent,
138 const char *name)
139{
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000140 size_t hash = name_hash(f, parent, name);
141 struct node *node;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000142
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000143 for(node = f->name_table[hash]; node != NULL; node = node->name_next)
144 if(node->parent == parent && strcmp(node->name, name) == 0)
145 return node;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000146
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000147 return NULL;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000148}
149
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000150static void hash_name(struct fuse *f, struct node *node, fino_t parent,
Miklos Szeredia181e612001-11-06 12:03:23 +0000151 const char *name)
Miklos Szeredi5e183482001-10-31 14:52:35 +0000152{
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000153 size_t hash = name_hash(f, parent, name);
Miklos Szeredia181e612001-11-06 12:03:23 +0000154 node->parent = parent;
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000155 node->name = strdup(name);
156 node->name_next = f->name_table[hash];
157 f->name_table[hash] = node;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000158}
159
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000160static void unhash_name(struct fuse *f, struct node *node)
Miklos Szeredia181e612001-11-06 12:03:23 +0000161{
162 if(node->name != NULL) {
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000163 size_t hash = name_hash(f, node->parent, node->name);
164 struct node **nodep = &f->name_table[hash];
165
166 for(; *nodep != NULL; nodep = &(*nodep)->name_next)
167 if(*nodep == node) {
168 *nodep = node->name_next;
169 node->name_next = NULL;
170 free(node->name);
171 node->name = NULL;
172 node->parent = 0;
173 return;
174 }
175 fprintf(stderr, "fuse internal error: unable to unhash node: %lu\n",
176 node->ino);
177 abort();
Miklos Szeredia181e612001-11-06 12:03:23 +0000178 }
179}
180
Miklos Szeredi76f65782004-02-19 16:55:40 +0000181static struct node *find_node(struct fuse *f, fino_t parent, char *name,
182 struct fuse_attr *attr, int version)
Miklos Szeredi5e183482001-10-31 14:52:35 +0000183{
184 struct node *node;
Miklos Szeredia181e612001-11-06 12:03:23 +0000185 int mode = attr->mode & S_IFMT;
186 int rdev = 0;
187
188 if(S_ISCHR(mode) || S_ISBLK(mode))
189 rdev = attr->rdev;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000190
Miklos Szeredia181e612001-11-06 12:03:23 +0000191 pthread_mutex_lock(&f->lock);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000192 node = lookup_node(f, parent, name);
193 if(node != NULL) {
Miklos Szeredia181e612001-11-06 12:03:23 +0000194 if(node->mode == mode && node->rdev == rdev)
195 goto out;
196
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000197 unhash_name(f, node);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000198 }
199
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000200 node = (struct node *) calloc(1, sizeof(struct node));
Miklos Szeredia181e612001-11-06 12:03:23 +0000201 node->mode = mode;
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000202 node->rdev = rdev;
Miklos Szeredi76f65782004-02-19 16:55:40 +0000203 node->ino = next_ino(f);
204 node->generation = f->generation;
205 hash_ino(f, node);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000206 hash_name(f, node, parent, name);
Miklos Szeredia181e612001-11-06 12:03:23 +0000207
208 out:
209 node->version = version;
210 pthread_mutex_unlock(&f->lock);
Miklos Szeredi76f65782004-02-19 16:55:40 +0000211 return node;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000212}
213
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000214static char *add_name(char *buf, char *s, const char *name)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000215{
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000216 size_t len = strlen(name);
217 s -= len;
218 if(s <= buf) {
219 fprintf(stderr, "fuse: path too long: ...%s\n", s + len);
220 return NULL;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000221 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000222 strncpy(s, name, len);
223 s--;
224 *s = '/';
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000225
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000226 return s;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000227}
228
Miklos Szeredia181e612001-11-06 12:03:23 +0000229static char *get_path_name(struct fuse *f, fino_t ino, const char *name)
Miklos Szeredib483c932001-10-29 14:57:57 +0000230{
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000231 char buf[FUSE_MAX_PATH];
232 char *s = buf + FUSE_MAX_PATH - 1;
233 struct node *node;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000234
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000235 *s = '\0';
Miklos Szeredia181e612001-11-06 12:03:23 +0000236
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000237 if(name != NULL) {
238 s = add_name(buf, s, name);
239 if(s == NULL)
240 return NULL;
241 }
242
243 pthread_mutex_lock(&f->lock);
244 for(node = get_node(f, ino); node->ino != FUSE_ROOT_INO;
245 node = get_node(f, node->parent)) {
246 if(node->name == NULL) {
247 s = NULL;
248 break;
249 }
250
251 s = add_name(buf, s, node->name);
252 if(s == NULL)
253 break;
254 }
255 pthread_mutex_unlock(&f->lock);
256
257 if(s == NULL)
Miklos Szeredi5e183482001-10-31 14:52:35 +0000258 return NULL;
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000259 else if(*s == '\0')
260 return strdup("/");
261 else
262 return strdup(s);
263}
Miklos Szeredia181e612001-11-06 12:03:23 +0000264
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000265static char *get_path(struct fuse *f, fino_t ino)
266{
267 return get_path_name(f, ino, NULL);
Miklos Szeredib483c932001-10-29 14:57:57 +0000268}
269
Miklos Szeredia181e612001-11-06 12:03:23 +0000270static void destroy_node(struct fuse *f, fino_t ino, int version)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000271{
Miklos Szeredia181e612001-11-06 12:03:23 +0000272 struct node *node;
273
274 pthread_mutex_lock(&f->lock);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000275 node = get_node(f, ino);
Miklos Szeredi39f28672001-11-14 14:52:54 +0000276 if(node->version == version && ino != FUSE_ROOT_INO) {
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000277 unhash_name(f, node);
278 unhash_ino(f, node);
Miklos Szeredia181e612001-11-06 12:03:23 +0000279 free_node(node);
280 }
281 pthread_mutex_unlock(&f->lock);
282
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000283}
284
Miklos Szeredi5e183482001-10-31 14:52:35 +0000285static void remove_node(struct fuse *f, fino_t dir, const char *name)
286{
Miklos Szeredia181e612001-11-06 12:03:23 +0000287 struct node *node;
288
289 pthread_mutex_lock(&f->lock);
290 node = lookup_node(f, dir, name);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000291 if(node == NULL) {
292 fprintf(stderr, "fuse internal error: unable to remove node %lu/%s\n",
293 dir, name);
294 abort();
295 }
296 unhash_name(f, node);
Miklos Szeredia181e612001-11-06 12:03:23 +0000297 pthread_mutex_unlock(&f->lock);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000298}
299
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000300static void rename_node(struct fuse *f, fino_t olddir, const char *oldname,
301 fino_t newdir, const char *newname)
302{
Miklos Szeredia181e612001-11-06 12:03:23 +0000303 struct node *node;
304 struct node *newnode;
305
306 pthread_mutex_lock(&f->lock);
307 node = lookup_node(f, olddir, oldname);
308 newnode = lookup_node(f, newdir, newname);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000309 if(node == NULL) {
310 fprintf(stderr, "fuse internal error: unable to rename node %lu/%s\n",
311 olddir, oldname);
312 abort();
313 }
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000314
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000315 if(newnode != NULL)
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000316 unhash_name(f, newnode);
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000317
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000318 unhash_name(f, node);
319 hash_name(f, node, newdir, newname);
Miklos Szeredia181e612001-11-06 12:03:23 +0000320 pthread_mutex_unlock(&f->lock);
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000321}
322
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000323static void convert_stat(struct stat *stbuf, struct fuse_attr *attr)
324{
Miklos Szeredib5958612004-02-20 14:10:49 +0000325 attr->mode = stbuf->st_mode;
326 attr->nlink = stbuf->st_nlink;
327 attr->uid = stbuf->st_uid;
328 attr->gid = stbuf->st_gid;
329 attr->rdev = stbuf->st_rdev;
330 attr->size = stbuf->st_size;
331 attr->blocks = stbuf->st_blocks;
332 attr->atime = stbuf->st_atime;
333 attr->atimensec = stbuf->st_atim.tv_nsec;
334 attr->mtime = stbuf->st_mtime;
335 attr->mtimensec = stbuf->st_mtim.tv_nsec;
336 attr->ctime = stbuf->st_ctime;
337 attr->ctimensec = stbuf->st_ctim.tv_nsec;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000338}
339
Miklos Szeredia181e612001-11-06 12:03:23 +0000340static int fill_dir(struct fuse_dirhandle *dh, char *name, int type)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000341{
342 struct fuse_dirent dirent;
343 size_t reclen;
344 size_t res;
345
Miklos Szeredi43696432001-11-18 19:15:05 +0000346 dirent.ino = (unsigned long) -1;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000347 dirent.namelen = strlen(name);
348 strncpy(dirent.name, name, sizeof(dirent.name));
349 dirent.type = type;
350 reclen = FUSE_DIRENT_SIZE(&dirent);
351 res = fwrite(&dirent, reclen, 1, dh->fp);
352 if(res == 0) {
Miklos Szeredi96249982001-11-21 12:21:19 +0000353 perror("fuse: writing directory file");
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000354 return -EIO;
355 }
356 return 0;
357}
358
Miklos Szeredi40b9a5a2002-12-10 16:09:02 +0000359static int send_reply_raw(struct fuse *f, char *outbuf, size_t outsize)
Miklos Szeredi43696432001-11-18 19:15:05 +0000360{
361 int res;
362
363 if((f->flags & FUSE_DEBUG)) {
364 struct fuse_out_header *out = (struct fuse_out_header *) outbuf;
365 printf(" unique: %i, error: %i (%s), outsize: %i\n", out->unique,
366 out->error, strerror(-out->error), outsize);
367 fflush(stdout);
368 }
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +0000369
Miklos Szeredi4e71c9f2004-02-09 12:05:14 +0000370 /* This needs to be done before the reply, otherwise the scheduler
371 could play tricks with us, and only let the counter be increased
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +0000372 long after the operation is done */
373 inc_avail(f);
374
Miklos Szeredi43696432001-11-18 19:15:05 +0000375 res = write(f->fd, outbuf, outsize);
376 if(res == -1) {
377 /* ENOENT means the operation was interrupted */
Miklos Szeredi4e71c9f2004-02-09 12:05:14 +0000378 if(!f->exited && errno != ENOENT)
Miklos Szeredi96249982001-11-21 12:21:19 +0000379 perror("fuse: writing device");
Miklos Szeredi40b9a5a2002-12-10 16:09:02 +0000380 return -errno;
Miklos Szeredi43696432001-11-18 19:15:05 +0000381 }
Miklos Szeredi40b9a5a2002-12-10 16:09:02 +0000382 return 0;
Miklos Szeredi43696432001-11-18 19:15:05 +0000383}
384
Miklos Szeredi40b9a5a2002-12-10 16:09:02 +0000385static int send_reply(struct fuse *f, struct fuse_in_header *in, int error,
386 void *arg, size_t argsize)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000387{
Miklos Szeredi40b9a5a2002-12-10 16:09:02 +0000388 int res;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000389 char *outbuf;
390 size_t outsize;
391 struct fuse_out_header *out;
392
Miklos Szeredi0f48a262002-12-05 14:23:01 +0000393 if(error <= -512 || error > 0) {
394 fprintf(stderr, "fuse: bad error value: %i\n", error);
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000395 error = -ERANGE;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000396 }
397
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000398 if(error)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000399 argsize = 0;
400
401 outsize = sizeof(struct fuse_out_header) + argsize;
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000402 outbuf = (char *) malloc(outsize);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000403 out = (struct fuse_out_header *) outbuf;
Miklos Szeredi0f48a262002-12-05 14:23:01 +0000404 memset(out, 0, sizeof(struct fuse_out_header));
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000405 out->unique = in->unique;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000406 out->error = error;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000407 if(argsize != 0)
408 memcpy(outbuf + sizeof(struct fuse_out_header), arg, argsize);
409
Miklos Szeredi40b9a5a2002-12-10 16:09:02 +0000410 res = send_reply_raw(f, outbuf, outsize);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000411 free(outbuf);
Miklos Szeredi40b9a5a2002-12-10 16:09:02 +0000412
413 return res;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000414}
415
Miklos Szeredi76f65782004-02-19 16:55:40 +0000416static int lookup_path(struct fuse *f, fino_t ino, int version, char *name,
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000417 const char *path, struct fuse_entry_out *arg)
Miklos Szeredi76f65782004-02-19 16:55:40 +0000418{
419 int res;
420 struct stat buf;
421
422 res = f->op.getattr(path, &buf);
423 if(res == 0) {
424 struct node *node;
425
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000426 memset(arg, 0, sizeof(struct fuse_entry_out));
Miklos Szeredi76f65782004-02-19 16:55:40 +0000427 convert_stat(&buf, &arg->attr);
428 node = find_node(f, ino, name, &arg->attr, version);
429 arg->ino = node->ino;
430 arg->generation = node->generation;
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000431 arg->entry_valid = ENTRY_REVALIDATE_TIME;
432 arg->entry_valid_nsec = 0;
433 arg->attr_valid = ATTR_REVALIDATE_TIME;
434 arg->attr_valid_nsec = 0;
Miklos Szeredi76f65782004-02-19 16:55:40 +0000435 if(f->flags & FUSE_DEBUG) {
436 printf(" INO: %li\n", arg->ino);
437 fflush(stdout);
438 }
439 }
440 return res;
441}
442
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000443static void do_lookup(struct fuse *f, struct fuse_in_header *in, char *name)
444{
445 int res;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000446 char *path;
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000447 struct fuse_entry_out arg;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000448
Miklos Szeredi5e183482001-10-31 14:52:35 +0000449 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000450 path = get_path_name(f, in->ino, name);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000451 if(path != NULL) {
Miklos Szeredi6ebe2342002-01-06 21:44:16 +0000452 if(f->flags & FUSE_DEBUG) {
453 printf("LOOKUP %s\n", path);
454 fflush(stdout);
455 }
Miklos Szeredi5e183482001-10-31 14:52:35 +0000456 res = -ENOSYS;
457 if(f->op.getattr)
Miklos Szeredi76f65782004-02-19 16:55:40 +0000458 res = lookup_path(f, in->ino, in->unique, name, path, &arg);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000459 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000460 }
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000461 send_reply(f, in, res, &arg, sizeof(arg));
462}
463
Miklos Szeredia181e612001-11-06 12:03:23 +0000464static void do_forget(struct fuse *f, struct fuse_in_header *in,
465 struct fuse_forget_in *arg)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000466{
Miklos Szeredi43696432001-11-18 19:15:05 +0000467 if(f->flags & FUSE_DEBUG) {
468 printf("FORGET %li/%i\n", in->ino, arg->version);
469 fflush(stdout);
470 }
Miklos Szeredia181e612001-11-06 12:03:23 +0000471 destroy_node(f, in->ino, arg->version);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000472}
473
474static void do_getattr(struct fuse *f, struct fuse_in_header *in)
475{
476 int res;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000477 char *path;
478 struct stat buf;
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000479 struct fuse_attr_out arg;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000480
Miklos Szeredi5e183482001-10-31 14:52:35 +0000481 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000482 path = get_path(f, in->ino);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000483 if(path != NULL) {
484 res = -ENOSYS;
485 if(f->op.getattr)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000486 res = f->op.getattr(path, &buf);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000487 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000488 }
Miklos Szeredi0f48a262002-12-05 14:23:01 +0000489
490 if(res == 0) {
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000491 memset(&arg, 0, sizeof(struct fuse_attr_out));
492 arg.attr_valid = ATTR_REVALIDATE_TIME;
493 arg.attr_valid_nsec = 0;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000494 convert_stat(&buf, &arg.attr);
Miklos Szeredi0f48a262002-12-05 14:23:01 +0000495 }
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000496
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000497 send_reply(f, in, res, &arg, sizeof(arg));
498}
499
Miklos Szeredi680a69a2001-11-16 13:31:14 +0000500static int do_chmod(struct fuse *f, const char *path, struct fuse_attr *attr)
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000501{
502 int res;
503
504 res = -ENOSYS;
505 if(f->op.chmod)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000506 res = f->op.chmod(path, attr->mode);
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000507
508 return res;
509}
510
Miklos Szeredi680a69a2001-11-16 13:31:14 +0000511static int do_chown(struct fuse *f, const char *path, struct fuse_attr *attr,
Miklos Szeredi2e50d432001-12-20 12:17:25 +0000512 int valid)
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000513{
514 int res;
515 uid_t uid = (valid & FATTR_UID) ? attr->uid : (uid_t) -1;
516 gid_t gid = (valid & FATTR_GID) ? attr->gid : (gid_t) -1;
517
518 res = -ENOSYS;
519 if(f->op.chown)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000520 res = f->op.chown(path, uid, gid);
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000521
522 return res;
523}
524
Miklos Szeredi680a69a2001-11-16 13:31:14 +0000525static int do_truncate(struct fuse *f, const char *path,
526 struct fuse_attr *attr)
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000527{
528 int res;
529
530 res = -ENOSYS;
531 if(f->op.truncate)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000532 res = f->op.truncate(path, attr->size);
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000533
534 return res;
535}
536
Miklos Szeredi680a69a2001-11-16 13:31:14 +0000537static int do_utime(struct fuse *f, const char *path, struct fuse_attr *attr)
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000538{
539 int res;
540 struct utimbuf buf;
541 buf.actime = attr->atime;
542 buf.modtime = attr->mtime;
543 res = -ENOSYS;
544 if(f->op.utime)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000545 res = f->op.utime(path, &buf);
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000546
547 return res;
548}
549
Miklos Szeredi5e183482001-10-31 14:52:35 +0000550static void do_setattr(struct fuse *f, struct fuse_in_header *in,
551 struct fuse_setattr_in *arg)
552{
553 int res;
554 char *path;
555 int valid = arg->valid;
556 struct fuse_attr *attr = &arg->attr;
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000557 struct fuse_attr_out outarg;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000558
559 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000560 path = get_path(f, in->ino);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000561 if(path != NULL) {
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000562 res = -ENOSYS;
563 if(f->op.getattr) {
564 res = 0;
565 if(!res && (valid & FATTR_MODE))
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000566 res = do_chmod(f, path, attr);
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000567 if(!res && (valid & (FATTR_UID | FATTR_GID)))
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000568 res = do_chown(f, path, attr, valid);
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000569 if(!res && (valid & FATTR_SIZE))
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000570 res = do_truncate(f, path, attr);
Miklos Szeredib5958612004-02-20 14:10:49 +0000571 if(!res && (valid & (FATTR_ATIME | FATTR_MTIME)) ==
572 (FATTR_ATIME | FATTR_MTIME))
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000573 res = do_utime(f, path, attr);
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000574 if(!res) {
575 struct stat buf;
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000576 res = f->op.getattr(path, &buf);
Miklos Szeredi0f48a262002-12-05 14:23:01 +0000577 if(!res) {
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000578 memset(&outarg, 0, sizeof(struct fuse_attr_out));
579 outarg.attr_valid = ATTR_REVALIDATE_TIME;
580 outarg.attr_valid_nsec = 0;
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000581 convert_stat(&buf, &outarg.attr);
Miklos Szeredi0f48a262002-12-05 14:23:01 +0000582 }
Miklos Szeredia181e612001-11-06 12:03:23 +0000583 }
Miklos Szeredi5e183482001-10-31 14:52:35 +0000584 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000585 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000586 }
Miklos Szeredia181e612001-11-06 12:03:23 +0000587 send_reply(f, in, res, &outarg, sizeof(outarg));
Miklos Szeredi5e183482001-10-31 14:52:35 +0000588}
589
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000590static void do_readlink(struct fuse *f, struct fuse_in_header *in)
591{
592 int res;
593 char link[PATH_MAX + 1];
Miklos Szeredib483c932001-10-29 14:57:57 +0000594 char *path;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000595
Miklos Szeredi5e183482001-10-31 14:52:35 +0000596 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000597 path = get_path(f, in->ino);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000598 if(path != NULL) {
599 res = -ENOSYS;
600 if(f->op.readlink)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000601 res = f->op.readlink(path, link, sizeof(link));
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000602 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000603 }
Miklos Szeredi2df1c042001-11-06 15:07:17 +0000604 link[PATH_MAX] = '\0';
Miklos Szeredi4b2bef42002-01-09 12:23:27 +0000605 send_reply(f, in, res, link, res == 0 ? strlen(link) : 0);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000606}
607
608static void do_getdir(struct fuse *f, struct fuse_in_header *in)
609{
610 int res;
611 struct fuse_getdir_out arg;
Miklos Szeredia181e612001-11-06 12:03:23 +0000612 struct fuse_dirhandle dh;
Miklos Szeredib483c932001-10-29 14:57:57 +0000613 char *path;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000614
Miklos Szeredib483c932001-10-29 14:57:57 +0000615 dh.fuse = f;
616 dh.fp = tmpfile();
617 dh.dir = in->ino;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000618 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000619 path = get_path(f, in->ino);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000620 if(path != NULL) {
621 res = -ENOSYS;
622 if(f->op.getdir)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000623 res = f->op.getdir(path, &dh, (fuse_dirfil_t) fill_dir);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000624 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000625 }
Miklos Szeredib483c932001-10-29 14:57:57 +0000626 fflush(dh.fp);
Miklos Szeredi0f48a262002-12-05 14:23:01 +0000627
628 memset(&arg, 0, sizeof(struct fuse_getdir_out));
Miklos Szeredib483c932001-10-29 14:57:57 +0000629 arg.fd = fileno(dh.fp);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000630 send_reply(f, in, res, &arg, sizeof(arg));
Miklos Szeredib483c932001-10-29 14:57:57 +0000631 fclose(dh.fp);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000632}
633
Miklos Szeredib483c932001-10-29 14:57:57 +0000634static void do_mknod(struct fuse *f, struct fuse_in_header *in,
635 struct fuse_mknod_in *inarg)
636{
637 int res;
638 char *path;
Miklos Szeredi76f65782004-02-19 16:55:40 +0000639 char *name = PARAM(inarg);
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000640 struct fuse_entry_out outarg;
Miklos Szeredib483c932001-10-29 14:57:57 +0000641
Miklos Szeredi5e183482001-10-31 14:52:35 +0000642 res = -ENOENT;
Miklos Szeredi76f65782004-02-19 16:55:40 +0000643 path = get_path_name(f, in->ino, name);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000644 if(path != NULL) {
Miklos Szeredi76f65782004-02-19 16:55:40 +0000645 if(f->flags & FUSE_DEBUG) {
646 printf("MKNOD %s\n", path);
647 fflush(stdout);
648 }
Miklos Szeredi5e183482001-10-31 14:52:35 +0000649 res = -ENOSYS;
650 if(f->op.mknod && f->op.getattr) {
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000651 res = f->op.mknod(path, inarg->mode, inarg->rdev);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000652 if(res == 0)
Miklos Szeredi76f65782004-02-19 16:55:40 +0000653 res = lookup_path(f, in->ino, in->unique, name, path, &outarg);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000654 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000655 free(path);
Miklos Szeredib483c932001-10-29 14:57:57 +0000656 }
Miklos Szeredib483c932001-10-29 14:57:57 +0000657 send_reply(f, in, res, &outarg, sizeof(outarg));
658}
659
660static void do_mkdir(struct fuse *f, struct fuse_in_header *in,
661 struct fuse_mkdir_in *inarg)
662{
663 int res;
664 char *path;
Miklos Szeredi76f65782004-02-19 16:55:40 +0000665 char *name = PARAM(inarg);
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000666 struct fuse_entry_out outarg;
Miklos Szeredib483c932001-10-29 14:57:57 +0000667
Miklos Szeredi5e183482001-10-31 14:52:35 +0000668 res = -ENOENT;
Miklos Szeredi76f65782004-02-19 16:55:40 +0000669 path = get_path_name(f, in->ino, name);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000670 if(path != NULL) {
Miklos Szeredi76f65782004-02-19 16:55:40 +0000671 if(f->flags & FUSE_DEBUG) {
672 printf("MKDIR %s\n", path);
673 fflush(stdout);
674 }
Miklos Szeredi5e183482001-10-31 14:52:35 +0000675 res = -ENOSYS;
Miklos Szeredi76f65782004-02-19 16:55:40 +0000676 if(f->op.mkdir && f->op.getattr) {
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000677 res = f->op.mkdir(path, inarg->mode);
Miklos Szeredi76f65782004-02-19 16:55:40 +0000678 if(res == 0)
679 res = lookup_path(f, in->ino, in->unique, name, path, &outarg);
680 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000681 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000682 }
Miklos Szeredi76f65782004-02-19 16:55:40 +0000683 send_reply(f, in, res, &outarg, sizeof(outarg));
Miklos Szeredib483c932001-10-29 14:57:57 +0000684}
685
Miklos Szeredib5958612004-02-20 14:10:49 +0000686static void do_unlink(struct fuse *f, struct fuse_in_header *in, char *name)
Miklos Szeredib483c932001-10-29 14:57:57 +0000687{
688 int res;
689 char *path;
690
Miklos Szeredi5e183482001-10-31 14:52:35 +0000691 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000692 path = get_path_name(f, in->ino, name);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000693 if(path != NULL) {
694 res = -ENOSYS;
Miklos Szeredib5958612004-02-20 14:10:49 +0000695 if(f->op.unlink) {
696 res = f->op.unlink(path);
697 if(res == 0)
698 remove_node(f, in->ino, name);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000699 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000700 free(path);
Miklos Szeredib483c932001-10-29 14:57:57 +0000701 }
Miklos Szeredib5958612004-02-20 14:10:49 +0000702 send_reply(f, in, res, NULL, 0);
703}
704
705static void do_rmdir(struct fuse *f, struct fuse_in_header *in, char *name)
706{
707 int res;
708 char *path;
709
710 res = -ENOENT;
711 path = get_path_name(f, in->ino, name);
712 if(path != NULL) {
713 res = -ENOSYS;
714 if(f->op.rmdir) {
715 res = f->op.rmdir(path);
716 if(res == 0)
717 remove_node(f, in->ino, name);
718 }
719 free(path);
720 }
Miklos Szeredib483c932001-10-29 14:57:57 +0000721 send_reply(f, in, res, NULL, 0);
722}
723
724static void do_symlink(struct fuse *f, struct fuse_in_header *in, char *name,
725 char *link)
726{
727 int res;
728 char *path;
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000729 struct fuse_entry_out outarg;
Miklos Szeredib483c932001-10-29 14:57:57 +0000730
Miklos Szeredi5e183482001-10-31 14:52:35 +0000731 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000732 path = get_path_name(f, in->ino, name);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000733 if(path != NULL) {
Miklos Szeredi76f65782004-02-19 16:55:40 +0000734 if(f->flags & FUSE_DEBUG) {
735 printf("SYMLINK %s\n", path);
736 fflush(stdout);
737 }
Miklos Szeredi5e183482001-10-31 14:52:35 +0000738 res = -ENOSYS;
Miklos Szeredi76f65782004-02-19 16:55:40 +0000739 if(f->op.symlink && f->op.getattr) {
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000740 res = f->op.symlink(link, path);
Miklos Szeredi76f65782004-02-19 16:55:40 +0000741 if(res == 0)
742 res = lookup_path(f, in->ino, in->unique, name, path, &outarg);
743 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000744 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000745 }
Miklos Szeredi76f65782004-02-19 16:55:40 +0000746 send_reply(f, in, res, &outarg, sizeof(outarg));
Miklos Szeredib483c932001-10-29 14:57:57 +0000747}
748
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000749static void do_rename(struct fuse *f, struct fuse_in_header *in,
750 struct fuse_rename_in *inarg)
751{
752 int res;
753 fino_t olddir = in->ino;
754 fino_t newdir = inarg->newdir;
Miklos Szeredi6bf8b682002-10-28 08:49:39 +0000755 char *oldname = PARAM(inarg);
756 char *newname = oldname + strlen(oldname) + 1;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000757 char *oldpath;
758 char *newpath;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000759
Miklos Szeredi5e183482001-10-31 14:52:35 +0000760 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000761 oldpath = get_path_name(f, olddir, oldname);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000762 if(oldpath != NULL) {
Miklos Szeredia181e612001-11-06 12:03:23 +0000763 newpath = get_path_name(f, newdir, newname);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000764 if(newpath != NULL) {
765 res = -ENOSYS;
766 if(f->op.rename)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000767 res = f->op.rename(oldpath, newpath);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000768 if(res == 0)
769 rename_node(f, olddir, oldname, newdir, newname);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000770 free(newpath);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000771 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000772 free(oldpath);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000773 }
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000774 send_reply(f, in, res, NULL, 0);
775}
776
777static void do_link(struct fuse *f, struct fuse_in_header *in,
Miklos Szeredi5e183482001-10-31 14:52:35 +0000778 struct fuse_link_in *arg)
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000779{
780 int res;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000781 char *oldpath;
782 char *newpath;
Miklos Szeredi76f65782004-02-19 16:55:40 +0000783 char *name = PARAM(arg);
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000784 struct fuse_entry_out outarg;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000785
Miklos Szeredi5e183482001-10-31 14:52:35 +0000786 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000787 oldpath = get_path(f, in->ino);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000788 if(oldpath != NULL) {
Miklos Szeredi76f65782004-02-19 16:55:40 +0000789 newpath = get_path_name(f, arg->newdir, name);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000790 if(newpath != NULL) {
Miklos Szeredi76f65782004-02-19 16:55:40 +0000791 if(f->flags & FUSE_DEBUG) {
792 printf("LINK %s\n", newpath);
793 fflush(stdout);
794 }
Miklos Szeredi5e183482001-10-31 14:52:35 +0000795 res = -ENOSYS;
Miklos Szeredi76f65782004-02-19 16:55:40 +0000796 if(f->op.link && f->op.getattr) {
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000797 res = f->op.link(oldpath, newpath);
Miklos Szeredi76f65782004-02-19 16:55:40 +0000798 if(res == 0)
799 res = lookup_path(f, arg->newdir, in->unique, name,
800 newpath, &outarg);
801 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000802 free(newpath);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000803 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000804 free(oldpath);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000805 }
Miklos Szeredi76f65782004-02-19 16:55:40 +0000806 send_reply(f, in, res, &outarg, sizeof(outarg));
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000807}
808
Miklos Szeredi5e183482001-10-31 14:52:35 +0000809static void do_open(struct fuse *f, struct fuse_in_header *in,
810 struct fuse_open_in *arg)
811{
812 int res;
Miklos Szeredi40b9a5a2002-12-10 16:09:02 +0000813 int res2;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000814 char *path;
815
816 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000817 path = get_path(f, in->ino);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000818 if(path != NULL) {
819 res = -ENOSYS;
820 if(f->op.open)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000821 res = f->op.open(path, arg->flags);
Miklos Szeredi40b9a5a2002-12-10 16:09:02 +0000822 }
823 res2 = send_reply(f, in, res, NULL, 0);
824 if(path != NULL) {
825 /* The open syscall was interrupted, so it must be cancelled */
826 if(res == 0 && res2 == -ENOENT && f->op.release)
Miklos Szeredi9478e862002-12-11 09:50:26 +0000827 f->op.release(path, arg->flags);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000828 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000829 }
Miklos Szeredi5e183482001-10-31 14:52:35 +0000830}
831
Miklos Szeredi9478e862002-12-11 09:50:26 +0000832static void do_release(struct fuse *f, struct fuse_in_header *in,
833 struct fuse_open_in *arg)
Miklos Szeredic8ba2372002-12-10 12:26:00 +0000834{
Miklos Szeredic8ba2372002-12-10 12:26:00 +0000835 char *path;
836
Miklos Szeredic8ba2372002-12-10 12:26:00 +0000837 path = get_path(f, in->ino);
838 if(path != NULL) {
Miklos Szeredic8ba2372002-12-10 12:26:00 +0000839 if(f->op.release)
Miklos Szeredi9478e862002-12-11 09:50:26 +0000840 f->op.release(path, arg->flags);
Miklos Szeredic8ba2372002-12-10 12:26:00 +0000841 free(path);
842 }
Miklos Szeredic8ba2372002-12-10 12:26:00 +0000843}
844
Miklos Szeredi5e183482001-10-31 14:52:35 +0000845static void do_read(struct fuse *f, struct fuse_in_header *in,
846 struct fuse_read_in *arg)
847{
848 int res;
849 char *path;
Miklos Szeredi43696432001-11-18 19:15:05 +0000850 char *outbuf = (char *) malloc(sizeof(struct fuse_out_header) + arg->size);
851 struct fuse_out_header *out = (struct fuse_out_header *) outbuf;
852 char *buf = outbuf + sizeof(struct fuse_out_header);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000853 size_t size;
Miklos Szeredi43696432001-11-18 19:15:05 +0000854 size_t outsize;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000855
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000856 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000857 path = get_path(f, in->ino);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000858 if(path != NULL) {
Miklos Szeredi6ebe2342002-01-06 21:44:16 +0000859 if(f->flags & FUSE_DEBUG) {
860 printf("READ %u bytes from %llu\n", arg->size, arg->offset);
861 fflush(stdout);
862 }
863
Miklos Szeredi5e183482001-10-31 14:52:35 +0000864 res = -ENOSYS;
Miklos Szeredia181e612001-11-06 12:03:23 +0000865 if(f->op.read)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000866 res = f->op.read(path, buf, arg->size, arg->offset);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000867 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000868 }
869
870 size = 0;
871 if(res > 0) {
872 size = res;
873 res = 0;
Miklos Szeredi6ebe2342002-01-06 21:44:16 +0000874 if(f->flags & FUSE_DEBUG) {
875 printf(" READ %u bytes\n", size);
876 fflush(stdout);
877 }
Miklos Szeredi5e183482001-10-31 14:52:35 +0000878 }
Miklos Szeredi0f48a262002-12-05 14:23:01 +0000879 memset(out, 0, sizeof(struct fuse_out_header));
Miklos Szeredi43696432001-11-18 19:15:05 +0000880 out->unique = in->unique;
881 out->error = res;
882 outsize = sizeof(struct fuse_out_header) + size;
883
884 send_reply_raw(f, outbuf, outsize);
885 free(outbuf);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000886}
Miklos Szeredib483c932001-10-29 14:57:57 +0000887
Miklos Szeredia181e612001-11-06 12:03:23 +0000888static void do_write(struct fuse *f, struct fuse_in_header *in,
889 struct fuse_write_in *arg)
890{
891 int res;
892 char *path;
Miklos Szeredia181e612001-11-06 12:03:23 +0000893
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000894 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000895 path = get_path(f, in->ino);
896 if(path != NULL) {
Miklos Szeredi6ebe2342002-01-06 21:44:16 +0000897 if(f->flags & FUSE_DEBUG) {
898 printf("WRITE %u bytes to %llu\n", arg->size, arg->offset);
899 fflush(stdout);
900 }
901
Miklos Szeredia181e612001-11-06 12:03:23 +0000902 res = -ENOSYS;
903 if(f->op.write)
Miklos Szeredi6bf8b682002-10-28 08:49:39 +0000904 res = f->op.write(path, PARAM(arg), arg->size, arg->offset);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000905 free(path);
Miklos Szeredia181e612001-11-06 12:03:23 +0000906 }
907
908 if(res > 0) {
909 if((size_t) res != arg->size) {
910 fprintf(stderr, "short write: %u (should be %u)\n", res,
911 arg->size);
Miklos Szeredi0e535082003-10-13 10:08:06 +0000912 res = -EINVAL;
Miklos Szeredia181e612001-11-06 12:03:23 +0000913 }
914 else
915 res = 0;
916 }
917
918 send_reply(f, in, res, NULL, 0);
919}
920
Miklos Szeredi77f39942004-03-25 11:17:52 +0000921static int default_statfs(struct statfs *buf)
922{
923 buf->f_namelen = 255;
924 buf->f_bsize = 512;
925 return 0;
926}
927
Miklos Szeredi18e75e42004-02-19 14:23:27 +0000928static void convert_statfs(struct statfs *statfs, struct fuse_kstatfs *kstatfs)
929{
930 kstatfs->bsize = statfs->f_bsize;
931 kstatfs->blocks = statfs->f_blocks;
932 kstatfs->bfree = statfs->f_bfree;
933 kstatfs->bavail = statfs->f_bavail;
934 kstatfs->files = statfs->f_files;
935 kstatfs->ffree = statfs->f_ffree;
936 kstatfs->namelen = statfs->f_namelen;
937}
938
Mark Glinesd84b39a2002-01-07 16:32:02 +0000939static void do_statfs(struct fuse *f, struct fuse_in_header *in)
940{
941 int res;
Mark Glinesd84b39a2002-01-07 16:32:02 +0000942 struct fuse_statfs_out arg;
Miklos Szeredi18e75e42004-02-19 14:23:27 +0000943 struct statfs buf;
Mark Glinesd84b39a2002-01-07 16:32:02 +0000944
Miklos Szeredi77f39942004-03-25 11:17:52 +0000945 memset(&buf, 0, sizeof(struct statfs));
946 if(f->op.statfs)
Miklos Szeredi18e75e42004-02-19 14:23:27 +0000947 res = f->op.statfs("/", &buf);
Miklos Szeredi77f39942004-03-25 11:17:52 +0000948 else
949 res = default_statfs(&buf);
950
951 if(res == 0)
952 convert_statfs(&buf, &arg.st);
Miklos Szeredi4b2bef42002-01-09 12:23:27 +0000953
Mark Glinesd84b39a2002-01-07 16:32:02 +0000954 send_reply(f, in, res, &arg, sizeof(arg));
955}
956
Miklos Szeredi5e43f2c2003-12-12 14:06:41 +0000957static void do_fsync(struct fuse *f, struct fuse_in_header *in,
958 struct fuse_fsync_in *inarg)
959{
960 int res;
961 char *path;
962
963 res = -ENOENT;
964 path = get_path(f, in->ino);
965 if(path != NULL) {
966 /* fsync is not mandatory, so don't return ENOSYS */
967 res = 0;
968 if(f->op.fsync)
969 res = f->op.fsync(path, inarg->datasync);
970 free(path);
971 }
972 send_reply(f, in, res, NULL, 0);
973}
974
Miklos Szeredi3ed84232004-03-30 15:17:26 +0000975static void do_setxattr(struct fuse *f, struct fuse_in_header *in,
976 struct fuse_setxattr_in *arg)
977{
978 int res;
979 char *path;
980 char *name = PARAM(arg);
981 unsigned char *value = name + strlen(name) + 1;
982
983 res = -ENOENT;
984 path = get_path(f, in->ino);
985 if (path != NULL) {
986 res = -EOPNOTSUPP; /* or is it ENOTSUPP ??? */
987 if (f->op.setxattr)
988 res = f->op.setxattr(path, name, value, arg->size, arg->flags);
989 free(path);
990 }
991 send_reply(f, in, res, NULL, 0);
992}
993
994static void do_getxattr(struct fuse *f, struct fuse_in_header *in,
995 struct fuse_getlistxattr_in *arg)
996{
997 int res;
998 char *path;
999 char *name = PARAM(arg);
1000 char *outbuf = (char *) malloc(sizeof(struct fuse_out_header) + arg->size);
1001 struct fuse_out_header *out = (struct fuse_out_header *) outbuf;
1002 char *value = outbuf + sizeof(struct fuse_out_header);
1003 size_t size;
1004 size_t outsize;
1005
1006 res = -ENOENT;
1007 path = get_path(f, in->ino);
1008 if (path != NULL) {
1009 res = -EOPNOTSUPP; /* or is it ENOTSUPP ??? */
1010 if (f->op.getxattr)
1011 res = f->op.getxattr(path, name, value, arg->size);
1012 free(path);
1013 }
1014 size = 0;
1015 if(res > 0) {
1016 size = res;
1017 res = 0;
1018 }
1019 memset(out, 0, sizeof(struct fuse_out_header));
1020 out->unique = in->unique;
1021 out->error = res;
1022 outsize = sizeof(struct fuse_out_header) + size;
1023
1024 send_reply_raw(f, outbuf, outsize);
1025 free(outbuf);
1026}
1027
1028static void do_listxattr(struct fuse *f, struct fuse_in_header *in,
1029 struct fuse_getlistxattr_in *arg)
1030{
1031 int res;
1032 char *path;
1033 char *outbuf = (char *) malloc(sizeof(struct fuse_out_header) + arg->size);
1034 struct fuse_out_header *out = (struct fuse_out_header *) outbuf;
1035 char *value = outbuf + sizeof(struct fuse_out_header);
1036 size_t size;
1037 size_t outsize;
1038
1039 res = -ENOENT;
1040 path = get_path(f, in->ino);
1041 if (path != NULL) {
1042 res = -EOPNOTSUPP; /* or is it ENOTSUPP ??? */
1043 if (f->op.listxattr)
1044 res = f->op.listxattr(path, value, arg->size);
1045 free(path);
1046 }
1047 size = 0;
1048 if(res > 0) {
1049 size = res;
1050 res = 0;
1051 }
1052 memset(out, 0, sizeof(struct fuse_out_header));
1053 out->unique = in->unique;
1054 out->error = res;
1055 outsize = sizeof(struct fuse_out_header) + size;
1056
1057 send_reply_raw(f, outbuf, outsize);
1058 free(outbuf);
1059}
1060
1061static void do_removexattr(struct fuse *f, struct fuse_in_header *in,
1062 char *name)
1063{
1064 int res;
1065 char *path;
1066
1067 res = -ENOENT;
1068 path = get_path(f, in->ino);
1069 if (path != NULL) {
1070 res = -EOPNOTSUPP; /* or is it ENOTSUPP ??? */
1071 if (f->op.removexattr)
1072 res = f->op.removexattr(path, name);
1073 free(path);
1074 }
1075 send_reply(f, in, res, NULL, 0);
1076}
1077
1078
Miklos Szeredi43696432001-11-18 19:15:05 +00001079static void free_cmd(struct fuse_cmd *cmd)
1080{
1081 free(cmd->buf);
1082 free(cmd);
1083}
1084
Miklos Szeredifff56ab2001-11-16 10:12:59 +00001085void __fuse_process_cmd(struct fuse *f, struct fuse_cmd *cmd)
Miklos Szeredia181e612001-11-06 12:03:23 +00001086{
Miklos Szeredia181e612001-11-06 12:03:23 +00001087 struct fuse_in_header *in = (struct fuse_in_header *) cmd->buf;
1088 void *inarg = cmd->buf + sizeof(struct fuse_in_header);
1089 size_t argsize;
Miklos Szeredife25def2001-12-20 15:38:05 +00001090 struct fuse_context *ctx = fuse_get_context(f);
Miklos Szeredia181e612001-11-06 12:03:23 +00001091
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +00001092 dec_avail(f);
Miklos Szeredi33232032001-11-19 17:55:51 +00001093
Miklos Szeredic0938ea2001-11-07 12:35:06 +00001094 if((f->flags & FUSE_DEBUG)) {
Miklos Szeredic8ba2372002-12-10 12:26:00 +00001095 printf("unique: %i, opcode: %s (%i), ino: %li, insize: %i\n",
1096 in->unique, opname(in->opcode), in->opcode, in->ino,
1097 cmd->buflen);
Miklos Szeredic0938ea2001-11-07 12:35:06 +00001098 fflush(stdout);
1099 }
Miklos Szeredife25def2001-12-20 15:38:05 +00001100
1101 ctx->uid = in->uid;
1102 ctx->gid = in->gid;
Miklos Szeredia181e612001-11-06 12:03:23 +00001103
1104 argsize = cmd->buflen - sizeof(struct fuse_in_header);
1105
1106 switch(in->opcode) {
1107 case FUSE_LOOKUP:
1108 do_lookup(f, in, (char *) inarg);
1109 break;
1110
Miklos Szeredia181e612001-11-06 12:03:23 +00001111 case FUSE_GETATTR:
1112 do_getattr(f, in);
1113 break;
1114
1115 case FUSE_SETATTR:
1116 do_setattr(f, in, (struct fuse_setattr_in *) inarg);
1117 break;
1118
1119 case FUSE_READLINK:
1120 do_readlink(f, in);
1121 break;
1122
1123 case FUSE_GETDIR:
1124 do_getdir(f, in);
1125 break;
1126
1127 case FUSE_MKNOD:
1128 do_mknod(f, in, (struct fuse_mknod_in *) inarg);
1129 break;
1130
1131 case FUSE_MKDIR:
1132 do_mkdir(f, in, (struct fuse_mkdir_in *) inarg);
1133 break;
1134
1135 case FUSE_UNLINK:
Miklos Szeredib5958612004-02-20 14:10:49 +00001136 do_unlink(f, in, (char *) inarg);
1137 break;
1138
Miklos Szeredia181e612001-11-06 12:03:23 +00001139 case FUSE_RMDIR:
Miklos Szeredib5958612004-02-20 14:10:49 +00001140 do_rmdir(f, in, (char *) inarg);
Miklos Szeredia181e612001-11-06 12:03:23 +00001141 break;
1142
1143 case FUSE_SYMLINK:
1144 do_symlink(f, in, (char *) inarg,
1145 ((char *) inarg) + strlen((char *) inarg) + 1);
1146 break;
1147
1148 case FUSE_RENAME:
1149 do_rename(f, in, (struct fuse_rename_in *) inarg);
1150 break;
1151
1152 case FUSE_LINK:
1153 do_link(f, in, (struct fuse_link_in *) inarg);
1154 break;
1155
1156 case FUSE_OPEN:
1157 do_open(f, in, (struct fuse_open_in *) inarg);
1158 break;
1159
Miklos Szeredi9478e862002-12-11 09:50:26 +00001160 case FUSE_RELEASE:
1161 do_release(f, in, (struct fuse_open_in *) inarg);
1162 break;
1163
Miklos Szeredia181e612001-11-06 12:03:23 +00001164 case FUSE_READ:
1165 do_read(f, in, (struct fuse_read_in *) inarg);
1166 break;
1167
1168 case FUSE_WRITE:
1169 do_write(f, in, (struct fuse_write_in *) inarg);
1170 break;
1171
Mark Glinesd84b39a2002-01-07 16:32:02 +00001172 case FUSE_STATFS:
1173 do_statfs(f, in);
1174 break;
1175
Miklos Szeredi5e43f2c2003-12-12 14:06:41 +00001176 case FUSE_FSYNC:
1177 do_fsync(f, in, (struct fuse_fsync_in *) inarg);
1178 break;
1179
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001180 case FUSE_SETXATTR:
1181 do_setxattr(f, in, (struct fuse_setxattr_in *) inarg);
1182 break;
1183
1184 case FUSE_GETXATTR:
1185 do_getxattr(f, in, (struct fuse_getlistxattr_in *) inarg);
1186 break;
1187
1188 case FUSE_LISTXATTR:
1189 do_listxattr(f, in, (struct fuse_getlistxattr_in *) inarg);
1190 break;
1191
1192 case FUSE_REMOVEXATTR:
1193 do_removexattr(f, in, (char *) inarg);
1194 break;
1195
Miklos Szeredia181e612001-11-06 12:03:23 +00001196 default:
Miklos Szeredi43696432001-11-18 19:15:05 +00001197 send_reply(f, in, -ENOSYS, NULL, 0);
Miklos Szeredia181e612001-11-06 12:03:23 +00001198 }
Miklos Szeredi43696432001-11-18 19:15:05 +00001199
1200 free_cmd(cmd);
Miklos Szeredia181e612001-11-06 12:03:23 +00001201}
1202
Miklos Szeredifff56ab2001-11-16 10:12:59 +00001203struct fuse_cmd *__fuse_read_cmd(struct fuse *f)
Miklos Szeredi2df1c042001-11-06 15:07:17 +00001204{
Miklos Szeredifff56ab2001-11-16 10:12:59 +00001205 ssize_t res;
Miklos Szeredifff56ab2001-11-16 10:12:59 +00001206 struct fuse_cmd *cmd;
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +00001207 struct fuse_in_header *in;
1208 void *inarg;
Miklos Szeredifff56ab2001-11-16 10:12:59 +00001209
Miklos Szeredi43696432001-11-18 19:15:05 +00001210 cmd = (struct fuse_cmd *) malloc(sizeof(struct fuse_cmd));
1211 cmd->buf = (char *) malloc(FUSE_MAX_IN);
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +00001212 in = (struct fuse_in_header *) cmd->buf;
1213 inarg = cmd->buf + sizeof(struct fuse_in_header);
Miklos Szeredi43696432001-11-18 19:15:05 +00001214
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +00001215 do {
1216 res = read(f->fd, cmd->buf, FUSE_MAX_IN);
1217 if(res == -1) {
Miklos Szeredi0f48a262002-12-05 14:23:01 +00001218 free_cmd(cmd);
Miklos Szeredi307242f2004-01-26 11:28:44 +00001219 if(f->exited || errno == EINTR)
Miklos Szeredi0f48a262002-12-05 14:23:01 +00001220 return NULL;
1221
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +00001222 /* ENODEV means we got unmounted, so we silenty return failure */
1223 if(errno != ENODEV) {
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +00001224 /* BAD... This will happen again */
Miklos Szeredi0f48a262002-12-05 14:23:01 +00001225 perror("fuse: reading device");
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +00001226 }
Miklos Szeredi0f48a262002-12-05 14:23:01 +00001227
1228 fuse_exit(f);
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +00001229 return NULL;
Miklos Szeredi96249982001-11-21 12:21:19 +00001230 }
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +00001231 if((size_t) res < sizeof(struct fuse_in_header)) {
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +00001232 free_cmd(cmd);
Miklos Szeredi0f48a262002-12-05 14:23:01 +00001233 /* Cannot happen */
1234 fprintf(stderr, "short read on fuse device\n");
1235 fuse_exit(f);
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +00001236 return NULL;
1237 }
1238 cmd->buflen = res;
1239
1240 /* Forget is special, it can be done without messing with threads. */
1241 if(in->opcode == FUSE_FORGET)
1242 do_forget(f, in, (struct fuse_forget_in *) inarg);
1243
1244 } while(in->opcode == FUSE_FORGET);
1245
Miklos Szeredifff56ab2001-11-16 10:12:59 +00001246 return cmd;
Miklos Szeredi2df1c042001-11-06 15:07:17 +00001247}
1248
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001249void fuse_loop(struct fuse *f)
1250{
Miklos Szeredic40748a2004-02-20 16:38:45 +00001251 if(f == NULL)
1252 return;
1253
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001254 while(1) {
Miklos Szeredi0f48a262002-12-05 14:23:01 +00001255 struct fuse_cmd *cmd;
1256
1257 if(f->exited)
1258 return;
1259
1260 cmd = __fuse_read_cmd(f);
Miklos Szeredifff56ab2001-11-16 10:12:59 +00001261 if(cmd == NULL)
Miklos Szeredi0f48a262002-12-05 14:23:01 +00001262 continue;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001263
Miklos Szeredifff56ab2001-11-16 10:12:59 +00001264 __fuse_process_cmd(f, cmd);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001265 }
1266}
1267
Miklos Szeredi0f48a262002-12-05 14:23:01 +00001268void fuse_exit(struct fuse *f)
1269{
1270 f->exited = 1;
1271}
1272
Miklos Szeredi2e50d432001-12-20 12:17:25 +00001273struct fuse_context *fuse_get_context(struct fuse *f)
1274{
1275 if(f->getcontext)
1276 return f->getcontext(f);
1277 else
1278 return &f->context;
1279}
1280
Miklos Szeredic40748a2004-02-20 16:38:45 +00001281static int check_version(struct fuse *f)
1282{
1283 int res;
1284 FILE *vf = fopen(FUSE_VERSION_FILE, "r");
1285 if(vf == NULL) {
1286 fprintf(stderr, "fuse: kernel interface too old, need >= %i.%i\n",
1287 FUSE_KERNEL_VERSION, FUSE_KERNEL_MINOR_VERSION);
1288 return -1;
1289 }
1290 res = fscanf(vf, "%i.%i", &f->majorver, &f->minorver);
1291 fclose(vf);
1292 if(res != 2) {
1293 fprintf(stderr, "fuse: error reading %s\n", FUSE_VERSION_FILE);
1294 return -1;
1295 }
1296 if(f->majorver != FUSE_KERNEL_VERSION) {
1297 fprintf(stderr, "fuse: bad kernel interface major version: needs %i\n",
1298 FUSE_KERNEL_VERSION);
1299 return -1;
1300 }
1301 if(f->minorver < FUSE_KERNEL_MINOR_VERSION) {
1302 fprintf(stderr, "fuse: kernel interface too old: need >= %i.%i",
1303 FUSE_KERNEL_VERSION, FUSE_KERNEL_MINOR_VERSION);
1304 return -1;
1305 }
1306
1307 return 0;
1308}
1309
Miklos Szeredi2e50d432001-12-20 12:17:25 +00001310struct fuse *fuse_new(int fd, int flags, const struct fuse_operations *op)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001311{
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001312 struct fuse *f;
1313 struct node *root;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001314
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001315 f = (struct fuse *) calloc(1, sizeof(struct fuse));
Miklos Szeredi2df1c042001-11-06 15:07:17 +00001316
Miklos Szeredic40748a2004-02-20 16:38:45 +00001317 if(check_version(f) == -1) {
1318 free(f);
1319 return NULL;
1320 }
1321
Miklos Szeredia181e612001-11-06 12:03:23 +00001322 f->flags = flags;
Miklos Szeredi8cffdb92001-11-09 14:49:18 +00001323 f->fd = fd;
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001324 f->ctr = 0;
Miklos Szeredi76f65782004-02-19 16:55:40 +00001325 f->generation = 0;
Miklos Szeredifff56ab2001-11-16 10:12:59 +00001326 /* FIXME: Dynamic hash table */
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001327 f->name_table_size = 14057;
1328 f->name_table = (struct node **)
1329 calloc(1, sizeof(struct node *) * f->name_table_size);
1330 f->ino_table_size = 14057;
1331 f->ino_table = (struct node **)
1332 calloc(1, sizeof(struct node *) * f->ino_table_size);
Miklos Szeredia181e612001-11-06 12:03:23 +00001333 pthread_mutex_init(&f->lock, NULL);
Miklos Szeredi33232032001-11-19 17:55:51 +00001334 f->numworker = 0;
1335 f->numavail = 0;
Miklos Szeredi2e50d432001-12-20 12:17:25 +00001336 f->op = *op;
1337 f->getcontext = NULL;
1338 f->context.uid = 0;
1339 f->context.gid = 0;
Miklos Szeredi0f48a262002-12-05 14:23:01 +00001340 f->exited = 0;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001341
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001342 root = (struct node *) calloc(1, sizeof(struct node));
Miklos Szeredi8cffdb92001-11-09 14:49:18 +00001343 root->mode = 0;
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001344 root->rdev = 0;
1345 root->name = strdup("/");
1346 root->parent = 0;
Miklos Szeredi76f65782004-02-19 16:55:40 +00001347 root->ino = FUSE_ROOT_INO;
1348 root->generation = 0;
1349 hash_ino(f, root);
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001350
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001351 return f;
1352}
1353
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001354void fuse_destroy(struct fuse *f)
1355{
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001356 size_t i;
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001357 for(i = 0; i < f->ino_table_size; i++) {
1358 struct node *node;
1359 struct node *next;
1360 for(node = f->ino_table[i]; node != NULL; node = next) {
1361 next = node->ino_next;
1362 free_node(node);
1363 }
1364 }
1365 free(f->ino_table);
1366 free(f->name_table);
Miklos Szeredia181e612001-11-06 12:03:23 +00001367 pthread_mutex_destroy(&f->lock);
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001368 free(f);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001369}