blob: 8e801b8ff3d6c4f66a48e7d8a4f5ac4d9f4ff8eb [file] [log] [blame]
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001/*
2 FUSE: Filesystem in Userspace
Miklos Szeredi611ad932007-04-25 16:19:15 +00003 Copyright (C) 2001-2007 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 Szeredie2aa2e22005-07-15 13:31:36 +00009
10/* For pthread_rwlock_t */
11#define _GNU_SOURCE
12
Miklos Szeredi178451d2005-08-15 13:19:07 +000013#include "fuse_i.h"
Miklos Szeredie2aa2e22005-07-15 13:31:36 +000014#include "fuse_lowlevel.h"
Miklos Szeredi659743b2005-12-09 17:41:42 +000015#include "fuse_opt.h"
Miklos Szeredi38f152c2006-09-03 18:28:52 +000016#include "fuse_misc.h"
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +000017#include "fuse_common_compat.h"
18#include "fuse_compat.h"
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000019
Miklos Szeredi0f62d722005-01-04 12:45:54 +000020#include <stdio.h>
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000021#include <string.h>
Miklos Szeredi97c61e92001-11-07 12:09:43 +000022#include <stdlib.h>
Miklos Szeredi659743b2005-12-09 17:41:42 +000023#include <stddef.h>
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000024#include <unistd.h>
Miklos Szeredi320abe42006-01-30 18:14:51 +000025#include <time.h>
Miklos Szeredib3f99722005-11-16 13:00:24 +000026#include <fcntl.h>
Miklos Szeredi97c61e92001-11-07 12:09:43 +000027#include <limits.h>
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000028#include <errno.h>
Miklos Szeredi288ed4e2006-09-07 06:02:44 +000029#include <signal.h>
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +000030#include <dlfcn.h>
Miklos Szeredi0f62d722005-01-04 12:45:54 +000031#include <assert.h>
Miklos Szeredi019b4e92001-12-26 18:08:09 +000032#include <sys/param.h>
Miklos Szerediab974562005-04-07 15:40:21 +000033#include <sys/uio.h>
Miklos Szeredi288ed4e2006-09-07 06:02:44 +000034#include <sys/time.h>
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000035
Miklos Szeredi97c61e92001-11-07 12:09:43 +000036#define FUSE_MAX_PATH 4096
Miklos Szeredi288ed4e2006-09-07 06:02:44 +000037#define FUSE_DEFAULT_INTR_SIGNAL SIGUSR1
Miklos Szeredi30e093a2005-04-03 17:44:54 +000038
Miklos Szeredie248e4b2005-12-14 16:18:32 +000039#define FUSE_UNKNOWN_INO 0xffffffff
Miklos Szeredi0c59ebf2006-09-10 20:53:36 +000040#define OFFSET_MAX 0x7fffffffffffffffLL
Miklos Szeredie248e4b2005-12-14 16:18:32 +000041
Miklos Szeredi659743b2005-12-09 17:41:42 +000042struct fuse_config {
Miklos Szeredi659743b2005-12-09 17:41:42 +000043 unsigned int uid;
44 unsigned int gid;
45 unsigned int umask;
46 double entry_timeout;
47 double negative_timeout;
48 double attr_timeout;
Miklos Szeredi6e806e92006-02-16 16:59:39 +000049 double ac_attr_timeout;
50 int ac_attr_timeout_set;
Miklos Szeredi659743b2005-12-09 17:41:42 +000051 int debug;
52 int hard_remove;
53 int use_ino;
54 int readdir_ino;
55 int set_mode;
56 int set_uid;
57 int set_gid;
58 int direct_io;
59 int kernel_cache;
Miklos Szeredi320abe42006-01-30 18:14:51 +000060 int auto_cache;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +000061 int intr;
62 int intr_signal;
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +000063 int help;
64 char *modules;
65};
66
67struct fuse_fs {
68 struct fuse_operations op;
69 struct fuse_module *m;
70 void *user_data;
71 int compat;
72};
73
74struct fusemod_so {
75 void *handle;
76 int ctr;
Miklos Szeredi659743b2005-12-09 17:41:42 +000077};
78
Miklos Szeredie2aa2e22005-07-15 13:31:36 +000079struct fuse {
Miklos Szeredia1482422005-08-14 23:00:27 +000080 struct fuse_session *se;
Miklos Szeredie2aa2e22005-07-15 13:31:36 +000081 struct node **name_table;
82 size_t name_table_size;
83 struct node **id_table;
84 size_t id_table_size;
85 fuse_ino_t ctr;
86 unsigned int generation;
87 unsigned int hidectr;
88 pthread_mutex_t lock;
89 pthread_rwlock_t tree_lock;
Miklos Szeredi659743b2005-12-09 17:41:42 +000090 struct fuse_config conf;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +000091 int intr_installed;
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +000092 struct fuse_fs *fs;
Miklos Szeredie2aa2e22005-07-15 13:31:36 +000093};
94
Miklos Szeredi0c59ebf2006-09-10 20:53:36 +000095struct lock {
96 int type;
97 off_t start;
98 off_t end;
99 pid_t pid;
100 uint64_t owner;
101 struct lock *next;
102};
103
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000104struct node {
105 struct node *name_next;
106 struct node *id_next;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000107 fuse_ino_t nodeid;
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000108 unsigned int generation;
109 int refctr;
Miklos Szeredi7bc05b02007-05-29 23:08:11 +0000110 struct node *parent;
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000111 char *name;
Miklos Szeredi38009022005-05-08 19:47:22 +0000112 uint64_t nlookup;
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000113 int open_count;
114 int is_hidden;
Miklos Szeredi320abe42006-01-30 18:14:51 +0000115 struct timespec stat_updated;
116 struct timespec mtime;
117 off_t size;
118 int cache_valid;
Miklos Szeredi0c59ebf2006-09-10 20:53:36 +0000119 struct lock *locks;
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000120};
121
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +0000122struct fuse_dh {
Miklos Szerediab974562005-04-07 15:40:21 +0000123 pthread_mutex_t lock;
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000124 struct fuse *fuse;
Miklos Szeredi1bf64f42006-02-17 15:49:25 +0000125 fuse_req_t req;
Miklos Szeredi1b188022005-07-28 11:07:29 +0000126 char *contents;
Miklos Szerediab974562005-04-07 15:40:21 +0000127 int allocated;
Miklos Szeredib92d9782005-02-07 16:10:49 +0000128 unsigned len;
Miklos Szeredic4c12ae2005-10-20 14:48:50 +0000129 unsigned size;
Miklos Szerediab974562005-04-07 15:40:21 +0000130 unsigned needlen;
Miklos Szeredi3ead28e2005-01-18 21:23:41 +0000131 int filled;
Miklos Szeredi3a770472005-11-11 21:32:42 +0000132 uint64_t fh;
Miklos Szerediab974562005-04-07 15:40:21 +0000133 int error;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000134 fuse_ino_t nodeid;
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000135};
136
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +0000137/* old dir handle */
138struct fuse_dirhandle {
139 fuse_fill_dir_t filler;
140 void *buf;
141};
142
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000143struct fuse_context_i {
144 struct fuse_context ctx;
145 fuse_req_t req;
146};
Miklos Szeredid169f312004-09-22 08:48:26 +0000147
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000148static pthread_key_t fuse_context_key;
149static pthread_mutex_t fuse_context_lock = PTHREAD_MUTEX_INITIALIZER;
150static int fuse_context_ref;
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +0000151static struct fusemod_so *fuse_current_so;
152static struct fuse_module *fuse_modules;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000153
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +0000154static int fuse_load_so_name(const char *soname)
155{
156 struct fusemod_so *so;
157
158 so = calloc(1, sizeof(struct fusemod_so));
159 if (!so) {
160 fprintf(stderr, "fuse: memory allocation failed\n");
161 return -1;
162 }
163
164 pthread_mutex_lock(&fuse_context_lock);
165 fuse_current_so = so;
166 so->handle = dlopen(soname, RTLD_NOW);
167 fuse_current_so = NULL;
168 pthread_mutex_unlock(&fuse_context_lock);
169 if (!so->handle) {
170 fprintf(stderr, "fuse: %s\n", dlerror());
171 goto err;
172 }
173 if (!so->ctr) {
174 fprintf(stderr, "fuse: %s did not register any modules", soname);
175 goto err;
176 }
177 return 0;
178
179 err:
180 if (so->handle)
181 dlclose(so->handle);
182 free(so);
183 return -1;
184}
185
186static int fuse_load_so_module(const char *module)
187{
188 int res;
189 char *soname = malloc(strlen(module) + 64);
190 if (!soname) {
191 fprintf(stderr, "fuse: memory allocation failed\n");
192 return -1;
193 }
194 if (soname)
195 sprintf(soname, "libfusemod_%s.so", module);
196
197 res = fuse_load_so_name(soname);
198 free(soname);
199 return res;
200}
201
202static struct fuse_module *fuse_find_module(const char *module)
203{
204 struct fuse_module *m;
205 for (m = fuse_modules; m; m = m->next) {
206 if (strcmp(module, m->name) == 0) {
207 m->ctr++;
208 break;
209 }
210 }
211 return m;
212}
213
214static struct fuse_module *fuse_get_module(const char *module)
215{
216 struct fuse_module *m;
217
218 pthread_mutex_lock(&fuse_context_lock);
219 m = fuse_find_module(module);
220 if (!m) {
221 int err = fuse_load_so_module(module);
222 if (!err)
223 m = fuse_find_module(module);
224 }
225 pthread_mutex_unlock(&fuse_context_lock);
226 return m;
227}
228
229static void fuse_put_module(struct fuse_module *m)
230{
231 pthread_mutex_lock(&fuse_context_lock);
232 assert(m->ctr > 0);
233 m->ctr--;
234 if (!m->ctr && m->so) {
235 struct fusemod_so *so = m->so;
236 assert(so->ctr > 0);
237 so->ctr--;
238 if (!so->ctr) {
239 struct fuse_module **mp;
240 for (mp = &fuse_modules; *mp;) {
241 if ((*mp)->so == so)
242 *mp = (*mp)->next;
243 else
244 mp = &(*mp)->next;
245 }
246 dlclose(so->handle);
247 free(so);
248 }
249 }
250 pthread_mutex_unlock(&fuse_context_lock);
251}
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +0000252
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000253static struct node *get_node_nocheck(struct fuse *f, fuse_ino_t nodeid)
Miklos Szeredia181e612001-11-06 12:03:23 +0000254{
Miklos Szeredia13d9002004-11-02 17:32:03 +0000255 size_t hash = nodeid % f->id_table_size;
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000256 struct node *node;
257
Miklos Szeredia13d9002004-11-02 17:32:03 +0000258 for (node = f->id_table[hash]; node != NULL; node = node->id_next)
259 if (node->nodeid == nodeid)
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000260 return node;
Miklos Szeredie5183742005-02-02 11:14:04 +0000261
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000262 return NULL;
Miklos Szeredia181e612001-11-06 12:03:23 +0000263}
264
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000265static struct node *get_node(struct fuse *f, fuse_ino_t nodeid)
Miklos Szeredia181e612001-11-06 12:03:23 +0000266{
Miklos Szeredif458b8c2004-12-07 16:46:42 +0000267 struct node *node = get_node_nocheck(f, nodeid);
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000268 if (!node) {
Miklos Szeredi3a770472005-11-11 21:32:42 +0000269 fprintf(stderr, "fuse internal error: node %llu not found\n",
270 (unsigned long long) nodeid);
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000271 abort();
272 }
273 return node;
Miklos Szeredia181e612001-11-06 12:03:23 +0000274}
275
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000276static void free_node(struct node *node)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000277{
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000278 free(node->name);
279 free(node);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000280}
281
Miklos Szeredia13d9002004-11-02 17:32:03 +0000282static void unhash_id(struct fuse *f, struct node *node)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000283{
Miklos Szeredia13d9002004-11-02 17:32:03 +0000284 size_t hash = node->nodeid % f->id_table_size;
285 struct node **nodep = &f->id_table[hash];
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000286
Miklos Szeredie5183742005-02-02 11:14:04 +0000287 for (; *nodep != NULL; nodep = &(*nodep)->id_next)
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000288 if (*nodep == node) {
Miklos Szeredia13d9002004-11-02 17:32:03 +0000289 *nodep = node->id_next;
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000290 return;
291 }
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000292}
293
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000294static void hash_id(struct fuse *f, struct node *node)
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000295{
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000296 size_t hash = node->nodeid % f->id_table_size;
297 node->id_next = f->id_table[hash];
Miklos Szeredie5183742005-02-02 11:14:04 +0000298 f->id_table[hash] = node;
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000299}
300
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +0000301static unsigned int name_hash(struct fuse *f, fuse_ino_t parent,
302 const char *name)
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000303{
304 unsigned int hash = *name;
305
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000306 if (hash)
307 for (name += 1; *name != '\0'; name++)
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000308 hash = (hash << 5) - hash + *name;
309
310 return (hash + parent) % f->name_table_size;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000311}
312
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000313static void unref_node(struct fuse *f, struct node *node);
314
315static void unhash_name(struct fuse *f, struct node *node)
316{
317 if (node->name) {
Miklos Szeredi7bc05b02007-05-29 23:08:11 +0000318 size_t hash = name_hash(f, node->parent->nodeid, node->name);
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000319 struct node **nodep = &f->name_table[hash];
Miklos Szeredie5183742005-02-02 11:14:04 +0000320
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000321 for (; *nodep != NULL; nodep = &(*nodep)->name_next)
322 if (*nodep == node) {
323 *nodep = node->name_next;
324 node->name_next = NULL;
Miklos Szeredi7bc05b02007-05-29 23:08:11 +0000325 unref_node(f, node->parent);
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000326 free(node->name);
327 node->name = NULL;
Miklos Szeredi7bc05b02007-05-29 23:08:11 +0000328 node->parent = NULL;
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000329 return;
330 }
Miklos Szeredi3a770472005-11-11 21:32:42 +0000331 fprintf(stderr, "fuse internal error: unable to unhash node: %llu\n",
332 (unsigned long long) node->nodeid);
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000333 abort();
334 }
335}
336
Miklos Szeredi7bc05b02007-05-29 23:08:11 +0000337static int hash_name(struct fuse *f, struct node *node, fuse_ino_t parentid,
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000338 const char *name)
339{
Miklos Szeredi7bc05b02007-05-29 23:08:11 +0000340 size_t hash = name_hash(f, parentid, name);
341 struct node *parent = get_node(f, parentid);
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000342 node->name = strdup(name);
343 if (node->name == NULL)
344 return -1;
345
Miklos Szeredi7bc05b02007-05-29 23:08:11 +0000346 parent->refctr ++;
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000347 node->parent = parent;
348 node->name_next = f->name_table[hash];
349 f->name_table[hash] = node;
350 return 0;
351}
352
353static void delete_node(struct fuse *f, struct node *node)
354{
Miklos Szeredi659743b2005-12-09 17:41:42 +0000355 if (f->conf.debug) {
Miklos Szeredi3a770472005-11-11 21:32:42 +0000356 printf("delete: %llu\n", (unsigned long long) node->nodeid);
Miklos Szeredi38009022005-05-08 19:47:22 +0000357 fflush(stdout);
358 }
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000359 assert(!node->name);
360 unhash_id(f, node);
361 free_node(node);
362}
363
364static void unref_node(struct fuse *f, struct node *node)
365{
366 assert(node->refctr > 0);
367 node->refctr --;
368 if (!node->refctr)
369 delete_node(f, node);
370}
371
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000372static fuse_ino_t next_id(struct fuse *f)
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000373{
374 do {
Miklos Szeredi7e7fa1f2006-10-08 15:41:20 +0000375 f->ctr = (f->ctr + 1) & 0xffffffff;
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000376 if (!f->ctr)
377 f->generation ++;
Miklos Szeredi7e7fa1f2006-10-08 15:41:20 +0000378 } while (f->ctr == 0 || f->ctr == FUSE_UNKNOWN_INO ||
379 get_node_nocheck(f, f->ctr) != NULL);
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000380 return f->ctr;
381}
382
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000383static struct node *lookup_node(struct fuse *f, fuse_ino_t parent,
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000384 const char *name)
385{
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000386 size_t hash = name_hash(f, parent, name);
387 struct node *node;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000388
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000389 for (node = f->name_table[hash]; node != NULL; node = node->name_next)
Miklos Szeredi7bc05b02007-05-29 23:08:11 +0000390 if (node->parent->nodeid == parent && strcmp(node->name, name) == 0)
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000391 return node;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000392
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000393 return NULL;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000394}
395
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000396static struct node *find_node(struct fuse *f, fuse_ino_t parent,
397 const char *name)
Miklos Szeredi5e183482001-10-31 14:52:35 +0000398{
399 struct node *node;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000400
Miklos Szeredia181e612001-11-06 12:03:23 +0000401 pthread_mutex_lock(&f->lock);
Miklos Szeredif458b8c2004-12-07 16:46:42 +0000402 node = lookup_node(f, parent, name);
Miklos Szeredie331c4b2005-07-06 13:34:02 +0000403 if (node == NULL) {
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000404 node = (struct node *) calloc(1, sizeof(struct node));
405 if (node == NULL)
406 goto out_err;
Miklos Szeredie5183742005-02-02 11:14:04 +0000407
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000408 node->refctr = 1;
409 node->nodeid = next_id(f);
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000410 node->open_count = 0;
411 node->is_hidden = 0;
412 node->generation = f->generation;
413 if (hash_name(f, node, parent, name) == -1) {
414 free(node);
415 node = NULL;
416 goto out_err;
417 }
418 hash_id(f, node);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000419 }
Miklos Szeredi38009022005-05-08 19:47:22 +0000420 node->nlookup ++;
Miklos Szeredic2309912004-09-21 13:40:38 +0000421 out_err:
Miklos Szeredia181e612001-11-06 12:03:23 +0000422 pthread_mutex_unlock(&f->lock);
Miklos Szeredi76f65782004-02-19 16:55:40 +0000423 return node;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000424}
425
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000426static char *add_name(char *buf, char *s, const char *name)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000427{
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000428 size_t len = strlen(name);
429 s -= len;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000430 if (s <= buf) {
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000431 fprintf(stderr, "fuse: path too long: ...%s\n", s + len);
432 return NULL;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000433 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000434 strncpy(s, name, len);
435 s--;
436 *s = '/';
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000437
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000438 return s;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000439}
440
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000441static char *get_path_name(struct fuse *f, fuse_ino_t nodeid, const char *name)
Miklos Szeredib483c932001-10-29 14:57:57 +0000442{
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000443 char buf[FUSE_MAX_PATH];
444 char *s = buf + FUSE_MAX_PATH - 1;
445 struct node *node;
Miklos Szeredie5183742005-02-02 11:14:04 +0000446
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000447 *s = '\0';
Miklos Szeredia181e612001-11-06 12:03:23 +0000448
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000449 if (name != NULL) {
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000450 s = add_name(buf, s, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000451 if (s == NULL)
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000452 return NULL;
453 }
454
455 pthread_mutex_lock(&f->lock);
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000456 for (node = get_node(f, nodeid); node && node->nodeid != FUSE_ROOT_ID;
Miklos Szeredi7bc05b02007-05-29 23:08:11 +0000457 node = node->parent) {
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000458 if (node->name == NULL) {
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000459 s = NULL;
460 break;
461 }
Miklos Szeredie5183742005-02-02 11:14:04 +0000462
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000463 s = add_name(buf, s, node->name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000464 if (s == NULL)
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000465 break;
466 }
467 pthread_mutex_unlock(&f->lock);
468
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000469 if (node == NULL || s == NULL)
Miklos Szeredi5e183482001-10-31 14:52:35 +0000470 return NULL;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000471 else if (*s == '\0')
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000472 return strdup("/");
473 else
474 return strdup(s);
475}
Miklos Szeredia181e612001-11-06 12:03:23 +0000476
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000477static char *get_path(struct fuse *f, fuse_ino_t nodeid)
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000478{
Miklos Szeredia13d9002004-11-02 17:32:03 +0000479 return get_path_name(f, nodeid, NULL);
Miklos Szeredib483c932001-10-29 14:57:57 +0000480}
481
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000482static void forget_node(struct fuse *f, fuse_ino_t nodeid, uint64_t nlookup)
Miklos Szeredi38009022005-05-08 19:47:22 +0000483{
484 struct node *node;
485 if (nodeid == FUSE_ROOT_ID)
486 return;
487 pthread_mutex_lock(&f->lock);
488 node = get_node(f, nodeid);
489 assert(node->nlookup >= nlookup);
490 node->nlookup -= nlookup;
491 if (!node->nlookup) {
492 unhash_name(f, node);
493 unref_node(f, node);
494 }
495 pthread_mutex_unlock(&f->lock);
496}
497
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000498static void remove_node(struct fuse *f, fuse_ino_t dir, const char *name)
Miklos Szeredi5e183482001-10-31 14:52:35 +0000499{
Miklos Szeredia181e612001-11-06 12:03:23 +0000500 struct node *node;
501
502 pthread_mutex_lock(&f->lock);
Miklos Szeredif458b8c2004-12-07 16:46:42 +0000503 node = lookup_node(f, dir, name);
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000504 if (node != NULL)
505 unhash_name(f, node);
Miklos Szeredia181e612001-11-06 12:03:23 +0000506 pthread_mutex_unlock(&f->lock);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000507}
508
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000509static int rename_node(struct fuse *f, fuse_ino_t olddir, const char *oldname,
510 fuse_ino_t newdir, const char *newname, int hide)
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000511{
Miklos Szeredia181e612001-11-06 12:03:23 +0000512 struct node *node;
513 struct node *newnode;
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000514 int err = 0;
Miklos Szeredie5183742005-02-02 11:14:04 +0000515
Miklos Szeredia181e612001-11-06 12:03:23 +0000516 pthread_mutex_lock(&f->lock);
Miklos Szeredif458b8c2004-12-07 16:46:42 +0000517 node = lookup_node(f, olddir, oldname);
518 newnode = lookup_node(f, newdir, newname);
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000519 if (node == NULL)
520 goto out;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000521
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000522 if (newnode != NULL) {
523 if (hide) {
524 fprintf(stderr, "fuse: hidden file got created during hiding\n");
Miklos Szeredib2cf9562004-09-16 08:42:40 +0000525 err = -EBUSY;
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000526 goto out;
527 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000528 unhash_name(f, newnode);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000529 }
Miklos Szeredie5183742005-02-02 11:14:04 +0000530
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000531 unhash_name(f, node);
Miklos Szeredib2cf9562004-09-16 08:42:40 +0000532 if (hash_name(f, node, newdir, newname) == -1) {
533 err = -ENOMEM;
534 goto out;
535 }
Miklos Szeredie5183742005-02-02 11:14:04 +0000536
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000537 if (hide)
538 node->is_hidden = 1;
539
540 out:
Miklos Szeredia181e612001-11-06 12:03:23 +0000541 pthread_mutex_unlock(&f->lock);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000542 return err;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000543}
544
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000545static void set_stat(struct fuse *f, fuse_ino_t nodeid, struct stat *stbuf)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000546{
Miklos Szeredi659743b2005-12-09 17:41:42 +0000547 if (!f->conf.use_ino)
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000548 stbuf->st_ino = nodeid;
Miklos Szeredi659743b2005-12-09 17:41:42 +0000549 if (f->conf.set_mode)
550 stbuf->st_mode = (stbuf->st_mode & S_IFMT) | (0777 & ~f->conf.umask);
551 if (f->conf.set_uid)
552 stbuf->st_uid = f->conf.uid;
553 if (f->conf.set_gid)
554 stbuf->st_gid = f->conf.gid;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000555}
556
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000557static struct fuse *req_fuse(fuse_req_t req)
558{
559 return (struct fuse *) fuse_req_userdata(req);
560}
561
562static void fuse_intr_sighandler(int sig)
563{
564 (void) sig;
565 /* Nothing to do */
566}
567
568struct fuse_intr_data {
569 pthread_t id;
570 pthread_cond_t cond;
571 int finished;
572};
573
574static void fuse_interrupt(fuse_req_t req, void *d_)
575{
576 struct fuse_intr_data *d = d_;
577 struct fuse *f = req_fuse(req);
578
579 if (d->id == pthread_self())
580 return;
581
582 pthread_mutex_lock(&f->lock);
583 while (!d->finished) {
584 struct timeval now;
585 struct timespec timeout;
586
587 pthread_kill(d->id, f->conf.intr_signal);
588 gettimeofday(&now, NULL);
589 timeout.tv_sec = now.tv_sec + 1;
590 timeout.tv_nsec = now.tv_usec * 1000;
591 pthread_cond_timedwait(&d->cond, &f->lock, &timeout);
592 }
593 pthread_mutex_unlock(&f->lock);
594}
595
596static void fuse_do_finish_interrupt(struct fuse *f, fuse_req_t req,
597 struct fuse_intr_data *d)
598{
599 pthread_mutex_lock(&f->lock);
600 d->finished = 1;
601 pthread_cond_broadcast(&d->cond);
602 pthread_mutex_unlock(&f->lock);
603 fuse_req_interrupt_func(req, NULL, NULL);
604 pthread_cond_destroy(&d->cond);
605}
606
607static void fuse_do_prepare_interrupt(fuse_req_t req, struct fuse_intr_data *d)
608{
609 d->id = pthread_self();
610 pthread_cond_init(&d->cond, NULL);
611 d->finished = 0;
612 fuse_req_interrupt_func(req, fuse_interrupt, d);
613}
614
615static inline void fuse_finish_interrupt(struct fuse *f, fuse_req_t req,
616 struct fuse_intr_data *d)
617{
618 if (f->conf.intr)
619 fuse_do_finish_interrupt(f, req, d);
620}
621
622static inline void fuse_prepare_interrupt(struct fuse *f, fuse_req_t req,
623 struct fuse_intr_data *d)
624{
625 if (f->conf.intr)
626 fuse_do_prepare_interrupt(req, d);
627}
628
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +0000629#ifndef __FreeBSD__
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000630
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +0000631static int fuse_compat_open(struct fuse_fs *fs, const char *path,
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000632 struct fuse_file_info *fi)
633{
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +0000634 int err;
635 if (!fs->compat || fs->compat >= 25)
636 err = fs->op.open(path, fi);
637 else if (fs->compat == 22) {
638 struct fuse_file_info_compat tmp;
639 memcpy(&tmp, fi, sizeof(tmp));
640 err = ((struct fuse_operations_compat22 *) &fs->op)->open(path, &tmp);
641 memcpy(fi, &tmp, sizeof(tmp));
642 fi->fh = tmp.fh;
643 } else
644 err = ((struct fuse_operations_compat2 *) &fs->op)
645 ->open(path, fi->flags);
646 return err;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000647}
648
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +0000649static int fuse_compat_release(struct fuse_fs *fs, const char *path,
650 struct fuse_file_info *fi)
651{
652 if (!fs->compat || fs->compat >= 22)
653 return fs->op.release(path, fi);
654 else
655 return ((struct fuse_operations_compat2 *) &fs->op)
656 ->release(path, fi->flags);
657}
658
659static int fuse_compat_opendir(struct fuse_fs *fs, const char *path,
660 struct fuse_file_info *fi)
661{
662 if (!fs->compat || fs->compat >= 25)
663 return fs->op.opendir(path, fi);
664 else {
665 int err;
666 struct fuse_file_info_compat tmp;
667 memcpy(&tmp, fi, sizeof(tmp));
668 err = ((struct fuse_operations_compat22 *) &fs->op)
669 ->opendir(path, &tmp);
670 memcpy(fi, &tmp, sizeof(tmp));
671 fi->fh = tmp.fh;
672 return err;
673 }
674}
675
676static void convert_statfs_compat(struct fuse_statfs_compat1 *compatbuf,
677 struct statvfs *stbuf)
678{
679 stbuf->f_bsize = compatbuf->block_size;
680 stbuf->f_blocks = compatbuf->blocks;
681 stbuf->f_bfree = compatbuf->blocks_free;
682 stbuf->f_bavail = compatbuf->blocks_free;
683 stbuf->f_files = compatbuf->files;
684 stbuf->f_ffree = compatbuf->files_free;
685 stbuf->f_namemax = compatbuf->namelen;
686}
687
688static void convert_statfs_old(struct statfs *oldbuf, struct statvfs *stbuf)
689{
690 stbuf->f_bsize = oldbuf->f_bsize;
691 stbuf->f_blocks = oldbuf->f_blocks;
692 stbuf->f_bfree = oldbuf->f_bfree;
693 stbuf->f_bavail = oldbuf->f_bavail;
694 stbuf->f_files = oldbuf->f_files;
695 stbuf->f_ffree = oldbuf->f_ffree;
696 stbuf->f_namemax = oldbuf->f_namelen;
697}
698
699static int fuse_compat_statfs(struct fuse_fs *fs, const char *path,
700 struct statvfs *buf)
701{
702 int err;
703
704 if (!fs->compat || fs->compat >= 25) {
705 err = fs->op.statfs(fs->compat == 25 ? "/" : path, buf);
706 } else if (fs->compat > 11) {
707 struct statfs oldbuf;
708 err = ((struct fuse_operations_compat22 *) &fs->op)
709 ->statfs("/", &oldbuf);
710 if (!err)
711 convert_statfs_old(&oldbuf, buf);
712 } else {
713 struct fuse_statfs_compat1 compatbuf;
714 memset(&compatbuf, 0, sizeof(struct fuse_statfs_compat1));
715 err = ((struct fuse_operations_compat1 *) &fs->op)->statfs(&compatbuf);
716 if (!err)
717 convert_statfs_compat(&compatbuf, buf);
718 }
719 return err;
720}
721
722#else /* __FreeBSD__ */
723
724static inline int fuse_compat_open(struct fuse_fs *fs, char *path,
725 struct fuse_file_info *fi)
726{
727 return fs->op.open(path, fi);
728}
729
730static inline int fuse_compat_release(struct fuse_fs *fs, const char *path,
731 struct fuse_file_info *fi)
732{
733 return fs->op.release(path, fi);
734}
735
736static inline int fuse_compat_opendir(struct fuse_fs *fs, const char *path,
737 struct fuse_file_info *fi)
738{
739 return fs->op.opendir(path, fi);
740}
741
742static inline int fuse_compat_statfs(struct fuse_fs *fs, const char *path,
743 struct statvfs *buf)
744{
745 return fs->op.statfs(fs->compat == 25 ? "/" : path, buf);
746}
747
748#endif /* __FreeBSD__ */
749
750int fuse_fs_getattr(struct fuse_fs *fs, const char *path, struct stat *buf)
751{
752 fuse_get_context()->private_data = fs->user_data;
753 if (fs->op.getattr)
754 return fs->op.getattr(path, buf);
755 else
756 return -ENOSYS;
757}
758
759int fuse_fs_fgetattr(struct fuse_fs *fs, const char *path, struct stat *buf,
760 struct fuse_file_info *fi)
761{
762 fuse_get_context()->private_data = fs->user_data;
763 if (fs->op.fgetattr)
764 return fs->op.fgetattr(path, buf, fi);
765 else if (fs->op.getattr)
766 return fs->op.getattr(path, buf);
767 else
768 return -ENOSYS;
769}
770
771int fuse_fs_rename(struct fuse_fs *fs, const char *oldpath,
772 const char *newpath)
773{
774 fuse_get_context()->private_data = fs->user_data;
775 if (fs->op.rename)
776 return fs->op.rename(oldpath, newpath);
777 else
778 return -ENOSYS;
779}
780
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +0000781int fuse_fs_unlink(struct fuse_fs *fs, const char *path)
782{
783 fuse_get_context()->private_data = fs->user_data;
784 if (fs->op.unlink)
785 return fs->op.unlink(path);
786 else
787 return -ENOSYS;
788}
789
790int fuse_fs_rmdir(struct fuse_fs *fs, const char *path)
791{
792 fuse_get_context()->private_data = fs->user_data;
793 if (fs->op.rmdir)
794 return fs->op.rmdir(path);
795 else
796 return -ENOSYS;
797}
798
799int fuse_fs_symlink(struct fuse_fs *fs, const char *linkname, const char *path)
800{
801 fuse_get_context()->private_data = fs->user_data;
802 if (fs->op.symlink)
803 return fs->op.symlink(linkname, path);
804 else
805 return -ENOSYS;
806}
807
808int fuse_fs_link(struct fuse_fs *fs, const char *oldpath, const char *newpath)
809{
810 fuse_get_context()->private_data = fs->user_data;
811 if (fs->op.link)
812 return fs->op.link(oldpath, newpath);
813 else
814 return -ENOSYS;
815}
816
817int fuse_fs_release(struct fuse_fs *fs, const char *path,
818 struct fuse_file_info *fi)
819{
820 fuse_get_context()->private_data = fs->user_data;
821 if (fs->op.release)
822 return fuse_compat_release(fs, path, fi);
823 else
824 return 0;
825}
826
827int fuse_fs_opendir(struct fuse_fs *fs, const char *path,
828 struct fuse_file_info *fi)
829{
830 fuse_get_context()->private_data = fs->user_data;
831 if (fs->op.opendir)
832 return fuse_compat_opendir(fs, path, fi);
833 else
834 return 0;
835}
836
837int fuse_fs_open(struct fuse_fs *fs, const char *path,
838 struct fuse_file_info *fi)
839{
840 fuse_get_context()->private_data = fs->user_data;
841 if (fs->op.open)
842 return fuse_compat_open(fs, path, fi);
843 else
844 return 0;
845}
846
847int fuse_fs_read(struct fuse_fs *fs, const char *path, char *buf, size_t size,
848 off_t off, struct fuse_file_info *fi)
849{
850 fuse_get_context()->private_data = fs->user_data;
851 if (fs->op.read)
852 return fs->op.read(path, buf, size, off, fi);
853 else
854 return -ENOSYS;
855}
856
857int fuse_fs_write(struct fuse_fs *fs, const char *path, const char *buf,
858 size_t size, off_t off, struct fuse_file_info *fi)
859{
860 fuse_get_context()->private_data = fs->user_data;
861 if (fs->op.write)
862 return fs->op.write(path, buf, size, off, fi);
863 else
864 return -ENOSYS;
865}
866
867int fuse_fs_fsync(struct fuse_fs *fs, const char *path, int datasync,
868 struct fuse_file_info *fi)
869{
870 fuse_get_context()->private_data = fs->user_data;
871 if (fs->op.fsync)
872 return fs->op.fsync(path, datasync, fi);
873 else
874 return -ENOSYS;
875}
876
877int fuse_fs_fsyncdir(struct fuse_fs *fs, const char *path, int datasync,
878 struct fuse_file_info *fi)
879{
880 fuse_get_context()->private_data = fs->user_data;
881 if (fs->op.fsyncdir)
882 return fs->op.fsyncdir(path, datasync, fi);
883 else
884 return -ENOSYS;
885}
886
887int fuse_fs_flush(struct fuse_fs *fs, const char *path,
888 struct fuse_file_info *fi)
889{
890 fuse_get_context()->private_data = fs->user_data;
891 if (fs->op.flush)
892 return fs->op.flush(path, fi);
893 else
894 return -ENOSYS;
895}
896
897int fuse_fs_statfs(struct fuse_fs *fs, const char *path, struct statvfs *buf)
898{
899 fuse_get_context()->private_data = fs->user_data;
900 if (fs->op.statfs)
901 return fuse_compat_statfs(fs, path, buf);
902 else {
903 buf->f_namemax = 255;
904 buf->f_bsize = 512;
905 return 0;
906 }
907}
908
909int fuse_fs_releasedir(struct fuse_fs *fs, const char *path,
910 struct fuse_file_info *fi)
911{
912 fuse_get_context()->private_data = fs->user_data;
913 if (fs->op.releasedir)
914 return fs->op.releasedir(path, fi);
915 else
916 return 0;
917}
918
919static int fill_dir_old(struct fuse_dirhandle *dh, const char *name, int type,
920 ino_t ino)
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000921{
922 int res;
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +0000923 struct stat stbuf;
924
925 memset(&stbuf, 0, sizeof(stbuf));
926 stbuf.st_mode = type << 12;
927 stbuf.st_ino = ino;
928
929 res = dh->filler(dh->buf, name, &stbuf, 0);
930 return res ? -ENOMEM : 0;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000931}
932
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +0000933int fuse_fs_readdir(struct fuse_fs *fs, const char *path, void *buf,
934 fuse_fill_dir_t filler, off_t off,
935 struct fuse_file_info *fi)
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000936{
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +0000937 fuse_get_context()->private_data = fs->user_data;
938 if (fs->op.readdir)
939 return fs->op.readdir(path, buf, filler, off, fi);
940 else if (fs->op.getdir) {
941 struct fuse_dirhandle dh;
942 dh.filler = filler;
943 dh.buf = buf;
944 return fs->op.getdir(path, &dh, fill_dir_old);
945 } else
946 return -ENOSYS;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000947}
948
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +0000949int fuse_fs_create(struct fuse_fs *fs, const char *path, mode_t mode,
950 struct fuse_file_info *fi)
Miklos Szeredi4fca4322006-10-01 14:41:04 +0000951{
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +0000952 fuse_get_context()->private_data = fs->user_data;
953 if (fs->op.create)
954 return fs->op.create(path, mode, fi);
955 else
956 return -ENOSYS;
Miklos Szeredi4fca4322006-10-01 14:41:04 +0000957}
958
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +0000959int fuse_fs_lock(struct fuse_fs *fs, const char *path,
960 struct fuse_file_info *fi, int cmd, struct flock *lock)
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000961{
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +0000962 fuse_get_context()->private_data = fs->user_data;
963 if (fs->op.lock)
964 return fs->op.lock(path, fi, cmd, lock);
965 else
966 return -ENOSYS;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000967}
968
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +0000969int fuse_fs_chown(struct fuse_fs *fs, const char *path, uid_t uid, gid_t gid)
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000970{
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +0000971 fuse_get_context()->private_data = fs->user_data;
972 if (fs->op.chown)
973 return fs->op.chown(path, uid, gid);
974 else
975 return -ENOSYS;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000976}
977
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +0000978int fuse_fs_truncate(struct fuse_fs *fs, const char *path, off_t size)
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000979{
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +0000980 fuse_get_context()->private_data = fs->user_data;
981 if (fs->op.truncate)
982 return fs->op.truncate(path, size);
983 else
984 return -ENOSYS;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000985}
986
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +0000987int fuse_fs_ftruncate(struct fuse_fs *fs, const char *path, off_t size,
988 struct fuse_file_info *fi)
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000989{
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +0000990 fuse_get_context()->private_data = fs->user_data;
991 if (fs->op.ftruncate)
992 return fs->op.ftruncate(path, size, fi);
993 else if (fs->op.truncate)
994 return fs->op.truncate(path, size);
995 else
996 return -ENOSYS;
997}
998
999int fuse_fs_utimens(struct fuse_fs *fs, const char *path,
1000 const struct timespec tv[2])
1001{
1002 fuse_get_context()->private_data = fs->user_data;
1003 if (fs->op.utimens)
1004 return fs->op.utimens(path, tv);
1005 else if(fs->op.utime) {
1006 struct utimbuf buf;
1007 buf.actime = tv[0].tv_sec;
1008 buf.modtime = tv[1].tv_sec;
1009 return fs->op.utime(path, &buf);
1010 } else
1011 return -ENOSYS;
1012}
1013
1014int fuse_fs_access(struct fuse_fs *fs, const char *path, int mask)
1015{
1016 fuse_get_context()->private_data = fs->user_data;
1017 if (fs->op.access)
1018 return fs->op.access(path, mask);
1019 else
1020 return -ENOSYS;
1021}
1022
1023int fuse_fs_readlink(struct fuse_fs *fs, const char *path, char *buf,
1024 size_t len)
1025{
1026 fuse_get_context()->private_data = fs->user_data;
1027 if (fs->op.readlink)
1028 return fs->op.readlink(path, buf, len);
1029 else
1030 return -ENOSYS;
1031}
1032
1033int fuse_fs_mknod(struct fuse_fs *fs, const char *path, mode_t mode,
1034 dev_t rdev)
1035{
1036 fuse_get_context()->private_data = fs->user_data;
1037 if (fs->op.mknod)
1038 return fs->op.mknod(path, mode, rdev);
1039 else
1040 return -ENOSYS;
1041}
1042
1043int fuse_fs_mkdir(struct fuse_fs *fs, const char *path, mode_t mode)
1044{
1045 fuse_get_context()->private_data = fs->user_data;
1046 if (fs->op.mkdir)
1047 return fs->op.mkdir(path, mode);
1048 else
1049 return -ENOSYS;
1050}
1051
1052int fuse_fs_setxattr(struct fuse_fs *fs, const char *path, const char *name,
1053 const char *value, size_t size, int flags)
1054{
1055 fuse_get_context()->private_data = fs->user_data;
1056 if (fs->op.setxattr)
1057 return fs->op.setxattr(path, name, value, size, flags);
1058 else
1059 return -ENOSYS;
1060}
1061
1062int fuse_fs_getxattr(struct fuse_fs *fs, const char *path, const char *name,
1063 char *value, size_t size)
1064{
1065 fuse_get_context()->private_data = fs->user_data;
1066 if (fs->op.getxattr)
1067 return fs->op.getxattr(path, name, value, size);
1068 else
1069 return -ENOSYS;
1070}
1071
1072int fuse_fs_listxattr(struct fuse_fs *fs, const char *path, char *list,
1073 size_t size)
1074{
1075 fuse_get_context()->private_data = fs->user_data;
1076 if (fs->op.listxattr)
1077 return fs->op.listxattr(path, list, size);
1078 else
1079 return -ENOSYS;
1080}
1081
1082int fuse_fs_bmap(struct fuse_fs *fs, const char *path, size_t blocksize,
1083 uint64_t *idx)
1084{
1085 fuse_get_context()->private_data = fs->user_data;
1086 if (fs->op.bmap)
1087 return fs->op.bmap(path, blocksize, idx);
1088 else
1089 return -ENOSYS;
1090}
1091
1092int fuse_fs_removexattr(struct fuse_fs *fs, const char *path, const char *name)
1093{
1094 fuse_get_context()->private_data = fs->user_data;
1095 if (fs->op.removexattr)
1096 return fs->op.removexattr(path, name);
1097 else
1098 return -ENOSYS;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001099}
1100
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001101static int is_open(struct fuse *f, fuse_ino_t dir, const char *name)
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001102{
1103 struct node *node;
1104 int isopen = 0;
1105 pthread_mutex_lock(&f->lock);
Miklos Szeredif458b8c2004-12-07 16:46:42 +00001106 node = lookup_node(f, dir, name);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001107 if (node && node->open_count > 0)
1108 isopen = 1;
1109 pthread_mutex_unlock(&f->lock);
1110 return isopen;
1111}
1112
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001113static char *hidden_name(struct fuse *f, fuse_ino_t dir, const char *oldname,
1114 char *newname, size_t bufsize)
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001115{
1116 struct stat buf;
1117 struct node *node;
1118 struct node *newnode;
1119 char *newpath;
1120 int res;
1121 int failctr = 10;
1122
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001123 do {
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001124 pthread_mutex_lock(&f->lock);
Miklos Szeredif458b8c2004-12-07 16:46:42 +00001125 node = lookup_node(f, dir, oldname);
1126 if (node == NULL) {
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001127 pthread_mutex_unlock(&f->lock);
1128 return NULL;
Miklos Szeredif458b8c2004-12-07 16:46:42 +00001129 }
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001130 do {
1131 f->hidectr ++;
1132 snprintf(newname, bufsize, ".fuse_hidden%08x%08x",
Miklos Szeredia13d9002004-11-02 17:32:03 +00001133 (unsigned int) node->nodeid, f->hidectr);
Miklos Szeredif458b8c2004-12-07 16:46:42 +00001134 newnode = lookup_node(f, dir, newname);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001135 } while(newnode);
1136 pthread_mutex_unlock(&f->lock);
Miklos Szeredie5183742005-02-02 11:14:04 +00001137
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001138 newpath = get_path_name(f, dir, newname);
1139 if (!newpath)
1140 break;
Miklos Szeredie5183742005-02-02 11:14:04 +00001141
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001142 res = fuse_fs_getattr(f->fs, newpath, &buf);
1143 if (res == -ENOENT)
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001144 break;
1145 free(newpath);
1146 newpath = NULL;
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001147 } while(res == 0 && --failctr);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001148
1149 return newpath;
1150}
1151
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001152static int hide_node(struct fuse *f, const char *oldpath,
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001153 fuse_ino_t dir, const char *oldname)
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001154{
1155 char newname[64];
1156 char *newpath;
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001157 int err = -EBUSY;
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001158
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001159 newpath = hidden_name(f, dir, oldname, newname, sizeof(newname));
1160 if (newpath) {
1161 err = fuse_fs_rename(f->fs, oldpath, newpath);
1162 if (!err)
1163 err = rename_node(f, dir, oldname, dir, newname, 1);
1164 free(newpath);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001165 }
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001166 return err;
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001167}
1168
Miklos Szeredi320abe42006-01-30 18:14:51 +00001169static int mtime_eq(const struct stat *stbuf, const struct timespec *ts)
1170{
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001171 return stbuf->st_mtime == ts->tv_sec && ST_MTIM_NSEC(stbuf) == ts->tv_nsec;
Miklos Szeredi320abe42006-01-30 18:14:51 +00001172}
1173
Miklos Szeredi2512aaa2006-05-03 14:54:59 +00001174#ifndef CLOCK_MONOTONIC
1175#define CLOCK_MONOTONIC CLOCK_REALTIME
1176#endif
1177
Miklos Szeredi320abe42006-01-30 18:14:51 +00001178static void curr_time(struct timespec *now)
1179{
1180 static clockid_t clockid = CLOCK_MONOTONIC;
1181 int res = clock_gettime(clockid, now);
1182 if (res == -1 && errno == EINVAL) {
1183 clockid = CLOCK_REALTIME;
1184 res = clock_gettime(clockid, now);
1185 }
1186 if (res == -1) {
1187 perror("fuse: clock_gettime");
1188 abort();
1189 }
1190}
1191
1192static void update_stat(struct node *node, const struct stat *stbuf)
1193{
1194 if (node->cache_valid && (!mtime_eq(stbuf, &node->mtime) ||
1195 stbuf->st_size != node->size))
1196 node->cache_valid = 0;
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001197 node->mtime.tv_sec = stbuf->st_mtime;
1198 node->mtime.tv_nsec = ST_MTIM_NSEC(stbuf);
Miklos Szeredi320abe42006-01-30 18:14:51 +00001199 node->size = stbuf->st_size;
1200 curr_time(&node->stat_updated);
1201}
1202
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001203static int lookup_path(struct fuse *f, fuse_ino_t nodeid,
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001204 const char *name, const char *path,
1205 struct fuse_entry_param *e, struct fuse_file_info *fi)
Miklos Szeredi76f65782004-02-19 16:55:40 +00001206{
1207 int res;
Miklos Szeredi76f65782004-02-19 16:55:40 +00001208
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001209 memset(e, 0, sizeof(struct fuse_entry_param));
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001210 if (fi)
1211 res = fuse_fs_fgetattr(f->fs, path, &e->attr, fi);
Miklos Szeredif7eec032005-10-28 13:09:50 +00001212 else
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001213 res = fuse_fs_getattr(f->fs, path, &e->attr);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001214 if (res == 0) {
Miklos Szeredi76f65782004-02-19 16:55:40 +00001215 struct node *node;
1216
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001217 node = find_node(f, nodeid, name);
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001218 if (node == NULL)
1219 res = -ENOMEM;
1220 else {
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001221 e->ino = node->nodeid;
1222 e->generation = node->generation;
Miklos Szeredi659743b2005-12-09 17:41:42 +00001223 e->entry_timeout = f->conf.entry_timeout;
1224 e->attr_timeout = f->conf.attr_timeout;
Miklos Szeredi320abe42006-01-30 18:14:51 +00001225 if (f->conf.auto_cache) {
1226 pthread_mutex_lock(&f->lock);
1227 update_stat(node, &e->attr);
1228 pthread_mutex_unlock(&f->lock);
1229 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001230 set_stat(f, e->ino, &e->attr);
Miklos Szeredi659743b2005-12-09 17:41:42 +00001231 if (f->conf.debug) {
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001232 printf(" NODEID: %lu\n", (unsigned long) e->ino);
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001233 fflush(stdout);
1234 }
Miklos Szeredi76f65782004-02-19 16:55:40 +00001235 }
1236 }
1237 return res;
1238}
1239
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001240static struct fuse_context_i *fuse_get_context_internal(void)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001241{
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001242 struct fuse_context_i *c;
1243
1244 c = (struct fuse_context_i *) pthread_getspecific(fuse_context_key);
1245 if (c == NULL) {
1246 c = (struct fuse_context_i *) malloc(sizeof(struct fuse_context_i));
1247 if (c == NULL) {
1248 /* This is hard to deal with properly, so just abort. If
1249 memory is so low that the context cannot be allocated,
1250 there's not much hope for the filesystem anyway */
1251 fprintf(stderr, "fuse: failed to allocate thread specific data\n");
1252 abort();
1253 }
1254 pthread_setspecific(fuse_context_key, c);
1255 }
1256 return c;
1257}
1258
1259static void fuse_freecontext(void *data)
1260{
1261 free(data);
1262}
1263
1264static int fuse_create_context_key(void)
1265{
1266 int err = 0;
1267 pthread_mutex_lock(&fuse_context_lock);
1268 if (!fuse_context_ref) {
1269 err = pthread_key_create(&fuse_context_key, fuse_freecontext);
1270 if (err) {
1271 fprintf(stderr, "fuse: failed to create thread specific key: %s\n",
1272 strerror(err));
1273 pthread_mutex_unlock(&fuse_context_lock);
1274 return -1;
1275 }
1276 }
1277 fuse_context_ref++;
1278 pthread_mutex_unlock(&fuse_context_lock);
1279 return 0;
1280}
1281
1282static void fuse_delete_context_key(void)
1283{
1284 pthread_mutex_lock(&fuse_context_lock);
1285 fuse_context_ref--;
1286 if (!fuse_context_ref) {
1287 free(pthread_getspecific(fuse_context_key));
1288 pthread_key_delete(fuse_context_key);
1289 }
1290 pthread_mutex_unlock(&fuse_context_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001291}
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001292
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001293static struct fuse *req_fuse_prepare(fuse_req_t req)
1294{
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001295 struct fuse_context_i *c = fuse_get_context_internal();
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001296 const struct fuse_ctx *ctx = fuse_req_ctx(req);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001297 c->req = req;
1298 c->ctx.fuse = req_fuse(req);
1299 c->ctx.uid = ctx->uid;
1300 c->ctx.gid = ctx->gid;
1301 c->ctx.pid = ctx->pid;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001302 return c->ctx.fuse;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001303}
1304
1305static inline void reply_err(fuse_req_t req, int err)
1306{
1307 /* fuse_reply_err() uses non-negated errno values */
1308 fuse_reply_err(req, -err);
1309}
1310
1311static void reply_entry(fuse_req_t req, const struct fuse_entry_param *e,
1312 int err)
1313{
1314 if (!err) {
Miklos Szeredib67f2162006-02-20 10:55:33 +00001315 struct fuse *f = req_fuse(req);
Miklos Szeredi9b813af2005-07-21 07:59:37 +00001316 if (fuse_reply_entry(req, e) == -ENOENT)
Miklos Szeredib67f2162006-02-20 10:55:33 +00001317 forget_node(f, e->ino, 1);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001318 } else
1319 reply_err(req, err);
1320}
1321
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001322void fuse_fs_init(struct fuse_fs *fs, struct fuse_conn_info *conn)
1323{
1324 fuse_get_context()->private_data = fs->user_data;
1325 if (fs->op.init)
1326 fs->user_data = fs->op.init(conn);
1327}
1328
1329static void fuse_lib_init(void *data, struct fuse_conn_info *conn)
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001330{
1331 struct fuse *f = (struct fuse *) data;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001332 struct fuse_context_i *c = fuse_get_context_internal();
Miklos Szeredi4f5df5e2005-10-07 12:39:58 +00001333
1334 memset(c, 0, sizeof(*c));
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001335 c->ctx.fuse = f;
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001336 fuse_fs_init(f->fs, conn);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001337}
1338
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001339void fuse_fs_destroy(struct fuse_fs *fs)
1340{
1341 fuse_get_context()->private_data = fs->user_data;
1342 if (fs->op.destroy)
1343 fs->op.destroy(fs->user_data);
1344 if (fs->m)
1345 fuse_put_module(fs->m);
1346 free(fs);
1347}
1348
1349static void fuse_lib_destroy(void *data)
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001350{
1351 struct fuse *f = (struct fuse *) data;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001352 struct fuse_context_i *c = fuse_get_context_internal();
Miklos Szeredi4f5df5e2005-10-07 12:39:58 +00001353
1354 memset(c, 0, sizeof(*c));
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001355 c->ctx.fuse = f;
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001356 fuse_fs_destroy(f->fs);
1357 f->fs = NULL;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001358}
1359
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001360static void fuse_lib_lookup(fuse_req_t req, fuse_ino_t parent,
1361 const char *name)
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001362{
1363 struct fuse *f = req_fuse_prepare(req);
1364 struct fuse_entry_param e;
1365 char *path;
1366 int err;
1367
1368 err = -ENOENT;
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001369 pthread_rwlock_rdlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001370 path = get_path_name(f, parent, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001371 if (path != NULL) {
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001372 struct fuse_intr_data d;
Miklos Szeredi659743b2005-12-09 17:41:42 +00001373 if (f->conf.debug) {
Miklos Szeredi6ebe2342002-01-06 21:44:16 +00001374 printf("LOOKUP %s\n", path);
1375 fflush(stdout);
1376 }
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001377 fuse_prepare_interrupt(f, req, &d);
1378 err = lookup_path(f, parent, name, path, &e, NULL);
1379 if (err == -ENOENT && f->conf.negative_timeout != 0.0) {
1380 e.ino = 0;
1381 e.entry_timeout = f->conf.negative_timeout;
1382 err = 0;
Miklos Szeredi2b478112005-11-28 13:27:10 +00001383 }
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001384 fuse_finish_interrupt(f, req, &d);
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001385 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001386 }
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001387 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001388 reply_entry(req, &e, err);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001389}
1390
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001391static void fuse_lib_forget(fuse_req_t req, fuse_ino_t ino,
1392 unsigned long nlookup)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001393{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001394 struct fuse *f = req_fuse(req);
Miklos Szeredi659743b2005-12-09 17:41:42 +00001395 if (f->conf.debug) {
Miklos Szeredi3a770472005-11-11 21:32:42 +00001396 printf("FORGET %llu/%lu\n", (unsigned long long) ino, nlookup);
Miklos Szeredi43696432001-11-18 19:15:05 +00001397 fflush(stdout);
1398 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001399 forget_node(f, ino, nlookup);
1400 fuse_reply_none(req);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001401}
1402
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001403static void fuse_lib_getattr(fuse_req_t req, fuse_ino_t ino,
1404 struct fuse_file_info *fi)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001405{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001406 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredi19dff1b2001-10-30 15:06:52 +00001407 struct stat buf;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001408 char *path;
1409 int err;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001410
Miklos Szerediecce1bf2005-08-25 15:19:06 +00001411 (void) fi;
Miklos Szeredi16dbf942006-09-02 13:20:40 +00001412 memset(&buf, 0, sizeof(buf));
Miklos Szerediecce1bf2005-08-25 15:19:06 +00001413
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001414 err = -ENOENT;
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001415 pthread_rwlock_rdlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001416 path = get_path(f, ino);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001417 if (path != NULL) {
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001418 struct fuse_intr_data d;
1419 fuse_prepare_interrupt(f, req, &d);
1420 err = fuse_fs_getattr(f->fs, path, &buf);
1421 fuse_finish_interrupt(f, req, &d);
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001422 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001423 }
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001424 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001425 if (!err) {
Miklos Szeredi08dab162006-02-01 13:39:15 +00001426 if (f->conf.auto_cache) {
1427 pthread_mutex_lock(&f->lock);
1428 update_stat(get_node(f, ino), &buf);
1429 pthread_mutex_unlock(&f->lock);
1430 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001431 set_stat(f, ino, &buf);
Miklos Szeredi659743b2005-12-09 17:41:42 +00001432 fuse_reply_attr(req, &buf, f->conf.attr_timeout);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001433 } else
1434 reply_err(req, err);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001435}
1436
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001437int fuse_fs_chmod(struct fuse_fs *fs, const char *path, mode_t mode)
Miklos Szeredif3ea83b2001-11-07 14:55:16 +00001438{
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001439 if (fs->op.chmod)
1440 return fs->op.chmod(path, mode);
1441 else
1442 return -ENOSYS;
Miklos Szeredie5183742005-02-02 11:14:04 +00001443}
Miklos Szeredif3ea83b2001-11-07 14:55:16 +00001444
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001445static void fuse_lib_setattr(fuse_req_t req, fuse_ino_t ino, struct stat *attr,
1446 int valid, struct fuse_file_info *fi)
Miklos Szeredi5e183482001-10-31 14:52:35 +00001447{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001448 struct fuse *f = req_fuse_prepare(req);
1449 struct stat buf;
Miklos Szeredi5e183482001-10-31 14:52:35 +00001450 char *path;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001451 int err;
Miklos Szeredi5e183482001-10-31 14:52:35 +00001452
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001453 err = -ENOENT;
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001454 pthread_rwlock_rdlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001455 path = get_path(f, ino);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001456 if (path != NULL) {
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001457 struct fuse_intr_data d;
1458 fuse_prepare_interrupt(f, req, &d);
1459 err = 0;
1460 if (!err && (valid & FUSE_SET_ATTR_MODE))
1461 err = fuse_fs_chmod(f->fs, path, attr->st_mode);
1462 if (!err && (valid & (FUSE_SET_ATTR_UID | FUSE_SET_ATTR_GID))) {
1463 uid_t uid =
1464 (valid & FUSE_SET_ATTR_UID) ? attr->st_uid : (uid_t) -1;
1465 gid_t gid =
1466 (valid & FUSE_SET_ATTR_GID) ? attr->st_gid : (gid_t) -1;
1467 err = fuse_fs_chown(f->fs, path, uid, gid);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001468 }
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001469 if (!err && (valid & FUSE_SET_ATTR_SIZE)) {
1470 if (fi)
1471 err = fuse_fs_ftruncate(f->fs, path, attr->st_size, fi);
1472 else
1473 err = fuse_fs_truncate(f->fs, path, attr->st_size);
1474 }
1475 if (!err && (valid & (FUSE_SET_ATTR_ATIME | FUSE_SET_ATTR_MTIME)) ==
1476 (FUSE_SET_ATTR_ATIME | FUSE_SET_ATTR_MTIME)) {
1477 struct timespec tv[2];
1478 tv[0].tv_sec = attr->st_atime;
1479 tv[0].tv_nsec = ST_ATIM_NSEC(attr);
1480 tv[1].tv_sec = attr->st_mtime;
1481 tv[1].tv_nsec = ST_MTIM_NSEC(attr);
1482 err = fuse_fs_utimens(f->fs, path, tv);
1483 }
1484 if (!err)
1485 err = fuse_fs_getattr(f->fs, path, &buf);
1486 fuse_finish_interrupt(f, req, &d);
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001487 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001488 }
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001489 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001490 if (!err) {
Miklos Szeredi08dab162006-02-01 13:39:15 +00001491 if (f->conf.auto_cache) {
1492 pthread_mutex_lock(&f->lock);
1493 update_stat(get_node(f, ino), &buf);
1494 pthread_mutex_unlock(&f->lock);
1495 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001496 set_stat(f, ino, &buf);
Miklos Szeredi659743b2005-12-09 17:41:42 +00001497 fuse_reply_attr(req, &buf, f->conf.attr_timeout);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001498 } else
1499 reply_err(req, err);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001500}
1501
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001502static void fuse_lib_access(fuse_req_t req, fuse_ino_t ino, int mask)
Miklos Szeredib0b13d12005-10-26 12:53:25 +00001503{
1504 struct fuse *f = req_fuse_prepare(req);
1505 char *path;
1506 int err;
1507
1508 err = -ENOENT;
1509 pthread_rwlock_rdlock(&f->tree_lock);
1510 path = get_path(f, ino);
1511 if (path != NULL) {
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001512 struct fuse_intr_data d;
Miklos Szeredi659743b2005-12-09 17:41:42 +00001513 if (f->conf.debug) {
Miklos Szeredib0b13d12005-10-26 12:53:25 +00001514 printf("ACCESS %s 0%o\n", path, mask);
1515 fflush(stdout);
1516 }
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001517 fuse_prepare_interrupt(f, req, &d);
1518 err = fuse_fs_access(f->fs, path, mask);
1519 fuse_finish_interrupt(f, req, &d);
Miklos Szeredib0b13d12005-10-26 12:53:25 +00001520 free(path);
1521 }
1522 pthread_rwlock_unlock(&f->tree_lock);
1523 reply_err(req, err);
1524}
1525
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001526static void fuse_lib_readlink(fuse_req_t req, fuse_ino_t ino)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001527{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001528 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredif6e0ec62005-08-03 09:11:06 +00001529 char linkname[PATH_MAX + 1];
Miklos Szeredib483c932001-10-29 14:57:57 +00001530 char *path;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001531 int err;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001532
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001533 err = -ENOENT;
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001534 pthread_rwlock_rdlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001535 path = get_path(f, ino);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001536 if (path != NULL) {
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001537 struct fuse_intr_data d;
1538 fuse_prepare_interrupt(f, req, &d);
1539 err = fuse_fs_readlink(f->fs, path, linkname, sizeof(linkname));
1540 fuse_finish_interrupt(f, req, &d);
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001541 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001542 }
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001543 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001544 if (!err) {
Miklos Szeredif6e0ec62005-08-03 09:11:06 +00001545 linkname[PATH_MAX] = '\0';
1546 fuse_reply_readlink(req, linkname);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001547 } else
1548 reply_err(req, err);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001549}
1550
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001551static void fuse_lib_mknod(fuse_req_t req, fuse_ino_t parent, const char *name,
1552 mode_t mode, dev_t rdev)
Miklos Szeredib483c932001-10-29 14:57:57 +00001553{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001554 struct fuse *f = req_fuse_prepare(req);
1555 struct fuse_entry_param e;
Miklos Szeredib483c932001-10-29 14:57:57 +00001556 char *path;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001557 int err;
Miklos Szeredib483c932001-10-29 14:57:57 +00001558
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001559 err = -ENOENT;
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001560 pthread_rwlock_rdlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001561 path = get_path_name(f, parent, name);
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001562 if (path) {
1563 struct fuse_intr_data d;
Miklos Szeredi659743b2005-12-09 17:41:42 +00001564 if (f->conf.debug) {
Miklos Szeredi76f65782004-02-19 16:55:40 +00001565 printf("MKNOD %s\n", path);
1566 fflush(stdout);
1567 }
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001568 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001569 err = -ENOSYS;
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001570 if (S_ISREG(mode)) {
Miklos Szeredib3f99722005-11-16 13:00:24 +00001571 struct fuse_file_info fi;
1572
1573 memset(&fi, 0, sizeof(fi));
1574 fi.flags = O_CREAT | O_EXCL | O_WRONLY;
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001575 err = fuse_fs_create(f->fs, path, mode, &fi);
Miklos Szeredib3f99722005-11-16 13:00:24 +00001576 if (!err) {
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001577 err = lookup_path(f, parent, name, path, &e, &fi);
1578 fuse_fs_release(f->fs, path, &fi);
Miklos Szeredib3f99722005-11-16 13:00:24 +00001579 }
Miklos Szeredi5e183482001-10-31 14:52:35 +00001580 }
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001581 if (err == -ENOSYS) {
1582 err = fuse_fs_mknod(f->fs, path, mode, rdev);
1583 if (!err)
1584 err = lookup_path(f, parent, name, path, &e, NULL);
1585 }
1586 fuse_finish_interrupt(f, req, &d);
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001587 free(path);
Miklos Szeredib483c932001-10-29 14:57:57 +00001588 }
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001589 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001590 reply_entry(req, &e, err);
Miklos Szeredib483c932001-10-29 14:57:57 +00001591}
1592
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001593static void fuse_lib_mkdir(fuse_req_t req, fuse_ino_t parent, const char *name,
1594 mode_t mode)
Miklos Szeredib483c932001-10-29 14:57:57 +00001595{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001596 struct fuse *f = req_fuse_prepare(req);
1597 struct fuse_entry_param e;
Miklos Szeredib483c932001-10-29 14:57:57 +00001598 char *path;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001599 int err;
Miklos Szeredib483c932001-10-29 14:57:57 +00001600
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001601 err = -ENOENT;
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001602 pthread_rwlock_rdlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001603 path = get_path_name(f, parent, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001604 if (path != NULL) {
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001605 struct fuse_intr_data d;
Miklos Szeredi659743b2005-12-09 17:41:42 +00001606 if (f->conf.debug) {
Miklos Szeredi76f65782004-02-19 16:55:40 +00001607 printf("MKDIR %s\n", path);
1608 fflush(stdout);
1609 }
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001610 fuse_prepare_interrupt(f, req, &d);
1611 err = fuse_fs_mkdir(f->fs, path, mode);
1612 if (!err)
1613 err = lookup_path(f, parent, name, path, &e, NULL);
1614 fuse_finish_interrupt(f, req, &d);
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001615 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001616 }
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001617 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001618 reply_entry(req, &e, err);
Miklos Szeredib483c932001-10-29 14:57:57 +00001619}
1620
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001621static void fuse_lib_unlink(fuse_req_t req, fuse_ino_t parent,
1622 const char *name)
Miklos Szeredib483c932001-10-29 14:57:57 +00001623{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001624 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredib483c932001-10-29 14:57:57 +00001625 char *path;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001626 int err;
Miklos Szeredib483c932001-10-29 14:57:57 +00001627
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001628 err = -ENOENT;
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001629 pthread_rwlock_wrlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001630 path = get_path_name(f, parent, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001631 if (path != NULL) {
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001632 struct fuse_intr_data d;
Miklos Szeredi659743b2005-12-09 17:41:42 +00001633 if (f->conf.debug) {
Miklos Szeredi209f5d02004-07-24 19:56:16 +00001634 printf("UNLINK %s\n", path);
1635 fflush(stdout);
1636 }
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001637 fuse_prepare_interrupt(f, req, &d);
1638 if (!f->conf.hard_remove && is_open(f, parent, name))
1639 err = hide_node(f, path, parent, name);
1640 else {
1641 err = fuse_fs_unlink(f->fs, path);
1642 if (!err)
1643 remove_node(f, parent, name);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001644 }
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001645 fuse_finish_interrupt(f, req, &d);
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001646 free(path);
Miklos Szeredib483c932001-10-29 14:57:57 +00001647 }
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001648 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001649 reply_err(req, err);
Miklos Szeredib5958612004-02-20 14:10:49 +00001650}
1651
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001652static void fuse_lib_rmdir(fuse_req_t req, fuse_ino_t parent, const char *name)
Miklos Szeredib5958612004-02-20 14:10:49 +00001653{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001654 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredib5958612004-02-20 14:10:49 +00001655 char *path;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001656 int err;
Miklos Szeredib5958612004-02-20 14:10:49 +00001657
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001658 err = -ENOENT;
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001659 pthread_rwlock_wrlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001660 path = get_path_name(f, parent, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001661 if (path != NULL) {
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001662 struct fuse_intr_data d;
Miklos Szeredi659743b2005-12-09 17:41:42 +00001663 if (f->conf.debug) {
Miklos Szeredi209f5d02004-07-24 19:56:16 +00001664 printf("RMDIR %s\n", path);
1665 fflush(stdout);
1666 }
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001667 fuse_prepare_interrupt(f, req, &d);
1668 err = fuse_fs_rmdir(f->fs, path);
1669 fuse_finish_interrupt(f, req, &d);
1670 if (!err)
1671 remove_node(f, parent, name);
Miklos Szeredib5958612004-02-20 14:10:49 +00001672 free(path);
1673 }
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001674 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001675 reply_err(req, err);
Miklos Szeredib483c932001-10-29 14:57:57 +00001676}
1677
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001678static void fuse_lib_symlink(fuse_req_t req, const char *linkname,
1679 fuse_ino_t parent, const char *name)
Miklos Szeredib483c932001-10-29 14:57:57 +00001680{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001681 struct fuse *f = req_fuse_prepare(req);
1682 struct fuse_entry_param e;
Miklos Szeredib483c932001-10-29 14:57:57 +00001683 char *path;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001684 int err;
Miklos Szeredib483c932001-10-29 14:57:57 +00001685
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001686 err = -ENOENT;
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001687 pthread_rwlock_rdlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001688 path = get_path_name(f, parent, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001689 if (path != NULL) {
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001690 struct fuse_intr_data d;
Miklos Szeredi659743b2005-12-09 17:41:42 +00001691 if (f->conf.debug) {
Miklos Szeredi76f65782004-02-19 16:55:40 +00001692 printf("SYMLINK %s\n", path);
1693 fflush(stdout);
1694 }
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001695 fuse_prepare_interrupt(f, req, &d);
1696 err = fuse_fs_symlink(f->fs, linkname, path);
1697 if (!err)
1698 err = lookup_path(f, parent, name, path, &e, NULL);
1699 fuse_finish_interrupt(f, req, &d);
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001700 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001701 }
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001702 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001703 reply_entry(req, &e, err);
Miklos Szeredib483c932001-10-29 14:57:57 +00001704}
1705
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001706static void fuse_lib_rename(fuse_req_t req, fuse_ino_t olddir,
1707 const char *oldname, fuse_ino_t newdir,
1708 const char *newname)
Miklos Szeredi19dff1b2001-10-30 15:06:52 +00001709{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001710 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001711 char *oldpath;
1712 char *newpath;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001713 int err;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +00001714
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001715 err = -ENOENT;
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001716 pthread_rwlock_wrlock(&f->tree_lock);
Miklos Szeredia181e612001-11-06 12:03:23 +00001717 oldpath = get_path_name(f, olddir, oldname);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001718 if (oldpath != NULL) {
Miklos Szeredia181e612001-11-06 12:03:23 +00001719 newpath = get_path_name(f, newdir, newname);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001720 if (newpath != NULL) {
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001721 struct fuse_intr_data d;
Miklos Szeredi659743b2005-12-09 17:41:42 +00001722 if (f->conf.debug) {
Miklos Szeredi209f5d02004-07-24 19:56:16 +00001723 printf("RENAME %s -> %s\n", oldpath, newpath);
1724 fflush(stdout);
1725 }
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001726 err = 0;
1727 fuse_prepare_interrupt(f, req, &d);
1728 if (!f->conf.hard_remove && is_open(f, newdir, newname))
1729 err = hide_node(f, newpath, newdir, newname);
1730 if (!err) {
1731 err = fuse_fs_rename(f->fs, oldpath, newpath);
1732 if (!err)
1733 err = rename_node(f, olddir, oldname, newdir, newname, 0);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001734 }
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001735 fuse_finish_interrupt(f, req, &d);
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001736 free(newpath);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001737 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001738 free(oldpath);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001739 }
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001740 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001741 reply_err(req, err);
Miklos Szeredi19dff1b2001-10-30 15:06:52 +00001742}
1743
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001744static void fuse_lib_link(fuse_req_t req, fuse_ino_t ino, fuse_ino_t newparent,
1745 const char *newname)
Miklos Szeredi19dff1b2001-10-30 15:06:52 +00001746{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001747 struct fuse *f = req_fuse_prepare(req);
1748 struct fuse_entry_param e;
Miklos Szeredi5e183482001-10-31 14:52:35 +00001749 char *oldpath;
1750 char *newpath;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001751 int err;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +00001752
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001753 err = -ENOENT;
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001754 pthread_rwlock_rdlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001755 oldpath = get_path(f, ino);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001756 if (oldpath != NULL) {
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001757 newpath = get_path_name(f, newparent, newname);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001758 if (newpath != NULL) {
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001759 struct fuse_intr_data d;
Miklos Szeredi659743b2005-12-09 17:41:42 +00001760 if (f->conf.debug) {
Miklos Szeredi76f65782004-02-19 16:55:40 +00001761 printf("LINK %s\n", newpath);
1762 fflush(stdout);
1763 }
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001764 fuse_prepare_interrupt(f, req, &d);
1765 err = fuse_fs_link(f->fs, oldpath, newpath);
1766 if (!err)
1767 err = lookup_path(f, newparent, newname, newpath, &e, NULL);
1768 fuse_finish_interrupt(f, req, &d);
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001769 free(newpath);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001770 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001771 free(oldpath);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001772 }
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001773 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001774 reply_entry(req, &e, err);
Miklos Szeredi19dff1b2001-10-30 15:06:52 +00001775}
1776
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001777static void fuse_do_release(struct fuse *f, fuse_ino_t ino, const char *path,
1778 struct fuse_file_info *fi)
1779{
1780 struct node *node;
1781 int unlink_hidden = 0;
1782
1783 fuse_fs_release(f->fs, path ? path : "-", fi);
1784
1785 pthread_mutex_lock(&f->lock);
1786 node = get_node(f, ino);
1787 assert(node->open_count > 0);
1788 --node->open_count;
1789 if (node->is_hidden && !node->open_count) {
1790 unlink_hidden = 1;
1791 node->is_hidden = 0;
1792 }
1793 pthread_mutex_unlock(&f->lock);
1794
1795 if(unlink_hidden && path)
1796 fuse_fs_unlink(f->fs, path);
1797}
1798
1799static void fuse_lib_create(fuse_req_t req, fuse_ino_t parent,
1800 const char *name, mode_t mode,
1801 struct fuse_file_info *fi)
Miklos Szeredid9079a72005-10-26 15:29:06 +00001802{
1803 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001804 struct fuse_intr_data d;
Miklos Szeredid9079a72005-10-26 15:29:06 +00001805 struct fuse_entry_param e;
1806 char *path;
1807 int err;
1808
1809 err = -ENOENT;
1810 pthread_rwlock_rdlock(&f->tree_lock);
1811 path = get_path_name(f, parent, name);
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001812 if (path) {
1813 fuse_prepare_interrupt(f, req, &d);
1814 err = fuse_fs_create(f->fs, path, mode, fi);
1815 if (!err) {
1816 err = lookup_path(f, parent, name, path, &e, fi);
1817 if (err)
1818 fuse_fs_release(f->fs, path, fi);
1819 else if (!S_ISREG(e.attr.st_mode)) {
1820 err = -EIO;
1821 fuse_fs_release(f->fs, path, fi);
1822 forget_node(f, e.ino, 1);
1823 } else {
1824 if (f->conf.direct_io)
1825 fi->direct_io = 1;
1826 if (f->conf.kernel_cache)
1827 fi->keep_cache = 1;
1828
Miklos Szeredid9079a72005-10-26 15:29:06 +00001829 }
1830 }
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001831 fuse_finish_interrupt(f, req, &d);
Miklos Szeredid9079a72005-10-26 15:29:06 +00001832 }
Miklos Szeredid9079a72005-10-26 15:29:06 +00001833 if (!err) {
Miklos Szeredid9079a72005-10-26 15:29:06 +00001834 pthread_mutex_lock(&f->lock);
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001835 get_node(f, e.ino)->open_count++;
1836 pthread_mutex_unlock(&f->lock);
Miklos Szeredid9079a72005-10-26 15:29:06 +00001837 if (fuse_reply_create(req, &e, fi) == -ENOENT) {
1838 /* The open syscall was interrupted, so it must be cancelled */
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001839 fuse_prepare_interrupt(f, req, &d);
1840 fuse_do_release(f, e.ino, path, fi);
1841 fuse_finish_interrupt(f, req, &d);
Miklos Szeredid9079a72005-10-26 15:29:06 +00001842 forget_node(f, e.ino, 1);
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001843 } else if (f->conf.debug) {
1844 printf(" CREATE[%llu] flags: 0x%x %s\n",
1845 (unsigned long long) fi->fh, fi->flags, path);
1846 fflush(stdout);
Miklos Szeredid9079a72005-10-26 15:29:06 +00001847 }
Miklos Szeredid9079a72005-10-26 15:29:06 +00001848 } else
1849 reply_err(req, err);
1850
1851 if (path)
1852 free(path);
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001853
Miklos Szeredid9079a72005-10-26 15:29:06 +00001854 pthread_rwlock_unlock(&f->tree_lock);
1855}
1856
Miklos Szeredi320abe42006-01-30 18:14:51 +00001857static double diff_timespec(const struct timespec *t1,
1858 const struct timespec *t2)
1859{
1860 return (t1->tv_sec - t2->tv_sec) +
1861 ((double) t1->tv_nsec - (double) t2->tv_nsec) / 1000000000.0;
1862}
1863
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001864static void open_auto_cache(struct fuse *f, fuse_ino_t ino, const char *path,
1865 struct fuse_file_info *fi)
Miklos Szeredi320abe42006-01-30 18:14:51 +00001866{
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001867 struct node *node;
1868
1869 pthread_mutex_lock(&f->lock);
1870 node = get_node(f, ino);
Miklos Szeredi08dab162006-02-01 13:39:15 +00001871 if (node->cache_valid) {
1872 struct timespec now;
Miklos Szeredi320abe42006-01-30 18:14:51 +00001873
Miklos Szeredi08dab162006-02-01 13:39:15 +00001874 curr_time(&now);
Miklos Szeredi6e806e92006-02-16 16:59:39 +00001875 if (diff_timespec(&now, &node->stat_updated) > f->conf.ac_attr_timeout) {
Miklos Szeredi08dab162006-02-01 13:39:15 +00001876 struct stat stbuf;
1877 int err;
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001878 pthread_mutex_unlock(&f->lock);
1879 err = fuse_fs_fgetattr(f->fs, path, &stbuf, fi);
1880 pthread_mutex_lock(&f->lock);
Miklos Szeredi08dab162006-02-01 13:39:15 +00001881 if (!err)
1882 update_stat(node, &stbuf);
1883 else
1884 node->cache_valid = 0;
1885 }
Miklos Szeredi320abe42006-01-30 18:14:51 +00001886 }
1887 if (node->cache_valid)
1888 fi->keep_cache = 1;
Miklos Szeredi08dab162006-02-01 13:39:15 +00001889
1890 node->cache_valid = 1;
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001891 pthread_mutex_unlock(&f->lock);
Miklos Szeredi320abe42006-01-30 18:14:51 +00001892}
1893
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001894static void fuse_lib_open(fuse_req_t req, fuse_ino_t ino,
1895 struct fuse_file_info *fi)
Miklos Szeredi5e183482001-10-31 14:52:35 +00001896{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001897 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001898 struct fuse_intr_data d;
Miklos Szeredi31066bb2005-08-01 14:49:31 +00001899 char *path = NULL;
1900 int err = 0;
Miklos Szeredi5e183482001-10-31 14:52:35 +00001901
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001902 err = -ENOENT;
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001903 pthread_rwlock_rdlock(&f->tree_lock);
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001904 path = get_path(f, ino);
1905 if (path) {
1906 fuse_prepare_interrupt(f, req, &d);
1907 err = fuse_fs_open(f->fs, path, fi);
1908 if (!err) {
1909 if (f->conf.direct_io)
1910 fi->direct_io = 1;
1911 if (f->conf.kernel_cache)
1912 fi->keep_cache = 1;
1913
1914 if (f->conf.auto_cache)
1915 open_auto_cache(f, ino, path, fi);
1916 }
1917 fuse_finish_interrupt(f, req, &d);
Miklos Szeredi40b9a5a2002-12-10 16:09:02 +00001918 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001919 if (!err) {
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001920 pthread_mutex_lock(&f->lock);
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001921 get_node(f, ino)->open_count++;
1922 pthread_mutex_unlock(&f->lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001923 if (fuse_reply_open(req, fi) == -ENOENT) {
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001924 /* The open syscall was interrupted, so it must be cancelled */
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001925 fuse_prepare_interrupt(f, req, &d);
1926 fuse_do_release(f, ino, path, fi);
1927 fuse_finish_interrupt(f, req, &d);
1928 } else if (f->conf.debug) {
1929 printf("OPEN[%llu] flags: 0x%x %s\n",
1930 (unsigned long long) fi->fh, fi->flags, path);
1931 fflush(stdout);
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001932 }
Miklos Szeredi73798f92004-07-12 15:55:11 +00001933 } else
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001934 reply_err(req, err);
Miklos Szeredi73798f92004-07-12 15:55:11 +00001935
Miklos Szeredi9a31cca2004-06-26 21:11:25 +00001936 if (path)
1937 free(path);
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001938 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001939}
1940
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001941static void fuse_lib_read(fuse_req_t req, fuse_ino_t ino, size_t size,
1942 off_t off, struct fuse_file_info *fi)
Miklos Szeredie2e4ac22004-05-18 08:45:28 +00001943{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001944 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredie2e4ac22004-05-18 08:45:28 +00001945 char *path;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001946 char *buf;
Miklos Szeredie2e4ac22004-05-18 08:45:28 +00001947 int res;
1948
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001949 buf = (char *) malloc(size);
1950 if (buf == NULL) {
1951 reply_err(req, -ENOMEM);
1952 return;
1953 }
1954
Miklos Szeredie2e4ac22004-05-18 08:45:28 +00001955 res = -ENOENT;
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001956 pthread_rwlock_rdlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001957 path = get_path(f, ino);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001958 if (path != NULL) {
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001959 struct fuse_intr_data d;
Miklos Szeredi659743b2005-12-09 17:41:42 +00001960 if (f->conf.debug) {
Miklos Szeredia039f8f2006-02-24 16:21:58 +00001961 printf("READ[%llu] %lu bytes from %llu\n",
1962 (unsigned long long) fi->fh, (unsigned long) size,
1963 (unsigned long long) off);
Miklos Szeredi209f5d02004-07-24 19:56:16 +00001964 fflush(stdout);
1965 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001966
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001967 fuse_prepare_interrupt(f, req, &d);
1968 res = fuse_fs_read(f->fs, path, buf, size, off, fi);
1969 fuse_finish_interrupt(f, req, &d);
Miklos Szeredie2e4ac22004-05-18 08:45:28 +00001970 free(path);
1971 }
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001972 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001973
1974 if (res >= 0) {
Miklos Szeredi659743b2005-12-09 17:41:42 +00001975 if (f->conf.debug) {
Miklos Szeredi3a770472005-11-11 21:32:42 +00001976 printf(" READ[%llu] %u bytes\n", (unsigned long long) fi->fh,
1977 res);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001978 fflush(stdout);
1979 }
Miklos Szeredif412d072005-10-14 21:24:32 +00001980 if ((size_t) res > size)
1981 fprintf(stderr, "fuse: read too many bytes");
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001982 fuse_reply_buf(req, buf, res);
1983 } else
1984 reply_err(req, res);
1985
1986 free(buf);
Miklos Szeredie2e4ac22004-05-18 08:45:28 +00001987}
1988
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001989static void fuse_lib_write(fuse_req_t req, fuse_ino_t ino, const char *buf,
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001990 size_t size, off_t off, struct fuse_file_info *fi)
Miklos Szeredic8ba2372002-12-10 12:26:00 +00001991{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001992 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001993 char *path;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001994 int res;
1995
1996 res = -ENOENT;
1997 pthread_rwlock_rdlock(&f->tree_lock);
1998 path = get_path(f, ino);
1999 if (path != NULL) {
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002000 struct fuse_intr_data d;
Miklos Szeredi659743b2005-12-09 17:41:42 +00002001 if (f->conf.debug) {
Miklos Szeredia039f8f2006-02-24 16:21:58 +00002002 printf("WRITE%s[%llu] %lu bytes to %llu\n",
Miklos Szeredi3a770472005-11-11 21:32:42 +00002003 fi->writepage ? "PAGE" : "", (unsigned long long) fi->fh,
Miklos Szeredia039f8f2006-02-24 16:21:58 +00002004 (unsigned long) size, (unsigned long long) off);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002005 fflush(stdout);
2006 }
2007
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002008 fuse_prepare_interrupt(f, req, &d);
2009 res = fuse_fs_write(f->fs, path, buf, size, off, fi);
2010 fuse_finish_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002011 free(path);
2012 }
2013 pthread_rwlock_unlock(&f->tree_lock);
2014
Miklos Szeredif412d072005-10-14 21:24:32 +00002015 if (res >= 0) {
Miklos Szeredi659743b2005-12-09 17:41:42 +00002016 if (f->conf.debug) {
Miklos Szeredi3a770472005-11-11 21:32:42 +00002017 printf(" WRITE%s[%llu] %u bytes\n",
2018 fi->writepage ? "PAGE" : "", (unsigned long long) fi->fh,
2019 res);
Miklos Szeredif412d072005-10-14 21:24:32 +00002020 fflush(stdout);
2021 }
2022 if ((size_t) res > size)
2023 fprintf(stderr, "fuse: wrote too many bytes");
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002024 fuse_reply_write(req, res);
Miklos Szeredif412d072005-10-14 21:24:32 +00002025 } else
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002026 reply_err(req, res);
2027}
2028
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002029static void fuse_lib_fsync(fuse_req_t req, fuse_ino_t ino, int datasync,
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002030 struct fuse_file_info *fi)
Miklos Szeredi5e183482001-10-31 14:52:35 +00002031{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002032 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredi5e183482001-10-31 14:52:35 +00002033 char *path;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002034 int err;
Miklos Szerediab974562005-04-07 15:40:21 +00002035
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002036 err = -ENOENT;
2037 pthread_rwlock_rdlock(&f->tree_lock);
2038 path = get_path(f, ino);
2039 if (path != NULL) {
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002040 struct fuse_intr_data d;
Miklos Szeredi659743b2005-12-09 17:41:42 +00002041 if (f->conf.debug) {
Miklos Szeredi3a770472005-11-11 21:32:42 +00002042 printf("FSYNC[%llu]\n", (unsigned long long) fi->fh);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002043 fflush(stdout);
2044 }
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002045 fuse_prepare_interrupt(f, req, &d);
2046 err = fuse_fs_fsync(f->fs, path, datasync, fi);
2047 fuse_finish_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002048 free(path);
2049 }
2050 pthread_rwlock_unlock(&f->tree_lock);
2051 reply_err(req, err);
2052}
2053
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002054static struct fuse_dh *get_dirhandle(const struct fuse_file_info *llfi,
2055 struct fuse_file_info *fi)
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002056{
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002057 struct fuse_dh *dh = (struct fuse_dh *) (uintptr_t) llfi->fh;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002058 memset(fi, 0, sizeof(struct fuse_file_info));
2059 fi->fh = dh->fh;
Miklos Szerediead7f102005-11-28 16:02:27 +00002060 fi->fh_old = dh->fh;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002061 return dh;
2062}
2063
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002064static void fuse_lib_opendir(fuse_req_t req, fuse_ino_t ino,
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002065 struct fuse_file_info *llfi)
2066{
2067 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002068 struct fuse_intr_data d;
2069 struct fuse_dh *dh;
2070 struct fuse_file_info fi;
2071 char *path;
2072 int err;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002073
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002074 dh = (struct fuse_dh *) malloc(sizeof(struct fuse_dh));
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002075 if (dh == NULL) {
2076 reply_err(req, -ENOMEM);
Miklos Szerediab974562005-04-07 15:40:21 +00002077 return;
Miklos Szeredi5e183482001-10-31 14:52:35 +00002078 }
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002079 memset(dh, 0, sizeof(struct fuse_dh));
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002080 dh->fuse = f;
2081 dh->contents = NULL;
2082 dh->len = 0;
2083 dh->filled = 0;
2084 dh->nodeid = ino;
Miklos Szeredi38f152c2006-09-03 18:28:52 +00002085 fuse_mutex_init(&dh->lock);
Miklos Szerediab974562005-04-07 15:40:21 +00002086
Miklos Szeredi3a770472005-11-11 21:32:42 +00002087 llfi->fh = (uintptr_t) dh;
Miklos Szerediab974562005-04-07 15:40:21 +00002088
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002089 memset(&fi, 0, sizeof(fi));
2090 fi.flags = llfi->flags;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002091
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002092 err = -ENOENT;
2093 pthread_rwlock_rdlock(&f->tree_lock);
2094 path = get_path(f, ino);
2095 if (path != NULL) {
2096 fuse_prepare_interrupt(f, req, &d);
2097 err = fuse_fs_opendir(f->fs, path, &fi);
2098 fuse_finish_interrupt(f, req, &d);
2099 dh->fh = fi.fh;
2100 }
2101 if (!err) {
2102 if (fuse_reply_open(req, llfi) == -ENOENT) {
2103 /* The opendir syscall was interrupted, so it must be cancelled */
2104 fuse_prepare_interrupt(f, req, &d);
2105 fuse_fs_releasedir(f->fs, path, &fi);
2106 fuse_finish_interrupt(f, req, &d);
2107 pthread_mutex_destroy(&dh->lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002108 free(dh);
2109 }
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002110 } else {
2111 reply_err(req, err);
2112 free(dh);
2113 }
2114 free(path);
2115 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredi5e183482001-10-31 14:52:35 +00002116}
Miklos Szeredib483c932001-10-29 14:57:57 +00002117
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002118static int extend_contents(struct fuse_dh *dh, unsigned minsize)
Miklos Szeredi1bf64f42006-02-17 15:49:25 +00002119{
2120 if (minsize > dh->size) {
2121 char *newptr;
2122 unsigned newsize = dh->size;
2123 if (!newsize)
2124 newsize = 1024;
2125 while (newsize < minsize)
2126 newsize *= 2;
2127
2128 newptr = (char *) realloc(dh->contents, newsize);
2129 if (!newptr) {
2130 dh->error = -ENOMEM;
2131 return -1;
2132 }
2133 dh->contents = newptr;
2134 dh->size = newsize;
2135 }
2136 return 0;
2137}
2138
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002139static int fill_dir(void *dh_, const char *name, const struct stat *statp,
2140 off_t off)
Miklos Szeredia181e612001-11-06 12:03:23 +00002141{
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002142 struct fuse_dh *dh = (struct fuse_dh *) dh_;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002143 struct stat stbuf;
Miklos Szeredi1bf64f42006-02-17 15:49:25 +00002144 size_t newlen;
Miklos Szeredifb28c5e2004-11-26 12:15:06 +00002145
Miklos Szeredif6e0ec62005-08-03 09:11:06 +00002146 if (statp)
2147 stbuf = *statp;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002148 else {
2149 memset(&stbuf, 0, sizeof(stbuf));
Miklos Szeredie248e4b2005-12-14 16:18:32 +00002150 stbuf.st_ino = FUSE_UNKNOWN_INO;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002151 }
Miklos Szeredia181e612001-11-06 12:03:23 +00002152
Miklos Szeredi659743b2005-12-09 17:41:42 +00002153 if (!dh->fuse->conf.use_ino) {
Miklos Szeredie248e4b2005-12-14 16:18:32 +00002154 stbuf.st_ino = FUSE_UNKNOWN_INO;
Miklos Szeredi659743b2005-12-09 17:41:42 +00002155 if (dh->fuse->conf.readdir_ino) {
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002156 struct node *node;
2157 pthread_mutex_lock(&dh->fuse->lock);
2158 node = lookup_node(dh->fuse, dh->nodeid, name);
2159 if (node)
2160 stbuf.st_ino = (ino_t) node->nodeid;
2161 pthread_mutex_unlock(&dh->fuse->lock);
Miklos Szeredi6ebe2342002-01-06 21:44:16 +00002162 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002163 }
Miklos Szeredi6ebe2342002-01-06 21:44:16 +00002164
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002165 if (off) {
Miklos Szeredi1bf64f42006-02-17 15:49:25 +00002166 if (extend_contents(dh, dh->needlen) == -1)
2167 return 1;
2168
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002169 dh->filled = 0;
Miklos Szeredi1bf64f42006-02-17 15:49:25 +00002170 newlen = dh->len + fuse_add_direntry(dh->req, dh->contents + dh->len,
2171 dh->needlen - dh->len, name,
2172 &stbuf, off);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002173 if (newlen > dh->needlen)
2174 return 1;
Miklos Szeredi1bf64f42006-02-17 15:49:25 +00002175 } else {
2176 newlen = dh->len + fuse_add_direntry(dh->req, NULL, 0, name, NULL, 0);
2177 if (extend_contents(dh, newlen) == -1)
Miklos Szeredic4c12ae2005-10-20 14:48:50 +00002178 return 1;
Miklos Szeredi1bf64f42006-02-17 15:49:25 +00002179
2180 fuse_add_direntry(dh->req, dh->contents + dh->len, dh->size - dh->len,
2181 name, &stbuf, newlen);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002182 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002183 dh->len = newlen;
2184 return 0;
2185}
2186
Miklos Szeredi1bf64f42006-02-17 15:49:25 +00002187static int readdir_fill(struct fuse *f, fuse_req_t req, fuse_ino_t ino,
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002188 size_t size, off_t off, struct fuse_dh *dh,
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002189 struct fuse_file_info *fi)
2190{
2191 int err = -ENOENT;
2192 char *path;
2193 pthread_rwlock_rdlock(&f->tree_lock);
2194 path = get_path(f, ino);
2195 if (path != NULL) {
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002196 struct fuse_intr_data d;
2197
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002198 dh->len = 0;
2199 dh->error = 0;
2200 dh->needlen = size;
2201 dh->filled = 1;
Miklos Szeredi1bf64f42006-02-17 15:49:25 +00002202 dh->req = req;
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002203 fuse_prepare_interrupt(f, req, &d);
2204 err = fuse_fs_readdir(f->fs, path, dh, fill_dir, off, fi);
2205 fuse_finish_interrupt(f, req, &d);
Miklos Szeredi1bf64f42006-02-17 15:49:25 +00002206 dh->req = NULL;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002207 if (!err)
2208 err = dh->error;
2209 if (err)
2210 dh->filled = 0;
Miklos Szeredi97c61e92001-11-07 12:09:43 +00002211 free(path);
Miklos Szeredia181e612001-11-06 12:03:23 +00002212 }
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00002213 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002214 return err;
2215}
Miklos Szeredie5183742005-02-02 11:14:04 +00002216
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002217static void fuse_lib_readdir(fuse_req_t req, fuse_ino_t ino, size_t size,
2218 off_t off, struct fuse_file_info *llfi)
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002219{
2220 struct fuse *f = req_fuse_prepare(req);
2221 struct fuse_file_info fi;
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002222 struct fuse_dh *dh = get_dirhandle(llfi, &fi);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002223
2224 pthread_mutex_lock(&dh->lock);
Miklos Szeredi77ccf652005-08-19 14:40:27 +00002225 /* According to SUS, directory contents need to be refreshed on
2226 rewinddir() */
2227 if (!off)
2228 dh->filled = 0;
2229
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002230 if (!dh->filled) {
Miklos Szeredi1bf64f42006-02-17 15:49:25 +00002231 int err = readdir_fill(f, req, ino, size, off, dh, &fi);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002232 if (err) {
2233 reply_err(req, err);
2234 goto out;
2235 }
Miklos Szeredia181e612001-11-06 12:03:23 +00002236 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002237 if (dh->filled) {
2238 if (off < dh->len) {
2239 if (off + size > dh->len)
2240 size = dh->len - off;
2241 } else
2242 size = 0;
2243 } else {
2244 size = dh->len;
2245 off = 0;
2246 }
2247 fuse_reply_buf(req, dh->contents + off, size);
2248 out:
2249 pthread_mutex_unlock(&dh->lock);
2250}
Miklos Szeredia181e612001-11-06 12:03:23 +00002251
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002252static void fuse_lib_releasedir(fuse_req_t req, fuse_ino_t ino,
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002253 struct fuse_file_info *llfi)
2254{
2255 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002256 struct fuse_intr_data d;
Miklos Szeredi9b813af2005-07-21 07:59:37 +00002257 struct fuse_file_info fi;
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002258 struct fuse_dh *dh = get_dirhandle(llfi, &fi);
2259 char *path;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002260
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002261 pthread_rwlock_rdlock(&f->tree_lock);
2262 path = get_path(f, ino);
2263 fuse_prepare_interrupt(f, req, &d);
2264 fuse_fs_releasedir(f->fs, path ? path : "-", &fi);
2265 fuse_finish_interrupt(f, req, &d);
2266 if (path)
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002267 free(path);
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002268 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002269 pthread_mutex_lock(&dh->lock);
2270 pthread_mutex_unlock(&dh->lock);
2271 pthread_mutex_destroy(&dh->lock);
2272 free(dh->contents);
2273 free(dh);
2274 reply_err(req, 0);
2275}
2276
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002277static void fuse_lib_fsyncdir(fuse_req_t req, fuse_ino_t ino, int datasync,
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002278 struct fuse_file_info *llfi)
2279{
2280 struct fuse *f = req_fuse_prepare(req);
2281 struct fuse_file_info fi;
2282 char *path;
2283 int err;
2284
2285 get_dirhandle(llfi, &fi);
2286
2287 err = -ENOENT;
2288 pthread_rwlock_rdlock(&f->tree_lock);
2289 path = get_path(f, ino);
2290 if (path != NULL) {
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002291 struct fuse_intr_data d;
2292 fuse_prepare_interrupt(f, req, &d);
2293 err = fuse_fs_fsyncdir(f->fs, path, datasync, &fi);
2294 fuse_finish_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002295 free(path);
2296 }
2297 pthread_rwlock_unlock(&f->tree_lock);
2298 reply_err(req, err);
Miklos Szeredia181e612001-11-06 12:03:23 +00002299}
2300
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002301static void fuse_lib_statfs(fuse_req_t req, fuse_ino_t ino)
Miklos Szeredi18e75e42004-02-19 14:23:27 +00002302{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002303 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredi52cb09d2005-11-07 11:59:00 +00002304 struct statvfs buf;
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002305 char *path;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002306 int err;
Mark Glinesd84b39a2002-01-07 16:32:02 +00002307
Miklos Szeredi52cb09d2005-11-07 11:59:00 +00002308 memset(&buf, 0, sizeof(buf));
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002309 pthread_rwlock_rdlock(&f->tree_lock);
2310 if (!ino) {
2311 err = -ENOMEM;
2312 path = strdup("/");
2313 } else {
2314 err = -ENOENT;
2315 path = get_path(f, ino);
2316 }
2317 if (path) {
2318 struct fuse_intr_data d;
2319 fuse_prepare_interrupt(f, req, &d);
2320 err = fuse_fs_statfs(f->fs, path, &buf);
2321 fuse_finish_interrupt(f, req, &d);
2322 free(path);
2323 }
2324 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredi77f39942004-03-25 11:17:52 +00002325
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002326 if (!err)
2327 fuse_reply_statfs(req, &buf);
Miklos Szeredi03cebae2004-03-31 10:19:18 +00002328 else
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002329 reply_err(req, err);
Miklos Szeredi03cebae2004-03-31 10:19:18 +00002330}
2331
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002332static void fuse_lib_setxattr(fuse_req_t req, fuse_ino_t ino, const char *name,
2333 const char *value, size_t size, int flags)
Miklos Szeredi3ed84232004-03-30 15:17:26 +00002334{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002335 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredi3ed84232004-03-30 15:17:26 +00002336 char *path;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002337 int err;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00002338
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002339 err = -ENOENT;
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00002340 pthread_rwlock_rdlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002341 path = get_path(f, ino);
Miklos Szeredi3ed84232004-03-30 15:17:26 +00002342 if (path != NULL) {
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002343 struct fuse_intr_data d;
2344 fuse_prepare_interrupt(f, req, &d);
2345 err = fuse_fs_setxattr(f->fs, path, name, value, size, flags);
2346 fuse_finish_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002347 free(path);
2348 }
2349 pthread_rwlock_unlock(&f->tree_lock);
2350 reply_err(req, err);
2351}
2352
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002353static int common_getxattr(struct fuse *f, fuse_req_t req, fuse_ino_t ino,
2354 const char *name, char *value, size_t size)
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002355{
2356 int err;
2357 char *path;
2358
2359 err = -ENOENT;
2360 pthread_rwlock_rdlock(&f->tree_lock);
2361 path = get_path(f, ino);
2362 if (path != NULL) {
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002363 struct fuse_intr_data d;
2364 fuse_prepare_interrupt(f, req, &d);
2365 err = fuse_fs_getxattr(f->fs, path, name, value, size);
2366 fuse_finish_interrupt(f, req, &d);
Miklos Szerediab974562005-04-07 15:40:21 +00002367 free(path);
2368 }
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00002369 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szerediab974562005-04-07 15:40:21 +00002370 return err;
2371}
2372
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002373static void fuse_lib_getxattr(fuse_req_t req, fuse_ino_t ino, const char *name,
2374 size_t size)
Miklos Szeredi3ead28e2005-01-18 21:23:41 +00002375{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002376 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredi4283ee72005-03-21 12:09:04 +00002377 int res;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002378
2379 if (size) {
2380 char *value = (char *) malloc(size);
2381 if (value == NULL) {
2382 reply_err(req, -ENOMEM);
2383 return;
2384 }
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002385 res = common_getxattr(f, req, ino, name, value, size);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002386 if (res > 0)
2387 fuse_reply_buf(req, value, res);
2388 else
2389 reply_err(req, res);
2390 free(value);
2391 } else {
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002392 res = common_getxattr(f, req, ino, name, NULL, 0);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002393 if (res >= 0)
2394 fuse_reply_xattr(req, res);
2395 else
2396 reply_err(req, res);
2397 }
2398}
2399
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002400static int common_listxattr(struct fuse *f, fuse_req_t req, fuse_ino_t ino,
2401 char *list, size_t size)
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002402{
Miklos Szeredi4283ee72005-03-21 12:09:04 +00002403 char *path;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002404 int err;
Miklos Szeredi4283ee72005-03-21 12:09:04 +00002405
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002406 err = -ENOENT;
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00002407 pthread_rwlock_rdlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002408 path = get_path(f, ino);
Miklos Szeredi4283ee72005-03-21 12:09:04 +00002409 if (path != NULL) {
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002410 struct fuse_intr_data d;
2411 fuse_prepare_interrupt(f, req, &d);
2412 err = fuse_fs_listxattr(f->fs, path, list, size);
2413 fuse_finish_interrupt(f, req, &d);
Miklos Szeredi4283ee72005-03-21 12:09:04 +00002414 free(path);
2415 }
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00002416 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002417 return err;
Miklos Szeredi4283ee72005-03-21 12:09:04 +00002418}
Miklos Szeredi3ead28e2005-01-18 21:23:41 +00002419
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002420static void fuse_lib_listxattr(fuse_req_t req, fuse_ino_t ino, size_t size)
Miklos Szeredi43696432001-11-18 19:15:05 +00002421{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002422 struct fuse *f = req_fuse_prepare(req);
2423 int res;
2424
2425 if (size) {
2426 char *list = (char *) malloc(size);
2427 if (list == NULL) {
2428 reply_err(req, -ENOMEM);
2429 return;
2430 }
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002431 res = common_listxattr(f, req, ino, list, size);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002432 if (res > 0)
2433 fuse_reply_buf(req, list, res);
2434 else
2435 reply_err(req, res);
2436 free(list);
2437 } else {
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002438 res = common_listxattr(f, req, ino, NULL, 0);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002439 if (res >= 0)
2440 fuse_reply_xattr(req, res);
2441 else
2442 reply_err(req, res);
2443 }
Miklos Szeredi43696432001-11-18 19:15:05 +00002444}
2445
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002446static void fuse_lib_removexattr(fuse_req_t req, fuse_ino_t ino,
2447 const char *name)
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002448{
2449 struct fuse *f = req_fuse_prepare(req);
2450 char *path;
2451 int err;
2452
2453 err = -ENOENT;
2454 pthread_rwlock_rdlock(&f->tree_lock);
2455 path = get_path(f, ino);
2456 if (path != NULL) {
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002457 struct fuse_intr_data d;
2458 fuse_prepare_interrupt(f, req, &d);
2459 err = fuse_fs_removexattr(f->fs, path, name);
2460 fuse_finish_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002461 free(path);
2462 }
2463 pthread_rwlock_unlock(&f->tree_lock);
2464 reply_err(req, err);
2465}
2466
Miklos Szeredi0c59ebf2006-09-10 20:53:36 +00002467static struct lock *locks_conflict(struct node *node, const struct lock *lock)
2468{
2469 struct lock *l;
2470
2471 for (l = node->locks; l; l = l->next)
2472 if (l->owner != lock->owner &&
2473 lock->start <= l->end && l->start <= lock->end &&
2474 (l->type == F_WRLCK || lock->type == F_WRLCK))
2475 break;
2476
2477 return l;
2478}
2479
2480static void delete_lock(struct lock **lockp)
2481{
2482 struct lock *l = *lockp;
2483 *lockp = l->next;
2484 free(l);
2485}
2486
2487static void insert_lock(struct lock **pos, struct lock *lock)
2488{
2489 lock->next = *pos;
2490 *pos = lock;
2491}
2492
2493static int locks_insert(struct node *node, struct lock *lock)
2494{
2495 struct lock **lp;
2496 struct lock *newl1 = NULL;
2497 struct lock *newl2 = NULL;
2498
2499 if (lock->type != F_UNLCK || lock->start != 0 || lock->end != OFFSET_MAX) {
2500 newl1 = malloc(sizeof(struct lock));
2501 newl2 = malloc(sizeof(struct lock));
2502
2503 if (!newl1 || !newl2) {
2504 free(newl1);
2505 free(newl2);
2506 return -ENOLCK;
2507 }
2508 }
2509
2510 for (lp = &node->locks; *lp;) {
2511 struct lock *l = *lp;
2512 if (l->owner != lock->owner)
2513 goto skip;
2514
2515 if (lock->type == l->type) {
2516 if (l->end < lock->start - 1)
2517 goto skip;
2518 if (lock->end < l->start - 1)
2519 break;
2520 if (l->start <= lock->start && lock->end <= l->end)
2521 goto out;
2522 if (l->start < lock->start)
2523 lock->start = l->start;
2524 if (lock->end < l->end)
2525 lock->end = l->end;
2526 goto delete;
2527 } else {
2528 if (l->end < lock->start)
2529 goto skip;
2530 if (lock->end < l->start)
2531 break;
2532 if (lock->start <= l->start && l->end <= lock->end)
2533 goto delete;
2534 if (l->end <= lock->end) {
2535 l->end = lock->start - 1;
2536 goto skip;
2537 }
2538 if (lock->start <= l->start) {
2539 l->start = lock->end + 1;
2540 break;
2541 }
2542 *newl2 = *l;
2543 newl2->start = lock->end + 1;
2544 l->end = lock->start - 1;
2545 insert_lock(&l->next, newl2);
2546 newl2 = NULL;
2547 }
2548 skip:
2549 lp = &l->next;
2550 continue;
2551
2552 delete:
2553 delete_lock(lp);
2554 }
2555 if (lock->type != F_UNLCK) {
2556 *newl1 = *lock;
2557 insert_lock(lp, newl1);
2558 newl1 = NULL;
2559 }
2560out:
2561 free(newl1);
2562 free(newl2);
2563 return 0;
2564}
2565
2566static void flock_to_lock(struct flock *flock, struct lock *lock)
2567{
2568 memset(lock, 0, sizeof(struct lock));
2569 lock->type = flock->l_type;
2570 lock->start = flock->l_start;
2571 lock->end = flock->l_len ? flock->l_start + flock->l_len - 1 : OFFSET_MAX;
2572 lock->pid = flock->l_pid;
2573}
2574
2575static void lock_to_flock(struct lock *lock, struct flock *flock)
2576{
2577 flock->l_type = lock->type;
2578 flock->l_start = lock->start;
2579 flock->l_len = (lock->end == OFFSET_MAX) ? 0 : lock->end - lock->start + 1;
2580 flock->l_pid = lock->pid;
2581}
2582
Miklos Szeredi6353dca2007-05-11 09:19:36 +00002583static int fuse_flush_common(struct fuse *f, fuse_req_t req, fuse_ino_t ino,
2584 const char *path, struct fuse_file_info *fi)
Csaba Henk79b9e9f2007-05-10 22:56:46 +00002585{
Csaba Henk79b9e9f2007-05-10 22:56:46 +00002586 struct fuse_intr_data d;
2587 struct flock lock;
2588 struct lock l;
Miklos Szeredi0c59ebf2006-09-10 20:53:36 +00002589 int err;
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002590 int errlock;
Miklos Szeredi0c59ebf2006-09-10 20:53:36 +00002591
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002592 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredi6353dca2007-05-11 09:19:36 +00002593 memset(&lock, 0, sizeof(lock));
2594 lock.l_type = F_UNLCK;
2595 lock.l_whence = SEEK_SET;
2596 err = fuse_fs_flush(f->fs, path, fi);
2597 errlock = fuse_fs_lock(f->fs, path, fi, F_SETLK, &lock);
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002598 fuse_finish_interrupt(f, req, &d);
Miklos Szeredi6353dca2007-05-11 09:19:36 +00002599
Csaba Henk79b9e9f2007-05-10 22:56:46 +00002600 if (errlock != -ENOSYS) {
Miklos Szeredi0c59ebf2006-09-10 20:53:36 +00002601 flock_to_lock(&lock, &l);
Miklos Szeredi07407852006-09-30 20:03:52 +00002602 l.owner = fi->lock_owner;
Miklos Szeredi0c59ebf2006-09-10 20:53:36 +00002603 pthread_mutex_lock(&f->lock);
2604 locks_insert(get_node(f, ino), &l);
2605 pthread_mutex_unlock(&f->lock);
2606
2607 /* if op.lock() is defined FLUSH is needed regardless of op.flush() */
2608 if (err == -ENOSYS)
2609 err = 0;
2610 }
Miklos Szeredi6353dca2007-05-11 09:19:36 +00002611 return err;
2612}
2613
2614static void fuse_lib_release(fuse_req_t req, fuse_ino_t ino,
2615 struct fuse_file_info *fi)
2616{
2617 struct fuse *f = req_fuse_prepare(req);
2618 struct fuse_intr_data d;
2619 char *path;
2620 int err = 0;
2621
2622 pthread_rwlock_rdlock(&f->tree_lock);
2623 path = get_path(f, ino);
2624 if (f->conf.debug) {
2625 printf("RELEASE%s[%llu] flags: 0x%x\n", fi->flush ? "+FLUSH" : "",
2626 (unsigned long long) fi->fh, fi->flags);
2627 fflush(stdout);
2628 }
2629
2630 if (fi->flush) {
2631 err = fuse_flush_common(f, req, ino, path, fi);
2632 if (err == -ENOSYS)
2633 err = 0;
2634 }
2635
2636 fuse_prepare_interrupt(f, req, &d);
2637 fuse_do_release(f, ino, path, fi);
2638 fuse_finish_interrupt(f, req, &d);
2639 free(path);
2640 pthread_rwlock_unlock(&f->tree_lock);
2641
2642 reply_err(req, err);
2643}
2644
2645static void fuse_lib_flush(fuse_req_t req, fuse_ino_t ino,
2646 struct fuse_file_info *fi)
2647{
2648 struct fuse *f = req_fuse_prepare(req);
2649 char *path;
2650 int err;
2651
2652 pthread_rwlock_rdlock(&f->tree_lock);
2653 path = get_path(f, ino);
2654 if (path && f->conf.debug) {
2655 printf("FLUSH[%llu]\n", (unsigned long long) fi->fh);
2656 fflush(stdout);
2657 }
2658 err = fuse_flush_common(f, req, ino, path, fi);
2659 free(path);
Miklos Szeredi0c59ebf2006-09-10 20:53:36 +00002660 pthread_rwlock_unlock(&f->tree_lock);
2661 reply_err(req, err);
2662}
2663
Miklos Szeredi9a5c11d2006-07-30 17:33:40 +00002664static int fuse_lock_common(fuse_req_t req, fuse_ino_t ino,
2665 struct fuse_file_info *fi, struct flock *lock,
Miklos Szeredi07407852006-09-30 20:03:52 +00002666 int cmd)
Miklos Szeredi9a5c11d2006-07-30 17:33:40 +00002667{
2668 struct fuse *f = req_fuse_prepare(req);
2669 char *path;
2670 int err;
2671
2672 err = -ENOENT;
2673 pthread_rwlock_rdlock(&f->tree_lock);
2674 path = get_path(f, ino);
2675 if (path != NULL) {
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002676 struct fuse_intr_data d;
2677 fuse_prepare_interrupt(f, req, &d);
2678 err = fuse_fs_lock(f->fs, path, fi, cmd, lock);
2679 fuse_finish_interrupt(f, req, &d);
Miklos Szeredi9a5c11d2006-07-30 17:33:40 +00002680 free(path);
2681 }
2682 pthread_rwlock_unlock(&f->tree_lock);
2683 return err;
2684}
2685
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002686static void fuse_lib_getlk(fuse_req_t req, fuse_ino_t ino,
2687 struct fuse_file_info *fi, struct flock *lock)
Miklos Szeredi9a5c11d2006-07-30 17:33:40 +00002688{
Miklos Szeredi0c59ebf2006-09-10 20:53:36 +00002689 int err;
2690 struct lock l;
2691 struct lock *conflict;
2692 struct fuse *f = req_fuse(req);
2693
2694 flock_to_lock(lock, &l);
Miklos Szeredi07407852006-09-30 20:03:52 +00002695 l.owner = fi->lock_owner;
Miklos Szeredi0c59ebf2006-09-10 20:53:36 +00002696 pthread_mutex_lock(&f->lock);
2697 conflict = locks_conflict(get_node(f, ino), &l);
2698 if (conflict)
2699 lock_to_flock(conflict, lock);
2700 pthread_mutex_unlock(&f->lock);
2701 if (!conflict)
Miklos Szeredi07407852006-09-30 20:03:52 +00002702 err = fuse_lock_common(req, ino, fi, lock, F_GETLK);
Miklos Szeredi0c59ebf2006-09-10 20:53:36 +00002703 else
2704 err = 0;
2705
Miklos Szeredi9a5c11d2006-07-30 17:33:40 +00002706 if (!err)
2707 fuse_reply_lock(req, lock);
2708 else
2709 reply_err(req, err);
2710}
2711
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002712static void fuse_lib_setlk(fuse_req_t req, fuse_ino_t ino,
2713 struct fuse_file_info *fi, struct flock *lock,
2714 int sleep)
Miklos Szeredi9a5c11d2006-07-30 17:33:40 +00002715{
Miklos Szeredi07407852006-09-30 20:03:52 +00002716 int err = fuse_lock_common(req, ino, fi, lock, sleep ? F_SETLKW : F_SETLK);
Miklos Szeredi0c59ebf2006-09-10 20:53:36 +00002717 if (!err) {
2718 struct fuse *f = req_fuse(req);
2719 struct lock l;
2720 flock_to_lock(lock, &l);
Miklos Szeredi07407852006-09-30 20:03:52 +00002721 l.owner = fi->lock_owner;
Miklos Szeredi0c59ebf2006-09-10 20:53:36 +00002722 pthread_mutex_lock(&f->lock);
2723 locks_insert(get_node(f, ino), &l);
2724 pthread_mutex_unlock(&f->lock);
2725 }
2726 reply_err(req, err);
Miklos Szeredi9a5c11d2006-07-30 17:33:40 +00002727}
2728
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002729static void fuse_lib_bmap(fuse_req_t req, fuse_ino_t ino, size_t blocksize,
2730 uint64_t idx)
Miklos Szeredi708b4812006-09-30 16:02:25 +00002731{
2732 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002733 struct fuse_intr_data d;
Miklos Szeredi708b4812006-09-30 16:02:25 +00002734 char *path;
2735 int err;
2736
2737 err = -ENOENT;
2738 pthread_rwlock_rdlock(&f->tree_lock);
2739 path = get_path(f, ino);
2740 if (path != NULL) {
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002741 fuse_prepare_interrupt(f, req, &d);
2742 err = fuse_fs_bmap(f->fs, path, blocksize, &idx);
2743 fuse_finish_interrupt(f, req, &d);
Miklos Szeredi708b4812006-09-30 16:02:25 +00002744 free(path);
2745 }
2746 pthread_rwlock_unlock(&f->tree_lock);
2747 if (!err)
2748 fuse_reply_bmap(req, idx);
2749 else
2750 reply_err(req, err);
2751}
2752
Miklos Szeredia1482422005-08-14 23:00:27 +00002753static struct fuse_lowlevel_ops fuse_path_ops = {
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002754 .init = fuse_lib_init,
2755 .destroy = fuse_lib_destroy,
2756 .lookup = fuse_lib_lookup,
2757 .forget = fuse_lib_forget,
2758 .getattr = fuse_lib_getattr,
2759 .setattr = fuse_lib_setattr,
2760 .access = fuse_lib_access,
2761 .readlink = fuse_lib_readlink,
2762 .mknod = fuse_lib_mknod,
2763 .mkdir = fuse_lib_mkdir,
2764 .unlink = fuse_lib_unlink,
2765 .rmdir = fuse_lib_rmdir,
2766 .symlink = fuse_lib_symlink,
2767 .rename = fuse_lib_rename,
2768 .link = fuse_lib_link,
2769 .create = fuse_lib_create,
2770 .open = fuse_lib_open,
2771 .read = fuse_lib_read,
2772 .write = fuse_lib_write,
2773 .flush = fuse_lib_flush,
2774 .release = fuse_lib_release,
2775 .fsync = fuse_lib_fsync,
2776 .opendir = fuse_lib_opendir,
2777 .readdir = fuse_lib_readdir,
2778 .releasedir = fuse_lib_releasedir,
2779 .fsyncdir = fuse_lib_fsyncdir,
2780 .statfs = fuse_lib_statfs,
2781 .setxattr = fuse_lib_setxattr,
2782 .getxattr = fuse_lib_getxattr,
2783 .listxattr = fuse_lib_listxattr,
2784 .removexattr = fuse_lib_removexattr,
2785 .getlk = fuse_lib_getlk,
2786 .setlk = fuse_lib_setlk,
2787 .bmap = fuse_lib_bmap,
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002788};
2789
Miklos Szeredia1482422005-08-14 23:00:27 +00002790static void free_cmd(struct fuse_cmd *cmd)
2791{
2792 free(cmd->buf);
2793 free(cmd);
2794}
2795
Miklos Szeredif458b8c2004-12-07 16:46:42 +00002796void fuse_process_cmd(struct fuse *f, struct fuse_cmd *cmd)
Miklos Szeredia181e612001-11-06 12:03:23 +00002797{
Miklos Szeredi178451d2005-08-15 13:19:07 +00002798 fuse_session_process(f->se, cmd->buf, cmd->buflen, cmd->ch);
Miklos Szeredifa829b52005-12-02 11:05:41 +00002799 free_cmd(cmd);
Miklos Szeredia181e612001-11-06 12:03:23 +00002800}
2801
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002802int fuse_exited(struct fuse *f)
Miklos Szeredi65cf7c72004-06-30 11:34:56 +00002803{
Miklos Szeredia1482422005-08-14 23:00:27 +00002804 return fuse_session_exited(f->se);
2805}
2806
2807struct fuse_session *fuse_get_session(struct fuse *f)
2808{
2809 return f->se;
2810}
2811
2812static struct fuse_cmd *fuse_alloc_cmd(size_t bufsize)
2813{
2814 struct fuse_cmd *cmd = (struct fuse_cmd *) malloc(sizeof(*cmd));
2815 if (cmd == NULL) {
2816 fprintf(stderr, "fuse: failed to allocate cmd\n");
2817 return NULL;
2818 }
2819 cmd->buf = (char *) malloc(bufsize);
2820 if (cmd->buf == NULL) {
2821 fprintf(stderr, "fuse: failed to allocate read buffer\n");
2822 free(cmd);
2823 return NULL;
2824 }
2825 return cmd;
Miklos Szeredi65cf7c72004-06-30 11:34:56 +00002826}
2827
Miklos Szeredif458b8c2004-12-07 16:46:42 +00002828struct fuse_cmd *fuse_read_cmd(struct fuse *f)
Miklos Szeredi2df1c042001-11-06 15:07:17 +00002829{
Miklos Szeredia1482422005-08-14 23:00:27 +00002830 struct fuse_chan *ch = fuse_session_next_chan(f->se, NULL);
2831 size_t bufsize = fuse_chan_bufsize(ch);
2832 struct fuse_cmd *cmd = fuse_alloc_cmd(bufsize);
2833 if (cmd != NULL) {
Miklos Szeredi8d975f62006-03-17 15:56:05 +00002834 int res = fuse_chan_recv(&ch, cmd->buf, bufsize);
Miklos Szeredia1482422005-08-14 23:00:27 +00002835 if (res <= 0) {
2836 free_cmd(cmd);
Miklos Szeredi5d9ce362006-03-01 12:10:13 +00002837 if (res < 0 && res != -EINTR && res != -EAGAIN)
Miklos Szeredifa829b52005-12-02 11:05:41 +00002838 fuse_exit(f);
Miklos Szeredia1482422005-08-14 23:00:27 +00002839 return NULL;
2840 }
2841 cmd->buflen = res;
Miklos Szeredi178451d2005-08-15 13:19:07 +00002842 cmd->ch = ch;
Miklos Szeredia1482422005-08-14 23:00:27 +00002843 }
2844 return cmd;
Miklos Szeredi2df1c042001-11-06 15:07:17 +00002845}
2846
Miklos Szeredib2cf9562004-09-16 08:42:40 +00002847int fuse_loop(struct fuse *f)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00002848{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002849 if (f)
Miklos Szeredia1482422005-08-14 23:00:27 +00002850 return fuse_session_loop(f->se);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002851 else
Miklos Szeredib2cf9562004-09-16 08:42:40 +00002852 return -1;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00002853}
2854
Miklos Szeredi891b8742004-07-29 09:27:49 +00002855int fuse_invalidate(struct fuse *f, const char *path)
2856{
Miklos Szeredie56818b2004-12-12 11:45:24 +00002857 (void) f;
2858 (void) path;
2859 return -EINVAL;
Miklos Szeredi891b8742004-07-29 09:27:49 +00002860}
2861
Miklos Szeredi0f48a262002-12-05 14:23:01 +00002862void fuse_exit(struct fuse *f)
2863{
Miklos Szeredia1482422005-08-14 23:00:27 +00002864 fuse_session_exit(f->se);
Miklos Szeredi0f48a262002-12-05 14:23:01 +00002865}
2866
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002867struct fuse_context *fuse_get_context(void)
Miklos Szeredi2e50d432001-12-20 12:17:25 +00002868{
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002869 return &fuse_get_context_internal()->ctx;
2870}
2871
2872int fuse_interrupted(void)
2873{
2874 return fuse_req_interrupted(fuse_get_context_internal()->req);
Miklos Szeredid169f312004-09-22 08:48:26 +00002875}
2876
Miklos Szeredif458b8c2004-12-07 16:46:42 +00002877void fuse_set_getcontext_func(struct fuse_context *(*func)(void))
Miklos Szeredid169f312004-09-22 08:48:26 +00002878{
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002879 (void) func;
2880 /* no-op */
Miklos Szeredi2e50d432001-12-20 12:17:25 +00002881}
2882
Miklos Szerediad005972006-01-07 10:14:34 +00002883enum {
2884 KEY_HELP,
Miklos Szerediad005972006-01-07 10:14:34 +00002885};
2886
Miklos Szeredi659743b2005-12-09 17:41:42 +00002887#define FUSE_LIB_OPT(t, p, v) { t, offsetof(struct fuse_config, p), v }
2888
2889static const struct fuse_opt fuse_lib_opts[] = {
Miklos Szerediad005972006-01-07 10:14:34 +00002890 FUSE_OPT_KEY("-h", KEY_HELP),
2891 FUSE_OPT_KEY("--help", KEY_HELP),
Miklos Szeredi065f2222006-01-20 15:15:21 +00002892 FUSE_OPT_KEY("debug", FUSE_OPT_KEY_KEEP),
2893 FUSE_OPT_KEY("-d", FUSE_OPT_KEY_KEEP),
Miklos Szeredi659743b2005-12-09 17:41:42 +00002894 FUSE_LIB_OPT("debug", debug, 1),
Miklos Szeredi95da8602006-01-06 18:29:40 +00002895 FUSE_LIB_OPT("-d", debug, 1),
Miklos Szeredi659743b2005-12-09 17:41:42 +00002896 FUSE_LIB_OPT("hard_remove", hard_remove, 1),
2897 FUSE_LIB_OPT("use_ino", use_ino, 1),
2898 FUSE_LIB_OPT("readdir_ino", readdir_ino, 1),
2899 FUSE_LIB_OPT("direct_io", direct_io, 1),
2900 FUSE_LIB_OPT("kernel_cache", kernel_cache, 1),
Miklos Szeredi320abe42006-01-30 18:14:51 +00002901 FUSE_LIB_OPT("auto_cache", auto_cache, 1),
2902 FUSE_LIB_OPT("noauto_cache", auto_cache, 0),
Miklos Szeredi659743b2005-12-09 17:41:42 +00002903 FUSE_LIB_OPT("umask=", set_mode, 1),
2904 FUSE_LIB_OPT("umask=%o", umask, 0),
2905 FUSE_LIB_OPT("uid=", set_uid, 1),
2906 FUSE_LIB_OPT("uid=%d", uid, 0),
2907 FUSE_LIB_OPT("gid=", set_gid, 1),
2908 FUSE_LIB_OPT("gid=%d", gid, 0),
2909 FUSE_LIB_OPT("entry_timeout=%lf", entry_timeout, 0),
2910 FUSE_LIB_OPT("attr_timeout=%lf", attr_timeout, 0),
Miklos Szeredi6e806e92006-02-16 16:59:39 +00002911 FUSE_LIB_OPT("ac_attr_timeout=%lf", ac_attr_timeout, 0),
2912 FUSE_LIB_OPT("ac_attr_timeout=", ac_attr_timeout_set, 1),
Miklos Szeredi659743b2005-12-09 17:41:42 +00002913 FUSE_LIB_OPT("negative_timeout=%lf", negative_timeout, 0),
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002914 FUSE_LIB_OPT("intr", intr, 1),
2915 FUSE_LIB_OPT("intr_signal=%d", intr_signal, 0),
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002916 FUSE_LIB_OPT("modules=%s", modules, 0),
Miklos Szeredi659743b2005-12-09 17:41:42 +00002917 FUSE_OPT_END
2918};
2919
Miklos Szerediad005972006-01-07 10:14:34 +00002920static void fuse_lib_help(void)
2921{
2922 fprintf(stderr,
Miklos Szeredi06091462006-02-16 16:38:34 +00002923" -o hard_remove immediate removal (don't hide files)\n"
2924" -o use_ino let filesystem set inode numbers\n"
2925" -o readdir_ino try to fill in d_ino in readdir\n"
2926" -o direct_io use direct I/O\n"
2927" -o kernel_cache cache files in kernel\n"
2928" -o [no]auto_cache enable caching based on modification times\n"
2929" -o umask=M set file permissions (octal)\n"
2930" -o uid=N set file owner\n"
2931" -o gid=N set file group\n"
2932" -o entry_timeout=T cache timeout for names (1.0s)\n"
2933" -o negative_timeout=T cache timeout for deleted names (0.0s)\n"
Miklos Szeredi6e806e92006-02-16 16:59:39 +00002934" -o attr_timeout=T cache timeout for attributes (1.0s)\n"
2935" -o ac_attr_timeout=T auto cache timeout for attributes (attr_timeout)\n"
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002936" -o intr allow requests to be interrupted\n"
2937" -o intr_signal=NUM signal to send on interrupt (%i)\n"
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002938" -o modules=M1[:M2...] names of modules to push onto filesystem stack\n"
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002939"\n", FUSE_DEFAULT_INTR_SIGNAL);
Miklos Szerediad005972006-01-07 10:14:34 +00002940}
2941
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002942static void fuse_lib_help_modules(void)
2943{
2944 struct fuse_module *m;
2945 fprintf(stderr, "\nModule options:\n");
2946 pthread_mutex_lock(&fuse_context_lock);
2947 for (m = fuse_modules; m; m = m->next) {
2948 struct fuse_fs *fs = NULL;
2949 struct fuse_fs *newfs;
2950 struct fuse_args args = FUSE_ARGS_INIT(0, NULL);
2951 if (fuse_opt_add_arg(&args, "") != -1 &&
2952 fuse_opt_add_arg(&args, "-h") != -1) {
2953 fprintf(stderr, "\n[%s]\n", m->name);
2954 newfs = m->factory(&args, &fs);
2955 assert(newfs == NULL);
2956 }
2957 fuse_opt_free_args(&args);
2958 }
2959 pthread_mutex_unlock(&fuse_context_lock);
2960}
2961
Miklos Szerediad005972006-01-07 10:14:34 +00002962static int fuse_lib_opt_proc(void *data, const char *arg, int key,
2963 struct fuse_args *outargs)
2964{
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002965 (void) arg; (void) outargs;
Miklos Szerediad005972006-01-07 10:14:34 +00002966
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002967 if (key == KEY_HELP) {
2968 struct fuse_config *conf = (struct fuse_config *) data;
Miklos Szerediad005972006-01-07 10:14:34 +00002969 fuse_lib_help();
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002970 conf->help = 1;
2971 }
Miklos Szerediad005972006-01-07 10:14:34 +00002972
2973 return 1;
2974}
2975
Miklos Szeredibd7661b2004-07-23 17:16:29 +00002976int fuse_is_lib_option(const char *opt)
2977{
Miklos Szeredi659743b2005-12-09 17:41:42 +00002978 return fuse_lowlevel_is_lib_option(opt) ||
2979 fuse_opt_match(fuse_lib_opts, opt);
Miklos Szeredibd7661b2004-07-23 17:16:29 +00002980}
2981
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002982static int fuse_init_intr_signal(int signum, int *installed)
2983{
2984 struct sigaction old_sa;
2985
2986 if (sigaction(signum, NULL, &old_sa) == -1) {
2987 perror("fuse: cannot get old signal handler");
2988 return -1;
2989 }
2990
2991 if (old_sa.sa_handler == SIG_DFL) {
2992 struct sigaction sa;
2993
2994 memset(&sa, 0, sizeof(struct sigaction));
2995 sa.sa_handler = fuse_intr_sighandler;
Miklos Szeredi0c59ebf2006-09-10 20:53:36 +00002996 sigemptyset(&sa.sa_mask);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002997
2998 if (sigaction(signum, &sa, NULL) == -1) {
2999 perror("fuse: cannot set interrupt signal handler");
3000 return -1;
3001 }
3002 *installed = 1;
3003 }
3004 return 0;
3005}
3006
Miklos Szeredi349bdda2006-09-07 11:48:16 +00003007static void fuse_restore_intr_signal(int signum)
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00003008{
Miklos Szeredi349bdda2006-09-07 11:48:16 +00003009 struct sigaction sa;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00003010
Miklos Szeredi349bdda2006-09-07 11:48:16 +00003011 memset(&sa, 0, sizeof(struct sigaction));
3012 sa.sa_handler = SIG_DFL;
3013 sigaction(signum, &sa, NULL);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00003014}
3015
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00003016
3017static int fuse_push_module(struct fuse *f, const char *module,
3018 struct fuse_args *args)
3019{
3020 struct fuse_fs *fs[2] = { f->fs, NULL };
3021 struct fuse_fs *newfs;
3022 struct fuse_module *m = fuse_get_module(module);
3023
3024 if (!m)
3025 return -1;
3026
3027 newfs = m->factory(args, fs);
3028 if (!newfs) {
3029 fuse_put_module(m);
3030 return -1;
3031 }
3032 newfs->m = m;
3033 f->fs = newfs;
3034 return 0;
3035}
3036
3037struct fuse_fs *fuse_fs_new(const struct fuse_operations *op, size_t op_size,
3038 void *user_data)
3039{
3040 struct fuse_fs *fs;
3041
3042 if (sizeof(struct fuse_operations) < op_size) {
3043 fprintf(stderr, "fuse: warning: library too old, some operations may not not work\n");
3044 op_size = sizeof(struct fuse_operations);
3045 }
3046
3047 fs = (struct fuse_fs *) calloc(1, sizeof(struct fuse_fs));
3048 if (!fs) {
3049 fprintf(stderr, "fuse: failed to allocate fuse_fs object\n");
3050 return NULL;
3051 }
3052
3053 fs->user_data = user_data;
3054 memcpy(&fs->op, op, op_size);
3055 return fs;
3056}
3057
Miklos Szeredi6f385412006-03-17 15:05:40 +00003058struct fuse *fuse_new_common(struct fuse_chan *ch, struct fuse_args *args,
Miklos Szeredi0b6a0ad2004-12-04 00:40:50 +00003059 const struct fuse_operations *op,
Miklos Szeredi6f385412006-03-17 15:05:40 +00003060 size_t op_size, void *user_data, int compat)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00003061{
Miklos Szeredi97c61e92001-11-07 12:09:43 +00003062 struct fuse *f;
3063 struct node *root;
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00003064 struct fuse_fs *fs;
Miklos Szeredi9a5c11d2006-07-30 17:33:40 +00003065 struct fuse_lowlevel_ops llop = fuse_path_ops;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00003066
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00003067 if (fuse_create_context_key() == -1)
3068 goto out;
3069
Miklos Szeredi97c61e92001-11-07 12:09:43 +00003070 f = (struct fuse *) calloc(1, sizeof(struct fuse));
Miklos Szeredie56818b2004-12-12 11:45:24 +00003071 if (f == NULL) {
3072 fprintf(stderr, "fuse: failed to allocate fuse object\n");
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00003073 goto out_delete_context_key;
Miklos Szeredie56818b2004-12-12 11:45:24 +00003074 }
Miklos Szeredi2df1c042001-11-06 15:07:17 +00003075
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00003076 fs = fuse_fs_new(op, op_size, user_data);
3077 if (!fs)
3078 goto out_free;
3079
3080 fs->compat = compat;
3081 f->fs = fs;
3082
3083 /* Oh f**k, this is ugly! */
3084 if (!fs->op.lock) {
3085 llop.getlk = NULL;
3086 llop.setlk = NULL;
3087 }
3088
Miklos Szeredi659743b2005-12-09 17:41:42 +00003089 f->conf.entry_timeout = 1.0;
3090 f->conf.attr_timeout = 1.0;
3091 f->conf.negative_timeout = 0.0;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00003092 f->conf.intr_signal = FUSE_DEFAULT_INTR_SIGNAL;
Miklos Szeredi6c0209a2005-08-02 13:31:28 +00003093
Miklos Szerediad005972006-01-07 10:14:34 +00003094 if (fuse_opt_parse(args, &f->conf, fuse_lib_opts, fuse_lib_opt_proc) == -1)
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00003095 goto out_free_fs;
3096
3097 if (f->conf.modules) {
3098 char *module;
3099 char *next;
3100
3101 for (module = f->conf.modules; module; module = next) {
3102 char *p;
3103 for (p = module; *p && *p != ':'; p++);
3104 next = *p ? p + 1 : NULL;
3105 *p = '\0';
3106 if (module[0] && fuse_push_module(f, module, args) == -1)
3107 goto out_free_fs;
3108 }
3109 }
Miklos Szeredib2cf9562004-09-16 08:42:40 +00003110
Miklos Szeredi6e806e92006-02-16 16:59:39 +00003111 if (!f->conf.ac_attr_timeout_set)
3112 f->conf.ac_attr_timeout = f->conf.attr_timeout;
3113
Miklos Szeredi659743b2005-12-09 17:41:42 +00003114#ifdef __FreeBSD__
3115 /*
3116 * In FreeBSD, we always use these settings as inode numbers are needed to
3117 * make getcwd(3) work.
3118 */
Miklos Szeredi76fc3de2005-12-12 09:34:45 +00003119 f->conf.readdir_ino = 1;
Miklos Szeredi659743b2005-12-09 17:41:42 +00003120#endif
3121
Miklos Szeredi065f2222006-01-20 15:15:21 +00003122 if (compat && compat <= 25) {
3123 if (fuse_sync_compat_args(args) == -1)
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00003124 goto out_free_fs;
Miklos Szeredi9a5c11d2006-07-30 17:33:40 +00003125 }
3126
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00003127 f->se = fuse_lowlevel_new_common(args, &llop, sizeof(llop), f);
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00003128 if (f->se == NULL) {
3129 if (f->conf.help)
3130 fuse_lib_help_modules();
3131 goto out_free_fs;
3132 }
Miklos Szeredi2bb750e2005-10-03 14:54:24 +00003133
Miklos Szeredia1482422005-08-14 23:00:27 +00003134 fuse_session_add_chan(f->se, ch);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00003135
Miklos Szeredi97c61e92001-11-07 12:09:43 +00003136 f->ctr = 0;
Miklos Szeredi76f65782004-02-19 16:55:40 +00003137 f->generation = 0;
Miklos Szeredifff56ab2001-11-16 10:12:59 +00003138 /* FIXME: Dynamic hash table */
Miklos Szeredi97c61e92001-11-07 12:09:43 +00003139 f->name_table_size = 14057;
3140 f->name_table = (struct node **)
3141 calloc(1, sizeof(struct node *) * f->name_table_size);
Miklos Szeredie56818b2004-12-12 11:45:24 +00003142 if (f->name_table == NULL) {
3143 fprintf(stderr, "fuse: memory allocation failed\n");
Miklos Szeredia1482422005-08-14 23:00:27 +00003144 goto out_free_session;
Miklos Szeredie56818b2004-12-12 11:45:24 +00003145 }
Miklos Szeredib2cf9562004-09-16 08:42:40 +00003146
Miklos Szeredia13d9002004-11-02 17:32:03 +00003147 f->id_table_size = 14057;
3148 f->id_table = (struct node **)
3149 calloc(1, sizeof(struct node *) * f->id_table_size);
Miklos Szeredie56818b2004-12-12 11:45:24 +00003150 if (f->id_table == NULL) {
3151 fprintf(stderr, "fuse: memory allocation failed\n");
Miklos Szeredib2cf9562004-09-16 08:42:40 +00003152 goto out_free_name_table;
Miklos Szeredie56818b2004-12-12 11:45:24 +00003153 }
Miklos Szeredib2cf9562004-09-16 08:42:40 +00003154
Miklos Szeredi38f152c2006-09-03 18:28:52 +00003155 fuse_mutex_init(&f->lock);
Miklos Szeredid0a777a2006-04-05 07:18:00 +00003156 pthread_rwlock_init(&f->tree_lock, NULL);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00003157
Miklos Szeredi97c61e92001-11-07 12:09:43 +00003158 root = (struct node *) calloc(1, sizeof(struct node));
Miklos Szeredie56818b2004-12-12 11:45:24 +00003159 if (root == NULL) {
3160 fprintf(stderr, "fuse: memory allocation failed\n");
Miklos Szeredia13d9002004-11-02 17:32:03 +00003161 goto out_free_id_table;
Miklos Szeredie56818b2004-12-12 11:45:24 +00003162 }
Miklos Szeredib2cf9562004-09-16 08:42:40 +00003163
Miklos Szeredi97c61e92001-11-07 12:09:43 +00003164 root->name = strdup("/");
Miklos Szeredie56818b2004-12-12 11:45:24 +00003165 if (root->name == NULL) {
3166 fprintf(stderr, "fuse: memory allocation failed\n");
Miklos Szeredib2cf9562004-09-16 08:42:40 +00003167 goto out_free_root;
Miklos Szeredie56818b2004-12-12 11:45:24 +00003168 }
Miklos Szeredib2cf9562004-09-16 08:42:40 +00003169
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00003170 if (f->conf.intr &&
3171 fuse_init_intr_signal(f->conf.intr_signal, &f->intr_installed) == -1)
3172 goto out_free_root_name;
3173
Miklos Szeredi7bc05b02007-05-29 23:08:11 +00003174 root->parent = NULL;
Miklos Szeredia13d9002004-11-02 17:32:03 +00003175 root->nodeid = FUSE_ROOT_ID;
Miklos Szeredi76f65782004-02-19 16:55:40 +00003176 root->generation = 0;
Miklos Szeredi0f62d722005-01-04 12:45:54 +00003177 root->refctr = 1;
Miklos Szeredi38009022005-05-08 19:47:22 +00003178 root->nlookup = 1;
Miklos Szeredia13d9002004-11-02 17:32:03 +00003179 hash_id(f, root);
Miklos Szeredi97c61e92001-11-07 12:09:43 +00003180
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00003181 return f;
Miklos Szeredib2cf9562004-09-16 08:42:40 +00003182
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00003183 out_free_root_name:
3184 free(root->name);
Miklos Szeredib2cf9562004-09-16 08:42:40 +00003185 out_free_root:
3186 free(root);
Miklos Szeredia13d9002004-11-02 17:32:03 +00003187 out_free_id_table:
3188 free(f->id_table);
Miklos Szeredib2cf9562004-09-16 08:42:40 +00003189 out_free_name_table:
3190 free(f->name_table);
Miklos Szeredia1482422005-08-14 23:00:27 +00003191 out_free_session:
3192 fuse_session_destroy(f->se);
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00003193 out_free_fs:
3194 /* Horrible compatibility hack to stop the destructor from being
3195 called on the filesystem without init being called first */
3196 fs->op.destroy = NULL;
3197 fuse_fs_destroy(f->fs);
Miklos Szeredib2cf9562004-09-16 08:42:40 +00003198 out_free:
3199 free(f);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00003200 out_delete_context_key:
3201 fuse_delete_context_key();
Miklos Szeredib2cf9562004-09-16 08:42:40 +00003202 out:
Miklos Szeredib2cf9562004-09-16 08:42:40 +00003203 return NULL;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00003204}
3205
Miklos Szeredi6f385412006-03-17 15:05:40 +00003206struct fuse *fuse_new(struct fuse_chan *ch, struct fuse_args *args,
3207 const struct fuse_operations *op, size_t op_size,
3208 void *user_data)
Miklos Szeredi0b6a0ad2004-12-04 00:40:50 +00003209{
Miklos Szeredi6f385412006-03-17 15:05:40 +00003210 return fuse_new_common(ch, args, op, op_size, user_data, 0);
Miklos Szeredi0b6a0ad2004-12-04 00:40:50 +00003211}
3212
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00003213void fuse_destroy(struct fuse *f)
3214{
Miklos Szeredi97c61e92001-11-07 12:09:43 +00003215 size_t i;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00003216
3217 if (f->conf.intr && f->intr_installed)
3218 fuse_restore_intr_signal(f->conf.intr_signal);
Miklos Szerediad519562006-07-31 11:07:40 +00003219
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00003220 if (f->fs) {
3221 struct fuse_context_i *c = fuse_get_context_internal();
Miklos Szerediad519562006-07-31 11:07:40 +00003222
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00003223 memset(c, 0, sizeof(*c));
3224 c->ctx.fuse = f;
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00003225
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00003226 for (i = 0; i < f->id_table_size; i++) {
3227 struct node *node;
3228
3229 for (node = f->id_table[i]; node != NULL; node = node->id_next) {
3230 if (node->is_hidden) {
3231 char *path = get_path(f, node->nodeid);
3232 if (path) {
3233 fuse_fs_unlink(f->fs, path);
3234 free(path);
3235 }
Miklos Szeredi21019c92005-05-09 11:22:41 +00003236 }
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00003237 }
3238 }
3239 }
Miklos Szeredia13d9002004-11-02 17:32:03 +00003240 for (i = 0; i < f->id_table_size; i++) {
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00003241 struct node *node;
Miklos Szeredi97c61e92001-11-07 12:09:43 +00003242 struct node *next;
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00003243
Miklos Szeredia13d9002004-11-02 17:32:03 +00003244 for (node = f->id_table[i]; node != NULL; node = next) {
3245 next = node->id_next;
Miklos Szeredi97c61e92001-11-07 12:09:43 +00003246 free_node(node);
3247 }
3248 }
Miklos Szeredia13d9002004-11-02 17:32:03 +00003249 free(f->id_table);
Miklos Szeredi97c61e92001-11-07 12:09:43 +00003250 free(f->name_table);
Miklos Szeredia181e612001-11-06 12:03:23 +00003251 pthread_mutex_destroy(&f->lock);
Miklos Szeredi55a84102006-06-06 10:16:38 +00003252 pthread_rwlock_destroy(&f->tree_lock);
Miklos Szeredia1482422005-08-14 23:00:27 +00003253 fuse_session_destroy(f->se);
Miklos Szeredi97c61e92001-11-07 12:09:43 +00003254 free(f);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00003255 fuse_delete_context_key();
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00003256}
Miklos Szeredi0b6a0ad2004-12-04 00:40:50 +00003257
Miklos Szeredi6f385412006-03-17 15:05:40 +00003258static struct fuse *fuse_new_common_compat25(int fd, struct fuse_args *args,
3259 const struct fuse_operations *op,
3260 size_t op_size, int compat)
3261{
3262 struct fuse *f = NULL;
3263 struct fuse_chan *ch = fuse_kern_chan_new(fd);
3264
3265 if (ch)
3266 f = fuse_new_common(ch, args, op, op_size, NULL, compat);
3267
3268 return f;
3269}
3270
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00003271/* called with fuse_context_lock held or during initialization (before
3272 main() has been called) */
3273void fuse_register_module(struct fuse_module *mod)
3274{
Miklos Szeredi2f759e12007-03-14 09:13:27 +00003275 mod->ctr = 0;
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00003276 mod->so = fuse_current_so;
3277 if (mod->so)
3278 mod->so->ctr++;
3279 mod->next = fuse_modules;
3280 fuse_modules = mod;
3281}
3282
Miklos Szeredi065f2222006-01-20 15:15:21 +00003283#ifndef __FreeBSD__
3284
Miklos Szeredi95da8602006-01-06 18:29:40 +00003285static struct fuse *fuse_new_common_compat(int fd, const char *opts,
3286 const struct fuse_operations *op,
3287 size_t op_size, int compat)
3288{
3289 struct fuse *f;
3290 struct fuse_args args = FUSE_ARGS_INIT(0, NULL);
3291
Miklos Szeredi6e7d0182007-01-19 22:11:40 +00003292 if (fuse_opt_add_arg(&args, "") == -1)
3293 return NULL;
Miklos Szeredi95da8602006-01-06 18:29:40 +00003294 if (opts &&
Miklos Szeredi6e7d0182007-01-19 22:11:40 +00003295 (fuse_opt_add_arg(&args, "-o") == -1 ||
Miklos Szeredi95da8602006-01-06 18:29:40 +00003296 fuse_opt_add_arg(&args, opts) == -1)) {
3297 fuse_opt_free_args(&args);
3298 return NULL;
3299 }
Miklos Szeredi6f385412006-03-17 15:05:40 +00003300 f = fuse_new_common_compat25(fd, &args, op, op_size, compat);
Miklos Szeredi95da8602006-01-06 18:29:40 +00003301 fuse_opt_free_args(&args);
3302
3303 return f;
3304}
3305
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00003306struct fuse *fuse_new_compat22(int fd, const char *opts,
3307 const struct fuse_operations_compat22 *op,
3308 size_t op_size)
3309{
Miklos Szeredi95da8602006-01-06 18:29:40 +00003310 return fuse_new_common_compat(fd, opts, (struct fuse_operations *) op,
3311 op_size, 22);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00003312}
3313
3314struct fuse *fuse_new_compat2(int fd, const char *opts,
3315 const struct fuse_operations_compat2 *op)
3316{
Miklos Szeredi95da8602006-01-06 18:29:40 +00003317 return fuse_new_common_compat(fd, opts, (struct fuse_operations *) op,
3318 sizeof(struct fuse_operations_compat2), 21);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00003319}
3320
3321struct fuse *fuse_new_compat1(int fd, int flags,
3322 const struct fuse_operations_compat1 *op)
3323{
3324 const char *opts = NULL;
3325 if (flags & FUSE_DEBUG_COMPAT1)
3326 opts = "debug";
Miklos Szeredi95da8602006-01-06 18:29:40 +00003327 return fuse_new_common_compat(fd, opts, (struct fuse_operations *) op,
3328 sizeof(struct fuse_operations_compat1), 11);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00003329}
3330
Miklos Szeredif458b8c2004-12-07 16:46:42 +00003331__asm__(".symver fuse_exited,__fuse_exited@");
3332__asm__(".symver fuse_process_cmd,__fuse_process_cmd@");
3333__asm__(".symver fuse_read_cmd,__fuse_read_cmd@");
3334__asm__(".symver fuse_set_getcontext_func,__fuse_set_getcontext_func@");
3335__asm__(".symver fuse_new_compat2,fuse_new@");
Miklos Szeredi3a770472005-11-11 21:32:42 +00003336__asm__(".symver fuse_new_compat22,fuse_new@FUSE_2.2");
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00003337
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00003338#endif /* __FreeBSD__ */
Miklos Szeredi065f2222006-01-20 15:15:21 +00003339
3340struct fuse *fuse_new_compat25(int fd, struct fuse_args *args,
3341 const struct fuse_operations_compat25 *op,
3342 size_t op_size)
3343{
Miklos Szeredi6f385412006-03-17 15:05:40 +00003344 return fuse_new_common_compat25(fd, args, (struct fuse_operations *) op,
3345 op_size, 25);
Miklos Szeredi065f2222006-01-20 15:15:21 +00003346}
3347
3348__asm__(".symver fuse_new_compat25,fuse_new@FUSE_2.5");