blob: 80c14883d024bcb2f31f3e5ca192b75a233d40de [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 Szeredi97c61e92001-11-07 12:09:43 +0000162static void hash_name(struct fuse *f, struct node *node, fino_t parent,
Miklos Szeredia181e612001-11-06 12:03:23 +0000163 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);
168 node->name_next = f->name_table[hash];
169 f->name_table[hash] = node;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000170}
171
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000172static void unhash_name(struct fuse *f, struct node *node)
Miklos Szeredia181e612001-11-06 12:03:23 +0000173{
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000174 if (node->name != NULL) {
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000175 size_t hash = name_hash(f, node->parent, node->name);
176 struct node **nodep = &f->name_table[hash];
177
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000178 for (; *nodep != NULL; nodep = &(*nodep)->name_next)
179 if (*nodep == node) {
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000180 *nodep = node->name_next;
181 node->name_next = NULL;
182 free(node->name);
183 node->name = NULL;
184 node->parent = 0;
185 return;
186 }
187 fprintf(stderr, "fuse internal error: unable to unhash node: %lu\n",
188 node->ino);
189 abort();
Miklos Szeredia181e612001-11-06 12:03:23 +0000190 }
191}
192
Miklos Szeredi76f65782004-02-19 16:55:40 +0000193static struct node *find_node(struct fuse *f, fino_t parent, char *name,
194 struct fuse_attr *attr, int version)
Miklos Szeredi5e183482001-10-31 14:52:35 +0000195{
196 struct node *node;
Miklos Szeredia181e612001-11-06 12:03:23 +0000197 int mode = attr->mode & S_IFMT;
198 int rdev = 0;
199
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000200 if (S_ISCHR(mode) || S_ISBLK(mode))
Miklos Szeredia181e612001-11-06 12:03:23 +0000201 rdev = attr->rdev;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000202
Miklos Szeredia181e612001-11-06 12:03:23 +0000203 pthread_mutex_lock(&f->lock);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000204 node = __lookup_node(f, parent, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000205 if (node != NULL) {
206 if (node->mode == mode && node->rdev == rdev)
Miklos Szeredia181e612001-11-06 12:03:23 +0000207 goto out;
208
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000209 unhash_name(f, node);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000210 }
211
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000212 node = (struct node *) calloc(1, sizeof(struct node));
Miklos Szeredia181e612001-11-06 12:03:23 +0000213 node->mode = mode;
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000214 node->rdev = rdev;
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000215 node->open_count = 0;
216 node->is_hidden = 0;
Miklos Szeredi76f65782004-02-19 16:55:40 +0000217 node->ino = next_ino(f);
218 node->generation = f->generation;
219 hash_ino(f, node);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000220 hash_name(f, node, parent, name);
Miklos Szeredia181e612001-11-06 12:03:23 +0000221
222 out:
223 node->version = version;
224 pthread_mutex_unlock(&f->lock);
Miklos Szeredi76f65782004-02-19 16:55:40 +0000225 return node;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000226}
227
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000228static char *add_name(char *buf, char *s, const char *name)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000229{
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000230 size_t len = strlen(name);
231 s -= len;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000232 if (s <= buf) {
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000233 fprintf(stderr, "fuse: path too long: ...%s\n", s + len);
234 return NULL;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000235 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000236 strncpy(s, name, len);
237 s--;
238 *s = '/';
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000239
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000240 return s;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000241}
242
Miklos Szeredia181e612001-11-06 12:03:23 +0000243static char *get_path_name(struct fuse *f, fino_t ino, const char *name)
Miklos Szeredib483c932001-10-29 14:57:57 +0000244{
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000245 char buf[FUSE_MAX_PATH];
246 char *s = buf + FUSE_MAX_PATH - 1;
247 struct node *node;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000248
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000249 *s = '\0';
Miklos Szeredia181e612001-11-06 12:03:23 +0000250
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000251 if (name != NULL) {
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000252 s = add_name(buf, s, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000253 if (s == NULL)
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000254 return NULL;
255 }
256
257 pthread_mutex_lock(&f->lock);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000258 for (node = get_node(f, ino); node->ino != FUSE_ROOT_INO;
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000259 node = get_node(f, node->parent)) {
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000260 if (node->name == NULL) {
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000261 s = NULL;
262 break;
263 }
264
265 s = add_name(buf, s, node->name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000266 if (s == NULL)
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000267 break;
268 }
269 pthread_mutex_unlock(&f->lock);
270
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000271 if (s == NULL)
Miklos Szeredi5e183482001-10-31 14:52:35 +0000272 return NULL;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000273 else if (*s == '\0')
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000274 return strdup("/");
275 else
276 return strdup(s);
277}
Miklos Szeredia181e612001-11-06 12:03:23 +0000278
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000279static char *get_path(struct fuse *f, fino_t ino)
280{
281 return get_path_name(f, ino, NULL);
Miklos Szeredib483c932001-10-29 14:57:57 +0000282}
283
Miklos Szeredia181e612001-11-06 12:03:23 +0000284static void destroy_node(struct fuse *f, fino_t ino, int version)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000285{
Miklos Szeredia181e612001-11-06 12:03:23 +0000286 struct node *node;
287
288 pthread_mutex_lock(&f->lock);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000289 node = get_node(f, ino);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000290 if (node->version == version && ino != FUSE_ROOT_INO) {
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000291 unhash_name(f, node);
292 unhash_ino(f, node);
Miklos Szeredia181e612001-11-06 12:03:23 +0000293 free_node(node);
294 }
295 pthread_mutex_unlock(&f->lock);
296
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000297}
298
Miklos Szeredi5e183482001-10-31 14:52:35 +0000299static void remove_node(struct fuse *f, fino_t dir, const char *name)
300{
Miklos Szeredia181e612001-11-06 12:03:23 +0000301 struct node *node;
302
303 pthread_mutex_lock(&f->lock);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000304 node = __lookup_node(f, dir, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000305 if (node == NULL) {
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000306 fprintf(stderr, "fuse internal error: unable to remove node %lu/%s\n",
307 dir, name);
308 abort();
309 }
310 unhash_name(f, node);
Miklos Szeredia181e612001-11-06 12:03:23 +0000311 pthread_mutex_unlock(&f->lock);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000312}
313
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000314static int rename_node(struct fuse *f, fino_t olddir, const char *oldname,
315 fino_t newdir, const char *newname, int hide)
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000316{
Miklos Szeredia181e612001-11-06 12:03:23 +0000317 struct node *node;
318 struct node *newnode;
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000319 int err = 0;
Miklos Szeredia181e612001-11-06 12:03:23 +0000320
321 pthread_mutex_lock(&f->lock);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000322 node = __lookup_node(f, olddir, oldname);
323 newnode = __lookup_node(f, newdir, newname);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000324 if (node == NULL) {
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000325 fprintf(stderr, "fuse internal error: unable to rename node %lu/%s\n",
326 olddir, oldname);
327 abort();
328 }
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000329
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000330 if (newnode != NULL) {
331 if (hide) {
332 fprintf(stderr, "fuse: hidden file got created during hiding\n");
333 err = -1;
334 goto out;
335 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000336 unhash_name(f, newnode);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000337 }
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000338
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000339 unhash_name(f, node);
340 hash_name(f, node, newdir, newname);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000341 if (hide)
342 node->is_hidden = 1;
343
344 out:
Miklos Szeredia181e612001-11-06 12:03:23 +0000345 pthread_mutex_unlock(&f->lock);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000346 return err;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000347}
348
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000349static void convert_stat(struct stat *stbuf, struct fuse_attr *attr)
350{
Miklos Szeredib5958612004-02-20 14:10:49 +0000351 attr->mode = stbuf->st_mode;
352 attr->nlink = stbuf->st_nlink;
353 attr->uid = stbuf->st_uid;
354 attr->gid = stbuf->st_gid;
355 attr->rdev = stbuf->st_rdev;
356 attr->size = stbuf->st_size;
357 attr->blocks = stbuf->st_blocks;
358 attr->atime = stbuf->st_atime;
Miklos Szeredib5958612004-02-20 14:10:49 +0000359 attr->mtime = stbuf->st_mtime;
Miklos Szeredib5958612004-02-20 14:10:49 +0000360 attr->ctime = stbuf->st_ctime;
Miklos Szeredicb264512004-06-23 18:52:50 +0000361#ifdef HAVE_STRUCT_STAT_ST_ATIM
362 attr->atimensec = stbuf->st_atim.tv_nsec;
363 attr->mtimensec = stbuf->st_mtim.tv_nsec;
Miklos Szeredib5958612004-02-20 14:10:49 +0000364 attr->ctimensec = stbuf->st_ctim.tv_nsec;
Miklos Szeredicb264512004-06-23 18:52:50 +0000365#endif
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000366}
367
Miklos Szeredia181e612001-11-06 12:03:23 +0000368static int fill_dir(struct fuse_dirhandle *dh, char *name, int type)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000369{
370 struct fuse_dirent dirent;
371 size_t reclen;
372 size_t res;
373
Miklos Szeredi43696432001-11-18 19:15:05 +0000374 dirent.ino = (unsigned long) -1;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000375 dirent.namelen = strlen(name);
376 strncpy(dirent.name, name, sizeof(dirent.name));
377 dirent.type = type;
378 reclen = FUSE_DIRENT_SIZE(&dirent);
379 res = fwrite(&dirent, reclen, 1, dh->fp);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000380 if (res == 0) {
Miklos Szeredi96249982001-11-21 12:21:19 +0000381 perror("fuse: writing directory file");
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000382 return -EIO;
383 }
384 return 0;
385}
386
Miklos Szeredi73798f92004-07-12 15:55:11 +0000387static int send_reply_raw(struct fuse *f, char *outbuf, size_t outsize,
388 int locked)
Miklos Szeredi43696432001-11-18 19:15:05 +0000389{
390 int res;
391
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000392 if ((f->flags & FUSE_DEBUG)) {
Miklos Szeredi43696432001-11-18 19:15:05 +0000393 struct fuse_out_header *out = (struct fuse_out_header *) outbuf;
394 printf(" unique: %i, error: %i (%s), outsize: %i\n", out->unique,
395 out->error, strerror(-out->error), outsize);
396 fflush(stdout);
397 }
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +0000398
Miklos Szeredi4e71c9f2004-02-09 12:05:14 +0000399 /* This needs to be done before the reply, otherwise the scheduler
400 could play tricks with us, and only let the counter be increased
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +0000401 long after the operation is done */
Miklos Szeredi73798f92004-07-12 15:55:11 +0000402 if (!locked)
403 pthread_mutex_lock(&f->lock);
404 f->numavail ++;
405 if (!locked)
406 pthread_mutex_unlock(&f->lock);
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +0000407
Miklos Szeredi43696432001-11-18 19:15:05 +0000408 res = write(f->fd, outbuf, outsize);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000409 if (res == -1) {
Miklos Szeredi43696432001-11-18 19:15:05 +0000410 /* ENOENT means the operation was interrupted */
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000411 if (!f->exited && errno != ENOENT)
Miklos Szeredi96249982001-11-21 12:21:19 +0000412 perror("fuse: writing device");
Miklos Szeredi40b9a5a2002-12-10 16:09:02 +0000413 return -errno;
Miklos Szeredi43696432001-11-18 19:15:05 +0000414 }
Miklos Szeredi40b9a5a2002-12-10 16:09:02 +0000415 return 0;
Miklos Szeredi43696432001-11-18 19:15:05 +0000416}
417
Miklos Szeredi73798f92004-07-12 15:55:11 +0000418static int __send_reply(struct fuse *f, struct fuse_in_header *in, int error,
419 void *arg, size_t argsize, int locked)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000420{
Miklos Szeredi40b9a5a2002-12-10 16:09:02 +0000421 int res;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000422 char *outbuf;
423 size_t outsize;
424 struct fuse_out_header *out;
425
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000426 if (error <= -1000 || error > 0) {
Miklos Szeredi0f48a262002-12-05 14:23:01 +0000427 fprintf(stderr, "fuse: bad error value: %i\n", error);
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000428 error = -ERANGE;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000429 }
430
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000431 if (error)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000432 argsize = 0;
433
434 outsize = sizeof(struct fuse_out_header) + argsize;
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000435 outbuf = (char *) malloc(outsize);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000436 out = (struct fuse_out_header *) outbuf;
Miklos Szeredi0f48a262002-12-05 14:23:01 +0000437 memset(out, 0, sizeof(struct fuse_out_header));
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000438 out->unique = in->unique;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000439 out->error = error;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000440 if (argsize != 0)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000441 memcpy(outbuf + sizeof(struct fuse_out_header), arg, argsize);
442
Miklos Szeredi73798f92004-07-12 15:55:11 +0000443 res = send_reply_raw(f, outbuf, outsize, locked);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000444 free(outbuf);
Miklos Szeredi40b9a5a2002-12-10 16:09:02 +0000445
446 return res;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000447}
448
Miklos Szeredi73798f92004-07-12 15:55:11 +0000449static int send_reply(struct fuse *f, struct fuse_in_header *in, int error,
450 void *arg, size_t argsize)
451{
452 return __send_reply(f, in, error, arg, argsize, 0);
453}
454
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000455static int is_open(struct fuse *f, fino_t dir, const char *name)
456{
457 struct node *node;
458 int isopen = 0;
459 pthread_mutex_lock(&f->lock);
460 node = __lookup_node(f, dir, name);
461 if (node && node->open_count > 0)
462 isopen = 1;
463 pthread_mutex_unlock(&f->lock);
464 return isopen;
465}
466
467static char *hidden_name(struct fuse *f, fino_t dir, const char *oldname,
468 char *newname, size_t bufsize)
469{
470 struct stat buf;
471 struct node *node;
472 struct node *newnode;
473 char *newpath;
474 int res;
475 int failctr = 10;
476
477 if (!f->op.getattr)
478 return NULL;
479
480 do {
481 node = lookup_node(f, dir, oldname);
482 pthread_mutex_lock(&f->lock);
483 do {
484 f->hidectr ++;
485 snprintf(newname, bufsize, ".fuse_hidden%08x%08x",
486 (unsigned int) node->ino, f->hidectr);
487 newnode = __lookup_node(f, dir, newname);
488 } while(newnode);
489 pthread_mutex_unlock(&f->lock);
490
491 newpath = get_path_name(f, dir, newname);
492 if (!newpath)
493 break;
494
495 res = f->op.getattr(newpath, &buf);
496 if (res != 0)
497 break;
498 free(newpath);
499 newpath = NULL;
500 } while(--failctr);
501
502 return newpath;
503}
504
505static int hide_node(struct fuse *f, const char *oldpath, fino_t dir,
506 const char *oldname)
507{
508 char newname[64];
509 char *newpath;
510 int err = -1;
511
512 if (!f->op.rename || !f->op.unlink)
513 return -EBUSY;
514
515 newpath = hidden_name(f, dir, oldname, newname, sizeof(newname));
516 if (newpath) {
517 err = f->op.rename(oldpath, newpath);
518 if (!err)
519 err = rename_node(f, dir, oldname, dir, newname, 1);
520 free(newpath);
521 }
522 if (err)
523 return -EBUSY;
524
525 return 0;
526}
527
Miklos Szeredi76f65782004-02-19 16:55:40 +0000528static int lookup_path(struct fuse *f, fino_t ino, int version, char *name,
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000529 const char *path, struct fuse_entry_out *arg)
Miklos Szeredi76f65782004-02-19 16:55:40 +0000530{
531 int res;
532 struct stat buf;
533
534 res = f->op.getattr(path, &buf);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000535 if (res == 0) {
Miklos Szeredi76f65782004-02-19 16:55:40 +0000536 struct node *node;
537
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000538 memset(arg, 0, sizeof(struct fuse_entry_out));
Miklos Szeredi76f65782004-02-19 16:55:40 +0000539 convert_stat(&buf, &arg->attr);
540 node = find_node(f, ino, name, &arg->attr, version);
541 arg->ino = node->ino;
542 arg->generation = node->generation;
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000543 arg->entry_valid = ENTRY_REVALIDATE_TIME;
544 arg->entry_valid_nsec = 0;
545 arg->attr_valid = ATTR_REVALIDATE_TIME;
546 arg->attr_valid_nsec = 0;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000547 if (f->flags & FUSE_DEBUG) {
Miklos Szeredi76f65782004-02-19 16:55:40 +0000548 printf(" INO: %li\n", arg->ino);
549 fflush(stdout);
550 }
551 }
552 return res;
553}
554
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000555static void do_lookup(struct fuse *f, struct fuse_in_header *in, char *name)
556{
557 int res;
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000558 int res2;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000559 char *path;
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000560 struct fuse_entry_out arg;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000561
Miklos Szeredi5e183482001-10-31 14:52:35 +0000562 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000563 path = get_path_name(f, in->ino, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000564 if (path != NULL) {
565 if (f->flags & FUSE_DEBUG) {
Miklos Szeredi6ebe2342002-01-06 21:44:16 +0000566 printf("LOOKUP %s\n", path);
567 fflush(stdout);
568 }
Miklos Szeredi5e183482001-10-31 14:52:35 +0000569 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000570 if (f->op.getattr)
Miklos Szeredi76f65782004-02-19 16:55:40 +0000571 res = lookup_path(f, in->ino, in->unique, name, path, &arg);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000572 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000573 }
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000574 res2 = send_reply(f, in, res, &arg, sizeof(arg));
575 if (res == 0 && res2 == -ENOENT)
576 destroy_node(f, arg.ino, in->unique);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000577}
578
Miklos Szeredia181e612001-11-06 12:03:23 +0000579static void do_forget(struct fuse *f, struct fuse_in_header *in,
580 struct fuse_forget_in *arg)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000581{
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000582 if (f->flags & FUSE_DEBUG) {
Miklos Szeredi43696432001-11-18 19:15:05 +0000583 printf("FORGET %li/%i\n", in->ino, arg->version);
584 fflush(stdout);
585 }
Miklos Szeredia181e612001-11-06 12:03:23 +0000586 destroy_node(f, in->ino, arg->version);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000587}
588
589static void do_getattr(struct fuse *f, struct fuse_in_header *in)
590{
591 int res;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000592 char *path;
593 struct stat buf;
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000594 struct fuse_attr_out arg;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000595
Miklos Szeredi5e183482001-10-31 14:52:35 +0000596 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000597 path = get_path(f, in->ino);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000598 if (path != NULL) {
Miklos Szeredi5e183482001-10-31 14:52:35 +0000599 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000600 if (f->op.getattr)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000601 res = f->op.getattr(path, &buf);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000602 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000603 }
Miklos Szeredi0f48a262002-12-05 14:23:01 +0000604
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000605 if (res == 0) {
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000606 memset(&arg, 0, sizeof(struct fuse_attr_out));
607 arg.attr_valid = ATTR_REVALIDATE_TIME;
608 arg.attr_valid_nsec = 0;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000609 convert_stat(&buf, &arg.attr);
Miklos Szeredi0f48a262002-12-05 14:23:01 +0000610 }
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000611
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000612 send_reply(f, in, res, &arg, sizeof(arg));
613}
614
Miklos Szeredi680a69a2001-11-16 13:31:14 +0000615static int do_chmod(struct fuse *f, const char *path, struct fuse_attr *attr)
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000616{
617 int res;
618
619 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000620 if (f->op.chmod)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000621 res = f->op.chmod(path, attr->mode);
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000622
623 return res;
624}
625
Miklos Szeredi680a69a2001-11-16 13:31:14 +0000626static int do_chown(struct fuse *f, const char *path, struct fuse_attr *attr,
Miklos Szeredi2e50d432001-12-20 12:17:25 +0000627 int valid)
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000628{
629 int res;
630 uid_t uid = (valid & FATTR_UID) ? attr->uid : (uid_t) -1;
631 gid_t gid = (valid & FATTR_GID) ? attr->gid : (gid_t) -1;
632
633 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000634 if (f->op.chown)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000635 res = f->op.chown(path, uid, gid);
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000636
637 return res;
638}
639
Miklos Szeredi680a69a2001-11-16 13:31:14 +0000640static int do_truncate(struct fuse *f, const char *path,
641 struct fuse_attr *attr)
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000642{
643 int res;
644
645 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000646 if (f->op.truncate)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000647 res = f->op.truncate(path, attr->size);
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000648
649 return res;
650}
651
Miklos Szeredi680a69a2001-11-16 13:31:14 +0000652static int do_utime(struct fuse *f, const char *path, struct fuse_attr *attr)
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000653{
654 int res;
655 struct utimbuf buf;
656 buf.actime = attr->atime;
657 buf.modtime = attr->mtime;
658 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000659 if (f->op.utime)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000660 res = f->op.utime(path, &buf);
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000661
662 return res;
663}
664
Miklos Szeredi5e183482001-10-31 14:52:35 +0000665static void do_setattr(struct fuse *f, struct fuse_in_header *in,
666 struct fuse_setattr_in *arg)
667{
668 int res;
669 char *path;
670 int valid = arg->valid;
671 struct fuse_attr *attr = &arg->attr;
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000672 struct fuse_attr_out outarg;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000673
674 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000675 path = get_path(f, in->ino);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000676 if (path != NULL) {
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000677 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000678 if (f->op.getattr) {
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000679 res = 0;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000680 if (!res && (valid & FATTR_MODE))
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000681 res = do_chmod(f, path, attr);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000682 if (!res && (valid & (FATTR_UID | FATTR_GID)))
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000683 res = do_chown(f, path, attr, valid);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000684 if (!res && (valid & FATTR_SIZE))
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000685 res = do_truncate(f, path, attr);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000686 if (!res && (valid & (FATTR_ATIME | FATTR_MTIME)) ==
Miklos Szeredib5958612004-02-20 14:10:49 +0000687 (FATTR_ATIME | FATTR_MTIME))
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000688 res = do_utime(f, path, attr);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000689 if (!res) {
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000690 struct stat buf;
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000691 res = f->op.getattr(path, &buf);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000692 if (!res) {
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000693 memset(&outarg, 0, sizeof(struct fuse_attr_out));
694 outarg.attr_valid = ATTR_REVALIDATE_TIME;
695 outarg.attr_valid_nsec = 0;
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000696 convert_stat(&buf, &outarg.attr);
Miklos Szeredi0f48a262002-12-05 14:23:01 +0000697 }
Miklos Szeredia181e612001-11-06 12:03:23 +0000698 }
Miklos Szeredi5e183482001-10-31 14:52:35 +0000699 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000700 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000701 }
Miklos Szeredia181e612001-11-06 12:03:23 +0000702 send_reply(f, in, res, &outarg, sizeof(outarg));
Miklos Szeredi5e183482001-10-31 14:52:35 +0000703}
704
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000705static void do_readlink(struct fuse *f, struct fuse_in_header *in)
706{
707 int res;
708 char link[PATH_MAX + 1];
Miklos Szeredib483c932001-10-29 14:57:57 +0000709 char *path;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000710
Miklos Szeredi5e183482001-10-31 14:52:35 +0000711 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000712 path = get_path(f, in->ino);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000713 if (path != NULL) {
Miklos Szeredi5e183482001-10-31 14:52:35 +0000714 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000715 if (f->op.readlink)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000716 res = f->op.readlink(path, link, sizeof(link));
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000717 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000718 }
Miklos Szeredi2df1c042001-11-06 15:07:17 +0000719 link[PATH_MAX] = '\0';
Miklos Szeredi4b2bef42002-01-09 12:23:27 +0000720 send_reply(f, in, res, link, res == 0 ? strlen(link) : 0);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000721}
722
723static void do_getdir(struct fuse *f, struct fuse_in_header *in)
724{
725 int res;
726 struct fuse_getdir_out arg;
Miklos Szeredia181e612001-11-06 12:03:23 +0000727 struct fuse_dirhandle dh;
Miklos Szeredib483c932001-10-29 14:57:57 +0000728 char *path;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000729
Miklos Szeredib483c932001-10-29 14:57:57 +0000730 dh.fuse = f;
731 dh.fp = tmpfile();
732 dh.dir = in->ino;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000733 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000734 path = get_path(f, in->ino);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000735 if (path != NULL) {
Miklos Szeredi5e183482001-10-31 14:52:35 +0000736 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000737 if (f->op.getdir)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000738 res = f->op.getdir(path, &dh, (fuse_dirfil_t) fill_dir);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000739 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000740 }
Miklos Szeredib483c932001-10-29 14:57:57 +0000741 fflush(dh.fp);
Miklos Szeredi0f48a262002-12-05 14:23:01 +0000742
743 memset(&arg, 0, sizeof(struct fuse_getdir_out));
Miklos Szeredib483c932001-10-29 14:57:57 +0000744 arg.fd = fileno(dh.fp);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000745 send_reply(f, in, res, &arg, sizeof(arg));
Miklos Szeredib483c932001-10-29 14:57:57 +0000746 fclose(dh.fp);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000747}
748
Miklos Szeredib483c932001-10-29 14:57:57 +0000749static void do_mknod(struct fuse *f, struct fuse_in_header *in,
750 struct fuse_mknod_in *inarg)
751{
752 int res;
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000753 int res2;
Miklos Szeredib483c932001-10-29 14:57:57 +0000754 char *path;
Miklos Szeredi76f65782004-02-19 16:55:40 +0000755 char *name = PARAM(inarg);
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000756 struct fuse_entry_out outarg;
Miklos Szeredib483c932001-10-29 14:57:57 +0000757
Miklos Szeredi5e183482001-10-31 14:52:35 +0000758 res = -ENOENT;
Miklos Szeredi76f65782004-02-19 16:55:40 +0000759 path = get_path_name(f, in->ino, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000760 if (path != NULL) {
761 if (f->flags & FUSE_DEBUG) {
Miklos Szeredi76f65782004-02-19 16:55:40 +0000762 printf("MKNOD %s\n", path);
763 fflush(stdout);
764 }
Miklos Szeredi5e183482001-10-31 14:52:35 +0000765 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000766 if (f->op.mknod && f->op.getattr) {
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000767 res = f->op.mknod(path, inarg->mode, inarg->rdev);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000768 if (res == 0)
Miklos Szeredi76f65782004-02-19 16:55:40 +0000769 res = lookup_path(f, in->ino, in->unique, name, path, &outarg);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000770 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000771 free(path);
Miklos Szeredib483c932001-10-29 14:57:57 +0000772 }
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000773 res2 = send_reply(f, in, res, &outarg, sizeof(outarg));
774 if (res == 0 && res2 == -ENOENT)
775 destroy_node(f, outarg.ino, in->unique);
Miklos Szeredib483c932001-10-29 14:57:57 +0000776}
777
778static void do_mkdir(struct fuse *f, struct fuse_in_header *in,
779 struct fuse_mkdir_in *inarg)
780{
781 int res;
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000782 int res2;
Miklos Szeredib483c932001-10-29 14:57:57 +0000783 char *path;
Miklos Szeredi76f65782004-02-19 16:55:40 +0000784 char *name = PARAM(inarg);
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000785 struct fuse_entry_out outarg;
Miklos Szeredib483c932001-10-29 14:57:57 +0000786
Miklos Szeredi5e183482001-10-31 14:52:35 +0000787 res = -ENOENT;
Miklos Szeredi76f65782004-02-19 16:55:40 +0000788 path = get_path_name(f, in->ino, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000789 if (path != NULL) {
790 if (f->flags & FUSE_DEBUG) {
Miklos Szeredi76f65782004-02-19 16:55:40 +0000791 printf("MKDIR %s\n", path);
792 fflush(stdout);
793 }
Miklos Szeredi5e183482001-10-31 14:52:35 +0000794 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000795 if (f->op.mkdir && f->op.getattr) {
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000796 res = f->op.mkdir(path, inarg->mode);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000797 if (res == 0)
Miklos Szeredi76f65782004-02-19 16:55:40 +0000798 res = lookup_path(f, in->ino, in->unique, name, path, &outarg);
799 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000800 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000801 }
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000802 res2 = send_reply(f, in, res, &outarg, sizeof(outarg));
803 if (res == 0 && res2 == -ENOENT)
804 destroy_node(f, outarg.ino, in->unique);
Miklos Szeredib483c932001-10-29 14:57:57 +0000805}
806
Miklos Szeredib5958612004-02-20 14:10:49 +0000807static void do_unlink(struct fuse *f, struct fuse_in_header *in, char *name)
Miklos Szeredib483c932001-10-29 14:57:57 +0000808{
809 int res;
810 char *path;
811
Miklos Szeredi5e183482001-10-31 14:52:35 +0000812 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000813 path = get_path_name(f, in->ino, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000814 if (path != NULL) {
Miklos Szeredi209f5d02004-07-24 19:56:16 +0000815 if (f->flags & FUSE_DEBUG) {
816 printf("UNLINK %s\n", path);
817 fflush(stdout);
818 }
Miklos Szeredi5e183482001-10-31 14:52:35 +0000819 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000820 if (f->op.unlink) {
Miklos Szeredi2529ca22004-07-13 15:36:52 +0000821 if (!(f->flags & FUSE_HARD_REMOVE) && is_open(f, in->ino, name))
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000822 res = hide_node(f, path, in->ino, name);
823 else {
824 res = f->op.unlink(path);
825 if (res == 0)
826 remove_node(f, in->ino, name);
827 }
Miklos Szeredi5e183482001-10-31 14:52:35 +0000828 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000829 free(path);
Miklos Szeredib483c932001-10-29 14:57:57 +0000830 }
Miklos Szeredib5958612004-02-20 14:10:49 +0000831 send_reply(f, in, res, NULL, 0);
832}
833
834static void do_rmdir(struct fuse *f, struct fuse_in_header *in, char *name)
835{
836 int res;
837 char *path;
838
839 res = -ENOENT;
840 path = get_path_name(f, in->ino, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000841 if (path != NULL) {
Miklos Szeredi209f5d02004-07-24 19:56:16 +0000842 if (f->flags & FUSE_DEBUG) {
843 printf("RMDIR %s\n", path);
844 fflush(stdout);
845 }
Miklos Szeredib5958612004-02-20 14:10:49 +0000846 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000847 if (f->op.rmdir) {
Miklos Szeredib5958612004-02-20 14:10:49 +0000848 res = f->op.rmdir(path);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000849 if (res == 0)
Miklos Szeredib5958612004-02-20 14:10:49 +0000850 remove_node(f, in->ino, name);
851 }
852 free(path);
853 }
Miklos Szeredib483c932001-10-29 14:57:57 +0000854 send_reply(f, in, res, NULL, 0);
855}
856
857static void do_symlink(struct fuse *f, struct fuse_in_header *in, char *name,
858 char *link)
859{
860 int res;
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000861 int res2;
Miklos Szeredib483c932001-10-29 14:57:57 +0000862 char *path;
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000863 struct fuse_entry_out outarg;
Miklos Szeredib483c932001-10-29 14:57:57 +0000864
Miklos Szeredi5e183482001-10-31 14:52:35 +0000865 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000866 path = get_path_name(f, in->ino, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000867 if (path != NULL) {
868 if (f->flags & FUSE_DEBUG) {
Miklos Szeredi76f65782004-02-19 16:55:40 +0000869 printf("SYMLINK %s\n", path);
870 fflush(stdout);
871 }
Miklos Szeredi5e183482001-10-31 14:52:35 +0000872 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000873 if (f->op.symlink && f->op.getattr) {
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000874 res = f->op.symlink(link, path);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000875 if (res == 0)
Miklos Szeredi76f65782004-02-19 16:55:40 +0000876 res = lookup_path(f, in->ino, in->unique, name, path, &outarg);
877 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000878 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000879 }
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000880 res2 = send_reply(f, in, res, &outarg, sizeof(outarg));
881 if (res == 0 && res2 == -ENOENT)
882 destroy_node(f, outarg.ino, in->unique);
883
Miklos Szeredib483c932001-10-29 14:57:57 +0000884}
885
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000886static void do_rename(struct fuse *f, struct fuse_in_header *in,
887 struct fuse_rename_in *inarg)
888{
889 int res;
890 fino_t olddir = in->ino;
891 fino_t newdir = inarg->newdir;
Miklos Szeredi6bf8b682002-10-28 08:49:39 +0000892 char *oldname = PARAM(inarg);
893 char *newname = oldname + strlen(oldname) + 1;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000894 char *oldpath;
895 char *newpath;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000896
Miklos Szeredi5e183482001-10-31 14:52:35 +0000897 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000898 oldpath = get_path_name(f, olddir, oldname);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000899 if (oldpath != NULL) {
Miklos Szeredia181e612001-11-06 12:03:23 +0000900 newpath = get_path_name(f, newdir, newname);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000901 if (newpath != NULL) {
Miklos Szeredi209f5d02004-07-24 19:56:16 +0000902 if (f->flags & FUSE_DEBUG) {
903 printf("RENAME %s -> %s\n", oldpath, newpath);
904 fflush(stdout);
905 }
Miklos Szeredi5e183482001-10-31 14:52:35 +0000906 res = -ENOSYS;
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000907 if (f->op.rename) {
908 res = 0;
Miklos Szeredi2529ca22004-07-13 15:36:52 +0000909 if (!(f->flags & FUSE_HARD_REMOVE) &&
910 is_open(f, newdir, newname))
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000911 res = hide_node(f, newpath, newdir, newname);
912 if (res == 0) {
913 res = f->op.rename(oldpath, newpath);
914 if (res == 0)
915 rename_node(f, olddir, oldname, newdir, newname, 0);
916 }
917 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000918 free(newpath);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000919 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000920 free(oldpath);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000921 }
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000922 send_reply(f, in, res, NULL, 0);
923}
924
925static void do_link(struct fuse *f, struct fuse_in_header *in,
Miklos Szeredi5e183482001-10-31 14:52:35 +0000926 struct fuse_link_in *arg)
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000927{
928 int res;
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000929 int res2;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000930 char *oldpath;
931 char *newpath;
Miklos Szeredi76f65782004-02-19 16:55:40 +0000932 char *name = PARAM(arg);
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000933 struct fuse_entry_out outarg;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000934
Miklos Szeredi5e183482001-10-31 14:52:35 +0000935 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000936 oldpath = get_path(f, in->ino);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000937 if (oldpath != NULL) {
Miklos Szeredi76f65782004-02-19 16:55:40 +0000938 newpath = get_path_name(f, arg->newdir, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000939 if (newpath != NULL) {
940 if (f->flags & FUSE_DEBUG) {
Miklos Szeredi76f65782004-02-19 16:55:40 +0000941 printf("LINK %s\n", newpath);
942 fflush(stdout);
943 }
Miklos Szeredi5e183482001-10-31 14:52:35 +0000944 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000945 if (f->op.link && f->op.getattr) {
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000946 res = f->op.link(oldpath, newpath);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000947 if (res == 0)
Miklos Szeredi76f65782004-02-19 16:55:40 +0000948 res = lookup_path(f, arg->newdir, in->unique, name,
949 newpath, &outarg);
950 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000951 free(newpath);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000952 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000953 free(oldpath);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000954 }
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000955 res2 = send_reply(f, in, res, &outarg, sizeof(outarg));
956 if (res == 0 && res2 == -ENOENT)
957 destroy_node(f, outarg.ino, in->unique);
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000958}
959
Miklos Szeredi5e183482001-10-31 14:52:35 +0000960static void do_open(struct fuse *f, struct fuse_in_header *in,
961 struct fuse_open_in *arg)
962{
963 int res;
964 char *path;
Miklos Szeredi209f5d02004-07-24 19:56:16 +0000965 struct fuse_open_out outarg;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000966
967 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000968 path = get_path(f, in->ino);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000969 if (path != NULL) {
Miklos Szeredi5e183482001-10-31 14:52:35 +0000970 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000971 if (f->op.open)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000972 res = f->op.open(path, arg->flags);
Miklos Szeredi40b9a5a2002-12-10 16:09:02 +0000973 }
Miklos Szeredi73798f92004-07-12 15:55:11 +0000974 if (res == 0) {
975 int res2;
976
977 /* If the request is interrupted the lock must be held until
978 the cancellation is finished. Otherwise there could be
979 races with rename/unlink, against which the kernel can't
980 protect */
981 pthread_mutex_lock(&f->lock);
Miklos Szeredi209f5d02004-07-24 19:56:16 +0000982 f->fh_ctr ++;
983 outarg.fh = f->fh_ctr;
984 if (f->flags & FUSE_DEBUG) {
985 printf("OPEN[%u] flags: 0x%x\n", outarg.fh, arg->flags);
986 fflush(stdout);
987 }
988
989 res2 = __send_reply(f, in, res, &outarg, sizeof(outarg), 1);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000990 if(res2 == -ENOENT) {
991 /* The open syscall was interrupted, so it must be cancelled */
992 if(f->op.release)
993 f->op.release(path, arg->flags);
Miklos Szeredi73798f92004-07-12 15:55:11 +0000994 } else
995 get_node(f, in->ino)->open_count ++;
996 pthread_mutex_unlock(&f->lock);
997
998 } else
999 send_reply(f, in, res, NULL, 0);
1000
Miklos Szeredi9a31cca2004-06-26 21:11:25 +00001001 if (path)
1002 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001003}
1004
Miklos Szeredi209f5d02004-07-24 19:56:16 +00001005static void do_flush(struct fuse *f, struct fuse_in_header *in,
1006 struct fuse_flush_in *arg)
Miklos Szeredie2e4ac22004-05-18 08:45:28 +00001007{
1008 char *path;
1009 int res;
1010
1011 res = -ENOENT;
1012 path = get_path(f, in->ino);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001013 if (path != NULL) {
Miklos Szeredi209f5d02004-07-24 19:56:16 +00001014 if (f->flags & FUSE_DEBUG) {
1015 printf("FLUSH[%u]\n", arg->fh);
1016 fflush(stdout);
1017 }
Miklos Szeredie2e4ac22004-05-18 08:45:28 +00001018 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001019 if (f->op.flush)
Miklos Szeredie2e4ac22004-05-18 08:45:28 +00001020 res = f->op.flush(path);
1021 free(path);
1022 }
1023 send_reply(f, in, res, NULL, 0);
1024}
1025
Miklos Szeredi9478e862002-12-11 09:50:26 +00001026static void do_release(struct fuse *f, struct fuse_in_header *in,
Miklos Szeredi209f5d02004-07-24 19:56:16 +00001027 struct fuse_release_in *arg)
Miklos Szeredic8ba2372002-12-10 12:26:00 +00001028{
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001029 struct node *node;
1030 char *path;
Miklos Szeredic8ba2372002-12-10 12:26:00 +00001031
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001032 pthread_mutex_lock(&f->lock);
1033 node = get_node(f, in->ino);
1034 --node->open_count;
1035 pthread_mutex_unlock(&f->lock);
1036
1037 path = get_path(f, in->ino);
1038 if (path != NULL) {
Miklos Szeredi209f5d02004-07-24 19:56:16 +00001039 if (f->flags & FUSE_DEBUG) {
1040 printf("RELEASE[%u]\n", arg->fh);
1041 fflush(stdout);
1042 }
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001043 if (f->op.release)
Miklos Szeredib3210582004-06-23 13:54:33 +00001044 f->op.release(path, arg->flags);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001045
1046 if(node->is_hidden && node->open_count == 0)
1047 /* can now clean up this hidden file */
1048 f->op.unlink(path);
1049
1050 free(path);
Miklos Szeredic8ba2372002-12-10 12:26:00 +00001051 }
Miklos Szeredi556d03d2004-06-30 11:13:41 +00001052 send_reply(f, in, 0, NULL, 0);
Miklos Szeredic8ba2372002-12-10 12:26:00 +00001053}
1054
Miklos Szeredi5e183482001-10-31 14:52:35 +00001055static void do_read(struct fuse *f, struct fuse_in_header *in,
1056 struct fuse_read_in *arg)
1057{
1058 int res;
1059 char *path;
Miklos Szeredi43696432001-11-18 19:15:05 +00001060 char *outbuf = (char *) malloc(sizeof(struct fuse_out_header) + arg->size);
1061 struct fuse_out_header *out = (struct fuse_out_header *) outbuf;
1062 char *buf = outbuf + sizeof(struct fuse_out_header);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001063 size_t size;
Miklos Szeredi43696432001-11-18 19:15:05 +00001064 size_t outsize;
Miklos Szeredi5e183482001-10-31 14:52:35 +00001065
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001066 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +00001067 path = get_path(f, in->ino);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001068 if (path != NULL) {
1069 if (f->flags & FUSE_DEBUG) {
Miklos Szeredi209f5d02004-07-24 19:56:16 +00001070 printf("READ[%u] %u bytes from %llu\n", arg->fh, arg->size,
1071 arg->offset);
Miklos Szeredi6ebe2342002-01-06 21:44:16 +00001072 fflush(stdout);
1073 }
1074
Miklos Szeredi5e183482001-10-31 14:52:35 +00001075 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001076 if (f->op.read)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +00001077 res = f->op.read(path, buf, arg->size, arg->offset);
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001078 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001079 }
1080
1081 size = 0;
Miklos Szeredi25385bb2004-07-06 22:27:36 +00001082 if (res >= 0) {
Miklos Szeredi5e183482001-10-31 14:52:35 +00001083 size = res;
1084 res = 0;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001085 if (f->flags & FUSE_DEBUG) {
Miklos Szeredi209f5d02004-07-24 19:56:16 +00001086 printf(" READ[%u] %u bytes\n", arg->fh, size);
Miklos Szeredi6ebe2342002-01-06 21:44:16 +00001087 fflush(stdout);
1088 }
Miklos Szeredi5e183482001-10-31 14:52:35 +00001089 }
Miklos Szeredi0f48a262002-12-05 14:23:01 +00001090 memset(out, 0, sizeof(struct fuse_out_header));
Miklos Szeredi43696432001-11-18 19:15:05 +00001091 out->unique = in->unique;
1092 out->error = res;
1093 outsize = sizeof(struct fuse_out_header) + size;
1094
Miklos Szeredi73798f92004-07-12 15:55:11 +00001095 send_reply_raw(f, outbuf, outsize, 0);
Miklos Szeredi43696432001-11-18 19:15:05 +00001096 free(outbuf);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001097}
Miklos Szeredib483c932001-10-29 14:57:57 +00001098
Miklos Szeredia181e612001-11-06 12:03:23 +00001099static void do_write(struct fuse *f, struct fuse_in_header *in,
1100 struct fuse_write_in *arg)
1101{
1102 int res;
1103 char *path;
Miklos Szerediad051c32004-07-02 09:22:50 +00001104 struct fuse_write_out outarg;
Miklos Szeredia181e612001-11-06 12:03:23 +00001105
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001106 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +00001107 path = get_path(f, in->ino);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001108 if (path != NULL) {
1109 if (f->flags & FUSE_DEBUG) {
Miklos Szeredi209f5d02004-07-24 19:56:16 +00001110 printf("WRITE%s[%u] %u bytes to %llu\n",
1111 arg->writepage ? "PAGE" : "", arg->fh, arg->size,
1112 arg->offset);
Miklos Szeredi6ebe2342002-01-06 21:44:16 +00001113 fflush(stdout);
1114 }
1115
Miklos Szeredia181e612001-11-06 12:03:23 +00001116 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001117 if (f->op.write)
Miklos Szeredi6bf8b682002-10-28 08:49:39 +00001118 res = f->op.write(path, PARAM(arg), arg->size, arg->offset);
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001119 free(path);
Miklos Szeredia181e612001-11-06 12:03:23 +00001120 }
1121
Miklos Szerediad051c32004-07-02 09:22:50 +00001122 if (res >= 0) {
1123 outarg.size = res;
1124 res = 0;
Miklos Szeredia181e612001-11-06 12:03:23 +00001125 }
1126
Miklos Szerediad051c32004-07-02 09:22:50 +00001127 send_reply(f, in, res, &outarg, sizeof(outarg));
Miklos Szeredia181e612001-11-06 12:03:23 +00001128}
1129
Miklos Szeredi77f39942004-03-25 11:17:52 +00001130static int default_statfs(struct statfs *buf)
1131{
1132 buf->f_namelen = 255;
1133 buf->f_bsize = 512;
1134 return 0;
1135}
1136
Miklos Szeredi18e75e42004-02-19 14:23:27 +00001137static void convert_statfs(struct statfs *statfs, struct fuse_kstatfs *kstatfs)
1138{
1139 kstatfs->bsize = statfs->f_bsize;
1140 kstatfs->blocks = statfs->f_blocks;
1141 kstatfs->bfree = statfs->f_bfree;
1142 kstatfs->bavail = statfs->f_bavail;
1143 kstatfs->files = statfs->f_files;
1144 kstatfs->ffree = statfs->f_ffree;
1145 kstatfs->namelen = statfs->f_namelen;
1146}
1147
Mark Glinesd84b39a2002-01-07 16:32:02 +00001148static void do_statfs(struct fuse *f, struct fuse_in_header *in)
1149{
1150 int res;
Mark Glinesd84b39a2002-01-07 16:32:02 +00001151 struct fuse_statfs_out arg;
Miklos Szeredi18e75e42004-02-19 14:23:27 +00001152 struct statfs buf;
Mark Glinesd84b39a2002-01-07 16:32:02 +00001153
Miklos Szeredi77f39942004-03-25 11:17:52 +00001154 memset(&buf, 0, sizeof(struct statfs));
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001155 if (f->op.statfs)
Miklos Szeredi18e75e42004-02-19 14:23:27 +00001156 res = f->op.statfs("/", &buf);
Miklos Szeredi77f39942004-03-25 11:17:52 +00001157 else
1158 res = default_statfs(&buf);
1159
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001160 if (res == 0)
Miklos Szeredi77f39942004-03-25 11:17:52 +00001161 convert_statfs(&buf, &arg.st);
Miklos Szeredi4b2bef42002-01-09 12:23:27 +00001162
Mark Glinesd84b39a2002-01-07 16:32:02 +00001163 send_reply(f, in, res, &arg, sizeof(arg));
1164}
1165
Miklos Szeredi5e43f2c2003-12-12 14:06:41 +00001166static void do_fsync(struct fuse *f, struct fuse_in_header *in,
1167 struct fuse_fsync_in *inarg)
1168{
1169 int res;
1170 char *path;
1171
1172 res = -ENOENT;
1173 path = get_path(f, in->ino);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001174 if (path != NULL) {
Miklos Szeredi209f5d02004-07-24 19:56:16 +00001175 if (f->flags & FUSE_DEBUG) {
1176 printf("FSYNC[%u]\n", inarg->fh);
1177 fflush(stdout);
1178 }
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001179 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001180 if (f->op.fsync)
Miklos Szeredi5e43f2c2003-12-12 14:06:41 +00001181 res = f->op.fsync(path, inarg->datasync);
1182 free(path);
1183 }
1184 send_reply(f, in, res, NULL, 0);
1185}
1186
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001187static void do_setxattr(struct fuse *f, struct fuse_in_header *in,
1188 struct fuse_setxattr_in *arg)
1189{
1190 int res;
1191 char *path;
1192 char *name = PARAM(arg);
1193 unsigned char *value = name + strlen(name) + 1;
1194
1195 res = -ENOENT;
1196 path = get_path(f, in->ino);
1197 if (path != NULL) {
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001198 res = -ENOSYS;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001199 if (f->op.setxattr)
1200 res = f->op.setxattr(path, name, value, arg->size, arg->flags);
1201 free(path);
1202 }
1203 send_reply(f, in, res, NULL, 0);
1204}
1205
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001206static int common_getxattr(struct fuse *f, struct fuse_in_header *in,
1207 const char *name, char *value, size_t size)
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001208{
1209 int res;
1210 char *path;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001211
1212 res = -ENOENT;
1213 path = get_path(f, in->ino);
1214 if (path != NULL) {
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001215 res = -ENOSYS;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001216 if (f->op.getxattr)
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001217 res = f->op.getxattr(path, name, value, size);
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001218 free(path);
1219 }
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001220 return res;
1221}
1222
1223static void do_getxattr_read(struct fuse *f, struct fuse_in_header *in,
1224 const char *name, size_t size)
1225{
1226 int res;
1227 char *outbuf = (char *) malloc(sizeof(struct fuse_out_header) + size);
1228 struct fuse_out_header *out = (struct fuse_out_header *) outbuf;
1229 char *value = outbuf + sizeof(struct fuse_out_header);
1230
1231 res = common_getxattr(f, in, name, value, size);
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001232 size = 0;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001233 if (res > 0) {
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001234 size = res;
1235 res = 0;
1236 }
1237 memset(out, 0, sizeof(struct fuse_out_header));
1238 out->unique = in->unique;
1239 out->error = res;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001240
Miklos Szeredi73798f92004-07-12 15:55:11 +00001241 send_reply_raw(f, outbuf, sizeof(struct fuse_out_header) + size, 0);
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001242 free(outbuf);
1243}
1244
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001245static void do_getxattr_size(struct fuse *f, struct fuse_in_header *in,
1246 const char *name)
1247{
1248 int res;
1249 struct fuse_getxattr_out arg;
1250
1251 res = common_getxattr(f, in, name, NULL, 0);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001252 if (res >= 0) {
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001253 arg.size = res;
1254 res = 0;
1255 }
1256 send_reply(f, in, res, &arg, sizeof(arg));
1257}
1258
1259static void do_getxattr(struct fuse *f, struct fuse_in_header *in,
1260 struct fuse_getxattr_in *arg)
1261{
1262 char *name = PARAM(arg);
1263
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001264 if (arg->size)
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001265 do_getxattr_read(f, in, name, arg->size);
1266 else
1267 do_getxattr_size(f, in, name);
1268}
1269
1270static int common_listxattr(struct fuse *f, struct fuse_in_header *in,
1271 char *list, size_t size)
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001272{
1273 int res;
1274 char *path;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001275
1276 res = -ENOENT;
1277 path = get_path(f, in->ino);
1278 if (path != NULL) {
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001279 res = -ENOSYS;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001280 if (f->op.listxattr)
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001281 res = f->op.listxattr(path, list, size);
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001282 free(path);
1283 }
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001284 return res;
1285}
1286
1287static void do_listxattr_read(struct fuse *f, struct fuse_in_header *in,
1288 size_t size)
1289{
1290 int res;
1291 char *outbuf = (char *) malloc(sizeof(struct fuse_out_header) + size);
1292 struct fuse_out_header *out = (struct fuse_out_header *) outbuf;
1293 char *list = outbuf + sizeof(struct fuse_out_header);
1294
1295 res = common_listxattr(f, in, list, size);
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001296 size = 0;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001297 if (res > 0) {
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001298 size = res;
1299 res = 0;
1300 }
1301 memset(out, 0, sizeof(struct fuse_out_header));
1302 out->unique = in->unique;
1303 out->error = res;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001304
Miklos Szeredi73798f92004-07-12 15:55:11 +00001305 send_reply_raw(f, outbuf, sizeof(struct fuse_out_header) + size, 0);
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001306 free(outbuf);
1307}
1308
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001309static void do_listxattr_size(struct fuse *f, struct fuse_in_header *in)
1310{
1311 int res;
1312 struct fuse_getxattr_out arg;
1313
1314 res = common_listxattr(f, in, NULL, 0);
1315 if (res >= 0) {
1316 arg.size = res;
1317 res = 0;
1318 }
1319 send_reply(f, in, res, &arg, sizeof(arg));
1320}
1321
1322static void do_listxattr(struct fuse *f, struct fuse_in_header *in,
1323 struct fuse_getxattr_in *arg)
1324{
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001325 if (arg->size)
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001326 do_listxattr_read(f, in, arg->size);
1327 else
1328 do_listxattr_size(f, in);
1329}
1330
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001331static void do_removexattr(struct fuse *f, struct fuse_in_header *in,
1332 char *name)
1333{
1334 int res;
1335 char *path;
1336
1337 res = -ENOENT;
1338 path = get_path(f, in->ino);
1339 if (path != NULL) {
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001340 res = -ENOSYS;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001341 if (f->op.removexattr)
1342 res = f->op.removexattr(path, name);
1343 free(path);
1344 }
1345 send_reply(f, in, res, NULL, 0);
1346}
1347
1348
Miklos Szeredi43696432001-11-18 19:15:05 +00001349static void free_cmd(struct fuse_cmd *cmd)
1350{
1351 free(cmd->buf);
1352 free(cmd);
1353}
1354
Miklos Szeredifff56ab2001-11-16 10:12:59 +00001355void __fuse_process_cmd(struct fuse *f, struct fuse_cmd *cmd)
Miklos Szeredia181e612001-11-06 12:03:23 +00001356{
Miklos Szeredia181e612001-11-06 12:03:23 +00001357 struct fuse_in_header *in = (struct fuse_in_header *) cmd->buf;
1358 void *inarg = cmd->buf + sizeof(struct fuse_in_header);
1359 size_t argsize;
Miklos Szeredife25def2001-12-20 15:38:05 +00001360 struct fuse_context *ctx = fuse_get_context(f);
Miklos Szeredia181e612001-11-06 12:03:23 +00001361
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +00001362 dec_avail(f);
Miklos Szeredi33232032001-11-19 17:55:51 +00001363
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001364 if ((f->flags & FUSE_DEBUG)) {
Miklos Szeredic8ba2372002-12-10 12:26:00 +00001365 printf("unique: %i, opcode: %s (%i), ino: %li, insize: %i\n",
1366 in->unique, opname(in->opcode), in->opcode, in->ino,
1367 cmd->buflen);
Miklos Szeredic0938ea2001-11-07 12:35:06 +00001368 fflush(stdout);
1369 }
Miklos Szeredife25def2001-12-20 15:38:05 +00001370
1371 ctx->uid = in->uid;
1372 ctx->gid = in->gid;
Miklos Szeredia181e612001-11-06 12:03:23 +00001373
1374 argsize = cmd->buflen - sizeof(struct fuse_in_header);
1375
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001376 switch (in->opcode) {
Miklos Szeredia181e612001-11-06 12:03:23 +00001377 case FUSE_LOOKUP:
1378 do_lookup(f, in, (char *) inarg);
1379 break;
1380
Miklos Szeredia181e612001-11-06 12:03:23 +00001381 case FUSE_GETATTR:
1382 do_getattr(f, in);
1383 break;
1384
1385 case FUSE_SETATTR:
1386 do_setattr(f, in, (struct fuse_setattr_in *) inarg);
1387 break;
1388
1389 case FUSE_READLINK:
1390 do_readlink(f, in);
1391 break;
1392
1393 case FUSE_GETDIR:
1394 do_getdir(f, in);
1395 break;
1396
1397 case FUSE_MKNOD:
1398 do_mknod(f, in, (struct fuse_mknod_in *) inarg);
1399 break;
1400
1401 case FUSE_MKDIR:
1402 do_mkdir(f, in, (struct fuse_mkdir_in *) inarg);
1403 break;
1404
1405 case FUSE_UNLINK:
Miklos Szeredib5958612004-02-20 14:10:49 +00001406 do_unlink(f, in, (char *) inarg);
1407 break;
1408
Miklos Szeredia181e612001-11-06 12:03:23 +00001409 case FUSE_RMDIR:
Miklos Szeredib5958612004-02-20 14:10:49 +00001410 do_rmdir(f, in, (char *) inarg);
Miklos Szeredia181e612001-11-06 12:03:23 +00001411 break;
1412
1413 case FUSE_SYMLINK:
1414 do_symlink(f, in, (char *) inarg,
1415 ((char *) inarg) + strlen((char *) inarg) + 1);
1416 break;
1417
1418 case FUSE_RENAME:
1419 do_rename(f, in, (struct fuse_rename_in *) inarg);
1420 break;
1421
1422 case FUSE_LINK:
1423 do_link(f, in, (struct fuse_link_in *) inarg);
1424 break;
1425
1426 case FUSE_OPEN:
1427 do_open(f, in, (struct fuse_open_in *) inarg);
1428 break;
1429
Miklos Szeredie2e4ac22004-05-18 08:45:28 +00001430 case FUSE_FLUSH:
Miklos Szeredi209f5d02004-07-24 19:56:16 +00001431 do_flush(f, in, (struct fuse_flush_in *) inarg);
Miklos Szeredie2e4ac22004-05-18 08:45:28 +00001432 break;
1433
Miklos Szeredi9478e862002-12-11 09:50:26 +00001434 case FUSE_RELEASE:
Miklos Szeredi209f5d02004-07-24 19:56:16 +00001435 do_release(f, in, (struct fuse_release_in *) inarg);
Miklos Szeredi9478e862002-12-11 09:50:26 +00001436 break;
1437
Miklos Szeredia181e612001-11-06 12:03:23 +00001438 case FUSE_READ:
1439 do_read(f, in, (struct fuse_read_in *) inarg);
1440 break;
1441
1442 case FUSE_WRITE:
1443 do_write(f, in, (struct fuse_write_in *) inarg);
1444 break;
1445
Mark Glinesd84b39a2002-01-07 16:32:02 +00001446 case FUSE_STATFS:
1447 do_statfs(f, in);
1448 break;
1449
Miklos Szeredi5e43f2c2003-12-12 14:06:41 +00001450 case FUSE_FSYNC:
1451 do_fsync(f, in, (struct fuse_fsync_in *) inarg);
1452 break;
1453
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001454 case FUSE_SETXATTR:
1455 do_setxattr(f, in, (struct fuse_setxattr_in *) inarg);
1456 break;
1457
1458 case FUSE_GETXATTR:
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001459 do_getxattr(f, in, (struct fuse_getxattr_in *) inarg);
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001460 break;
1461
1462 case FUSE_LISTXATTR:
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001463 do_listxattr(f, in, (struct fuse_getxattr_in *) inarg);
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001464 break;
1465
1466 case FUSE_REMOVEXATTR:
1467 do_removexattr(f, in, (char *) inarg);
1468 break;
1469
Miklos Szeredia181e612001-11-06 12:03:23 +00001470 default:
Miklos Szeredi43696432001-11-18 19:15:05 +00001471 send_reply(f, in, -ENOSYS, NULL, 0);
Miklos Szeredia181e612001-11-06 12:03:23 +00001472 }
Miklos Szeredi43696432001-11-18 19:15:05 +00001473
1474 free_cmd(cmd);
Miklos Szeredia181e612001-11-06 12:03:23 +00001475}
1476
Miklos Szeredi65cf7c72004-06-30 11:34:56 +00001477int __fuse_exited(struct fuse* f)
1478{
1479 return f->exited;
1480}
1481
Miklos Szeredifff56ab2001-11-16 10:12:59 +00001482struct fuse_cmd *__fuse_read_cmd(struct fuse *f)
Miklos Szeredi2df1c042001-11-06 15:07:17 +00001483{
Miklos Szeredifff56ab2001-11-16 10:12:59 +00001484 ssize_t res;
Miklos Szeredifff56ab2001-11-16 10:12:59 +00001485 struct fuse_cmd *cmd;
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +00001486 struct fuse_in_header *in;
1487 void *inarg;
Miklos Szeredifff56ab2001-11-16 10:12:59 +00001488
Miklos Szeredi43696432001-11-18 19:15:05 +00001489 cmd = (struct fuse_cmd *) malloc(sizeof(struct fuse_cmd));
1490 cmd->buf = (char *) malloc(FUSE_MAX_IN);
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +00001491 in = (struct fuse_in_header *) cmd->buf;
1492 inarg = cmd->buf + sizeof(struct fuse_in_header);
Miklos Szeredi43696432001-11-18 19:15:05 +00001493
Miklos Szeredi65cf7c72004-06-30 11:34:56 +00001494 res = read(f->fd, cmd->buf, FUSE_MAX_IN);
1495 if (res == -1) {
1496 free_cmd(cmd);
1497 if (__fuse_exited(f) || errno == EINTR)
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +00001498 return NULL;
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +00001499
Miklos Szeredi65cf7c72004-06-30 11:34:56 +00001500 /* ENODEV means we got unmounted, so we silenty return failure */
1501 if (errno != ENODEV) {
1502 /* BAD... This will happen again */
1503 perror("fuse: reading device");
1504 }
1505
1506 fuse_exit(f);
1507 return NULL;
1508 }
1509 if ((size_t) res < sizeof(struct fuse_in_header)) {
1510 free_cmd(cmd);
1511 /* Cannot happen */
1512 fprintf(stderr, "short read on fuse device\n");
1513 fuse_exit(f);
1514 return NULL;
1515 }
1516 cmd->buflen = res;
1517
1518 /* Forget is special, it can be done without messing with threads. */
1519 if (in->opcode == FUSE_FORGET) {
1520 do_forget(f, in, (struct fuse_forget_in *) inarg);
1521 free_cmd(cmd);
1522 return NULL;
1523 }
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +00001524
Miklos Szeredifff56ab2001-11-16 10:12:59 +00001525 return cmd;
Miklos Szeredi2df1c042001-11-06 15:07:17 +00001526}
1527
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001528void fuse_loop(struct fuse *f)
1529{
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001530 if (f == NULL)
Miklos Szeredic40748a2004-02-20 16:38:45 +00001531 return;
1532
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001533 while (1) {
Miklos Szeredi0f48a262002-12-05 14:23:01 +00001534 struct fuse_cmd *cmd;
1535
Miklos Szeredi65cf7c72004-06-30 11:34:56 +00001536 if (__fuse_exited(f))
Miklos Szeredi0f48a262002-12-05 14:23:01 +00001537 return;
1538
1539 cmd = __fuse_read_cmd(f);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001540 if (cmd == NULL)
Miklos Szeredi0f48a262002-12-05 14:23:01 +00001541 continue;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001542
Miklos Szeredifff56ab2001-11-16 10:12:59 +00001543 __fuse_process_cmd(f, cmd);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001544 }
1545}
1546
Miklos Szeredi0f48a262002-12-05 14:23:01 +00001547void fuse_exit(struct fuse *f)
1548{
1549 f->exited = 1;
1550}
1551
Miklos Szeredi2e50d432001-12-20 12:17:25 +00001552struct fuse_context *fuse_get_context(struct fuse *f)
1553{
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001554 if (f->getcontext)
Miklos Szeredi2e50d432001-12-20 12:17:25 +00001555 return f->getcontext(f);
1556 else
1557 return &f->context;
1558}
1559
Miklos Szeredic40748a2004-02-20 16:38:45 +00001560static int check_version(struct fuse *f)
1561{
1562 int res;
1563 FILE *vf = fopen(FUSE_VERSION_FILE, "r");
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001564 if (vf == NULL) {
Miklos Szeredic40748a2004-02-20 16:38:45 +00001565 fprintf(stderr, "fuse: kernel interface too old, need >= %i.%i\n",
1566 FUSE_KERNEL_VERSION, FUSE_KERNEL_MINOR_VERSION);
1567 return -1;
1568 }
1569 res = fscanf(vf, "%i.%i", &f->majorver, &f->minorver);
1570 fclose(vf);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001571 if (res != 2) {
Miklos Szeredic40748a2004-02-20 16:38:45 +00001572 fprintf(stderr, "fuse: error reading %s\n", FUSE_VERSION_FILE);
1573 return -1;
1574 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001575 if (f->majorver != FUSE_KERNEL_VERSION) {
Miklos Szeredic40748a2004-02-20 16:38:45 +00001576 fprintf(stderr, "fuse: bad kernel interface major version: needs %i\n",
1577 FUSE_KERNEL_VERSION);
1578 return -1;
1579 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001580 if (f->minorver < FUSE_KERNEL_MINOR_VERSION) {
Miklos Szeredic40748a2004-02-20 16:38:45 +00001581 fprintf(stderr, "fuse: kernel interface too old: need >= %i.%i",
1582 FUSE_KERNEL_VERSION, FUSE_KERNEL_MINOR_VERSION);
1583 return -1;
1584 }
1585
1586 return 0;
1587}
1588
Miklos Szeredibd7661b2004-07-23 17:16:29 +00001589
1590int fuse_is_lib_option(const char *opt)
1591{
1592 if (strcmp(opt, "debug") == 0 ||
1593 strcmp(opt, "hard_remove") == 0)
1594 return 1;
1595 else
1596 return 0;
1597}
1598
1599static void parse_lib_opts(struct fuse *f, const char *opts)
1600{
1601 if (opts) {
1602 char *xopts = strdup(opts);
1603 char *s = xopts;
1604 char *opt;
1605
1606 while((opt = strsep(&s, ","))) {
1607 if (strcmp(opt, "debug") == 0)
1608 f->flags |= FUSE_DEBUG;
1609 else if (strcmp(opt, "hard_remove") == 0)
1610 f->flags |= FUSE_HARD_REMOVE;
1611 else
1612 fprintf(stderr, "fuse: warning: unknown option `%s'\n", opt);
1613 }
1614 free(xopts);
1615 }
1616}
1617
1618struct fuse *fuse_new(int fd, const char *opts, const struct fuse_operations *op)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001619{
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001620 struct fuse *f;
1621 struct node *root;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001622
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001623 f = (struct fuse *) calloc(1, sizeof(struct fuse));
Miklos Szeredi2df1c042001-11-06 15:07:17 +00001624
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001625 if (check_version(f) == -1) {
Miklos Szeredic40748a2004-02-20 16:38:45 +00001626 free(f);
1627 return NULL;
1628 }
1629
Miklos Szeredibd7661b2004-07-23 17:16:29 +00001630 parse_lib_opts(f, opts);
Miklos Szeredi8cffdb92001-11-09 14:49:18 +00001631 f->fd = fd;
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001632 f->ctr = 0;
Miklos Szeredi76f65782004-02-19 16:55:40 +00001633 f->generation = 0;
Miklos Szeredifff56ab2001-11-16 10:12:59 +00001634 /* FIXME: Dynamic hash table */
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001635 f->name_table_size = 14057;
1636 f->name_table = (struct node **)
1637 calloc(1, sizeof(struct node *) * f->name_table_size);
1638 f->ino_table_size = 14057;
1639 f->ino_table = (struct node **)
1640 calloc(1, sizeof(struct node *) * f->ino_table_size);
Miklos Szeredia181e612001-11-06 12:03:23 +00001641 pthread_mutex_init(&f->lock, NULL);
Miklos Szeredi33232032001-11-19 17:55:51 +00001642 f->numworker = 0;
1643 f->numavail = 0;
Miklos Szeredi2e50d432001-12-20 12:17:25 +00001644 f->op = *op;
1645 f->getcontext = NULL;
1646 f->context.uid = 0;
1647 f->context.gid = 0;
Miklos Szeredi0f48a262002-12-05 14:23:01 +00001648 f->exited = 0;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001649
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001650 root = (struct node *) calloc(1, sizeof(struct node));
Miklos Szeredi8cffdb92001-11-09 14:49:18 +00001651 root->mode = 0;
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001652 root->rdev = 0;
1653 root->name = strdup("/");
1654 root->parent = 0;
Miklos Szeredi76f65782004-02-19 16:55:40 +00001655 root->ino = FUSE_ROOT_INO;
1656 root->generation = 0;
1657 hash_ino(f, root);
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001658
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001659 return f;
1660}
1661
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001662void fuse_destroy(struct fuse *f)
1663{
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001664 size_t i;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001665 for (i = 0; i < f->ino_table_size; i++) {
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001666 struct node *node;
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001667
1668 for (node = f->ino_table[i]; node != NULL; node = node->ino_next) {
1669 if (node->is_hidden) {
1670 char *path = get_path(f, node->ino);
1671 if (path)
1672 f->op.unlink(path);
1673 }
1674 }
1675 }
1676 for (i = 0; i < f->ino_table_size; i++) {
1677 struct node *node;
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001678 struct node *next;
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001679
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001680 for (node = f->ino_table[i]; node != NULL; node = next) {
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001681 next = node->ino_next;
1682 free_node(node);
1683 }
1684 }
1685 free(f->ino_table);
1686 free(f->name_table);
Miklos Szeredia181e612001-11-06 12:03:23 +00001687 pthread_mutex_destroy(&f->lock);
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001688 free(f);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001689}