blob: a4d547a6f8e170ce1237d43857fc5cb7e3aaa2cb [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 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 +000057
58static inline void dec_avail(struct fuse *f)
59{
60 pthread_mutex_lock(&f->lock);
61 f->numavail --;
62 pthread_mutex_unlock(&f->lock);
63}
64
Miklos Szeredi97c61e92001-11-07 12:09:43 +000065static struct node *__get_node(struct fuse *f, fino_t ino)
Miklos Szeredia181e612001-11-06 12:03:23 +000066{
Miklos Szeredi97c61e92001-11-07 12:09:43 +000067 size_t hash = ino % f->ino_table_size;
68 struct node *node;
69
Miklos Szeredi7eafcce2004-06-19 22:42:38 +000070 for (node = f->ino_table[hash]; node != NULL; node = node->ino_next)
71 if (node->ino == ino)
Miklos Szeredi97c61e92001-11-07 12:09:43 +000072 return node;
73
74 return NULL;
Miklos Szeredia181e612001-11-06 12:03:23 +000075}
76
Miklos Szeredi97c61e92001-11-07 12:09:43 +000077static struct node *get_node(struct fuse *f, fino_t ino)
Miklos Szeredia181e612001-11-06 12:03:23 +000078{
Miklos Szeredi97c61e92001-11-07 12:09:43 +000079 struct node *node = __get_node(f, ino);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +000080 if (node != NULL)
Miklos Szeredi97c61e92001-11-07 12:09:43 +000081 return node;
82
83 fprintf(stderr, "fuse internal error: inode %lu not found\n", ino);
84 abort();
Miklos Szeredia181e612001-11-06 12:03:23 +000085}
86
Miklos Szeredi76f65782004-02-19 16:55:40 +000087static void hash_ino(struct fuse *f, struct node *node)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000088{
Miklos Szeredi76f65782004-02-19 16:55:40 +000089 size_t hash = node->ino % f->ino_table_size;
Miklos Szeredi97c61e92001-11-07 12:09:43 +000090 node->ino_next = f->ino_table[hash];
91 f->ino_table[hash] = node;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000092}
93
Miklos Szeredi97c61e92001-11-07 12:09:43 +000094static void unhash_ino(struct fuse *f, struct node *node)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000095{
Miklos Szeredi97c61e92001-11-07 12:09:43 +000096 size_t hash = node->ino % f->ino_table_size;
97 struct node **nodep = &f->ino_table[hash];
98
Miklos Szeredi7eafcce2004-06-19 22:42:38 +000099 for (; *nodep != NULL; nodep = &(*nodep)->ino_next)
100 if (*nodep == node) {
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000101 *nodep = node->ino_next;
102 return;
103 }
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000104}
105
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000106static fino_t next_ino(struct fuse *f)
107{
Miklos Szeredi76f65782004-02-19 16:55:40 +0000108 do {
109 f->ctr++;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000110 if (!f->ctr)
Miklos Szeredi76f65782004-02-19 16:55:40 +0000111 f->generation ++;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000112 } while (f->ctr == 0 || __get_node(f, f->ctr) != NULL);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000113 return f->ctr;
114}
115
116static void free_node(struct node *node)
117{
118 free(node->name);
119 free(node);
120}
121
122static unsigned int name_hash(struct fuse *f, fino_t parent, const char *name)
123{
124 unsigned int hash = *name;
125
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000126 if (hash)
127 for (name += 1; *name != '\0'; name++)
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000128 hash = (hash << 5) - hash + *name;
129
130 return (hash + parent) % f->name_table_size;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000131}
132
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000133static struct node *__lookup_node(struct fuse *f, fino_t parent,
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000134 const char *name)
135{
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000136 size_t hash = name_hash(f, parent, name);
137 struct node *node;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000138
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000139 for (node = f->name_table[hash]; node != NULL; node = node->name_next)
140 if (node->parent == parent && strcmp(node->name, name) == 0)
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000141 return node;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000142
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000143 return NULL;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000144}
145
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000146static struct node *lookup_node(struct fuse *f, fino_t parent,
147 const char *name)
148{
149 struct node *node;
150
151 pthread_mutex_lock(&f->lock);
152 node = __lookup_node(f, parent, name);
153 pthread_mutex_unlock(&f->lock);
154 if (node != NULL)
155 return node;
156
157 fprintf(stderr, "fuse internal error: node %lu/%s not found\n", parent,
158 name);
159 abort();
160}
161
Miklos Szeredib2cf9562004-09-16 08:42:40 +0000162static int hash_name(struct fuse *f, struct node *node, fino_t parent,
163 const char *name)
Miklos Szeredi5e183482001-10-31 14:52:35 +0000164{
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000165 size_t hash = name_hash(f, parent, name);
Miklos Szeredia181e612001-11-06 12:03:23 +0000166 node->parent = parent;
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000167 node->name = strdup(name);
Miklos Szeredib2cf9562004-09-16 08:42:40 +0000168 if (node->name == NULL)
169 return -1;
170
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000171 node->name_next = f->name_table[hash];
Miklos Szeredib2cf9562004-09-16 08:42:40 +0000172 f->name_table[hash] = node;
173 return 0;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000174}
175
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000176static void unhash_name(struct fuse *f, struct node *node)
Miklos Szeredia181e612001-11-06 12:03:23 +0000177{
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000178 if (node->name != NULL) {
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000179 size_t hash = name_hash(f, node->parent, node->name);
180 struct node **nodep = &f->name_table[hash];
181
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000182 for (; *nodep != NULL; nodep = &(*nodep)->name_next)
183 if (*nodep == node) {
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000184 *nodep = node->name_next;
185 node->name_next = NULL;
186 free(node->name);
187 node->name = NULL;
188 node->parent = 0;
189 return;
190 }
191 fprintf(stderr, "fuse internal error: unable to unhash node: %lu\n",
192 node->ino);
193 abort();
Miklos Szeredia181e612001-11-06 12:03:23 +0000194 }
195}
196
Miklos Szeredi76f65782004-02-19 16:55:40 +0000197static struct node *find_node(struct fuse *f, fino_t parent, char *name,
198 struct fuse_attr *attr, int version)
Miklos Szeredi5e183482001-10-31 14:52:35 +0000199{
200 struct node *node;
Miklos Szeredia181e612001-11-06 12:03:23 +0000201 int mode = attr->mode & S_IFMT;
202 int rdev = 0;
203
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000204 if (S_ISCHR(mode) || S_ISBLK(mode))
Miklos Szeredia181e612001-11-06 12:03:23 +0000205 rdev = attr->rdev;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000206
Miklos Szeredia181e612001-11-06 12:03:23 +0000207 pthread_mutex_lock(&f->lock);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000208 node = __lookup_node(f, parent, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000209 if (node != NULL) {
210 if (node->mode == mode && node->rdev == rdev)
Miklos Szeredia181e612001-11-06 12:03:23 +0000211 goto out;
212
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000213 unhash_name(f, node);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000214 }
215
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000216 node = (struct node *) calloc(1, sizeof(struct node));
Miklos Szeredib2cf9562004-09-16 08:42:40 +0000217 if (node == NULL)
Miklos Szeredic2309912004-09-21 13:40:38 +0000218 goto out_err;
Miklos Szeredib2cf9562004-09-16 08:42:40 +0000219
Miklos Szeredia181e612001-11-06 12:03:23 +0000220 node->mode = mode;
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000221 node->rdev = rdev;
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000222 node->open_count = 0;
223 node->is_hidden = 0;
Miklos Szeredi76f65782004-02-19 16:55:40 +0000224 node->ino = next_ino(f);
225 node->generation = f->generation;
Miklos Szeredib2cf9562004-09-16 08:42:40 +0000226 if (hash_name(f, node, parent, name) == -1) {
227 free(node);
Miklos Szeredic2309912004-09-21 13:40:38 +0000228 node = NULL;
229 goto out_err;
Miklos Szeredib2cf9562004-09-16 08:42:40 +0000230 }
Miklos Szeredi76f65782004-02-19 16:55:40 +0000231 hash_ino(f, node);
Miklos Szeredia181e612001-11-06 12:03:23 +0000232
Miklos Szeredic2309912004-09-21 13:40:38 +0000233 out:
Miklos Szeredia181e612001-11-06 12:03:23 +0000234 node->version = version;
Miklos Szeredic2309912004-09-21 13:40:38 +0000235 out_err:
Miklos Szeredia181e612001-11-06 12:03:23 +0000236 pthread_mutex_unlock(&f->lock);
Miklos Szeredi76f65782004-02-19 16:55:40 +0000237 return node;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000238}
239
Miklos Szeredi891b8742004-07-29 09:27:49 +0000240static int path_lookup(struct fuse *f, const char *path, fino_t *inop)
241{
242 fino_t ino;
243 int err;
244 char *s;
245 char *name;
246 char *tmp = strdup(path);
247 if (!tmp)
248 return -ENOMEM;
249
250 pthread_mutex_lock(&f->lock);
251 ino = FUSE_ROOT_INO;
252 err = 0;
253 for (s = tmp; (name = strsep(&s, "/")) != NULL; ) {
254 if (name[0]) {
255 struct node *node = __lookup_node(f, ino, name);
256 if (node == NULL) {
257 err = -ENOENT;
258 break;
259 }
260 ino = node->ino;
261 }
262 }
263 pthread_mutex_unlock(&f->lock);
264 free(tmp);
265 if (!err)
266 *inop = ino;
267
268 return err;
269}
270
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000271static char *add_name(char *buf, char *s, const char *name)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000272{
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000273 size_t len = strlen(name);
274 s -= len;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000275 if (s <= buf) {
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000276 fprintf(stderr, "fuse: path too long: ...%s\n", s + len);
277 return NULL;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000278 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000279 strncpy(s, name, len);
280 s--;
281 *s = '/';
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000282
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000283 return s;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000284}
285
Miklos Szeredia181e612001-11-06 12:03:23 +0000286static char *get_path_name(struct fuse *f, fino_t ino, const char *name)
Miklos Szeredib483c932001-10-29 14:57:57 +0000287{
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000288 char buf[FUSE_MAX_PATH];
289 char *s = buf + FUSE_MAX_PATH - 1;
290 struct node *node;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000291
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000292 *s = '\0';
Miklos Szeredia181e612001-11-06 12:03:23 +0000293
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000294 if (name != NULL) {
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000295 s = add_name(buf, s, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000296 if (s == NULL)
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000297 return NULL;
298 }
299
300 pthread_mutex_lock(&f->lock);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000301 for (node = get_node(f, ino); node->ino != FUSE_ROOT_INO;
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000302 node = get_node(f, node->parent)) {
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000303 if (node->name == NULL) {
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000304 s = NULL;
305 break;
306 }
307
308 s = add_name(buf, s, node->name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000309 if (s == NULL)
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000310 break;
311 }
312 pthread_mutex_unlock(&f->lock);
313
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000314 if (s == NULL)
Miklos Szeredi5e183482001-10-31 14:52:35 +0000315 return NULL;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000316 else if (*s == '\0')
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000317 return strdup("/");
318 else
319 return strdup(s);
320}
Miklos Szeredia181e612001-11-06 12:03:23 +0000321
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000322static char *get_path(struct fuse *f, fino_t ino)
323{
324 return get_path_name(f, ino, NULL);
Miklos Szeredib483c932001-10-29 14:57:57 +0000325}
326
Miklos Szeredia181e612001-11-06 12:03:23 +0000327static void destroy_node(struct fuse *f, fino_t ino, int version)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000328{
Miklos Szeredia181e612001-11-06 12:03:23 +0000329 struct node *node;
330
331 pthread_mutex_lock(&f->lock);
Miklos Szeredi8b2d3332004-09-09 08:44:01 +0000332 node = __get_node(f, ino);
333 if (node && node->version == version && ino != FUSE_ROOT_INO) {
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000334 unhash_name(f, node);
335 unhash_ino(f, node);
Miklos Szeredia181e612001-11-06 12:03:23 +0000336 free_node(node);
337 }
338 pthread_mutex_unlock(&f->lock);
339
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000340}
341
Miklos Szeredi5e183482001-10-31 14:52:35 +0000342static void remove_node(struct fuse *f, fino_t dir, const char *name)
343{
Miklos Szeredia181e612001-11-06 12:03:23 +0000344 struct node *node;
345
346 pthread_mutex_lock(&f->lock);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000347 node = __lookup_node(f, dir, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000348 if (node == NULL) {
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000349 fprintf(stderr, "fuse internal error: unable to remove node %lu/%s\n",
350 dir, name);
351 abort();
352 }
353 unhash_name(f, node);
Miklos Szeredia181e612001-11-06 12:03:23 +0000354 pthread_mutex_unlock(&f->lock);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000355}
356
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000357static int rename_node(struct fuse *f, fino_t olddir, const char *oldname,
358 fino_t newdir, const char *newname, int hide)
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000359{
Miklos Szeredia181e612001-11-06 12:03:23 +0000360 struct node *node;
361 struct node *newnode;
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000362 int err = 0;
Miklos Szeredia181e612001-11-06 12:03:23 +0000363
364 pthread_mutex_lock(&f->lock);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000365 node = __lookup_node(f, olddir, oldname);
366 newnode = __lookup_node(f, newdir, newname);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000367 if (node == NULL) {
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000368 fprintf(stderr, "fuse internal error: unable to rename node %lu/%s\n",
369 olddir, oldname);
370 abort();
371 }
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000372
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000373 if (newnode != NULL) {
374 if (hide) {
375 fprintf(stderr, "fuse: hidden file got created during hiding\n");
Miklos Szeredib2cf9562004-09-16 08:42:40 +0000376 err = -EBUSY;
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000377 goto out;
378 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000379 unhash_name(f, newnode);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000380 }
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000381
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000382 unhash_name(f, node);
Miklos Szeredib2cf9562004-09-16 08:42:40 +0000383 if (hash_name(f, node, newdir, newname) == -1) {
384 err = -ENOMEM;
385 goto out;
386 }
387
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000388 if (hide)
389 node->is_hidden = 1;
390
391 out:
Miklos Szeredia181e612001-11-06 12:03:23 +0000392 pthread_mutex_unlock(&f->lock);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000393 return err;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000394}
395
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000396static void convert_stat(struct stat *stbuf, struct fuse_attr *attr)
397{
Miklos Szeredib5958612004-02-20 14:10:49 +0000398 attr->mode = stbuf->st_mode;
399 attr->nlink = stbuf->st_nlink;
400 attr->uid = stbuf->st_uid;
401 attr->gid = stbuf->st_gid;
402 attr->rdev = stbuf->st_rdev;
403 attr->size = stbuf->st_size;
404 attr->blocks = stbuf->st_blocks;
405 attr->atime = stbuf->st_atime;
Miklos Szeredib5958612004-02-20 14:10:49 +0000406 attr->mtime = stbuf->st_mtime;
Miklos Szeredib5958612004-02-20 14:10:49 +0000407 attr->ctime = stbuf->st_ctime;
Miklos Szeredicb264512004-06-23 18:52:50 +0000408#ifdef HAVE_STRUCT_STAT_ST_ATIM
409 attr->atimensec = stbuf->st_atim.tv_nsec;
410 attr->mtimensec = stbuf->st_mtim.tv_nsec;
Miklos Szeredib5958612004-02-20 14:10:49 +0000411 attr->ctimensec = stbuf->st_ctim.tv_nsec;
Miklos Szeredicb264512004-06-23 18:52:50 +0000412#endif
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000413}
414
Miklos Szeredia181e612001-11-06 12:03:23 +0000415static int fill_dir(struct fuse_dirhandle *dh, char *name, int type)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000416{
417 struct fuse_dirent dirent;
418 size_t reclen;
419 size_t res;
420
Miklos Szeredi43696432001-11-18 19:15:05 +0000421 dirent.ino = (unsigned long) -1;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000422 dirent.namelen = strlen(name);
423 strncpy(dirent.name, name, sizeof(dirent.name));
424 dirent.type = type;
425 reclen = FUSE_DIRENT_SIZE(&dirent);
426 res = fwrite(&dirent, reclen, 1, dh->fp);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000427 if (res == 0) {
Miklos Szeredi96249982001-11-21 12:21:19 +0000428 perror("fuse: writing directory file");
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000429 return -EIO;
430 }
431 return 0;
432}
433
Miklos Szeredi73798f92004-07-12 15:55:11 +0000434static int send_reply_raw(struct fuse *f, char *outbuf, size_t outsize,
435 int locked)
Miklos Szeredi43696432001-11-18 19:15:05 +0000436{
437 int res;
438
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000439 if ((f->flags & FUSE_DEBUG)) {
Miklos Szeredi43696432001-11-18 19:15:05 +0000440 struct fuse_out_header *out = (struct fuse_out_header *) outbuf;
441 printf(" unique: %i, error: %i (%s), outsize: %i\n", out->unique,
442 out->error, strerror(-out->error), outsize);
443 fflush(stdout);
444 }
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +0000445
Miklos Szeredi4e71c9f2004-02-09 12:05:14 +0000446 /* This needs to be done before the reply, otherwise the scheduler
447 could play tricks with us, and only let the counter be increased
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +0000448 long after the operation is done */
Miklos Szeredi73798f92004-07-12 15:55:11 +0000449 if (!locked)
450 pthread_mutex_lock(&f->lock);
451 f->numavail ++;
452 if (!locked)
453 pthread_mutex_unlock(&f->lock);
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +0000454
Miklos Szeredi43696432001-11-18 19:15:05 +0000455 res = write(f->fd, outbuf, outsize);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000456 if (res == -1) {
Miklos Szeredi43696432001-11-18 19:15:05 +0000457 /* ENOENT means the operation was interrupted */
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000458 if (!f->exited && errno != ENOENT)
Miklos Szeredi96249982001-11-21 12:21:19 +0000459 perror("fuse: writing device");
Miklos Szeredi40b9a5a2002-12-10 16:09:02 +0000460 return -errno;
Miklos Szeredi43696432001-11-18 19:15:05 +0000461 }
Miklos Szeredi40b9a5a2002-12-10 16:09:02 +0000462 return 0;
Miklos Szeredi43696432001-11-18 19:15:05 +0000463}
464
Miklos Szeredi73798f92004-07-12 15:55:11 +0000465static int __send_reply(struct fuse *f, struct fuse_in_header *in, int error,
466 void *arg, size_t argsize, int locked)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000467{
Miklos Szeredi40b9a5a2002-12-10 16:09:02 +0000468 int res;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000469 char *outbuf;
470 size_t outsize;
471 struct fuse_out_header *out;
472
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000473 if (error <= -1000 || error > 0) {
Miklos Szeredi0f48a262002-12-05 14:23:01 +0000474 fprintf(stderr, "fuse: bad error value: %i\n", error);
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000475 error = -ERANGE;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000476 }
477
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000478 if (error)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000479 argsize = 0;
480
481 outsize = sizeof(struct fuse_out_header) + argsize;
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000482 outbuf = (char *) malloc(outsize);
Miklos Szeredib2cf9562004-09-16 08:42:40 +0000483 if (outbuf == NULL) {
484 fprintf(stderr, "fuse: failed to allocate reply buffer\n");
485 res = -ENOMEM;
486 } else {
487 out = (struct fuse_out_header *) outbuf;
488 memset(out, 0, sizeof(struct fuse_out_header));
489 out->unique = in->unique;
490 out->error = error;
491 if (argsize != 0)
492 memcpy(outbuf + sizeof(struct fuse_out_header), arg, argsize);
493
494 res = send_reply_raw(f, outbuf, outsize, locked);
495 free(outbuf);
496 }
Miklos Szeredi40b9a5a2002-12-10 16:09:02 +0000497
498 return res;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000499}
500
Miklos Szeredi73798f92004-07-12 15:55:11 +0000501static int send_reply(struct fuse *f, struct fuse_in_header *in, int error,
502 void *arg, size_t argsize)
503{
504 return __send_reply(f, in, error, arg, argsize, 0);
505}
506
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000507static int is_open(struct fuse *f, fino_t dir, const char *name)
508{
509 struct node *node;
510 int isopen = 0;
511 pthread_mutex_lock(&f->lock);
512 node = __lookup_node(f, dir, name);
513 if (node && node->open_count > 0)
514 isopen = 1;
515 pthread_mutex_unlock(&f->lock);
516 return isopen;
517}
518
519static char *hidden_name(struct fuse *f, fino_t dir, const char *oldname,
520 char *newname, size_t bufsize)
521{
522 struct stat buf;
523 struct node *node;
524 struct node *newnode;
525 char *newpath;
526 int res;
527 int failctr = 10;
528
529 if (!f->op.getattr)
530 return NULL;
531
532 do {
533 node = lookup_node(f, dir, oldname);
534 pthread_mutex_lock(&f->lock);
535 do {
536 f->hidectr ++;
537 snprintf(newname, bufsize, ".fuse_hidden%08x%08x",
538 (unsigned int) node->ino, f->hidectr);
539 newnode = __lookup_node(f, dir, newname);
540 } while(newnode);
541 pthread_mutex_unlock(&f->lock);
542
543 newpath = get_path_name(f, dir, newname);
544 if (!newpath)
545 break;
546
547 res = f->op.getattr(newpath, &buf);
548 if (res != 0)
549 break;
550 free(newpath);
551 newpath = NULL;
552 } while(--failctr);
553
554 return newpath;
555}
556
557static int hide_node(struct fuse *f, const char *oldpath, fino_t dir,
558 const char *oldname)
559{
560 char newname[64];
561 char *newpath;
Miklos Szeredib2cf9562004-09-16 08:42:40 +0000562 int err = -EBUSY;
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000563
Miklos Szeredib2cf9562004-09-16 08:42:40 +0000564 if (f->op.rename && f->op.unlink) {
565 newpath = hidden_name(f, dir, oldname, newname, sizeof(newname));
566 if (newpath) {
567 int res = f->op.rename(oldpath, newpath);
568 if (res == 0)
569 err = rename_node(f, dir, oldname, dir, newname, 1);
570 free(newpath);
571 }
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000572 }
Miklos Szeredib2cf9562004-09-16 08:42:40 +0000573 return err;
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000574}
575
Miklos Szeredi76f65782004-02-19 16:55:40 +0000576static int lookup_path(struct fuse *f, fino_t ino, int version, char *name,
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000577 const char *path, struct fuse_entry_out *arg)
Miklos Szeredi76f65782004-02-19 16:55:40 +0000578{
579 int res;
580 struct stat buf;
581
582 res = f->op.getattr(path, &buf);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000583 if (res == 0) {
Miklos Szeredi76f65782004-02-19 16:55:40 +0000584 struct node *node;
585
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000586 memset(arg, 0, sizeof(struct fuse_entry_out));
Miklos Szeredi76f65782004-02-19 16:55:40 +0000587 convert_stat(&buf, &arg->attr);
588 node = find_node(f, ino, name, &arg->attr, version);
Miklos Szeredib2cf9562004-09-16 08:42:40 +0000589 if (node == NULL)
590 res = -ENOMEM;
591 else {
592 arg->ino = node->ino;
593 arg->generation = node->generation;
594 arg->entry_valid = ENTRY_REVALIDATE_TIME;
595 arg->entry_valid_nsec = 0;
596 arg->attr_valid = ATTR_REVALIDATE_TIME;
597 arg->attr_valid_nsec = 0;
598 if (f->flags & FUSE_DEBUG) {
599 printf(" INO: %li\n", arg->ino);
600 fflush(stdout);
601 }
Miklos Szeredi76f65782004-02-19 16:55:40 +0000602 }
603 }
604 return res;
605}
606
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000607static void do_lookup(struct fuse *f, struct fuse_in_header *in, char *name)
608{
609 int res;
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000610 int res2;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000611 char *path;
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000612 struct fuse_entry_out arg;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000613
Miklos Szeredi5e183482001-10-31 14:52:35 +0000614 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000615 path = get_path_name(f, in->ino, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000616 if (path != NULL) {
617 if (f->flags & FUSE_DEBUG) {
Miklos Szeredi6ebe2342002-01-06 21:44:16 +0000618 printf("LOOKUP %s\n", path);
619 fflush(stdout);
620 }
Miklos Szeredi5e183482001-10-31 14:52:35 +0000621 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000622 if (f->op.getattr)
Miklos Szeredi76f65782004-02-19 16:55:40 +0000623 res = lookup_path(f, in->ino, in->unique, name, path, &arg);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000624 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000625 }
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000626 res2 = send_reply(f, in, res, &arg, sizeof(arg));
627 if (res == 0 && res2 == -ENOENT)
628 destroy_node(f, arg.ino, in->unique);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000629}
630
Miklos Szeredia181e612001-11-06 12:03:23 +0000631static void do_forget(struct fuse *f, struct fuse_in_header *in,
632 struct fuse_forget_in *arg)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000633{
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000634 if (f->flags & FUSE_DEBUG) {
Miklos Szeredi43696432001-11-18 19:15:05 +0000635 printf("FORGET %li/%i\n", in->ino, arg->version);
636 fflush(stdout);
637 }
Miklos Szeredia181e612001-11-06 12:03:23 +0000638 destroy_node(f, in->ino, arg->version);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000639}
640
641static void do_getattr(struct fuse *f, struct fuse_in_header *in)
642{
643 int res;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000644 char *path;
645 struct stat buf;
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000646 struct fuse_attr_out arg;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000647
Miklos Szeredi5e183482001-10-31 14:52:35 +0000648 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000649 path = get_path(f, in->ino);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000650 if (path != NULL) {
Miklos Szeredi5e183482001-10-31 14:52:35 +0000651 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000652 if (f->op.getattr)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000653 res = f->op.getattr(path, &buf);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000654 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000655 }
Miklos Szeredi0f48a262002-12-05 14:23:01 +0000656
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000657 if (res == 0) {
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000658 memset(&arg, 0, sizeof(struct fuse_attr_out));
659 arg.attr_valid = ATTR_REVALIDATE_TIME;
660 arg.attr_valid_nsec = 0;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000661 convert_stat(&buf, &arg.attr);
Miklos Szeredi0f48a262002-12-05 14:23:01 +0000662 }
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000663
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000664 send_reply(f, in, res, &arg, sizeof(arg));
665}
666
Miklos Szeredi680a69a2001-11-16 13:31:14 +0000667static int do_chmod(struct fuse *f, const char *path, struct fuse_attr *attr)
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000668{
669 int res;
670
671 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000672 if (f->op.chmod)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000673 res = f->op.chmod(path, attr->mode);
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000674
675 return res;
676}
677
Miklos Szeredi680a69a2001-11-16 13:31:14 +0000678static int do_chown(struct fuse *f, const char *path, struct fuse_attr *attr,
Miklos Szeredi2e50d432001-12-20 12:17:25 +0000679 int valid)
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000680{
681 int res;
682 uid_t uid = (valid & FATTR_UID) ? attr->uid : (uid_t) -1;
683 gid_t gid = (valid & FATTR_GID) ? attr->gid : (gid_t) -1;
684
685 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000686 if (f->op.chown)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000687 res = f->op.chown(path, uid, gid);
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000688
689 return res;
690}
691
Miklos Szeredi680a69a2001-11-16 13:31:14 +0000692static int do_truncate(struct fuse *f, const char *path,
693 struct fuse_attr *attr)
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000694{
695 int res;
696
697 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000698 if (f->op.truncate)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000699 res = f->op.truncate(path, attr->size);
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000700
701 return res;
702}
703
Miklos Szeredi680a69a2001-11-16 13:31:14 +0000704static int do_utime(struct fuse *f, const char *path, struct fuse_attr *attr)
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000705{
706 int res;
707 struct utimbuf buf;
708 buf.actime = attr->atime;
709 buf.modtime = attr->mtime;
710 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000711 if (f->op.utime)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000712 res = f->op.utime(path, &buf);
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000713
714 return res;
715}
716
Miklos Szeredi5e183482001-10-31 14:52:35 +0000717static void do_setattr(struct fuse *f, struct fuse_in_header *in,
718 struct fuse_setattr_in *arg)
719{
720 int res;
721 char *path;
722 int valid = arg->valid;
723 struct fuse_attr *attr = &arg->attr;
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000724 struct fuse_attr_out outarg;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000725
726 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000727 path = get_path(f, in->ino);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000728 if (path != NULL) {
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000729 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000730 if (f->op.getattr) {
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000731 res = 0;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000732 if (!res && (valid & FATTR_MODE))
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000733 res = do_chmod(f, path, attr);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000734 if (!res && (valid & (FATTR_UID | FATTR_GID)))
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000735 res = do_chown(f, path, attr, valid);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000736 if (!res && (valid & FATTR_SIZE))
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000737 res = do_truncate(f, path, attr);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000738 if (!res && (valid & (FATTR_ATIME | FATTR_MTIME)) ==
Miklos Szeredib5958612004-02-20 14:10:49 +0000739 (FATTR_ATIME | FATTR_MTIME))
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000740 res = do_utime(f, path, attr);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000741 if (!res) {
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000742 struct stat buf;
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000743 res = f->op.getattr(path, &buf);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000744 if (!res) {
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000745 memset(&outarg, 0, sizeof(struct fuse_attr_out));
746 outarg.attr_valid = ATTR_REVALIDATE_TIME;
747 outarg.attr_valid_nsec = 0;
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000748 convert_stat(&buf, &outarg.attr);
Miklos Szeredi0f48a262002-12-05 14:23:01 +0000749 }
Miklos Szeredia181e612001-11-06 12:03:23 +0000750 }
Miklos Szeredi5e183482001-10-31 14:52:35 +0000751 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000752 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000753 }
Miklos Szeredia181e612001-11-06 12:03:23 +0000754 send_reply(f, in, res, &outarg, sizeof(outarg));
Miklos Szeredi5e183482001-10-31 14:52:35 +0000755}
756
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000757static void do_readlink(struct fuse *f, struct fuse_in_header *in)
758{
759 int res;
760 char link[PATH_MAX + 1];
Miklos Szeredib483c932001-10-29 14:57:57 +0000761 char *path;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000762
Miklos Szeredi5e183482001-10-31 14:52:35 +0000763 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000764 path = get_path(f, in->ino);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000765 if (path != NULL) {
Miklos Szeredi5e183482001-10-31 14:52:35 +0000766 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000767 if (f->op.readlink)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000768 res = f->op.readlink(path, link, sizeof(link));
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000769 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000770 }
Miklos Szeredi2df1c042001-11-06 15:07:17 +0000771 link[PATH_MAX] = '\0';
Miklos Szeredi4b2bef42002-01-09 12:23:27 +0000772 send_reply(f, in, res, link, res == 0 ? strlen(link) : 0);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000773}
774
775static void do_getdir(struct fuse *f, struct fuse_in_header *in)
776{
777 int res;
778 struct fuse_getdir_out arg;
Miklos Szeredia181e612001-11-06 12:03:23 +0000779 struct fuse_dirhandle dh;
Miklos Szeredib483c932001-10-29 14:57:57 +0000780 char *path;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000781
Miklos Szeredib483c932001-10-29 14:57:57 +0000782 dh.fuse = f;
783 dh.fp = tmpfile();
784 dh.dir = in->ino;
Miklos Szeredi0f48a262002-12-05 14:23:01 +0000785
Miklos Szeredi65afea12004-09-14 07:13:45 +0000786 res = -EIO;
787 if (dh.fp == NULL)
788 perror("fuse: failed to create temporary file");
789 else {
790 res = -ENOENT;
791 path = get_path(f, in->ino);
792 if (path != NULL) {
793 res = -ENOSYS;
794 if (f->op.getdir)
795 res = f->op.getdir(path, &dh, (fuse_dirfil_t) fill_dir);
796 free(path);
797 }
798 fflush(dh.fp);
799 }
Miklos Szeredi0f48a262002-12-05 14:23:01 +0000800 memset(&arg, 0, sizeof(struct fuse_getdir_out));
Miklos Szeredi65afea12004-09-14 07:13:45 +0000801 if (res == 0)
802 arg.fd = fileno(dh.fp);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000803 send_reply(f, in, res, &arg, sizeof(arg));
Miklos Szeredi65afea12004-09-14 07:13:45 +0000804 if (dh.fp != NULL)
805 fclose(dh.fp);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000806}
807
Miklos Szeredib483c932001-10-29 14:57:57 +0000808static void do_mknod(struct fuse *f, struct fuse_in_header *in,
809 struct fuse_mknod_in *inarg)
810{
811 int res;
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000812 int res2;
Miklos Szeredib483c932001-10-29 14:57:57 +0000813 char *path;
Miklos Szeredi76f65782004-02-19 16:55:40 +0000814 char *name = PARAM(inarg);
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000815 struct fuse_entry_out outarg;
Miklos Szeredib483c932001-10-29 14:57:57 +0000816
Miklos Szeredi5e183482001-10-31 14:52:35 +0000817 res = -ENOENT;
Miklos Szeredi76f65782004-02-19 16:55:40 +0000818 path = get_path_name(f, in->ino, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000819 if (path != NULL) {
820 if (f->flags & FUSE_DEBUG) {
Miklos Szeredi76f65782004-02-19 16:55:40 +0000821 printf("MKNOD %s\n", path);
822 fflush(stdout);
823 }
Miklos Szeredi5e183482001-10-31 14:52:35 +0000824 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000825 if (f->op.mknod && f->op.getattr) {
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000826 res = f->op.mknod(path, inarg->mode, inarg->rdev);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000827 if (res == 0)
Miklos Szeredi76f65782004-02-19 16:55:40 +0000828 res = lookup_path(f, in->ino, in->unique, name, path, &outarg);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000829 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000830 free(path);
Miklos Szeredib483c932001-10-29 14:57:57 +0000831 }
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000832 res2 = send_reply(f, in, res, &outarg, sizeof(outarg));
833 if (res == 0 && res2 == -ENOENT)
834 destroy_node(f, outarg.ino, in->unique);
Miklos Szeredib483c932001-10-29 14:57:57 +0000835}
836
837static void do_mkdir(struct fuse *f, struct fuse_in_header *in,
838 struct fuse_mkdir_in *inarg)
839{
840 int res;
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000841 int res2;
Miklos Szeredib483c932001-10-29 14:57:57 +0000842 char *path;
Miklos Szeredi76f65782004-02-19 16:55:40 +0000843 char *name = PARAM(inarg);
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000844 struct fuse_entry_out outarg;
Miklos Szeredib483c932001-10-29 14:57:57 +0000845
Miklos Szeredi5e183482001-10-31 14:52:35 +0000846 res = -ENOENT;
Miklos Szeredi76f65782004-02-19 16:55:40 +0000847 path = get_path_name(f, in->ino, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000848 if (path != NULL) {
849 if (f->flags & FUSE_DEBUG) {
Miklos Szeredi76f65782004-02-19 16:55:40 +0000850 printf("MKDIR %s\n", path);
851 fflush(stdout);
852 }
Miklos Szeredi5e183482001-10-31 14:52:35 +0000853 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000854 if (f->op.mkdir && f->op.getattr) {
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000855 res = f->op.mkdir(path, inarg->mode);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000856 if (res == 0)
Miklos Szeredi76f65782004-02-19 16:55:40 +0000857 res = lookup_path(f, in->ino, in->unique, name, path, &outarg);
858 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000859 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000860 }
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000861 res2 = send_reply(f, in, res, &outarg, sizeof(outarg));
862 if (res == 0 && res2 == -ENOENT)
863 destroy_node(f, outarg.ino, in->unique);
Miklos Szeredib483c932001-10-29 14:57:57 +0000864}
865
Miklos Szeredib5958612004-02-20 14:10:49 +0000866static void do_unlink(struct fuse *f, struct fuse_in_header *in, char *name)
Miklos Szeredib483c932001-10-29 14:57:57 +0000867{
868 int res;
869 char *path;
870
Miklos Szeredi5e183482001-10-31 14:52:35 +0000871 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000872 path = get_path_name(f, in->ino, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000873 if (path != NULL) {
Miklos Szeredi209f5d02004-07-24 19:56:16 +0000874 if (f->flags & FUSE_DEBUG) {
875 printf("UNLINK %s\n", path);
876 fflush(stdout);
877 }
Miklos Szeredi5e183482001-10-31 14:52:35 +0000878 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000879 if (f->op.unlink) {
Miklos Szeredi2529ca22004-07-13 15:36:52 +0000880 if (!(f->flags & FUSE_HARD_REMOVE) && is_open(f, in->ino, name))
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000881 res = hide_node(f, path, in->ino, name);
882 else {
883 res = f->op.unlink(path);
884 if (res == 0)
885 remove_node(f, in->ino, name);
886 }
Miklos Szeredi5e183482001-10-31 14:52:35 +0000887 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000888 free(path);
Miklos Szeredib483c932001-10-29 14:57:57 +0000889 }
Miklos Szeredib5958612004-02-20 14:10:49 +0000890 send_reply(f, in, res, NULL, 0);
891}
892
893static void do_rmdir(struct fuse *f, struct fuse_in_header *in, char *name)
894{
895 int res;
896 char *path;
897
898 res = -ENOENT;
899 path = get_path_name(f, in->ino, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000900 if (path != NULL) {
Miklos Szeredi209f5d02004-07-24 19:56:16 +0000901 if (f->flags & FUSE_DEBUG) {
902 printf("RMDIR %s\n", path);
903 fflush(stdout);
904 }
Miklos Szeredib5958612004-02-20 14:10:49 +0000905 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000906 if (f->op.rmdir) {
Miklos Szeredib5958612004-02-20 14:10:49 +0000907 res = f->op.rmdir(path);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000908 if (res == 0)
Miklos Szeredib5958612004-02-20 14:10:49 +0000909 remove_node(f, in->ino, name);
910 }
911 free(path);
912 }
Miklos Szeredib483c932001-10-29 14:57:57 +0000913 send_reply(f, in, res, NULL, 0);
914}
915
916static void do_symlink(struct fuse *f, struct fuse_in_header *in, char *name,
917 char *link)
918{
919 int res;
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000920 int res2;
Miklos Szeredib483c932001-10-29 14:57:57 +0000921 char *path;
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000922 struct fuse_entry_out outarg;
Miklos Szeredib483c932001-10-29 14:57:57 +0000923
Miklos Szeredi5e183482001-10-31 14:52:35 +0000924 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000925 path = get_path_name(f, in->ino, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000926 if (path != NULL) {
927 if (f->flags & FUSE_DEBUG) {
Miklos Szeredi76f65782004-02-19 16:55:40 +0000928 printf("SYMLINK %s\n", path);
929 fflush(stdout);
930 }
Miklos Szeredi5e183482001-10-31 14:52:35 +0000931 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000932 if (f->op.symlink && f->op.getattr) {
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000933 res = f->op.symlink(link, path);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000934 if (res == 0)
Miklos Szeredi76f65782004-02-19 16:55:40 +0000935 res = lookup_path(f, in->ino, in->unique, name, path, &outarg);
936 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000937 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000938 }
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000939 res2 = send_reply(f, in, res, &outarg, sizeof(outarg));
940 if (res == 0 && res2 == -ENOENT)
941 destroy_node(f, outarg.ino, in->unique);
942
Miklos Szeredib483c932001-10-29 14:57:57 +0000943}
944
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000945static void do_rename(struct fuse *f, struct fuse_in_header *in,
946 struct fuse_rename_in *inarg)
947{
948 int res;
949 fino_t olddir = in->ino;
950 fino_t newdir = inarg->newdir;
Miklos Szeredi6bf8b682002-10-28 08:49:39 +0000951 char *oldname = PARAM(inarg);
952 char *newname = oldname + strlen(oldname) + 1;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000953 char *oldpath;
954 char *newpath;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000955
Miklos Szeredi5e183482001-10-31 14:52:35 +0000956 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000957 oldpath = get_path_name(f, olddir, oldname);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000958 if (oldpath != NULL) {
Miklos Szeredia181e612001-11-06 12:03:23 +0000959 newpath = get_path_name(f, newdir, newname);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000960 if (newpath != NULL) {
Miklos Szeredi209f5d02004-07-24 19:56:16 +0000961 if (f->flags & FUSE_DEBUG) {
962 printf("RENAME %s -> %s\n", oldpath, newpath);
963 fflush(stdout);
964 }
Miklos Szeredi5e183482001-10-31 14:52:35 +0000965 res = -ENOSYS;
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000966 if (f->op.rename) {
967 res = 0;
Miklos Szeredi2529ca22004-07-13 15:36:52 +0000968 if (!(f->flags & FUSE_HARD_REMOVE) &&
969 is_open(f, newdir, newname))
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000970 res = hide_node(f, newpath, newdir, newname);
971 if (res == 0) {
972 res = f->op.rename(oldpath, newpath);
973 if (res == 0)
Miklos Szeredib2cf9562004-09-16 08:42:40 +0000974 res = rename_node(f, olddir, oldname, newdir, newname, 0);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000975 }
976 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000977 free(newpath);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000978 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000979 free(oldpath);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000980 }
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000981 send_reply(f, in, res, NULL, 0);
982}
983
984static void do_link(struct fuse *f, struct fuse_in_header *in,
Miklos Szeredi5e183482001-10-31 14:52:35 +0000985 struct fuse_link_in *arg)
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000986{
987 int res;
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000988 int res2;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000989 char *oldpath;
990 char *newpath;
Miklos Szeredi76f65782004-02-19 16:55:40 +0000991 char *name = PARAM(arg);
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000992 struct fuse_entry_out outarg;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000993
Miklos Szeredi5e183482001-10-31 14:52:35 +0000994 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000995 oldpath = get_path(f, in->ino);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000996 if (oldpath != NULL) {
Miklos Szeredi76f65782004-02-19 16:55:40 +0000997 newpath = get_path_name(f, arg->newdir, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000998 if (newpath != NULL) {
999 if (f->flags & FUSE_DEBUG) {
Miklos Szeredi76f65782004-02-19 16:55:40 +00001000 printf("LINK %s\n", newpath);
1001 fflush(stdout);
1002 }
Miklos Szeredi5e183482001-10-31 14:52:35 +00001003 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001004 if (f->op.link && f->op.getattr) {
Miklos Szeredi0a7077f2001-11-11 18:20:17 +00001005 res = f->op.link(oldpath, newpath);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001006 if (res == 0)
Miklos Szeredi76f65782004-02-19 16:55:40 +00001007 res = lookup_path(f, arg->newdir, in->unique, name,
1008 newpath, &outarg);
1009 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001010 free(newpath);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001011 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001012 free(oldpath);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001013 }
Miklos Szeredi2778f6c2004-06-21 09:45:30 +00001014 res2 = send_reply(f, in, res, &outarg, sizeof(outarg));
1015 if (res == 0 && res2 == -ENOENT)
1016 destroy_node(f, outarg.ino, in->unique);
Miklos Szeredi19dff1b2001-10-30 15:06:52 +00001017}
1018
Miklos Szeredi5e183482001-10-31 14:52:35 +00001019static void do_open(struct fuse *f, struct fuse_in_header *in,
1020 struct fuse_open_in *arg)
1021{
1022 int res;
1023 char *path;
Miklos Szeredi209f5d02004-07-24 19:56:16 +00001024 struct fuse_open_out outarg;
Miklos Szeredi5e183482001-10-31 14:52:35 +00001025
1026 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) {
Miklos Szeredi5e183482001-10-31 14:52:35 +00001029 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001030 if (f->op.open)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +00001031 res = f->op.open(path, arg->flags);
Miklos Szeredi40b9a5a2002-12-10 16:09:02 +00001032 }
Miklos Szeredi73798f92004-07-12 15:55:11 +00001033 if (res == 0) {
1034 int res2;
1035
1036 /* If the request is interrupted the lock must be held until
1037 the cancellation is finished. Otherwise there could be
1038 races with rename/unlink, against which the kernel can't
1039 protect */
1040 pthread_mutex_lock(&f->lock);
Miklos Szeredi209f5d02004-07-24 19:56:16 +00001041 f->fh_ctr ++;
1042 outarg.fh = f->fh_ctr;
1043 if (f->flags & FUSE_DEBUG) {
1044 printf("OPEN[%u] flags: 0x%x\n", outarg.fh, arg->flags);
1045 fflush(stdout);
1046 }
1047
1048 res2 = __send_reply(f, in, res, &outarg, sizeof(outarg), 1);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001049 if(res2 == -ENOENT) {
1050 /* The open syscall was interrupted, so it must be cancelled */
1051 if(f->op.release)
1052 f->op.release(path, arg->flags);
Miklos Szeredi73798f92004-07-12 15:55:11 +00001053 } else
1054 get_node(f, in->ino)->open_count ++;
1055 pthread_mutex_unlock(&f->lock);
1056
1057 } else
1058 send_reply(f, in, res, NULL, 0);
1059
Miklos Szeredi9a31cca2004-06-26 21:11:25 +00001060 if (path)
1061 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001062}
1063
Miklos Szeredi209f5d02004-07-24 19:56:16 +00001064static void do_flush(struct fuse *f, struct fuse_in_header *in,
1065 struct fuse_flush_in *arg)
Miklos Szeredie2e4ac22004-05-18 08:45:28 +00001066{
1067 char *path;
1068 int res;
1069
1070 res = -ENOENT;
1071 path = get_path(f, in->ino);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001072 if (path != NULL) {
Miklos Szeredi209f5d02004-07-24 19:56:16 +00001073 if (f->flags & FUSE_DEBUG) {
1074 printf("FLUSH[%u]\n", arg->fh);
1075 fflush(stdout);
1076 }
Miklos Szeredie2e4ac22004-05-18 08:45:28 +00001077 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001078 if (f->op.flush)
Miklos Szeredie2e4ac22004-05-18 08:45:28 +00001079 res = f->op.flush(path);
1080 free(path);
1081 }
1082 send_reply(f, in, res, NULL, 0);
1083}
1084
Miklos Szeredi9478e862002-12-11 09:50:26 +00001085static void do_release(struct fuse *f, struct fuse_in_header *in,
Miklos Szeredi209f5d02004-07-24 19:56:16 +00001086 struct fuse_release_in *arg)
Miklos Szeredic8ba2372002-12-10 12:26:00 +00001087{
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001088 struct node *node;
1089 char *path;
Miklos Szeredic8ba2372002-12-10 12:26:00 +00001090
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001091 pthread_mutex_lock(&f->lock);
1092 node = get_node(f, in->ino);
1093 --node->open_count;
1094 pthread_mutex_unlock(&f->lock);
1095
1096 path = get_path(f, in->ino);
1097 if (path != NULL) {
Miklos Szeredi209f5d02004-07-24 19:56:16 +00001098 if (f->flags & FUSE_DEBUG) {
1099 printf("RELEASE[%u]\n", arg->fh);
1100 fflush(stdout);
1101 }
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001102 if (f->op.release)
Miklos Szeredib3210582004-06-23 13:54:33 +00001103 f->op.release(path, arg->flags);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001104
1105 if(node->is_hidden && node->open_count == 0)
1106 /* can now clean up this hidden file */
1107 f->op.unlink(path);
1108
1109 free(path);
Miklos Szeredic8ba2372002-12-10 12:26:00 +00001110 }
Miklos Szeredi556d03d2004-06-30 11:13:41 +00001111 send_reply(f, in, 0, NULL, 0);
Miklos Szeredic8ba2372002-12-10 12:26:00 +00001112}
1113
Miklos Szeredi5e183482001-10-31 14:52:35 +00001114static void do_read(struct fuse *f, struct fuse_in_header *in,
1115 struct fuse_read_in *arg)
1116{
1117 int res;
1118 char *path;
Miklos Szeredi43696432001-11-18 19:15:05 +00001119 char *outbuf = (char *) malloc(sizeof(struct fuse_out_header) + arg->size);
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001120 if (outbuf == NULL)
1121 send_reply(f, in, -ENOMEM, NULL, 0);
1122 else {
1123 struct fuse_out_header *out = (struct fuse_out_header *) outbuf;
1124 char *buf = outbuf + sizeof(struct fuse_out_header);
1125 size_t size;
1126 size_t outsize;
1127
1128 res = -ENOENT;
1129 path = get_path(f, in->ino);
1130 if (path != NULL) {
1131 if (f->flags & FUSE_DEBUG) {
1132 printf("READ[%u] %u bytes from %llu\n", arg->fh, arg->size,
1133 arg->offset);
1134 fflush(stdout);
1135 }
1136
1137 res = -ENOSYS;
1138 if (f->op.read)
1139 res = f->op.read(path, buf, arg->size, arg->offset);
1140 free(path);
Miklos Szeredi6ebe2342002-01-06 21:44:16 +00001141 }
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001142
1143 size = 0;
1144 if (res >= 0) {
1145 size = res;
1146 res = 0;
1147 if (f->flags & FUSE_DEBUG) {
1148 printf(" READ[%u] %u bytes\n", arg->fh, size);
1149 fflush(stdout);
1150 }
Miklos Szeredi6ebe2342002-01-06 21:44:16 +00001151 }
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001152 memset(out, 0, sizeof(struct fuse_out_header));
1153 out->unique = in->unique;
1154 out->error = res;
1155 outsize = sizeof(struct fuse_out_header) + size;
1156
1157 send_reply_raw(f, outbuf, outsize, 0);
1158 free(outbuf);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001159 }
Miklos Szeredi5e183482001-10-31 14:52:35 +00001160}
Miklos Szeredib483c932001-10-29 14:57:57 +00001161
Miklos Szeredia181e612001-11-06 12:03:23 +00001162static void do_write(struct fuse *f, struct fuse_in_header *in,
1163 struct fuse_write_in *arg)
1164{
1165 int res;
1166 char *path;
Miklos Szerediad051c32004-07-02 09:22:50 +00001167 struct fuse_write_out outarg;
Miklos Szeredia181e612001-11-06 12:03:23 +00001168
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001169 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +00001170 path = get_path(f, in->ino);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001171 if (path != NULL) {
1172 if (f->flags & FUSE_DEBUG) {
Miklos Szeredi209f5d02004-07-24 19:56:16 +00001173 printf("WRITE%s[%u] %u bytes to %llu\n",
1174 arg->writepage ? "PAGE" : "", arg->fh, arg->size,
1175 arg->offset);
Miklos Szeredi6ebe2342002-01-06 21:44:16 +00001176 fflush(stdout);
1177 }
1178
Miklos Szeredia181e612001-11-06 12:03:23 +00001179 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001180 if (f->op.write)
Miklos Szeredi6bf8b682002-10-28 08:49:39 +00001181 res = f->op.write(path, PARAM(arg), arg->size, arg->offset);
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001182 free(path);
Miklos Szeredia181e612001-11-06 12:03:23 +00001183 }
1184
Miklos Szerediad051c32004-07-02 09:22:50 +00001185 if (res >= 0) {
1186 outarg.size = res;
1187 res = 0;
Miklos Szeredia181e612001-11-06 12:03:23 +00001188 }
1189
Miklos Szerediad051c32004-07-02 09:22:50 +00001190 send_reply(f, in, res, &outarg, sizeof(outarg));
Miklos Szeredia181e612001-11-06 12:03:23 +00001191}
1192
Miklos Szeredi77f39942004-03-25 11:17:52 +00001193static int default_statfs(struct statfs *buf)
1194{
1195 buf->f_namelen = 255;
1196 buf->f_bsize = 512;
1197 return 0;
1198}
1199
Miklos Szeredi18e75e42004-02-19 14:23:27 +00001200static void convert_statfs(struct statfs *statfs, struct fuse_kstatfs *kstatfs)
1201{
1202 kstatfs->bsize = statfs->f_bsize;
1203 kstatfs->blocks = statfs->f_blocks;
1204 kstatfs->bfree = statfs->f_bfree;
1205 kstatfs->bavail = statfs->f_bavail;
1206 kstatfs->files = statfs->f_files;
1207 kstatfs->ffree = statfs->f_ffree;
1208 kstatfs->namelen = statfs->f_namelen;
1209}
1210
Mark Glinesd84b39a2002-01-07 16:32:02 +00001211static void do_statfs(struct fuse *f, struct fuse_in_header *in)
1212{
1213 int res;
Mark Glinesd84b39a2002-01-07 16:32:02 +00001214 struct fuse_statfs_out arg;
Miklos Szeredi18e75e42004-02-19 14:23:27 +00001215 struct statfs buf;
Mark Glinesd84b39a2002-01-07 16:32:02 +00001216
Miklos Szeredi77f39942004-03-25 11:17:52 +00001217 memset(&buf, 0, sizeof(struct statfs));
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001218 if (f->op.statfs)
Miklos Szeredi18e75e42004-02-19 14:23:27 +00001219 res = f->op.statfs("/", &buf);
Miklos Szeredi77f39942004-03-25 11:17:52 +00001220 else
1221 res = default_statfs(&buf);
1222
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001223 if (res == 0)
Miklos Szeredi77f39942004-03-25 11:17:52 +00001224 convert_statfs(&buf, &arg.st);
Miklos Szeredi4b2bef42002-01-09 12:23:27 +00001225
Mark Glinesd84b39a2002-01-07 16:32:02 +00001226 send_reply(f, in, res, &arg, sizeof(arg));
1227}
1228
Miklos Szeredi5e43f2c2003-12-12 14:06:41 +00001229static void do_fsync(struct fuse *f, struct fuse_in_header *in,
1230 struct fuse_fsync_in *inarg)
1231{
1232 int res;
1233 char *path;
1234
1235 res = -ENOENT;
1236 path = get_path(f, in->ino);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001237 if (path != NULL) {
Miklos Szeredi209f5d02004-07-24 19:56:16 +00001238 if (f->flags & FUSE_DEBUG) {
1239 printf("FSYNC[%u]\n", inarg->fh);
1240 fflush(stdout);
1241 }
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001242 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001243 if (f->op.fsync)
Miklos Szeredi5e43f2c2003-12-12 14:06:41 +00001244 res = f->op.fsync(path, inarg->datasync);
1245 free(path);
1246 }
1247 send_reply(f, in, res, NULL, 0);
1248}
1249
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001250static void do_setxattr(struct fuse *f, struct fuse_in_header *in,
1251 struct fuse_setxattr_in *arg)
1252{
1253 int res;
1254 char *path;
1255 char *name = PARAM(arg);
1256 unsigned char *value = name + strlen(name) + 1;
1257
1258 res = -ENOENT;
1259 path = get_path(f, in->ino);
1260 if (path != NULL) {
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001261 res = -ENOSYS;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001262 if (f->op.setxattr)
1263 res = f->op.setxattr(path, name, value, arg->size, arg->flags);
1264 free(path);
1265 }
1266 send_reply(f, in, res, NULL, 0);
1267}
1268
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001269static int common_getxattr(struct fuse *f, struct fuse_in_header *in,
1270 const char *name, char *value, size_t size)
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001271{
1272 int res;
1273 char *path;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001274
1275 res = -ENOENT;
1276 path = get_path(f, in->ino);
1277 if (path != NULL) {
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001278 res = -ENOSYS;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001279 if (f->op.getxattr)
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001280 res = f->op.getxattr(path, name, value, size);
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001281 free(path);
1282 }
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001283 return res;
1284}
1285
1286static void do_getxattr_read(struct fuse *f, struct fuse_in_header *in,
1287 const char *name, size_t size)
1288{
1289 int res;
1290 char *outbuf = (char *) malloc(sizeof(struct fuse_out_header) + size);
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001291 if (outbuf == NULL)
1292 send_reply(f, in, -ENOMEM, NULL, 0);
1293 else {
1294 struct fuse_out_header *out = (struct fuse_out_header *) outbuf;
1295 char *value = outbuf + sizeof(struct fuse_out_header);
1296
1297 res = common_getxattr(f, in, name, value, size);
1298 size = 0;
1299 if (res > 0) {
1300 size = res;
1301 res = 0;
1302 }
1303 memset(out, 0, sizeof(struct fuse_out_header));
1304 out->unique = in->unique;
1305 out->error = res;
1306
1307 send_reply_raw(f, outbuf, sizeof(struct fuse_out_header) + size, 0);
1308 free(outbuf);
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001309 }
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001310}
1311
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001312static void do_getxattr_size(struct fuse *f, struct fuse_in_header *in,
1313 const char *name)
1314{
1315 int res;
1316 struct fuse_getxattr_out arg;
1317
1318 res = common_getxattr(f, in, name, NULL, 0);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001319 if (res >= 0) {
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001320 arg.size = res;
1321 res = 0;
1322 }
1323 send_reply(f, in, res, &arg, sizeof(arg));
1324}
1325
1326static void do_getxattr(struct fuse *f, struct fuse_in_header *in,
1327 struct fuse_getxattr_in *arg)
1328{
1329 char *name = PARAM(arg);
1330
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001331 if (arg->size)
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001332 do_getxattr_read(f, in, name, arg->size);
1333 else
1334 do_getxattr_size(f, in, name);
1335}
1336
1337static int common_listxattr(struct fuse *f, struct fuse_in_header *in,
1338 char *list, size_t size)
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001339{
1340 int res;
1341 char *path;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001342
1343 res = -ENOENT;
1344 path = get_path(f, in->ino);
1345 if (path != NULL) {
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001346 res = -ENOSYS;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001347 if (f->op.listxattr)
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001348 res = f->op.listxattr(path, list, size);
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001349 free(path);
1350 }
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001351 return res;
1352}
1353
1354static void do_listxattr_read(struct fuse *f, struct fuse_in_header *in,
1355 size_t size)
1356{
1357 int res;
1358 char *outbuf = (char *) malloc(sizeof(struct fuse_out_header) + size);
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001359 if (outbuf == NULL)
1360 send_reply(f, in, -ENOMEM, NULL, 0);
1361 else {
1362 struct fuse_out_header *out = (struct fuse_out_header *) outbuf;
1363 char *list = outbuf + sizeof(struct fuse_out_header);
1364
1365 res = common_listxattr(f, in, list, size);
1366 size = 0;
1367 if (res > 0) {
1368 size = res;
1369 res = 0;
1370 }
1371 memset(out, 0, sizeof(struct fuse_out_header));
1372 out->unique = in->unique;
1373 out->error = res;
1374
1375 send_reply_raw(f, outbuf, sizeof(struct fuse_out_header) + size, 0);
1376 free(outbuf);
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001377 }
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001378}
1379
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001380static void do_listxattr_size(struct fuse *f, struct fuse_in_header *in)
1381{
1382 int res;
1383 struct fuse_getxattr_out arg;
1384
1385 res = common_listxattr(f, in, NULL, 0);
1386 if (res >= 0) {
1387 arg.size = res;
1388 res = 0;
1389 }
1390 send_reply(f, in, res, &arg, sizeof(arg));
1391}
1392
1393static void do_listxattr(struct fuse *f, struct fuse_in_header *in,
1394 struct fuse_getxattr_in *arg)
1395{
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001396 if (arg->size)
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001397 do_listxattr_read(f, in, arg->size);
1398 else
1399 do_listxattr_size(f, in);
1400}
1401
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001402static void do_removexattr(struct fuse *f, struct fuse_in_header *in,
1403 char *name)
1404{
1405 int res;
1406 char *path;
1407
1408 res = -ENOENT;
1409 path = get_path(f, in->ino);
1410 if (path != NULL) {
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001411 res = -ENOSYS;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001412 if (f->op.removexattr)
1413 res = f->op.removexattr(path, name);
1414 free(path);
1415 }
1416 send_reply(f, in, res, NULL, 0);
1417}
1418
1419
Miklos Szeredi43696432001-11-18 19:15:05 +00001420static void free_cmd(struct fuse_cmd *cmd)
1421{
1422 free(cmd->buf);
1423 free(cmd);
1424}
1425
Miklos Szeredifff56ab2001-11-16 10:12:59 +00001426void __fuse_process_cmd(struct fuse *f, struct fuse_cmd *cmd)
Miklos Szeredia181e612001-11-06 12:03:23 +00001427{
Miklos Szeredia181e612001-11-06 12:03:23 +00001428 struct fuse_in_header *in = (struct fuse_in_header *) cmd->buf;
1429 void *inarg = cmd->buf + sizeof(struct fuse_in_header);
1430 size_t argsize;
Miklos Szeredife25def2001-12-20 15:38:05 +00001431 struct fuse_context *ctx = fuse_get_context(f);
Miklos Szeredia181e612001-11-06 12:03:23 +00001432
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +00001433 dec_avail(f);
Miklos Szeredi33232032001-11-19 17:55:51 +00001434
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001435 if ((f->flags & FUSE_DEBUG)) {
Miklos Szeredic8ba2372002-12-10 12:26:00 +00001436 printf("unique: %i, opcode: %s (%i), ino: %li, insize: %i\n",
1437 in->unique, opname(in->opcode), in->opcode, in->ino,
1438 cmd->buflen);
Miklos Szeredic0938ea2001-11-07 12:35:06 +00001439 fflush(stdout);
1440 }
Miklos Szeredife25def2001-12-20 15:38:05 +00001441
1442 ctx->uid = in->uid;
1443 ctx->gid = in->gid;
Miklos Szeredia181e612001-11-06 12:03:23 +00001444
1445 argsize = cmd->buflen - sizeof(struct fuse_in_header);
1446
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001447 switch (in->opcode) {
Miklos Szeredia181e612001-11-06 12:03:23 +00001448 case FUSE_LOOKUP:
1449 do_lookup(f, in, (char *) inarg);
1450 break;
1451
Miklos Szeredia181e612001-11-06 12:03:23 +00001452 case FUSE_GETATTR:
1453 do_getattr(f, in);
1454 break;
1455
1456 case FUSE_SETATTR:
1457 do_setattr(f, in, (struct fuse_setattr_in *) inarg);
1458 break;
1459
1460 case FUSE_READLINK:
1461 do_readlink(f, in);
1462 break;
1463
1464 case FUSE_GETDIR:
1465 do_getdir(f, in);
1466 break;
1467
1468 case FUSE_MKNOD:
1469 do_mknod(f, in, (struct fuse_mknod_in *) inarg);
1470 break;
1471
1472 case FUSE_MKDIR:
1473 do_mkdir(f, in, (struct fuse_mkdir_in *) inarg);
1474 break;
1475
1476 case FUSE_UNLINK:
Miklos Szeredib5958612004-02-20 14:10:49 +00001477 do_unlink(f, in, (char *) inarg);
1478 break;
1479
Miklos Szeredia181e612001-11-06 12:03:23 +00001480 case FUSE_RMDIR:
Miklos Szeredib5958612004-02-20 14:10:49 +00001481 do_rmdir(f, in, (char *) inarg);
Miklos Szeredia181e612001-11-06 12:03:23 +00001482 break;
1483
1484 case FUSE_SYMLINK:
1485 do_symlink(f, in, (char *) inarg,
1486 ((char *) inarg) + strlen((char *) inarg) + 1);
1487 break;
1488
1489 case FUSE_RENAME:
1490 do_rename(f, in, (struct fuse_rename_in *) inarg);
1491 break;
1492
1493 case FUSE_LINK:
1494 do_link(f, in, (struct fuse_link_in *) inarg);
1495 break;
1496
1497 case FUSE_OPEN:
1498 do_open(f, in, (struct fuse_open_in *) inarg);
1499 break;
1500
Miklos Szeredie2e4ac22004-05-18 08:45:28 +00001501 case FUSE_FLUSH:
Miklos Szeredi209f5d02004-07-24 19:56:16 +00001502 do_flush(f, in, (struct fuse_flush_in *) inarg);
Miklos Szeredie2e4ac22004-05-18 08:45:28 +00001503 break;
1504
Miklos Szeredi9478e862002-12-11 09:50:26 +00001505 case FUSE_RELEASE:
Miklos Szeredi209f5d02004-07-24 19:56:16 +00001506 do_release(f, in, (struct fuse_release_in *) inarg);
Miklos Szeredi9478e862002-12-11 09:50:26 +00001507 break;
1508
Miklos Szeredia181e612001-11-06 12:03:23 +00001509 case FUSE_READ:
1510 do_read(f, in, (struct fuse_read_in *) inarg);
1511 break;
1512
1513 case FUSE_WRITE:
1514 do_write(f, in, (struct fuse_write_in *) inarg);
1515 break;
1516
Mark Glinesd84b39a2002-01-07 16:32:02 +00001517 case FUSE_STATFS:
1518 do_statfs(f, in);
1519 break;
1520
Miklos Szeredi5e43f2c2003-12-12 14:06:41 +00001521 case FUSE_FSYNC:
1522 do_fsync(f, in, (struct fuse_fsync_in *) inarg);
1523 break;
1524
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001525 case FUSE_SETXATTR:
1526 do_setxattr(f, in, (struct fuse_setxattr_in *) inarg);
1527 break;
1528
1529 case FUSE_GETXATTR:
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001530 do_getxattr(f, in, (struct fuse_getxattr_in *) inarg);
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001531 break;
1532
1533 case FUSE_LISTXATTR:
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001534 do_listxattr(f, in, (struct fuse_getxattr_in *) inarg);
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001535 break;
1536
1537 case FUSE_REMOVEXATTR:
1538 do_removexattr(f, in, (char *) inarg);
1539 break;
1540
Miklos Szeredia181e612001-11-06 12:03:23 +00001541 default:
Miklos Szeredi43696432001-11-18 19:15:05 +00001542 send_reply(f, in, -ENOSYS, NULL, 0);
Miklos Szeredia181e612001-11-06 12:03:23 +00001543 }
Miklos Szeredi43696432001-11-18 19:15:05 +00001544
1545 free_cmd(cmd);
Miklos Szeredia181e612001-11-06 12:03:23 +00001546}
1547
Miklos Szeredi65cf7c72004-06-30 11:34:56 +00001548int __fuse_exited(struct fuse* f)
1549{
1550 return f->exited;
1551}
1552
Miklos Szeredifff56ab2001-11-16 10:12:59 +00001553struct fuse_cmd *__fuse_read_cmd(struct fuse *f)
Miklos Szeredi2df1c042001-11-06 15:07:17 +00001554{
Miklos Szeredifff56ab2001-11-16 10:12:59 +00001555 ssize_t res;
Miklos Szeredifff56ab2001-11-16 10:12:59 +00001556 struct fuse_cmd *cmd;
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +00001557 struct fuse_in_header *in;
1558 void *inarg;
Miklos Szeredifff56ab2001-11-16 10:12:59 +00001559
Miklos Szeredi43696432001-11-18 19:15:05 +00001560 cmd = (struct fuse_cmd *) malloc(sizeof(struct fuse_cmd));
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001561 if (cmd == NULL) {
1562 fprintf(stderr, "fuse: failed to allocate cmd in read\n");
1563 return NULL;
1564 }
Miklos Szeredi43696432001-11-18 19:15:05 +00001565 cmd->buf = (char *) malloc(FUSE_MAX_IN);
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001566 if (cmd->buf == NULL) {
1567 fprintf(stderr, "fuse: failed to allocate read buffer\n");
1568 free(cmd);
1569 return NULL;
1570 }
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +00001571 in = (struct fuse_in_header *) cmd->buf;
1572 inarg = cmd->buf + sizeof(struct fuse_in_header);
Miklos Szeredi43696432001-11-18 19:15:05 +00001573
Miklos Szeredi65cf7c72004-06-30 11:34:56 +00001574 res = read(f->fd, cmd->buf, FUSE_MAX_IN);
1575 if (res == -1) {
1576 free_cmd(cmd);
1577 if (__fuse_exited(f) || errno == EINTR)
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +00001578 return NULL;
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +00001579
Miklos Szeredi65cf7c72004-06-30 11:34:56 +00001580 /* ENODEV means we got unmounted, so we silenty return failure */
1581 if (errno != ENODEV) {
1582 /* BAD... This will happen again */
1583 perror("fuse: reading device");
1584 }
1585
1586 fuse_exit(f);
1587 return NULL;
1588 }
1589 if ((size_t) res < sizeof(struct fuse_in_header)) {
1590 free_cmd(cmd);
1591 /* Cannot happen */
1592 fprintf(stderr, "short read on fuse device\n");
1593 fuse_exit(f);
1594 return NULL;
1595 }
1596 cmd->buflen = res;
1597
1598 /* Forget is special, it can be done without messing with threads. */
1599 if (in->opcode == FUSE_FORGET) {
1600 do_forget(f, in, (struct fuse_forget_in *) inarg);
1601 free_cmd(cmd);
1602 return NULL;
1603 }
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +00001604
Miklos Szeredifff56ab2001-11-16 10:12:59 +00001605 return cmd;
Miklos Szeredi2df1c042001-11-06 15:07:17 +00001606}
1607
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001608int fuse_loop(struct fuse *f)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001609{
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001610 if (f == NULL)
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001611 return -1;
Miklos Szeredic40748a2004-02-20 16:38:45 +00001612
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001613 while (1) {
Miklos Szeredi0f48a262002-12-05 14:23:01 +00001614 struct fuse_cmd *cmd;
1615
Miklos Szeredi65cf7c72004-06-30 11:34:56 +00001616 if (__fuse_exited(f))
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001617 return 0;
Miklos Szeredi0f48a262002-12-05 14:23:01 +00001618
1619 cmd = __fuse_read_cmd(f);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001620 if (cmd == NULL)
Miklos Szeredi0f48a262002-12-05 14:23:01 +00001621 continue;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001622
Miklos Szeredifff56ab2001-11-16 10:12:59 +00001623 __fuse_process_cmd(f, cmd);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001624 }
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001625 return 0;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001626}
1627
Miklos Szeredi891b8742004-07-29 09:27:49 +00001628int fuse_invalidate(struct fuse *f, const char *path)
1629{
1630 int res;
1631 int err;
1632 fino_t ino;
1633 struct fuse_user_header h;
1634
1635 err = path_lookup(f, path, &ino);
1636 if (err) {
1637 if (err == -ENOENT)
1638 return 0;
1639 else
1640 return err;
1641 }
1642
1643 memset(&h, 0, sizeof(struct fuse_user_header));
1644 h.opcode = FUSE_INVALIDATE;
1645 h.ino = ino;
1646
1647 if ((f->flags & FUSE_DEBUG)) {
1648 printf("INVALIDATE ino: %li\n", ino);
1649 fflush(stdout);
1650 }
1651
1652 res = write(f->fd, &h, sizeof(struct fuse_user_header));
1653 if (res == -1) {
1654 if (errno != ENOENT) {
1655 perror("fuse: writing device");
1656 return -errno;
1657 }
1658 }
1659 return 0;
1660}
1661
Miklos Szeredi0f48a262002-12-05 14:23:01 +00001662void fuse_exit(struct fuse *f)
1663{
1664 f->exited = 1;
1665}
1666
Miklos Szeredi2e50d432001-12-20 12:17:25 +00001667struct fuse_context *fuse_get_context(struct fuse *f)
1668{
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001669 if (f->getcontext)
Miklos Szeredi2e50d432001-12-20 12:17:25 +00001670 return f->getcontext(f);
1671 else
1672 return &f->context;
1673}
1674
Miklos Szeredic40748a2004-02-20 16:38:45 +00001675static int check_version(struct fuse *f)
1676{
1677 int res;
1678 FILE *vf = fopen(FUSE_VERSION_FILE, "r");
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001679 if (vf == NULL) {
Miklos Szeredic40748a2004-02-20 16:38:45 +00001680 fprintf(stderr, "fuse: kernel interface too old, need >= %i.%i\n",
1681 FUSE_KERNEL_VERSION, FUSE_KERNEL_MINOR_VERSION);
1682 return -1;
1683 }
1684 res = fscanf(vf, "%i.%i", &f->majorver, &f->minorver);
1685 fclose(vf);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001686 if (res != 2) {
Miklos Szeredic40748a2004-02-20 16:38:45 +00001687 fprintf(stderr, "fuse: error reading %s\n", FUSE_VERSION_FILE);
1688 return -1;
1689 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001690 if (f->majorver != FUSE_KERNEL_VERSION) {
Miklos Szeredic40748a2004-02-20 16:38:45 +00001691 fprintf(stderr, "fuse: bad kernel interface major version: needs %i\n",
1692 FUSE_KERNEL_VERSION);
1693 return -1;
1694 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001695 if (f->minorver < FUSE_KERNEL_MINOR_VERSION) {
Miklos Szeredic40748a2004-02-20 16:38:45 +00001696 fprintf(stderr, "fuse: kernel interface too old: need >= %i.%i",
1697 FUSE_KERNEL_VERSION, FUSE_KERNEL_MINOR_VERSION);
1698 return -1;
1699 }
1700
1701 return 0;
1702}
1703
Miklos Szeredibd7661b2004-07-23 17:16:29 +00001704
1705int fuse_is_lib_option(const char *opt)
1706{
1707 if (strcmp(opt, "debug") == 0 ||
1708 strcmp(opt, "hard_remove") == 0)
1709 return 1;
1710 else
1711 return 0;
1712}
1713
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001714static int parse_lib_opts(struct fuse *f, const char *opts)
Miklos Szeredibd7661b2004-07-23 17:16:29 +00001715{
1716 if (opts) {
1717 char *xopts = strdup(opts);
1718 char *s = xopts;
1719 char *opt;
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001720
1721 if (xopts == NULL)
1722 return -1;
Miklos Szeredibd7661b2004-07-23 17:16:29 +00001723
1724 while((opt = strsep(&s, ","))) {
1725 if (strcmp(opt, "debug") == 0)
1726 f->flags |= FUSE_DEBUG;
1727 else if (strcmp(opt, "hard_remove") == 0)
1728 f->flags |= FUSE_HARD_REMOVE;
1729 else
1730 fprintf(stderr, "fuse: warning: unknown option `%s'\n", opt);
1731 }
1732 free(xopts);
1733 }
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001734 return 0;
Miklos Szeredibd7661b2004-07-23 17:16:29 +00001735}
1736
1737struct fuse *fuse_new(int fd, const char *opts, const struct fuse_operations *op)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001738{
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001739 struct fuse *f;
1740 struct node *root;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001741
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001742 f = (struct fuse *) calloc(1, sizeof(struct fuse));
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001743 if (f == NULL)
1744 goto out;
Miklos Szeredi2df1c042001-11-06 15:07:17 +00001745
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001746 if (check_version(f) == -1)
1747 goto out_free;
Miklos Szeredic40748a2004-02-20 16:38:45 +00001748
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001749 if (parse_lib_opts(f, opts) == -1)
1750 goto out_free;
1751
Miklos Szeredi8cffdb92001-11-09 14:49:18 +00001752 f->fd = fd;
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001753 f->ctr = 0;
Miklos Szeredi76f65782004-02-19 16:55:40 +00001754 f->generation = 0;
Miklos Szeredifff56ab2001-11-16 10:12:59 +00001755 /* FIXME: Dynamic hash table */
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001756 f->name_table_size = 14057;
1757 f->name_table = (struct node **)
1758 calloc(1, sizeof(struct node *) * f->name_table_size);
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001759 if (f->name_table == NULL)
1760 goto out_free;
1761
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001762 f->ino_table_size = 14057;
1763 f->ino_table = (struct node **)
1764 calloc(1, sizeof(struct node *) * f->ino_table_size);
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001765 if (f->ino_table == NULL)
1766 goto out_free_name_table;
1767
Miklos Szeredia181e612001-11-06 12:03:23 +00001768 pthread_mutex_init(&f->lock, NULL);
Miklos Szeredi33232032001-11-19 17:55:51 +00001769 f->numworker = 0;
1770 f->numavail = 0;
Miklos Szeredi2e50d432001-12-20 12:17:25 +00001771 f->op = *op;
1772 f->getcontext = NULL;
1773 f->context.uid = 0;
1774 f->context.gid = 0;
Miklos Szeredi0f48a262002-12-05 14:23:01 +00001775 f->exited = 0;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001776
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001777 root = (struct node *) calloc(1, sizeof(struct node));
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001778 if (root == NULL)
1779 goto out_free_ino_table;
1780
Miklos Szeredi8cffdb92001-11-09 14:49:18 +00001781 root->mode = 0;
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001782 root->rdev = 0;
1783 root->name = strdup("/");
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001784 if (root->name == NULL)
1785 goto out_free_root;
1786
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001787 root->parent = 0;
Miklos Szeredi76f65782004-02-19 16:55:40 +00001788 root->ino = FUSE_ROOT_INO;
1789 root->generation = 0;
1790 hash_ino(f, root);
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001791
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001792 return f;
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001793
1794 out_free_root:
1795 free(root);
1796 out_free_ino_table:
1797 free(f->ino_table);
1798 out_free_name_table:
1799 free(f->name_table);
1800 out_free:
1801 free(f);
1802 out:
1803 fprintf(stderr, "fuse: failed to allocate fuse object\n");
1804 return NULL;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001805}
1806
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001807void fuse_destroy(struct fuse *f)
1808{
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001809 size_t i;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001810 for (i = 0; i < f->ino_table_size; i++) {
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001811 struct node *node;
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001812
1813 for (node = f->ino_table[i]; node != NULL; node = node->ino_next) {
1814 if (node->is_hidden) {
1815 char *path = get_path(f, node->ino);
1816 if (path)
1817 f->op.unlink(path);
1818 }
1819 }
1820 }
1821 for (i = 0; i < f->ino_table_size; i++) {
1822 struct node *node;
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001823 struct node *next;
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001824
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001825 for (node = f->ino_table[i]; node != NULL; node = next) {
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001826 next = node->ino_next;
1827 free_node(node);
1828 }
1829 }
1830 free(f->ino_table);
1831 free(f->name_table);
Miklos Szeredia181e612001-11-06 12:03:23 +00001832 pthread_mutex_destroy(&f->lock);
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001833 free(f);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001834}