blob: 2b7947944f00ef2535f174d485fc66d7f3e93ee8 [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
Miklos Szeredicb264512004-06-23 18:52:50 +00009#include <config.h>
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000010#include "fuse_i.h"
11#include <linux/fuse.h>
12
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 Szeredi97c61e92001-11-07 12:09:43 +000020#define FUSE_MAX_PATH 4096
Miklos Szeredi6bf8b682002-10-28 08:49:39 +000021#define PARAM(inarg) (((char *)(inarg)) + sizeof(*inarg))
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000022
Miklos Szeredi254d5ed2004-03-02 11:11:24 +000023#define ENTRY_REVALIDATE_TIME 1 /* sec */
24#define ATTR_REVALIDATE_TIME 1 /* sec */
25
Miklos Szeredic8ba2372002-12-10 12:26:00 +000026static const char *opname(enum fuse_opcode opcode)
27{
Miklos Szeredi7eafcce2004-06-19 22:42:38 +000028 switch (opcode) {
Miklos Szeredi3ed84232004-03-30 15:17:26 +000029 case FUSE_LOOKUP: return "LOOKUP";
30 case FUSE_FORGET: return "FORGET";
31 case FUSE_GETATTR: return "GETATTR";
32 case FUSE_SETATTR: return "SETATTR";
33 case FUSE_READLINK: return "READLINK";
34 case FUSE_SYMLINK: return "SYMLINK";
35 case FUSE_GETDIR: return "GETDIR";
36 case FUSE_MKNOD: return "MKNOD";
37 case FUSE_MKDIR: return "MKDIR";
38 case FUSE_UNLINK: return "UNLINK";
39 case FUSE_RMDIR: return "RMDIR";
40 case FUSE_RENAME: return "RENAME";
41 case FUSE_LINK: return "LINK";
42 case FUSE_OPEN: return "OPEN";
43 case FUSE_READ: return "READ";
44 case FUSE_WRITE: return "WRITE";
45 case FUSE_STATFS: return "STATFS";
Miklos Szeredi99f20742004-05-19 08:01:10 +000046 case FUSE_FLUSH: return "FLUSH";
Miklos Szeredi3ed84232004-03-30 15:17:26 +000047 case FUSE_RELEASE: return "RELEASE";
48 case FUSE_FSYNC: return "FSYNC";
49 case FUSE_SETXATTR: return "SETXATTR";
50 case FUSE_GETXATTR: return "GETXATTR";
51 case FUSE_LISTXATTR: return "LISTXATTR";
52 case FUSE_REMOVEXATTR: return "REMOVEXATTR";
Miklos Szeredi99f20742004-05-19 08:01:10 +000053 default: return "???";
Miklos Szeredic8ba2372002-12-10 12:26:00 +000054 }
55}
56
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +000057static inline void inc_avail(struct fuse *f)
58{
59 pthread_mutex_lock(&f->lock);
60 f->numavail ++;
61 pthread_mutex_unlock(&f->lock);
62}
63
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 Szeredi97c61e92001-11-07 12:09:43 +000071static struct node *__get_node(struct fuse *f, fino_t ino)
Miklos Szeredia181e612001-11-06 12:03:23 +000072{
Miklos Szeredi97c61e92001-11-07 12:09:43 +000073 size_t hash = ino % f->ino_table_size;
74 struct node *node;
75
Miklos Szeredi7eafcce2004-06-19 22:42:38 +000076 for (node = f->ino_table[hash]; node != NULL; node = node->ino_next)
77 if (node->ino == ino)
Miklos Szeredi97c61e92001-11-07 12:09:43 +000078 return node;
79
80 return NULL;
Miklos Szeredia181e612001-11-06 12:03:23 +000081}
82
Miklos Szeredi97c61e92001-11-07 12:09:43 +000083static struct node *get_node(struct fuse *f, fino_t ino)
Miklos Szeredia181e612001-11-06 12:03:23 +000084{
Miklos Szeredi97c61e92001-11-07 12:09:43 +000085 struct node *node = __get_node(f, ino);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +000086 if (node != NULL)
Miklos Szeredi97c61e92001-11-07 12:09:43 +000087 return node;
88
89 fprintf(stderr, "fuse internal error: inode %lu not found\n", ino);
90 abort();
Miklos Szeredia181e612001-11-06 12:03:23 +000091}
92
Miklos Szeredi76f65782004-02-19 16:55:40 +000093static void hash_ino(struct fuse *f, struct node *node)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000094{
Miklos Szeredi76f65782004-02-19 16:55:40 +000095 size_t hash = node->ino % f->ino_table_size;
Miklos Szeredi97c61e92001-11-07 12:09:43 +000096 node->ino_next = f->ino_table[hash];
97 f->ino_table[hash] = node;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000098}
99
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000100static void unhash_ino(struct fuse *f, struct node *node)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000101{
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000102 size_t hash = node->ino % f->ino_table_size;
103 struct node **nodep = &f->ino_table[hash];
104
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000105 for (; *nodep != NULL; nodep = &(*nodep)->ino_next)
106 if (*nodep == node) {
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000107 *nodep = node->ino_next;
108 return;
109 }
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000110}
111
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000112static fino_t next_ino(struct fuse *f)
113{
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
128static unsigned int name_hash(struct fuse *f, fino_t parent, const char *name)
129{
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 Szeredi1ea9c962004-06-24 21:00:00 +0000139static struct node *__lookup_node(struct fuse *f, fino_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 Szeredi1ea9c962004-06-24 21:00:00 +0000152static struct node *lookup_node(struct fuse *f, fino_t parent,
153 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 Szeredi97c61e92001-11-07 12:09:43 +0000168static void hash_name(struct fuse *f, struct node *node, fino_t parent,
Miklos Szeredia181e612001-11-06 12:03:23 +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);
174 node->name_next = f->name_table[hash];
175 f->name_table[hash] = node;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000176}
177
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000178static void unhash_name(struct fuse *f, struct node *node)
Miklos Szeredia181e612001-11-06 12:03:23 +0000179{
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000180 if (node->name != NULL) {
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000181 size_t hash = name_hash(f, node->parent, node->name);
182 struct node **nodep = &f->name_table[hash];
183
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000184 for (; *nodep != NULL; nodep = &(*nodep)->name_next)
185 if (*nodep == node) {
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000186 *nodep = node->name_next;
187 node->name_next = NULL;
188 free(node->name);
189 node->name = NULL;
190 node->parent = 0;
191 return;
192 }
193 fprintf(stderr, "fuse internal error: unable to unhash node: %lu\n",
194 node->ino);
195 abort();
Miklos Szeredia181e612001-11-06 12:03:23 +0000196 }
197}
198
Miklos Szeredi76f65782004-02-19 16:55:40 +0000199static struct node *find_node(struct fuse *f, fino_t parent, char *name,
200 struct fuse_attr *attr, int version)
Miklos Szeredi5e183482001-10-31 14:52:35 +0000201{
202 struct node *node;
Miklos Szeredia181e612001-11-06 12:03:23 +0000203 int mode = attr->mode & S_IFMT;
204 int rdev = 0;
205
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000206 if (S_ISCHR(mode) || S_ISBLK(mode))
Miklos Szeredia181e612001-11-06 12:03:23 +0000207 rdev = attr->rdev;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000208
Miklos Szeredia181e612001-11-06 12:03:23 +0000209 pthread_mutex_lock(&f->lock);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000210 node = __lookup_node(f, parent, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000211 if (node != NULL) {
212 if (node->mode == mode && node->rdev == rdev)
Miklos Szeredia181e612001-11-06 12:03:23 +0000213 goto out;
214
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000215 unhash_name(f, node);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000216 }
217
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000218 node = (struct node *) calloc(1, sizeof(struct node));
Miklos Szeredia181e612001-11-06 12:03:23 +0000219 node->mode = mode;
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000220 node->rdev = rdev;
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000221 node->open_count = 0;
222 node->is_hidden = 0;
Miklos Szeredi76f65782004-02-19 16:55:40 +0000223 node->ino = next_ino(f);
224 node->generation = f->generation;
225 hash_ino(f, node);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000226 hash_name(f, node, parent, name);
Miklos Szeredia181e612001-11-06 12:03:23 +0000227
228 out:
229 node->version = version;
230 pthread_mutex_unlock(&f->lock);
Miklos Szeredi76f65782004-02-19 16:55:40 +0000231 return node;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000232}
233
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000234static char *add_name(char *buf, char *s, const char *name)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000235{
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000236 size_t len = strlen(name);
237 s -= len;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000238 if (s <= buf) {
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000239 fprintf(stderr, "fuse: path too long: ...%s\n", s + len);
240 return NULL;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000241 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000242 strncpy(s, name, len);
243 s--;
244 *s = '/';
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000245
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000246 return s;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000247}
248
Miklos Szeredia181e612001-11-06 12:03:23 +0000249static char *get_path_name(struct fuse *f, fino_t ino, const char *name)
Miklos Szeredib483c932001-10-29 14:57:57 +0000250{
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000251 char buf[FUSE_MAX_PATH];
252 char *s = buf + FUSE_MAX_PATH - 1;
253 struct node *node;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000254
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000255 *s = '\0';
Miklos Szeredia181e612001-11-06 12:03:23 +0000256
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000257 if (name != NULL) {
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000258 s = add_name(buf, s, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000259 if (s == NULL)
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000260 return NULL;
261 }
262
263 pthread_mutex_lock(&f->lock);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000264 for (node = get_node(f, ino); node->ino != FUSE_ROOT_INO;
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000265 node = get_node(f, node->parent)) {
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000266 if (node->name == NULL) {
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000267 s = NULL;
268 break;
269 }
270
271 s = add_name(buf, s, node->name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000272 if (s == NULL)
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000273 break;
274 }
275 pthread_mutex_unlock(&f->lock);
276
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000277 if (s == NULL)
Miklos Szeredi5e183482001-10-31 14:52:35 +0000278 return NULL;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000279 else if (*s == '\0')
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000280 return strdup("/");
281 else
282 return strdup(s);
283}
Miklos Szeredia181e612001-11-06 12:03:23 +0000284
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000285static char *get_path(struct fuse *f, fino_t ino)
286{
287 return get_path_name(f, ino, NULL);
Miklos Szeredib483c932001-10-29 14:57:57 +0000288}
289
Miklos Szeredia181e612001-11-06 12:03:23 +0000290static void destroy_node(struct fuse *f, fino_t ino, int version)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000291{
Miklos Szeredia181e612001-11-06 12:03:23 +0000292 struct node *node;
293
294 pthread_mutex_lock(&f->lock);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000295 node = get_node(f, ino);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000296 if (node->version == version && ino != FUSE_ROOT_INO) {
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000297 unhash_name(f, node);
298 unhash_ino(f, node);
Miklos Szeredia181e612001-11-06 12:03:23 +0000299 free_node(node);
300 }
301 pthread_mutex_unlock(&f->lock);
302
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000303}
304
Miklos Szeredi5e183482001-10-31 14:52:35 +0000305static void remove_node(struct fuse *f, fino_t dir, const char *name)
306{
Miklos Szeredia181e612001-11-06 12:03:23 +0000307 struct node *node;
308
309 pthread_mutex_lock(&f->lock);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000310 node = __lookup_node(f, dir, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000311 if (node == NULL) {
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000312 fprintf(stderr, "fuse internal error: unable to remove node %lu/%s\n",
313 dir, name);
314 abort();
315 }
316 unhash_name(f, node);
Miklos Szeredia181e612001-11-06 12:03:23 +0000317 pthread_mutex_unlock(&f->lock);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000318}
319
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000320static int rename_node(struct fuse *f, fino_t olddir, const char *oldname,
321 fino_t newdir, const char *newname, int hide)
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000322{
Miklos Szeredia181e612001-11-06 12:03:23 +0000323 struct node *node;
324 struct node *newnode;
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000325 int err = 0;
Miklos Szeredia181e612001-11-06 12:03:23 +0000326
327 pthread_mutex_lock(&f->lock);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000328 node = __lookup_node(f, olddir, oldname);
329 newnode = __lookup_node(f, newdir, newname);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000330 if (node == NULL) {
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000331 fprintf(stderr, "fuse internal error: unable to rename node %lu/%s\n",
332 olddir, oldname);
333 abort();
334 }
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000335
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000336 if (newnode != NULL) {
337 if (hide) {
338 fprintf(stderr, "fuse: hidden file got created during hiding\n");
339 err = -1;
340 goto out;
341 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000342 unhash_name(f, newnode);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000343 }
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000344
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000345 unhash_name(f, node);
346 hash_name(f, node, newdir, newname);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000347 if (hide)
348 node->is_hidden = 1;
349
350 out:
Miklos Szeredia181e612001-11-06 12:03:23 +0000351 pthread_mutex_unlock(&f->lock);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000352 return err;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000353}
354
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000355static void convert_stat(struct stat *stbuf, struct fuse_attr *attr)
356{
Miklos Szeredib5958612004-02-20 14:10:49 +0000357 attr->mode = stbuf->st_mode;
358 attr->nlink = stbuf->st_nlink;
359 attr->uid = stbuf->st_uid;
360 attr->gid = stbuf->st_gid;
361 attr->rdev = stbuf->st_rdev;
362 attr->size = stbuf->st_size;
363 attr->blocks = stbuf->st_blocks;
364 attr->atime = stbuf->st_atime;
Miklos Szeredib5958612004-02-20 14:10:49 +0000365 attr->mtime = stbuf->st_mtime;
Miklos Szeredib5958612004-02-20 14:10:49 +0000366 attr->ctime = stbuf->st_ctime;
Miklos Szeredicb264512004-06-23 18:52:50 +0000367#ifdef HAVE_STRUCT_STAT_ST_ATIM
368 attr->atimensec = stbuf->st_atim.tv_nsec;
369 attr->mtimensec = stbuf->st_mtim.tv_nsec;
Miklos Szeredib5958612004-02-20 14:10:49 +0000370 attr->ctimensec = stbuf->st_ctim.tv_nsec;
Miklos Szeredicb264512004-06-23 18:52:50 +0000371#endif
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000372}
373
Miklos Szeredia181e612001-11-06 12:03:23 +0000374static int fill_dir(struct fuse_dirhandle *dh, char *name, int type)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000375{
376 struct fuse_dirent dirent;
377 size_t reclen;
378 size_t res;
379
Miklos Szeredi43696432001-11-18 19:15:05 +0000380 dirent.ino = (unsigned long) -1;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000381 dirent.namelen = strlen(name);
382 strncpy(dirent.name, name, sizeof(dirent.name));
383 dirent.type = type;
384 reclen = FUSE_DIRENT_SIZE(&dirent);
385 res = fwrite(&dirent, reclen, 1, dh->fp);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000386 if (res == 0) {
Miklos Szeredi96249982001-11-21 12:21:19 +0000387 perror("fuse: writing directory file");
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000388 return -EIO;
389 }
390 return 0;
391}
392
Miklos Szeredi40b9a5a2002-12-10 16:09:02 +0000393static int send_reply_raw(struct fuse *f, char *outbuf, size_t outsize)
Miklos Szeredi43696432001-11-18 19:15:05 +0000394{
395 int res;
396
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000397 if ((f->flags & FUSE_DEBUG)) {
Miklos Szeredi43696432001-11-18 19:15:05 +0000398 struct fuse_out_header *out = (struct fuse_out_header *) outbuf;
399 printf(" unique: %i, error: %i (%s), outsize: %i\n", out->unique,
400 out->error, strerror(-out->error), outsize);
401 fflush(stdout);
402 }
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +0000403
Miklos Szeredi4e71c9f2004-02-09 12:05:14 +0000404 /* This needs to be done before the reply, otherwise the scheduler
405 could play tricks with us, and only let the counter be increased
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +0000406 long after the operation is done */
407 inc_avail(f);
408
Miklos Szeredi43696432001-11-18 19:15:05 +0000409 res = write(f->fd, outbuf, outsize);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000410 if (res == -1) {
Miklos Szeredi43696432001-11-18 19:15:05 +0000411 /* ENOENT means the operation was interrupted */
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000412 if (!f->exited && errno != ENOENT)
Miklos Szeredi96249982001-11-21 12:21:19 +0000413 perror("fuse: writing device");
Miklos Szeredi40b9a5a2002-12-10 16:09:02 +0000414 return -errno;
Miklos Szeredi43696432001-11-18 19:15:05 +0000415 }
Miklos Szeredi40b9a5a2002-12-10 16:09:02 +0000416 return 0;
Miklos Szeredi43696432001-11-18 19:15:05 +0000417}
418
Miklos Szeredi40b9a5a2002-12-10 16:09:02 +0000419static int send_reply(struct fuse *f, struct fuse_in_header *in, int error,
420 void *arg, size_t argsize)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000421{
Miklos Szeredi40b9a5a2002-12-10 16:09:02 +0000422 int res;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000423 char *outbuf;
424 size_t outsize;
425 struct fuse_out_header *out;
426
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000427 if (error <= -1000 || error > 0) {
Miklos Szeredi0f48a262002-12-05 14:23:01 +0000428 fprintf(stderr, "fuse: bad error value: %i\n", error);
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000429 error = -ERANGE;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000430 }
431
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000432 if (error)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000433 argsize = 0;
434
435 outsize = sizeof(struct fuse_out_header) + argsize;
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000436 outbuf = (char *) malloc(outsize);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000437 out = (struct fuse_out_header *) outbuf;
Miklos Szeredi0f48a262002-12-05 14:23:01 +0000438 memset(out, 0, sizeof(struct fuse_out_header));
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000439 out->unique = in->unique;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000440 out->error = error;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000441 if (argsize != 0)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000442 memcpy(outbuf + sizeof(struct fuse_out_header), arg, argsize);
443
Miklos Szeredi40b9a5a2002-12-10 16:09:02 +0000444 res = send_reply_raw(f, outbuf, outsize);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000445 free(outbuf);
Miklos Szeredi40b9a5a2002-12-10 16:09:02 +0000446
447 return res;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000448}
449
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000450static int is_open(struct fuse *f, fino_t dir, const char *name)
451{
452 struct node *node;
453 int isopen = 0;
454 pthread_mutex_lock(&f->lock);
455 node = __lookup_node(f, dir, name);
456 if (node && node->open_count > 0)
457 isopen = 1;
458 pthread_mutex_unlock(&f->lock);
459 return isopen;
460}
461
462static char *hidden_name(struct fuse *f, fino_t dir, const char *oldname,
463 char *newname, size_t bufsize)
464{
465 struct stat buf;
466 struct node *node;
467 struct node *newnode;
468 char *newpath;
469 int res;
470 int failctr = 10;
471
472 if (!f->op.getattr)
473 return NULL;
474
475 do {
476 node = lookup_node(f, dir, oldname);
477 pthread_mutex_lock(&f->lock);
478 do {
479 f->hidectr ++;
480 snprintf(newname, bufsize, ".fuse_hidden%08x%08x",
481 (unsigned int) node->ino, f->hidectr);
482 newnode = __lookup_node(f, dir, newname);
483 } while(newnode);
484 pthread_mutex_unlock(&f->lock);
485
486 newpath = get_path_name(f, dir, newname);
487 if (!newpath)
488 break;
489
490 res = f->op.getattr(newpath, &buf);
491 if (res != 0)
492 break;
493 free(newpath);
494 newpath = NULL;
495 } while(--failctr);
496
497 return newpath;
498}
499
500static int hide_node(struct fuse *f, const char *oldpath, fino_t dir,
501 const char *oldname)
502{
503 char newname[64];
504 char *newpath;
505 int err = -1;
506
507 if (!f->op.rename || !f->op.unlink)
508 return -EBUSY;
509
510 newpath = hidden_name(f, dir, oldname, newname, sizeof(newname));
511 if (newpath) {
512 err = f->op.rename(oldpath, newpath);
513 if (!err)
514 err = rename_node(f, dir, oldname, dir, newname, 1);
515 free(newpath);
516 }
517 if (err)
518 return -EBUSY;
519
520 return 0;
521}
522
Miklos Szeredi76f65782004-02-19 16:55:40 +0000523static int lookup_path(struct fuse *f, fino_t ino, int version, char *name,
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000524 const char *path, struct fuse_entry_out *arg)
Miklos Szeredi76f65782004-02-19 16:55:40 +0000525{
526 int res;
527 struct stat buf;
528
529 res = f->op.getattr(path, &buf);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000530 if (res == 0) {
Miklos Szeredi76f65782004-02-19 16:55:40 +0000531 struct node *node;
532
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000533 memset(arg, 0, sizeof(struct fuse_entry_out));
Miklos Szeredi76f65782004-02-19 16:55:40 +0000534 convert_stat(&buf, &arg->attr);
535 node = find_node(f, ino, name, &arg->attr, version);
536 arg->ino = node->ino;
537 arg->generation = node->generation;
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000538 arg->entry_valid = ENTRY_REVALIDATE_TIME;
539 arg->entry_valid_nsec = 0;
540 arg->attr_valid = ATTR_REVALIDATE_TIME;
541 arg->attr_valid_nsec = 0;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000542 if (f->flags & FUSE_DEBUG) {
Miklos Szeredi76f65782004-02-19 16:55:40 +0000543 printf(" INO: %li\n", arg->ino);
544 fflush(stdout);
545 }
546 }
547 return res;
548}
549
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000550static void do_lookup(struct fuse *f, struct fuse_in_header *in, char *name)
551{
552 int res;
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000553 int res2;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000554 char *path;
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000555 struct fuse_entry_out arg;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000556
Miklos Szeredi5e183482001-10-31 14:52:35 +0000557 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000558 path = get_path_name(f, in->ino, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000559 if (path != NULL) {
560 if (f->flags & FUSE_DEBUG) {
Miklos Szeredi6ebe2342002-01-06 21:44:16 +0000561 printf("LOOKUP %s\n", path);
562 fflush(stdout);
563 }
Miklos Szeredi5e183482001-10-31 14:52:35 +0000564 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000565 if (f->op.getattr)
Miklos Szeredi76f65782004-02-19 16:55:40 +0000566 res = lookup_path(f, in->ino, in->unique, name, path, &arg);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000567 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000568 }
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000569 res2 = send_reply(f, in, res, &arg, sizeof(arg));
570 if (res == 0 && res2 == -ENOENT)
571 destroy_node(f, arg.ino, in->unique);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000572}
573
Miklos Szeredia181e612001-11-06 12:03:23 +0000574static void do_forget(struct fuse *f, struct fuse_in_header *in,
575 struct fuse_forget_in *arg)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000576{
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000577 if (f->flags & FUSE_DEBUG) {
Miklos Szeredi43696432001-11-18 19:15:05 +0000578 printf("FORGET %li/%i\n", in->ino, arg->version);
579 fflush(stdout);
580 }
Miklos Szeredia181e612001-11-06 12:03:23 +0000581 destroy_node(f, in->ino, arg->version);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000582}
583
584static void do_getattr(struct fuse *f, struct fuse_in_header *in)
585{
586 int res;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000587 char *path;
588 struct stat buf;
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000589 struct fuse_attr_out arg;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000590
Miklos Szeredi5e183482001-10-31 14:52:35 +0000591 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000592 path = get_path(f, in->ino);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000593 if (path != NULL) {
Miklos Szeredi5e183482001-10-31 14:52:35 +0000594 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000595 if (f->op.getattr)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000596 res = f->op.getattr(path, &buf);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000597 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000598 }
Miklos Szeredi0f48a262002-12-05 14:23:01 +0000599
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000600 if (res == 0) {
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000601 memset(&arg, 0, sizeof(struct fuse_attr_out));
602 arg.attr_valid = ATTR_REVALIDATE_TIME;
603 arg.attr_valid_nsec = 0;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000604 convert_stat(&buf, &arg.attr);
Miklos Szeredi0f48a262002-12-05 14:23:01 +0000605 }
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000606
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000607 send_reply(f, in, res, &arg, sizeof(arg));
608}
609
Miklos Szeredi680a69a2001-11-16 13:31:14 +0000610static int do_chmod(struct fuse *f, const char *path, struct fuse_attr *attr)
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000611{
612 int res;
613
614 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000615 if (f->op.chmod)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000616 res = f->op.chmod(path, attr->mode);
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000617
618 return res;
619}
620
Miklos Szeredi680a69a2001-11-16 13:31:14 +0000621static int do_chown(struct fuse *f, const char *path, struct fuse_attr *attr,
Miklos Szeredi2e50d432001-12-20 12:17:25 +0000622 int valid)
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000623{
624 int res;
625 uid_t uid = (valid & FATTR_UID) ? attr->uid : (uid_t) -1;
626 gid_t gid = (valid & FATTR_GID) ? attr->gid : (gid_t) -1;
627
628 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000629 if (f->op.chown)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000630 res = f->op.chown(path, uid, gid);
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000631
632 return res;
633}
634
Miklos Szeredi680a69a2001-11-16 13:31:14 +0000635static int do_truncate(struct fuse *f, const char *path,
636 struct fuse_attr *attr)
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000637{
638 int res;
639
640 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000641 if (f->op.truncate)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000642 res = f->op.truncate(path, attr->size);
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000643
644 return res;
645}
646
Miklos Szeredi680a69a2001-11-16 13:31:14 +0000647static int do_utime(struct fuse *f, const char *path, struct fuse_attr *attr)
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000648{
649 int res;
650 struct utimbuf buf;
651 buf.actime = attr->atime;
652 buf.modtime = attr->mtime;
653 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000654 if (f->op.utime)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000655 res = f->op.utime(path, &buf);
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000656
657 return res;
658}
659
Miklos Szeredi5e183482001-10-31 14:52:35 +0000660static void do_setattr(struct fuse *f, struct fuse_in_header *in,
661 struct fuse_setattr_in *arg)
662{
663 int res;
664 char *path;
665 int valid = arg->valid;
666 struct fuse_attr *attr = &arg->attr;
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000667 struct fuse_attr_out outarg;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000668
669 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000670 path = get_path(f, in->ino);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000671 if (path != NULL) {
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000672 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000673 if (f->op.getattr) {
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000674 res = 0;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000675 if (!res && (valid & FATTR_MODE))
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000676 res = do_chmod(f, path, attr);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000677 if (!res && (valid & (FATTR_UID | FATTR_GID)))
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000678 res = do_chown(f, path, attr, valid);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000679 if (!res && (valid & FATTR_SIZE))
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000680 res = do_truncate(f, path, attr);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000681 if (!res && (valid & (FATTR_ATIME | FATTR_MTIME)) ==
Miklos Szeredib5958612004-02-20 14:10:49 +0000682 (FATTR_ATIME | FATTR_MTIME))
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000683 res = do_utime(f, path, attr);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000684 if (!res) {
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000685 struct stat buf;
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000686 res = f->op.getattr(path, &buf);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000687 if (!res) {
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000688 memset(&outarg, 0, sizeof(struct fuse_attr_out));
689 outarg.attr_valid = ATTR_REVALIDATE_TIME;
690 outarg.attr_valid_nsec = 0;
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000691 convert_stat(&buf, &outarg.attr);
Miklos Szeredi0f48a262002-12-05 14:23:01 +0000692 }
Miklos Szeredia181e612001-11-06 12:03:23 +0000693 }
Miklos Szeredi5e183482001-10-31 14:52:35 +0000694 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000695 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000696 }
Miklos Szeredia181e612001-11-06 12:03:23 +0000697 send_reply(f, in, res, &outarg, sizeof(outarg));
Miklos Szeredi5e183482001-10-31 14:52:35 +0000698}
699
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000700static void do_readlink(struct fuse *f, struct fuse_in_header *in)
701{
702 int res;
703 char link[PATH_MAX + 1];
Miklos Szeredib483c932001-10-29 14:57:57 +0000704 char *path;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000705
Miklos Szeredi5e183482001-10-31 14:52:35 +0000706 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000707 path = get_path(f, in->ino);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000708 if (path != NULL) {
Miklos Szeredi5e183482001-10-31 14:52:35 +0000709 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000710 if (f->op.readlink)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000711 res = f->op.readlink(path, link, sizeof(link));
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000712 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000713 }
Miklos Szeredi2df1c042001-11-06 15:07:17 +0000714 link[PATH_MAX] = '\0';
Miklos Szeredi4b2bef42002-01-09 12:23:27 +0000715 send_reply(f, in, res, link, res == 0 ? strlen(link) : 0);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000716}
717
718static void do_getdir(struct fuse *f, struct fuse_in_header *in)
719{
720 int res;
721 struct fuse_getdir_out arg;
Miklos Szeredia181e612001-11-06 12:03:23 +0000722 struct fuse_dirhandle dh;
Miklos Szeredib483c932001-10-29 14:57:57 +0000723 char *path;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000724
Miklos Szeredib483c932001-10-29 14:57:57 +0000725 dh.fuse = f;
726 dh.fp = tmpfile();
727 dh.dir = in->ino;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000728 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000729 path = get_path(f, in->ino);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000730 if (path != NULL) {
Miklos Szeredi5e183482001-10-31 14:52:35 +0000731 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000732 if (f->op.getdir)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000733 res = f->op.getdir(path, &dh, (fuse_dirfil_t) fill_dir);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000734 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000735 }
Miklos Szeredib483c932001-10-29 14:57:57 +0000736 fflush(dh.fp);
Miklos Szeredi0f48a262002-12-05 14:23:01 +0000737
738 memset(&arg, 0, sizeof(struct fuse_getdir_out));
Miklos Szeredib483c932001-10-29 14:57:57 +0000739 arg.fd = fileno(dh.fp);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000740 send_reply(f, in, res, &arg, sizeof(arg));
Miklos Szeredib483c932001-10-29 14:57:57 +0000741 fclose(dh.fp);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000742}
743
Miklos Szeredib483c932001-10-29 14:57:57 +0000744static void do_mknod(struct fuse *f, struct fuse_in_header *in,
745 struct fuse_mknod_in *inarg)
746{
747 int res;
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000748 int res2;
Miklos Szeredib483c932001-10-29 14:57:57 +0000749 char *path;
Miklos Szeredi76f65782004-02-19 16:55:40 +0000750 char *name = PARAM(inarg);
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000751 struct fuse_entry_out outarg;
Miklos Szeredib483c932001-10-29 14:57:57 +0000752
Miklos Szeredi5e183482001-10-31 14:52:35 +0000753 res = -ENOENT;
Miklos Szeredi76f65782004-02-19 16:55:40 +0000754 path = get_path_name(f, in->ino, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000755 if (path != NULL) {
756 if (f->flags & FUSE_DEBUG) {
Miklos Szeredi76f65782004-02-19 16:55:40 +0000757 printf("MKNOD %s\n", path);
758 fflush(stdout);
759 }
Miklos Szeredi5e183482001-10-31 14:52:35 +0000760 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000761 if (f->op.mknod && f->op.getattr) {
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000762 res = f->op.mknod(path, inarg->mode, inarg->rdev);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000763 if (res == 0)
Miklos Szeredi76f65782004-02-19 16:55:40 +0000764 res = lookup_path(f, in->ino, in->unique, name, path, &outarg);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000765 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000766 free(path);
Miklos Szeredib483c932001-10-29 14:57:57 +0000767 }
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000768 res2 = send_reply(f, in, res, &outarg, sizeof(outarg));
769 if (res == 0 && res2 == -ENOENT)
770 destroy_node(f, outarg.ino, in->unique);
Miklos Szeredib483c932001-10-29 14:57:57 +0000771}
772
773static void do_mkdir(struct fuse *f, struct fuse_in_header *in,
774 struct fuse_mkdir_in *inarg)
775{
776 int res;
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000777 int res2;
Miklos Szeredib483c932001-10-29 14:57:57 +0000778 char *path;
Miklos Szeredi76f65782004-02-19 16:55:40 +0000779 char *name = PARAM(inarg);
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000780 struct fuse_entry_out outarg;
Miklos Szeredib483c932001-10-29 14:57:57 +0000781
Miklos Szeredi5e183482001-10-31 14:52:35 +0000782 res = -ENOENT;
Miklos Szeredi76f65782004-02-19 16:55:40 +0000783 path = get_path_name(f, in->ino, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000784 if (path != NULL) {
785 if (f->flags & FUSE_DEBUG) {
Miklos Szeredi76f65782004-02-19 16:55:40 +0000786 printf("MKDIR %s\n", path);
787 fflush(stdout);
788 }
Miklos Szeredi5e183482001-10-31 14:52:35 +0000789 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000790 if (f->op.mkdir && f->op.getattr) {
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000791 res = f->op.mkdir(path, inarg->mode);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000792 if (res == 0)
Miklos Szeredi76f65782004-02-19 16:55:40 +0000793 res = lookup_path(f, in->ino, in->unique, name, path, &outarg);
794 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000795 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000796 }
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000797 res2 = send_reply(f, in, res, &outarg, sizeof(outarg));
798 if (res == 0 && res2 == -ENOENT)
799 destroy_node(f, outarg.ino, in->unique);
Miklos Szeredib483c932001-10-29 14:57:57 +0000800}
801
Miklos Szeredib5958612004-02-20 14:10:49 +0000802static void do_unlink(struct fuse *f, struct fuse_in_header *in, char *name)
Miklos Szeredib483c932001-10-29 14:57:57 +0000803{
804 int res;
805 char *path;
806
Miklos Szeredi5e183482001-10-31 14:52:35 +0000807 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000808 path = get_path_name(f, in->ino, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000809 if (path != NULL) {
Miklos Szeredi5e183482001-10-31 14:52:35 +0000810 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000811 if (f->op.unlink) {
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000812 if (is_open(f, in->ino, name))
813 res = hide_node(f, path, in->ino, name);
814 else {
815 res = f->op.unlink(path);
816 if (res == 0)
817 remove_node(f, in->ino, name);
818 }
Miklos Szeredi5e183482001-10-31 14:52:35 +0000819 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000820 free(path);
Miklos Szeredib483c932001-10-29 14:57:57 +0000821 }
Miklos Szeredib5958612004-02-20 14:10:49 +0000822 send_reply(f, in, res, NULL, 0);
823}
824
825static void do_rmdir(struct fuse *f, struct fuse_in_header *in, char *name)
826{
827 int res;
828 char *path;
829
830 res = -ENOENT;
831 path = get_path_name(f, in->ino, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000832 if (path != NULL) {
Miklos Szeredib5958612004-02-20 14:10:49 +0000833 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000834 if (f->op.rmdir) {
Miklos Szeredib5958612004-02-20 14:10:49 +0000835 res = f->op.rmdir(path);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000836 if (res == 0)
Miklos Szeredib5958612004-02-20 14:10:49 +0000837 remove_node(f, in->ino, name);
838 }
839 free(path);
840 }
Miklos Szeredib483c932001-10-29 14:57:57 +0000841 send_reply(f, in, res, NULL, 0);
842}
843
844static void do_symlink(struct fuse *f, struct fuse_in_header *in, char *name,
845 char *link)
846{
847 int res;
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000848 int res2;
Miklos Szeredib483c932001-10-29 14:57:57 +0000849 char *path;
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000850 struct fuse_entry_out outarg;
Miklos Szeredib483c932001-10-29 14:57:57 +0000851
Miklos Szeredi5e183482001-10-31 14:52:35 +0000852 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000853 path = get_path_name(f, in->ino, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000854 if (path != NULL) {
855 if (f->flags & FUSE_DEBUG) {
Miklos Szeredi76f65782004-02-19 16:55:40 +0000856 printf("SYMLINK %s\n", path);
857 fflush(stdout);
858 }
Miklos Szeredi5e183482001-10-31 14:52:35 +0000859 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000860 if (f->op.symlink && f->op.getattr) {
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000861 res = f->op.symlink(link, path);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000862 if (res == 0)
Miklos Szeredi76f65782004-02-19 16:55:40 +0000863 res = lookup_path(f, in->ino, in->unique, name, path, &outarg);
864 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000865 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000866 }
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000867 res2 = send_reply(f, in, res, &outarg, sizeof(outarg));
868 if (res == 0 && res2 == -ENOENT)
869 destroy_node(f, outarg.ino, in->unique);
870
Miklos Szeredib483c932001-10-29 14:57:57 +0000871}
872
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000873static void do_rename(struct fuse *f, struct fuse_in_header *in,
874 struct fuse_rename_in *inarg)
875{
876 int res;
877 fino_t olddir = in->ino;
878 fino_t newdir = inarg->newdir;
Miklos Szeredi6bf8b682002-10-28 08:49:39 +0000879 char *oldname = PARAM(inarg);
880 char *newname = oldname + strlen(oldname) + 1;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000881 char *oldpath;
882 char *newpath;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000883
Miklos Szeredi5e183482001-10-31 14:52:35 +0000884 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000885 oldpath = get_path_name(f, olddir, oldname);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000886 if (oldpath != NULL) {
Miklos Szeredia181e612001-11-06 12:03:23 +0000887 newpath = get_path_name(f, newdir, newname);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000888 if (newpath != NULL) {
Miklos Szeredi5e183482001-10-31 14:52:35 +0000889 res = -ENOSYS;
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000890 if (f->op.rename) {
891 res = 0;
892 if (is_open(f, newdir, newname))
893 res = hide_node(f, newpath, newdir, newname);
894 if (res == 0) {
895 res = f->op.rename(oldpath, newpath);
896 if (res == 0)
897 rename_node(f, olddir, oldname, newdir, newname, 0);
898 }
899 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000900 free(newpath);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000901 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000902 free(oldpath);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000903 }
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000904 send_reply(f, in, res, NULL, 0);
905}
906
907static void do_link(struct fuse *f, struct fuse_in_header *in,
Miklos Szeredi5e183482001-10-31 14:52:35 +0000908 struct fuse_link_in *arg)
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000909{
910 int res;
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000911 int res2;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000912 char *oldpath;
913 char *newpath;
Miklos Szeredi76f65782004-02-19 16:55:40 +0000914 char *name = PARAM(arg);
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000915 struct fuse_entry_out outarg;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000916
Miklos Szeredi5e183482001-10-31 14:52:35 +0000917 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000918 oldpath = get_path(f, in->ino);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000919 if (oldpath != NULL) {
Miklos Szeredi76f65782004-02-19 16:55:40 +0000920 newpath = get_path_name(f, arg->newdir, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000921 if (newpath != NULL) {
922 if (f->flags & FUSE_DEBUG) {
Miklos Szeredi76f65782004-02-19 16:55:40 +0000923 printf("LINK %s\n", newpath);
924 fflush(stdout);
925 }
Miklos Szeredi5e183482001-10-31 14:52:35 +0000926 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000927 if (f->op.link && f->op.getattr) {
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000928 res = f->op.link(oldpath, newpath);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000929 if (res == 0)
Miklos Szeredi76f65782004-02-19 16:55:40 +0000930 res = lookup_path(f, arg->newdir, in->unique, name,
931 newpath, &outarg);
932 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000933 free(newpath);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000934 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000935 free(oldpath);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000936 }
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000937 res2 = send_reply(f, in, res, &outarg, sizeof(outarg));
938 if (res == 0 && res2 == -ENOENT)
939 destroy_node(f, outarg.ino, in->unique);
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000940}
941
Miklos Szeredi5e183482001-10-31 14:52:35 +0000942static void do_open(struct fuse *f, struct fuse_in_header *in,
943 struct fuse_open_in *arg)
944{
945 int res;
Miklos Szeredi40b9a5a2002-12-10 16:09:02 +0000946 int res2;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000947 char *path;
948
949 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000950 path = get_path(f, in->ino);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000951 if (path != NULL) {
Miklos Szeredi5e183482001-10-31 14:52:35 +0000952 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000953 if (f->op.open)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000954 res = f->op.open(path, arg->flags);
Miklos Szeredi40b9a5a2002-12-10 16:09:02 +0000955 }
956 res2 = send_reply(f, in, res, NULL, 0);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000957 if(res == 0) {
958 if(res2 == -ENOENT) {
959 /* The open syscall was interrupted, so it must be cancelled */
960 if(f->op.release)
961 f->op.release(path, arg->flags);
962 } else {
963 struct node *node;
964
965 pthread_mutex_lock(&f->lock);
966 node = get_node(f, in->ino);
967 ++node->open_count;
968 pthread_mutex_unlock(&f->lock);
969 }
Miklos Szeredi5e183482001-10-31 14:52:35 +0000970 }
Miklos Szeredi9a31cca2004-06-26 21:11:25 +0000971 if (path)
972 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000973}
974
Miklos Szeredie2e4ac22004-05-18 08:45:28 +0000975static void do_flush(struct fuse *f, struct fuse_in_header *in)
976{
977 char *path;
978 int res;
979
980 res = -ENOENT;
981 path = get_path(f, in->ino);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000982 if (path != NULL) {
Miklos Szeredie2e4ac22004-05-18 08:45:28 +0000983 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000984 if (f->op.flush)
Miklos Szeredie2e4ac22004-05-18 08:45:28 +0000985 res = f->op.flush(path);
986 free(path);
987 }
988 send_reply(f, in, res, NULL, 0);
989}
990
Miklos Szeredi9478e862002-12-11 09:50:26 +0000991static void do_release(struct fuse *f, struct fuse_in_header *in,
992 struct fuse_open_in *arg)
Miklos Szeredic8ba2372002-12-10 12:26:00 +0000993{
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000994 struct node *node;
995 char *path;
Miklos Szeredic8ba2372002-12-10 12:26:00 +0000996
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000997 pthread_mutex_lock(&f->lock);
998 node = get_node(f, in->ino);
999 --node->open_count;
1000 pthread_mutex_unlock(&f->lock);
1001
1002 path = get_path(f, in->ino);
1003 if (path != NULL) {
1004 if (f->op.release)
Miklos Szeredib3210582004-06-23 13:54:33 +00001005 f->op.release(path, arg->flags);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001006
1007 if(node->is_hidden && node->open_count == 0)
1008 /* can now clean up this hidden file */
1009 f->op.unlink(path);
1010
1011 free(path);
Miklos Szeredic8ba2372002-12-10 12:26:00 +00001012 }
Miklos Szeredic8ba2372002-12-10 12:26:00 +00001013}
1014
Miklos Szeredi5e183482001-10-31 14:52:35 +00001015static void do_read(struct fuse *f, struct fuse_in_header *in,
1016 struct fuse_read_in *arg)
1017{
1018 int res;
1019 char *path;
Miklos Szeredi43696432001-11-18 19:15:05 +00001020 char *outbuf = (char *) malloc(sizeof(struct fuse_out_header) + arg->size);
1021 struct fuse_out_header *out = (struct fuse_out_header *) outbuf;
1022 char *buf = outbuf + sizeof(struct fuse_out_header);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001023 size_t size;
Miklos Szeredi43696432001-11-18 19:15:05 +00001024 size_t outsize;
Miklos Szeredi5e183482001-10-31 14:52:35 +00001025
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001026 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +00001027 path = get_path(f, in->ino);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001028 if (path != NULL) {
1029 if (f->flags & FUSE_DEBUG) {
Miklos Szeredi6ebe2342002-01-06 21:44:16 +00001030 printf("READ %u bytes from %llu\n", arg->size, arg->offset);
1031 fflush(stdout);
1032 }
1033
Miklos Szeredi5e183482001-10-31 14:52:35 +00001034 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001035 if (f->op.read)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +00001036 res = f->op.read(path, buf, arg->size, arg->offset);
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001037 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001038 }
1039
1040 size = 0;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001041 if (res > 0) {
Miklos Szeredi5e183482001-10-31 14:52:35 +00001042 size = res;
1043 res = 0;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001044 if (f->flags & FUSE_DEBUG) {
Miklos Szeredi6ebe2342002-01-06 21:44:16 +00001045 printf(" READ %u bytes\n", size);
1046 fflush(stdout);
1047 }
Miklos Szeredi5e183482001-10-31 14:52:35 +00001048 }
Miklos Szeredi0f48a262002-12-05 14:23:01 +00001049 memset(out, 0, sizeof(struct fuse_out_header));
Miklos Szeredi43696432001-11-18 19:15:05 +00001050 out->unique = in->unique;
1051 out->error = res;
1052 outsize = sizeof(struct fuse_out_header) + size;
1053
1054 send_reply_raw(f, outbuf, outsize);
1055 free(outbuf);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001056}
Miklos Szeredib483c932001-10-29 14:57:57 +00001057
Miklos Szeredia181e612001-11-06 12:03:23 +00001058static void do_write(struct fuse *f, struct fuse_in_header *in,
1059 struct fuse_write_in *arg)
1060{
1061 int res;
1062 char *path;
Miklos Szeredia181e612001-11-06 12:03:23 +00001063
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001064 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +00001065 path = get_path(f, in->ino);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001066 if (path != NULL) {
1067 if (f->flags & FUSE_DEBUG) {
Miklos Szeredi6ebe2342002-01-06 21:44:16 +00001068 printf("WRITE %u bytes to %llu\n", arg->size, arg->offset);
1069 fflush(stdout);
1070 }
1071
Miklos Szeredia181e612001-11-06 12:03:23 +00001072 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001073 if (f->op.write)
Miklos Szeredi6bf8b682002-10-28 08:49:39 +00001074 res = f->op.write(path, PARAM(arg), arg->size, arg->offset);
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001075 free(path);
Miklos Szeredia181e612001-11-06 12:03:23 +00001076 }
1077
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001078 if (res > 0) {
1079 if ((size_t) res != arg->size) {
Miklos Szeredia181e612001-11-06 12:03:23 +00001080 fprintf(stderr, "short write: %u (should be %u)\n", res,
1081 arg->size);
Miklos Szeredi0e535082003-10-13 10:08:06 +00001082 res = -EINVAL;
Miklos Szeredia181e612001-11-06 12:03:23 +00001083 }
1084 else
1085 res = 0;
1086 }
1087
1088 send_reply(f, in, res, NULL, 0);
1089}
1090
Miklos Szeredi77f39942004-03-25 11:17:52 +00001091static int default_statfs(struct statfs *buf)
1092{
1093 buf->f_namelen = 255;
1094 buf->f_bsize = 512;
1095 return 0;
1096}
1097
Miklos Szeredi18e75e42004-02-19 14:23:27 +00001098static void convert_statfs(struct statfs *statfs, struct fuse_kstatfs *kstatfs)
1099{
1100 kstatfs->bsize = statfs->f_bsize;
1101 kstatfs->blocks = statfs->f_blocks;
1102 kstatfs->bfree = statfs->f_bfree;
1103 kstatfs->bavail = statfs->f_bavail;
1104 kstatfs->files = statfs->f_files;
1105 kstatfs->ffree = statfs->f_ffree;
1106 kstatfs->namelen = statfs->f_namelen;
1107}
1108
Mark Glinesd84b39a2002-01-07 16:32:02 +00001109static void do_statfs(struct fuse *f, struct fuse_in_header *in)
1110{
1111 int res;
Mark Glinesd84b39a2002-01-07 16:32:02 +00001112 struct fuse_statfs_out arg;
Miklos Szeredi18e75e42004-02-19 14:23:27 +00001113 struct statfs buf;
Mark Glinesd84b39a2002-01-07 16:32:02 +00001114
Miklos Szeredi77f39942004-03-25 11:17:52 +00001115 memset(&buf, 0, sizeof(struct statfs));
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001116 if (f->op.statfs)
Miklos Szeredi18e75e42004-02-19 14:23:27 +00001117 res = f->op.statfs("/", &buf);
Miklos Szeredi77f39942004-03-25 11:17:52 +00001118 else
1119 res = default_statfs(&buf);
1120
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001121 if (res == 0)
Miklos Szeredi77f39942004-03-25 11:17:52 +00001122 convert_statfs(&buf, &arg.st);
Miklos Szeredi4b2bef42002-01-09 12:23:27 +00001123
Mark Glinesd84b39a2002-01-07 16:32:02 +00001124 send_reply(f, in, res, &arg, sizeof(arg));
1125}
1126
Miklos Szeredi5e43f2c2003-12-12 14:06:41 +00001127static void do_fsync(struct fuse *f, struct fuse_in_header *in,
1128 struct fuse_fsync_in *inarg)
1129{
1130 int res;
1131 char *path;
1132
1133 res = -ENOENT;
1134 path = get_path(f, in->ino);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001135 if (path != NULL) {
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001136 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001137 if (f->op.fsync)
Miklos Szeredi5e43f2c2003-12-12 14:06:41 +00001138 res = f->op.fsync(path, inarg->datasync);
1139 free(path);
1140 }
1141 send_reply(f, in, res, NULL, 0);
1142}
1143
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001144static void do_setxattr(struct fuse *f, struct fuse_in_header *in,
1145 struct fuse_setxattr_in *arg)
1146{
1147 int res;
1148 char *path;
1149 char *name = PARAM(arg);
1150 unsigned char *value = name + strlen(name) + 1;
1151
1152 res = -ENOENT;
1153 path = get_path(f, in->ino);
1154 if (path != NULL) {
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001155 res = -ENOSYS;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001156 if (f->op.setxattr)
1157 res = f->op.setxattr(path, name, value, arg->size, arg->flags);
1158 free(path);
1159 }
1160 send_reply(f, in, res, NULL, 0);
1161}
1162
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001163static int common_getxattr(struct fuse *f, struct fuse_in_header *in,
1164 const char *name, char *value, size_t size)
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001165{
1166 int res;
1167 char *path;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001168
1169 res = -ENOENT;
1170 path = get_path(f, in->ino);
1171 if (path != NULL) {
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001172 res = -ENOSYS;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001173 if (f->op.getxattr)
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001174 res = f->op.getxattr(path, name, value, size);
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001175 free(path);
1176 }
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001177 return res;
1178}
1179
1180static void do_getxattr_read(struct fuse *f, struct fuse_in_header *in,
1181 const char *name, size_t size)
1182{
1183 int res;
1184 char *outbuf = (char *) malloc(sizeof(struct fuse_out_header) + size);
1185 struct fuse_out_header *out = (struct fuse_out_header *) outbuf;
1186 char *value = outbuf + sizeof(struct fuse_out_header);
1187
1188 res = common_getxattr(f, in, name, value, size);
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001189 size = 0;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001190 if (res > 0) {
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001191 size = res;
1192 res = 0;
1193 }
1194 memset(out, 0, sizeof(struct fuse_out_header));
1195 out->unique = in->unique;
1196 out->error = res;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001197
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001198 send_reply_raw(f, outbuf, sizeof(struct fuse_out_header) + size);
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001199 free(outbuf);
1200}
1201
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001202static void do_getxattr_size(struct fuse *f, struct fuse_in_header *in,
1203 const char *name)
1204{
1205 int res;
1206 struct fuse_getxattr_out arg;
1207
1208 res = common_getxattr(f, in, name, NULL, 0);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001209 if (res >= 0) {
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001210 arg.size = res;
1211 res = 0;
1212 }
1213 send_reply(f, in, res, &arg, sizeof(arg));
1214}
1215
1216static void do_getxattr(struct fuse *f, struct fuse_in_header *in,
1217 struct fuse_getxattr_in *arg)
1218{
1219 char *name = PARAM(arg);
1220
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001221 if (arg->size)
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001222 do_getxattr_read(f, in, name, arg->size);
1223 else
1224 do_getxattr_size(f, in, name);
1225}
1226
1227static int common_listxattr(struct fuse *f, struct fuse_in_header *in,
1228 char *list, size_t size)
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001229{
1230 int res;
1231 char *path;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001232
1233 res = -ENOENT;
1234 path = get_path(f, in->ino);
1235 if (path != NULL) {
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001236 res = -ENOSYS;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001237 if (f->op.listxattr)
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001238 res = f->op.listxattr(path, list, size);
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001239 free(path);
1240 }
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001241 return res;
1242}
1243
1244static void do_listxattr_read(struct fuse *f, struct fuse_in_header *in,
1245 size_t size)
1246{
1247 int res;
1248 char *outbuf = (char *) malloc(sizeof(struct fuse_out_header) + size);
1249 struct fuse_out_header *out = (struct fuse_out_header *) outbuf;
1250 char *list = outbuf + sizeof(struct fuse_out_header);
1251
1252 res = common_listxattr(f, in, list, size);
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001253 size = 0;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001254 if (res > 0) {
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001255 size = res;
1256 res = 0;
1257 }
1258 memset(out, 0, sizeof(struct fuse_out_header));
1259 out->unique = in->unique;
1260 out->error = res;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001261
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001262 send_reply_raw(f, outbuf, sizeof(struct fuse_out_header) + size);
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001263 free(outbuf);
1264}
1265
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001266static void do_listxattr_size(struct fuse *f, struct fuse_in_header *in)
1267{
1268 int res;
1269 struct fuse_getxattr_out arg;
1270
1271 res = common_listxattr(f, in, NULL, 0);
1272 if (res >= 0) {
1273 arg.size = res;
1274 res = 0;
1275 }
1276 send_reply(f, in, res, &arg, sizeof(arg));
1277}
1278
1279static void do_listxattr(struct fuse *f, struct fuse_in_header *in,
1280 struct fuse_getxattr_in *arg)
1281{
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001282 if (arg->size)
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001283 do_listxattr_read(f, in, arg->size);
1284 else
1285 do_listxattr_size(f, in);
1286}
1287
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001288static void do_removexattr(struct fuse *f, struct fuse_in_header *in,
1289 char *name)
1290{
1291 int res;
1292 char *path;
1293
1294 res = -ENOENT;
1295 path = get_path(f, in->ino);
1296 if (path != NULL) {
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001297 res = -ENOSYS;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001298 if (f->op.removexattr)
1299 res = f->op.removexattr(path, name);
1300 free(path);
1301 }
1302 send_reply(f, in, res, NULL, 0);
1303}
1304
1305
Miklos Szeredi43696432001-11-18 19:15:05 +00001306static void free_cmd(struct fuse_cmd *cmd)
1307{
1308 free(cmd->buf);
1309 free(cmd);
1310}
1311
Miklos Szeredifff56ab2001-11-16 10:12:59 +00001312void __fuse_process_cmd(struct fuse *f, struct fuse_cmd *cmd)
Miklos Szeredia181e612001-11-06 12:03:23 +00001313{
Miklos Szeredia181e612001-11-06 12:03:23 +00001314 struct fuse_in_header *in = (struct fuse_in_header *) cmd->buf;
1315 void *inarg = cmd->buf + sizeof(struct fuse_in_header);
1316 size_t argsize;
Miklos Szeredife25def2001-12-20 15:38:05 +00001317 struct fuse_context *ctx = fuse_get_context(f);
Miklos Szeredia181e612001-11-06 12:03:23 +00001318
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +00001319 dec_avail(f);
Miklos Szeredi33232032001-11-19 17:55:51 +00001320
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001321 if ((f->flags & FUSE_DEBUG)) {
Miklos Szeredic8ba2372002-12-10 12:26:00 +00001322 printf("unique: %i, opcode: %s (%i), ino: %li, insize: %i\n",
1323 in->unique, opname(in->opcode), in->opcode, in->ino,
1324 cmd->buflen);
Miklos Szeredic0938ea2001-11-07 12:35:06 +00001325 fflush(stdout);
1326 }
Miklos Szeredife25def2001-12-20 15:38:05 +00001327
1328 ctx->uid = in->uid;
1329 ctx->gid = in->gid;
Miklos Szeredia181e612001-11-06 12:03:23 +00001330
1331 argsize = cmd->buflen - sizeof(struct fuse_in_header);
1332
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001333 switch (in->opcode) {
Miklos Szeredia181e612001-11-06 12:03:23 +00001334 case FUSE_LOOKUP:
1335 do_lookup(f, in, (char *) inarg);
1336 break;
1337
Miklos Szeredia181e612001-11-06 12:03:23 +00001338 case FUSE_GETATTR:
1339 do_getattr(f, in);
1340 break;
1341
1342 case FUSE_SETATTR:
1343 do_setattr(f, in, (struct fuse_setattr_in *) inarg);
1344 break;
1345
1346 case FUSE_READLINK:
1347 do_readlink(f, in);
1348 break;
1349
1350 case FUSE_GETDIR:
1351 do_getdir(f, in);
1352 break;
1353
1354 case FUSE_MKNOD:
1355 do_mknod(f, in, (struct fuse_mknod_in *) inarg);
1356 break;
1357
1358 case FUSE_MKDIR:
1359 do_mkdir(f, in, (struct fuse_mkdir_in *) inarg);
1360 break;
1361
1362 case FUSE_UNLINK:
Miklos Szeredib5958612004-02-20 14:10:49 +00001363 do_unlink(f, in, (char *) inarg);
1364 break;
1365
Miklos Szeredia181e612001-11-06 12:03:23 +00001366 case FUSE_RMDIR:
Miklos Szeredib5958612004-02-20 14:10:49 +00001367 do_rmdir(f, in, (char *) inarg);
Miklos Szeredia181e612001-11-06 12:03:23 +00001368 break;
1369
1370 case FUSE_SYMLINK:
1371 do_symlink(f, in, (char *) inarg,
1372 ((char *) inarg) + strlen((char *) inarg) + 1);
1373 break;
1374
1375 case FUSE_RENAME:
1376 do_rename(f, in, (struct fuse_rename_in *) inarg);
1377 break;
1378
1379 case FUSE_LINK:
1380 do_link(f, in, (struct fuse_link_in *) inarg);
1381 break;
1382
1383 case FUSE_OPEN:
1384 do_open(f, in, (struct fuse_open_in *) inarg);
1385 break;
1386
Miklos Szeredie2e4ac22004-05-18 08:45:28 +00001387 case FUSE_FLUSH:
1388 do_flush(f, in);
1389 break;
1390
Miklos Szeredi9478e862002-12-11 09:50:26 +00001391 case FUSE_RELEASE:
1392 do_release(f, in, (struct fuse_open_in *) inarg);
1393 break;
1394
Miklos Szeredia181e612001-11-06 12:03:23 +00001395 case FUSE_READ:
1396 do_read(f, in, (struct fuse_read_in *) inarg);
1397 break;
1398
1399 case FUSE_WRITE:
1400 do_write(f, in, (struct fuse_write_in *) inarg);
1401 break;
1402
Mark Glinesd84b39a2002-01-07 16:32:02 +00001403 case FUSE_STATFS:
1404 do_statfs(f, in);
1405 break;
1406
Miklos Szeredi5e43f2c2003-12-12 14:06:41 +00001407 case FUSE_FSYNC:
1408 do_fsync(f, in, (struct fuse_fsync_in *) inarg);
1409 break;
1410
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001411 case FUSE_SETXATTR:
1412 do_setxattr(f, in, (struct fuse_setxattr_in *) inarg);
1413 break;
1414
1415 case FUSE_GETXATTR:
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001416 do_getxattr(f, in, (struct fuse_getxattr_in *) inarg);
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001417 break;
1418
1419 case FUSE_LISTXATTR:
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001420 do_listxattr(f, in, (struct fuse_getxattr_in *) inarg);
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001421 break;
1422
1423 case FUSE_REMOVEXATTR:
1424 do_removexattr(f, in, (char *) inarg);
1425 break;
1426
Miklos Szeredia181e612001-11-06 12:03:23 +00001427 default:
Miklos Szeredi43696432001-11-18 19:15:05 +00001428 send_reply(f, in, -ENOSYS, NULL, 0);
Miklos Szeredia181e612001-11-06 12:03:23 +00001429 }
Miklos Szeredi43696432001-11-18 19:15:05 +00001430
1431 free_cmd(cmd);
Miklos Szeredia181e612001-11-06 12:03:23 +00001432}
1433
Miklos Szeredifff56ab2001-11-16 10:12:59 +00001434struct fuse_cmd *__fuse_read_cmd(struct fuse *f)
Miklos Szeredi2df1c042001-11-06 15:07:17 +00001435{
Miklos Szeredifff56ab2001-11-16 10:12:59 +00001436 ssize_t res;
Miklos Szeredifff56ab2001-11-16 10:12:59 +00001437 struct fuse_cmd *cmd;
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +00001438 struct fuse_in_header *in;
1439 void *inarg;
Miklos Szeredifff56ab2001-11-16 10:12:59 +00001440
Miklos Szeredi43696432001-11-18 19:15:05 +00001441 cmd = (struct fuse_cmd *) malloc(sizeof(struct fuse_cmd));
1442 cmd->buf = (char *) malloc(FUSE_MAX_IN);
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +00001443 in = (struct fuse_in_header *) cmd->buf;
1444 inarg = cmd->buf + sizeof(struct fuse_in_header);
Miklos Szeredi43696432001-11-18 19:15:05 +00001445
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +00001446 do {
1447 res = read(f->fd, cmd->buf, FUSE_MAX_IN);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001448 if (res == -1) {
Miklos Szeredi0f48a262002-12-05 14:23:01 +00001449 free_cmd(cmd);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001450 if (f->exited || errno == EINTR)
Miklos Szeredi0f48a262002-12-05 14:23:01 +00001451 return NULL;
1452
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +00001453 /* ENODEV means we got unmounted, so we silenty return failure */
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001454 if (errno != ENODEV) {
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +00001455 /* BAD... This will happen again */
Miklos Szeredi0f48a262002-12-05 14:23:01 +00001456 perror("fuse: reading device");
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +00001457 }
Miklos Szeredi0f48a262002-12-05 14:23:01 +00001458
1459 fuse_exit(f);
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +00001460 return NULL;
Miklos Szeredi96249982001-11-21 12:21:19 +00001461 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001462 if ((size_t) res < sizeof(struct fuse_in_header)) {
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +00001463 free_cmd(cmd);
Miklos Szeredi0f48a262002-12-05 14:23:01 +00001464 /* Cannot happen */
1465 fprintf(stderr, "short read on fuse device\n");
1466 fuse_exit(f);
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +00001467 return NULL;
1468 }
1469 cmd->buflen = res;
1470
1471 /* Forget is special, it can be done without messing with threads. */
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001472 if (in->opcode == FUSE_FORGET)
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +00001473 do_forget(f, in, (struct fuse_forget_in *) inarg);
1474
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001475 } while (in->opcode == FUSE_FORGET);
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +00001476
Miklos Szeredifff56ab2001-11-16 10:12:59 +00001477 return cmd;
Miklos Szeredi2df1c042001-11-06 15:07:17 +00001478}
1479
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001480void fuse_loop(struct fuse *f)
1481{
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001482 if (f == NULL)
Miklos Szeredic40748a2004-02-20 16:38:45 +00001483 return;
1484
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001485 while (1) {
Miklos Szeredi0f48a262002-12-05 14:23:01 +00001486 struct fuse_cmd *cmd;
1487
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001488 if (f->exited)
Miklos Szeredi0f48a262002-12-05 14:23:01 +00001489 return;
1490
1491 cmd = __fuse_read_cmd(f);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001492 if (cmd == NULL)
Miklos Szeredi0f48a262002-12-05 14:23:01 +00001493 continue;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001494
Miklos Szeredifff56ab2001-11-16 10:12:59 +00001495 __fuse_process_cmd(f, cmd);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001496 }
1497}
1498
Miklos Szeredi0f48a262002-12-05 14:23:01 +00001499void fuse_exit(struct fuse *f)
1500{
1501 f->exited = 1;
1502}
1503
Miklos Szeredi2e50d432001-12-20 12:17:25 +00001504struct fuse_context *fuse_get_context(struct fuse *f)
1505{
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001506 if (f->getcontext)
Miklos Szeredi2e50d432001-12-20 12:17:25 +00001507 return f->getcontext(f);
1508 else
1509 return &f->context;
1510}
1511
Miklos Szeredic40748a2004-02-20 16:38:45 +00001512static int check_version(struct fuse *f)
1513{
1514 int res;
1515 FILE *vf = fopen(FUSE_VERSION_FILE, "r");
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001516 if (vf == NULL) {
Miklos Szeredic40748a2004-02-20 16:38:45 +00001517 fprintf(stderr, "fuse: kernel interface too old, need >= %i.%i\n",
1518 FUSE_KERNEL_VERSION, FUSE_KERNEL_MINOR_VERSION);
1519 return -1;
1520 }
1521 res = fscanf(vf, "%i.%i", &f->majorver, &f->minorver);
1522 fclose(vf);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001523 if (res != 2) {
Miklos Szeredic40748a2004-02-20 16:38:45 +00001524 fprintf(stderr, "fuse: error reading %s\n", FUSE_VERSION_FILE);
1525 return -1;
1526 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001527 if (f->majorver != FUSE_KERNEL_VERSION) {
Miklos Szeredic40748a2004-02-20 16:38:45 +00001528 fprintf(stderr, "fuse: bad kernel interface major version: needs %i\n",
1529 FUSE_KERNEL_VERSION);
1530 return -1;
1531 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001532 if (f->minorver < FUSE_KERNEL_MINOR_VERSION) {
Miklos Szeredic40748a2004-02-20 16:38:45 +00001533 fprintf(stderr, "fuse: kernel interface too old: need >= %i.%i",
1534 FUSE_KERNEL_VERSION, FUSE_KERNEL_MINOR_VERSION);
1535 return -1;
1536 }
1537
1538 return 0;
1539}
1540
Miklos Szeredi2e50d432001-12-20 12:17:25 +00001541struct fuse *fuse_new(int fd, int flags, const struct fuse_operations *op)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001542{
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001543 struct fuse *f;
1544 struct node *root;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001545
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001546 f = (struct fuse *) calloc(1, sizeof(struct fuse));
Miklos Szeredi2df1c042001-11-06 15:07:17 +00001547
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001548 if (check_version(f) == -1) {
Miklos Szeredic40748a2004-02-20 16:38:45 +00001549 free(f);
1550 return NULL;
1551 }
1552
Miklos Szeredia181e612001-11-06 12:03:23 +00001553 f->flags = flags;
Miklos Szeredi8cffdb92001-11-09 14:49:18 +00001554 f->fd = fd;
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001555 f->ctr = 0;
Miklos Szeredi76f65782004-02-19 16:55:40 +00001556 f->generation = 0;
Miklos Szeredifff56ab2001-11-16 10:12:59 +00001557 /* FIXME: Dynamic hash table */
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001558 f->name_table_size = 14057;
1559 f->name_table = (struct node **)
1560 calloc(1, sizeof(struct node *) * f->name_table_size);
1561 f->ino_table_size = 14057;
1562 f->ino_table = (struct node **)
1563 calloc(1, sizeof(struct node *) * f->ino_table_size);
Miklos Szeredia181e612001-11-06 12:03:23 +00001564 pthread_mutex_init(&f->lock, NULL);
Miklos Szeredi33232032001-11-19 17:55:51 +00001565 f->numworker = 0;
1566 f->numavail = 0;
Miklos Szeredi2e50d432001-12-20 12:17:25 +00001567 f->op = *op;
1568 f->getcontext = NULL;
1569 f->context.uid = 0;
1570 f->context.gid = 0;
Miklos Szeredi0f48a262002-12-05 14:23:01 +00001571 f->exited = 0;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001572
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001573 root = (struct node *) calloc(1, sizeof(struct node));
Miklos Szeredi8cffdb92001-11-09 14:49:18 +00001574 root->mode = 0;
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001575 root->rdev = 0;
1576 root->name = strdup("/");
1577 root->parent = 0;
Miklos Szeredi76f65782004-02-19 16:55:40 +00001578 root->ino = FUSE_ROOT_INO;
1579 root->generation = 0;
1580 hash_ino(f, root);
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001581
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001582 return f;
1583}
1584
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001585void fuse_destroy(struct fuse *f)
1586{
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001587 size_t i;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001588 for (i = 0; i < f->ino_table_size; i++) {
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001589 struct node *node;
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001590
1591 for (node = f->ino_table[i]; node != NULL; node = node->ino_next) {
1592 if (node->is_hidden) {
1593 char *path = get_path(f, node->ino);
1594 if (path)
1595 f->op.unlink(path);
1596 }
1597 }
1598 }
1599 for (i = 0; i < f->ino_table_size; i++) {
1600 struct node *node;
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001601 struct node *next;
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001602
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001603 for (node = f->ino_table[i]; node != NULL; node = next) {
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001604 next = node->ino_next;
1605 free_node(node);
1606 }
1607 }
1608 free(f->ino_table);
1609 free(f->name_table);
Miklos Szeredia181e612001-11-06 12:03:23 +00001610 pthread_mutex_destroy(&f->lock);
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001611 free(f);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001612}