blob: bc944c71670a85989568a2a505a036b3e57e015f [file] [log] [blame]
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001/*
2 FUSE: Filesystem in Userspace
Miklos Szeredi95da8602006-01-06 18:29:40 +00003 Copyright (C) 2001-2006 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 Szeredibd10a7b2005-07-15 09:59:59 +0000110 fuse_ino_t 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) {
318 size_t hash = name_hash(f, node->parent, node->name);
319 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;
325 unref_node(f, get_node(f, node->parent));
326 free(node->name);
327 node->name = NULL;
328 node->parent = 0;
329 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 Szeredibd10a7b2005-07-15 09:59:59 +0000337static int hash_name(struct fuse *f, struct node *node, fuse_ino_t parent,
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000338 const char *name)
339{
340 size_t hash = name_hash(f, parent, name);
341 node->name = strdup(name);
342 if (node->name == NULL)
343 return -1;
344
345 get_node(f, parent)->refctr ++;
346 node->parent = parent;
347 node->name_next = f->name_table[hash];
348 f->name_table[hash] = node;
349 return 0;
350}
351
352static void delete_node(struct fuse *f, struct node *node)
353{
Miklos Szeredi659743b2005-12-09 17:41:42 +0000354 if (f->conf.debug) {
Miklos Szeredi3a770472005-11-11 21:32:42 +0000355 printf("delete: %llu\n", (unsigned long long) node->nodeid);
Miklos Szeredi38009022005-05-08 19:47:22 +0000356 fflush(stdout);
357 }
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000358 assert(!node->name);
359 unhash_id(f, node);
360 free_node(node);
361}
362
363static void unref_node(struct fuse *f, struct node *node)
364{
365 assert(node->refctr > 0);
366 node->refctr --;
367 if (!node->refctr)
368 delete_node(f, node);
369}
370
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000371static fuse_ino_t next_id(struct fuse *f)
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000372{
373 do {
Miklos Szeredi7e7fa1f2006-10-08 15:41:20 +0000374 f->ctr = (f->ctr + 1) & 0xffffffff;
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000375 if (!f->ctr)
376 f->generation ++;
Miklos Szeredi7e7fa1f2006-10-08 15:41:20 +0000377 } while (f->ctr == 0 || f->ctr == FUSE_UNKNOWN_INO ||
378 get_node_nocheck(f, f->ctr) != NULL);
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000379 return f->ctr;
380}
381
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000382static struct node *lookup_node(struct fuse *f, fuse_ino_t parent,
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000383 const char *name)
384{
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000385 size_t hash = name_hash(f, parent, name);
386 struct node *node;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000387
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000388 for (node = f->name_table[hash]; node != NULL; node = node->name_next)
389 if (node->parent == parent && strcmp(node->name, name) == 0)
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000390 return node;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000391
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000392 return NULL;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000393}
394
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000395static struct node *find_node(struct fuse *f, fuse_ino_t parent,
396 const char *name)
Miklos Szeredi5e183482001-10-31 14:52:35 +0000397{
398 struct node *node;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000399
Miklos Szeredia181e612001-11-06 12:03:23 +0000400 pthread_mutex_lock(&f->lock);
Miklos Szeredif458b8c2004-12-07 16:46:42 +0000401 node = lookup_node(f, parent, name);
Miklos Szeredie331c4b2005-07-06 13:34:02 +0000402 if (node == NULL) {
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000403 node = (struct node *) calloc(1, sizeof(struct node));
404 if (node == NULL)
405 goto out_err;
Miklos Szeredie5183742005-02-02 11:14:04 +0000406
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000407 node->refctr = 1;
408 node->nodeid = next_id(f);
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000409 node->open_count = 0;
410 node->is_hidden = 0;
411 node->generation = f->generation;
412 if (hash_name(f, node, parent, name) == -1) {
413 free(node);
414 node = NULL;
415 goto out_err;
416 }
417 hash_id(f, node);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000418 }
Miklos Szeredi38009022005-05-08 19:47:22 +0000419 node->nlookup ++;
Miklos Szeredic2309912004-09-21 13:40:38 +0000420 out_err:
Miklos Szeredia181e612001-11-06 12:03:23 +0000421 pthread_mutex_unlock(&f->lock);
Miklos Szeredi76f65782004-02-19 16:55:40 +0000422 return node;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000423}
424
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000425static char *add_name(char *buf, char *s, const char *name)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000426{
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000427 size_t len = strlen(name);
428 s -= len;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000429 if (s <= buf) {
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000430 fprintf(stderr, "fuse: path too long: ...%s\n", s + len);
431 return NULL;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000432 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000433 strncpy(s, name, len);
434 s--;
435 *s = '/';
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000436
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000437 return s;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000438}
439
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000440static char *get_path_name(struct fuse *f, fuse_ino_t nodeid, const char *name)
Miklos Szeredib483c932001-10-29 14:57:57 +0000441{
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000442 char buf[FUSE_MAX_PATH];
443 char *s = buf + FUSE_MAX_PATH - 1;
444 struct node *node;
Miklos Szeredie5183742005-02-02 11:14:04 +0000445
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000446 *s = '\0';
Miklos Szeredia181e612001-11-06 12:03:23 +0000447
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000448 if (name != NULL) {
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000449 s = add_name(buf, s, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000450 if (s == NULL)
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000451 return NULL;
452 }
453
454 pthread_mutex_lock(&f->lock);
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000455 for (node = get_node(f, nodeid); node && node->nodeid != FUSE_ROOT_ID;
456 node = get_node(f, node->parent)) {
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000457 if (node->name == NULL) {
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000458 s = NULL;
459 break;
460 }
Miklos Szeredie5183742005-02-02 11:14:04 +0000461
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000462 s = add_name(buf, s, node->name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000463 if (s == NULL)
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000464 break;
465 }
466 pthread_mutex_unlock(&f->lock);
467
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000468 if (node == NULL || s == NULL)
Miklos Szeredi5e183482001-10-31 14:52:35 +0000469 return NULL;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000470 else if (*s == '\0')
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000471 return strdup("/");
472 else
473 return strdup(s);
474}
Miklos Szeredia181e612001-11-06 12:03:23 +0000475
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000476static char *get_path(struct fuse *f, fuse_ino_t nodeid)
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000477{
Miklos Szeredia13d9002004-11-02 17:32:03 +0000478 return get_path_name(f, nodeid, NULL);
Miklos Szeredib483c932001-10-29 14:57:57 +0000479}
480
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000481static void forget_node(struct fuse *f, fuse_ino_t nodeid, uint64_t nlookup)
Miklos Szeredi38009022005-05-08 19:47:22 +0000482{
483 struct node *node;
484 if (nodeid == FUSE_ROOT_ID)
485 return;
486 pthread_mutex_lock(&f->lock);
487 node = get_node(f, nodeid);
488 assert(node->nlookup >= nlookup);
489 node->nlookup -= nlookup;
490 if (!node->nlookup) {
491 unhash_name(f, node);
492 unref_node(f, node);
493 }
494 pthread_mutex_unlock(&f->lock);
495}
496
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000497static void remove_node(struct fuse *f, fuse_ino_t dir, const char *name)
Miklos Szeredi5e183482001-10-31 14:52:35 +0000498{
Miklos Szeredia181e612001-11-06 12:03:23 +0000499 struct node *node;
500
501 pthread_mutex_lock(&f->lock);
Miklos Szeredif458b8c2004-12-07 16:46:42 +0000502 node = lookup_node(f, dir, name);
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000503 if (node != NULL)
504 unhash_name(f, node);
Miklos Szeredia181e612001-11-06 12:03:23 +0000505 pthread_mutex_unlock(&f->lock);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000506}
507
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000508static int rename_node(struct fuse *f, fuse_ino_t olddir, const char *oldname,
509 fuse_ino_t newdir, const char *newname, int hide)
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000510{
Miklos Szeredia181e612001-11-06 12:03:23 +0000511 struct node *node;
512 struct node *newnode;
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000513 int err = 0;
Miklos Szeredie5183742005-02-02 11:14:04 +0000514
Miklos Szeredia181e612001-11-06 12:03:23 +0000515 pthread_mutex_lock(&f->lock);
Miklos Szeredif458b8c2004-12-07 16:46:42 +0000516 node = lookup_node(f, olddir, oldname);
517 newnode = lookup_node(f, newdir, newname);
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000518 if (node == NULL)
519 goto out;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000520
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000521 if (newnode != NULL) {
522 if (hide) {
523 fprintf(stderr, "fuse: hidden file got created during hiding\n");
Miklos Szeredib2cf9562004-09-16 08:42:40 +0000524 err = -EBUSY;
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000525 goto out;
526 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000527 unhash_name(f, newnode);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000528 }
Miklos Szeredie5183742005-02-02 11:14:04 +0000529
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000530 unhash_name(f, node);
Miklos Szeredib2cf9562004-09-16 08:42:40 +0000531 if (hash_name(f, node, newdir, newname) == -1) {
532 err = -ENOMEM;
533 goto out;
534 }
Miklos Szeredie5183742005-02-02 11:14:04 +0000535
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000536 if (hide)
537 node->is_hidden = 1;
538
539 out:
Miklos Szeredia181e612001-11-06 12:03:23 +0000540 pthread_mutex_unlock(&f->lock);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000541 return err;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000542}
543
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000544static void set_stat(struct fuse *f, fuse_ino_t nodeid, struct stat *stbuf)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000545{
Miklos Szeredi659743b2005-12-09 17:41:42 +0000546 if (!f->conf.use_ino)
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000547 stbuf->st_ino = nodeid;
Miklos Szeredi659743b2005-12-09 17:41:42 +0000548 if (f->conf.set_mode)
549 stbuf->st_mode = (stbuf->st_mode & S_IFMT) | (0777 & ~f->conf.umask);
550 if (f->conf.set_uid)
551 stbuf->st_uid = f->conf.uid;
552 if (f->conf.set_gid)
553 stbuf->st_gid = f->conf.gid;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000554}
555
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000556static struct fuse *req_fuse(fuse_req_t req)
557{
558 return (struct fuse *) fuse_req_userdata(req);
559}
560
561static void fuse_intr_sighandler(int sig)
562{
563 (void) sig;
564 /* Nothing to do */
565}
566
567struct fuse_intr_data {
568 pthread_t id;
569 pthread_cond_t cond;
570 int finished;
571};
572
573static void fuse_interrupt(fuse_req_t req, void *d_)
574{
575 struct fuse_intr_data *d = d_;
576 struct fuse *f = req_fuse(req);
577
578 if (d->id == pthread_self())
579 return;
580
581 pthread_mutex_lock(&f->lock);
582 while (!d->finished) {
583 struct timeval now;
584 struct timespec timeout;
585
586 pthread_kill(d->id, f->conf.intr_signal);
587 gettimeofday(&now, NULL);
588 timeout.tv_sec = now.tv_sec + 1;
589 timeout.tv_nsec = now.tv_usec * 1000;
590 pthread_cond_timedwait(&d->cond, &f->lock, &timeout);
591 }
592 pthread_mutex_unlock(&f->lock);
593}
594
595static void fuse_do_finish_interrupt(struct fuse *f, fuse_req_t req,
596 struct fuse_intr_data *d)
597{
598 pthread_mutex_lock(&f->lock);
599 d->finished = 1;
600 pthread_cond_broadcast(&d->cond);
601 pthread_mutex_unlock(&f->lock);
602 fuse_req_interrupt_func(req, NULL, NULL);
603 pthread_cond_destroy(&d->cond);
604}
605
606static void fuse_do_prepare_interrupt(fuse_req_t req, struct fuse_intr_data *d)
607{
608 d->id = pthread_self();
609 pthread_cond_init(&d->cond, NULL);
610 d->finished = 0;
611 fuse_req_interrupt_func(req, fuse_interrupt, d);
612}
613
614static inline void fuse_finish_interrupt(struct fuse *f, fuse_req_t req,
615 struct fuse_intr_data *d)
616{
617 if (f->conf.intr)
618 fuse_do_finish_interrupt(f, req, d);
619}
620
621static inline void fuse_prepare_interrupt(struct fuse *f, fuse_req_t req,
622 struct fuse_intr_data *d)
623{
624 if (f->conf.intr)
625 fuse_do_prepare_interrupt(req, d);
626}
627
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +0000628#ifndef __FreeBSD__
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000629
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +0000630static int fuse_compat_open(struct fuse_fs *fs, const char *path,
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000631 struct fuse_file_info *fi)
632{
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +0000633 int err;
634 if (!fs->compat || fs->compat >= 25)
635 err = fs->op.open(path, fi);
636 else if (fs->compat == 22) {
637 struct fuse_file_info_compat tmp;
638 memcpy(&tmp, fi, sizeof(tmp));
639 err = ((struct fuse_operations_compat22 *) &fs->op)->open(path, &tmp);
640 memcpy(fi, &tmp, sizeof(tmp));
641 fi->fh = tmp.fh;
642 } else
643 err = ((struct fuse_operations_compat2 *) &fs->op)
644 ->open(path, fi->flags);
645 return err;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000646}
647
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +0000648static int fuse_compat_release(struct fuse_fs *fs, const char *path,
649 struct fuse_file_info *fi)
650{
651 if (!fs->compat || fs->compat >= 22)
652 return fs->op.release(path, fi);
653 else
654 return ((struct fuse_operations_compat2 *) &fs->op)
655 ->release(path, fi->flags);
656}
657
658static int fuse_compat_opendir(struct fuse_fs *fs, const char *path,
659 struct fuse_file_info *fi)
660{
661 if (!fs->compat || fs->compat >= 25)
662 return fs->op.opendir(path, fi);
663 else {
664 int err;
665 struct fuse_file_info_compat tmp;
666 memcpy(&tmp, fi, sizeof(tmp));
667 err = ((struct fuse_operations_compat22 *) &fs->op)
668 ->opendir(path, &tmp);
669 memcpy(fi, &tmp, sizeof(tmp));
670 fi->fh = tmp.fh;
671 return err;
672 }
673}
674
675static void convert_statfs_compat(struct fuse_statfs_compat1 *compatbuf,
676 struct statvfs *stbuf)
677{
678 stbuf->f_bsize = compatbuf->block_size;
679 stbuf->f_blocks = compatbuf->blocks;
680 stbuf->f_bfree = compatbuf->blocks_free;
681 stbuf->f_bavail = compatbuf->blocks_free;
682 stbuf->f_files = compatbuf->files;
683 stbuf->f_ffree = compatbuf->files_free;
684 stbuf->f_namemax = compatbuf->namelen;
685}
686
687static void convert_statfs_old(struct statfs *oldbuf, struct statvfs *stbuf)
688{
689 stbuf->f_bsize = oldbuf->f_bsize;
690 stbuf->f_blocks = oldbuf->f_blocks;
691 stbuf->f_bfree = oldbuf->f_bfree;
692 stbuf->f_bavail = oldbuf->f_bavail;
693 stbuf->f_files = oldbuf->f_files;
694 stbuf->f_ffree = oldbuf->f_ffree;
695 stbuf->f_namemax = oldbuf->f_namelen;
696}
697
698static int fuse_compat_statfs(struct fuse_fs *fs, const char *path,
699 struct statvfs *buf)
700{
701 int err;
702
703 if (!fs->compat || fs->compat >= 25) {
704 err = fs->op.statfs(fs->compat == 25 ? "/" : path, buf);
705 } else if (fs->compat > 11) {
706 struct statfs oldbuf;
707 err = ((struct fuse_operations_compat22 *) &fs->op)
708 ->statfs("/", &oldbuf);
709 if (!err)
710 convert_statfs_old(&oldbuf, buf);
711 } else {
712 struct fuse_statfs_compat1 compatbuf;
713 memset(&compatbuf, 0, sizeof(struct fuse_statfs_compat1));
714 err = ((struct fuse_operations_compat1 *) &fs->op)->statfs(&compatbuf);
715 if (!err)
716 convert_statfs_compat(&compatbuf, buf);
717 }
718 return err;
719}
720
721#else /* __FreeBSD__ */
722
723static inline int fuse_compat_open(struct fuse_fs *fs, char *path,
724 struct fuse_file_info *fi)
725{
726 return fs->op.open(path, fi);
727}
728
729static inline int fuse_compat_release(struct fuse_fs *fs, const char *path,
730 struct fuse_file_info *fi)
731{
732 return fs->op.release(path, fi);
733}
734
735static inline int fuse_compat_opendir(struct fuse_fs *fs, const char *path,
736 struct fuse_file_info *fi)
737{
738 return fs->op.opendir(path, fi);
739}
740
741static inline int fuse_compat_statfs(struct fuse_fs *fs, const char *path,
742 struct statvfs *buf)
743{
744 return fs->op.statfs(fs->compat == 25 ? "/" : path, buf);
745}
746
747#endif /* __FreeBSD__ */
748
749int fuse_fs_getattr(struct fuse_fs *fs, const char *path, struct stat *buf)
750{
751 fuse_get_context()->private_data = fs->user_data;
752 if (fs->op.getattr)
753 return fs->op.getattr(path, buf);
754 else
755 return -ENOSYS;
756}
757
758int fuse_fs_fgetattr(struct fuse_fs *fs, const char *path, struct stat *buf,
759 struct fuse_file_info *fi)
760{
761 fuse_get_context()->private_data = fs->user_data;
762 if (fs->op.fgetattr)
763 return fs->op.fgetattr(path, buf, fi);
764 else if (fs->op.getattr)
765 return fs->op.getattr(path, buf);
766 else
767 return -ENOSYS;
768}
769
770int fuse_fs_rename(struct fuse_fs *fs, const char *oldpath,
771 const char *newpath)
772{
773 fuse_get_context()->private_data = fs->user_data;
774 if (fs->op.rename)
775 return fs->op.rename(oldpath, newpath);
776 else
777 return -ENOSYS;
778}
779
780
781int 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_release(fuse_req_t req, fuse_ino_t ino,
2030 struct fuse_file_info *fi)
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002031{
2032 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002033 struct fuse_intr_data d;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002034 char *path;
Miklos Szeredi4fca4322006-10-01 14:41:04 +00002035 int err = 0;
Miklos Szeredifb28c5e2004-11-26 12:15:06 +00002036
Miklos Szerediaa8258e2006-02-25 14:42:03 +00002037 pthread_rwlock_rdlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002038 path = get_path(f, ino);
Miklos Szeredi659743b2005-12-09 17:41:42 +00002039 if (f->conf.debug) {
Miklos Szeredi4fca4322006-10-01 14:41:04 +00002040 printf("RELEASE%s[%llu] flags: 0x%x\n", fi->flush ? "+FLUSH" : "",
2041 (unsigned long long) fi->fh, fi->flags);
Miklos Szeredi0f62d722005-01-04 12:45:54 +00002042 fflush(stdout);
Miklos Szeredic8ba2372002-12-10 12:26:00 +00002043 }
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002044 fuse_prepare_interrupt(f, req, &d);
2045 if (fi->flush && path) {
2046 err = fuse_fs_flush(f->fs, path, fi);
2047 if (err == -ENOSYS)
2048 err = 0;
Miklos Szeredic3b76812006-09-16 08:52:09 +00002049 }
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002050 fuse_do_release(f, ino, path, fi);
2051 fuse_finish_interrupt(f, req, &d);
Miklos Szeredie5183742005-02-02 11:14:04 +00002052
Miklos Szeredi0f62d722005-01-04 12:45:54 +00002053 if (path)
2054 free(path);
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00002055 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredi0f62d722005-01-04 12:45:54 +00002056
Miklos Szeredi4fca4322006-10-01 14:41:04 +00002057 reply_err(req, err);
Miklos Szeredic8ba2372002-12-10 12:26:00 +00002058}
2059
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002060static void fuse_lib_fsync(fuse_req_t req, fuse_ino_t ino, int datasync,
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002061 struct fuse_file_info *fi)
Miklos Szeredi5e183482001-10-31 14:52:35 +00002062{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002063 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredi5e183482001-10-31 14:52:35 +00002064 char *path;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002065 int err;
Miklos Szerediab974562005-04-07 15:40:21 +00002066
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002067 err = -ENOENT;
2068 pthread_rwlock_rdlock(&f->tree_lock);
2069 path = get_path(f, ino);
2070 if (path != NULL) {
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002071 struct fuse_intr_data d;
Miklos Szeredi659743b2005-12-09 17:41:42 +00002072 if (f->conf.debug) {
Miklos Szeredi3a770472005-11-11 21:32:42 +00002073 printf("FSYNC[%llu]\n", (unsigned long long) fi->fh);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002074 fflush(stdout);
2075 }
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002076 fuse_prepare_interrupt(f, req, &d);
2077 err = fuse_fs_fsync(f->fs, path, datasync, fi);
2078 fuse_finish_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002079 free(path);
2080 }
2081 pthread_rwlock_unlock(&f->tree_lock);
2082 reply_err(req, err);
2083}
2084
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002085static struct fuse_dh *get_dirhandle(const struct fuse_file_info *llfi,
2086 struct fuse_file_info *fi)
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002087{
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002088 struct fuse_dh *dh = (struct fuse_dh *) (uintptr_t) llfi->fh;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002089 memset(fi, 0, sizeof(struct fuse_file_info));
2090 fi->fh = dh->fh;
Miklos Szerediead7f102005-11-28 16:02:27 +00002091 fi->fh_old = dh->fh;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002092 return dh;
2093}
2094
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002095static void fuse_lib_opendir(fuse_req_t req, fuse_ino_t ino,
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002096 struct fuse_file_info *llfi)
2097{
2098 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002099 struct fuse_intr_data d;
2100 struct fuse_dh *dh;
2101 struct fuse_file_info fi;
2102 char *path;
2103 int err;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002104
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002105 dh = (struct fuse_dh *) malloc(sizeof(struct fuse_dh));
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002106 if (dh == NULL) {
2107 reply_err(req, -ENOMEM);
Miklos Szerediab974562005-04-07 15:40:21 +00002108 return;
Miklos Szeredi5e183482001-10-31 14:52:35 +00002109 }
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002110 memset(dh, 0, sizeof(struct fuse_dh));
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002111 dh->fuse = f;
2112 dh->contents = NULL;
2113 dh->len = 0;
2114 dh->filled = 0;
2115 dh->nodeid = ino;
Miklos Szeredi38f152c2006-09-03 18:28:52 +00002116 fuse_mutex_init(&dh->lock);
Miklos Szerediab974562005-04-07 15:40:21 +00002117
Miklos Szeredi3a770472005-11-11 21:32:42 +00002118 llfi->fh = (uintptr_t) dh;
Miklos Szerediab974562005-04-07 15:40:21 +00002119
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002120 memset(&fi, 0, sizeof(fi));
2121 fi.flags = llfi->flags;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002122
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002123 err = -ENOENT;
2124 pthread_rwlock_rdlock(&f->tree_lock);
2125 path = get_path(f, ino);
2126 if (path != NULL) {
2127 fuse_prepare_interrupt(f, req, &d);
2128 err = fuse_fs_opendir(f->fs, path, &fi);
2129 fuse_finish_interrupt(f, req, &d);
2130 dh->fh = fi.fh;
2131 }
2132 if (!err) {
2133 if (fuse_reply_open(req, llfi) == -ENOENT) {
2134 /* The opendir syscall was interrupted, so it must be cancelled */
2135 fuse_prepare_interrupt(f, req, &d);
2136 fuse_fs_releasedir(f->fs, path, &fi);
2137 fuse_finish_interrupt(f, req, &d);
2138 pthread_mutex_destroy(&dh->lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002139 free(dh);
2140 }
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002141 } else {
2142 reply_err(req, err);
2143 free(dh);
2144 }
2145 free(path);
2146 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredi5e183482001-10-31 14:52:35 +00002147}
Miklos Szeredib483c932001-10-29 14:57:57 +00002148
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002149static int extend_contents(struct fuse_dh *dh, unsigned minsize)
Miklos Szeredi1bf64f42006-02-17 15:49:25 +00002150{
2151 if (minsize > dh->size) {
2152 char *newptr;
2153 unsigned newsize = dh->size;
2154 if (!newsize)
2155 newsize = 1024;
2156 while (newsize < minsize)
2157 newsize *= 2;
2158
2159 newptr = (char *) realloc(dh->contents, newsize);
2160 if (!newptr) {
2161 dh->error = -ENOMEM;
2162 return -1;
2163 }
2164 dh->contents = newptr;
2165 dh->size = newsize;
2166 }
2167 return 0;
2168}
2169
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002170static int fill_dir(void *dh_, const char *name, const struct stat *statp,
2171 off_t off)
Miklos Szeredia181e612001-11-06 12:03:23 +00002172{
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002173 struct fuse_dh *dh = (struct fuse_dh *) dh_;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002174 struct stat stbuf;
Miklos Szeredi1bf64f42006-02-17 15:49:25 +00002175 size_t newlen;
Miklos Szeredifb28c5e2004-11-26 12:15:06 +00002176
Miklos Szeredif6e0ec62005-08-03 09:11:06 +00002177 if (statp)
2178 stbuf = *statp;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002179 else {
2180 memset(&stbuf, 0, sizeof(stbuf));
Miklos Szeredie248e4b2005-12-14 16:18:32 +00002181 stbuf.st_ino = FUSE_UNKNOWN_INO;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002182 }
Miklos Szeredia181e612001-11-06 12:03:23 +00002183
Miklos Szeredi659743b2005-12-09 17:41:42 +00002184 if (!dh->fuse->conf.use_ino) {
Miklos Szeredie248e4b2005-12-14 16:18:32 +00002185 stbuf.st_ino = FUSE_UNKNOWN_INO;
Miklos Szeredi659743b2005-12-09 17:41:42 +00002186 if (dh->fuse->conf.readdir_ino) {
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002187 struct node *node;
2188 pthread_mutex_lock(&dh->fuse->lock);
2189 node = lookup_node(dh->fuse, dh->nodeid, name);
2190 if (node)
2191 stbuf.st_ino = (ino_t) node->nodeid;
2192 pthread_mutex_unlock(&dh->fuse->lock);
Miklos Szeredi6ebe2342002-01-06 21:44:16 +00002193 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002194 }
Miklos Szeredi6ebe2342002-01-06 21:44:16 +00002195
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002196 if (off) {
Miklos Szeredi1bf64f42006-02-17 15:49:25 +00002197 if (extend_contents(dh, dh->needlen) == -1)
2198 return 1;
2199
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002200 dh->filled = 0;
Miklos Szeredi1bf64f42006-02-17 15:49:25 +00002201 newlen = dh->len + fuse_add_direntry(dh->req, dh->contents + dh->len,
2202 dh->needlen - dh->len, name,
2203 &stbuf, off);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002204 if (newlen > dh->needlen)
2205 return 1;
Miklos Szeredi1bf64f42006-02-17 15:49:25 +00002206 } else {
2207 newlen = dh->len + fuse_add_direntry(dh->req, NULL, 0, name, NULL, 0);
2208 if (extend_contents(dh, newlen) == -1)
Miklos Szeredic4c12ae2005-10-20 14:48:50 +00002209 return 1;
Miklos Szeredi1bf64f42006-02-17 15:49:25 +00002210
2211 fuse_add_direntry(dh->req, dh->contents + dh->len, dh->size - dh->len,
2212 name, &stbuf, newlen);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002213 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002214 dh->len = newlen;
2215 return 0;
2216}
2217
Miklos Szeredi1bf64f42006-02-17 15:49:25 +00002218static int readdir_fill(struct fuse *f, fuse_req_t req, fuse_ino_t ino,
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002219 size_t size, off_t off, struct fuse_dh *dh,
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002220 struct fuse_file_info *fi)
2221{
2222 int err = -ENOENT;
2223 char *path;
2224 pthread_rwlock_rdlock(&f->tree_lock);
2225 path = get_path(f, ino);
2226 if (path != NULL) {
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002227 struct fuse_intr_data d;
2228
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002229 dh->len = 0;
2230 dh->error = 0;
2231 dh->needlen = size;
2232 dh->filled = 1;
Miklos Szeredi1bf64f42006-02-17 15:49:25 +00002233 dh->req = req;
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002234 fuse_prepare_interrupt(f, req, &d);
2235 err = fuse_fs_readdir(f->fs, path, dh, fill_dir, off, fi);
2236 fuse_finish_interrupt(f, req, &d);
Miklos Szeredi1bf64f42006-02-17 15:49:25 +00002237 dh->req = NULL;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002238 if (!err)
2239 err = dh->error;
2240 if (err)
2241 dh->filled = 0;
Miklos Szeredi97c61e92001-11-07 12:09:43 +00002242 free(path);
Miklos Szeredia181e612001-11-06 12:03:23 +00002243 }
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00002244 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002245 return err;
2246}
Miklos Szeredie5183742005-02-02 11:14:04 +00002247
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002248static void fuse_lib_readdir(fuse_req_t req, fuse_ino_t ino, size_t size,
2249 off_t off, struct fuse_file_info *llfi)
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002250{
2251 struct fuse *f = req_fuse_prepare(req);
2252 struct fuse_file_info fi;
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002253 struct fuse_dh *dh = get_dirhandle(llfi, &fi);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002254
2255 pthread_mutex_lock(&dh->lock);
Miklos Szeredi77ccf652005-08-19 14:40:27 +00002256 /* According to SUS, directory contents need to be refreshed on
2257 rewinddir() */
2258 if (!off)
2259 dh->filled = 0;
2260
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002261 if (!dh->filled) {
Miklos Szeredi1bf64f42006-02-17 15:49:25 +00002262 int err = readdir_fill(f, req, ino, size, off, dh, &fi);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002263 if (err) {
2264 reply_err(req, err);
2265 goto out;
2266 }
Miklos Szeredia181e612001-11-06 12:03:23 +00002267 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002268 if (dh->filled) {
2269 if (off < dh->len) {
2270 if (off + size > dh->len)
2271 size = dh->len - off;
2272 } else
2273 size = 0;
2274 } else {
2275 size = dh->len;
2276 off = 0;
2277 }
2278 fuse_reply_buf(req, dh->contents + off, size);
2279 out:
2280 pthread_mutex_unlock(&dh->lock);
2281}
Miklos Szeredia181e612001-11-06 12:03:23 +00002282
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002283static void fuse_lib_releasedir(fuse_req_t req, fuse_ino_t ino,
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002284 struct fuse_file_info *llfi)
2285{
2286 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002287 struct fuse_intr_data d;
Miklos Szeredi9b813af2005-07-21 07:59:37 +00002288 struct fuse_file_info fi;
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002289 struct fuse_dh *dh = get_dirhandle(llfi, &fi);
2290 char *path;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002291
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002292 pthread_rwlock_rdlock(&f->tree_lock);
2293 path = get_path(f, ino);
2294 fuse_prepare_interrupt(f, req, &d);
2295 fuse_fs_releasedir(f->fs, path ? path : "-", &fi);
2296 fuse_finish_interrupt(f, req, &d);
2297 if (path)
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002298 free(path);
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002299 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002300 pthread_mutex_lock(&dh->lock);
2301 pthread_mutex_unlock(&dh->lock);
2302 pthread_mutex_destroy(&dh->lock);
2303 free(dh->contents);
2304 free(dh);
2305 reply_err(req, 0);
2306}
2307
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002308static void fuse_lib_fsyncdir(fuse_req_t req, fuse_ino_t ino, int datasync,
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002309 struct fuse_file_info *llfi)
2310{
2311 struct fuse *f = req_fuse_prepare(req);
2312 struct fuse_file_info fi;
2313 char *path;
2314 int err;
2315
2316 get_dirhandle(llfi, &fi);
2317
2318 err = -ENOENT;
2319 pthread_rwlock_rdlock(&f->tree_lock);
2320 path = get_path(f, ino);
2321 if (path != NULL) {
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002322 struct fuse_intr_data d;
2323 fuse_prepare_interrupt(f, req, &d);
2324 err = fuse_fs_fsyncdir(f->fs, path, datasync, &fi);
2325 fuse_finish_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002326 free(path);
2327 }
2328 pthread_rwlock_unlock(&f->tree_lock);
2329 reply_err(req, err);
Miklos Szeredia181e612001-11-06 12:03:23 +00002330}
2331
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002332static void fuse_lib_statfs(fuse_req_t req, fuse_ino_t ino)
Miklos Szeredi18e75e42004-02-19 14:23:27 +00002333{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002334 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredi52cb09d2005-11-07 11:59:00 +00002335 struct statvfs buf;
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002336 char *path;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002337 int err;
Mark Glinesd84b39a2002-01-07 16:32:02 +00002338
Miklos Szeredi52cb09d2005-11-07 11:59:00 +00002339 memset(&buf, 0, sizeof(buf));
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002340 pthread_rwlock_rdlock(&f->tree_lock);
2341 if (!ino) {
2342 err = -ENOMEM;
2343 path = strdup("/");
2344 } else {
2345 err = -ENOENT;
2346 path = get_path(f, ino);
2347 }
2348 if (path) {
2349 struct fuse_intr_data d;
2350 fuse_prepare_interrupt(f, req, &d);
2351 err = fuse_fs_statfs(f->fs, path, &buf);
2352 fuse_finish_interrupt(f, req, &d);
2353 free(path);
2354 }
2355 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredi77f39942004-03-25 11:17:52 +00002356
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002357 if (!err)
2358 fuse_reply_statfs(req, &buf);
Miklos Szeredi03cebae2004-03-31 10:19:18 +00002359 else
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002360 reply_err(req, err);
Miklos Szeredi03cebae2004-03-31 10:19:18 +00002361}
2362
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002363static void fuse_lib_setxattr(fuse_req_t req, fuse_ino_t ino, const char *name,
2364 const char *value, size_t size, int flags)
Miklos Szeredi3ed84232004-03-30 15:17:26 +00002365{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002366 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredi3ed84232004-03-30 15:17:26 +00002367 char *path;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002368 int err;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00002369
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002370 err = -ENOENT;
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00002371 pthread_rwlock_rdlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002372 path = get_path(f, ino);
Miklos Szeredi3ed84232004-03-30 15:17:26 +00002373 if (path != NULL) {
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002374 struct fuse_intr_data d;
2375 fuse_prepare_interrupt(f, req, &d);
2376 err = fuse_fs_setxattr(f->fs, path, name, value, size, flags);
2377 fuse_finish_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002378 free(path);
2379 }
2380 pthread_rwlock_unlock(&f->tree_lock);
2381 reply_err(req, err);
2382}
2383
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002384static int common_getxattr(struct fuse *f, fuse_req_t req, fuse_ino_t ino,
2385 const char *name, char *value, size_t size)
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002386{
2387 int err;
2388 char *path;
2389
2390 err = -ENOENT;
2391 pthread_rwlock_rdlock(&f->tree_lock);
2392 path = get_path(f, ino);
2393 if (path != NULL) {
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002394 struct fuse_intr_data d;
2395 fuse_prepare_interrupt(f, req, &d);
2396 err = fuse_fs_getxattr(f->fs, path, name, value, size);
2397 fuse_finish_interrupt(f, req, &d);
Miklos Szerediab974562005-04-07 15:40:21 +00002398 free(path);
2399 }
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00002400 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szerediab974562005-04-07 15:40:21 +00002401 return err;
2402}
2403
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002404static void fuse_lib_getxattr(fuse_req_t req, fuse_ino_t ino, const char *name,
2405 size_t size)
Miklos Szeredi3ead28e2005-01-18 21:23:41 +00002406{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002407 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredi4283ee72005-03-21 12:09:04 +00002408 int res;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002409
2410 if (size) {
2411 char *value = (char *) malloc(size);
2412 if (value == NULL) {
2413 reply_err(req, -ENOMEM);
2414 return;
2415 }
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002416 res = common_getxattr(f, req, ino, name, value, size);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002417 if (res > 0)
2418 fuse_reply_buf(req, value, res);
2419 else
2420 reply_err(req, res);
2421 free(value);
2422 } else {
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002423 res = common_getxattr(f, req, ino, name, NULL, 0);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002424 if (res >= 0)
2425 fuse_reply_xattr(req, res);
2426 else
2427 reply_err(req, res);
2428 }
2429}
2430
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002431static int common_listxattr(struct fuse *f, fuse_req_t req, fuse_ino_t ino,
2432 char *list, size_t size)
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002433{
Miklos Szeredi4283ee72005-03-21 12:09:04 +00002434 char *path;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002435 int err;
Miklos Szeredi4283ee72005-03-21 12:09:04 +00002436
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002437 err = -ENOENT;
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00002438 pthread_rwlock_rdlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002439 path = get_path(f, ino);
Miklos Szeredi4283ee72005-03-21 12:09:04 +00002440 if (path != NULL) {
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002441 struct fuse_intr_data d;
2442 fuse_prepare_interrupt(f, req, &d);
2443 err = fuse_fs_listxattr(f->fs, path, list, size);
2444 fuse_finish_interrupt(f, req, &d);
Miklos Szeredi4283ee72005-03-21 12:09:04 +00002445 free(path);
2446 }
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00002447 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002448 return err;
Miklos Szeredi4283ee72005-03-21 12:09:04 +00002449}
Miklos Szeredi3ead28e2005-01-18 21:23:41 +00002450
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002451static void fuse_lib_listxattr(fuse_req_t req, fuse_ino_t ino, size_t size)
Miklos Szeredi43696432001-11-18 19:15:05 +00002452{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002453 struct fuse *f = req_fuse_prepare(req);
2454 int res;
2455
2456 if (size) {
2457 char *list = (char *) malloc(size);
2458 if (list == NULL) {
2459 reply_err(req, -ENOMEM);
2460 return;
2461 }
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002462 res = common_listxattr(f, req, ino, list, size);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002463 if (res > 0)
2464 fuse_reply_buf(req, list, res);
2465 else
2466 reply_err(req, res);
2467 free(list);
2468 } else {
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002469 res = common_listxattr(f, req, ino, NULL, 0);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002470 if (res >= 0)
2471 fuse_reply_xattr(req, res);
2472 else
2473 reply_err(req, res);
2474 }
Miklos Szeredi43696432001-11-18 19:15:05 +00002475}
2476
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002477static void fuse_lib_removexattr(fuse_req_t req, fuse_ino_t ino,
2478 const char *name)
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002479{
2480 struct fuse *f = req_fuse_prepare(req);
2481 char *path;
2482 int err;
2483
2484 err = -ENOENT;
2485 pthread_rwlock_rdlock(&f->tree_lock);
2486 path = get_path(f, ino);
2487 if (path != NULL) {
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002488 struct fuse_intr_data d;
2489 fuse_prepare_interrupt(f, req, &d);
2490 err = fuse_fs_removexattr(f->fs, path, name);
2491 fuse_finish_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002492 free(path);
2493 }
2494 pthread_rwlock_unlock(&f->tree_lock);
2495 reply_err(req, err);
2496}
2497
Miklos Szeredi0c59ebf2006-09-10 20:53:36 +00002498static struct lock *locks_conflict(struct node *node, const struct lock *lock)
2499{
2500 struct lock *l;
2501
2502 for (l = node->locks; l; l = l->next)
2503 if (l->owner != lock->owner &&
2504 lock->start <= l->end && l->start <= lock->end &&
2505 (l->type == F_WRLCK || lock->type == F_WRLCK))
2506 break;
2507
2508 return l;
2509}
2510
2511static void delete_lock(struct lock **lockp)
2512{
2513 struct lock *l = *lockp;
2514 *lockp = l->next;
2515 free(l);
2516}
2517
2518static void insert_lock(struct lock **pos, struct lock *lock)
2519{
2520 lock->next = *pos;
2521 *pos = lock;
2522}
2523
2524static int locks_insert(struct node *node, struct lock *lock)
2525{
2526 struct lock **lp;
2527 struct lock *newl1 = NULL;
2528 struct lock *newl2 = NULL;
2529
2530 if (lock->type != F_UNLCK || lock->start != 0 || lock->end != OFFSET_MAX) {
2531 newl1 = malloc(sizeof(struct lock));
2532 newl2 = malloc(sizeof(struct lock));
2533
2534 if (!newl1 || !newl2) {
2535 free(newl1);
2536 free(newl2);
2537 return -ENOLCK;
2538 }
2539 }
2540
2541 for (lp = &node->locks; *lp;) {
2542 struct lock *l = *lp;
2543 if (l->owner != lock->owner)
2544 goto skip;
2545
2546 if (lock->type == l->type) {
2547 if (l->end < lock->start - 1)
2548 goto skip;
2549 if (lock->end < l->start - 1)
2550 break;
2551 if (l->start <= lock->start && lock->end <= l->end)
2552 goto out;
2553 if (l->start < lock->start)
2554 lock->start = l->start;
2555 if (lock->end < l->end)
2556 lock->end = l->end;
2557 goto delete;
2558 } else {
2559 if (l->end < lock->start)
2560 goto skip;
2561 if (lock->end < l->start)
2562 break;
2563 if (lock->start <= l->start && l->end <= lock->end)
2564 goto delete;
2565 if (l->end <= lock->end) {
2566 l->end = lock->start - 1;
2567 goto skip;
2568 }
2569 if (lock->start <= l->start) {
2570 l->start = lock->end + 1;
2571 break;
2572 }
2573 *newl2 = *l;
2574 newl2->start = lock->end + 1;
2575 l->end = lock->start - 1;
2576 insert_lock(&l->next, newl2);
2577 newl2 = NULL;
2578 }
2579 skip:
2580 lp = &l->next;
2581 continue;
2582
2583 delete:
2584 delete_lock(lp);
2585 }
2586 if (lock->type != F_UNLCK) {
2587 *newl1 = *lock;
2588 insert_lock(lp, newl1);
2589 newl1 = NULL;
2590 }
2591out:
2592 free(newl1);
2593 free(newl2);
2594 return 0;
2595}
2596
2597static void flock_to_lock(struct flock *flock, struct lock *lock)
2598{
2599 memset(lock, 0, sizeof(struct lock));
2600 lock->type = flock->l_type;
2601 lock->start = flock->l_start;
2602 lock->end = flock->l_len ? flock->l_start + flock->l_len - 1 : OFFSET_MAX;
2603 lock->pid = flock->l_pid;
2604}
2605
2606static void lock_to_flock(struct lock *lock, struct flock *flock)
2607{
2608 flock->l_type = lock->type;
2609 flock->l_start = lock->start;
2610 flock->l_len = (lock->end == OFFSET_MAX) ? 0 : lock->end - lock->start + 1;
2611 flock->l_pid = lock->pid;
2612}
2613
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002614static void fuse_lib_flush(fuse_req_t req, fuse_ino_t ino,
Miklos Szeredi07407852006-09-30 20:03:52 +00002615 struct fuse_file_info *fi)
Miklos Szeredi0c59ebf2006-09-10 20:53:36 +00002616{
2617 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002618 struct fuse_intr_data d;
2619 struct flock lock;
2620 struct lock l;
Miklos Szeredi0c59ebf2006-09-10 20:53:36 +00002621 char *path;
2622 int err;
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002623 int errlock;
Miklos Szeredi0c59ebf2006-09-10 20:53:36 +00002624
2625 err = -ENOENT;
2626 pthread_rwlock_rdlock(&f->tree_lock);
2627 path = get_path(f, ino);
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002628 if (path && f->conf.debug) {
2629 printf("FLUSH[%llu]\n", (unsigned long long) fi->fh);
2630 fflush(stdout);
Miklos Szeredi0c59ebf2006-09-10 20:53:36 +00002631 }
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002632 fuse_prepare_interrupt(f, req, &d);
2633 if (path)
2634 err = fuse_fs_flush(f->fs, path, fi);
2635
2636 memset(&lock, 0, sizeof(lock));
2637 lock.l_type = F_UNLCK;
2638 lock.l_whence = SEEK_SET;
2639 errlock = fuse_fs_lock(f->fs, path, fi, F_SETLK, &lock);
2640 fuse_finish_interrupt(f, req, &d);
2641 if (errlock != ENOSYS) {
Miklos Szeredi0c59ebf2006-09-10 20:53:36 +00002642 flock_to_lock(&lock, &l);
Miklos Szeredi07407852006-09-30 20:03:52 +00002643 l.owner = fi->lock_owner;
Miklos Szeredi0c59ebf2006-09-10 20:53:36 +00002644 pthread_mutex_lock(&f->lock);
2645 locks_insert(get_node(f, ino), &l);
2646 pthread_mutex_unlock(&f->lock);
2647
2648 /* if op.lock() is defined FLUSH is needed regardless of op.flush() */
2649 if (err == -ENOSYS)
2650 err = 0;
2651 }
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002652 if (path)
2653 free(path);
Miklos Szeredi0c59ebf2006-09-10 20:53:36 +00002654 pthread_rwlock_unlock(&f->tree_lock);
2655 reply_err(req, err);
2656}
2657
Miklos Szeredi9a5c11d2006-07-30 17:33:40 +00002658static int fuse_lock_common(fuse_req_t req, fuse_ino_t ino,
2659 struct fuse_file_info *fi, struct flock *lock,
Miklos Szeredi07407852006-09-30 20:03:52 +00002660 int cmd)
Miklos Szeredi9a5c11d2006-07-30 17:33:40 +00002661{
2662 struct fuse *f = req_fuse_prepare(req);
2663 char *path;
2664 int err;
2665
2666 err = -ENOENT;
2667 pthread_rwlock_rdlock(&f->tree_lock);
2668 path = get_path(f, ino);
2669 if (path != NULL) {
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002670 struct fuse_intr_data d;
2671 fuse_prepare_interrupt(f, req, &d);
2672 err = fuse_fs_lock(f->fs, path, fi, cmd, lock);
2673 fuse_finish_interrupt(f, req, &d);
Miklos Szeredi9a5c11d2006-07-30 17:33:40 +00002674 free(path);
2675 }
2676 pthread_rwlock_unlock(&f->tree_lock);
2677 return err;
2678}
2679
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002680static void fuse_lib_getlk(fuse_req_t req, fuse_ino_t ino,
2681 struct fuse_file_info *fi, struct flock *lock)
Miklos Szeredi9a5c11d2006-07-30 17:33:40 +00002682{
Miklos Szeredi0c59ebf2006-09-10 20:53:36 +00002683 int err;
2684 struct lock l;
2685 struct lock *conflict;
2686 struct fuse *f = req_fuse(req);
2687
2688 flock_to_lock(lock, &l);
Miklos Szeredi07407852006-09-30 20:03:52 +00002689 l.owner = fi->lock_owner;
Miklos Szeredi0c59ebf2006-09-10 20:53:36 +00002690 pthread_mutex_lock(&f->lock);
2691 conflict = locks_conflict(get_node(f, ino), &l);
2692 if (conflict)
2693 lock_to_flock(conflict, lock);
2694 pthread_mutex_unlock(&f->lock);
2695 if (!conflict)
Miklos Szeredi07407852006-09-30 20:03:52 +00002696 err = fuse_lock_common(req, ino, fi, lock, F_GETLK);
Miklos Szeredi0c59ebf2006-09-10 20:53:36 +00002697 else
2698 err = 0;
2699
Miklos Szeredi9a5c11d2006-07-30 17:33:40 +00002700 if (!err)
2701 fuse_reply_lock(req, lock);
2702 else
2703 reply_err(req, err);
2704}
2705
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002706static void fuse_lib_setlk(fuse_req_t req, fuse_ino_t ino,
2707 struct fuse_file_info *fi, struct flock *lock,
2708 int sleep)
Miklos Szeredi9a5c11d2006-07-30 17:33:40 +00002709{
Miklos Szeredi07407852006-09-30 20:03:52 +00002710 int err = fuse_lock_common(req, ino, fi, lock, sleep ? F_SETLKW : F_SETLK);
Miklos Szeredi0c59ebf2006-09-10 20:53:36 +00002711 if (!err) {
2712 struct fuse *f = req_fuse(req);
2713 struct lock l;
2714 flock_to_lock(lock, &l);
Miklos Szeredi07407852006-09-30 20:03:52 +00002715 l.owner = fi->lock_owner;
Miklos Szeredi0c59ebf2006-09-10 20:53:36 +00002716 pthread_mutex_lock(&f->lock);
2717 locks_insert(get_node(f, ino), &l);
2718 pthread_mutex_unlock(&f->lock);
2719 }
2720 reply_err(req, err);
Miklos Szeredi9a5c11d2006-07-30 17:33:40 +00002721}
2722
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002723static void fuse_lib_bmap(fuse_req_t req, fuse_ino_t ino, size_t blocksize,
2724 uint64_t idx)
Miklos Szeredi708b4812006-09-30 16:02:25 +00002725{
2726 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002727 struct fuse_intr_data d;
Miklos Szeredi708b4812006-09-30 16:02:25 +00002728 char *path;
2729 int err;
2730
2731 err = -ENOENT;
2732 pthread_rwlock_rdlock(&f->tree_lock);
2733 path = get_path(f, ino);
2734 if (path != NULL) {
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002735 fuse_prepare_interrupt(f, req, &d);
2736 err = fuse_fs_bmap(f->fs, path, blocksize, &idx);
2737 fuse_finish_interrupt(f, req, &d);
Miklos Szeredi708b4812006-09-30 16:02:25 +00002738 free(path);
2739 }
2740 pthread_rwlock_unlock(&f->tree_lock);
2741 if (!err)
2742 fuse_reply_bmap(req, idx);
2743 else
2744 reply_err(req, err);
2745}
2746
Miklos Szeredia1482422005-08-14 23:00:27 +00002747static struct fuse_lowlevel_ops fuse_path_ops = {
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002748 .init = fuse_lib_init,
2749 .destroy = fuse_lib_destroy,
2750 .lookup = fuse_lib_lookup,
2751 .forget = fuse_lib_forget,
2752 .getattr = fuse_lib_getattr,
2753 .setattr = fuse_lib_setattr,
2754 .access = fuse_lib_access,
2755 .readlink = fuse_lib_readlink,
2756 .mknod = fuse_lib_mknod,
2757 .mkdir = fuse_lib_mkdir,
2758 .unlink = fuse_lib_unlink,
2759 .rmdir = fuse_lib_rmdir,
2760 .symlink = fuse_lib_symlink,
2761 .rename = fuse_lib_rename,
2762 .link = fuse_lib_link,
2763 .create = fuse_lib_create,
2764 .open = fuse_lib_open,
2765 .read = fuse_lib_read,
2766 .write = fuse_lib_write,
2767 .flush = fuse_lib_flush,
2768 .release = fuse_lib_release,
2769 .fsync = fuse_lib_fsync,
2770 .opendir = fuse_lib_opendir,
2771 .readdir = fuse_lib_readdir,
2772 .releasedir = fuse_lib_releasedir,
2773 .fsyncdir = fuse_lib_fsyncdir,
2774 .statfs = fuse_lib_statfs,
2775 .setxattr = fuse_lib_setxattr,
2776 .getxattr = fuse_lib_getxattr,
2777 .listxattr = fuse_lib_listxattr,
2778 .removexattr = fuse_lib_removexattr,
2779 .getlk = fuse_lib_getlk,
2780 .setlk = fuse_lib_setlk,
2781 .bmap = fuse_lib_bmap,
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002782};
2783
Miklos Szeredia1482422005-08-14 23:00:27 +00002784static void free_cmd(struct fuse_cmd *cmd)
2785{
2786 free(cmd->buf);
2787 free(cmd);
2788}
2789
Miklos Szeredif458b8c2004-12-07 16:46:42 +00002790void fuse_process_cmd(struct fuse *f, struct fuse_cmd *cmd)
Miklos Szeredia181e612001-11-06 12:03:23 +00002791{
Miklos Szeredi178451d2005-08-15 13:19:07 +00002792 fuse_session_process(f->se, cmd->buf, cmd->buflen, cmd->ch);
Miklos Szeredifa829b52005-12-02 11:05:41 +00002793 free_cmd(cmd);
Miklos Szeredia181e612001-11-06 12:03:23 +00002794}
2795
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002796int fuse_exited(struct fuse *f)
Miklos Szeredi65cf7c72004-06-30 11:34:56 +00002797{
Miklos Szeredia1482422005-08-14 23:00:27 +00002798 return fuse_session_exited(f->se);
2799}
2800
2801struct fuse_session *fuse_get_session(struct fuse *f)
2802{
2803 return f->se;
2804}
2805
2806static struct fuse_cmd *fuse_alloc_cmd(size_t bufsize)
2807{
2808 struct fuse_cmd *cmd = (struct fuse_cmd *) malloc(sizeof(*cmd));
2809 if (cmd == NULL) {
2810 fprintf(stderr, "fuse: failed to allocate cmd\n");
2811 return NULL;
2812 }
2813 cmd->buf = (char *) malloc(bufsize);
2814 if (cmd->buf == NULL) {
2815 fprintf(stderr, "fuse: failed to allocate read buffer\n");
2816 free(cmd);
2817 return NULL;
2818 }
2819 return cmd;
Miklos Szeredi65cf7c72004-06-30 11:34:56 +00002820}
2821
Miklos Szeredif458b8c2004-12-07 16:46:42 +00002822struct fuse_cmd *fuse_read_cmd(struct fuse *f)
Miklos Szeredi2df1c042001-11-06 15:07:17 +00002823{
Miklos Szeredia1482422005-08-14 23:00:27 +00002824 struct fuse_chan *ch = fuse_session_next_chan(f->se, NULL);
2825 size_t bufsize = fuse_chan_bufsize(ch);
2826 struct fuse_cmd *cmd = fuse_alloc_cmd(bufsize);
2827 if (cmd != NULL) {
Miklos Szeredi8d975f62006-03-17 15:56:05 +00002828 int res = fuse_chan_recv(&ch, cmd->buf, bufsize);
Miklos Szeredia1482422005-08-14 23:00:27 +00002829 if (res <= 0) {
2830 free_cmd(cmd);
Miklos Szeredi5d9ce362006-03-01 12:10:13 +00002831 if (res < 0 && res != -EINTR && res != -EAGAIN)
Miklos Szeredifa829b52005-12-02 11:05:41 +00002832 fuse_exit(f);
Miklos Szeredia1482422005-08-14 23:00:27 +00002833 return NULL;
2834 }
2835 cmd->buflen = res;
Miklos Szeredi178451d2005-08-15 13:19:07 +00002836 cmd->ch = ch;
Miklos Szeredia1482422005-08-14 23:00:27 +00002837 }
2838 return cmd;
Miklos Szeredi2df1c042001-11-06 15:07:17 +00002839}
2840
Miklos Szeredib2cf9562004-09-16 08:42:40 +00002841int fuse_loop(struct fuse *f)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00002842{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002843 if (f)
Miklos Szeredia1482422005-08-14 23:00:27 +00002844 return fuse_session_loop(f->se);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002845 else
Miklos Szeredib2cf9562004-09-16 08:42:40 +00002846 return -1;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00002847}
2848
Miklos Szeredi891b8742004-07-29 09:27:49 +00002849int fuse_invalidate(struct fuse *f, const char *path)
2850{
Miklos Szeredie56818b2004-12-12 11:45:24 +00002851 (void) f;
2852 (void) path;
2853 return -EINVAL;
Miklos Szeredi891b8742004-07-29 09:27:49 +00002854}
2855
Miklos Szeredi0f48a262002-12-05 14:23:01 +00002856void fuse_exit(struct fuse *f)
2857{
Miklos Szeredia1482422005-08-14 23:00:27 +00002858 fuse_session_exit(f->se);
Miklos Szeredi0f48a262002-12-05 14:23:01 +00002859}
2860
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002861struct fuse_context *fuse_get_context(void)
Miklos Szeredi2e50d432001-12-20 12:17:25 +00002862{
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002863 return &fuse_get_context_internal()->ctx;
2864}
2865
2866int fuse_interrupted(void)
2867{
2868 return fuse_req_interrupted(fuse_get_context_internal()->req);
Miklos Szeredid169f312004-09-22 08:48:26 +00002869}
2870
Miklos Szeredif458b8c2004-12-07 16:46:42 +00002871void fuse_set_getcontext_func(struct fuse_context *(*func)(void))
Miklos Szeredid169f312004-09-22 08:48:26 +00002872{
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002873 (void) func;
2874 /* no-op */
Miklos Szeredi2e50d432001-12-20 12:17:25 +00002875}
2876
Miklos Szerediad005972006-01-07 10:14:34 +00002877enum {
2878 KEY_HELP,
Miklos Szerediad005972006-01-07 10:14:34 +00002879};
2880
Miklos Szeredi659743b2005-12-09 17:41:42 +00002881#define FUSE_LIB_OPT(t, p, v) { t, offsetof(struct fuse_config, p), v }
2882
2883static const struct fuse_opt fuse_lib_opts[] = {
Miklos Szerediad005972006-01-07 10:14:34 +00002884 FUSE_OPT_KEY("-h", KEY_HELP),
2885 FUSE_OPT_KEY("--help", KEY_HELP),
Miklos Szeredi065f2222006-01-20 15:15:21 +00002886 FUSE_OPT_KEY("debug", FUSE_OPT_KEY_KEEP),
2887 FUSE_OPT_KEY("-d", FUSE_OPT_KEY_KEEP),
Miklos Szeredi659743b2005-12-09 17:41:42 +00002888 FUSE_LIB_OPT("debug", debug, 1),
Miklos Szeredi95da8602006-01-06 18:29:40 +00002889 FUSE_LIB_OPT("-d", debug, 1),
Miklos Szeredi659743b2005-12-09 17:41:42 +00002890 FUSE_LIB_OPT("hard_remove", hard_remove, 1),
2891 FUSE_LIB_OPT("use_ino", use_ino, 1),
2892 FUSE_LIB_OPT("readdir_ino", readdir_ino, 1),
2893 FUSE_LIB_OPT("direct_io", direct_io, 1),
2894 FUSE_LIB_OPT("kernel_cache", kernel_cache, 1),
Miklos Szeredi320abe42006-01-30 18:14:51 +00002895 FUSE_LIB_OPT("auto_cache", auto_cache, 1),
2896 FUSE_LIB_OPT("noauto_cache", auto_cache, 0),
Miklos Szeredi659743b2005-12-09 17:41:42 +00002897 FUSE_LIB_OPT("umask=", set_mode, 1),
2898 FUSE_LIB_OPT("umask=%o", umask, 0),
2899 FUSE_LIB_OPT("uid=", set_uid, 1),
2900 FUSE_LIB_OPT("uid=%d", uid, 0),
2901 FUSE_LIB_OPT("gid=", set_gid, 1),
2902 FUSE_LIB_OPT("gid=%d", gid, 0),
2903 FUSE_LIB_OPT("entry_timeout=%lf", entry_timeout, 0),
2904 FUSE_LIB_OPT("attr_timeout=%lf", attr_timeout, 0),
Miklos Szeredi6e806e92006-02-16 16:59:39 +00002905 FUSE_LIB_OPT("ac_attr_timeout=%lf", ac_attr_timeout, 0),
2906 FUSE_LIB_OPT("ac_attr_timeout=", ac_attr_timeout_set, 1),
Miklos Szeredi659743b2005-12-09 17:41:42 +00002907 FUSE_LIB_OPT("negative_timeout=%lf", negative_timeout, 0),
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002908 FUSE_LIB_OPT("intr", intr, 1),
2909 FUSE_LIB_OPT("intr_signal=%d", intr_signal, 0),
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002910 FUSE_LIB_OPT("modules=%s", modules, 0),
Miklos Szeredi659743b2005-12-09 17:41:42 +00002911 FUSE_OPT_END
2912};
2913
Miklos Szerediad005972006-01-07 10:14:34 +00002914static void fuse_lib_help(void)
2915{
2916 fprintf(stderr,
Miklos Szeredi06091462006-02-16 16:38:34 +00002917" -o hard_remove immediate removal (don't hide files)\n"
2918" -o use_ino let filesystem set inode numbers\n"
2919" -o readdir_ino try to fill in d_ino in readdir\n"
2920" -o direct_io use direct I/O\n"
2921" -o kernel_cache cache files in kernel\n"
2922" -o [no]auto_cache enable caching based on modification times\n"
2923" -o umask=M set file permissions (octal)\n"
2924" -o uid=N set file owner\n"
2925" -o gid=N set file group\n"
2926" -o entry_timeout=T cache timeout for names (1.0s)\n"
2927" -o negative_timeout=T cache timeout for deleted names (0.0s)\n"
Miklos Szeredi6e806e92006-02-16 16:59:39 +00002928" -o attr_timeout=T cache timeout for attributes (1.0s)\n"
2929" -o ac_attr_timeout=T auto cache timeout for attributes (attr_timeout)\n"
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002930" -o intr allow requests to be interrupted\n"
2931" -o intr_signal=NUM signal to send on interrupt (%i)\n"
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002932" -o modules=M1[:M2...] names of modules to push onto filesystem stack\n"
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002933"\n", FUSE_DEFAULT_INTR_SIGNAL);
Miklos Szerediad005972006-01-07 10:14:34 +00002934}
2935
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002936static void fuse_lib_help_modules(void)
2937{
2938 struct fuse_module *m;
2939 fprintf(stderr, "\nModule options:\n");
2940 pthread_mutex_lock(&fuse_context_lock);
2941 for (m = fuse_modules; m; m = m->next) {
2942 struct fuse_fs *fs = NULL;
2943 struct fuse_fs *newfs;
2944 struct fuse_args args = FUSE_ARGS_INIT(0, NULL);
2945 if (fuse_opt_add_arg(&args, "") != -1 &&
2946 fuse_opt_add_arg(&args, "-h") != -1) {
2947 fprintf(stderr, "\n[%s]\n", m->name);
2948 newfs = m->factory(&args, &fs);
2949 assert(newfs == NULL);
2950 }
2951 fuse_opt_free_args(&args);
2952 }
2953 pthread_mutex_unlock(&fuse_context_lock);
2954}
2955
Miklos Szerediad005972006-01-07 10:14:34 +00002956static int fuse_lib_opt_proc(void *data, const char *arg, int key,
2957 struct fuse_args *outargs)
2958{
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002959 (void) arg; (void) outargs;
Miklos Szerediad005972006-01-07 10:14:34 +00002960
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002961 if (key == KEY_HELP) {
2962 struct fuse_config *conf = (struct fuse_config *) data;
Miklos Szerediad005972006-01-07 10:14:34 +00002963 fuse_lib_help();
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002964 conf->help = 1;
2965 }
Miklos Szerediad005972006-01-07 10:14:34 +00002966
2967 return 1;
2968}
2969
Miklos Szeredibd7661b2004-07-23 17:16:29 +00002970int fuse_is_lib_option(const char *opt)
2971{
Miklos Szeredi659743b2005-12-09 17:41:42 +00002972 return fuse_lowlevel_is_lib_option(opt) ||
2973 fuse_opt_match(fuse_lib_opts, opt);
Miklos Szeredibd7661b2004-07-23 17:16:29 +00002974}
2975
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002976static int fuse_init_intr_signal(int signum, int *installed)
2977{
2978 struct sigaction old_sa;
2979
2980 if (sigaction(signum, NULL, &old_sa) == -1) {
2981 perror("fuse: cannot get old signal handler");
2982 return -1;
2983 }
2984
2985 if (old_sa.sa_handler == SIG_DFL) {
2986 struct sigaction sa;
2987
2988 memset(&sa, 0, sizeof(struct sigaction));
2989 sa.sa_handler = fuse_intr_sighandler;
Miklos Szeredi0c59ebf2006-09-10 20:53:36 +00002990 sigemptyset(&sa.sa_mask);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002991
2992 if (sigaction(signum, &sa, NULL) == -1) {
2993 perror("fuse: cannot set interrupt signal handler");
2994 return -1;
2995 }
2996 *installed = 1;
2997 }
2998 return 0;
2999}
3000
Miklos Szeredi349bdda2006-09-07 11:48:16 +00003001static void fuse_restore_intr_signal(int signum)
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00003002{
Miklos Szeredi349bdda2006-09-07 11:48:16 +00003003 struct sigaction sa;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00003004
Miklos Szeredi349bdda2006-09-07 11:48:16 +00003005 memset(&sa, 0, sizeof(struct sigaction));
3006 sa.sa_handler = SIG_DFL;
3007 sigaction(signum, &sa, NULL);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00003008}
3009
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00003010
3011static int fuse_push_module(struct fuse *f, const char *module,
3012 struct fuse_args *args)
3013{
3014 struct fuse_fs *fs[2] = { f->fs, NULL };
3015 struct fuse_fs *newfs;
3016 struct fuse_module *m = fuse_get_module(module);
3017
3018 if (!m)
3019 return -1;
3020
3021 newfs = m->factory(args, fs);
3022 if (!newfs) {
3023 fuse_put_module(m);
3024 return -1;
3025 }
3026 newfs->m = m;
3027 f->fs = newfs;
3028 return 0;
3029}
3030
3031struct fuse_fs *fuse_fs_new(const struct fuse_operations *op, size_t op_size,
3032 void *user_data)
3033{
3034 struct fuse_fs *fs;
3035
3036 if (sizeof(struct fuse_operations) < op_size) {
3037 fprintf(stderr, "fuse: warning: library too old, some operations may not not work\n");
3038 op_size = sizeof(struct fuse_operations);
3039 }
3040
3041 fs = (struct fuse_fs *) calloc(1, sizeof(struct fuse_fs));
3042 if (!fs) {
3043 fprintf(stderr, "fuse: failed to allocate fuse_fs object\n");
3044 return NULL;
3045 }
3046
3047 fs->user_data = user_data;
3048 memcpy(&fs->op, op, op_size);
3049 return fs;
3050}
3051
Miklos Szeredi6f385412006-03-17 15:05:40 +00003052struct fuse *fuse_new_common(struct fuse_chan *ch, struct fuse_args *args,
Miklos Szeredi0b6a0ad2004-12-04 00:40:50 +00003053 const struct fuse_operations *op,
Miklos Szeredi6f385412006-03-17 15:05:40 +00003054 size_t op_size, void *user_data, int compat)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00003055{
Miklos Szeredi97c61e92001-11-07 12:09:43 +00003056 struct fuse *f;
3057 struct node *root;
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00003058 struct fuse_fs *fs;
Miklos Szeredi9a5c11d2006-07-30 17:33:40 +00003059 struct fuse_lowlevel_ops llop = fuse_path_ops;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00003060
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00003061 if (fuse_create_context_key() == -1)
3062 goto out;
3063
Miklos Szeredi97c61e92001-11-07 12:09:43 +00003064 f = (struct fuse *) calloc(1, sizeof(struct fuse));
Miklos Szeredie56818b2004-12-12 11:45:24 +00003065 if (f == NULL) {
3066 fprintf(stderr, "fuse: failed to allocate fuse object\n");
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00003067 goto out_delete_context_key;
Miklos Szeredie56818b2004-12-12 11:45:24 +00003068 }
Miklos Szeredi2df1c042001-11-06 15:07:17 +00003069
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00003070 fs = fuse_fs_new(op, op_size, user_data);
3071 if (!fs)
3072 goto out_free;
3073
3074 fs->compat = compat;
3075 f->fs = fs;
3076
3077 /* Oh f**k, this is ugly! */
3078 if (!fs->op.lock) {
3079 llop.getlk = NULL;
3080 llop.setlk = NULL;
3081 }
3082
Miklos Szeredi659743b2005-12-09 17:41:42 +00003083 f->conf.entry_timeout = 1.0;
3084 f->conf.attr_timeout = 1.0;
3085 f->conf.negative_timeout = 0.0;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00003086 f->conf.intr_signal = FUSE_DEFAULT_INTR_SIGNAL;
Miklos Szeredi6c0209a2005-08-02 13:31:28 +00003087
Miklos Szerediad005972006-01-07 10:14:34 +00003088 if (fuse_opt_parse(args, &f->conf, fuse_lib_opts, fuse_lib_opt_proc) == -1)
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00003089 goto out_free_fs;
3090
3091 if (f->conf.modules) {
3092 char *module;
3093 char *next;
3094
3095 for (module = f->conf.modules; module; module = next) {
3096 char *p;
3097 for (p = module; *p && *p != ':'; p++);
3098 next = *p ? p + 1 : NULL;
3099 *p = '\0';
3100 if (module[0] && fuse_push_module(f, module, args) == -1)
3101 goto out_free_fs;
3102 }
3103 }
Miklos Szeredib2cf9562004-09-16 08:42:40 +00003104
Miklos Szeredi6e806e92006-02-16 16:59:39 +00003105 if (!f->conf.ac_attr_timeout_set)
3106 f->conf.ac_attr_timeout = f->conf.attr_timeout;
3107
Miklos Szeredi659743b2005-12-09 17:41:42 +00003108#ifdef __FreeBSD__
3109 /*
3110 * In FreeBSD, we always use these settings as inode numbers are needed to
3111 * make getcwd(3) work.
3112 */
Miklos Szeredi76fc3de2005-12-12 09:34:45 +00003113 f->conf.readdir_ino = 1;
Miklos Szeredi659743b2005-12-09 17:41:42 +00003114#endif
3115
Miklos Szeredi065f2222006-01-20 15:15:21 +00003116 if (compat && compat <= 25) {
3117 if (fuse_sync_compat_args(args) == -1)
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00003118 goto out_free_fs;
Miklos Szeredi9a5c11d2006-07-30 17:33:40 +00003119 }
3120
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00003121 f->se = fuse_lowlevel_new_common(args, &llop, sizeof(llop), f);
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00003122 if (f->se == NULL) {
3123 if (f->conf.help)
3124 fuse_lib_help_modules();
3125 goto out_free_fs;
3126 }
Miklos Szeredi2bb750e2005-10-03 14:54:24 +00003127
Miklos Szeredia1482422005-08-14 23:00:27 +00003128 fuse_session_add_chan(f->se, ch);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00003129
Miklos Szeredi97c61e92001-11-07 12:09:43 +00003130 f->ctr = 0;
Miklos Szeredi76f65782004-02-19 16:55:40 +00003131 f->generation = 0;
Miklos Szeredifff56ab2001-11-16 10:12:59 +00003132 /* FIXME: Dynamic hash table */
Miklos Szeredi97c61e92001-11-07 12:09:43 +00003133 f->name_table_size = 14057;
3134 f->name_table = (struct node **)
3135 calloc(1, sizeof(struct node *) * f->name_table_size);
Miklos Szeredie56818b2004-12-12 11:45:24 +00003136 if (f->name_table == NULL) {
3137 fprintf(stderr, "fuse: memory allocation failed\n");
Miklos Szeredia1482422005-08-14 23:00:27 +00003138 goto out_free_session;
Miklos Szeredie56818b2004-12-12 11:45:24 +00003139 }
Miklos Szeredib2cf9562004-09-16 08:42:40 +00003140
Miklos Szeredia13d9002004-11-02 17:32:03 +00003141 f->id_table_size = 14057;
3142 f->id_table = (struct node **)
3143 calloc(1, sizeof(struct node *) * f->id_table_size);
Miklos Szeredie56818b2004-12-12 11:45:24 +00003144 if (f->id_table == NULL) {
3145 fprintf(stderr, "fuse: memory allocation failed\n");
Miklos Szeredib2cf9562004-09-16 08:42:40 +00003146 goto out_free_name_table;
Miklos Szeredie56818b2004-12-12 11:45:24 +00003147 }
Miklos Szeredib2cf9562004-09-16 08:42:40 +00003148
Miklos Szeredi38f152c2006-09-03 18:28:52 +00003149 fuse_mutex_init(&f->lock);
Miklos Szeredid0a777a2006-04-05 07:18:00 +00003150 pthread_rwlock_init(&f->tree_lock, NULL);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00003151
Miklos Szeredi97c61e92001-11-07 12:09:43 +00003152 root = (struct node *) calloc(1, sizeof(struct node));
Miklos Szeredie56818b2004-12-12 11:45:24 +00003153 if (root == NULL) {
3154 fprintf(stderr, "fuse: memory allocation failed\n");
Miklos Szeredia13d9002004-11-02 17:32:03 +00003155 goto out_free_id_table;
Miklos Szeredie56818b2004-12-12 11:45:24 +00003156 }
Miklos Szeredib2cf9562004-09-16 08:42:40 +00003157
Miklos Szeredi97c61e92001-11-07 12:09:43 +00003158 root->name = strdup("/");
Miklos Szeredie56818b2004-12-12 11:45:24 +00003159 if (root->name == NULL) {
3160 fprintf(stderr, "fuse: memory allocation failed\n");
Miklos Szeredib2cf9562004-09-16 08:42:40 +00003161 goto out_free_root;
Miklos Szeredie56818b2004-12-12 11:45:24 +00003162 }
Miklos Szeredib2cf9562004-09-16 08:42:40 +00003163
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00003164 if (f->conf.intr &&
3165 fuse_init_intr_signal(f->conf.intr_signal, &f->intr_installed) == -1)
3166 goto out_free_root_name;
3167
Miklos Szeredi97c61e92001-11-07 12:09:43 +00003168 root->parent = 0;
Miklos Szeredia13d9002004-11-02 17:32:03 +00003169 root->nodeid = FUSE_ROOT_ID;
Miklos Szeredi76f65782004-02-19 16:55:40 +00003170 root->generation = 0;
Miklos Szeredi0f62d722005-01-04 12:45:54 +00003171 root->refctr = 1;
Miklos Szeredi38009022005-05-08 19:47:22 +00003172 root->nlookup = 1;
Miklos Szeredia13d9002004-11-02 17:32:03 +00003173 hash_id(f, root);
Miklos Szeredi97c61e92001-11-07 12:09:43 +00003174
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00003175 return f;
Miklos Szeredib2cf9562004-09-16 08:42:40 +00003176
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00003177 out_free_root_name:
3178 free(root->name);
Miklos Szeredib2cf9562004-09-16 08:42:40 +00003179 out_free_root:
3180 free(root);
Miklos Szeredia13d9002004-11-02 17:32:03 +00003181 out_free_id_table:
3182 free(f->id_table);
Miklos Szeredib2cf9562004-09-16 08:42:40 +00003183 out_free_name_table:
3184 free(f->name_table);
Miklos Szeredia1482422005-08-14 23:00:27 +00003185 out_free_session:
3186 fuse_session_destroy(f->se);
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00003187 out_free_fs:
3188 /* Horrible compatibility hack to stop the destructor from being
3189 called on the filesystem without init being called first */
3190 fs->op.destroy = NULL;
3191 fuse_fs_destroy(f->fs);
Miklos Szeredib2cf9562004-09-16 08:42:40 +00003192 out_free:
3193 free(f);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00003194 out_delete_context_key:
3195 fuse_delete_context_key();
Miklos Szeredib2cf9562004-09-16 08:42:40 +00003196 out:
Miklos Szeredib2cf9562004-09-16 08:42:40 +00003197 return NULL;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00003198}
3199
Miklos Szeredi6f385412006-03-17 15:05:40 +00003200struct fuse *fuse_new(struct fuse_chan *ch, struct fuse_args *args,
3201 const struct fuse_operations *op, size_t op_size,
3202 void *user_data)
Miklos Szeredi0b6a0ad2004-12-04 00:40:50 +00003203{
Miklos Szeredi6f385412006-03-17 15:05:40 +00003204 return fuse_new_common(ch, args, op, op_size, user_data, 0);
Miklos Szeredi0b6a0ad2004-12-04 00:40:50 +00003205}
3206
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00003207void fuse_destroy(struct fuse *f)
3208{
Miklos Szeredi97c61e92001-11-07 12:09:43 +00003209 size_t i;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00003210
3211 if (f->conf.intr && f->intr_installed)
3212 fuse_restore_intr_signal(f->conf.intr_signal);
Miklos Szerediad519562006-07-31 11:07:40 +00003213
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00003214 if (f->fs) {
3215 struct fuse_context_i *c = fuse_get_context_internal();
Miklos Szerediad519562006-07-31 11:07:40 +00003216
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00003217 memset(c, 0, sizeof(*c));
3218 c->ctx.fuse = f;
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00003219
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00003220 for (i = 0; i < f->id_table_size; i++) {
3221 struct node *node;
3222
3223 for (node = f->id_table[i]; node != NULL; node = node->id_next) {
3224 if (node->is_hidden) {
3225 char *path = get_path(f, node->nodeid);
3226 if (path) {
3227 fuse_fs_unlink(f->fs, path);
3228 free(path);
3229 }
Miklos Szeredi21019c92005-05-09 11:22:41 +00003230 }
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00003231 }
3232 }
3233 }
Miklos Szeredia13d9002004-11-02 17:32:03 +00003234 for (i = 0; i < f->id_table_size; i++) {
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00003235 struct node *node;
Miklos Szeredi97c61e92001-11-07 12:09:43 +00003236 struct node *next;
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00003237
Miklos Szeredia13d9002004-11-02 17:32:03 +00003238 for (node = f->id_table[i]; node != NULL; node = next) {
3239 next = node->id_next;
Miklos Szeredi97c61e92001-11-07 12:09:43 +00003240 free_node(node);
3241 }
3242 }
Miklos Szeredia13d9002004-11-02 17:32:03 +00003243 free(f->id_table);
Miklos Szeredi97c61e92001-11-07 12:09:43 +00003244 free(f->name_table);
Miklos Szeredia181e612001-11-06 12:03:23 +00003245 pthread_mutex_destroy(&f->lock);
Miklos Szeredi55a84102006-06-06 10:16:38 +00003246 pthread_rwlock_destroy(&f->tree_lock);
Miklos Szeredia1482422005-08-14 23:00:27 +00003247 fuse_session_destroy(f->se);
Miklos Szeredi97c61e92001-11-07 12:09:43 +00003248 free(f);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00003249 fuse_delete_context_key();
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00003250}
Miklos Szeredi0b6a0ad2004-12-04 00:40:50 +00003251
Miklos Szeredi6f385412006-03-17 15:05:40 +00003252static struct fuse *fuse_new_common_compat25(int fd, struct fuse_args *args,
3253 const struct fuse_operations *op,
3254 size_t op_size, int compat)
3255{
3256 struct fuse *f = NULL;
3257 struct fuse_chan *ch = fuse_kern_chan_new(fd);
3258
3259 if (ch)
3260 f = fuse_new_common(ch, args, op, op_size, NULL, compat);
3261
3262 return f;
3263}
3264
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00003265/* called with fuse_context_lock held or during initialization (before
3266 main() has been called) */
3267void fuse_register_module(struct fuse_module *mod)
3268{
3269 mod->so = fuse_current_so;
3270 if (mod->so)
3271 mod->so->ctr++;
3272 mod->next = fuse_modules;
3273 fuse_modules = mod;
3274}
3275
Miklos Szeredi065f2222006-01-20 15:15:21 +00003276#ifndef __FreeBSD__
3277
Miklos Szeredi95da8602006-01-06 18:29:40 +00003278static struct fuse *fuse_new_common_compat(int fd, const char *opts,
3279 const struct fuse_operations *op,
3280 size_t op_size, int compat)
3281{
3282 struct fuse *f;
3283 struct fuse_args args = FUSE_ARGS_INIT(0, NULL);
3284
Miklos Szeredi6e7d0182007-01-19 22:11:40 +00003285 if (fuse_opt_add_arg(&args, "") == -1)
3286 return NULL;
Miklos Szeredi95da8602006-01-06 18:29:40 +00003287 if (opts &&
Miklos Szeredi6e7d0182007-01-19 22:11:40 +00003288 (fuse_opt_add_arg(&args, "-o") == -1 ||
Miklos Szeredi95da8602006-01-06 18:29:40 +00003289 fuse_opt_add_arg(&args, opts) == -1)) {
3290 fuse_opt_free_args(&args);
3291 return NULL;
3292 }
Miklos Szeredi6f385412006-03-17 15:05:40 +00003293 f = fuse_new_common_compat25(fd, &args, op, op_size, compat);
Miklos Szeredi95da8602006-01-06 18:29:40 +00003294 fuse_opt_free_args(&args);
3295
3296 return f;
3297}
3298
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00003299struct fuse *fuse_new_compat22(int fd, const char *opts,
3300 const struct fuse_operations_compat22 *op,
3301 size_t op_size)
3302{
Miklos Szeredi95da8602006-01-06 18:29:40 +00003303 return fuse_new_common_compat(fd, opts, (struct fuse_operations *) op,
3304 op_size, 22);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00003305}
3306
3307struct fuse *fuse_new_compat2(int fd, const char *opts,
3308 const struct fuse_operations_compat2 *op)
3309{
Miklos Szeredi95da8602006-01-06 18:29:40 +00003310 return fuse_new_common_compat(fd, opts, (struct fuse_operations *) op,
3311 sizeof(struct fuse_operations_compat2), 21);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00003312}
3313
3314struct fuse *fuse_new_compat1(int fd, int flags,
3315 const struct fuse_operations_compat1 *op)
3316{
3317 const char *opts = NULL;
3318 if (flags & FUSE_DEBUG_COMPAT1)
3319 opts = "debug";
Miklos Szeredi95da8602006-01-06 18:29:40 +00003320 return fuse_new_common_compat(fd, opts, (struct fuse_operations *) op,
3321 sizeof(struct fuse_operations_compat1), 11);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00003322}
3323
Miklos Szeredif458b8c2004-12-07 16:46:42 +00003324__asm__(".symver fuse_exited,__fuse_exited@");
3325__asm__(".symver fuse_process_cmd,__fuse_process_cmd@");
3326__asm__(".symver fuse_read_cmd,__fuse_read_cmd@");
3327__asm__(".symver fuse_set_getcontext_func,__fuse_set_getcontext_func@");
3328__asm__(".symver fuse_new_compat2,fuse_new@");
Miklos Szeredi3a770472005-11-11 21:32:42 +00003329__asm__(".symver fuse_new_compat22,fuse_new@FUSE_2.2");
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00003330
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00003331#endif /* __FreeBSD__ */
Miklos Szeredi065f2222006-01-20 15:15:21 +00003332
3333struct fuse *fuse_new_compat25(int fd, struct fuse_args *args,
3334 const struct fuse_operations_compat25 *op,
3335 size_t op_size)
3336{
Miklos Szeredi6f385412006-03-17 15:05:40 +00003337 return fuse_new_common_compat25(fd, args, (struct fuse_operations *) op,
3338 op_size, 25);
Miklos Szeredi065f2222006-01-20 15:15:21 +00003339}
3340
3341__asm__(".symver fuse_new_compat25,fuse_new@FUSE_2.5");