blob: a207fc0b0f3c393b26400c065c270812da024e8e [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)
218 return NULL;
219
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);
228 return NULL;
229 }
Miklos Szeredi76f65782004-02-19 16:55:40 +0000230 hash_ino(f, node);
Miklos Szeredia181e612001-11-06 12:03:23 +0000231
232 out:
233 node->version = version;
234 pthread_mutex_unlock(&f->lock);
Miklos Szeredi76f65782004-02-19 16:55:40 +0000235 return node;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000236}
237
Miklos Szeredi891b8742004-07-29 09:27:49 +0000238static int path_lookup(struct fuse *f, const char *path, fino_t *inop)
239{
240 fino_t ino;
241 int err;
242 char *s;
243 char *name;
244 char *tmp = strdup(path);
245 if (!tmp)
246 return -ENOMEM;
247
248 pthread_mutex_lock(&f->lock);
249 ino = FUSE_ROOT_INO;
250 err = 0;
251 for (s = tmp; (name = strsep(&s, "/")) != NULL; ) {
252 if (name[0]) {
253 struct node *node = __lookup_node(f, ino, name);
254 if (node == NULL) {
255 err = -ENOENT;
256 break;
257 }
258 ino = node->ino;
259 }
260 }
261 pthread_mutex_unlock(&f->lock);
262 free(tmp);
263 if (!err)
264 *inop = ino;
265
266 return err;
267}
268
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000269static char *add_name(char *buf, char *s, const char *name)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000270{
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000271 size_t len = strlen(name);
272 s -= len;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000273 if (s <= buf) {
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000274 fprintf(stderr, "fuse: path too long: ...%s\n", s + len);
275 return NULL;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000276 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000277 strncpy(s, name, len);
278 s--;
279 *s = '/';
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000280
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000281 return s;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000282}
283
Miklos Szeredia181e612001-11-06 12:03:23 +0000284static char *get_path_name(struct fuse *f, fino_t ino, const char *name)
Miklos Szeredib483c932001-10-29 14:57:57 +0000285{
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000286 char buf[FUSE_MAX_PATH];
287 char *s = buf + FUSE_MAX_PATH - 1;
288 struct node *node;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000289
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000290 *s = '\0';
Miklos Szeredia181e612001-11-06 12:03:23 +0000291
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000292 if (name != NULL) {
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000293 s = add_name(buf, s, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000294 if (s == NULL)
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000295 return NULL;
296 }
297
298 pthread_mutex_lock(&f->lock);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000299 for (node = get_node(f, ino); node->ino != FUSE_ROOT_INO;
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000300 node = get_node(f, node->parent)) {
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000301 if (node->name == NULL) {
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000302 s = NULL;
303 break;
304 }
305
306 s = add_name(buf, s, node->name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000307 if (s == NULL)
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000308 break;
309 }
310 pthread_mutex_unlock(&f->lock);
311
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000312 if (s == NULL)
Miklos Szeredi5e183482001-10-31 14:52:35 +0000313 return NULL;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000314 else if (*s == '\0')
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000315 return strdup("/");
316 else
317 return strdup(s);
318}
Miklos Szeredia181e612001-11-06 12:03:23 +0000319
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000320static char *get_path(struct fuse *f, fino_t ino)
321{
322 return get_path_name(f, ino, NULL);
Miklos Szeredib483c932001-10-29 14:57:57 +0000323}
324
Miklos Szeredia181e612001-11-06 12:03:23 +0000325static void destroy_node(struct fuse *f, fino_t ino, int version)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000326{
Miklos Szeredia181e612001-11-06 12:03:23 +0000327 struct node *node;
328
329 pthread_mutex_lock(&f->lock);
Miklos Szeredi8b2d3332004-09-09 08:44:01 +0000330 node = __get_node(f, ino);
331 if (node && node->version == version && ino != FUSE_ROOT_INO) {
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000332 unhash_name(f, node);
333 unhash_ino(f, node);
Miklos Szeredia181e612001-11-06 12:03:23 +0000334 free_node(node);
335 }
336 pthread_mutex_unlock(&f->lock);
337
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000338}
339
Miklos Szeredi5e183482001-10-31 14:52:35 +0000340static void remove_node(struct fuse *f, fino_t dir, const char *name)
341{
Miklos Szeredia181e612001-11-06 12:03:23 +0000342 struct node *node;
343
344 pthread_mutex_lock(&f->lock);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000345 node = __lookup_node(f, dir, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000346 if (node == NULL) {
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000347 fprintf(stderr, "fuse internal error: unable to remove node %lu/%s\n",
348 dir, name);
349 abort();
350 }
351 unhash_name(f, node);
Miklos Szeredia181e612001-11-06 12:03:23 +0000352 pthread_mutex_unlock(&f->lock);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000353}
354
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000355static int rename_node(struct fuse *f, fino_t olddir, const char *oldname,
356 fino_t newdir, const char *newname, int hide)
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000357{
Miklos Szeredia181e612001-11-06 12:03:23 +0000358 struct node *node;
359 struct node *newnode;
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000360 int err = 0;
Miklos Szeredia181e612001-11-06 12:03:23 +0000361
362 pthread_mutex_lock(&f->lock);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000363 node = __lookup_node(f, olddir, oldname);
364 newnode = __lookup_node(f, newdir, newname);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000365 if (node == NULL) {
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000366 fprintf(stderr, "fuse internal error: unable to rename node %lu/%s\n",
367 olddir, oldname);
368 abort();
369 }
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000370
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000371 if (newnode != NULL) {
372 if (hide) {
373 fprintf(stderr, "fuse: hidden file got created during hiding\n");
Miklos Szeredib2cf9562004-09-16 08:42:40 +0000374 err = -EBUSY;
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000375 goto out;
376 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000377 unhash_name(f, newnode);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000378 }
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000379
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000380 unhash_name(f, node);
Miklos Szeredib2cf9562004-09-16 08:42:40 +0000381 if (hash_name(f, node, newdir, newname) == -1) {
382 err = -ENOMEM;
383 goto out;
384 }
385
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000386 if (hide)
387 node->is_hidden = 1;
388
389 out:
Miklos Szeredia181e612001-11-06 12:03:23 +0000390 pthread_mutex_unlock(&f->lock);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000391 return err;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000392}
393
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000394static void convert_stat(struct stat *stbuf, struct fuse_attr *attr)
395{
Miklos Szeredib5958612004-02-20 14:10:49 +0000396 attr->mode = stbuf->st_mode;
397 attr->nlink = stbuf->st_nlink;
398 attr->uid = stbuf->st_uid;
399 attr->gid = stbuf->st_gid;
400 attr->rdev = stbuf->st_rdev;
401 attr->size = stbuf->st_size;
402 attr->blocks = stbuf->st_blocks;
403 attr->atime = stbuf->st_atime;
Miklos Szeredib5958612004-02-20 14:10:49 +0000404 attr->mtime = stbuf->st_mtime;
Miklos Szeredib5958612004-02-20 14:10:49 +0000405 attr->ctime = stbuf->st_ctime;
Miklos Szeredicb264512004-06-23 18:52:50 +0000406#ifdef HAVE_STRUCT_STAT_ST_ATIM
407 attr->atimensec = stbuf->st_atim.tv_nsec;
408 attr->mtimensec = stbuf->st_mtim.tv_nsec;
Miklos Szeredib5958612004-02-20 14:10:49 +0000409 attr->ctimensec = stbuf->st_ctim.tv_nsec;
Miklos Szeredicb264512004-06-23 18:52:50 +0000410#endif
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000411}
412
Miklos Szeredia181e612001-11-06 12:03:23 +0000413static int fill_dir(struct fuse_dirhandle *dh, char *name, int type)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000414{
415 struct fuse_dirent dirent;
416 size_t reclen;
417 size_t res;
418
Miklos Szeredi43696432001-11-18 19:15:05 +0000419 dirent.ino = (unsigned long) -1;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000420 dirent.namelen = strlen(name);
421 strncpy(dirent.name, name, sizeof(dirent.name));
422 dirent.type = type;
423 reclen = FUSE_DIRENT_SIZE(&dirent);
424 res = fwrite(&dirent, reclen, 1, dh->fp);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000425 if (res == 0) {
Miklos Szeredi96249982001-11-21 12:21:19 +0000426 perror("fuse: writing directory file");
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000427 return -EIO;
428 }
429 return 0;
430}
431
Miklos Szeredi73798f92004-07-12 15:55:11 +0000432static int send_reply_raw(struct fuse *f, char *outbuf, size_t outsize,
433 int locked)
Miklos Szeredi43696432001-11-18 19:15:05 +0000434{
435 int res;
436
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000437 if ((f->flags & FUSE_DEBUG)) {
Miklos Szeredi43696432001-11-18 19:15:05 +0000438 struct fuse_out_header *out = (struct fuse_out_header *) outbuf;
439 printf(" unique: %i, error: %i (%s), outsize: %i\n", out->unique,
440 out->error, strerror(-out->error), outsize);
441 fflush(stdout);
442 }
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +0000443
Miklos Szeredi4e71c9f2004-02-09 12:05:14 +0000444 /* This needs to be done before the reply, otherwise the scheduler
445 could play tricks with us, and only let the counter be increased
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +0000446 long after the operation is done */
Miklos Szeredi73798f92004-07-12 15:55:11 +0000447 if (!locked)
448 pthread_mutex_lock(&f->lock);
449 f->numavail ++;
450 if (!locked)
451 pthread_mutex_unlock(&f->lock);
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +0000452
Miklos Szeredi43696432001-11-18 19:15:05 +0000453 res = write(f->fd, outbuf, outsize);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000454 if (res == -1) {
Miklos Szeredi43696432001-11-18 19:15:05 +0000455 /* ENOENT means the operation was interrupted */
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000456 if (!f->exited && errno != ENOENT)
Miklos Szeredi96249982001-11-21 12:21:19 +0000457 perror("fuse: writing device");
Miklos Szeredi40b9a5a2002-12-10 16:09:02 +0000458 return -errno;
Miklos Szeredi43696432001-11-18 19:15:05 +0000459 }
Miklos Szeredi40b9a5a2002-12-10 16:09:02 +0000460 return 0;
Miklos Szeredi43696432001-11-18 19:15:05 +0000461}
462
Miklos Szeredi73798f92004-07-12 15:55:11 +0000463static int __send_reply(struct fuse *f, struct fuse_in_header *in, int error,
464 void *arg, size_t argsize, int locked)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000465{
Miklos Szeredi40b9a5a2002-12-10 16:09:02 +0000466 int res;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000467 char *outbuf;
468 size_t outsize;
469 struct fuse_out_header *out;
470
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000471 if (error <= -1000 || error > 0) {
Miklos Szeredi0f48a262002-12-05 14:23:01 +0000472 fprintf(stderr, "fuse: bad error value: %i\n", error);
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000473 error = -ERANGE;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000474 }
475
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000476 if (error)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000477 argsize = 0;
478
479 outsize = sizeof(struct fuse_out_header) + argsize;
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000480 outbuf = (char *) malloc(outsize);
Miklos Szeredib2cf9562004-09-16 08:42:40 +0000481 if (outbuf == NULL) {
482 fprintf(stderr, "fuse: failed to allocate reply buffer\n");
483 res = -ENOMEM;
484 } else {
485 out = (struct fuse_out_header *) outbuf;
486 memset(out, 0, sizeof(struct fuse_out_header));
487 out->unique = in->unique;
488 out->error = error;
489 if (argsize != 0)
490 memcpy(outbuf + sizeof(struct fuse_out_header), arg, argsize);
491
492 res = send_reply_raw(f, outbuf, outsize, locked);
493 free(outbuf);
494 }
Miklos Szeredi40b9a5a2002-12-10 16:09:02 +0000495
496 return res;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000497}
498
Miklos Szeredi73798f92004-07-12 15:55:11 +0000499static int send_reply(struct fuse *f, struct fuse_in_header *in, int error,
500 void *arg, size_t argsize)
501{
502 return __send_reply(f, in, error, arg, argsize, 0);
503}
504
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000505static int is_open(struct fuse *f, fino_t dir, const char *name)
506{
507 struct node *node;
508 int isopen = 0;
509 pthread_mutex_lock(&f->lock);
510 node = __lookup_node(f, dir, name);
511 if (node && node->open_count > 0)
512 isopen = 1;
513 pthread_mutex_unlock(&f->lock);
514 return isopen;
515}
516
517static char *hidden_name(struct fuse *f, fino_t dir, const char *oldname,
518 char *newname, size_t bufsize)
519{
520 struct stat buf;
521 struct node *node;
522 struct node *newnode;
523 char *newpath;
524 int res;
525 int failctr = 10;
526
527 if (!f->op.getattr)
528 return NULL;
529
530 do {
531 node = lookup_node(f, dir, oldname);
532 pthread_mutex_lock(&f->lock);
533 do {
534 f->hidectr ++;
535 snprintf(newname, bufsize, ".fuse_hidden%08x%08x",
536 (unsigned int) node->ino, f->hidectr);
537 newnode = __lookup_node(f, dir, newname);
538 } while(newnode);
539 pthread_mutex_unlock(&f->lock);
540
541 newpath = get_path_name(f, dir, newname);
542 if (!newpath)
543 break;
544
545 res = f->op.getattr(newpath, &buf);
546 if (res != 0)
547 break;
548 free(newpath);
549 newpath = NULL;
550 } while(--failctr);
551
552 return newpath;
553}
554
555static int hide_node(struct fuse *f, const char *oldpath, fino_t dir,
556 const char *oldname)
557{
558 char newname[64];
559 char *newpath;
Miklos Szeredib2cf9562004-09-16 08:42:40 +0000560 int err = -EBUSY;
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000561
Miklos Szeredib2cf9562004-09-16 08:42:40 +0000562 if (f->op.rename && f->op.unlink) {
563 newpath = hidden_name(f, dir, oldname, newname, sizeof(newname));
564 if (newpath) {
565 int res = f->op.rename(oldpath, newpath);
566 if (res == 0)
567 err = rename_node(f, dir, oldname, dir, newname, 1);
568 free(newpath);
569 }
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000570 }
Miklos Szeredib2cf9562004-09-16 08:42:40 +0000571 return err;
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000572}
573
Miklos Szeredi76f65782004-02-19 16:55:40 +0000574static int lookup_path(struct fuse *f, fino_t ino, int version, char *name,
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000575 const char *path, struct fuse_entry_out *arg)
Miklos Szeredi76f65782004-02-19 16:55:40 +0000576{
577 int res;
578 struct stat buf;
579
580 res = f->op.getattr(path, &buf);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000581 if (res == 0) {
Miklos Szeredi76f65782004-02-19 16:55:40 +0000582 struct node *node;
583
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000584 memset(arg, 0, sizeof(struct fuse_entry_out));
Miklos Szeredi76f65782004-02-19 16:55:40 +0000585 convert_stat(&buf, &arg->attr);
586 node = find_node(f, ino, name, &arg->attr, version);
Miklos Szeredib2cf9562004-09-16 08:42:40 +0000587 if (node == NULL)
588 res = -ENOMEM;
589 else {
590 arg->ino = node->ino;
591 arg->generation = node->generation;
592 arg->entry_valid = ENTRY_REVALIDATE_TIME;
593 arg->entry_valid_nsec = 0;
594 arg->attr_valid = ATTR_REVALIDATE_TIME;
595 arg->attr_valid_nsec = 0;
596 if (f->flags & FUSE_DEBUG) {
597 printf(" INO: %li\n", arg->ino);
598 fflush(stdout);
599 }
Miklos Szeredi76f65782004-02-19 16:55:40 +0000600 }
601 }
602 return res;
603}
604
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000605static void do_lookup(struct fuse *f, struct fuse_in_header *in, char *name)
606{
607 int res;
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000608 int res2;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000609 char *path;
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000610 struct fuse_entry_out arg;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000611
Miklos Szeredi5e183482001-10-31 14:52:35 +0000612 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000613 path = get_path_name(f, in->ino, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000614 if (path != NULL) {
615 if (f->flags & FUSE_DEBUG) {
Miklos Szeredi6ebe2342002-01-06 21:44:16 +0000616 printf("LOOKUP %s\n", path);
617 fflush(stdout);
618 }
Miklos Szeredi5e183482001-10-31 14:52:35 +0000619 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000620 if (f->op.getattr)
Miklos Szeredi76f65782004-02-19 16:55:40 +0000621 res = lookup_path(f, in->ino, in->unique, name, path, &arg);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000622 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000623 }
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000624 res2 = send_reply(f, in, res, &arg, sizeof(arg));
625 if (res == 0 && res2 == -ENOENT)
626 destroy_node(f, arg.ino, in->unique);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000627}
628
Miklos Szeredia181e612001-11-06 12:03:23 +0000629static void do_forget(struct fuse *f, struct fuse_in_header *in,
630 struct fuse_forget_in *arg)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000631{
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000632 if (f->flags & FUSE_DEBUG) {
Miklos Szeredi43696432001-11-18 19:15:05 +0000633 printf("FORGET %li/%i\n", in->ino, arg->version);
634 fflush(stdout);
635 }
Miklos Szeredia181e612001-11-06 12:03:23 +0000636 destroy_node(f, in->ino, arg->version);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000637}
638
639static void do_getattr(struct fuse *f, struct fuse_in_header *in)
640{
641 int res;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000642 char *path;
643 struct stat buf;
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000644 struct fuse_attr_out arg;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000645
Miklos Szeredi5e183482001-10-31 14:52:35 +0000646 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000647 path = get_path(f, in->ino);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000648 if (path != NULL) {
Miklos Szeredi5e183482001-10-31 14:52:35 +0000649 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000650 if (f->op.getattr)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000651 res = f->op.getattr(path, &buf);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000652 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000653 }
Miklos Szeredi0f48a262002-12-05 14:23:01 +0000654
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000655 if (res == 0) {
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000656 memset(&arg, 0, sizeof(struct fuse_attr_out));
657 arg.attr_valid = ATTR_REVALIDATE_TIME;
658 arg.attr_valid_nsec = 0;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000659 convert_stat(&buf, &arg.attr);
Miklos Szeredi0f48a262002-12-05 14:23:01 +0000660 }
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000661
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000662 send_reply(f, in, res, &arg, sizeof(arg));
663}
664
Miklos Szeredi680a69a2001-11-16 13:31:14 +0000665static int do_chmod(struct fuse *f, const char *path, struct fuse_attr *attr)
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000666{
667 int res;
668
669 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000670 if (f->op.chmod)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000671 res = f->op.chmod(path, attr->mode);
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000672
673 return res;
674}
675
Miklos Szeredi680a69a2001-11-16 13:31:14 +0000676static int do_chown(struct fuse *f, const char *path, struct fuse_attr *attr,
Miklos Szeredi2e50d432001-12-20 12:17:25 +0000677 int valid)
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000678{
679 int res;
680 uid_t uid = (valid & FATTR_UID) ? attr->uid : (uid_t) -1;
681 gid_t gid = (valid & FATTR_GID) ? attr->gid : (gid_t) -1;
682
683 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000684 if (f->op.chown)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000685 res = f->op.chown(path, uid, gid);
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000686
687 return res;
688}
689
Miklos Szeredi680a69a2001-11-16 13:31:14 +0000690static int do_truncate(struct fuse *f, const char *path,
691 struct fuse_attr *attr)
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000692{
693 int res;
694
695 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000696 if (f->op.truncate)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000697 res = f->op.truncate(path, attr->size);
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000698
699 return res;
700}
701
Miklos Szeredi680a69a2001-11-16 13:31:14 +0000702static int do_utime(struct fuse *f, const char *path, struct fuse_attr *attr)
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000703{
704 int res;
705 struct utimbuf buf;
706 buf.actime = attr->atime;
707 buf.modtime = attr->mtime;
708 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000709 if (f->op.utime)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000710 res = f->op.utime(path, &buf);
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000711
712 return res;
713}
714
Miklos Szeredi5e183482001-10-31 14:52:35 +0000715static void do_setattr(struct fuse *f, struct fuse_in_header *in,
716 struct fuse_setattr_in *arg)
717{
718 int res;
719 char *path;
720 int valid = arg->valid;
721 struct fuse_attr *attr = &arg->attr;
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000722 struct fuse_attr_out outarg;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000723
724 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000725 path = get_path(f, in->ino);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000726 if (path != NULL) {
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000727 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000728 if (f->op.getattr) {
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000729 res = 0;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000730 if (!res && (valid & FATTR_MODE))
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000731 res = do_chmod(f, path, attr);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000732 if (!res && (valid & (FATTR_UID | FATTR_GID)))
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000733 res = do_chown(f, path, attr, valid);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000734 if (!res && (valid & FATTR_SIZE))
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000735 res = do_truncate(f, path, attr);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000736 if (!res && (valid & (FATTR_ATIME | FATTR_MTIME)) ==
Miklos Szeredib5958612004-02-20 14:10:49 +0000737 (FATTR_ATIME | FATTR_MTIME))
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000738 res = do_utime(f, path, attr);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000739 if (!res) {
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000740 struct stat buf;
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000741 res = f->op.getattr(path, &buf);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000742 if (!res) {
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000743 memset(&outarg, 0, sizeof(struct fuse_attr_out));
744 outarg.attr_valid = ATTR_REVALIDATE_TIME;
745 outarg.attr_valid_nsec = 0;
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000746 convert_stat(&buf, &outarg.attr);
Miklos Szeredi0f48a262002-12-05 14:23:01 +0000747 }
Miklos Szeredia181e612001-11-06 12:03:23 +0000748 }
Miklos Szeredi5e183482001-10-31 14:52:35 +0000749 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000750 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000751 }
Miklos Szeredia181e612001-11-06 12:03:23 +0000752 send_reply(f, in, res, &outarg, sizeof(outarg));
Miklos Szeredi5e183482001-10-31 14:52:35 +0000753}
754
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000755static void do_readlink(struct fuse *f, struct fuse_in_header *in)
756{
757 int res;
758 char link[PATH_MAX + 1];
Miklos Szeredib483c932001-10-29 14:57:57 +0000759 char *path;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000760
Miklos Szeredi5e183482001-10-31 14:52:35 +0000761 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000762 path = get_path(f, in->ino);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000763 if (path != NULL) {
Miklos Szeredi5e183482001-10-31 14:52:35 +0000764 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000765 if (f->op.readlink)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000766 res = f->op.readlink(path, link, sizeof(link));
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000767 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000768 }
Miklos Szeredi2df1c042001-11-06 15:07:17 +0000769 link[PATH_MAX] = '\0';
Miklos Szeredi4b2bef42002-01-09 12:23:27 +0000770 send_reply(f, in, res, link, res == 0 ? strlen(link) : 0);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000771}
772
773static void do_getdir(struct fuse *f, struct fuse_in_header *in)
774{
775 int res;
776 struct fuse_getdir_out arg;
Miklos Szeredia181e612001-11-06 12:03:23 +0000777 struct fuse_dirhandle dh;
Miklos Szeredib483c932001-10-29 14:57:57 +0000778 char *path;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000779
Miklos Szeredib483c932001-10-29 14:57:57 +0000780 dh.fuse = f;
781 dh.fp = tmpfile();
782 dh.dir = in->ino;
Miklos Szeredi0f48a262002-12-05 14:23:01 +0000783
Miklos Szeredi65afea12004-09-14 07:13:45 +0000784 res = -EIO;
785 if (dh.fp == NULL)
786 perror("fuse: failed to create temporary file");
787 else {
788 res = -ENOENT;
789 path = get_path(f, in->ino);
790 if (path != NULL) {
791 res = -ENOSYS;
792 if (f->op.getdir)
793 res = f->op.getdir(path, &dh, (fuse_dirfil_t) fill_dir);
794 free(path);
795 }
796 fflush(dh.fp);
797 }
Miklos Szeredi0f48a262002-12-05 14:23:01 +0000798 memset(&arg, 0, sizeof(struct fuse_getdir_out));
Miklos Szeredi65afea12004-09-14 07:13:45 +0000799 if (res == 0)
800 arg.fd = fileno(dh.fp);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000801 send_reply(f, in, res, &arg, sizeof(arg));
Miklos Szeredi65afea12004-09-14 07:13:45 +0000802 if (dh.fp != NULL)
803 fclose(dh.fp);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000804}
805
Miklos Szeredib483c932001-10-29 14:57:57 +0000806static void do_mknod(struct fuse *f, struct fuse_in_header *in,
807 struct fuse_mknod_in *inarg)
808{
809 int res;
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000810 int res2;
Miklos Szeredib483c932001-10-29 14:57:57 +0000811 char *path;
Miklos Szeredi76f65782004-02-19 16:55:40 +0000812 char *name = PARAM(inarg);
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000813 struct fuse_entry_out outarg;
Miklos Szeredib483c932001-10-29 14:57:57 +0000814
Miklos Szeredi5e183482001-10-31 14:52:35 +0000815 res = -ENOENT;
Miklos Szeredi76f65782004-02-19 16:55:40 +0000816 path = get_path_name(f, in->ino, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000817 if (path != NULL) {
818 if (f->flags & FUSE_DEBUG) {
Miklos Szeredi76f65782004-02-19 16:55:40 +0000819 printf("MKNOD %s\n", path);
820 fflush(stdout);
821 }
Miklos Szeredi5e183482001-10-31 14:52:35 +0000822 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000823 if (f->op.mknod && f->op.getattr) {
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000824 res = f->op.mknod(path, inarg->mode, inarg->rdev);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000825 if (res == 0)
Miklos Szeredi76f65782004-02-19 16:55:40 +0000826 res = lookup_path(f, in->ino, in->unique, name, path, &outarg);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000827 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000828 free(path);
Miklos Szeredib483c932001-10-29 14:57:57 +0000829 }
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000830 res2 = send_reply(f, in, res, &outarg, sizeof(outarg));
831 if (res == 0 && res2 == -ENOENT)
832 destroy_node(f, outarg.ino, in->unique);
Miklos Szeredib483c932001-10-29 14:57:57 +0000833}
834
835static void do_mkdir(struct fuse *f, struct fuse_in_header *in,
836 struct fuse_mkdir_in *inarg)
837{
838 int res;
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000839 int res2;
Miklos Szeredib483c932001-10-29 14:57:57 +0000840 char *path;
Miklos Szeredi76f65782004-02-19 16:55:40 +0000841 char *name = PARAM(inarg);
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000842 struct fuse_entry_out outarg;
Miklos Szeredib483c932001-10-29 14:57:57 +0000843
Miklos Szeredi5e183482001-10-31 14:52:35 +0000844 res = -ENOENT;
Miklos Szeredi76f65782004-02-19 16:55:40 +0000845 path = get_path_name(f, in->ino, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000846 if (path != NULL) {
847 if (f->flags & FUSE_DEBUG) {
Miklos Szeredi76f65782004-02-19 16:55:40 +0000848 printf("MKDIR %s\n", path);
849 fflush(stdout);
850 }
Miklos Szeredi5e183482001-10-31 14:52:35 +0000851 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000852 if (f->op.mkdir && f->op.getattr) {
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000853 res = f->op.mkdir(path, inarg->mode);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000854 if (res == 0)
Miklos Szeredi76f65782004-02-19 16:55:40 +0000855 res = lookup_path(f, in->ino, in->unique, name, path, &outarg);
856 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000857 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000858 }
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000859 res2 = send_reply(f, in, res, &outarg, sizeof(outarg));
860 if (res == 0 && res2 == -ENOENT)
861 destroy_node(f, outarg.ino, in->unique);
Miklos Szeredib483c932001-10-29 14:57:57 +0000862}
863
Miklos Szeredib5958612004-02-20 14:10:49 +0000864static void do_unlink(struct fuse *f, struct fuse_in_header *in, char *name)
Miklos Szeredib483c932001-10-29 14:57:57 +0000865{
866 int res;
867 char *path;
868
Miklos Szeredi5e183482001-10-31 14:52:35 +0000869 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000870 path = get_path_name(f, in->ino, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000871 if (path != NULL) {
Miklos Szeredi209f5d02004-07-24 19:56:16 +0000872 if (f->flags & FUSE_DEBUG) {
873 printf("UNLINK %s\n", path);
874 fflush(stdout);
875 }
Miklos Szeredi5e183482001-10-31 14:52:35 +0000876 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000877 if (f->op.unlink) {
Miklos Szeredi2529ca22004-07-13 15:36:52 +0000878 if (!(f->flags & FUSE_HARD_REMOVE) && is_open(f, in->ino, name))
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000879 res = hide_node(f, path, in->ino, name);
880 else {
881 res = f->op.unlink(path);
882 if (res == 0)
883 remove_node(f, in->ino, name);
884 }
Miklos Szeredi5e183482001-10-31 14:52:35 +0000885 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000886 free(path);
Miklos Szeredib483c932001-10-29 14:57:57 +0000887 }
Miklos Szeredib5958612004-02-20 14:10:49 +0000888 send_reply(f, in, res, NULL, 0);
889}
890
891static void do_rmdir(struct fuse *f, struct fuse_in_header *in, char *name)
892{
893 int res;
894 char *path;
895
896 res = -ENOENT;
897 path = get_path_name(f, in->ino, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000898 if (path != NULL) {
Miklos Szeredi209f5d02004-07-24 19:56:16 +0000899 if (f->flags & FUSE_DEBUG) {
900 printf("RMDIR %s\n", path);
901 fflush(stdout);
902 }
Miklos Szeredib5958612004-02-20 14:10:49 +0000903 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000904 if (f->op.rmdir) {
Miklos Szeredib5958612004-02-20 14:10:49 +0000905 res = f->op.rmdir(path);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000906 if (res == 0)
Miklos Szeredib5958612004-02-20 14:10:49 +0000907 remove_node(f, in->ino, name);
908 }
909 free(path);
910 }
Miklos Szeredib483c932001-10-29 14:57:57 +0000911 send_reply(f, in, res, NULL, 0);
912}
913
914static void do_symlink(struct fuse *f, struct fuse_in_header *in, char *name,
915 char *link)
916{
917 int res;
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000918 int res2;
Miklos Szeredib483c932001-10-29 14:57:57 +0000919 char *path;
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000920 struct fuse_entry_out outarg;
Miklos Szeredib483c932001-10-29 14:57:57 +0000921
Miklos Szeredi5e183482001-10-31 14:52:35 +0000922 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000923 path = get_path_name(f, in->ino, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000924 if (path != NULL) {
925 if (f->flags & FUSE_DEBUG) {
Miklos Szeredi76f65782004-02-19 16:55:40 +0000926 printf("SYMLINK %s\n", path);
927 fflush(stdout);
928 }
Miklos Szeredi5e183482001-10-31 14:52:35 +0000929 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000930 if (f->op.symlink && f->op.getattr) {
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000931 res = f->op.symlink(link, path);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000932 if (res == 0)
Miklos Szeredi76f65782004-02-19 16:55:40 +0000933 res = lookup_path(f, in->ino, in->unique, name, path, &outarg);
934 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000935 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000936 }
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000937 res2 = send_reply(f, in, res, &outarg, sizeof(outarg));
938 if (res == 0 && res2 == -ENOENT)
939 destroy_node(f, outarg.ino, in->unique);
940
Miklos Szeredib483c932001-10-29 14:57:57 +0000941}
942
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000943static void do_rename(struct fuse *f, struct fuse_in_header *in,
944 struct fuse_rename_in *inarg)
945{
946 int res;
947 fino_t olddir = in->ino;
948 fino_t newdir = inarg->newdir;
Miklos Szeredi6bf8b682002-10-28 08:49:39 +0000949 char *oldname = PARAM(inarg);
950 char *newname = oldname + strlen(oldname) + 1;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000951 char *oldpath;
952 char *newpath;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000953
Miklos Szeredi5e183482001-10-31 14:52:35 +0000954 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000955 oldpath = get_path_name(f, olddir, oldname);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000956 if (oldpath != NULL) {
Miklos Szeredia181e612001-11-06 12:03:23 +0000957 newpath = get_path_name(f, newdir, newname);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000958 if (newpath != NULL) {
Miklos Szeredi209f5d02004-07-24 19:56:16 +0000959 if (f->flags & FUSE_DEBUG) {
960 printf("RENAME %s -> %s\n", oldpath, newpath);
961 fflush(stdout);
962 }
Miklos Szeredi5e183482001-10-31 14:52:35 +0000963 res = -ENOSYS;
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000964 if (f->op.rename) {
965 res = 0;
Miklos Szeredi2529ca22004-07-13 15:36:52 +0000966 if (!(f->flags & FUSE_HARD_REMOVE) &&
967 is_open(f, newdir, newname))
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000968 res = hide_node(f, newpath, newdir, newname);
969 if (res == 0) {
970 res = f->op.rename(oldpath, newpath);
971 if (res == 0)
Miklos Szeredib2cf9562004-09-16 08:42:40 +0000972 res = rename_node(f, olddir, oldname, newdir, newname, 0);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000973 }
974 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000975 free(newpath);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000976 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000977 free(oldpath);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000978 }
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000979 send_reply(f, in, res, NULL, 0);
980}
981
982static void do_link(struct fuse *f, struct fuse_in_header *in,
Miklos Szeredi5e183482001-10-31 14:52:35 +0000983 struct fuse_link_in *arg)
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000984{
985 int res;
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000986 int res2;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000987 char *oldpath;
988 char *newpath;
Miklos Szeredi76f65782004-02-19 16:55:40 +0000989 char *name = PARAM(arg);
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000990 struct fuse_entry_out outarg;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000991
Miklos Szeredi5e183482001-10-31 14:52:35 +0000992 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000993 oldpath = get_path(f, in->ino);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000994 if (oldpath != NULL) {
Miklos Szeredi76f65782004-02-19 16:55:40 +0000995 newpath = get_path_name(f, arg->newdir, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000996 if (newpath != NULL) {
997 if (f->flags & FUSE_DEBUG) {
Miklos Szeredi76f65782004-02-19 16:55:40 +0000998 printf("LINK %s\n", newpath);
999 fflush(stdout);
1000 }
Miklos Szeredi5e183482001-10-31 14:52:35 +00001001 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001002 if (f->op.link && f->op.getattr) {
Miklos Szeredi0a7077f2001-11-11 18:20:17 +00001003 res = f->op.link(oldpath, newpath);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001004 if (res == 0)
Miklos Szeredi76f65782004-02-19 16:55:40 +00001005 res = lookup_path(f, arg->newdir, in->unique, name,
1006 newpath, &outarg);
1007 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001008 free(newpath);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001009 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001010 free(oldpath);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001011 }
Miklos Szeredi2778f6c2004-06-21 09:45:30 +00001012 res2 = send_reply(f, in, res, &outarg, sizeof(outarg));
1013 if (res == 0 && res2 == -ENOENT)
1014 destroy_node(f, outarg.ino, in->unique);
Miklos Szeredi19dff1b2001-10-30 15:06:52 +00001015}
1016
Miklos Szeredi5e183482001-10-31 14:52:35 +00001017static void do_open(struct fuse *f, struct fuse_in_header *in,
1018 struct fuse_open_in *arg)
1019{
1020 int res;
1021 char *path;
Miklos Szeredi209f5d02004-07-24 19:56:16 +00001022 struct fuse_open_out outarg;
Miklos Szeredi5e183482001-10-31 14:52:35 +00001023
1024 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +00001025 path = get_path(f, in->ino);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001026 if (path != NULL) {
Miklos Szeredi5e183482001-10-31 14:52:35 +00001027 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001028 if (f->op.open)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +00001029 res = f->op.open(path, arg->flags);
Miklos Szeredi40b9a5a2002-12-10 16:09:02 +00001030 }
Miklos Szeredi73798f92004-07-12 15:55:11 +00001031 if (res == 0) {
1032 int res2;
1033
1034 /* If the request is interrupted the lock must be held until
1035 the cancellation is finished. Otherwise there could be
1036 races with rename/unlink, against which the kernel can't
1037 protect */
1038 pthread_mutex_lock(&f->lock);
Miklos Szeredi209f5d02004-07-24 19:56:16 +00001039 f->fh_ctr ++;
1040 outarg.fh = f->fh_ctr;
1041 if (f->flags & FUSE_DEBUG) {
1042 printf("OPEN[%u] flags: 0x%x\n", outarg.fh, arg->flags);
1043 fflush(stdout);
1044 }
1045
1046 res2 = __send_reply(f, in, res, &outarg, sizeof(outarg), 1);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001047 if(res2 == -ENOENT) {
1048 /* The open syscall was interrupted, so it must be cancelled */
1049 if(f->op.release)
1050 f->op.release(path, arg->flags);
Miklos Szeredi73798f92004-07-12 15:55:11 +00001051 } else
1052 get_node(f, in->ino)->open_count ++;
1053 pthread_mutex_unlock(&f->lock);
1054
1055 } else
1056 send_reply(f, in, res, NULL, 0);
1057
Miklos Szeredi9a31cca2004-06-26 21:11:25 +00001058 if (path)
1059 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001060}
1061
Miklos Szeredi209f5d02004-07-24 19:56:16 +00001062static void do_flush(struct fuse *f, struct fuse_in_header *in,
1063 struct fuse_flush_in *arg)
Miklos Szeredie2e4ac22004-05-18 08:45:28 +00001064{
1065 char *path;
1066 int res;
1067
1068 res = -ENOENT;
1069 path = get_path(f, in->ino);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001070 if (path != NULL) {
Miklos Szeredi209f5d02004-07-24 19:56:16 +00001071 if (f->flags & FUSE_DEBUG) {
1072 printf("FLUSH[%u]\n", arg->fh);
1073 fflush(stdout);
1074 }
Miklos Szeredie2e4ac22004-05-18 08:45:28 +00001075 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001076 if (f->op.flush)
Miklos Szeredie2e4ac22004-05-18 08:45:28 +00001077 res = f->op.flush(path);
1078 free(path);
1079 }
1080 send_reply(f, in, res, NULL, 0);
1081}
1082
Miklos Szeredi9478e862002-12-11 09:50:26 +00001083static void do_release(struct fuse *f, struct fuse_in_header *in,
Miklos Szeredi209f5d02004-07-24 19:56:16 +00001084 struct fuse_release_in *arg)
Miklos Szeredic8ba2372002-12-10 12:26:00 +00001085{
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001086 struct node *node;
1087 char *path;
Miklos Szeredic8ba2372002-12-10 12:26:00 +00001088
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001089 pthread_mutex_lock(&f->lock);
1090 node = get_node(f, in->ino);
1091 --node->open_count;
1092 pthread_mutex_unlock(&f->lock);
1093
1094 path = get_path(f, in->ino);
1095 if (path != NULL) {
Miklos Szeredi209f5d02004-07-24 19:56:16 +00001096 if (f->flags & FUSE_DEBUG) {
1097 printf("RELEASE[%u]\n", arg->fh);
1098 fflush(stdout);
1099 }
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001100 if (f->op.release)
Miklos Szeredib3210582004-06-23 13:54:33 +00001101 f->op.release(path, arg->flags);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001102
1103 if(node->is_hidden && node->open_count == 0)
1104 /* can now clean up this hidden file */
1105 f->op.unlink(path);
1106
1107 free(path);
Miklos Szeredic8ba2372002-12-10 12:26:00 +00001108 }
Miklos Szeredi556d03d2004-06-30 11:13:41 +00001109 send_reply(f, in, 0, NULL, 0);
Miklos Szeredic8ba2372002-12-10 12:26:00 +00001110}
1111
Miklos Szeredi5e183482001-10-31 14:52:35 +00001112static void do_read(struct fuse *f, struct fuse_in_header *in,
1113 struct fuse_read_in *arg)
1114{
1115 int res;
1116 char *path;
Miklos Szeredi43696432001-11-18 19:15:05 +00001117 char *outbuf = (char *) malloc(sizeof(struct fuse_out_header) + arg->size);
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001118 if (outbuf == NULL)
1119 send_reply(f, in, -ENOMEM, NULL, 0);
1120 else {
1121 struct fuse_out_header *out = (struct fuse_out_header *) outbuf;
1122 char *buf = outbuf + sizeof(struct fuse_out_header);
1123 size_t size;
1124 size_t outsize;
1125
1126 res = -ENOENT;
1127 path = get_path(f, in->ino);
1128 if (path != NULL) {
1129 if (f->flags & FUSE_DEBUG) {
1130 printf("READ[%u] %u bytes from %llu\n", arg->fh, arg->size,
1131 arg->offset);
1132 fflush(stdout);
1133 }
1134
1135 res = -ENOSYS;
1136 if (f->op.read)
1137 res = f->op.read(path, buf, arg->size, arg->offset);
1138 free(path);
Miklos Szeredi6ebe2342002-01-06 21:44:16 +00001139 }
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001140
1141 size = 0;
1142 if (res >= 0) {
1143 size = res;
1144 res = 0;
1145 if (f->flags & FUSE_DEBUG) {
1146 printf(" READ[%u] %u bytes\n", arg->fh, size);
1147 fflush(stdout);
1148 }
Miklos Szeredi6ebe2342002-01-06 21:44:16 +00001149 }
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001150 memset(out, 0, sizeof(struct fuse_out_header));
1151 out->unique = in->unique;
1152 out->error = res;
1153 outsize = sizeof(struct fuse_out_header) + size;
1154
1155 send_reply_raw(f, outbuf, outsize, 0);
1156 free(outbuf);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001157 }
Miklos Szeredi5e183482001-10-31 14:52:35 +00001158}
Miklos Szeredib483c932001-10-29 14:57:57 +00001159
Miklos Szeredia181e612001-11-06 12:03:23 +00001160static void do_write(struct fuse *f, struct fuse_in_header *in,
1161 struct fuse_write_in *arg)
1162{
1163 int res;
1164 char *path;
Miklos Szerediad051c32004-07-02 09:22:50 +00001165 struct fuse_write_out outarg;
Miklos Szeredia181e612001-11-06 12:03:23 +00001166
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001167 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +00001168 path = get_path(f, in->ino);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001169 if (path != NULL) {
1170 if (f->flags & FUSE_DEBUG) {
Miklos Szeredi209f5d02004-07-24 19:56:16 +00001171 printf("WRITE%s[%u] %u bytes to %llu\n",
1172 arg->writepage ? "PAGE" : "", arg->fh, arg->size,
1173 arg->offset);
Miklos Szeredi6ebe2342002-01-06 21:44:16 +00001174 fflush(stdout);
1175 }
1176
Miklos Szeredia181e612001-11-06 12:03:23 +00001177 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001178 if (f->op.write)
Miklos Szeredi6bf8b682002-10-28 08:49:39 +00001179 res = f->op.write(path, PARAM(arg), arg->size, arg->offset);
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001180 free(path);
Miklos Szeredia181e612001-11-06 12:03:23 +00001181 }
1182
Miklos Szerediad051c32004-07-02 09:22:50 +00001183 if (res >= 0) {
1184 outarg.size = res;
1185 res = 0;
Miklos Szeredia181e612001-11-06 12:03:23 +00001186 }
1187
Miklos Szerediad051c32004-07-02 09:22:50 +00001188 send_reply(f, in, res, &outarg, sizeof(outarg));
Miklos Szeredia181e612001-11-06 12:03:23 +00001189}
1190
Miklos Szeredi77f39942004-03-25 11:17:52 +00001191static int default_statfs(struct statfs *buf)
1192{
1193 buf->f_namelen = 255;
1194 buf->f_bsize = 512;
1195 return 0;
1196}
1197
Miklos Szeredi18e75e42004-02-19 14:23:27 +00001198static void convert_statfs(struct statfs *statfs, struct fuse_kstatfs *kstatfs)
1199{
1200 kstatfs->bsize = statfs->f_bsize;
1201 kstatfs->blocks = statfs->f_blocks;
1202 kstatfs->bfree = statfs->f_bfree;
1203 kstatfs->bavail = statfs->f_bavail;
1204 kstatfs->files = statfs->f_files;
1205 kstatfs->ffree = statfs->f_ffree;
1206 kstatfs->namelen = statfs->f_namelen;
1207}
1208
Mark Glinesd84b39a2002-01-07 16:32:02 +00001209static void do_statfs(struct fuse *f, struct fuse_in_header *in)
1210{
1211 int res;
Mark Glinesd84b39a2002-01-07 16:32:02 +00001212 struct fuse_statfs_out arg;
Miklos Szeredi18e75e42004-02-19 14:23:27 +00001213 struct statfs buf;
Mark Glinesd84b39a2002-01-07 16:32:02 +00001214
Miklos Szeredi77f39942004-03-25 11:17:52 +00001215 memset(&buf, 0, sizeof(struct statfs));
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001216 if (f->op.statfs)
Miklos Szeredi18e75e42004-02-19 14:23:27 +00001217 res = f->op.statfs("/", &buf);
Miklos Szeredi77f39942004-03-25 11:17:52 +00001218 else
1219 res = default_statfs(&buf);
1220
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001221 if (res == 0)
Miklos Szeredi77f39942004-03-25 11:17:52 +00001222 convert_statfs(&buf, &arg.st);
Miklos Szeredi4b2bef42002-01-09 12:23:27 +00001223
Mark Glinesd84b39a2002-01-07 16:32:02 +00001224 send_reply(f, in, res, &arg, sizeof(arg));
1225}
1226
Miklos Szeredi5e43f2c2003-12-12 14:06:41 +00001227static void do_fsync(struct fuse *f, struct fuse_in_header *in,
1228 struct fuse_fsync_in *inarg)
1229{
1230 int res;
1231 char *path;
1232
1233 res = -ENOENT;
1234 path = get_path(f, in->ino);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001235 if (path != NULL) {
Miklos Szeredi209f5d02004-07-24 19:56:16 +00001236 if (f->flags & FUSE_DEBUG) {
1237 printf("FSYNC[%u]\n", inarg->fh);
1238 fflush(stdout);
1239 }
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001240 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001241 if (f->op.fsync)
Miklos Szeredi5e43f2c2003-12-12 14:06:41 +00001242 res = f->op.fsync(path, inarg->datasync);
1243 free(path);
1244 }
1245 send_reply(f, in, res, NULL, 0);
1246}
1247
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001248static void do_setxattr(struct fuse *f, struct fuse_in_header *in,
1249 struct fuse_setxattr_in *arg)
1250{
1251 int res;
1252 char *path;
1253 char *name = PARAM(arg);
1254 unsigned char *value = name + strlen(name) + 1;
1255
1256 res = -ENOENT;
1257 path = get_path(f, in->ino);
1258 if (path != NULL) {
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001259 res = -ENOSYS;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001260 if (f->op.setxattr)
1261 res = f->op.setxattr(path, name, value, arg->size, arg->flags);
1262 free(path);
1263 }
1264 send_reply(f, in, res, NULL, 0);
1265}
1266
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001267static int common_getxattr(struct fuse *f, struct fuse_in_header *in,
1268 const char *name, char *value, size_t size)
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001269{
1270 int res;
1271 char *path;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001272
1273 res = -ENOENT;
1274 path = get_path(f, in->ino);
1275 if (path != NULL) {
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001276 res = -ENOSYS;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001277 if (f->op.getxattr)
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001278 res = f->op.getxattr(path, name, value, size);
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001279 free(path);
1280 }
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001281 return res;
1282}
1283
1284static void do_getxattr_read(struct fuse *f, struct fuse_in_header *in,
1285 const char *name, size_t size)
1286{
1287 int res;
1288 char *outbuf = (char *) malloc(sizeof(struct fuse_out_header) + size);
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001289 if (outbuf == NULL)
1290 send_reply(f, in, -ENOMEM, NULL, 0);
1291 else {
1292 struct fuse_out_header *out = (struct fuse_out_header *) outbuf;
1293 char *value = outbuf + sizeof(struct fuse_out_header);
1294
1295 res = common_getxattr(f, in, name, value, size);
1296 size = 0;
1297 if (res > 0) {
1298 size = res;
1299 res = 0;
1300 }
1301 memset(out, 0, sizeof(struct fuse_out_header));
1302 out->unique = in->unique;
1303 out->error = res;
1304
1305 send_reply_raw(f, outbuf, sizeof(struct fuse_out_header) + size, 0);
1306 free(outbuf);
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001307 }
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001308}
1309
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001310static void do_getxattr_size(struct fuse *f, struct fuse_in_header *in,
1311 const char *name)
1312{
1313 int res;
1314 struct fuse_getxattr_out arg;
1315
1316 res = common_getxattr(f, in, name, NULL, 0);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001317 if (res >= 0) {
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001318 arg.size = res;
1319 res = 0;
1320 }
1321 send_reply(f, in, res, &arg, sizeof(arg));
1322}
1323
1324static void do_getxattr(struct fuse *f, struct fuse_in_header *in,
1325 struct fuse_getxattr_in *arg)
1326{
1327 char *name = PARAM(arg);
1328
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001329 if (arg->size)
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001330 do_getxattr_read(f, in, name, arg->size);
1331 else
1332 do_getxattr_size(f, in, name);
1333}
1334
1335static int common_listxattr(struct fuse *f, struct fuse_in_header *in,
1336 char *list, size_t size)
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001337{
1338 int res;
1339 char *path;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001340
1341 res = -ENOENT;
1342 path = get_path(f, in->ino);
1343 if (path != NULL) {
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001344 res = -ENOSYS;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001345 if (f->op.listxattr)
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001346 res = f->op.listxattr(path, list, size);
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001347 free(path);
1348 }
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001349 return res;
1350}
1351
1352static void do_listxattr_read(struct fuse *f, struct fuse_in_header *in,
1353 size_t size)
1354{
1355 int res;
1356 char *outbuf = (char *) malloc(sizeof(struct fuse_out_header) + size);
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001357 if (outbuf == NULL)
1358 send_reply(f, in, -ENOMEM, NULL, 0);
1359 else {
1360 struct fuse_out_header *out = (struct fuse_out_header *) outbuf;
1361 char *list = outbuf + sizeof(struct fuse_out_header);
1362
1363 res = common_listxattr(f, in, list, size);
1364 size = 0;
1365 if (res > 0) {
1366 size = res;
1367 res = 0;
1368 }
1369 memset(out, 0, sizeof(struct fuse_out_header));
1370 out->unique = in->unique;
1371 out->error = res;
1372
1373 send_reply_raw(f, outbuf, sizeof(struct fuse_out_header) + size, 0);
1374 free(outbuf);
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001375 }
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001376}
1377
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001378static void do_listxattr_size(struct fuse *f, struct fuse_in_header *in)
1379{
1380 int res;
1381 struct fuse_getxattr_out arg;
1382
1383 res = common_listxattr(f, in, NULL, 0);
1384 if (res >= 0) {
1385 arg.size = res;
1386 res = 0;
1387 }
1388 send_reply(f, in, res, &arg, sizeof(arg));
1389}
1390
1391static void do_listxattr(struct fuse *f, struct fuse_in_header *in,
1392 struct fuse_getxattr_in *arg)
1393{
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001394 if (arg->size)
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001395 do_listxattr_read(f, in, arg->size);
1396 else
1397 do_listxattr_size(f, in);
1398}
1399
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001400static void do_removexattr(struct fuse *f, struct fuse_in_header *in,
1401 char *name)
1402{
1403 int res;
1404 char *path;
1405
1406 res = -ENOENT;
1407 path = get_path(f, in->ino);
1408 if (path != NULL) {
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001409 res = -ENOSYS;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001410 if (f->op.removexattr)
1411 res = f->op.removexattr(path, name);
1412 free(path);
1413 }
1414 send_reply(f, in, res, NULL, 0);
1415}
1416
1417
Miklos Szeredi43696432001-11-18 19:15:05 +00001418static void free_cmd(struct fuse_cmd *cmd)
1419{
1420 free(cmd->buf);
1421 free(cmd);
1422}
1423
Miklos Szeredifff56ab2001-11-16 10:12:59 +00001424void __fuse_process_cmd(struct fuse *f, struct fuse_cmd *cmd)
Miklos Szeredia181e612001-11-06 12:03:23 +00001425{
Miklos Szeredia181e612001-11-06 12:03:23 +00001426 struct fuse_in_header *in = (struct fuse_in_header *) cmd->buf;
1427 void *inarg = cmd->buf + sizeof(struct fuse_in_header);
1428 size_t argsize;
Miklos Szeredife25def2001-12-20 15:38:05 +00001429 struct fuse_context *ctx = fuse_get_context(f);
Miklos Szeredia181e612001-11-06 12:03:23 +00001430
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +00001431 dec_avail(f);
Miklos Szeredi33232032001-11-19 17:55:51 +00001432
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001433 if ((f->flags & FUSE_DEBUG)) {
Miklos Szeredic8ba2372002-12-10 12:26:00 +00001434 printf("unique: %i, opcode: %s (%i), ino: %li, insize: %i\n",
1435 in->unique, opname(in->opcode), in->opcode, in->ino,
1436 cmd->buflen);
Miklos Szeredic0938ea2001-11-07 12:35:06 +00001437 fflush(stdout);
1438 }
Miklos Szeredife25def2001-12-20 15:38:05 +00001439
1440 ctx->uid = in->uid;
1441 ctx->gid = in->gid;
Miklos Szeredia181e612001-11-06 12:03:23 +00001442
1443 argsize = cmd->buflen - sizeof(struct fuse_in_header);
1444
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001445 switch (in->opcode) {
Miklos Szeredia181e612001-11-06 12:03:23 +00001446 case FUSE_LOOKUP:
1447 do_lookup(f, in, (char *) inarg);
1448 break;
1449
Miklos Szeredia181e612001-11-06 12:03:23 +00001450 case FUSE_GETATTR:
1451 do_getattr(f, in);
1452 break;
1453
1454 case FUSE_SETATTR:
1455 do_setattr(f, in, (struct fuse_setattr_in *) inarg);
1456 break;
1457
1458 case FUSE_READLINK:
1459 do_readlink(f, in);
1460 break;
1461
1462 case FUSE_GETDIR:
1463 do_getdir(f, in);
1464 break;
1465
1466 case FUSE_MKNOD:
1467 do_mknod(f, in, (struct fuse_mknod_in *) inarg);
1468 break;
1469
1470 case FUSE_MKDIR:
1471 do_mkdir(f, in, (struct fuse_mkdir_in *) inarg);
1472 break;
1473
1474 case FUSE_UNLINK:
Miklos Szeredib5958612004-02-20 14:10:49 +00001475 do_unlink(f, in, (char *) inarg);
1476 break;
1477
Miklos Szeredia181e612001-11-06 12:03:23 +00001478 case FUSE_RMDIR:
Miklos Szeredib5958612004-02-20 14:10:49 +00001479 do_rmdir(f, in, (char *) inarg);
Miklos Szeredia181e612001-11-06 12:03:23 +00001480 break;
1481
1482 case FUSE_SYMLINK:
1483 do_symlink(f, in, (char *) inarg,
1484 ((char *) inarg) + strlen((char *) inarg) + 1);
1485 break;
1486
1487 case FUSE_RENAME:
1488 do_rename(f, in, (struct fuse_rename_in *) inarg);
1489 break;
1490
1491 case FUSE_LINK:
1492 do_link(f, in, (struct fuse_link_in *) inarg);
1493 break;
1494
1495 case FUSE_OPEN:
1496 do_open(f, in, (struct fuse_open_in *) inarg);
1497 break;
1498
Miklos Szeredie2e4ac22004-05-18 08:45:28 +00001499 case FUSE_FLUSH:
Miklos Szeredi209f5d02004-07-24 19:56:16 +00001500 do_flush(f, in, (struct fuse_flush_in *) inarg);
Miklos Szeredie2e4ac22004-05-18 08:45:28 +00001501 break;
1502
Miklos Szeredi9478e862002-12-11 09:50:26 +00001503 case FUSE_RELEASE:
Miklos Szeredi209f5d02004-07-24 19:56:16 +00001504 do_release(f, in, (struct fuse_release_in *) inarg);
Miklos Szeredi9478e862002-12-11 09:50:26 +00001505 break;
1506
Miklos Szeredia181e612001-11-06 12:03:23 +00001507 case FUSE_READ:
1508 do_read(f, in, (struct fuse_read_in *) inarg);
1509 break;
1510
1511 case FUSE_WRITE:
1512 do_write(f, in, (struct fuse_write_in *) inarg);
1513 break;
1514
Mark Glinesd84b39a2002-01-07 16:32:02 +00001515 case FUSE_STATFS:
1516 do_statfs(f, in);
1517 break;
1518
Miklos Szeredi5e43f2c2003-12-12 14:06:41 +00001519 case FUSE_FSYNC:
1520 do_fsync(f, in, (struct fuse_fsync_in *) inarg);
1521 break;
1522
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001523 case FUSE_SETXATTR:
1524 do_setxattr(f, in, (struct fuse_setxattr_in *) inarg);
1525 break;
1526
1527 case FUSE_GETXATTR:
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001528 do_getxattr(f, in, (struct fuse_getxattr_in *) inarg);
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001529 break;
1530
1531 case FUSE_LISTXATTR:
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001532 do_listxattr(f, in, (struct fuse_getxattr_in *) inarg);
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001533 break;
1534
1535 case FUSE_REMOVEXATTR:
1536 do_removexattr(f, in, (char *) inarg);
1537 break;
1538
Miklos Szeredia181e612001-11-06 12:03:23 +00001539 default:
Miklos Szeredi43696432001-11-18 19:15:05 +00001540 send_reply(f, in, -ENOSYS, NULL, 0);
Miklos Szeredia181e612001-11-06 12:03:23 +00001541 }
Miklos Szeredi43696432001-11-18 19:15:05 +00001542
1543 free_cmd(cmd);
Miklos Szeredia181e612001-11-06 12:03:23 +00001544}
1545
Miklos Szeredi65cf7c72004-06-30 11:34:56 +00001546int __fuse_exited(struct fuse* f)
1547{
1548 return f->exited;
1549}
1550
Miklos Szeredifff56ab2001-11-16 10:12:59 +00001551struct fuse_cmd *__fuse_read_cmd(struct fuse *f)
Miklos Szeredi2df1c042001-11-06 15:07:17 +00001552{
Miklos Szeredifff56ab2001-11-16 10:12:59 +00001553 ssize_t res;
Miklos Szeredifff56ab2001-11-16 10:12:59 +00001554 struct fuse_cmd *cmd;
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +00001555 struct fuse_in_header *in;
1556 void *inarg;
Miklos Szeredifff56ab2001-11-16 10:12:59 +00001557
Miklos Szeredi43696432001-11-18 19:15:05 +00001558 cmd = (struct fuse_cmd *) malloc(sizeof(struct fuse_cmd));
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001559 if (cmd == NULL) {
1560 fprintf(stderr, "fuse: failed to allocate cmd in read\n");
1561 return NULL;
1562 }
Miklos Szeredi43696432001-11-18 19:15:05 +00001563 cmd->buf = (char *) malloc(FUSE_MAX_IN);
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001564 if (cmd->buf == NULL) {
1565 fprintf(stderr, "fuse: failed to allocate read buffer\n");
1566 free(cmd);
1567 return NULL;
1568 }
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +00001569 in = (struct fuse_in_header *) cmd->buf;
1570 inarg = cmd->buf + sizeof(struct fuse_in_header);
Miklos Szeredi43696432001-11-18 19:15:05 +00001571
Miklos Szeredi65cf7c72004-06-30 11:34:56 +00001572 res = read(f->fd, cmd->buf, FUSE_MAX_IN);
1573 if (res == -1) {
1574 free_cmd(cmd);
1575 if (__fuse_exited(f) || errno == EINTR)
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +00001576 return NULL;
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +00001577
Miklos Szeredi65cf7c72004-06-30 11:34:56 +00001578 /* ENODEV means we got unmounted, so we silenty return failure */
1579 if (errno != ENODEV) {
1580 /* BAD... This will happen again */
1581 perror("fuse: reading device");
1582 }
1583
1584 fuse_exit(f);
1585 return NULL;
1586 }
1587 if ((size_t) res < sizeof(struct fuse_in_header)) {
1588 free_cmd(cmd);
1589 /* Cannot happen */
1590 fprintf(stderr, "short read on fuse device\n");
1591 fuse_exit(f);
1592 return NULL;
1593 }
1594 cmd->buflen = res;
1595
1596 /* Forget is special, it can be done without messing with threads. */
1597 if (in->opcode == FUSE_FORGET) {
1598 do_forget(f, in, (struct fuse_forget_in *) inarg);
1599 free_cmd(cmd);
1600 return NULL;
1601 }
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +00001602
Miklos Szeredifff56ab2001-11-16 10:12:59 +00001603 return cmd;
Miklos Szeredi2df1c042001-11-06 15:07:17 +00001604}
1605
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001606int fuse_loop(struct fuse *f)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001607{
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001608 if (f == NULL)
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001609 return -1;
Miklos Szeredic40748a2004-02-20 16:38:45 +00001610
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001611 while (1) {
Miklos Szeredi0f48a262002-12-05 14:23:01 +00001612 struct fuse_cmd *cmd;
1613
Miklos Szeredi65cf7c72004-06-30 11:34:56 +00001614 if (__fuse_exited(f))
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001615 return 0;
Miklos Szeredi0f48a262002-12-05 14:23:01 +00001616
1617 cmd = __fuse_read_cmd(f);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001618 if (cmd == NULL)
Miklos Szeredi0f48a262002-12-05 14:23:01 +00001619 continue;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001620
Miklos Szeredifff56ab2001-11-16 10:12:59 +00001621 __fuse_process_cmd(f, cmd);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001622 }
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001623 return 0;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001624}
1625
Miklos Szeredi891b8742004-07-29 09:27:49 +00001626int fuse_invalidate(struct fuse *f, const char *path)
1627{
1628 int res;
1629 int err;
1630 fino_t ino;
1631 struct fuse_user_header h;
1632
1633 err = path_lookup(f, path, &ino);
1634 if (err) {
1635 if (err == -ENOENT)
1636 return 0;
1637 else
1638 return err;
1639 }
1640
1641 memset(&h, 0, sizeof(struct fuse_user_header));
1642 h.opcode = FUSE_INVALIDATE;
1643 h.ino = ino;
1644
1645 if ((f->flags & FUSE_DEBUG)) {
1646 printf("INVALIDATE ino: %li\n", ino);
1647 fflush(stdout);
1648 }
1649
1650 res = write(f->fd, &h, sizeof(struct fuse_user_header));
1651 if (res == -1) {
1652 if (errno != ENOENT) {
1653 perror("fuse: writing device");
1654 return -errno;
1655 }
1656 }
1657 return 0;
1658}
1659
Miklos Szeredi0f48a262002-12-05 14:23:01 +00001660void fuse_exit(struct fuse *f)
1661{
1662 f->exited = 1;
1663}
1664
Miklos Szeredi2e50d432001-12-20 12:17:25 +00001665struct fuse_context *fuse_get_context(struct fuse *f)
1666{
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001667 if (f->getcontext)
Miklos Szeredi2e50d432001-12-20 12:17:25 +00001668 return f->getcontext(f);
1669 else
1670 return &f->context;
1671}
1672
Miklos Szeredic40748a2004-02-20 16:38:45 +00001673static int check_version(struct fuse *f)
1674{
1675 int res;
1676 FILE *vf = fopen(FUSE_VERSION_FILE, "r");
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001677 if (vf == NULL) {
Miklos Szeredic40748a2004-02-20 16:38:45 +00001678 fprintf(stderr, "fuse: kernel interface too old, need >= %i.%i\n",
1679 FUSE_KERNEL_VERSION, FUSE_KERNEL_MINOR_VERSION);
1680 return -1;
1681 }
1682 res = fscanf(vf, "%i.%i", &f->majorver, &f->minorver);
1683 fclose(vf);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001684 if (res != 2) {
Miklos Szeredic40748a2004-02-20 16:38:45 +00001685 fprintf(stderr, "fuse: error reading %s\n", FUSE_VERSION_FILE);
1686 return -1;
1687 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001688 if (f->majorver != FUSE_KERNEL_VERSION) {
Miklos Szeredic40748a2004-02-20 16:38:45 +00001689 fprintf(stderr, "fuse: bad kernel interface major version: needs %i\n",
1690 FUSE_KERNEL_VERSION);
1691 return -1;
1692 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001693 if (f->minorver < FUSE_KERNEL_MINOR_VERSION) {
Miklos Szeredic40748a2004-02-20 16:38:45 +00001694 fprintf(stderr, "fuse: kernel interface too old: need >= %i.%i",
1695 FUSE_KERNEL_VERSION, FUSE_KERNEL_MINOR_VERSION);
1696 return -1;
1697 }
1698
1699 return 0;
1700}
1701
Miklos Szeredibd7661b2004-07-23 17:16:29 +00001702
1703int fuse_is_lib_option(const char *opt)
1704{
1705 if (strcmp(opt, "debug") == 0 ||
1706 strcmp(opt, "hard_remove") == 0)
1707 return 1;
1708 else
1709 return 0;
1710}
1711
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001712static int parse_lib_opts(struct fuse *f, const char *opts)
Miklos Szeredibd7661b2004-07-23 17:16:29 +00001713{
1714 if (opts) {
1715 char *xopts = strdup(opts);
1716 char *s = xopts;
1717 char *opt;
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001718
1719 if (xopts == NULL)
1720 return -1;
Miklos Szeredibd7661b2004-07-23 17:16:29 +00001721
1722 while((opt = strsep(&s, ","))) {
1723 if (strcmp(opt, "debug") == 0)
1724 f->flags |= FUSE_DEBUG;
1725 else if (strcmp(opt, "hard_remove") == 0)
1726 f->flags |= FUSE_HARD_REMOVE;
1727 else
1728 fprintf(stderr, "fuse: warning: unknown option `%s'\n", opt);
1729 }
1730 free(xopts);
1731 }
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001732 return 0;
Miklos Szeredibd7661b2004-07-23 17:16:29 +00001733}
1734
1735struct fuse *fuse_new(int fd, const char *opts, const struct fuse_operations *op)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001736{
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001737 struct fuse *f;
1738 struct node *root;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001739
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001740 f = (struct fuse *) calloc(1, sizeof(struct fuse));
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001741 if (f == NULL)
1742 goto out;
Miklos Szeredi2df1c042001-11-06 15:07:17 +00001743
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001744 if (check_version(f) == -1)
1745 goto out_free;
Miklos Szeredic40748a2004-02-20 16:38:45 +00001746
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001747 if (parse_lib_opts(f, opts) == -1)
1748 goto out_free;
1749
Miklos Szeredi8cffdb92001-11-09 14:49:18 +00001750 f->fd = fd;
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001751 f->ctr = 0;
Miklos Szeredi76f65782004-02-19 16:55:40 +00001752 f->generation = 0;
Miklos Szeredifff56ab2001-11-16 10:12:59 +00001753 /* FIXME: Dynamic hash table */
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001754 f->name_table_size = 14057;
1755 f->name_table = (struct node **)
1756 calloc(1, sizeof(struct node *) * f->name_table_size);
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001757 if (f->name_table == NULL)
1758 goto out_free;
1759
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001760 f->ino_table_size = 14057;
1761 f->ino_table = (struct node **)
1762 calloc(1, sizeof(struct node *) * f->ino_table_size);
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001763 if (f->ino_table == NULL)
1764 goto out_free_name_table;
1765
Miklos Szeredia181e612001-11-06 12:03:23 +00001766 pthread_mutex_init(&f->lock, NULL);
Miklos Szeredi33232032001-11-19 17:55:51 +00001767 f->numworker = 0;
1768 f->numavail = 0;
Miklos Szeredi2e50d432001-12-20 12:17:25 +00001769 f->op = *op;
1770 f->getcontext = NULL;
1771 f->context.uid = 0;
1772 f->context.gid = 0;
Miklos Szeredi0f48a262002-12-05 14:23:01 +00001773 f->exited = 0;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001774
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001775 root = (struct node *) calloc(1, sizeof(struct node));
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001776 if (root == NULL)
1777 goto out_free_ino_table;
1778
Miklos Szeredi8cffdb92001-11-09 14:49:18 +00001779 root->mode = 0;
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001780 root->rdev = 0;
1781 root->name = strdup("/");
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001782 if (root->name == NULL)
1783 goto out_free_root;
1784
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001785 root->parent = 0;
Miklos Szeredi76f65782004-02-19 16:55:40 +00001786 root->ino = FUSE_ROOT_INO;
1787 root->generation = 0;
1788 hash_ino(f, root);
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001789
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001790 return f;
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001791
1792 out_free_root:
1793 free(root);
1794 out_free_ino_table:
1795 free(f->ino_table);
1796 out_free_name_table:
1797 free(f->name_table);
1798 out_free:
1799 free(f);
1800 out:
1801 fprintf(stderr, "fuse: failed to allocate fuse object\n");
1802 return NULL;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001803}
1804
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001805void fuse_destroy(struct fuse *f)
1806{
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001807 size_t i;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001808 for (i = 0; i < f->ino_table_size; i++) {
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001809 struct node *node;
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001810
1811 for (node = f->ino_table[i]; node != NULL; node = node->ino_next) {
1812 if (node->is_hidden) {
1813 char *path = get_path(f, node->ino);
1814 if (path)
1815 f->op.unlink(path);
1816 }
1817 }
1818 }
1819 for (i = 0; i < f->ino_table_size; i++) {
1820 struct node *node;
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001821 struct node *next;
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001822
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001823 for (node = f->ino_table[i]; node != NULL; node = next) {
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001824 next = node->ino_next;
1825 free_node(node);
1826 }
1827 }
1828 free(f->ino_table);
1829 free(f->name_table);
Miklos Szeredia181e612001-11-06 12:03:23 +00001830 pthread_mutex_destroy(&f->lock);
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001831 free(f);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001832}