blob: 100b50f6528e394429bf2327c0d8981e3faed191 [file] [log] [blame]
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001/*
2 FUSE: Filesystem in Userspace
Miklos Szeredi2e6b6f22004-07-07 19:19:53 +00003 Copyright (C) 2001-2004 Miklos Szeredi <miklos@szeredi.hu>
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00004
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
Miklos Szeredicb264512004-06-23 18:52:50 +00009#include <config.h>
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000010#include "fuse_i.h"
Miklos Szeredib9b94cd2004-12-01 18:56:39 +000011#include "fuse_kernel.h"
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000012
13#include <string.h>
Miklos Szeredi97c61e92001-11-07 12:09:43 +000014#include <stdlib.h>
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000015#include <unistd.h>
Miklos Szeredi97c61e92001-11-07 12:09:43 +000016#include <limits.h>
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000017#include <errno.h>
Miklos Szeredi019b4e92001-12-26 18:08:09 +000018#include <sys/param.h>
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000019
Miklos Szeredia25d4c22004-11-23 22:32:16 +000020#define FUSE_VERSION_FILE_OLD "/proc/fs/fuse/version"
Miklos Szeredi162bcbb2004-11-29 23:43:44 +000021#define FUSE_VERSION_FILE_NEW "/sys/fs/fuse/version"
Miklos Szeredia25d4c22004-11-23 22:32:16 +000022#define FUSE_DEV_OLD "/proc/fs/fuse/dev"
23
Miklos Szeredi97c61e92001-11-07 12:09:43 +000024#define FUSE_MAX_PATH 4096
Miklos Szeredi6bf8b682002-10-28 08:49:39 +000025#define PARAM(inarg) (((char *)(inarg)) + sizeof(*inarg))
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000026
Miklos Szeredi254d5ed2004-03-02 11:11:24 +000027#define ENTRY_REVALIDATE_TIME 1 /* sec */
28#define ATTR_REVALIDATE_TIME 1 /* sec */
29
Miklos Szeredid169f312004-09-22 08:48:26 +000030static struct fuse_context *(*fuse_getcontext)(void) = NULL;
31
Miklos Szeredic8ba2372002-12-10 12:26:00 +000032static const char *opname(enum fuse_opcode opcode)
33{
Miklos Szeredi7eafcce2004-06-19 22:42:38 +000034 switch (opcode) {
Miklos Szeredi3ed84232004-03-30 15:17:26 +000035 case FUSE_LOOKUP: return "LOOKUP";
36 case FUSE_FORGET: return "FORGET";
37 case FUSE_GETATTR: return "GETATTR";
38 case FUSE_SETATTR: return "SETATTR";
39 case FUSE_READLINK: return "READLINK";
40 case FUSE_SYMLINK: return "SYMLINK";
41 case FUSE_GETDIR: return "GETDIR";
42 case FUSE_MKNOD: return "MKNOD";
43 case FUSE_MKDIR: return "MKDIR";
44 case FUSE_UNLINK: return "UNLINK";
45 case FUSE_RMDIR: return "RMDIR";
46 case FUSE_RENAME: return "RENAME";
47 case FUSE_LINK: return "LINK";
48 case FUSE_OPEN: return "OPEN";
49 case FUSE_READ: return "READ";
50 case FUSE_WRITE: return "WRITE";
51 case FUSE_STATFS: return "STATFS";
Miklos Szeredi99f20742004-05-19 08:01:10 +000052 case FUSE_FLUSH: return "FLUSH";
Miklos Szeredi3ed84232004-03-30 15:17:26 +000053 case FUSE_RELEASE: return "RELEASE";
54 case FUSE_FSYNC: return "FSYNC";
55 case FUSE_SETXATTR: return "SETXATTR";
56 case FUSE_GETXATTR: return "GETXATTR";
57 case FUSE_LISTXATTR: return "LISTXATTR";
58 case FUSE_REMOVEXATTR: return "REMOVEXATTR";
Miklos Szeredi99f20742004-05-19 08:01:10 +000059 default: return "???";
Miklos Szeredic8ba2372002-12-10 12:26:00 +000060 }
61}
62
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +000063
64static inline void dec_avail(struct fuse *f)
65{
66 pthread_mutex_lock(&f->lock);
67 f->numavail --;
68 pthread_mutex_unlock(&f->lock);
69}
70
Miklos Szeredia13d9002004-11-02 17:32:03 +000071static struct node *__get_node(struct fuse *f, nodeid_t nodeid)
Miklos Szeredia181e612001-11-06 12:03:23 +000072{
Miklos Szeredia13d9002004-11-02 17:32:03 +000073 size_t hash = nodeid % f->id_table_size;
Miklos Szeredi97c61e92001-11-07 12:09:43 +000074 struct node *node;
75
Miklos Szeredia13d9002004-11-02 17:32:03 +000076 for (node = f->id_table[hash]; node != NULL; node = node->id_next)
77 if (node->nodeid == nodeid)
Miklos Szeredi97c61e92001-11-07 12:09:43 +000078 return node;
79
80 return NULL;
Miklos Szeredia181e612001-11-06 12:03:23 +000081}
82
Miklos Szeredia13d9002004-11-02 17:32:03 +000083static struct node *get_node(struct fuse *f, nodeid_t nodeid)
Miklos Szeredia181e612001-11-06 12:03:23 +000084{
Miklos Szeredia13d9002004-11-02 17:32:03 +000085 struct node *node = __get_node(f, nodeid);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +000086 if (node != NULL)
Miklos Szeredi97c61e92001-11-07 12:09:43 +000087 return node;
88
Miklos Szeredia13d9002004-11-02 17:32:03 +000089 fprintf(stderr, "fuse internal error: inode %lu not found\n", nodeid);
Miklos Szeredi97c61e92001-11-07 12:09:43 +000090 abort();
Miklos Szeredia181e612001-11-06 12:03:23 +000091}
92
Miklos Szeredia13d9002004-11-02 17:32:03 +000093static void hash_id(struct fuse *f, struct node *node)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000094{
Miklos Szeredia13d9002004-11-02 17:32:03 +000095 size_t hash = node->nodeid % f->id_table_size;
96 node->id_next = f->id_table[hash];
97 f->id_table[hash] = node;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000098}
99
Miklos Szeredia13d9002004-11-02 17:32:03 +0000100static void unhash_id(struct fuse *f, struct node *node)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000101{
Miklos Szeredia13d9002004-11-02 17:32:03 +0000102 size_t hash = node->nodeid % f->id_table_size;
103 struct node **nodep = &f->id_table[hash];
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000104
Miklos Szeredia13d9002004-11-02 17:32:03 +0000105 for (; *nodep != NULL; nodep = &(*nodep)->id_next)
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000106 if (*nodep == node) {
Miklos Szeredia13d9002004-11-02 17:32:03 +0000107 *nodep = node->id_next;
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000108 return;
109 }
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000110}
111
Miklos Szeredia13d9002004-11-02 17:32:03 +0000112static nodeid_t next_id(struct fuse *f)
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000113{
Miklos Szeredi76f65782004-02-19 16:55:40 +0000114 do {
115 f->ctr++;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000116 if (!f->ctr)
Miklos Szeredi76f65782004-02-19 16:55:40 +0000117 f->generation ++;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000118 } while (f->ctr == 0 || __get_node(f, f->ctr) != NULL);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000119 return f->ctr;
120}
121
122static void free_node(struct node *node)
123{
124 free(node->name);
125 free(node);
126}
127
Miklos Szeredia13d9002004-11-02 17:32:03 +0000128static unsigned int name_hash(struct fuse *f, nodeid_t parent, const char *name)
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000129{
130 unsigned int hash = *name;
131
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000132 if (hash)
133 for (name += 1; *name != '\0'; name++)
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000134 hash = (hash << 5) - hash + *name;
135
136 return (hash + parent) % f->name_table_size;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000137}
138
Miklos Szeredia13d9002004-11-02 17:32:03 +0000139static struct node *__lookup_node(struct fuse *f, nodeid_t parent,
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000140 const char *name)
141{
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000142 size_t hash = name_hash(f, parent, name);
143 struct node *node;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000144
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000145 for (node = f->name_table[hash]; node != NULL; node = node->name_next)
146 if (node->parent == parent && strcmp(node->name, name) == 0)
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000147 return node;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000148
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000149 return NULL;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000150}
151
Miklos Szeredia13d9002004-11-02 17:32:03 +0000152static struct node *lookup_node(struct fuse *f, nodeid_t parent,
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000153 const char *name)
154{
155 struct node *node;
156
157 pthread_mutex_lock(&f->lock);
158 node = __lookup_node(f, parent, name);
159 pthread_mutex_unlock(&f->lock);
160 if (node != NULL)
161 return node;
162
163 fprintf(stderr, "fuse internal error: node %lu/%s not found\n", parent,
164 name);
165 abort();
166}
167
Miklos Szeredia13d9002004-11-02 17:32:03 +0000168static int hash_name(struct fuse *f, struct node *node, nodeid_t parent,
Miklos Szeredib2cf9562004-09-16 08:42:40 +0000169 const char *name)
Miklos Szeredi5e183482001-10-31 14:52:35 +0000170{
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000171 size_t hash = name_hash(f, parent, name);
Miklos Szeredia181e612001-11-06 12:03:23 +0000172 node->parent = parent;
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000173 node->name = strdup(name);
Miklos Szeredib2cf9562004-09-16 08:42:40 +0000174 if (node->name == NULL)
175 return -1;
176
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000177 node->name_next = f->name_table[hash];
Miklos Szeredib2cf9562004-09-16 08:42:40 +0000178 f->name_table[hash] = node;
179 return 0;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000180}
181
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000182static void unhash_name(struct fuse *f, struct node *node)
Miklos Szeredia181e612001-11-06 12:03:23 +0000183{
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000184 if (node->name != NULL) {
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000185 size_t hash = name_hash(f, node->parent, node->name);
186 struct node **nodep = &f->name_table[hash];
187
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000188 for (; *nodep != NULL; nodep = &(*nodep)->name_next)
189 if (*nodep == node) {
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000190 *nodep = node->name_next;
191 node->name_next = NULL;
192 free(node->name);
193 node->name = NULL;
194 node->parent = 0;
195 return;
196 }
197 fprintf(stderr, "fuse internal error: unable to unhash node: %lu\n",
Miklos Szeredia13d9002004-11-02 17:32:03 +0000198 node->nodeid);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000199 abort();
Miklos Szeredia181e612001-11-06 12:03:23 +0000200 }
201}
202
Miklos Szeredia13d9002004-11-02 17:32:03 +0000203static struct node *find_node(struct fuse *f, nodeid_t parent, char *name,
Miklos Szeredi76f65782004-02-19 16:55:40 +0000204 struct fuse_attr *attr, int version)
Miklos Szeredi5e183482001-10-31 14:52:35 +0000205{
206 struct node *node;
Miklos Szeredia181e612001-11-06 12:03:23 +0000207 int mode = attr->mode & S_IFMT;
208 int rdev = 0;
209
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000210 if (S_ISCHR(mode) || S_ISBLK(mode))
Miklos Szeredia181e612001-11-06 12:03:23 +0000211 rdev = attr->rdev;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000212
Miklos Szeredia181e612001-11-06 12:03:23 +0000213 pthread_mutex_lock(&f->lock);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000214 node = __lookup_node(f, parent, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000215 if (node != NULL) {
Miklos Szeredia13d9002004-11-02 17:32:03 +0000216 if (node->mode == mode && node->rdev == rdev &&
217 (!(f->flags & FUSE_USE_INO) || node->ino == attr->ino)) {
218 if (!(f->flags & FUSE_USE_INO))
219 attr->ino = node->nodeid;
220
Miklos Szeredia181e612001-11-06 12:03:23 +0000221 goto out;
Miklos Szeredia13d9002004-11-02 17:32:03 +0000222 }
Miklos Szeredia181e612001-11-06 12:03:23 +0000223
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000224 unhash_name(f, node);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000225 }
226
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000227 node = (struct node *) calloc(1, sizeof(struct node));
Miklos Szeredib2cf9562004-09-16 08:42:40 +0000228 if (node == NULL)
Miklos Szeredic2309912004-09-21 13:40:38 +0000229 goto out_err;
Miklos Szeredib2cf9562004-09-16 08:42:40 +0000230
Miklos Szeredia13d9002004-11-02 17:32:03 +0000231 node->nodeid = next_id(f);
232 if (!(f->flags & FUSE_USE_INO))
233 attr->ino = node->nodeid;
Miklos Szeredia181e612001-11-06 12:03:23 +0000234 node->mode = mode;
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000235 node->rdev = rdev;
Miklos Szeredia13d9002004-11-02 17:32:03 +0000236 node->ino = attr->ino;
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000237 node->open_count = 0;
238 node->is_hidden = 0;
Miklos Szeredi76f65782004-02-19 16:55:40 +0000239 node->generation = f->generation;
Miklos Szeredib2cf9562004-09-16 08:42:40 +0000240 if (hash_name(f, node, parent, name) == -1) {
241 free(node);
Miklos Szeredic2309912004-09-21 13:40:38 +0000242 node = NULL;
243 goto out_err;
Miklos Szeredib2cf9562004-09-16 08:42:40 +0000244 }
Miklos Szeredia13d9002004-11-02 17:32:03 +0000245 hash_id(f, node);
Miklos Szeredia181e612001-11-06 12:03:23 +0000246
Miklos Szeredic2309912004-09-21 13:40:38 +0000247 out:
Miklos Szeredia181e612001-11-06 12:03:23 +0000248 node->version = version;
Miklos Szeredic2309912004-09-21 13:40:38 +0000249 out_err:
Miklos Szeredia181e612001-11-06 12:03:23 +0000250 pthread_mutex_unlock(&f->lock);
Miklos Szeredi76f65782004-02-19 16:55:40 +0000251 return node;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000252}
253
Miklos Szeredia13d9002004-11-02 17:32:03 +0000254static int path_lookup(struct fuse *f, const char *path, nodeid_t *nodeidp,
255 unsigned long *inop)
Miklos Szeredi891b8742004-07-29 09:27:49 +0000256{
Miklos Szeredia13d9002004-11-02 17:32:03 +0000257 nodeid_t nodeid;
258 unsigned long ino;
Miklos Szeredi891b8742004-07-29 09:27:49 +0000259 int err;
260 char *s;
261 char *name;
262 char *tmp = strdup(path);
263 if (!tmp)
264 return -ENOMEM;
265
266 pthread_mutex_lock(&f->lock);
Miklos Szeredia13d9002004-11-02 17:32:03 +0000267 nodeid = FUSE_ROOT_ID;
268 ino = nodeid;
Miklos Szeredi891b8742004-07-29 09:27:49 +0000269 err = 0;
270 for (s = tmp; (name = strsep(&s, "/")) != NULL; ) {
271 if (name[0]) {
Miklos Szeredia13d9002004-11-02 17:32:03 +0000272 struct node *node = __lookup_node(f, nodeid, name);
Miklos Szeredi891b8742004-07-29 09:27:49 +0000273 if (node == NULL) {
274 err = -ENOENT;
275 break;
276 }
Miklos Szeredia13d9002004-11-02 17:32:03 +0000277 nodeid = node->nodeid;
Miklos Szeredi891b8742004-07-29 09:27:49 +0000278 ino = node->ino;
279 }
280 }
281 pthread_mutex_unlock(&f->lock);
282 free(tmp);
Miklos Szeredia13d9002004-11-02 17:32:03 +0000283 if (!err) {
284 *nodeidp = nodeid;
Miklos Szeredi891b8742004-07-29 09:27:49 +0000285 *inop = ino;
Miklos Szeredia13d9002004-11-02 17:32:03 +0000286 }
Miklos Szeredi891b8742004-07-29 09:27:49 +0000287
288 return err;
289}
290
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000291static char *add_name(char *buf, char *s, const char *name)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000292{
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000293 size_t len = strlen(name);
294 s -= len;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000295 if (s <= buf) {
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000296 fprintf(stderr, "fuse: path too long: ...%s\n", s + len);
297 return NULL;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000298 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000299 strncpy(s, name, len);
300 s--;
301 *s = '/';
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000302
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000303 return s;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000304}
305
Miklos Szeredia13d9002004-11-02 17:32:03 +0000306static char *get_path_name(struct fuse *f, nodeid_t nodeid, const char *name)
Miklos Szeredib483c932001-10-29 14:57:57 +0000307{
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000308 char buf[FUSE_MAX_PATH];
309 char *s = buf + FUSE_MAX_PATH - 1;
310 struct node *node;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000311
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000312 *s = '\0';
Miklos Szeredia181e612001-11-06 12:03:23 +0000313
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000314 if (name != NULL) {
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000315 s = add_name(buf, s, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000316 if (s == NULL)
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000317 return NULL;
318 }
319
320 pthread_mutex_lock(&f->lock);
Miklos Szeredia13d9002004-11-02 17:32:03 +0000321 for (node = get_node(f, nodeid); node->nodeid != FUSE_ROOT_ID;
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000322 node = get_node(f, node->parent)) {
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000323 if (node->name == NULL) {
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000324 s = NULL;
325 break;
326 }
327
328 s = add_name(buf, s, node->name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000329 if (s == NULL)
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000330 break;
331 }
332 pthread_mutex_unlock(&f->lock);
333
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000334 if (s == NULL)
Miklos Szeredi5e183482001-10-31 14:52:35 +0000335 return NULL;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000336 else if (*s == '\0')
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000337 return strdup("/");
338 else
339 return strdup(s);
340}
Miklos Szeredia181e612001-11-06 12:03:23 +0000341
Miklos Szeredia13d9002004-11-02 17:32:03 +0000342static char *get_path(struct fuse *f, nodeid_t nodeid)
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000343{
Miklos Szeredia13d9002004-11-02 17:32:03 +0000344 return get_path_name(f, nodeid, NULL);
Miklos Szeredib483c932001-10-29 14:57:57 +0000345}
346
Miklos Szeredia13d9002004-11-02 17:32:03 +0000347static void destroy_node(struct fuse *f, nodeid_t nodeid, int version)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000348{
Miklos Szeredia181e612001-11-06 12:03:23 +0000349 struct node *node;
350
351 pthread_mutex_lock(&f->lock);
Miklos Szeredia13d9002004-11-02 17:32:03 +0000352 node = __get_node(f, nodeid);
353 if (node && node->version == version && nodeid != FUSE_ROOT_ID) {
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000354 unhash_name(f, node);
Miklos Szeredia13d9002004-11-02 17:32:03 +0000355 unhash_id(f, node);
Miklos Szeredia181e612001-11-06 12:03:23 +0000356 free_node(node);
357 }
358 pthread_mutex_unlock(&f->lock);
359
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000360}
361
Miklos Szeredia13d9002004-11-02 17:32:03 +0000362static void remove_node(struct fuse *f, nodeid_t dir, const char *name)
Miklos Szeredi5e183482001-10-31 14:52:35 +0000363{
Miklos Szeredia181e612001-11-06 12:03:23 +0000364 struct node *node;
365
366 pthread_mutex_lock(&f->lock);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000367 node = __lookup_node(f, dir, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000368 if (node == NULL) {
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000369 fprintf(stderr, "fuse internal error: unable to remove node %lu/%s\n",
370 dir, name);
371 abort();
372 }
373 unhash_name(f, node);
Miklos Szeredia181e612001-11-06 12:03:23 +0000374 pthread_mutex_unlock(&f->lock);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000375}
376
Miklos Szeredia13d9002004-11-02 17:32:03 +0000377static int rename_node(struct fuse *f, nodeid_t olddir, const char *oldname,
378 nodeid_t newdir, const char *newname, int hide)
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000379{
Miklos Szeredia181e612001-11-06 12:03:23 +0000380 struct node *node;
381 struct node *newnode;
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000382 int err = 0;
Miklos Szeredia181e612001-11-06 12:03:23 +0000383
384 pthread_mutex_lock(&f->lock);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000385 node = __lookup_node(f, olddir, oldname);
386 newnode = __lookup_node(f, newdir, newname);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000387 if (node == NULL) {
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000388 fprintf(stderr, "fuse internal error: unable to rename node %lu/%s\n",
389 olddir, oldname);
390 abort();
391 }
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000392
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000393 if (newnode != NULL) {
394 if (hide) {
395 fprintf(stderr, "fuse: hidden file got created during hiding\n");
Miklos Szeredib2cf9562004-09-16 08:42:40 +0000396 err = -EBUSY;
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000397 goto out;
398 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000399 unhash_name(f, newnode);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000400 }
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000401
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000402 unhash_name(f, node);
Miklos Szeredib2cf9562004-09-16 08:42:40 +0000403 if (hash_name(f, node, newdir, newname) == -1) {
404 err = -ENOMEM;
405 goto out;
406 }
407
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000408 if (hide)
409 node->is_hidden = 1;
410
411 out:
Miklos Szeredia181e612001-11-06 12:03:23 +0000412 pthread_mutex_unlock(&f->lock);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000413 return err;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000414}
415
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000416static void convert_stat(struct stat *stbuf, struct fuse_attr *attr)
417{
Miklos Szeredia13d9002004-11-02 17:32:03 +0000418 attr->ino = stbuf->st_ino;
Miklos Szeredib5958612004-02-20 14:10:49 +0000419 attr->mode = stbuf->st_mode;
420 attr->nlink = stbuf->st_nlink;
421 attr->uid = stbuf->st_uid;
422 attr->gid = stbuf->st_gid;
423 attr->rdev = stbuf->st_rdev;
424 attr->size = stbuf->st_size;
425 attr->blocks = stbuf->st_blocks;
426 attr->atime = stbuf->st_atime;
Miklos Szeredib5958612004-02-20 14:10:49 +0000427 attr->mtime = stbuf->st_mtime;
Miklos Szeredib5958612004-02-20 14:10:49 +0000428 attr->ctime = stbuf->st_ctime;
Miklos Szeredicb264512004-06-23 18:52:50 +0000429#ifdef HAVE_STRUCT_STAT_ST_ATIM
430 attr->atimensec = stbuf->st_atim.tv_nsec;
431 attr->mtimensec = stbuf->st_mtim.tv_nsec;
Miklos Szeredib5958612004-02-20 14:10:49 +0000432 attr->ctimensec = stbuf->st_ctim.tv_nsec;
Miklos Szeredicb264512004-06-23 18:52:50 +0000433#endif
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000434}
435
Miklos Szeredi8fb48fe2004-11-08 14:48:52 +0000436static int fill_dir(struct fuse_dirhandle *dh, const char *name, int type,
437 ino_t ino)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000438{
439 struct fuse_dirent dirent;
440 size_t reclen;
441 size_t res;
442
Miklos Szeredi8fb48fe2004-11-08 14:48:52 +0000443 if ((dh->fuse->flags & FUSE_USE_INO))
444 dirent.ino = ino;
445 else
446 dirent.ino = (unsigned long) -1;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000447 dirent.namelen = strlen(name);
448 strncpy(dirent.name, name, sizeof(dirent.name));
449 dirent.type = type;
450 reclen = FUSE_DIRENT_SIZE(&dirent);
451 res = fwrite(&dirent, reclen, 1, dh->fp);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000452 if (res == 0) {
Miklos Szeredi96249982001-11-21 12:21:19 +0000453 perror("fuse: writing directory file");
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000454 return -EIO;
455 }
456 return 0;
457}
458
Miklos Szeredi73798f92004-07-12 15:55:11 +0000459static int send_reply_raw(struct fuse *f, char *outbuf, size_t outsize,
460 int locked)
Miklos Szeredi43696432001-11-18 19:15:05 +0000461{
462 int res;
463
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000464 if ((f->flags & FUSE_DEBUG)) {
Miklos Szeredi43696432001-11-18 19:15:05 +0000465 struct fuse_out_header *out = (struct fuse_out_header *) outbuf;
466 printf(" unique: %i, error: %i (%s), outsize: %i\n", out->unique,
467 out->error, strerror(-out->error), outsize);
468 fflush(stdout);
469 }
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +0000470
Miklos Szeredi4e71c9f2004-02-09 12:05:14 +0000471 /* This needs to be done before the reply, otherwise the scheduler
472 could play tricks with us, and only let the counter be increased
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +0000473 long after the operation is done */
Miklos Szeredi73798f92004-07-12 15:55:11 +0000474 if (!locked)
475 pthread_mutex_lock(&f->lock);
476 f->numavail ++;
477 if (!locked)
478 pthread_mutex_unlock(&f->lock);
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +0000479
Miklos Szeredi43696432001-11-18 19:15:05 +0000480 res = write(f->fd, outbuf, outsize);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000481 if (res == -1) {
Miklos Szeredi43696432001-11-18 19:15:05 +0000482 /* ENOENT means the operation was interrupted */
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000483 if (!f->exited && errno != ENOENT)
Miklos Szeredi96249982001-11-21 12:21:19 +0000484 perror("fuse: writing device");
Miklos Szeredi40b9a5a2002-12-10 16:09:02 +0000485 return -errno;
Miklos Szeredi43696432001-11-18 19:15:05 +0000486 }
Miklos Szeredi40b9a5a2002-12-10 16:09:02 +0000487 return 0;
Miklos Szeredi43696432001-11-18 19:15:05 +0000488}
489
Miklos Szeredi73798f92004-07-12 15:55:11 +0000490static int __send_reply(struct fuse *f, struct fuse_in_header *in, int error,
491 void *arg, size_t argsize, int locked)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000492{
Miklos Szeredi40b9a5a2002-12-10 16:09:02 +0000493 int res;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000494 char *outbuf;
495 size_t outsize;
496 struct fuse_out_header *out;
497
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000498 if (error <= -1000 || error > 0) {
Miklos Szeredi0f48a262002-12-05 14:23:01 +0000499 fprintf(stderr, "fuse: bad error value: %i\n", error);
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000500 error = -ERANGE;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000501 }
502
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000503 if (error)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000504 argsize = 0;
505
506 outsize = sizeof(struct fuse_out_header) + argsize;
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000507 outbuf = (char *) malloc(outsize);
Miklos Szeredib2cf9562004-09-16 08:42:40 +0000508 if (outbuf == NULL) {
509 fprintf(stderr, "fuse: failed to allocate reply buffer\n");
510 res = -ENOMEM;
511 } else {
512 out = (struct fuse_out_header *) outbuf;
513 memset(out, 0, sizeof(struct fuse_out_header));
514 out->unique = in->unique;
515 out->error = error;
516 if (argsize != 0)
517 memcpy(outbuf + sizeof(struct fuse_out_header), arg, argsize);
518
519 res = send_reply_raw(f, outbuf, outsize, locked);
520 free(outbuf);
521 }
Miklos Szeredi40b9a5a2002-12-10 16:09:02 +0000522
523 return res;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000524}
525
Miklos Szeredi73798f92004-07-12 15:55:11 +0000526static int send_reply(struct fuse *f, struct fuse_in_header *in, int error,
527 void *arg, size_t argsize)
528{
529 return __send_reply(f, in, error, arg, argsize, 0);
530}
531
Miklos Szeredia13d9002004-11-02 17:32:03 +0000532static int is_open(struct fuse *f, nodeid_t dir, const char *name)
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000533{
534 struct node *node;
535 int isopen = 0;
536 pthread_mutex_lock(&f->lock);
537 node = __lookup_node(f, dir, name);
538 if (node && node->open_count > 0)
539 isopen = 1;
540 pthread_mutex_unlock(&f->lock);
541 return isopen;
542}
543
Miklos Szeredia13d9002004-11-02 17:32:03 +0000544static char *hidden_name(struct fuse *f, nodeid_t dir, const char *oldname,
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000545 char *newname, size_t bufsize)
546{
547 struct stat buf;
548 struct node *node;
549 struct node *newnode;
550 char *newpath;
551 int res;
552 int failctr = 10;
553
554 if (!f->op.getattr)
555 return NULL;
556
557 do {
558 node = lookup_node(f, dir, oldname);
559 pthread_mutex_lock(&f->lock);
560 do {
561 f->hidectr ++;
562 snprintf(newname, bufsize, ".fuse_hidden%08x%08x",
Miklos Szeredia13d9002004-11-02 17:32:03 +0000563 (unsigned int) node->nodeid, f->hidectr);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000564 newnode = __lookup_node(f, dir, newname);
565 } while(newnode);
566 pthread_mutex_unlock(&f->lock);
567
568 newpath = get_path_name(f, dir, newname);
569 if (!newpath)
570 break;
571
572 res = f->op.getattr(newpath, &buf);
573 if (res != 0)
574 break;
575 free(newpath);
576 newpath = NULL;
577 } while(--failctr);
578
579 return newpath;
580}
581
Miklos Szeredia13d9002004-11-02 17:32:03 +0000582static int hide_node(struct fuse *f, const char *oldpath, nodeid_t dir,
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000583 const char *oldname)
584{
585 char newname[64];
586 char *newpath;
Miklos Szeredib2cf9562004-09-16 08:42:40 +0000587 int err = -EBUSY;
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000588
Miklos Szeredib2cf9562004-09-16 08:42:40 +0000589 if (f->op.rename && f->op.unlink) {
590 newpath = hidden_name(f, dir, oldname, newname, sizeof(newname));
591 if (newpath) {
592 int res = f->op.rename(oldpath, newpath);
593 if (res == 0)
594 err = rename_node(f, dir, oldname, dir, newname, 1);
595 free(newpath);
596 }
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000597 }
Miklos Szeredib2cf9562004-09-16 08:42:40 +0000598 return err;
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000599}
600
Miklos Szeredia13d9002004-11-02 17:32:03 +0000601static int lookup_path(struct fuse *f, nodeid_t nodeid, int version, char *name,
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000602 const char *path, struct fuse_entry_out *arg)
Miklos Szeredi76f65782004-02-19 16:55:40 +0000603{
604 int res;
605 struct stat buf;
606
607 res = f->op.getattr(path, &buf);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000608 if (res == 0) {
Miklos Szeredi76f65782004-02-19 16:55:40 +0000609 struct node *node;
610
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000611 memset(arg, 0, sizeof(struct fuse_entry_out));
Miklos Szeredi76f65782004-02-19 16:55:40 +0000612 convert_stat(&buf, &arg->attr);
Miklos Szeredia13d9002004-11-02 17:32:03 +0000613 node = find_node(f, nodeid, name, &arg->attr, version);
Miklos Szeredib2cf9562004-09-16 08:42:40 +0000614 if (node == NULL)
615 res = -ENOMEM;
616 else {
Miklos Szeredia13d9002004-11-02 17:32:03 +0000617 arg->nodeid = node->nodeid;
Miklos Szeredib2cf9562004-09-16 08:42:40 +0000618 arg->generation = node->generation;
619 arg->entry_valid = ENTRY_REVALIDATE_TIME;
620 arg->entry_valid_nsec = 0;
621 arg->attr_valid = ATTR_REVALIDATE_TIME;
622 arg->attr_valid_nsec = 0;
623 if (f->flags & FUSE_DEBUG) {
Miklos Szeredia13d9002004-11-02 17:32:03 +0000624 printf(" NODEID: %li\n", arg->nodeid);
Miklos Szeredib2cf9562004-09-16 08:42:40 +0000625 fflush(stdout);
626 }
Miklos Szeredi76f65782004-02-19 16:55:40 +0000627 }
628 }
629 return res;
630}
631
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000632static void do_lookup(struct fuse *f, struct fuse_in_header *in, char *name)
633{
634 int res;
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000635 int res2;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000636 char *path;
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000637 struct fuse_entry_out arg;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000638
Miklos Szeredi5e183482001-10-31 14:52:35 +0000639 res = -ENOENT;
Miklos Szeredia13d9002004-11-02 17:32:03 +0000640 path = get_path_name(f, in->nodeid, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000641 if (path != NULL) {
642 if (f->flags & FUSE_DEBUG) {
Miklos Szeredi6ebe2342002-01-06 21:44:16 +0000643 printf("LOOKUP %s\n", path);
644 fflush(stdout);
645 }
Miklos Szeredi5e183482001-10-31 14:52:35 +0000646 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000647 if (f->op.getattr)
Miklos Szeredia13d9002004-11-02 17:32:03 +0000648 res = lookup_path(f, in->nodeid, in->unique, name, path, &arg);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000649 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000650 }
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000651 res2 = send_reply(f, in, res, &arg, sizeof(arg));
652 if (res == 0 && res2 == -ENOENT)
Miklos Szeredia13d9002004-11-02 17:32:03 +0000653 destroy_node(f, arg.nodeid, in->unique);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000654}
655
Miklos Szeredia181e612001-11-06 12:03:23 +0000656static void do_forget(struct fuse *f, struct fuse_in_header *in,
657 struct fuse_forget_in *arg)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000658{
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000659 if (f->flags & FUSE_DEBUG) {
Miklos Szeredia13d9002004-11-02 17:32:03 +0000660 printf("FORGET %li/%i\n", in->nodeid, arg->version);
Miklos Szeredi43696432001-11-18 19:15:05 +0000661 fflush(stdout);
662 }
Miklos Szeredia13d9002004-11-02 17:32:03 +0000663 destroy_node(f, in->nodeid, arg->version);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000664}
665
666static void do_getattr(struct fuse *f, struct fuse_in_header *in)
667{
668 int res;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000669 char *path;
670 struct stat buf;
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000671 struct fuse_attr_out arg;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000672
Miklos Szeredi5e183482001-10-31 14:52:35 +0000673 res = -ENOENT;
Miklos Szeredia13d9002004-11-02 17:32:03 +0000674 path = get_path(f, in->nodeid);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000675 if (path != NULL) {
Miklos Szeredi5e183482001-10-31 14:52:35 +0000676 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000677 if (f->op.getattr)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000678 res = f->op.getattr(path, &buf);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000679 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000680 }
Miklos Szeredi0f48a262002-12-05 14:23:01 +0000681
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000682 if (res == 0) {
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000683 memset(&arg, 0, sizeof(struct fuse_attr_out));
684 arg.attr_valid = ATTR_REVALIDATE_TIME;
685 arg.attr_valid_nsec = 0;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000686 convert_stat(&buf, &arg.attr);
Miklos Szeredia13d9002004-11-02 17:32:03 +0000687 if (!(f->flags & FUSE_USE_INO))
688 arg.attr.ino = in->nodeid;
689 else {
690 struct node *node = get_node(f, in->nodeid);
691 node->ino = arg.attr.ino;
692 }
Miklos Szeredi0f48a262002-12-05 14:23:01 +0000693 }
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000694
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000695 send_reply(f, in, res, &arg, sizeof(arg));
696}
697
Miklos Szeredi680a69a2001-11-16 13:31:14 +0000698static int do_chmod(struct fuse *f, const char *path, struct fuse_attr *attr)
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000699{
700 int res;
701
702 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000703 if (f->op.chmod)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000704 res = f->op.chmod(path, attr->mode);
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000705
706 return res;
707}
708
Miklos Szeredi680a69a2001-11-16 13:31:14 +0000709static int do_chown(struct fuse *f, const char *path, struct fuse_attr *attr,
Miklos Szeredi2e50d432001-12-20 12:17:25 +0000710 int valid)
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000711{
712 int res;
713 uid_t uid = (valid & FATTR_UID) ? attr->uid : (uid_t) -1;
714 gid_t gid = (valid & FATTR_GID) ? attr->gid : (gid_t) -1;
715
716 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000717 if (f->op.chown)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000718 res = f->op.chown(path, uid, gid);
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000719
720 return res;
721}
722
Miklos Szeredi680a69a2001-11-16 13:31:14 +0000723static int do_truncate(struct fuse *f, const char *path,
724 struct fuse_attr *attr)
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000725{
726 int res;
727
728 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000729 if (f->op.truncate)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000730 res = f->op.truncate(path, attr->size);
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000731
732 return res;
733}
734
Miklos Szeredi680a69a2001-11-16 13:31:14 +0000735static int do_utime(struct fuse *f, const char *path, struct fuse_attr *attr)
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000736{
737 int res;
738 struct utimbuf buf;
739 buf.actime = attr->atime;
740 buf.modtime = attr->mtime;
741 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000742 if (f->op.utime)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000743 res = f->op.utime(path, &buf);
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000744
745 return res;
746}
747
Miklos Szeredi5e183482001-10-31 14:52:35 +0000748static void do_setattr(struct fuse *f, struct fuse_in_header *in,
749 struct fuse_setattr_in *arg)
750{
751 int res;
752 char *path;
753 int valid = arg->valid;
754 struct fuse_attr *attr = &arg->attr;
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000755 struct fuse_attr_out outarg;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000756
757 res = -ENOENT;
Miklos Szeredia13d9002004-11-02 17:32:03 +0000758 path = get_path(f, in->nodeid);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000759 if (path != NULL) {
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000760 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000761 if (f->op.getattr) {
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000762 res = 0;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000763 if (!res && (valid & FATTR_MODE))
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000764 res = do_chmod(f, path, attr);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000765 if (!res && (valid & (FATTR_UID | FATTR_GID)))
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000766 res = do_chown(f, path, attr, valid);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000767 if (!res && (valid & FATTR_SIZE))
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000768 res = do_truncate(f, path, attr);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000769 if (!res && (valid & (FATTR_ATIME | FATTR_MTIME)) ==
Miklos Szeredib5958612004-02-20 14:10:49 +0000770 (FATTR_ATIME | FATTR_MTIME))
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000771 res = do_utime(f, path, attr);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000772 if (!res) {
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000773 struct stat buf;
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000774 res = f->op.getattr(path, &buf);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000775 if (!res) {
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000776 memset(&outarg, 0, sizeof(struct fuse_attr_out));
777 outarg.attr_valid = ATTR_REVALIDATE_TIME;
778 outarg.attr_valid_nsec = 0;
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000779 convert_stat(&buf, &outarg.attr);
Miklos Szeredia13d9002004-11-02 17:32:03 +0000780 if (!(f->flags & FUSE_USE_INO))
781 outarg.attr.ino = in->nodeid;
782 else {
783 struct node *node = get_node(f, in->nodeid);
784 node->ino = outarg.attr.ino;
785 }
Miklos Szeredi0f48a262002-12-05 14:23:01 +0000786 }
Miklos Szeredia181e612001-11-06 12:03:23 +0000787 }
Miklos Szeredi5e183482001-10-31 14:52:35 +0000788 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000789 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000790 }
Miklos Szeredia181e612001-11-06 12:03:23 +0000791 send_reply(f, in, res, &outarg, sizeof(outarg));
Miklos Szeredi5e183482001-10-31 14:52:35 +0000792}
793
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000794static void do_readlink(struct fuse *f, struct fuse_in_header *in)
795{
796 int res;
797 char link[PATH_MAX + 1];
Miklos Szeredib483c932001-10-29 14:57:57 +0000798 char *path;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000799
Miklos Szeredi5e183482001-10-31 14:52:35 +0000800 res = -ENOENT;
Miklos Szeredia13d9002004-11-02 17:32:03 +0000801 path = get_path(f, in->nodeid);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000802 if (path != NULL) {
Miklos Szeredi5e183482001-10-31 14:52:35 +0000803 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000804 if (f->op.readlink)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000805 res = f->op.readlink(path, link, sizeof(link));
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000806 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000807 }
Miklos Szeredi2df1c042001-11-06 15:07:17 +0000808 link[PATH_MAX] = '\0';
Miklos Szeredi4b2bef42002-01-09 12:23:27 +0000809 send_reply(f, in, res, link, res == 0 ? strlen(link) : 0);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000810}
811
812static void do_getdir(struct fuse *f, struct fuse_in_header *in)
813{
814 int res;
815 struct fuse_getdir_out arg;
Miklos Szeredia181e612001-11-06 12:03:23 +0000816 struct fuse_dirhandle dh;
Miklos Szeredib483c932001-10-29 14:57:57 +0000817 char *path;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000818
Miklos Szeredib483c932001-10-29 14:57:57 +0000819 dh.fuse = f;
820 dh.fp = tmpfile();
Miklos Szeredia13d9002004-11-02 17:32:03 +0000821 dh.dir = in->nodeid;
Miklos Szeredi0f48a262002-12-05 14:23:01 +0000822
Miklos Szeredi65afea12004-09-14 07:13:45 +0000823 res = -EIO;
824 if (dh.fp == NULL)
825 perror("fuse: failed to create temporary file");
826 else {
827 res = -ENOENT;
Miklos Szeredia13d9002004-11-02 17:32:03 +0000828 path = get_path(f, in->nodeid);
Miklos Szeredi65afea12004-09-14 07:13:45 +0000829 if (path != NULL) {
830 res = -ENOSYS;
831 if (f->op.getdir)
Miklos Szeredi8fb48fe2004-11-08 14:48:52 +0000832 res = f->op.getdir(path, &dh, fill_dir);
Miklos Szeredi65afea12004-09-14 07:13:45 +0000833 free(path);
834 }
835 fflush(dh.fp);
836 }
Miklos Szeredi0f48a262002-12-05 14:23:01 +0000837 memset(&arg, 0, sizeof(struct fuse_getdir_out));
Miklos Szeredi65afea12004-09-14 07:13:45 +0000838 if (res == 0)
839 arg.fd = fileno(dh.fp);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000840 send_reply(f, in, res, &arg, sizeof(arg));
Miklos Szeredi65afea12004-09-14 07:13:45 +0000841 if (dh.fp != NULL)
842 fclose(dh.fp);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000843}
844
Miklos Szeredib483c932001-10-29 14:57:57 +0000845static void do_mknod(struct fuse *f, struct fuse_in_header *in,
846 struct fuse_mknod_in *inarg)
847{
848 int res;
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000849 int res2;
Miklos Szeredib483c932001-10-29 14:57:57 +0000850 char *path;
Miklos Szeredi76f65782004-02-19 16:55:40 +0000851 char *name = PARAM(inarg);
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000852 struct fuse_entry_out outarg;
Miklos Szeredib483c932001-10-29 14:57:57 +0000853
Miklos Szeredi5e183482001-10-31 14:52:35 +0000854 res = -ENOENT;
Miklos Szeredia13d9002004-11-02 17:32:03 +0000855 path = get_path_name(f, in->nodeid, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000856 if (path != NULL) {
857 if (f->flags & FUSE_DEBUG) {
Miklos Szeredi76f65782004-02-19 16:55:40 +0000858 printf("MKNOD %s\n", path);
859 fflush(stdout);
860 }
Miklos Szeredi5e183482001-10-31 14:52:35 +0000861 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000862 if (f->op.mknod && f->op.getattr) {
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000863 res = f->op.mknod(path, inarg->mode, inarg->rdev);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000864 if (res == 0)
Miklos Szeredia13d9002004-11-02 17:32:03 +0000865 res = lookup_path(f, in->nodeid, in->unique, name, path, &outarg);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000866 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000867 free(path);
Miklos Szeredib483c932001-10-29 14:57:57 +0000868 }
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000869 res2 = send_reply(f, in, res, &outarg, sizeof(outarg));
870 if (res == 0 && res2 == -ENOENT)
Miklos Szeredia13d9002004-11-02 17:32:03 +0000871 destroy_node(f, outarg.nodeid, in->unique);
Miklos Szeredib483c932001-10-29 14:57:57 +0000872}
873
874static void do_mkdir(struct fuse *f, struct fuse_in_header *in,
875 struct fuse_mkdir_in *inarg)
876{
877 int res;
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000878 int res2;
Miklos Szeredib483c932001-10-29 14:57:57 +0000879 char *path;
Miklos Szeredi76f65782004-02-19 16:55:40 +0000880 char *name = PARAM(inarg);
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000881 struct fuse_entry_out outarg;
Miklos Szeredib483c932001-10-29 14:57:57 +0000882
Miklos Szeredi5e183482001-10-31 14:52:35 +0000883 res = -ENOENT;
Miklos Szeredia13d9002004-11-02 17:32:03 +0000884 path = get_path_name(f, in->nodeid, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000885 if (path != NULL) {
886 if (f->flags & FUSE_DEBUG) {
Miklos Szeredi76f65782004-02-19 16:55:40 +0000887 printf("MKDIR %s\n", path);
888 fflush(stdout);
889 }
Miklos Szeredi5e183482001-10-31 14:52:35 +0000890 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000891 if (f->op.mkdir && f->op.getattr) {
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000892 res = f->op.mkdir(path, inarg->mode);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000893 if (res == 0)
Miklos Szeredia13d9002004-11-02 17:32:03 +0000894 res = lookup_path(f, in->nodeid, in->unique, name, path, &outarg);
Miklos Szeredi76f65782004-02-19 16:55:40 +0000895 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000896 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000897 }
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000898 res2 = send_reply(f, in, res, &outarg, sizeof(outarg));
899 if (res == 0 && res2 == -ENOENT)
Miklos Szeredia13d9002004-11-02 17:32:03 +0000900 destroy_node(f, outarg.nodeid, in->unique);
Miklos Szeredib483c932001-10-29 14:57:57 +0000901}
902
Miklos Szeredib5958612004-02-20 14:10:49 +0000903static void do_unlink(struct fuse *f, struct fuse_in_header *in, char *name)
Miklos Szeredib483c932001-10-29 14:57:57 +0000904{
905 int res;
906 char *path;
907
Miklos Szeredi5e183482001-10-31 14:52:35 +0000908 res = -ENOENT;
Miklos Szeredia13d9002004-11-02 17:32:03 +0000909 path = get_path_name(f, in->nodeid, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000910 if (path != NULL) {
Miklos Szeredi209f5d02004-07-24 19:56:16 +0000911 if (f->flags & FUSE_DEBUG) {
912 printf("UNLINK %s\n", path);
913 fflush(stdout);
914 }
Miklos Szeredi5e183482001-10-31 14:52:35 +0000915 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000916 if (f->op.unlink) {
Miklos Szeredia13d9002004-11-02 17:32:03 +0000917 if (!(f->flags & FUSE_HARD_REMOVE) && is_open(f, in->nodeid, name))
918 res = hide_node(f, path, in->nodeid, name);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000919 else {
920 res = f->op.unlink(path);
921 if (res == 0)
Miklos Szeredia13d9002004-11-02 17:32:03 +0000922 remove_node(f, in->nodeid, name);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000923 }
Miklos Szeredi5e183482001-10-31 14:52:35 +0000924 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000925 free(path);
Miklos Szeredib483c932001-10-29 14:57:57 +0000926 }
Miklos Szeredib5958612004-02-20 14:10:49 +0000927 send_reply(f, in, res, NULL, 0);
928}
929
930static void do_rmdir(struct fuse *f, struct fuse_in_header *in, char *name)
931{
932 int res;
933 char *path;
934
935 res = -ENOENT;
Miklos Szeredia13d9002004-11-02 17:32:03 +0000936 path = get_path_name(f, in->nodeid, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000937 if (path != NULL) {
Miklos Szeredi209f5d02004-07-24 19:56:16 +0000938 if (f->flags & FUSE_DEBUG) {
939 printf("RMDIR %s\n", path);
940 fflush(stdout);
941 }
Miklos Szeredib5958612004-02-20 14:10:49 +0000942 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000943 if (f->op.rmdir) {
Miklos Szeredib5958612004-02-20 14:10:49 +0000944 res = f->op.rmdir(path);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000945 if (res == 0)
Miklos Szeredia13d9002004-11-02 17:32:03 +0000946 remove_node(f, in->nodeid, name);
Miklos Szeredib5958612004-02-20 14:10:49 +0000947 }
948 free(path);
949 }
Miklos Szeredib483c932001-10-29 14:57:57 +0000950 send_reply(f, in, res, NULL, 0);
951}
952
953static void do_symlink(struct fuse *f, struct fuse_in_header *in, char *name,
954 char *link)
955{
956 int res;
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000957 int res2;
Miklos Szeredib483c932001-10-29 14:57:57 +0000958 char *path;
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000959 struct fuse_entry_out outarg;
Miklos Szeredib483c932001-10-29 14:57:57 +0000960
Miklos Szeredi5e183482001-10-31 14:52:35 +0000961 res = -ENOENT;
Miklos Szeredia13d9002004-11-02 17:32:03 +0000962 path = get_path_name(f, in->nodeid, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000963 if (path != NULL) {
964 if (f->flags & FUSE_DEBUG) {
Miklos Szeredi76f65782004-02-19 16:55:40 +0000965 printf("SYMLINK %s\n", path);
966 fflush(stdout);
967 }
Miklos Szeredi5e183482001-10-31 14:52:35 +0000968 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000969 if (f->op.symlink && f->op.getattr) {
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000970 res = f->op.symlink(link, path);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000971 if (res == 0)
Miklos Szeredia13d9002004-11-02 17:32:03 +0000972 res = lookup_path(f, in->nodeid, in->unique, name, path, &outarg);
Miklos Szeredi76f65782004-02-19 16:55:40 +0000973 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000974 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000975 }
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000976 res2 = send_reply(f, in, res, &outarg, sizeof(outarg));
977 if (res == 0 && res2 == -ENOENT)
Miklos Szeredia13d9002004-11-02 17:32:03 +0000978 destroy_node(f, outarg.nodeid, in->unique);
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000979
Miklos Szeredib483c932001-10-29 14:57:57 +0000980}
981
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000982static void do_rename(struct fuse *f, struct fuse_in_header *in,
983 struct fuse_rename_in *inarg)
984{
985 int res;
Miklos Szeredia13d9002004-11-02 17:32:03 +0000986 nodeid_t olddir = in->nodeid;
987 nodeid_t newdir = inarg->newdir;
Miklos Szeredi6bf8b682002-10-28 08:49:39 +0000988 char *oldname = PARAM(inarg);
989 char *newname = oldname + strlen(oldname) + 1;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000990 char *oldpath;
991 char *newpath;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000992
Miklos Szeredi5e183482001-10-31 14:52:35 +0000993 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000994 oldpath = get_path_name(f, olddir, oldname);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000995 if (oldpath != NULL) {
Miklos Szeredia181e612001-11-06 12:03:23 +0000996 newpath = get_path_name(f, newdir, newname);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000997 if (newpath != NULL) {
Miklos Szeredi209f5d02004-07-24 19:56:16 +0000998 if (f->flags & FUSE_DEBUG) {
999 printf("RENAME %s -> %s\n", oldpath, newpath);
1000 fflush(stdout);
1001 }
Miklos Szeredi5e183482001-10-31 14:52:35 +00001002 res = -ENOSYS;
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001003 if (f->op.rename) {
1004 res = 0;
Miklos Szeredi2529ca22004-07-13 15:36:52 +00001005 if (!(f->flags & FUSE_HARD_REMOVE) &&
1006 is_open(f, newdir, newname))
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001007 res = hide_node(f, newpath, newdir, newname);
1008 if (res == 0) {
1009 res = f->op.rename(oldpath, newpath);
1010 if (res == 0)
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001011 res = rename_node(f, olddir, oldname, newdir, newname, 0);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001012 }
1013 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001014 free(newpath);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001015 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001016 free(oldpath);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001017 }
Miklos Szeredi19dff1b2001-10-30 15:06:52 +00001018 send_reply(f, in, res, NULL, 0);
1019}
1020
1021static void do_link(struct fuse *f, struct fuse_in_header *in,
Miklos Szeredi5e183482001-10-31 14:52:35 +00001022 struct fuse_link_in *arg)
Miklos Szeredi19dff1b2001-10-30 15:06:52 +00001023{
1024 int res;
Miklos Szeredi2778f6c2004-06-21 09:45:30 +00001025 int res2;
Miklos Szeredi5e183482001-10-31 14:52:35 +00001026 char *oldpath;
1027 char *newpath;
Miklos Szeredi76f65782004-02-19 16:55:40 +00001028 char *name = PARAM(arg);
Miklos Szeredi254d5ed2004-03-02 11:11:24 +00001029 struct fuse_entry_out outarg;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +00001030
Miklos Szeredi5e183482001-10-31 14:52:35 +00001031 res = -ENOENT;
Miklos Szeredia13d9002004-11-02 17:32:03 +00001032 oldpath = get_path(f, in->nodeid);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001033 if (oldpath != NULL) {
Miklos Szeredi76f65782004-02-19 16:55:40 +00001034 newpath = get_path_name(f, arg->newdir, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001035 if (newpath != NULL) {
1036 if (f->flags & FUSE_DEBUG) {
Miklos Szeredi76f65782004-02-19 16:55:40 +00001037 printf("LINK %s\n", newpath);
1038 fflush(stdout);
1039 }
Miklos Szeredi5e183482001-10-31 14:52:35 +00001040 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001041 if (f->op.link && f->op.getattr) {
Miklos Szeredi0a7077f2001-11-11 18:20:17 +00001042 res = f->op.link(oldpath, newpath);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001043 if (res == 0)
Miklos Szeredi76f65782004-02-19 16:55:40 +00001044 res = lookup_path(f, arg->newdir, in->unique, name,
1045 newpath, &outarg);
1046 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001047 free(newpath);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001048 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001049 free(oldpath);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001050 }
Miklos Szeredi2778f6c2004-06-21 09:45:30 +00001051 res2 = send_reply(f, in, res, &outarg, sizeof(outarg));
1052 if (res == 0 && res2 == -ENOENT)
Miklos Szeredia13d9002004-11-02 17:32:03 +00001053 destroy_node(f, outarg.nodeid, in->unique);
Miklos Szeredi19dff1b2001-10-30 15:06:52 +00001054}
1055
Miklos Szeredi5e183482001-10-31 14:52:35 +00001056static void do_open(struct fuse *f, struct fuse_in_header *in,
1057 struct fuse_open_in *arg)
1058{
1059 int res;
1060 char *path;
Miklos Szeredi209f5d02004-07-24 19:56:16 +00001061 struct fuse_open_out outarg;
Miklos Szeredifb28c5e2004-11-26 12:15:06 +00001062 struct fuse_file_info fi;
Miklos Szeredi5e183482001-10-31 14:52:35 +00001063
Miklos Szeredifb28c5e2004-11-26 12:15:06 +00001064 memset(&fi, 0, sizeof(fi));
1065 fi.flags = arg->flags;
Miklos Szeredi5e183482001-10-31 14:52:35 +00001066 res = -ENOENT;
Miklos Szeredia13d9002004-11-02 17:32:03 +00001067 path = get_path(f, in->nodeid);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001068 if (path != NULL) {
Miklos Szeredi5e183482001-10-31 14:52:35 +00001069 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001070 if (f->op.open)
Miklos Szeredifb28c5e2004-11-26 12:15:06 +00001071 res = f->op.open(path, &fi);
Miklos Szeredi40b9a5a2002-12-10 16:09:02 +00001072 }
Miklos Szeredi73798f92004-07-12 15:55:11 +00001073 if (res == 0) {
1074 int res2;
1075
1076 /* If the request is interrupted the lock must be held until
1077 the cancellation is finished. Otherwise there could be
1078 races with rename/unlink, against which the kernel can't
1079 protect */
1080 pthread_mutex_lock(&f->lock);
Miklos Szeredifb28c5e2004-11-26 12:15:06 +00001081 outarg.fh = fi.fh;
Miklos Szeredi209f5d02004-07-24 19:56:16 +00001082 if (f->flags & FUSE_DEBUG) {
Miklos Szeredi1eea0322004-09-27 18:50:11 +00001083 printf("OPEN[%lu] flags: 0x%x\n", outarg.fh, arg->flags);
Miklos Szeredi209f5d02004-07-24 19:56:16 +00001084 fflush(stdout);
1085 }
1086
1087 res2 = __send_reply(f, in, res, &outarg, sizeof(outarg), 1);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001088 if(res2 == -ENOENT) {
1089 /* The open syscall was interrupted, so it must be cancelled */
1090 if(f->op.release)
Miklos Szeredifb28c5e2004-11-26 12:15:06 +00001091 f->op.release(path, &fi);
Miklos Szeredi73798f92004-07-12 15:55:11 +00001092 } else
Miklos Szeredia13d9002004-11-02 17:32:03 +00001093 get_node(f, in->nodeid)->open_count ++;
Miklos Szeredi73798f92004-07-12 15:55:11 +00001094 pthread_mutex_unlock(&f->lock);
1095
1096 } else
1097 send_reply(f, in, res, NULL, 0);
1098
Miklos Szeredi9a31cca2004-06-26 21:11:25 +00001099 if (path)
1100 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001101}
1102
Miklos Szeredi209f5d02004-07-24 19:56:16 +00001103static void do_flush(struct fuse *f, struct fuse_in_header *in,
1104 struct fuse_flush_in *arg)
Miklos Szeredie2e4ac22004-05-18 08:45:28 +00001105{
1106 char *path;
1107 int res;
Miklos Szeredifb28c5e2004-11-26 12:15:06 +00001108 struct fuse_file_info fi;
Miklos Szeredie2e4ac22004-05-18 08:45:28 +00001109
Miklos Szeredifb28c5e2004-11-26 12:15:06 +00001110 memset(&fi, 0, sizeof(fi));
1111 fi.fh = arg->fh;
Miklos Szeredie2e4ac22004-05-18 08:45:28 +00001112 res = -ENOENT;
Miklos Szeredia13d9002004-11-02 17:32:03 +00001113 path = get_path(f, in->nodeid);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001114 if (path != NULL) {
Miklos Szeredi209f5d02004-07-24 19:56:16 +00001115 if (f->flags & FUSE_DEBUG) {
Miklos Szeredi1eea0322004-09-27 18:50:11 +00001116 printf("FLUSH[%lu]\n", arg->fh);
Miklos Szeredi209f5d02004-07-24 19:56:16 +00001117 fflush(stdout);
1118 }
Miklos Szeredie2e4ac22004-05-18 08:45:28 +00001119 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001120 if (f->op.flush)
Miklos Szeredifb28c5e2004-11-26 12:15:06 +00001121 res = f->op.flush(path, &fi);
Miklos Szeredie2e4ac22004-05-18 08:45:28 +00001122 free(path);
1123 }
1124 send_reply(f, in, res, NULL, 0);
1125}
1126
Miklos Szeredi9478e862002-12-11 09:50:26 +00001127static void do_release(struct fuse *f, struct fuse_in_header *in,
Miklos Szeredi209f5d02004-07-24 19:56:16 +00001128 struct fuse_release_in *arg)
Miklos Szeredic8ba2372002-12-10 12:26:00 +00001129{
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001130 struct node *node;
1131 char *path;
Miklos Szeredifb28c5e2004-11-26 12:15:06 +00001132 struct fuse_file_info fi;
1133
1134 memset(&fi, 0, sizeof(fi));
1135 fi.flags = arg->flags;
1136 fi.fh = arg->fh;
Miklos Szeredic8ba2372002-12-10 12:26:00 +00001137
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001138 pthread_mutex_lock(&f->lock);
Miklos Szeredia13d9002004-11-02 17:32:03 +00001139 node = get_node(f, in->nodeid);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001140 --node->open_count;
1141 pthread_mutex_unlock(&f->lock);
1142
Miklos Szeredia13d9002004-11-02 17:32:03 +00001143 path = get_path(f, in->nodeid);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001144 if (path != NULL) {
Miklos Szeredi209f5d02004-07-24 19:56:16 +00001145 if (f->flags & FUSE_DEBUG) {
Miklos Szeredi1eea0322004-09-27 18:50:11 +00001146 printf("RELEASE[%lu]\n", arg->fh);
Miklos Szeredi209f5d02004-07-24 19:56:16 +00001147 fflush(stdout);
1148 }
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001149 if (f->op.release)
Miklos Szeredifb28c5e2004-11-26 12:15:06 +00001150 f->op.release(path, &fi);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001151
1152 if(node->is_hidden && node->open_count == 0)
1153 /* can now clean up this hidden file */
1154 f->op.unlink(path);
1155
1156 free(path);
Miklos Szeredic8ba2372002-12-10 12:26:00 +00001157 }
Miklos Szeredi556d03d2004-06-30 11:13:41 +00001158 send_reply(f, in, 0, NULL, 0);
Miklos Szeredic8ba2372002-12-10 12:26:00 +00001159}
1160
Miklos Szeredi5e183482001-10-31 14:52:35 +00001161static void do_read(struct fuse *f, struct fuse_in_header *in,
1162 struct fuse_read_in *arg)
1163{
1164 int res;
1165 char *path;
Miklos Szeredi43696432001-11-18 19:15:05 +00001166 char *outbuf = (char *) malloc(sizeof(struct fuse_out_header) + arg->size);
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001167 if (outbuf == NULL)
1168 send_reply(f, in, -ENOMEM, NULL, 0);
1169 else {
1170 struct fuse_out_header *out = (struct fuse_out_header *) outbuf;
1171 char *buf = outbuf + sizeof(struct fuse_out_header);
1172 size_t size;
1173 size_t outsize;
Miklos Szeredifb28c5e2004-11-26 12:15:06 +00001174 struct fuse_file_info fi;
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001175
Miklos Szeredifb28c5e2004-11-26 12:15:06 +00001176 memset(&fi, 0, sizeof(fi));
1177 fi.fh = arg->fh;
1178
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001179 res = -ENOENT;
Miklos Szeredia13d9002004-11-02 17:32:03 +00001180 path = get_path(f, in->nodeid);
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001181 if (path != NULL) {
1182 if (f->flags & FUSE_DEBUG) {
Miklos Szeredi1eea0322004-09-27 18:50:11 +00001183 printf("READ[%lu] %u bytes from %llu\n", arg->fh, arg->size,
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001184 arg->offset);
1185 fflush(stdout);
1186 }
1187
1188 res = -ENOSYS;
1189 if (f->op.read)
Miklos Szeredifb28c5e2004-11-26 12:15:06 +00001190 res = f->op.read(path, buf, arg->size, arg->offset, &fi);
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001191 free(path);
Miklos Szeredi6ebe2342002-01-06 21:44:16 +00001192 }
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001193
1194 size = 0;
1195 if (res >= 0) {
1196 size = res;
1197 res = 0;
1198 if (f->flags & FUSE_DEBUG) {
Miklos Szeredi1eea0322004-09-27 18:50:11 +00001199 printf(" READ[%lu] %u bytes\n", arg->fh, size);
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001200 fflush(stdout);
1201 }
Miklos Szeredi6ebe2342002-01-06 21:44:16 +00001202 }
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001203 memset(out, 0, sizeof(struct fuse_out_header));
1204 out->unique = in->unique;
1205 out->error = res;
1206 outsize = sizeof(struct fuse_out_header) + size;
1207
1208 send_reply_raw(f, outbuf, outsize, 0);
1209 free(outbuf);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001210 }
Miklos Szeredi5e183482001-10-31 14:52:35 +00001211}
Miklos Szeredib483c932001-10-29 14:57:57 +00001212
Miklos Szeredia181e612001-11-06 12:03:23 +00001213static void do_write(struct fuse *f, struct fuse_in_header *in,
1214 struct fuse_write_in *arg)
1215{
1216 int res;
1217 char *path;
Miklos Szerediad051c32004-07-02 09:22:50 +00001218 struct fuse_write_out outarg;
Miklos Szeredifb28c5e2004-11-26 12:15:06 +00001219 struct fuse_file_info fi;
1220
1221 memset(&fi, 0, sizeof(fi));
1222 fi.fh = arg->fh;
Miklos Szeredia181e612001-11-06 12:03:23 +00001223
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001224 res = -ENOENT;
Miklos Szeredia13d9002004-11-02 17:32:03 +00001225 path = get_path(f, in->nodeid);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001226 if (path != NULL) {
1227 if (f->flags & FUSE_DEBUG) {
Miklos Szeredi1eea0322004-09-27 18:50:11 +00001228 printf("WRITE%s[%lu] %u bytes to %llu\n",
Miklos Szeredi209f5d02004-07-24 19:56:16 +00001229 arg->writepage ? "PAGE" : "", arg->fh, arg->size,
1230 arg->offset);
Miklos Szeredi6ebe2342002-01-06 21:44:16 +00001231 fflush(stdout);
1232 }
1233
Miklos Szeredia181e612001-11-06 12:03:23 +00001234 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001235 if (f->op.write)
Miklos Szeredifb28c5e2004-11-26 12:15:06 +00001236 res = f->op.write(path, PARAM(arg), arg->size, arg->offset, &fi);
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001237 free(path);
Miklos Szeredia181e612001-11-06 12:03:23 +00001238 }
1239
Miklos Szerediad051c32004-07-02 09:22:50 +00001240 if (res >= 0) {
1241 outarg.size = res;
1242 res = 0;
Miklos Szeredia181e612001-11-06 12:03:23 +00001243 }
1244
Miklos Szerediad051c32004-07-02 09:22:50 +00001245 send_reply(f, in, res, &outarg, sizeof(outarg));
Miklos Szeredia181e612001-11-06 12:03:23 +00001246}
1247
Miklos Szeredi77f39942004-03-25 11:17:52 +00001248static int default_statfs(struct statfs *buf)
1249{
1250 buf->f_namelen = 255;
1251 buf->f_bsize = 512;
1252 return 0;
1253}
1254
Miklos Szeredi18e75e42004-02-19 14:23:27 +00001255static void convert_statfs(struct statfs *statfs, struct fuse_kstatfs *kstatfs)
1256{
1257 kstatfs->bsize = statfs->f_bsize;
1258 kstatfs->blocks = statfs->f_blocks;
1259 kstatfs->bfree = statfs->f_bfree;
1260 kstatfs->bavail = statfs->f_bavail;
1261 kstatfs->files = statfs->f_files;
1262 kstatfs->ffree = statfs->f_ffree;
1263 kstatfs->namelen = statfs->f_namelen;
1264}
1265
Mark Glinesd84b39a2002-01-07 16:32:02 +00001266static void do_statfs(struct fuse *f, struct fuse_in_header *in)
1267{
1268 int res;
Mark Glinesd84b39a2002-01-07 16:32:02 +00001269 struct fuse_statfs_out arg;
Miklos Szeredi18e75e42004-02-19 14:23:27 +00001270 struct statfs buf;
Mark Glinesd84b39a2002-01-07 16:32:02 +00001271
Miklos Szeredi77f39942004-03-25 11:17:52 +00001272 memset(&buf, 0, sizeof(struct statfs));
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001273 if (f->op.statfs)
Miklos Szeredi18e75e42004-02-19 14:23:27 +00001274 res = f->op.statfs("/", &buf);
Miklos Szeredi77f39942004-03-25 11:17:52 +00001275 else
1276 res = default_statfs(&buf);
1277
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001278 if (res == 0)
Miklos Szeredi77f39942004-03-25 11:17:52 +00001279 convert_statfs(&buf, &arg.st);
Miklos Szeredi4b2bef42002-01-09 12:23:27 +00001280
Mark Glinesd84b39a2002-01-07 16:32:02 +00001281 send_reply(f, in, res, &arg, sizeof(arg));
1282}
1283
Miklos Szeredi5e43f2c2003-12-12 14:06:41 +00001284static void do_fsync(struct fuse *f, struct fuse_in_header *in,
1285 struct fuse_fsync_in *inarg)
1286{
1287 int res;
1288 char *path;
Miklos Szeredifb28c5e2004-11-26 12:15:06 +00001289 struct fuse_file_info fi;
1290
1291 memset(&fi, 0, sizeof(fi));
1292 fi.fh = inarg->fh;
Miklos Szeredi5e43f2c2003-12-12 14:06:41 +00001293
1294 res = -ENOENT;
Miklos Szeredia13d9002004-11-02 17:32:03 +00001295 path = get_path(f, in->nodeid);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001296 if (path != NULL) {
Miklos Szeredi209f5d02004-07-24 19:56:16 +00001297 if (f->flags & FUSE_DEBUG) {
Miklos Szeredi1eea0322004-09-27 18:50:11 +00001298 printf("FSYNC[%lu]\n", inarg->fh);
Miklos Szeredi209f5d02004-07-24 19:56:16 +00001299 fflush(stdout);
1300 }
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001301 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001302 if (f->op.fsync)
Miklos Szeredifb28c5e2004-11-26 12:15:06 +00001303 res = f->op.fsync(path, inarg->datasync, &fi);
Miklos Szeredi5e43f2c2003-12-12 14:06:41 +00001304 free(path);
1305 }
1306 send_reply(f, in, res, NULL, 0);
1307}
1308
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001309static void do_setxattr(struct fuse *f, struct fuse_in_header *in,
1310 struct fuse_setxattr_in *arg)
1311{
1312 int res;
1313 char *path;
1314 char *name = PARAM(arg);
1315 unsigned char *value = name + strlen(name) + 1;
1316
1317 res = -ENOENT;
Miklos Szeredia13d9002004-11-02 17:32:03 +00001318 path = get_path(f, in->nodeid);
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001319 if (path != NULL) {
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001320 res = -ENOSYS;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001321 if (f->op.setxattr)
1322 res = f->op.setxattr(path, name, value, arg->size, arg->flags);
1323 free(path);
1324 }
1325 send_reply(f, in, res, NULL, 0);
1326}
1327
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001328static int common_getxattr(struct fuse *f, struct fuse_in_header *in,
1329 const char *name, char *value, size_t size)
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001330{
1331 int res;
1332 char *path;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001333
1334 res = -ENOENT;
Miklos Szeredia13d9002004-11-02 17:32:03 +00001335 path = get_path(f, in->nodeid);
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001336 if (path != NULL) {
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001337 res = -ENOSYS;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001338 if (f->op.getxattr)
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001339 res = f->op.getxattr(path, name, value, size);
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001340 free(path);
1341 }
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001342 return res;
1343}
1344
1345static void do_getxattr_read(struct fuse *f, struct fuse_in_header *in,
1346 const char *name, size_t size)
1347{
1348 int res;
1349 char *outbuf = (char *) malloc(sizeof(struct fuse_out_header) + size);
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001350 if (outbuf == NULL)
1351 send_reply(f, in, -ENOMEM, NULL, 0);
1352 else {
1353 struct fuse_out_header *out = (struct fuse_out_header *) outbuf;
1354 char *value = outbuf + sizeof(struct fuse_out_header);
1355
1356 res = common_getxattr(f, in, name, value, size);
1357 size = 0;
1358 if (res > 0) {
1359 size = res;
1360 res = 0;
1361 }
1362 memset(out, 0, sizeof(struct fuse_out_header));
1363 out->unique = in->unique;
1364 out->error = res;
1365
1366 send_reply_raw(f, outbuf, sizeof(struct fuse_out_header) + size, 0);
1367 free(outbuf);
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001368 }
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001369}
1370
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001371static void do_getxattr_size(struct fuse *f, struct fuse_in_header *in,
1372 const char *name)
1373{
1374 int res;
1375 struct fuse_getxattr_out arg;
1376
1377 res = common_getxattr(f, in, name, NULL, 0);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001378 if (res >= 0) {
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001379 arg.size = res;
1380 res = 0;
1381 }
1382 send_reply(f, in, res, &arg, sizeof(arg));
1383}
1384
1385static void do_getxattr(struct fuse *f, struct fuse_in_header *in,
1386 struct fuse_getxattr_in *arg)
1387{
1388 char *name = PARAM(arg);
1389
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001390 if (arg->size)
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001391 do_getxattr_read(f, in, name, arg->size);
1392 else
1393 do_getxattr_size(f, in, name);
1394}
1395
1396static int common_listxattr(struct fuse *f, struct fuse_in_header *in,
1397 char *list, size_t size)
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001398{
1399 int res;
1400 char *path;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001401
1402 res = -ENOENT;
Miklos Szeredia13d9002004-11-02 17:32:03 +00001403 path = get_path(f, in->nodeid);
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001404 if (path != NULL) {
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001405 res = -ENOSYS;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001406 if (f->op.listxattr)
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001407 res = f->op.listxattr(path, list, size);
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001408 free(path);
1409 }
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001410 return res;
1411}
1412
1413static void do_listxattr_read(struct fuse *f, struct fuse_in_header *in,
1414 size_t size)
1415{
1416 int res;
1417 char *outbuf = (char *) malloc(sizeof(struct fuse_out_header) + size);
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001418 if (outbuf == NULL)
1419 send_reply(f, in, -ENOMEM, NULL, 0);
1420 else {
1421 struct fuse_out_header *out = (struct fuse_out_header *) outbuf;
1422 char *list = outbuf + sizeof(struct fuse_out_header);
1423
1424 res = common_listxattr(f, in, list, size);
1425 size = 0;
1426 if (res > 0) {
1427 size = res;
1428 res = 0;
1429 }
1430 memset(out, 0, sizeof(struct fuse_out_header));
1431 out->unique = in->unique;
1432 out->error = res;
1433
1434 send_reply_raw(f, outbuf, sizeof(struct fuse_out_header) + size, 0);
1435 free(outbuf);
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001436 }
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001437}
1438
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001439static void do_listxattr_size(struct fuse *f, struct fuse_in_header *in)
1440{
1441 int res;
1442 struct fuse_getxattr_out arg;
1443
1444 res = common_listxattr(f, in, NULL, 0);
1445 if (res >= 0) {
1446 arg.size = res;
1447 res = 0;
1448 }
1449 send_reply(f, in, res, &arg, sizeof(arg));
1450}
1451
1452static void do_listxattr(struct fuse *f, struct fuse_in_header *in,
1453 struct fuse_getxattr_in *arg)
1454{
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001455 if (arg->size)
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001456 do_listxattr_read(f, in, arg->size);
1457 else
1458 do_listxattr_size(f, in);
1459}
1460
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001461static void do_removexattr(struct fuse *f, struct fuse_in_header *in,
1462 char *name)
1463{
1464 int res;
1465 char *path;
1466
1467 res = -ENOENT;
Miklos Szeredia13d9002004-11-02 17:32:03 +00001468 path = get_path(f, in->nodeid);
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001469 if (path != NULL) {
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001470 res = -ENOSYS;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001471 if (f->op.removexattr)
1472 res = f->op.removexattr(path, name);
1473 free(path);
1474 }
1475 send_reply(f, in, res, NULL, 0);
1476}
1477
1478
Miklos Szeredi43696432001-11-18 19:15:05 +00001479static void free_cmd(struct fuse_cmd *cmd)
1480{
1481 free(cmd->buf);
1482 free(cmd);
1483}
1484
Miklos Szeredifff56ab2001-11-16 10:12:59 +00001485void __fuse_process_cmd(struct fuse *f, struct fuse_cmd *cmd)
Miklos Szeredia181e612001-11-06 12:03:23 +00001486{
Miklos Szeredia181e612001-11-06 12:03:23 +00001487 struct fuse_in_header *in = (struct fuse_in_header *) cmd->buf;
1488 void *inarg = cmd->buf + sizeof(struct fuse_in_header);
1489 size_t argsize;
Miklos Szeredid169f312004-09-22 08:48:26 +00001490 struct fuse_context *ctx = fuse_get_context();
Miklos Szeredia181e612001-11-06 12:03:23 +00001491
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +00001492 dec_avail(f);
Miklos Szeredi33232032001-11-19 17:55:51 +00001493
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001494 if ((f->flags & FUSE_DEBUG)) {
Miklos Szeredia13d9002004-11-02 17:32:03 +00001495 printf("unique: %i, opcode: %s (%i), nodeid: %li, insize: %i\n",
1496 in->unique, opname(in->opcode), in->opcode, in->nodeid,
Miklos Szeredic8ba2372002-12-10 12:26:00 +00001497 cmd->buflen);
Miklos Szeredic0938ea2001-11-07 12:35:06 +00001498 fflush(stdout);
1499 }
Miklos Szeredife25def2001-12-20 15:38:05 +00001500
Miklos Szeredid169f312004-09-22 08:48:26 +00001501 ctx->fuse = f;
Miklos Szeredife25def2001-12-20 15:38:05 +00001502 ctx->uid = in->uid;
1503 ctx->gid = in->gid;
Miklos Szeredi1f18db52004-09-27 06:54:49 +00001504 ctx->pid = in->pid;
Miklos Szeredia181e612001-11-06 12:03:23 +00001505
1506 argsize = cmd->buflen - sizeof(struct fuse_in_header);
1507
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001508 switch (in->opcode) {
Miklos Szeredia181e612001-11-06 12:03:23 +00001509 case FUSE_LOOKUP:
1510 do_lookup(f, in, (char *) inarg);
1511 break;
1512
Miklos Szeredia181e612001-11-06 12:03:23 +00001513 case FUSE_GETATTR:
1514 do_getattr(f, in);
1515 break;
1516
1517 case FUSE_SETATTR:
1518 do_setattr(f, in, (struct fuse_setattr_in *) inarg);
1519 break;
1520
1521 case FUSE_READLINK:
1522 do_readlink(f, in);
1523 break;
1524
1525 case FUSE_GETDIR:
1526 do_getdir(f, in);
1527 break;
1528
1529 case FUSE_MKNOD:
1530 do_mknod(f, in, (struct fuse_mknod_in *) inarg);
1531 break;
1532
1533 case FUSE_MKDIR:
1534 do_mkdir(f, in, (struct fuse_mkdir_in *) inarg);
1535 break;
1536
1537 case FUSE_UNLINK:
Miklos Szeredib5958612004-02-20 14:10:49 +00001538 do_unlink(f, in, (char *) inarg);
1539 break;
1540
Miklos Szeredia181e612001-11-06 12:03:23 +00001541 case FUSE_RMDIR:
Miklos Szeredib5958612004-02-20 14:10:49 +00001542 do_rmdir(f, in, (char *) inarg);
Miklos Szeredia181e612001-11-06 12:03:23 +00001543 break;
1544
1545 case FUSE_SYMLINK:
1546 do_symlink(f, in, (char *) inarg,
1547 ((char *) inarg) + strlen((char *) inarg) + 1);
1548 break;
1549
1550 case FUSE_RENAME:
1551 do_rename(f, in, (struct fuse_rename_in *) inarg);
1552 break;
1553
1554 case FUSE_LINK:
1555 do_link(f, in, (struct fuse_link_in *) inarg);
1556 break;
1557
1558 case FUSE_OPEN:
1559 do_open(f, in, (struct fuse_open_in *) inarg);
1560 break;
1561
Miklos Szeredie2e4ac22004-05-18 08:45:28 +00001562 case FUSE_FLUSH:
Miklos Szeredi209f5d02004-07-24 19:56:16 +00001563 do_flush(f, in, (struct fuse_flush_in *) inarg);
Miklos Szeredie2e4ac22004-05-18 08:45:28 +00001564 break;
1565
Miklos Szeredi9478e862002-12-11 09:50:26 +00001566 case FUSE_RELEASE:
Miklos Szeredi209f5d02004-07-24 19:56:16 +00001567 do_release(f, in, (struct fuse_release_in *) inarg);
Miklos Szeredi9478e862002-12-11 09:50:26 +00001568 break;
1569
Miklos Szeredia181e612001-11-06 12:03:23 +00001570 case FUSE_READ:
1571 do_read(f, in, (struct fuse_read_in *) inarg);
1572 break;
1573
1574 case FUSE_WRITE:
1575 do_write(f, in, (struct fuse_write_in *) inarg);
1576 break;
1577
Mark Glinesd84b39a2002-01-07 16:32:02 +00001578 case FUSE_STATFS:
1579 do_statfs(f, in);
1580 break;
1581
Miklos Szeredi5e43f2c2003-12-12 14:06:41 +00001582 case FUSE_FSYNC:
1583 do_fsync(f, in, (struct fuse_fsync_in *) inarg);
1584 break;
1585
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001586 case FUSE_SETXATTR:
1587 do_setxattr(f, in, (struct fuse_setxattr_in *) inarg);
1588 break;
1589
1590 case FUSE_GETXATTR:
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001591 do_getxattr(f, in, (struct fuse_getxattr_in *) inarg);
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001592 break;
1593
1594 case FUSE_LISTXATTR:
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001595 do_listxattr(f, in, (struct fuse_getxattr_in *) inarg);
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001596 break;
1597
1598 case FUSE_REMOVEXATTR:
1599 do_removexattr(f, in, (char *) inarg);
1600 break;
1601
Miklos Szeredia181e612001-11-06 12:03:23 +00001602 default:
Miklos Szeredi43696432001-11-18 19:15:05 +00001603 send_reply(f, in, -ENOSYS, NULL, 0);
Miklos Szeredia181e612001-11-06 12:03:23 +00001604 }
Miklos Szeredi43696432001-11-18 19:15:05 +00001605
1606 free_cmd(cmd);
Miklos Szeredia181e612001-11-06 12:03:23 +00001607}
1608
Miklos Szeredi65cf7c72004-06-30 11:34:56 +00001609int __fuse_exited(struct fuse* f)
1610{
1611 return f->exited;
1612}
1613
Miklos Szeredifff56ab2001-11-16 10:12:59 +00001614struct fuse_cmd *__fuse_read_cmd(struct fuse *f)
Miklos Szeredi2df1c042001-11-06 15:07:17 +00001615{
Miklos Szeredifff56ab2001-11-16 10:12:59 +00001616 ssize_t res;
Miklos Szeredifff56ab2001-11-16 10:12:59 +00001617 struct fuse_cmd *cmd;
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +00001618 struct fuse_in_header *in;
1619 void *inarg;
Miklos Szeredifff56ab2001-11-16 10:12:59 +00001620
Miklos Szeredi43696432001-11-18 19:15:05 +00001621 cmd = (struct fuse_cmd *) malloc(sizeof(struct fuse_cmd));
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001622 if (cmd == NULL) {
1623 fprintf(stderr, "fuse: failed to allocate cmd in read\n");
1624 return NULL;
1625 }
Miklos Szeredi43696432001-11-18 19:15:05 +00001626 cmd->buf = (char *) malloc(FUSE_MAX_IN);
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001627 if (cmd->buf == NULL) {
1628 fprintf(stderr, "fuse: failed to allocate read buffer\n");
1629 free(cmd);
1630 return NULL;
1631 }
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +00001632 in = (struct fuse_in_header *) cmd->buf;
1633 inarg = cmd->buf + sizeof(struct fuse_in_header);
Miklos Szeredi43696432001-11-18 19:15:05 +00001634
Miklos Szeredi65cf7c72004-06-30 11:34:56 +00001635 res = read(f->fd, cmd->buf, FUSE_MAX_IN);
1636 if (res == -1) {
1637 free_cmd(cmd);
1638 if (__fuse_exited(f) || errno == EINTR)
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +00001639 return NULL;
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +00001640
Miklos Szeredi65cf7c72004-06-30 11:34:56 +00001641 /* ENODEV means we got unmounted, so we silenty return failure */
1642 if (errno != ENODEV) {
1643 /* BAD... This will happen again */
1644 perror("fuse: reading device");
1645 }
1646
1647 fuse_exit(f);
1648 return NULL;
1649 }
1650 if ((size_t) res < sizeof(struct fuse_in_header)) {
1651 free_cmd(cmd);
1652 /* Cannot happen */
1653 fprintf(stderr, "short read on fuse device\n");
1654 fuse_exit(f);
1655 return NULL;
1656 }
1657 cmd->buflen = res;
1658
1659 /* Forget is special, it can be done without messing with threads. */
1660 if (in->opcode == FUSE_FORGET) {
1661 do_forget(f, in, (struct fuse_forget_in *) inarg);
1662 free_cmd(cmd);
1663 return NULL;
1664 }
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +00001665
Miklos Szeredifff56ab2001-11-16 10:12:59 +00001666 return cmd;
Miklos Szeredi2df1c042001-11-06 15:07:17 +00001667}
1668
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001669int fuse_loop(struct fuse *f)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001670{
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001671 if (f == NULL)
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001672 return -1;
Miklos Szeredic40748a2004-02-20 16:38:45 +00001673
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001674 while (1) {
Miklos Szeredi0f48a262002-12-05 14:23:01 +00001675 struct fuse_cmd *cmd;
1676
Miklos Szeredi65cf7c72004-06-30 11:34:56 +00001677 if (__fuse_exited(f))
Miklos Szeredi874e3c12004-11-01 23:15:20 +00001678 break;
Miklos Szeredi0f48a262002-12-05 14:23:01 +00001679
1680 cmd = __fuse_read_cmd(f);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001681 if (cmd == NULL)
Miklos Szeredi0f48a262002-12-05 14:23:01 +00001682 continue;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001683
Miklos Szeredifff56ab2001-11-16 10:12:59 +00001684 __fuse_process_cmd(f, cmd);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001685 }
Miklos Szeredi874e3c12004-11-01 23:15:20 +00001686 f->exited = 0;
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001687 return 0;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001688}
1689
Miklos Szeredi891b8742004-07-29 09:27:49 +00001690int fuse_invalidate(struct fuse *f, const char *path)
1691{
1692 int res;
1693 int err;
Miklos Szeredia13d9002004-11-02 17:32:03 +00001694 nodeid_t nodeid;
1695 unsigned long ino;
Miklos Szeredi891b8742004-07-29 09:27:49 +00001696 struct fuse_user_header h;
1697
Miklos Szeredia13d9002004-11-02 17:32:03 +00001698 err = path_lookup(f, path, &nodeid, &ino);
Miklos Szeredi891b8742004-07-29 09:27:49 +00001699 if (err) {
1700 if (err == -ENOENT)
1701 return 0;
1702 else
1703 return err;
1704 }
1705
1706 memset(&h, 0, sizeof(struct fuse_user_header));
1707 h.opcode = FUSE_INVALIDATE;
Miklos Szeredia13d9002004-11-02 17:32:03 +00001708 h.nodeid = nodeid;
Miklos Szeredi891b8742004-07-29 09:27:49 +00001709 h.ino = ino;
1710
1711 if ((f->flags & FUSE_DEBUG)) {
Miklos Szeredia13d9002004-11-02 17:32:03 +00001712 printf("INVALIDATE nodeid: %li\n", nodeid);
Miklos Szeredi891b8742004-07-29 09:27:49 +00001713 fflush(stdout);
1714 }
1715
1716 res = write(f->fd, &h, sizeof(struct fuse_user_header));
1717 if (res == -1) {
1718 if (errno != ENOENT) {
1719 perror("fuse: writing device");
1720 return -errno;
1721 }
1722 }
1723 return 0;
1724}
1725
Miklos Szeredi0f48a262002-12-05 14:23:01 +00001726void fuse_exit(struct fuse *f)
1727{
1728 f->exited = 1;
1729}
1730
Miklos Szeredid169f312004-09-22 08:48:26 +00001731struct fuse_context *fuse_get_context()
Miklos Szeredi2e50d432001-12-20 12:17:25 +00001732{
Miklos Szeredid169f312004-09-22 08:48:26 +00001733 static struct fuse_context context;
1734 if (fuse_getcontext)
1735 return fuse_getcontext();
Miklos Szeredi2e50d432001-12-20 12:17:25 +00001736 else
Miklos Szeredid169f312004-09-22 08:48:26 +00001737 return &context;
1738}
1739
1740void __fuse_set_getcontext_func(struct fuse_context *(*func)(void))
1741{
1742 fuse_getcontext = func;
Miklos Szeredi2e50d432001-12-20 12:17:25 +00001743}
1744
Miklos Szeredic40748a2004-02-20 16:38:45 +00001745static int check_version(struct fuse *f)
1746{
1747 int res;
Miklos Szeredi162bcbb2004-11-29 23:43:44 +00001748 const char *version_file = FUSE_VERSION_FILE_NEW;
Miklos Szeredif3845c42004-11-20 11:18:34 +00001749 FILE *vf = fopen(version_file, "r");
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001750 if (vf == NULL) {
Miklos Szeredia25d4c22004-11-23 22:32:16 +00001751 version_file = FUSE_VERSION_FILE_OLD;
Miklos Szeredif3845c42004-11-20 11:18:34 +00001752 vf = fopen(version_file, "r");
1753 if (vf == NULL) {
Miklos Szeredia25d4c22004-11-23 22:32:16 +00001754 struct stat tmp;
1755 if (stat(FUSE_DEV_OLD, &tmp) != -1) {
1756 fprintf(stderr, "fuse: kernel interface too old, need >= %i.%i\n",
1757 FUSE_KERNEL_VERSION, FUSE_KERNEL_MINOR_VERSION);
1758 return -1;
1759 } else {
1760 fprintf(stderr, "fuse: warning: version of kernel interface unknown\n");
1761 return 0;
1762 }
Miklos Szeredif3845c42004-11-20 11:18:34 +00001763 }
Miklos Szeredic40748a2004-02-20 16:38:45 +00001764 }
1765 res = fscanf(vf, "%i.%i", &f->majorver, &f->minorver);
1766 fclose(vf);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001767 if (res != 2) {
Miklos Szeredif3845c42004-11-20 11:18:34 +00001768 fprintf(stderr, "fuse: error reading %s\n", version_file);
Miklos Szeredic40748a2004-02-20 16:38:45 +00001769 return -1;
1770 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001771 if (f->majorver != FUSE_KERNEL_VERSION) {
Miklos Szeredic40748a2004-02-20 16:38:45 +00001772 fprintf(stderr, "fuse: bad kernel interface major version: needs %i\n",
1773 FUSE_KERNEL_VERSION);
1774 return -1;
1775 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001776 if (f->minorver < FUSE_KERNEL_MINOR_VERSION) {
Miklos Szeredi256739a2004-11-20 12:22:37 +00001777 fprintf(stderr, "fuse: kernel interface too old: need >= %i.%i\n",
Miklos Szeredic40748a2004-02-20 16:38:45 +00001778 FUSE_KERNEL_VERSION, FUSE_KERNEL_MINOR_VERSION);
1779 return -1;
1780 }
1781
1782 return 0;
1783}
1784
Miklos Szeredibd7661b2004-07-23 17:16:29 +00001785
1786int fuse_is_lib_option(const char *opt)
1787{
1788 if (strcmp(opt, "debug") == 0 ||
Miklos Szeredia13d9002004-11-02 17:32:03 +00001789 strcmp(opt, "hard_remove") == 0 ||
1790 strcmp(opt, "use_ino") == 0)
Miklos Szeredibd7661b2004-07-23 17:16:29 +00001791 return 1;
1792 else
1793 return 0;
1794}
1795
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001796static int parse_lib_opts(struct fuse *f, const char *opts)
Miklos Szeredibd7661b2004-07-23 17:16:29 +00001797{
1798 if (opts) {
1799 char *xopts = strdup(opts);
1800 char *s = xopts;
1801 char *opt;
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001802
1803 if (xopts == NULL)
1804 return -1;
Miklos Szeredibd7661b2004-07-23 17:16:29 +00001805
1806 while((opt = strsep(&s, ","))) {
1807 if (strcmp(opt, "debug") == 0)
1808 f->flags |= FUSE_DEBUG;
1809 else if (strcmp(opt, "hard_remove") == 0)
1810 f->flags |= FUSE_HARD_REMOVE;
Miklos Szeredia13d9002004-11-02 17:32:03 +00001811 else if (strcmp(opt, "use_ino") == 0)
1812 f->flags |= FUSE_USE_INO;
Miklos Szeredibd7661b2004-07-23 17:16:29 +00001813 else
1814 fprintf(stderr, "fuse: warning: unknown option `%s'\n", opt);
1815 }
1816 free(xopts);
1817 }
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001818 return 0;
Miklos Szeredibd7661b2004-07-23 17:16:29 +00001819}
1820
1821struct fuse *fuse_new(int fd, const char *opts, const struct fuse_operations *op)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001822{
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001823 struct fuse *f;
1824 struct node *root;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001825
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001826 f = (struct fuse *) calloc(1, sizeof(struct fuse));
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001827 if (f == NULL)
1828 goto out;
Miklos Szeredi2df1c042001-11-06 15:07:17 +00001829
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001830 if (check_version(f) == -1)
1831 goto out_free;
Miklos Szeredic40748a2004-02-20 16:38:45 +00001832
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001833 if (parse_lib_opts(f, opts) == -1)
1834 goto out_free;
1835
Miklos Szeredi8cffdb92001-11-09 14:49:18 +00001836 f->fd = fd;
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001837 f->ctr = 0;
Miklos Szeredi76f65782004-02-19 16:55:40 +00001838 f->generation = 0;
Miklos Szeredifff56ab2001-11-16 10:12:59 +00001839 /* FIXME: Dynamic hash table */
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001840 f->name_table_size = 14057;
1841 f->name_table = (struct node **)
1842 calloc(1, sizeof(struct node *) * f->name_table_size);
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001843 if (f->name_table == NULL)
1844 goto out_free;
1845
Miklos Szeredia13d9002004-11-02 17:32:03 +00001846 f->id_table_size = 14057;
1847 f->id_table = (struct node **)
1848 calloc(1, sizeof(struct node *) * f->id_table_size);
1849 if (f->id_table == NULL)
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001850 goto out_free_name_table;
1851
Miklos Szeredia25d4c22004-11-23 22:32:16 +00001852#ifndef USE_UCLIBC
1853 pthread_mutex_init(&f->lock, NULL);
1854#else
1855 {
1856 pthread_mutexattr_t attr;
1857 pthread_mutexattr_init(&attr);
1858 pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ADAPTIVE_NP);
1859 pthread_mutex_init(&f->lock, &attr);
1860 pthread_mutexattr_destroy(&attr);
1861 }
1862#endif
Miklos Szeredi33232032001-11-19 17:55:51 +00001863 f->numworker = 0;
1864 f->numavail = 0;
Miklos Szeredi2e50d432001-12-20 12:17:25 +00001865 f->op = *op;
Miklos Szeredi0f48a262002-12-05 14:23:01 +00001866 f->exited = 0;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001867
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001868 root = (struct node *) calloc(1, sizeof(struct node));
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001869 if (root == NULL)
Miklos Szeredia13d9002004-11-02 17:32:03 +00001870 goto out_free_id_table;
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001871
Miklos Szeredi8cffdb92001-11-09 14:49:18 +00001872 root->mode = 0;
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001873 root->rdev = 0;
1874 root->name = strdup("/");
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001875 if (root->name == NULL)
1876 goto out_free_root;
1877
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001878 root->parent = 0;
Miklos Szeredia13d9002004-11-02 17:32:03 +00001879 root->nodeid = FUSE_ROOT_ID;
Miklos Szeredi76f65782004-02-19 16:55:40 +00001880 root->generation = 0;
Miklos Szeredia13d9002004-11-02 17:32:03 +00001881 hash_id(f, root);
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001882
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001883 return f;
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001884
1885 out_free_root:
1886 free(root);
Miklos Szeredia13d9002004-11-02 17:32:03 +00001887 out_free_id_table:
1888 free(f->id_table);
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001889 out_free_name_table:
1890 free(f->name_table);
1891 out_free:
1892 free(f);
1893 out:
1894 fprintf(stderr, "fuse: failed to allocate fuse object\n");
1895 return NULL;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001896}
1897
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001898void fuse_destroy(struct fuse *f)
1899{
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001900 size_t i;
Miklos Szeredia13d9002004-11-02 17:32:03 +00001901 for (i = 0; i < f->id_table_size; i++) {
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001902 struct node *node;
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001903
Miklos Szeredia13d9002004-11-02 17:32:03 +00001904 for (node = f->id_table[i]; node != NULL; node = node->id_next) {
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001905 if (node->is_hidden) {
Miklos Szeredia13d9002004-11-02 17:32:03 +00001906 char *path = get_path(f, node->nodeid);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001907 if (path)
1908 f->op.unlink(path);
1909 }
1910 }
1911 }
Miklos Szeredia13d9002004-11-02 17:32:03 +00001912 for (i = 0; i < f->id_table_size; i++) {
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001913 struct node *node;
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001914 struct node *next;
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001915
Miklos Szeredia13d9002004-11-02 17:32:03 +00001916 for (node = f->id_table[i]; node != NULL; node = next) {
1917 next = node->id_next;
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001918 free_node(node);
1919 }
1920 }
Miklos Szeredia13d9002004-11-02 17:32:03 +00001921 free(f->id_table);
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001922 free(f->name_table);
Miklos Szeredia181e612001-11-06 12:03:23 +00001923 pthread_mutex_destroy(&f->lock);
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001924 free(f);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001925}