blob: fae68a1202e2610cdc2d5690d566dd2190b3246d [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"
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 Szeredid169f312004-09-22 08:48:26 +000026static struct fuse_context *(*fuse_getcontext)(void) = NULL;
27
Miklos Szeredic8ba2372002-12-10 12:26:00 +000028static const char *opname(enum fuse_opcode opcode)
29{
Miklos Szeredi7eafcce2004-06-19 22:42:38 +000030 switch (opcode) {
Miklos Szeredi3ed84232004-03-30 15:17:26 +000031 case FUSE_LOOKUP: return "LOOKUP";
32 case FUSE_FORGET: return "FORGET";
33 case FUSE_GETATTR: return "GETATTR";
34 case FUSE_SETATTR: return "SETATTR";
35 case FUSE_READLINK: return "READLINK";
36 case FUSE_SYMLINK: return "SYMLINK";
37 case FUSE_GETDIR: return "GETDIR";
38 case FUSE_MKNOD: return "MKNOD";
39 case FUSE_MKDIR: return "MKDIR";
40 case FUSE_UNLINK: return "UNLINK";
41 case FUSE_RMDIR: return "RMDIR";
42 case FUSE_RENAME: return "RENAME";
43 case FUSE_LINK: return "LINK";
44 case FUSE_OPEN: return "OPEN";
45 case FUSE_READ: return "READ";
46 case FUSE_WRITE: return "WRITE";
47 case FUSE_STATFS: return "STATFS";
Miklos Szeredi99f20742004-05-19 08:01:10 +000048 case FUSE_FLUSH: return "FLUSH";
Miklos Szeredi3ed84232004-03-30 15:17:26 +000049 case FUSE_RELEASE: return "RELEASE";
50 case FUSE_FSYNC: return "FSYNC";
51 case FUSE_SETXATTR: return "SETXATTR";
52 case FUSE_GETXATTR: return "GETXATTR";
53 case FUSE_LISTXATTR: return "LISTXATTR";
54 case FUSE_REMOVEXATTR: return "REMOVEXATTR";
Miklos Szeredi99f20742004-05-19 08:01:10 +000055 default: return "???";
Miklos Szeredic8ba2372002-12-10 12:26:00 +000056 }
57}
58
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +000059
60static inline void dec_avail(struct fuse *f)
61{
62 pthread_mutex_lock(&f->lock);
63 f->numavail --;
64 pthread_mutex_unlock(&f->lock);
65}
66
Miklos Szeredi97c61e92001-11-07 12:09:43 +000067static struct node *__get_node(struct fuse *f, fino_t ino)
Miklos Szeredia181e612001-11-06 12:03:23 +000068{
Miklos Szeredi97c61e92001-11-07 12:09:43 +000069 size_t hash = ino % f->ino_table_size;
70 struct node *node;
71
Miklos Szeredi7eafcce2004-06-19 22:42:38 +000072 for (node = f->ino_table[hash]; node != NULL; node = node->ino_next)
73 if (node->ino == ino)
Miklos Szeredi97c61e92001-11-07 12:09:43 +000074 return node;
75
76 return NULL;
Miklos Szeredia181e612001-11-06 12:03:23 +000077}
78
Miklos Szeredi97c61e92001-11-07 12:09:43 +000079static struct node *get_node(struct fuse *f, fino_t ino)
Miklos Szeredia181e612001-11-06 12:03:23 +000080{
Miklos Szeredi97c61e92001-11-07 12:09:43 +000081 struct node *node = __get_node(f, ino);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +000082 if (node != NULL)
Miklos Szeredi97c61e92001-11-07 12:09:43 +000083 return node;
84
85 fprintf(stderr, "fuse internal error: inode %lu not found\n", ino);
86 abort();
Miklos Szeredia181e612001-11-06 12:03:23 +000087}
88
Miklos Szeredi76f65782004-02-19 16:55:40 +000089static void hash_ino(struct fuse *f, struct node *node)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000090{
Miklos Szeredi76f65782004-02-19 16:55:40 +000091 size_t hash = node->ino % f->ino_table_size;
Miklos Szeredi97c61e92001-11-07 12:09:43 +000092 node->ino_next = f->ino_table[hash];
93 f->ino_table[hash] = node;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000094}
95
Miklos Szeredi97c61e92001-11-07 12:09:43 +000096static void unhash_ino(struct fuse *f, struct node *node)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000097{
Miklos Szeredi97c61e92001-11-07 12:09:43 +000098 size_t hash = node->ino % f->ino_table_size;
99 struct node **nodep = &f->ino_table[hash];
100
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000101 for (; *nodep != NULL; nodep = &(*nodep)->ino_next)
102 if (*nodep == node) {
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000103 *nodep = node->ino_next;
104 return;
105 }
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000106}
107
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000108static fino_t next_ino(struct fuse *f)
109{
Miklos Szeredi76f65782004-02-19 16:55:40 +0000110 do {
111 f->ctr++;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000112 if (!f->ctr)
Miklos Szeredi76f65782004-02-19 16:55:40 +0000113 f->generation ++;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000114 } while (f->ctr == 0 || __get_node(f, f->ctr) != NULL);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000115 return f->ctr;
116}
117
118static void free_node(struct node *node)
119{
120 free(node->name);
121 free(node);
122}
123
124static unsigned int name_hash(struct fuse *f, fino_t parent, const char *name)
125{
126 unsigned int hash = *name;
127
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000128 if (hash)
129 for (name += 1; *name != '\0'; name++)
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000130 hash = (hash << 5) - hash + *name;
131
132 return (hash + parent) % f->name_table_size;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000133}
134
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000135static struct node *__lookup_node(struct fuse *f, fino_t parent,
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000136 const char *name)
137{
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000138 size_t hash = name_hash(f, parent, name);
139 struct node *node;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000140
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000141 for (node = f->name_table[hash]; node != NULL; node = node->name_next)
142 if (node->parent == parent && strcmp(node->name, name) == 0)
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000143 return node;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000144
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000145 return NULL;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000146}
147
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000148static struct node *lookup_node(struct fuse *f, fino_t parent,
149 const char *name)
150{
151 struct node *node;
152
153 pthread_mutex_lock(&f->lock);
154 node = __lookup_node(f, parent, name);
155 pthread_mutex_unlock(&f->lock);
156 if (node != NULL)
157 return node;
158
159 fprintf(stderr, "fuse internal error: node %lu/%s not found\n", parent,
160 name);
161 abort();
162}
163
Miklos Szeredib2cf9562004-09-16 08:42:40 +0000164static int hash_name(struct fuse *f, struct node *node, fino_t parent,
165 const char *name)
Miklos Szeredi5e183482001-10-31 14:52:35 +0000166{
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000167 size_t hash = name_hash(f, parent, name);
Miklos Szeredia181e612001-11-06 12:03:23 +0000168 node->parent = parent;
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000169 node->name = strdup(name);
Miklos Szeredib2cf9562004-09-16 08:42:40 +0000170 if (node->name == NULL)
171 return -1;
172
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000173 node->name_next = f->name_table[hash];
Miklos Szeredib2cf9562004-09-16 08:42:40 +0000174 f->name_table[hash] = node;
175 return 0;
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 Szeredib2cf9562004-09-16 08:42:40 +0000219 if (node == NULL)
Miklos Szeredic2309912004-09-21 13:40:38 +0000220 goto out_err;
Miklos Szeredib2cf9562004-09-16 08:42:40 +0000221
Miklos Szeredia181e612001-11-06 12:03:23 +0000222 node->mode = mode;
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000223 node->rdev = rdev;
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000224 node->open_count = 0;
225 node->is_hidden = 0;
Miklos Szeredi76f65782004-02-19 16:55:40 +0000226 node->ino = next_ino(f);
227 node->generation = f->generation;
Miklos Szeredib2cf9562004-09-16 08:42:40 +0000228 if (hash_name(f, node, parent, name) == -1) {
229 free(node);
Miklos Szeredic2309912004-09-21 13:40:38 +0000230 node = NULL;
231 goto out_err;
Miklos Szeredib2cf9562004-09-16 08:42:40 +0000232 }
Miklos Szeredi76f65782004-02-19 16:55:40 +0000233 hash_ino(f, node);
Miklos Szeredia181e612001-11-06 12:03:23 +0000234
Miklos Szeredic2309912004-09-21 13:40:38 +0000235 out:
Miklos Szeredia181e612001-11-06 12:03:23 +0000236 node->version = version;
Miklos Szeredic2309912004-09-21 13:40:38 +0000237 out_err:
Miklos Szeredia181e612001-11-06 12:03:23 +0000238 pthread_mutex_unlock(&f->lock);
Miklos Szeredi76f65782004-02-19 16:55:40 +0000239 return node;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000240}
241
Miklos Szeredi891b8742004-07-29 09:27:49 +0000242static int path_lookup(struct fuse *f, const char *path, fino_t *inop)
243{
244 fino_t ino;
245 int err;
246 char *s;
247 char *name;
248 char *tmp = strdup(path);
249 if (!tmp)
250 return -ENOMEM;
251
252 pthread_mutex_lock(&f->lock);
253 ino = FUSE_ROOT_INO;
254 err = 0;
255 for (s = tmp; (name = strsep(&s, "/")) != NULL; ) {
256 if (name[0]) {
257 struct node *node = __lookup_node(f, ino, name);
258 if (node == NULL) {
259 err = -ENOENT;
260 break;
261 }
262 ino = node->ino;
263 }
264 }
265 pthread_mutex_unlock(&f->lock);
266 free(tmp);
267 if (!err)
268 *inop = ino;
269
270 return err;
271}
272
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000273static char *add_name(char *buf, char *s, const char *name)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000274{
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000275 size_t len = strlen(name);
276 s -= len;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000277 if (s <= buf) {
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000278 fprintf(stderr, "fuse: path too long: ...%s\n", s + len);
279 return NULL;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000280 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000281 strncpy(s, name, len);
282 s--;
283 *s = '/';
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000284
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000285 return s;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000286}
287
Miklos Szeredia181e612001-11-06 12:03:23 +0000288static char *get_path_name(struct fuse *f, fino_t ino, const char *name)
Miklos Szeredib483c932001-10-29 14:57:57 +0000289{
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000290 char buf[FUSE_MAX_PATH];
291 char *s = buf + FUSE_MAX_PATH - 1;
292 struct node *node;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000293
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000294 *s = '\0';
Miklos Szeredia181e612001-11-06 12:03:23 +0000295
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000296 if (name != NULL) {
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000297 s = add_name(buf, s, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000298 if (s == NULL)
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000299 return NULL;
300 }
301
302 pthread_mutex_lock(&f->lock);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000303 for (node = get_node(f, ino); node->ino != FUSE_ROOT_INO;
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000304 node = get_node(f, node->parent)) {
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000305 if (node->name == NULL) {
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000306 s = NULL;
307 break;
308 }
309
310 s = add_name(buf, s, node->name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000311 if (s == NULL)
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000312 break;
313 }
314 pthread_mutex_unlock(&f->lock);
315
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000316 if (s == NULL)
Miklos Szeredi5e183482001-10-31 14:52:35 +0000317 return NULL;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000318 else if (*s == '\0')
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000319 return strdup("/");
320 else
321 return strdup(s);
322}
Miklos Szeredia181e612001-11-06 12:03:23 +0000323
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000324static char *get_path(struct fuse *f, fino_t ino)
325{
326 return get_path_name(f, ino, NULL);
Miklos Szeredib483c932001-10-29 14:57:57 +0000327}
328
Miklos Szeredia181e612001-11-06 12:03:23 +0000329static void destroy_node(struct fuse *f, fino_t ino, int version)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000330{
Miklos Szeredia181e612001-11-06 12:03:23 +0000331 struct node *node;
332
333 pthread_mutex_lock(&f->lock);
Miklos Szeredi8b2d3332004-09-09 08:44:01 +0000334 node = __get_node(f, ino);
335 if (node && node->version == version && ino != FUSE_ROOT_INO) {
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000336 unhash_name(f, node);
337 unhash_ino(f, node);
Miklos Szeredia181e612001-11-06 12:03:23 +0000338 free_node(node);
339 }
340 pthread_mutex_unlock(&f->lock);
341
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000342}
343
Miklos Szeredi5e183482001-10-31 14:52:35 +0000344static void remove_node(struct fuse *f, fino_t dir, const char *name)
345{
Miklos Szeredia181e612001-11-06 12:03:23 +0000346 struct node *node;
347
348 pthread_mutex_lock(&f->lock);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000349 node = __lookup_node(f, dir, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000350 if (node == NULL) {
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000351 fprintf(stderr, "fuse internal error: unable to remove node %lu/%s\n",
352 dir, name);
353 abort();
354 }
355 unhash_name(f, node);
Miklos Szeredia181e612001-11-06 12:03:23 +0000356 pthread_mutex_unlock(&f->lock);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000357}
358
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000359static int rename_node(struct fuse *f, fino_t olddir, const char *oldname,
360 fino_t newdir, const char *newname, int hide)
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000361{
Miklos Szeredia181e612001-11-06 12:03:23 +0000362 struct node *node;
363 struct node *newnode;
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000364 int err = 0;
Miklos Szeredia181e612001-11-06 12:03:23 +0000365
366 pthread_mutex_lock(&f->lock);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000367 node = __lookup_node(f, olddir, oldname);
368 newnode = __lookup_node(f, newdir, newname);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000369 if (node == NULL) {
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000370 fprintf(stderr, "fuse internal error: unable to rename node %lu/%s\n",
371 olddir, oldname);
372 abort();
373 }
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000374
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000375 if (newnode != NULL) {
376 if (hide) {
377 fprintf(stderr, "fuse: hidden file got created during hiding\n");
Miklos Szeredib2cf9562004-09-16 08:42:40 +0000378 err = -EBUSY;
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000379 goto out;
380 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000381 unhash_name(f, newnode);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000382 }
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000383
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000384 unhash_name(f, node);
Miklos Szeredib2cf9562004-09-16 08:42:40 +0000385 if (hash_name(f, node, newdir, newname) == -1) {
386 err = -ENOMEM;
387 goto out;
388 }
389
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000390 if (hide)
391 node->is_hidden = 1;
392
393 out:
Miklos Szeredia181e612001-11-06 12:03:23 +0000394 pthread_mutex_unlock(&f->lock);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000395 return err;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000396}
397
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000398static void convert_stat(struct stat *stbuf, struct fuse_attr *attr)
399{
Miklos Szeredib5958612004-02-20 14:10:49 +0000400 attr->mode = stbuf->st_mode;
401 attr->nlink = stbuf->st_nlink;
402 attr->uid = stbuf->st_uid;
403 attr->gid = stbuf->st_gid;
404 attr->rdev = stbuf->st_rdev;
405 attr->size = stbuf->st_size;
406 attr->blocks = stbuf->st_blocks;
407 attr->atime = stbuf->st_atime;
Miklos Szeredib5958612004-02-20 14:10:49 +0000408 attr->mtime = stbuf->st_mtime;
Miklos Szeredib5958612004-02-20 14:10:49 +0000409 attr->ctime = stbuf->st_ctime;
Miklos Szeredicb264512004-06-23 18:52:50 +0000410#ifdef HAVE_STRUCT_STAT_ST_ATIM
411 attr->atimensec = stbuf->st_atim.tv_nsec;
412 attr->mtimensec = stbuf->st_mtim.tv_nsec;
Miklos Szeredib5958612004-02-20 14:10:49 +0000413 attr->ctimensec = stbuf->st_ctim.tv_nsec;
Miklos Szeredicb264512004-06-23 18:52:50 +0000414#endif
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000415}
416
Miklos Szeredia181e612001-11-06 12:03:23 +0000417static int fill_dir(struct fuse_dirhandle *dh, char *name, int type)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000418{
419 struct fuse_dirent dirent;
420 size_t reclen;
421 size_t res;
422
Miklos Szeredi43696432001-11-18 19:15:05 +0000423 dirent.ino = (unsigned long) -1;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000424 dirent.namelen = strlen(name);
425 strncpy(dirent.name, name, sizeof(dirent.name));
426 dirent.type = type;
427 reclen = FUSE_DIRENT_SIZE(&dirent);
428 res = fwrite(&dirent, reclen, 1, dh->fp);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000429 if (res == 0) {
Miklos Szeredi96249982001-11-21 12:21:19 +0000430 perror("fuse: writing directory file");
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000431 return -EIO;
432 }
433 return 0;
434}
435
Miklos Szeredi73798f92004-07-12 15:55:11 +0000436static int send_reply_raw(struct fuse *f, char *outbuf, size_t outsize,
437 int locked)
Miklos Szeredi43696432001-11-18 19:15:05 +0000438{
439 int res;
440
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000441 if ((f->flags & FUSE_DEBUG)) {
Miklos Szeredi43696432001-11-18 19:15:05 +0000442 struct fuse_out_header *out = (struct fuse_out_header *) outbuf;
443 printf(" unique: %i, error: %i (%s), outsize: %i\n", out->unique,
444 out->error, strerror(-out->error), outsize);
445 fflush(stdout);
446 }
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +0000447
Miklos Szeredi4e71c9f2004-02-09 12:05:14 +0000448 /* This needs to be done before the reply, otherwise the scheduler
449 could play tricks with us, and only let the counter be increased
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +0000450 long after the operation is done */
Miklos Szeredi73798f92004-07-12 15:55:11 +0000451 if (!locked)
452 pthread_mutex_lock(&f->lock);
453 f->numavail ++;
454 if (!locked)
455 pthread_mutex_unlock(&f->lock);
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +0000456
Miklos Szeredi43696432001-11-18 19:15:05 +0000457 res = write(f->fd, outbuf, outsize);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000458 if (res == -1) {
Miklos Szeredi43696432001-11-18 19:15:05 +0000459 /* ENOENT means the operation was interrupted */
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000460 if (!f->exited && errno != ENOENT)
Miklos Szeredi96249982001-11-21 12:21:19 +0000461 perror("fuse: writing device");
Miklos Szeredi40b9a5a2002-12-10 16:09:02 +0000462 return -errno;
Miklos Szeredi43696432001-11-18 19:15:05 +0000463 }
Miklos Szeredi40b9a5a2002-12-10 16:09:02 +0000464 return 0;
Miklos Szeredi43696432001-11-18 19:15:05 +0000465}
466
Miklos Szeredi73798f92004-07-12 15:55:11 +0000467static int __send_reply(struct fuse *f, struct fuse_in_header *in, int error,
468 void *arg, size_t argsize, int locked)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000469{
Miklos Szeredi40b9a5a2002-12-10 16:09:02 +0000470 int res;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000471 char *outbuf;
472 size_t outsize;
473 struct fuse_out_header *out;
474
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000475 if (error <= -1000 || error > 0) {
Miklos Szeredi0f48a262002-12-05 14:23:01 +0000476 fprintf(stderr, "fuse: bad error value: %i\n", error);
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000477 error = -ERANGE;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000478 }
479
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000480 if (error)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000481 argsize = 0;
482
483 outsize = sizeof(struct fuse_out_header) + argsize;
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000484 outbuf = (char *) malloc(outsize);
Miklos Szeredib2cf9562004-09-16 08:42:40 +0000485 if (outbuf == NULL) {
486 fprintf(stderr, "fuse: failed to allocate reply buffer\n");
487 res = -ENOMEM;
488 } else {
489 out = (struct fuse_out_header *) outbuf;
490 memset(out, 0, sizeof(struct fuse_out_header));
491 out->unique = in->unique;
492 out->error = error;
493 if (argsize != 0)
494 memcpy(outbuf + sizeof(struct fuse_out_header), arg, argsize);
495
496 res = send_reply_raw(f, outbuf, outsize, locked);
497 free(outbuf);
498 }
Miklos Szeredi40b9a5a2002-12-10 16:09:02 +0000499
500 return res;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000501}
502
Miklos Szeredi73798f92004-07-12 15:55:11 +0000503static int send_reply(struct fuse *f, struct fuse_in_header *in, int error,
504 void *arg, size_t argsize)
505{
506 return __send_reply(f, in, error, arg, argsize, 0);
507}
508
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000509static int is_open(struct fuse *f, fino_t dir, const char *name)
510{
511 struct node *node;
512 int isopen = 0;
513 pthread_mutex_lock(&f->lock);
514 node = __lookup_node(f, dir, name);
515 if (node && node->open_count > 0)
516 isopen = 1;
517 pthread_mutex_unlock(&f->lock);
518 return isopen;
519}
520
521static char *hidden_name(struct fuse *f, fino_t dir, const char *oldname,
522 char *newname, size_t bufsize)
523{
524 struct stat buf;
525 struct node *node;
526 struct node *newnode;
527 char *newpath;
528 int res;
529 int failctr = 10;
530
531 if (!f->op.getattr)
532 return NULL;
533
534 do {
535 node = lookup_node(f, dir, oldname);
536 pthread_mutex_lock(&f->lock);
537 do {
538 f->hidectr ++;
539 snprintf(newname, bufsize, ".fuse_hidden%08x%08x",
540 (unsigned int) node->ino, f->hidectr);
541 newnode = __lookup_node(f, dir, newname);
542 } while(newnode);
543 pthread_mutex_unlock(&f->lock);
544
545 newpath = get_path_name(f, dir, newname);
546 if (!newpath)
547 break;
548
549 res = f->op.getattr(newpath, &buf);
550 if (res != 0)
551 break;
552 free(newpath);
553 newpath = NULL;
554 } while(--failctr);
555
556 return newpath;
557}
558
559static int hide_node(struct fuse *f, const char *oldpath, fino_t dir,
560 const char *oldname)
561{
562 char newname[64];
563 char *newpath;
Miklos Szeredib2cf9562004-09-16 08:42:40 +0000564 int err = -EBUSY;
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000565
Miklos Szeredib2cf9562004-09-16 08:42:40 +0000566 if (f->op.rename && f->op.unlink) {
567 newpath = hidden_name(f, dir, oldname, newname, sizeof(newname));
568 if (newpath) {
569 int res = f->op.rename(oldpath, newpath);
570 if (res == 0)
571 err = rename_node(f, dir, oldname, dir, newname, 1);
572 free(newpath);
573 }
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000574 }
Miklos Szeredib2cf9562004-09-16 08:42:40 +0000575 return err;
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000576}
577
Miklos Szeredi76f65782004-02-19 16:55:40 +0000578static int lookup_path(struct fuse *f, fino_t ino, int version, char *name,
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000579 const char *path, struct fuse_entry_out *arg)
Miklos Szeredi76f65782004-02-19 16:55:40 +0000580{
581 int res;
582 struct stat buf;
583
584 res = f->op.getattr(path, &buf);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000585 if (res == 0) {
Miklos Szeredi76f65782004-02-19 16:55:40 +0000586 struct node *node;
587
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000588 memset(arg, 0, sizeof(struct fuse_entry_out));
Miklos Szeredi76f65782004-02-19 16:55:40 +0000589 convert_stat(&buf, &arg->attr);
590 node = find_node(f, ino, name, &arg->attr, version);
Miklos Szeredib2cf9562004-09-16 08:42:40 +0000591 if (node == NULL)
592 res = -ENOMEM;
593 else {
594 arg->ino = node->ino;
595 arg->generation = node->generation;
596 arg->entry_valid = ENTRY_REVALIDATE_TIME;
597 arg->entry_valid_nsec = 0;
598 arg->attr_valid = ATTR_REVALIDATE_TIME;
599 arg->attr_valid_nsec = 0;
600 if (f->flags & FUSE_DEBUG) {
601 printf(" INO: %li\n", arg->ino);
602 fflush(stdout);
603 }
Miklos Szeredi76f65782004-02-19 16:55:40 +0000604 }
605 }
606 return res;
607}
608
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000609static void do_lookup(struct fuse *f, struct fuse_in_header *in, char *name)
610{
611 int res;
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000612 int res2;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000613 char *path;
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000614 struct fuse_entry_out arg;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000615
Miklos Szeredi5e183482001-10-31 14:52:35 +0000616 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000617 path = get_path_name(f, in->ino, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000618 if (path != NULL) {
619 if (f->flags & FUSE_DEBUG) {
Miklos Szeredi6ebe2342002-01-06 21:44:16 +0000620 printf("LOOKUP %s\n", path);
621 fflush(stdout);
622 }
Miklos Szeredi5e183482001-10-31 14:52:35 +0000623 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000624 if (f->op.getattr)
Miklos Szeredi76f65782004-02-19 16:55:40 +0000625 res = lookup_path(f, in->ino, in->unique, name, path, &arg);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000626 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000627 }
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000628 res2 = send_reply(f, in, res, &arg, sizeof(arg));
629 if (res == 0 && res2 == -ENOENT)
630 destroy_node(f, arg.ino, in->unique);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000631}
632
Miklos Szeredia181e612001-11-06 12:03:23 +0000633static void do_forget(struct fuse *f, struct fuse_in_header *in,
634 struct fuse_forget_in *arg)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000635{
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000636 if (f->flags & FUSE_DEBUG) {
Miklos Szeredi43696432001-11-18 19:15:05 +0000637 printf("FORGET %li/%i\n", in->ino, arg->version);
638 fflush(stdout);
639 }
Miklos Szeredia181e612001-11-06 12:03:23 +0000640 destroy_node(f, in->ino, arg->version);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000641}
642
643static void do_getattr(struct fuse *f, struct fuse_in_header *in)
644{
645 int res;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000646 char *path;
647 struct stat buf;
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000648 struct fuse_attr_out arg;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000649
Miklos Szeredi5e183482001-10-31 14:52:35 +0000650 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000651 path = get_path(f, in->ino);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000652 if (path != NULL) {
Miklos Szeredi5e183482001-10-31 14:52:35 +0000653 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000654 if (f->op.getattr)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000655 res = f->op.getattr(path, &buf);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000656 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000657 }
Miklos Szeredi0f48a262002-12-05 14:23:01 +0000658
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000659 if (res == 0) {
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000660 memset(&arg, 0, sizeof(struct fuse_attr_out));
661 arg.attr_valid = ATTR_REVALIDATE_TIME;
662 arg.attr_valid_nsec = 0;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000663 convert_stat(&buf, &arg.attr);
Miklos Szeredi0f48a262002-12-05 14:23:01 +0000664 }
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000665
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000666 send_reply(f, in, res, &arg, sizeof(arg));
667}
668
Miklos Szeredi680a69a2001-11-16 13:31:14 +0000669static int do_chmod(struct fuse *f, const char *path, struct fuse_attr *attr)
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000670{
671 int res;
672
673 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000674 if (f->op.chmod)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000675 res = f->op.chmod(path, attr->mode);
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000676
677 return res;
678}
679
Miklos Szeredi680a69a2001-11-16 13:31:14 +0000680static int do_chown(struct fuse *f, const char *path, struct fuse_attr *attr,
Miklos Szeredi2e50d432001-12-20 12:17:25 +0000681 int valid)
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000682{
683 int res;
684 uid_t uid = (valid & FATTR_UID) ? attr->uid : (uid_t) -1;
685 gid_t gid = (valid & FATTR_GID) ? attr->gid : (gid_t) -1;
686
687 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000688 if (f->op.chown)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000689 res = f->op.chown(path, uid, gid);
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000690
691 return res;
692}
693
Miklos Szeredi680a69a2001-11-16 13:31:14 +0000694static int do_truncate(struct fuse *f, const char *path,
695 struct fuse_attr *attr)
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000696{
697 int res;
698
699 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000700 if (f->op.truncate)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000701 res = f->op.truncate(path, attr->size);
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000702
703 return res;
704}
705
Miklos Szeredi680a69a2001-11-16 13:31:14 +0000706static int do_utime(struct fuse *f, const char *path, struct fuse_attr *attr)
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000707{
708 int res;
709 struct utimbuf buf;
710 buf.actime = attr->atime;
711 buf.modtime = attr->mtime;
712 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000713 if (f->op.utime)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000714 res = f->op.utime(path, &buf);
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000715
716 return res;
717}
718
Miklos Szeredi5e183482001-10-31 14:52:35 +0000719static void do_setattr(struct fuse *f, struct fuse_in_header *in,
720 struct fuse_setattr_in *arg)
721{
722 int res;
723 char *path;
724 int valid = arg->valid;
725 struct fuse_attr *attr = &arg->attr;
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000726 struct fuse_attr_out outarg;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000727
728 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 Szeredif3ea83b2001-11-07 14:55:16 +0000731 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000732 if (f->op.getattr) {
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000733 res = 0;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000734 if (!res && (valid & FATTR_MODE))
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000735 res = do_chmod(f, path, attr);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000736 if (!res && (valid & (FATTR_UID | FATTR_GID)))
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000737 res = do_chown(f, path, attr, valid);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000738 if (!res && (valid & FATTR_SIZE))
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000739 res = do_truncate(f, path, attr);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000740 if (!res && (valid & (FATTR_ATIME | FATTR_MTIME)) ==
Miklos Szeredib5958612004-02-20 14:10:49 +0000741 (FATTR_ATIME | FATTR_MTIME))
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000742 res = do_utime(f, path, attr);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000743 if (!res) {
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000744 struct stat buf;
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000745 res = f->op.getattr(path, &buf);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000746 if (!res) {
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000747 memset(&outarg, 0, sizeof(struct fuse_attr_out));
748 outarg.attr_valid = ATTR_REVALIDATE_TIME;
749 outarg.attr_valid_nsec = 0;
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000750 convert_stat(&buf, &outarg.attr);
Miklos Szeredi0f48a262002-12-05 14:23:01 +0000751 }
Miklos Szeredia181e612001-11-06 12:03:23 +0000752 }
Miklos Szeredi5e183482001-10-31 14:52:35 +0000753 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000754 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000755 }
Miklos Szeredia181e612001-11-06 12:03:23 +0000756 send_reply(f, in, res, &outarg, sizeof(outarg));
Miklos Szeredi5e183482001-10-31 14:52:35 +0000757}
758
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000759static void do_readlink(struct fuse *f, struct fuse_in_header *in)
760{
761 int res;
762 char link[PATH_MAX + 1];
Miklos Szeredib483c932001-10-29 14:57:57 +0000763 char *path;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000764
Miklos Szeredi5e183482001-10-31 14:52:35 +0000765 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000766 path = get_path(f, in->ino);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000767 if (path != NULL) {
Miklos Szeredi5e183482001-10-31 14:52:35 +0000768 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000769 if (f->op.readlink)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000770 res = f->op.readlink(path, link, sizeof(link));
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000771 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000772 }
Miklos Szeredi2df1c042001-11-06 15:07:17 +0000773 link[PATH_MAX] = '\0';
Miklos Szeredi4b2bef42002-01-09 12:23:27 +0000774 send_reply(f, in, res, link, res == 0 ? strlen(link) : 0);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000775}
776
777static void do_getdir(struct fuse *f, struct fuse_in_header *in)
778{
779 int res;
780 struct fuse_getdir_out arg;
Miklos Szeredia181e612001-11-06 12:03:23 +0000781 struct fuse_dirhandle dh;
Miklos Szeredib483c932001-10-29 14:57:57 +0000782 char *path;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000783
Miklos Szeredib483c932001-10-29 14:57:57 +0000784 dh.fuse = f;
785 dh.fp = tmpfile();
786 dh.dir = in->ino;
Miklos Szeredi0f48a262002-12-05 14:23:01 +0000787
Miklos Szeredi65afea12004-09-14 07:13:45 +0000788 res = -EIO;
789 if (dh.fp == NULL)
790 perror("fuse: failed to create temporary file");
791 else {
792 res = -ENOENT;
793 path = get_path(f, in->ino);
794 if (path != NULL) {
795 res = -ENOSYS;
796 if (f->op.getdir)
797 res = f->op.getdir(path, &dh, (fuse_dirfil_t) fill_dir);
798 free(path);
799 }
800 fflush(dh.fp);
801 }
Miklos Szeredi0f48a262002-12-05 14:23:01 +0000802 memset(&arg, 0, sizeof(struct fuse_getdir_out));
Miklos Szeredi65afea12004-09-14 07:13:45 +0000803 if (res == 0)
804 arg.fd = fileno(dh.fp);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000805 send_reply(f, in, res, &arg, sizeof(arg));
Miklos Szeredi65afea12004-09-14 07:13:45 +0000806 if (dh.fp != NULL)
807 fclose(dh.fp);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000808}
809
Miklos Szeredib483c932001-10-29 14:57:57 +0000810static void do_mknod(struct fuse *f, struct fuse_in_header *in,
811 struct fuse_mknod_in *inarg)
812{
813 int res;
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000814 int res2;
Miklos Szeredib483c932001-10-29 14:57:57 +0000815 char *path;
Miklos Szeredi76f65782004-02-19 16:55:40 +0000816 char *name = PARAM(inarg);
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000817 struct fuse_entry_out outarg;
Miklos Szeredib483c932001-10-29 14:57:57 +0000818
Miklos Szeredi5e183482001-10-31 14:52:35 +0000819 res = -ENOENT;
Miklos Szeredi76f65782004-02-19 16:55:40 +0000820 path = get_path_name(f, in->ino, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000821 if (path != NULL) {
822 if (f->flags & FUSE_DEBUG) {
Miklos Szeredi76f65782004-02-19 16:55:40 +0000823 printf("MKNOD %s\n", path);
824 fflush(stdout);
825 }
Miklos Szeredi5e183482001-10-31 14:52:35 +0000826 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000827 if (f->op.mknod && f->op.getattr) {
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000828 res = f->op.mknod(path, inarg->mode, inarg->rdev);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000829 if (res == 0)
Miklos Szeredi76f65782004-02-19 16:55:40 +0000830 res = lookup_path(f, in->ino, in->unique, name, path, &outarg);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000831 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000832 free(path);
Miklos Szeredib483c932001-10-29 14:57:57 +0000833 }
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000834 res2 = send_reply(f, in, res, &outarg, sizeof(outarg));
835 if (res == 0 && res2 == -ENOENT)
836 destroy_node(f, outarg.ino, in->unique);
Miklos Szeredib483c932001-10-29 14:57:57 +0000837}
838
839static void do_mkdir(struct fuse *f, struct fuse_in_header *in,
840 struct fuse_mkdir_in *inarg)
841{
842 int res;
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000843 int res2;
Miklos Szeredib483c932001-10-29 14:57:57 +0000844 char *path;
Miklos Szeredi76f65782004-02-19 16:55:40 +0000845 char *name = PARAM(inarg);
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000846 struct fuse_entry_out outarg;
Miklos Szeredib483c932001-10-29 14:57:57 +0000847
Miklos Szeredi5e183482001-10-31 14:52:35 +0000848 res = -ENOENT;
Miklos Szeredi76f65782004-02-19 16:55:40 +0000849 path = get_path_name(f, in->ino, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000850 if (path != NULL) {
851 if (f->flags & FUSE_DEBUG) {
Miklos Szeredi76f65782004-02-19 16:55:40 +0000852 printf("MKDIR %s\n", path);
853 fflush(stdout);
854 }
Miklos Szeredi5e183482001-10-31 14:52:35 +0000855 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000856 if (f->op.mkdir && f->op.getattr) {
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000857 res = f->op.mkdir(path, inarg->mode);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000858 if (res == 0)
Miklos Szeredi76f65782004-02-19 16:55:40 +0000859 res = lookup_path(f, in->ino, in->unique, name, path, &outarg);
860 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000861 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000862 }
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000863 res2 = send_reply(f, in, res, &outarg, sizeof(outarg));
864 if (res == 0 && res2 == -ENOENT)
865 destroy_node(f, outarg.ino, in->unique);
Miklos Szeredib483c932001-10-29 14:57:57 +0000866}
867
Miklos Szeredib5958612004-02-20 14:10:49 +0000868static void do_unlink(struct fuse *f, struct fuse_in_header *in, char *name)
Miklos Szeredib483c932001-10-29 14:57:57 +0000869{
870 int res;
871 char *path;
872
Miklos Szeredi5e183482001-10-31 14:52:35 +0000873 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000874 path = get_path_name(f, in->ino, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000875 if (path != NULL) {
Miklos Szeredi209f5d02004-07-24 19:56:16 +0000876 if (f->flags & FUSE_DEBUG) {
877 printf("UNLINK %s\n", path);
878 fflush(stdout);
879 }
Miklos Szeredi5e183482001-10-31 14:52:35 +0000880 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000881 if (f->op.unlink) {
Miklos Szeredi2529ca22004-07-13 15:36:52 +0000882 if (!(f->flags & FUSE_HARD_REMOVE) && is_open(f, in->ino, name))
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000883 res = hide_node(f, path, in->ino, name);
884 else {
885 res = f->op.unlink(path);
886 if (res == 0)
887 remove_node(f, in->ino, name);
888 }
Miklos Szeredi5e183482001-10-31 14:52:35 +0000889 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000890 free(path);
Miklos Szeredib483c932001-10-29 14:57:57 +0000891 }
Miklos Szeredib5958612004-02-20 14:10:49 +0000892 send_reply(f, in, res, NULL, 0);
893}
894
895static void do_rmdir(struct fuse *f, struct fuse_in_header *in, char *name)
896{
897 int res;
898 char *path;
899
900 res = -ENOENT;
901 path = get_path_name(f, in->ino, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000902 if (path != NULL) {
Miklos Szeredi209f5d02004-07-24 19:56:16 +0000903 if (f->flags & FUSE_DEBUG) {
904 printf("RMDIR %s\n", path);
905 fflush(stdout);
906 }
Miklos Szeredib5958612004-02-20 14:10:49 +0000907 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000908 if (f->op.rmdir) {
Miklos Szeredib5958612004-02-20 14:10:49 +0000909 res = f->op.rmdir(path);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000910 if (res == 0)
Miklos Szeredib5958612004-02-20 14:10:49 +0000911 remove_node(f, in->ino, name);
912 }
913 free(path);
914 }
Miklos Szeredib483c932001-10-29 14:57:57 +0000915 send_reply(f, in, res, NULL, 0);
916}
917
918static void do_symlink(struct fuse *f, struct fuse_in_header *in, char *name,
919 char *link)
920{
921 int res;
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000922 int res2;
Miklos Szeredib483c932001-10-29 14:57:57 +0000923 char *path;
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000924 struct fuse_entry_out outarg;
Miklos Szeredib483c932001-10-29 14:57:57 +0000925
Miklos Szeredi5e183482001-10-31 14:52:35 +0000926 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000927 path = get_path_name(f, in->ino, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000928 if (path != NULL) {
929 if (f->flags & FUSE_DEBUG) {
Miklos Szeredi76f65782004-02-19 16:55:40 +0000930 printf("SYMLINK %s\n", path);
931 fflush(stdout);
932 }
Miklos Szeredi5e183482001-10-31 14:52:35 +0000933 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000934 if (f->op.symlink && f->op.getattr) {
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000935 res = f->op.symlink(link, path);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000936 if (res == 0)
Miklos Szeredi76f65782004-02-19 16:55:40 +0000937 res = lookup_path(f, in->ino, in->unique, name, path, &outarg);
938 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000939 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000940 }
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000941 res2 = send_reply(f, in, res, &outarg, sizeof(outarg));
942 if (res == 0 && res2 == -ENOENT)
943 destroy_node(f, outarg.ino, in->unique);
944
Miklos Szeredib483c932001-10-29 14:57:57 +0000945}
946
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000947static void do_rename(struct fuse *f, struct fuse_in_header *in,
948 struct fuse_rename_in *inarg)
949{
950 int res;
951 fino_t olddir = in->ino;
952 fino_t newdir = inarg->newdir;
Miklos Szeredi6bf8b682002-10-28 08:49:39 +0000953 char *oldname = PARAM(inarg);
954 char *newname = oldname + strlen(oldname) + 1;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000955 char *oldpath;
956 char *newpath;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000957
Miklos Szeredi5e183482001-10-31 14:52:35 +0000958 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000959 oldpath = get_path_name(f, olddir, oldname);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000960 if (oldpath != NULL) {
Miklos Szeredia181e612001-11-06 12:03:23 +0000961 newpath = get_path_name(f, newdir, newname);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000962 if (newpath != NULL) {
Miklos Szeredi209f5d02004-07-24 19:56:16 +0000963 if (f->flags & FUSE_DEBUG) {
964 printf("RENAME %s -> %s\n", oldpath, newpath);
965 fflush(stdout);
966 }
Miklos Szeredi5e183482001-10-31 14:52:35 +0000967 res = -ENOSYS;
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000968 if (f->op.rename) {
969 res = 0;
Miklos Szeredi2529ca22004-07-13 15:36:52 +0000970 if (!(f->flags & FUSE_HARD_REMOVE) &&
971 is_open(f, newdir, newname))
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000972 res = hide_node(f, newpath, newdir, newname);
973 if (res == 0) {
974 res = f->op.rename(oldpath, newpath);
975 if (res == 0)
Miklos Szeredib2cf9562004-09-16 08:42:40 +0000976 res = rename_node(f, olddir, oldname, newdir, newname, 0);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000977 }
978 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000979 free(newpath);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000980 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000981 free(oldpath);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000982 }
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000983 send_reply(f, in, res, NULL, 0);
984}
985
986static void do_link(struct fuse *f, struct fuse_in_header *in,
Miklos Szeredi5e183482001-10-31 14:52:35 +0000987 struct fuse_link_in *arg)
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000988{
989 int res;
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000990 int res2;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000991 char *oldpath;
992 char *newpath;
Miklos Szeredi76f65782004-02-19 16:55:40 +0000993 char *name = PARAM(arg);
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000994 struct fuse_entry_out outarg;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000995
Miklos Szeredi5e183482001-10-31 14:52:35 +0000996 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000997 oldpath = get_path(f, in->ino);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000998 if (oldpath != NULL) {
Miklos Szeredi76f65782004-02-19 16:55:40 +0000999 newpath = get_path_name(f, arg->newdir, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001000 if (newpath != NULL) {
1001 if (f->flags & FUSE_DEBUG) {
Miklos Szeredi76f65782004-02-19 16:55:40 +00001002 printf("LINK %s\n", newpath);
1003 fflush(stdout);
1004 }
Miklos Szeredi5e183482001-10-31 14:52:35 +00001005 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001006 if (f->op.link && f->op.getattr) {
Miklos Szeredi0a7077f2001-11-11 18:20:17 +00001007 res = f->op.link(oldpath, newpath);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001008 if (res == 0)
Miklos Szeredi76f65782004-02-19 16:55:40 +00001009 res = lookup_path(f, arg->newdir, in->unique, name,
1010 newpath, &outarg);
1011 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001012 free(newpath);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001013 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001014 free(oldpath);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001015 }
Miklos Szeredi2778f6c2004-06-21 09:45:30 +00001016 res2 = send_reply(f, in, res, &outarg, sizeof(outarg));
1017 if (res == 0 && res2 == -ENOENT)
1018 destroy_node(f, outarg.ino, in->unique);
Miklos Szeredi19dff1b2001-10-30 15:06:52 +00001019}
1020
Miklos Szeredi5e183482001-10-31 14:52:35 +00001021static void do_open(struct fuse *f, struct fuse_in_header *in,
1022 struct fuse_open_in *arg)
1023{
1024 int res;
1025 char *path;
Miklos Szeredi209f5d02004-07-24 19:56:16 +00001026 struct fuse_open_out outarg;
Miklos Szeredi5e183482001-10-31 14:52:35 +00001027
1028 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +00001029 path = get_path(f, in->ino);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001030 if (path != NULL) {
Miklos Szeredi5e183482001-10-31 14:52:35 +00001031 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001032 if (f->op.open)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +00001033 res = f->op.open(path, arg->flags);
Miklos Szeredi40b9a5a2002-12-10 16:09:02 +00001034 }
Miklos Szeredi73798f92004-07-12 15:55:11 +00001035 if (res == 0) {
1036 int res2;
1037
1038 /* If the request is interrupted the lock must be held until
1039 the cancellation is finished. Otherwise there could be
1040 races with rename/unlink, against which the kernel can't
1041 protect */
1042 pthread_mutex_lock(&f->lock);
Miklos Szeredi209f5d02004-07-24 19:56:16 +00001043 f->fh_ctr ++;
1044 outarg.fh = f->fh_ctr;
1045 if (f->flags & FUSE_DEBUG) {
1046 printf("OPEN[%u] flags: 0x%x\n", outarg.fh, arg->flags);
1047 fflush(stdout);
1048 }
1049
1050 res2 = __send_reply(f, in, res, &outarg, sizeof(outarg), 1);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001051 if(res2 == -ENOENT) {
1052 /* The open syscall was interrupted, so it must be cancelled */
1053 if(f->op.release)
1054 f->op.release(path, arg->flags);
Miklos Szeredi73798f92004-07-12 15:55:11 +00001055 } else
1056 get_node(f, in->ino)->open_count ++;
1057 pthread_mutex_unlock(&f->lock);
1058
1059 } else
1060 send_reply(f, in, res, NULL, 0);
1061
Miklos Szeredi9a31cca2004-06-26 21:11:25 +00001062 if (path)
1063 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001064}
1065
Miklos Szeredi209f5d02004-07-24 19:56:16 +00001066static void do_flush(struct fuse *f, struct fuse_in_header *in,
1067 struct fuse_flush_in *arg)
Miklos Szeredie2e4ac22004-05-18 08:45:28 +00001068{
1069 char *path;
1070 int res;
1071
1072 res = -ENOENT;
1073 path = get_path(f, in->ino);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001074 if (path != NULL) {
Miklos Szeredi209f5d02004-07-24 19:56:16 +00001075 if (f->flags & FUSE_DEBUG) {
1076 printf("FLUSH[%u]\n", arg->fh);
1077 fflush(stdout);
1078 }
Miklos Szeredie2e4ac22004-05-18 08:45:28 +00001079 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001080 if (f->op.flush)
Miklos Szeredie2e4ac22004-05-18 08:45:28 +00001081 res = f->op.flush(path);
1082 free(path);
1083 }
1084 send_reply(f, in, res, NULL, 0);
1085}
1086
Miklos Szeredi9478e862002-12-11 09:50:26 +00001087static void do_release(struct fuse *f, struct fuse_in_header *in,
Miklos Szeredi209f5d02004-07-24 19:56:16 +00001088 struct fuse_release_in *arg)
Miklos Szeredic8ba2372002-12-10 12:26:00 +00001089{
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001090 struct node *node;
1091 char *path;
Miklos Szeredic8ba2372002-12-10 12:26:00 +00001092
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001093 pthread_mutex_lock(&f->lock);
1094 node = get_node(f, in->ino);
1095 --node->open_count;
1096 pthread_mutex_unlock(&f->lock);
1097
1098 path = get_path(f, in->ino);
1099 if (path != NULL) {
Miklos Szeredi209f5d02004-07-24 19:56:16 +00001100 if (f->flags & FUSE_DEBUG) {
1101 printf("RELEASE[%u]\n", arg->fh);
1102 fflush(stdout);
1103 }
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001104 if (f->op.release)
Miklos Szeredib3210582004-06-23 13:54:33 +00001105 f->op.release(path, arg->flags);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001106
1107 if(node->is_hidden && node->open_count == 0)
1108 /* can now clean up this hidden file */
1109 f->op.unlink(path);
1110
1111 free(path);
Miklos Szeredic8ba2372002-12-10 12:26:00 +00001112 }
Miklos Szeredi556d03d2004-06-30 11:13:41 +00001113 send_reply(f, in, 0, NULL, 0);
Miklos Szeredic8ba2372002-12-10 12:26:00 +00001114}
1115
Miklos Szeredi5e183482001-10-31 14:52:35 +00001116static void do_read(struct fuse *f, struct fuse_in_header *in,
1117 struct fuse_read_in *arg)
1118{
1119 int res;
1120 char *path;
Miklos Szeredi43696432001-11-18 19:15:05 +00001121 char *outbuf = (char *) malloc(sizeof(struct fuse_out_header) + arg->size);
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001122 if (outbuf == NULL)
1123 send_reply(f, in, -ENOMEM, NULL, 0);
1124 else {
1125 struct fuse_out_header *out = (struct fuse_out_header *) outbuf;
1126 char *buf = outbuf + sizeof(struct fuse_out_header);
1127 size_t size;
1128 size_t outsize;
1129
1130 res = -ENOENT;
1131 path = get_path(f, in->ino);
1132 if (path != NULL) {
1133 if (f->flags & FUSE_DEBUG) {
1134 printf("READ[%u] %u bytes from %llu\n", arg->fh, arg->size,
1135 arg->offset);
1136 fflush(stdout);
1137 }
1138
1139 res = -ENOSYS;
1140 if (f->op.read)
1141 res = f->op.read(path, buf, arg->size, arg->offset);
1142 free(path);
Miklos Szeredi6ebe2342002-01-06 21:44:16 +00001143 }
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001144
1145 size = 0;
1146 if (res >= 0) {
1147 size = res;
1148 res = 0;
1149 if (f->flags & FUSE_DEBUG) {
1150 printf(" READ[%u] %u bytes\n", arg->fh, size);
1151 fflush(stdout);
1152 }
Miklos Szeredi6ebe2342002-01-06 21:44:16 +00001153 }
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001154 memset(out, 0, sizeof(struct fuse_out_header));
1155 out->unique = in->unique;
1156 out->error = res;
1157 outsize = sizeof(struct fuse_out_header) + size;
1158
1159 send_reply_raw(f, outbuf, outsize, 0);
1160 free(outbuf);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001161 }
Miklos Szeredi5e183482001-10-31 14:52:35 +00001162}
Miklos Szeredib483c932001-10-29 14:57:57 +00001163
Miklos Szeredia181e612001-11-06 12:03:23 +00001164static void do_write(struct fuse *f, struct fuse_in_header *in,
1165 struct fuse_write_in *arg)
1166{
1167 int res;
1168 char *path;
Miklos Szerediad051c32004-07-02 09:22:50 +00001169 struct fuse_write_out outarg;
Miklos Szeredia181e612001-11-06 12:03:23 +00001170
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001171 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +00001172 path = get_path(f, in->ino);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001173 if (path != NULL) {
1174 if (f->flags & FUSE_DEBUG) {
Miklos Szeredi209f5d02004-07-24 19:56:16 +00001175 printf("WRITE%s[%u] %u bytes to %llu\n",
1176 arg->writepage ? "PAGE" : "", arg->fh, arg->size,
1177 arg->offset);
Miklos Szeredi6ebe2342002-01-06 21:44:16 +00001178 fflush(stdout);
1179 }
1180
Miklos Szeredia181e612001-11-06 12:03:23 +00001181 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001182 if (f->op.write)
Miklos Szeredi6bf8b682002-10-28 08:49:39 +00001183 res = f->op.write(path, PARAM(arg), arg->size, arg->offset);
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001184 free(path);
Miklos Szeredia181e612001-11-06 12:03:23 +00001185 }
1186
Miklos Szerediad051c32004-07-02 09:22:50 +00001187 if (res >= 0) {
1188 outarg.size = res;
1189 res = 0;
Miklos Szeredia181e612001-11-06 12:03:23 +00001190 }
1191
Miklos Szerediad051c32004-07-02 09:22:50 +00001192 send_reply(f, in, res, &outarg, sizeof(outarg));
Miklos Szeredia181e612001-11-06 12:03:23 +00001193}
1194
Miklos Szeredi77f39942004-03-25 11:17:52 +00001195static int default_statfs(struct statfs *buf)
1196{
1197 buf->f_namelen = 255;
1198 buf->f_bsize = 512;
1199 return 0;
1200}
1201
Miklos Szeredi18e75e42004-02-19 14:23:27 +00001202static void convert_statfs(struct statfs *statfs, struct fuse_kstatfs *kstatfs)
1203{
1204 kstatfs->bsize = statfs->f_bsize;
1205 kstatfs->blocks = statfs->f_blocks;
1206 kstatfs->bfree = statfs->f_bfree;
1207 kstatfs->bavail = statfs->f_bavail;
1208 kstatfs->files = statfs->f_files;
1209 kstatfs->ffree = statfs->f_ffree;
1210 kstatfs->namelen = statfs->f_namelen;
1211}
1212
Mark Glinesd84b39a2002-01-07 16:32:02 +00001213static void do_statfs(struct fuse *f, struct fuse_in_header *in)
1214{
1215 int res;
Mark Glinesd84b39a2002-01-07 16:32:02 +00001216 struct fuse_statfs_out arg;
Miklos Szeredi18e75e42004-02-19 14:23:27 +00001217 struct statfs buf;
Mark Glinesd84b39a2002-01-07 16:32:02 +00001218
Miklos Szeredi77f39942004-03-25 11:17:52 +00001219 memset(&buf, 0, sizeof(struct statfs));
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001220 if (f->op.statfs)
Miklos Szeredi18e75e42004-02-19 14:23:27 +00001221 res = f->op.statfs("/", &buf);
Miklos Szeredi77f39942004-03-25 11:17:52 +00001222 else
1223 res = default_statfs(&buf);
1224
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001225 if (res == 0)
Miklos Szeredi77f39942004-03-25 11:17:52 +00001226 convert_statfs(&buf, &arg.st);
Miklos Szeredi4b2bef42002-01-09 12:23:27 +00001227
Mark Glinesd84b39a2002-01-07 16:32:02 +00001228 send_reply(f, in, res, &arg, sizeof(arg));
1229}
1230
Miklos Szeredi5e43f2c2003-12-12 14:06:41 +00001231static void do_fsync(struct fuse *f, struct fuse_in_header *in,
1232 struct fuse_fsync_in *inarg)
1233{
1234 int res;
1235 char *path;
1236
1237 res = -ENOENT;
1238 path = get_path(f, in->ino);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001239 if (path != NULL) {
Miklos Szeredi209f5d02004-07-24 19:56:16 +00001240 if (f->flags & FUSE_DEBUG) {
1241 printf("FSYNC[%u]\n", inarg->fh);
1242 fflush(stdout);
1243 }
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001244 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001245 if (f->op.fsync)
Miklos Szeredi5e43f2c2003-12-12 14:06:41 +00001246 res = f->op.fsync(path, inarg->datasync);
1247 free(path);
1248 }
1249 send_reply(f, in, res, NULL, 0);
1250}
1251
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001252static void do_setxattr(struct fuse *f, struct fuse_in_header *in,
1253 struct fuse_setxattr_in *arg)
1254{
1255 int res;
1256 char *path;
1257 char *name = PARAM(arg);
1258 unsigned char *value = name + strlen(name) + 1;
1259
1260 res = -ENOENT;
1261 path = get_path(f, in->ino);
1262 if (path != NULL) {
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001263 res = -ENOSYS;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001264 if (f->op.setxattr)
1265 res = f->op.setxattr(path, name, value, arg->size, arg->flags);
1266 free(path);
1267 }
1268 send_reply(f, in, res, NULL, 0);
1269}
1270
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001271static int common_getxattr(struct fuse *f, struct fuse_in_header *in,
1272 const char *name, char *value, size_t size)
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001273{
1274 int res;
1275 char *path;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001276
1277 res = -ENOENT;
1278 path = get_path(f, in->ino);
1279 if (path != NULL) {
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001280 res = -ENOSYS;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001281 if (f->op.getxattr)
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001282 res = f->op.getxattr(path, name, value, size);
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001283 free(path);
1284 }
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001285 return res;
1286}
1287
1288static void do_getxattr_read(struct fuse *f, struct fuse_in_header *in,
1289 const char *name, size_t size)
1290{
1291 int res;
1292 char *outbuf = (char *) malloc(sizeof(struct fuse_out_header) + size);
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001293 if (outbuf == NULL)
1294 send_reply(f, in, -ENOMEM, NULL, 0);
1295 else {
1296 struct fuse_out_header *out = (struct fuse_out_header *) outbuf;
1297 char *value = outbuf + sizeof(struct fuse_out_header);
1298
1299 res = common_getxattr(f, in, name, value, size);
1300 size = 0;
1301 if (res > 0) {
1302 size = res;
1303 res = 0;
1304 }
1305 memset(out, 0, sizeof(struct fuse_out_header));
1306 out->unique = in->unique;
1307 out->error = res;
1308
1309 send_reply_raw(f, outbuf, sizeof(struct fuse_out_header) + size, 0);
1310 free(outbuf);
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001311 }
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001312}
1313
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001314static void do_getxattr_size(struct fuse *f, struct fuse_in_header *in,
1315 const char *name)
1316{
1317 int res;
1318 struct fuse_getxattr_out arg;
1319
1320 res = common_getxattr(f, in, name, NULL, 0);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001321 if (res >= 0) {
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001322 arg.size = res;
1323 res = 0;
1324 }
1325 send_reply(f, in, res, &arg, sizeof(arg));
1326}
1327
1328static void do_getxattr(struct fuse *f, struct fuse_in_header *in,
1329 struct fuse_getxattr_in *arg)
1330{
1331 char *name = PARAM(arg);
1332
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001333 if (arg->size)
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001334 do_getxattr_read(f, in, name, arg->size);
1335 else
1336 do_getxattr_size(f, in, name);
1337}
1338
1339static int common_listxattr(struct fuse *f, struct fuse_in_header *in,
1340 char *list, size_t size)
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001341{
1342 int res;
1343 char *path;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001344
1345 res = -ENOENT;
1346 path = get_path(f, in->ino);
1347 if (path != NULL) {
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001348 res = -ENOSYS;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001349 if (f->op.listxattr)
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001350 res = f->op.listxattr(path, list, size);
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001351 free(path);
1352 }
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001353 return res;
1354}
1355
1356static void do_listxattr_read(struct fuse *f, struct fuse_in_header *in,
1357 size_t size)
1358{
1359 int res;
1360 char *outbuf = (char *) malloc(sizeof(struct fuse_out_header) + size);
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001361 if (outbuf == NULL)
1362 send_reply(f, in, -ENOMEM, NULL, 0);
1363 else {
1364 struct fuse_out_header *out = (struct fuse_out_header *) outbuf;
1365 char *list = outbuf + sizeof(struct fuse_out_header);
1366
1367 res = common_listxattr(f, in, list, size);
1368 size = 0;
1369 if (res > 0) {
1370 size = res;
1371 res = 0;
1372 }
1373 memset(out, 0, sizeof(struct fuse_out_header));
1374 out->unique = in->unique;
1375 out->error = res;
1376
1377 send_reply_raw(f, outbuf, sizeof(struct fuse_out_header) + size, 0);
1378 free(outbuf);
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001379 }
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001380}
1381
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001382static void do_listxattr_size(struct fuse *f, struct fuse_in_header *in)
1383{
1384 int res;
1385 struct fuse_getxattr_out arg;
1386
1387 res = common_listxattr(f, in, NULL, 0);
1388 if (res >= 0) {
1389 arg.size = res;
1390 res = 0;
1391 }
1392 send_reply(f, in, res, &arg, sizeof(arg));
1393}
1394
1395static void do_listxattr(struct fuse *f, struct fuse_in_header *in,
1396 struct fuse_getxattr_in *arg)
1397{
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001398 if (arg->size)
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001399 do_listxattr_read(f, in, arg->size);
1400 else
1401 do_listxattr_size(f, in);
1402}
1403
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001404static void do_removexattr(struct fuse *f, struct fuse_in_header *in,
1405 char *name)
1406{
1407 int res;
1408 char *path;
1409
1410 res = -ENOENT;
1411 path = get_path(f, in->ino);
1412 if (path != NULL) {
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001413 res = -ENOSYS;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001414 if (f->op.removexattr)
1415 res = f->op.removexattr(path, name);
1416 free(path);
1417 }
1418 send_reply(f, in, res, NULL, 0);
1419}
1420
1421
Miklos Szeredi43696432001-11-18 19:15:05 +00001422static void free_cmd(struct fuse_cmd *cmd)
1423{
1424 free(cmd->buf);
1425 free(cmd);
1426}
1427
Miklos Szeredifff56ab2001-11-16 10:12:59 +00001428void __fuse_process_cmd(struct fuse *f, struct fuse_cmd *cmd)
Miklos Szeredia181e612001-11-06 12:03:23 +00001429{
Miklos Szeredia181e612001-11-06 12:03:23 +00001430 struct fuse_in_header *in = (struct fuse_in_header *) cmd->buf;
1431 void *inarg = cmd->buf + sizeof(struct fuse_in_header);
1432 size_t argsize;
Miklos Szeredid169f312004-09-22 08:48:26 +00001433 struct fuse_context *ctx = fuse_get_context();
Miklos Szeredia181e612001-11-06 12:03:23 +00001434
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +00001435 dec_avail(f);
Miklos Szeredi33232032001-11-19 17:55:51 +00001436
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001437 if ((f->flags & FUSE_DEBUG)) {
Miklos Szeredic8ba2372002-12-10 12:26:00 +00001438 printf("unique: %i, opcode: %s (%i), ino: %li, insize: %i\n",
1439 in->unique, opname(in->opcode), in->opcode, in->ino,
1440 cmd->buflen);
Miklos Szeredic0938ea2001-11-07 12:35:06 +00001441 fflush(stdout);
1442 }
Miklos Szeredife25def2001-12-20 15:38:05 +00001443
Miklos Szeredid169f312004-09-22 08:48:26 +00001444 ctx->fuse = f;
Miklos Szeredife25def2001-12-20 15:38:05 +00001445 ctx->uid = in->uid;
1446 ctx->gid = in->gid;
Miklos Szeredia181e612001-11-06 12:03:23 +00001447
1448 argsize = cmd->buflen - sizeof(struct fuse_in_header);
1449
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001450 switch (in->opcode) {
Miklos Szeredia181e612001-11-06 12:03:23 +00001451 case FUSE_LOOKUP:
1452 do_lookup(f, in, (char *) inarg);
1453 break;
1454
Miklos Szeredia181e612001-11-06 12:03:23 +00001455 case FUSE_GETATTR:
1456 do_getattr(f, in);
1457 break;
1458
1459 case FUSE_SETATTR:
1460 do_setattr(f, in, (struct fuse_setattr_in *) inarg);
1461 break;
1462
1463 case FUSE_READLINK:
1464 do_readlink(f, in);
1465 break;
1466
1467 case FUSE_GETDIR:
1468 do_getdir(f, in);
1469 break;
1470
1471 case FUSE_MKNOD:
1472 do_mknod(f, in, (struct fuse_mknod_in *) inarg);
1473 break;
1474
1475 case FUSE_MKDIR:
1476 do_mkdir(f, in, (struct fuse_mkdir_in *) inarg);
1477 break;
1478
1479 case FUSE_UNLINK:
Miklos Szeredib5958612004-02-20 14:10:49 +00001480 do_unlink(f, in, (char *) inarg);
1481 break;
1482
Miklos Szeredia181e612001-11-06 12:03:23 +00001483 case FUSE_RMDIR:
Miklos Szeredib5958612004-02-20 14:10:49 +00001484 do_rmdir(f, in, (char *) inarg);
Miklos Szeredia181e612001-11-06 12:03:23 +00001485 break;
1486
1487 case FUSE_SYMLINK:
1488 do_symlink(f, in, (char *) inarg,
1489 ((char *) inarg) + strlen((char *) inarg) + 1);
1490 break;
1491
1492 case FUSE_RENAME:
1493 do_rename(f, in, (struct fuse_rename_in *) inarg);
1494 break;
1495
1496 case FUSE_LINK:
1497 do_link(f, in, (struct fuse_link_in *) inarg);
1498 break;
1499
1500 case FUSE_OPEN:
1501 do_open(f, in, (struct fuse_open_in *) inarg);
1502 break;
1503
Miklos Szeredie2e4ac22004-05-18 08:45:28 +00001504 case FUSE_FLUSH:
Miklos Szeredi209f5d02004-07-24 19:56:16 +00001505 do_flush(f, in, (struct fuse_flush_in *) inarg);
Miklos Szeredie2e4ac22004-05-18 08:45:28 +00001506 break;
1507
Miklos Szeredi9478e862002-12-11 09:50:26 +00001508 case FUSE_RELEASE:
Miklos Szeredi209f5d02004-07-24 19:56:16 +00001509 do_release(f, in, (struct fuse_release_in *) inarg);
Miklos Szeredi9478e862002-12-11 09:50:26 +00001510 break;
1511
Miklos Szeredia181e612001-11-06 12:03:23 +00001512 case FUSE_READ:
1513 do_read(f, in, (struct fuse_read_in *) inarg);
1514 break;
1515
1516 case FUSE_WRITE:
1517 do_write(f, in, (struct fuse_write_in *) inarg);
1518 break;
1519
Mark Glinesd84b39a2002-01-07 16:32:02 +00001520 case FUSE_STATFS:
1521 do_statfs(f, in);
1522 break;
1523
Miklos Szeredi5e43f2c2003-12-12 14:06:41 +00001524 case FUSE_FSYNC:
1525 do_fsync(f, in, (struct fuse_fsync_in *) inarg);
1526 break;
1527
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001528 case FUSE_SETXATTR:
1529 do_setxattr(f, in, (struct fuse_setxattr_in *) inarg);
1530 break;
1531
1532 case FUSE_GETXATTR:
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001533 do_getxattr(f, in, (struct fuse_getxattr_in *) inarg);
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001534 break;
1535
1536 case FUSE_LISTXATTR:
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001537 do_listxattr(f, in, (struct fuse_getxattr_in *) inarg);
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001538 break;
1539
1540 case FUSE_REMOVEXATTR:
1541 do_removexattr(f, in, (char *) inarg);
1542 break;
1543
Miklos Szeredia181e612001-11-06 12:03:23 +00001544 default:
Miklos Szeredi43696432001-11-18 19:15:05 +00001545 send_reply(f, in, -ENOSYS, NULL, 0);
Miklos Szeredia181e612001-11-06 12:03:23 +00001546 }
Miklos Szeredi43696432001-11-18 19:15:05 +00001547
1548 free_cmd(cmd);
Miklos Szeredia181e612001-11-06 12:03:23 +00001549}
1550
Miklos Szeredi65cf7c72004-06-30 11:34:56 +00001551int __fuse_exited(struct fuse* f)
1552{
1553 return f->exited;
1554}
1555
Miklos Szeredifff56ab2001-11-16 10:12:59 +00001556struct fuse_cmd *__fuse_read_cmd(struct fuse *f)
Miklos Szeredi2df1c042001-11-06 15:07:17 +00001557{
Miklos Szeredifff56ab2001-11-16 10:12:59 +00001558 ssize_t res;
Miklos Szeredifff56ab2001-11-16 10:12:59 +00001559 struct fuse_cmd *cmd;
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +00001560 struct fuse_in_header *in;
1561 void *inarg;
Miklos Szeredifff56ab2001-11-16 10:12:59 +00001562
Miklos Szeredi43696432001-11-18 19:15:05 +00001563 cmd = (struct fuse_cmd *) malloc(sizeof(struct fuse_cmd));
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001564 if (cmd == NULL) {
1565 fprintf(stderr, "fuse: failed to allocate cmd in read\n");
1566 return NULL;
1567 }
Miklos Szeredi43696432001-11-18 19:15:05 +00001568 cmd->buf = (char *) malloc(FUSE_MAX_IN);
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001569 if (cmd->buf == NULL) {
1570 fprintf(stderr, "fuse: failed to allocate read buffer\n");
1571 free(cmd);
1572 return NULL;
1573 }
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +00001574 in = (struct fuse_in_header *) cmd->buf;
1575 inarg = cmd->buf + sizeof(struct fuse_in_header);
Miklos Szeredi43696432001-11-18 19:15:05 +00001576
Miklos Szeredi65cf7c72004-06-30 11:34:56 +00001577 res = read(f->fd, cmd->buf, FUSE_MAX_IN);
1578 if (res == -1) {
1579 free_cmd(cmd);
1580 if (__fuse_exited(f) || errno == EINTR)
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +00001581 return NULL;
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +00001582
Miklos Szeredi65cf7c72004-06-30 11:34:56 +00001583 /* ENODEV means we got unmounted, so we silenty return failure */
1584 if (errno != ENODEV) {
1585 /* BAD... This will happen again */
1586 perror("fuse: reading device");
1587 }
1588
1589 fuse_exit(f);
1590 return NULL;
1591 }
1592 if ((size_t) res < sizeof(struct fuse_in_header)) {
1593 free_cmd(cmd);
1594 /* Cannot happen */
1595 fprintf(stderr, "short read on fuse device\n");
1596 fuse_exit(f);
1597 return NULL;
1598 }
1599 cmd->buflen = res;
1600
1601 /* Forget is special, it can be done without messing with threads. */
1602 if (in->opcode == FUSE_FORGET) {
1603 do_forget(f, in, (struct fuse_forget_in *) inarg);
1604 free_cmd(cmd);
1605 return NULL;
1606 }
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +00001607
Miklos Szeredifff56ab2001-11-16 10:12:59 +00001608 return cmd;
Miklos Szeredi2df1c042001-11-06 15:07:17 +00001609}
1610
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001611int fuse_loop(struct fuse *f)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001612{
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001613 if (f == NULL)
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001614 return -1;
Miklos Szeredic40748a2004-02-20 16:38:45 +00001615
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001616 while (1) {
Miklos Szeredi0f48a262002-12-05 14:23:01 +00001617 struct fuse_cmd *cmd;
1618
Miklos Szeredi65cf7c72004-06-30 11:34:56 +00001619 if (__fuse_exited(f))
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001620 return 0;
Miklos Szeredi0f48a262002-12-05 14:23:01 +00001621
1622 cmd = __fuse_read_cmd(f);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001623 if (cmd == NULL)
Miklos Szeredi0f48a262002-12-05 14:23:01 +00001624 continue;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001625
Miklos Szeredifff56ab2001-11-16 10:12:59 +00001626 __fuse_process_cmd(f, cmd);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001627 }
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001628 return 0;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001629}
1630
Miklos Szeredi891b8742004-07-29 09:27:49 +00001631int fuse_invalidate(struct fuse *f, const char *path)
1632{
1633 int res;
1634 int err;
1635 fino_t ino;
1636 struct fuse_user_header h;
1637
1638 err = path_lookup(f, path, &ino);
1639 if (err) {
1640 if (err == -ENOENT)
1641 return 0;
1642 else
1643 return err;
1644 }
1645
1646 memset(&h, 0, sizeof(struct fuse_user_header));
1647 h.opcode = FUSE_INVALIDATE;
1648 h.ino = ino;
1649
1650 if ((f->flags & FUSE_DEBUG)) {
1651 printf("INVALIDATE ino: %li\n", ino);
1652 fflush(stdout);
1653 }
1654
1655 res = write(f->fd, &h, sizeof(struct fuse_user_header));
1656 if (res == -1) {
1657 if (errno != ENOENT) {
1658 perror("fuse: writing device");
1659 return -errno;
1660 }
1661 }
1662 return 0;
1663}
1664
Miklos Szeredi0f48a262002-12-05 14:23:01 +00001665void fuse_exit(struct fuse *f)
1666{
1667 f->exited = 1;
1668}
1669
Miklos Szeredid169f312004-09-22 08:48:26 +00001670struct fuse_context *fuse_get_context()
Miklos Szeredi2e50d432001-12-20 12:17:25 +00001671{
Miklos Szeredid169f312004-09-22 08:48:26 +00001672 static struct fuse_context context;
1673 if (fuse_getcontext)
1674 return fuse_getcontext();
Miklos Szeredi2e50d432001-12-20 12:17:25 +00001675 else
Miklos Szeredid169f312004-09-22 08:48:26 +00001676 return &context;
1677}
1678
1679void __fuse_set_getcontext_func(struct fuse_context *(*func)(void))
1680{
1681 fuse_getcontext = func;
Miklos Szeredi2e50d432001-12-20 12:17:25 +00001682}
1683
Miklos Szeredic40748a2004-02-20 16:38:45 +00001684static int check_version(struct fuse *f)
1685{
1686 int res;
1687 FILE *vf = fopen(FUSE_VERSION_FILE, "r");
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001688 if (vf == NULL) {
Miklos Szeredic40748a2004-02-20 16:38:45 +00001689 fprintf(stderr, "fuse: kernel interface too old, need >= %i.%i\n",
1690 FUSE_KERNEL_VERSION, FUSE_KERNEL_MINOR_VERSION);
1691 return -1;
1692 }
1693 res = fscanf(vf, "%i.%i", &f->majorver, &f->minorver);
1694 fclose(vf);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001695 if (res != 2) {
Miklos Szeredic40748a2004-02-20 16:38:45 +00001696 fprintf(stderr, "fuse: error reading %s\n", FUSE_VERSION_FILE);
1697 return -1;
1698 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001699 if (f->majorver != FUSE_KERNEL_VERSION) {
Miklos Szeredic40748a2004-02-20 16:38:45 +00001700 fprintf(stderr, "fuse: bad kernel interface major version: needs %i\n",
1701 FUSE_KERNEL_VERSION);
1702 return -1;
1703 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001704 if (f->minorver < FUSE_KERNEL_MINOR_VERSION) {
Miklos Szeredic40748a2004-02-20 16:38:45 +00001705 fprintf(stderr, "fuse: kernel interface too old: need >= %i.%i",
1706 FUSE_KERNEL_VERSION, FUSE_KERNEL_MINOR_VERSION);
1707 return -1;
1708 }
1709
1710 return 0;
1711}
1712
Miklos Szeredibd7661b2004-07-23 17:16:29 +00001713
1714int fuse_is_lib_option(const char *opt)
1715{
1716 if (strcmp(opt, "debug") == 0 ||
1717 strcmp(opt, "hard_remove") == 0)
1718 return 1;
1719 else
1720 return 0;
1721}
1722
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001723static int parse_lib_opts(struct fuse *f, const char *opts)
Miklos Szeredibd7661b2004-07-23 17:16:29 +00001724{
1725 if (opts) {
1726 char *xopts = strdup(opts);
1727 char *s = xopts;
1728 char *opt;
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001729
1730 if (xopts == NULL)
1731 return -1;
Miklos Szeredibd7661b2004-07-23 17:16:29 +00001732
1733 while((opt = strsep(&s, ","))) {
1734 if (strcmp(opt, "debug") == 0)
1735 f->flags |= FUSE_DEBUG;
1736 else if (strcmp(opt, "hard_remove") == 0)
1737 f->flags |= FUSE_HARD_REMOVE;
1738 else
1739 fprintf(stderr, "fuse: warning: unknown option `%s'\n", opt);
1740 }
1741 free(xopts);
1742 }
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001743 return 0;
Miklos Szeredibd7661b2004-07-23 17:16:29 +00001744}
1745
1746struct fuse *fuse_new(int fd, const char *opts, const struct fuse_operations *op)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001747{
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001748 struct fuse *f;
1749 struct node *root;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001750
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001751 f = (struct fuse *) calloc(1, sizeof(struct fuse));
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001752 if (f == NULL)
1753 goto out;
Miklos Szeredi2df1c042001-11-06 15:07:17 +00001754
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001755 if (check_version(f) == -1)
1756 goto out_free;
Miklos Szeredic40748a2004-02-20 16:38:45 +00001757
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001758 if (parse_lib_opts(f, opts) == -1)
1759 goto out_free;
1760
Miklos Szeredi8cffdb92001-11-09 14:49:18 +00001761 f->fd = fd;
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001762 f->ctr = 0;
Miklos Szeredi76f65782004-02-19 16:55:40 +00001763 f->generation = 0;
Miklos Szeredifff56ab2001-11-16 10:12:59 +00001764 /* FIXME: Dynamic hash table */
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001765 f->name_table_size = 14057;
1766 f->name_table = (struct node **)
1767 calloc(1, sizeof(struct node *) * f->name_table_size);
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001768 if (f->name_table == NULL)
1769 goto out_free;
1770
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001771 f->ino_table_size = 14057;
1772 f->ino_table = (struct node **)
1773 calloc(1, sizeof(struct node *) * f->ino_table_size);
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001774 if (f->ino_table == NULL)
1775 goto out_free_name_table;
1776
Miklos Szeredia181e612001-11-06 12:03:23 +00001777 pthread_mutex_init(&f->lock, NULL);
Miklos Szeredi33232032001-11-19 17:55:51 +00001778 f->numworker = 0;
1779 f->numavail = 0;
Miklos Szeredi2e50d432001-12-20 12:17:25 +00001780 f->op = *op;
Miklos Szeredi0f48a262002-12-05 14:23:01 +00001781 f->exited = 0;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001782
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001783 root = (struct node *) calloc(1, sizeof(struct node));
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001784 if (root == NULL)
1785 goto out_free_ino_table;
1786
Miklos Szeredi8cffdb92001-11-09 14:49:18 +00001787 root->mode = 0;
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001788 root->rdev = 0;
1789 root->name = strdup("/");
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001790 if (root->name == NULL)
1791 goto out_free_root;
1792
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001793 root->parent = 0;
Miklos Szeredi76f65782004-02-19 16:55:40 +00001794 root->ino = FUSE_ROOT_INO;
1795 root->generation = 0;
1796 hash_ino(f, root);
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001797
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001798 return f;
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001799
1800 out_free_root:
1801 free(root);
1802 out_free_ino_table:
1803 free(f->ino_table);
1804 out_free_name_table:
1805 free(f->name_table);
1806 out_free:
1807 free(f);
1808 out:
1809 fprintf(stderr, "fuse: failed to allocate fuse object\n");
1810 return NULL;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001811}
1812
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001813void fuse_destroy(struct fuse *f)
1814{
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001815 size_t i;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001816 for (i = 0; i < f->ino_table_size; i++) {
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001817 struct node *node;
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001818
1819 for (node = f->ino_table[i]; node != NULL; node = node->ino_next) {
1820 if (node->is_hidden) {
1821 char *path = get_path(f, node->ino);
1822 if (path)
1823 f->op.unlink(path);
1824 }
1825 }
1826 }
1827 for (i = 0; i < f->ino_table_size; i++) {
1828 struct node *node;
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001829 struct node *next;
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001830
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001831 for (node = f->ino_table[i]; node != NULL; node = next) {
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001832 next = node->ino_next;
1833 free_node(node);
1834 }
1835 }
1836 free(f->ino_table);
1837 free(f->name_table);
Miklos Szeredia181e612001-11-06 12:03:23 +00001838 pthread_mutex_destroy(&f->lock);
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001839 free(f);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001840}