blob: ce5d9af26e8bc085da986b8bdfd01cf507d0de7c [file] [log] [blame]
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001/*
2 FUSE: Filesystem in Userspace
Miklos Szeredi611ad932007-04-25 16:19:15 +00003 Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00004
Miklos Szeredi8b39a9f2002-10-25 12:41:16 +00005 This program can be distributed under the terms of the GNU LGPL.
6 See the file COPYING.LIB
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00007*/
8
Miklos Szeredie2aa2e22005-07-15 13:31:36 +00009
10/* For pthread_rwlock_t */
11#define _GNU_SOURCE
12
Miklos Szeredi178451d2005-08-15 13:19:07 +000013#include "fuse_i.h"
Miklos Szeredie2aa2e22005-07-15 13:31:36 +000014#include "fuse_lowlevel.h"
Miklos Szeredi659743b2005-12-09 17:41:42 +000015#include "fuse_opt.h"
Miklos Szeredi38f152c2006-09-03 18:28:52 +000016#include "fuse_misc.h"
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +000017#include "fuse_common_compat.h"
18#include "fuse_compat.h"
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000019
Miklos Szeredi0f62d722005-01-04 12:45:54 +000020#include <stdio.h>
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000021#include <string.h>
Miklos Szeredi97c61e92001-11-07 12:09:43 +000022#include <stdlib.h>
Miklos Szeredi659743b2005-12-09 17:41:42 +000023#include <stddef.h>
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000024#include <unistd.h>
Miklos Szeredi320abe42006-01-30 18:14:51 +000025#include <time.h>
Miklos Szeredib3f99722005-11-16 13:00:24 +000026#include <fcntl.h>
Miklos Szeredi97c61e92001-11-07 12:09:43 +000027#include <limits.h>
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000028#include <errno.h>
Miklos Szeredi288ed4e2006-09-07 06:02:44 +000029#include <signal.h>
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +000030#include <dlfcn.h>
Miklos Szeredi0f62d722005-01-04 12:45:54 +000031#include <assert.h>
Miklos Szeredi019b4e92001-12-26 18:08:09 +000032#include <sys/param.h>
Miklos Szerediab974562005-04-07 15:40:21 +000033#include <sys/uio.h>
Miklos Szeredi288ed4e2006-09-07 06:02:44 +000034#include <sys/time.h>
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000035
Miklos Szeredi97c61e92001-11-07 12:09:43 +000036#define FUSE_MAX_PATH 4096
Miklos Szeredi288ed4e2006-09-07 06:02:44 +000037#define FUSE_DEFAULT_INTR_SIGNAL SIGUSR1
Miklos Szeredi30e093a2005-04-03 17:44:54 +000038
Miklos Szeredie248e4b2005-12-14 16:18:32 +000039#define FUSE_UNKNOWN_INO 0xffffffff
Miklos Szeredi0c59ebf2006-09-10 20:53:36 +000040#define OFFSET_MAX 0x7fffffffffffffffLL
Miklos Szeredie248e4b2005-12-14 16:18:32 +000041
Miklos Szeredi659743b2005-12-09 17:41:42 +000042struct fuse_config {
Miklos Szeredi659743b2005-12-09 17:41:42 +000043 unsigned int uid;
44 unsigned int gid;
45 unsigned int umask;
46 double entry_timeout;
47 double negative_timeout;
48 double attr_timeout;
Miklos Szeredi6e806e92006-02-16 16:59:39 +000049 double ac_attr_timeout;
50 int ac_attr_timeout_set;
Miklos Szeredi659743b2005-12-09 17:41:42 +000051 int debug;
52 int hard_remove;
53 int use_ino;
54 int readdir_ino;
55 int set_mode;
56 int set_uid;
57 int set_gid;
58 int direct_io;
59 int kernel_cache;
Miklos Szeredi320abe42006-01-30 18:14:51 +000060 int auto_cache;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +000061 int intr;
62 int intr_signal;
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +000063 int help;
64 char *modules;
65};
66
67struct fuse_fs {
68 struct fuse_operations op;
69 struct fuse_module *m;
70 void *user_data;
71 int compat;
72};
73
74struct fusemod_so {
75 void *handle;
76 int ctr;
Miklos Szeredi659743b2005-12-09 17:41:42 +000077};
78
Miklos Szeredie2aa2e22005-07-15 13:31:36 +000079struct fuse {
Miklos Szeredia1482422005-08-14 23:00:27 +000080 struct fuse_session *se;
Miklos Szeredie2aa2e22005-07-15 13:31:36 +000081 struct node **name_table;
82 size_t name_table_size;
83 struct node **id_table;
84 size_t id_table_size;
85 fuse_ino_t ctr;
86 unsigned int generation;
87 unsigned int hidectr;
88 pthread_mutex_t lock;
89 pthread_rwlock_t tree_lock;
Miklos Szeredi659743b2005-12-09 17:41:42 +000090 struct fuse_config conf;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +000091 int intr_installed;
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +000092 struct fuse_fs *fs;
Miklos Szeredie2aa2e22005-07-15 13:31:36 +000093};
94
Miklos Szeredi0c59ebf2006-09-10 20:53:36 +000095struct lock {
96 int type;
97 off_t start;
98 off_t end;
99 pid_t pid;
100 uint64_t owner;
101 struct lock *next;
102};
103
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000104struct node {
105 struct node *name_next;
106 struct node *id_next;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000107 fuse_ino_t nodeid;
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000108 unsigned int generation;
109 int refctr;
Miklos 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
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +0000780int fuse_fs_unlink(struct fuse_fs *fs, const char *path)
781{
782 fuse_get_context()->private_data = fs->user_data;
783 if (fs->op.unlink)
784 return fs->op.unlink(path);
785 else
786 return -ENOSYS;
787}
788
789int fuse_fs_rmdir(struct fuse_fs *fs, const char *path)
790{
791 fuse_get_context()->private_data = fs->user_data;
792 if (fs->op.rmdir)
793 return fs->op.rmdir(path);
794 else
795 return -ENOSYS;
796}
797
798int fuse_fs_symlink(struct fuse_fs *fs, const char *linkname, const char *path)
799{
800 fuse_get_context()->private_data = fs->user_data;
801 if (fs->op.symlink)
802 return fs->op.symlink(linkname, path);
803 else
804 return -ENOSYS;
805}
806
807int fuse_fs_link(struct fuse_fs *fs, const char *oldpath, const char *newpath)
808{
809 fuse_get_context()->private_data = fs->user_data;
810 if (fs->op.link)
811 return fs->op.link(oldpath, newpath);
812 else
813 return -ENOSYS;
814}
815
816int fuse_fs_release(struct fuse_fs *fs, const char *path,
817 struct fuse_file_info *fi)
818{
819 fuse_get_context()->private_data = fs->user_data;
820 if (fs->op.release)
821 return fuse_compat_release(fs, path, fi);
822 else
823 return 0;
824}
825
826int fuse_fs_opendir(struct fuse_fs *fs, const char *path,
827 struct fuse_file_info *fi)
828{
829 fuse_get_context()->private_data = fs->user_data;
830 if (fs->op.opendir)
831 return fuse_compat_opendir(fs, path, fi);
832 else
833 return 0;
834}
835
836int fuse_fs_open(struct fuse_fs *fs, const char *path,
837 struct fuse_file_info *fi)
838{
839 fuse_get_context()->private_data = fs->user_data;
840 if (fs->op.open)
841 return fuse_compat_open(fs, path, fi);
842 else
843 return 0;
844}
845
846int fuse_fs_read(struct fuse_fs *fs, const char *path, char *buf, size_t size,
847 off_t off, struct fuse_file_info *fi)
848{
849 fuse_get_context()->private_data = fs->user_data;
850 if (fs->op.read)
851 return fs->op.read(path, buf, size, off, fi);
852 else
853 return -ENOSYS;
854}
855
856int fuse_fs_write(struct fuse_fs *fs, const char *path, const char *buf,
857 size_t size, off_t off, struct fuse_file_info *fi)
858{
859 fuse_get_context()->private_data = fs->user_data;
860 if (fs->op.write)
861 return fs->op.write(path, buf, size, off, fi);
862 else
863 return -ENOSYS;
864}
865
866int fuse_fs_fsync(struct fuse_fs *fs, const char *path, int datasync,
867 struct fuse_file_info *fi)
868{
869 fuse_get_context()->private_data = fs->user_data;
870 if (fs->op.fsync)
871 return fs->op.fsync(path, datasync, fi);
872 else
873 return -ENOSYS;
874}
875
876int fuse_fs_fsyncdir(struct fuse_fs *fs, const char *path, int datasync,
877 struct fuse_file_info *fi)
878{
879 fuse_get_context()->private_data = fs->user_data;
880 if (fs->op.fsyncdir)
881 return fs->op.fsyncdir(path, datasync, fi);
882 else
883 return -ENOSYS;
884}
885
886int fuse_fs_flush(struct fuse_fs *fs, const char *path,
887 struct fuse_file_info *fi)
888{
889 fuse_get_context()->private_data = fs->user_data;
890 if (fs->op.flush)
891 return fs->op.flush(path, fi);
892 else
893 return -ENOSYS;
894}
895
896int fuse_fs_statfs(struct fuse_fs *fs, const char *path, struct statvfs *buf)
897{
898 fuse_get_context()->private_data = fs->user_data;
899 if (fs->op.statfs)
900 return fuse_compat_statfs(fs, path, buf);
901 else {
902 buf->f_namemax = 255;
903 buf->f_bsize = 512;
904 return 0;
905 }
906}
907
908int fuse_fs_releasedir(struct fuse_fs *fs, const char *path,
909 struct fuse_file_info *fi)
910{
911 fuse_get_context()->private_data = fs->user_data;
912 if (fs->op.releasedir)
913 return fs->op.releasedir(path, fi);
914 else
915 return 0;
916}
917
918static int fill_dir_old(struct fuse_dirhandle *dh, const char *name, int type,
919 ino_t ino)
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000920{
921 int res;
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +0000922 struct stat stbuf;
923
924 memset(&stbuf, 0, sizeof(stbuf));
925 stbuf.st_mode = type << 12;
926 stbuf.st_ino = ino;
927
928 res = dh->filler(dh->buf, name, &stbuf, 0);
929 return res ? -ENOMEM : 0;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000930}
931
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +0000932int fuse_fs_readdir(struct fuse_fs *fs, const char *path, void *buf,
933 fuse_fill_dir_t filler, off_t off,
934 struct fuse_file_info *fi)
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000935{
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +0000936 fuse_get_context()->private_data = fs->user_data;
937 if (fs->op.readdir)
938 return fs->op.readdir(path, buf, filler, off, fi);
939 else if (fs->op.getdir) {
940 struct fuse_dirhandle dh;
941 dh.filler = filler;
942 dh.buf = buf;
943 return fs->op.getdir(path, &dh, fill_dir_old);
944 } else
945 return -ENOSYS;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000946}
947
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +0000948int fuse_fs_create(struct fuse_fs *fs, const char *path, mode_t mode,
949 struct fuse_file_info *fi)
Miklos Szeredi4fca4322006-10-01 14:41:04 +0000950{
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +0000951 fuse_get_context()->private_data = fs->user_data;
952 if (fs->op.create)
953 return fs->op.create(path, mode, fi);
954 else
955 return -ENOSYS;
Miklos Szeredi4fca4322006-10-01 14:41:04 +0000956}
957
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +0000958int fuse_fs_lock(struct fuse_fs *fs, const char *path,
959 struct fuse_file_info *fi, int cmd, struct flock *lock)
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000960{
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +0000961 fuse_get_context()->private_data = fs->user_data;
962 if (fs->op.lock)
963 return fs->op.lock(path, fi, cmd, lock);
964 else
965 return -ENOSYS;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000966}
967
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +0000968int fuse_fs_chown(struct fuse_fs *fs, const char *path, uid_t uid, gid_t gid)
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000969{
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +0000970 fuse_get_context()->private_data = fs->user_data;
971 if (fs->op.chown)
972 return fs->op.chown(path, uid, gid);
973 else
974 return -ENOSYS;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000975}
976
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +0000977int fuse_fs_truncate(struct fuse_fs *fs, const char *path, off_t size)
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000978{
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +0000979 fuse_get_context()->private_data = fs->user_data;
980 if (fs->op.truncate)
981 return fs->op.truncate(path, size);
982 else
983 return -ENOSYS;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000984}
985
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +0000986int fuse_fs_ftruncate(struct fuse_fs *fs, const char *path, off_t size,
987 struct fuse_file_info *fi)
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000988{
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +0000989 fuse_get_context()->private_data = fs->user_data;
990 if (fs->op.ftruncate)
991 return fs->op.ftruncate(path, size, fi);
992 else if (fs->op.truncate)
993 return fs->op.truncate(path, size);
994 else
995 return -ENOSYS;
996}
997
998int fuse_fs_utimens(struct fuse_fs *fs, const char *path,
999 const struct timespec tv[2])
1000{
1001 fuse_get_context()->private_data = fs->user_data;
1002 if (fs->op.utimens)
1003 return fs->op.utimens(path, tv);
1004 else if(fs->op.utime) {
1005 struct utimbuf buf;
1006 buf.actime = tv[0].tv_sec;
1007 buf.modtime = tv[1].tv_sec;
1008 return fs->op.utime(path, &buf);
1009 } else
1010 return -ENOSYS;
1011}
1012
1013int fuse_fs_access(struct fuse_fs *fs, const char *path, int mask)
1014{
1015 fuse_get_context()->private_data = fs->user_data;
1016 if (fs->op.access)
1017 return fs->op.access(path, mask);
1018 else
1019 return -ENOSYS;
1020}
1021
1022int fuse_fs_readlink(struct fuse_fs *fs, const char *path, char *buf,
1023 size_t len)
1024{
1025 fuse_get_context()->private_data = fs->user_data;
1026 if (fs->op.readlink)
1027 return fs->op.readlink(path, buf, len);
1028 else
1029 return -ENOSYS;
1030}
1031
1032int fuse_fs_mknod(struct fuse_fs *fs, const char *path, mode_t mode,
1033 dev_t rdev)
1034{
1035 fuse_get_context()->private_data = fs->user_data;
1036 if (fs->op.mknod)
1037 return fs->op.mknod(path, mode, rdev);
1038 else
1039 return -ENOSYS;
1040}
1041
1042int fuse_fs_mkdir(struct fuse_fs *fs, const char *path, mode_t mode)
1043{
1044 fuse_get_context()->private_data = fs->user_data;
1045 if (fs->op.mkdir)
1046 return fs->op.mkdir(path, mode);
1047 else
1048 return -ENOSYS;
1049}
1050
1051int fuse_fs_setxattr(struct fuse_fs *fs, const char *path, const char *name,
1052 const char *value, size_t size, int flags)
1053{
1054 fuse_get_context()->private_data = fs->user_data;
1055 if (fs->op.setxattr)
1056 return fs->op.setxattr(path, name, value, size, flags);
1057 else
1058 return -ENOSYS;
1059}
1060
1061int fuse_fs_getxattr(struct fuse_fs *fs, const char *path, const char *name,
1062 char *value, size_t size)
1063{
1064 fuse_get_context()->private_data = fs->user_data;
1065 if (fs->op.getxattr)
1066 return fs->op.getxattr(path, name, value, size);
1067 else
1068 return -ENOSYS;
1069}
1070
1071int fuse_fs_listxattr(struct fuse_fs *fs, const char *path, char *list,
1072 size_t size)
1073{
1074 fuse_get_context()->private_data = fs->user_data;
1075 if (fs->op.listxattr)
1076 return fs->op.listxattr(path, list, size);
1077 else
1078 return -ENOSYS;
1079}
1080
1081int fuse_fs_bmap(struct fuse_fs *fs, const char *path, size_t blocksize,
1082 uint64_t *idx)
1083{
1084 fuse_get_context()->private_data = fs->user_data;
1085 if (fs->op.bmap)
1086 return fs->op.bmap(path, blocksize, idx);
1087 else
1088 return -ENOSYS;
1089}
1090
1091int fuse_fs_removexattr(struct fuse_fs *fs, const char *path, const char *name)
1092{
1093 fuse_get_context()->private_data = fs->user_data;
1094 if (fs->op.removexattr)
1095 return fs->op.removexattr(path, name);
1096 else
1097 return -ENOSYS;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001098}
1099
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001100static int is_open(struct fuse *f, fuse_ino_t dir, const char *name)
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001101{
1102 struct node *node;
1103 int isopen = 0;
1104 pthread_mutex_lock(&f->lock);
Miklos Szeredif458b8c2004-12-07 16:46:42 +00001105 node = lookup_node(f, dir, name);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001106 if (node && node->open_count > 0)
1107 isopen = 1;
1108 pthread_mutex_unlock(&f->lock);
1109 return isopen;
1110}
1111
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001112static char *hidden_name(struct fuse *f, fuse_ino_t dir, const char *oldname,
1113 char *newname, size_t bufsize)
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001114{
1115 struct stat buf;
1116 struct node *node;
1117 struct node *newnode;
1118 char *newpath;
1119 int res;
1120 int failctr = 10;
1121
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001122 do {
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001123 pthread_mutex_lock(&f->lock);
Miklos Szeredif458b8c2004-12-07 16:46:42 +00001124 node = lookup_node(f, dir, oldname);
1125 if (node == NULL) {
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001126 pthread_mutex_unlock(&f->lock);
1127 return NULL;
Miklos Szeredif458b8c2004-12-07 16:46:42 +00001128 }
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001129 do {
1130 f->hidectr ++;
1131 snprintf(newname, bufsize, ".fuse_hidden%08x%08x",
Miklos Szeredia13d9002004-11-02 17:32:03 +00001132 (unsigned int) node->nodeid, f->hidectr);
Miklos Szeredif458b8c2004-12-07 16:46:42 +00001133 newnode = lookup_node(f, dir, newname);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001134 } while(newnode);
1135 pthread_mutex_unlock(&f->lock);
Miklos Szeredie5183742005-02-02 11:14:04 +00001136
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001137 newpath = get_path_name(f, dir, newname);
1138 if (!newpath)
1139 break;
Miklos Szeredie5183742005-02-02 11:14:04 +00001140
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001141 res = fuse_fs_getattr(f->fs, newpath, &buf);
1142 if (res == -ENOENT)
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001143 break;
1144 free(newpath);
1145 newpath = NULL;
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001146 } while(res == 0 && --failctr);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001147
1148 return newpath;
1149}
1150
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001151static int hide_node(struct fuse *f, const char *oldpath,
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001152 fuse_ino_t dir, const char *oldname)
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001153{
1154 char newname[64];
1155 char *newpath;
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001156 int err = -EBUSY;
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001157
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001158 newpath = hidden_name(f, dir, oldname, newname, sizeof(newname));
1159 if (newpath) {
1160 err = fuse_fs_rename(f->fs, oldpath, newpath);
1161 if (!err)
1162 err = rename_node(f, dir, oldname, dir, newname, 1);
1163 free(newpath);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001164 }
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001165 return err;
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001166}
1167
Miklos Szeredi320abe42006-01-30 18:14:51 +00001168static int mtime_eq(const struct stat *stbuf, const struct timespec *ts)
1169{
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001170 return stbuf->st_mtime == ts->tv_sec && ST_MTIM_NSEC(stbuf) == ts->tv_nsec;
Miklos Szeredi320abe42006-01-30 18:14:51 +00001171}
1172
Miklos Szeredi2512aaa2006-05-03 14:54:59 +00001173#ifndef CLOCK_MONOTONIC
1174#define CLOCK_MONOTONIC CLOCK_REALTIME
1175#endif
1176
Miklos Szeredi320abe42006-01-30 18:14:51 +00001177static void curr_time(struct timespec *now)
1178{
1179 static clockid_t clockid = CLOCK_MONOTONIC;
1180 int res = clock_gettime(clockid, now);
1181 if (res == -1 && errno == EINVAL) {
1182 clockid = CLOCK_REALTIME;
1183 res = clock_gettime(clockid, now);
1184 }
1185 if (res == -1) {
1186 perror("fuse: clock_gettime");
1187 abort();
1188 }
1189}
1190
1191static void update_stat(struct node *node, const struct stat *stbuf)
1192{
1193 if (node->cache_valid && (!mtime_eq(stbuf, &node->mtime) ||
1194 stbuf->st_size != node->size))
1195 node->cache_valid = 0;
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001196 node->mtime.tv_sec = stbuf->st_mtime;
1197 node->mtime.tv_nsec = ST_MTIM_NSEC(stbuf);
Miklos Szeredi320abe42006-01-30 18:14:51 +00001198 node->size = stbuf->st_size;
1199 curr_time(&node->stat_updated);
1200}
1201
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001202static int lookup_path(struct fuse *f, fuse_ino_t nodeid,
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001203 const char *name, const char *path,
1204 struct fuse_entry_param *e, struct fuse_file_info *fi)
Miklos Szeredi76f65782004-02-19 16:55:40 +00001205{
1206 int res;
Miklos Szeredi76f65782004-02-19 16:55:40 +00001207
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001208 memset(e, 0, sizeof(struct fuse_entry_param));
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001209 if (fi)
1210 res = fuse_fs_fgetattr(f->fs, path, &e->attr, fi);
Miklos Szeredif7eec032005-10-28 13:09:50 +00001211 else
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001212 res = fuse_fs_getattr(f->fs, path, &e->attr);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001213 if (res == 0) {
Miklos Szeredi76f65782004-02-19 16:55:40 +00001214 struct node *node;
1215
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001216 node = find_node(f, nodeid, name);
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001217 if (node == NULL)
1218 res = -ENOMEM;
1219 else {
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001220 e->ino = node->nodeid;
1221 e->generation = node->generation;
Miklos Szeredi659743b2005-12-09 17:41:42 +00001222 e->entry_timeout = f->conf.entry_timeout;
1223 e->attr_timeout = f->conf.attr_timeout;
Miklos Szeredi320abe42006-01-30 18:14:51 +00001224 if (f->conf.auto_cache) {
1225 pthread_mutex_lock(&f->lock);
1226 update_stat(node, &e->attr);
1227 pthread_mutex_unlock(&f->lock);
1228 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001229 set_stat(f, e->ino, &e->attr);
Miklos Szeredi659743b2005-12-09 17:41:42 +00001230 if (f->conf.debug) {
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001231 printf(" NODEID: %lu\n", (unsigned long) e->ino);
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001232 fflush(stdout);
1233 }
Miklos Szeredi76f65782004-02-19 16:55:40 +00001234 }
1235 }
1236 return res;
1237}
1238
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001239static struct fuse_context_i *fuse_get_context_internal(void)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001240{
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001241 struct fuse_context_i *c;
1242
1243 c = (struct fuse_context_i *) pthread_getspecific(fuse_context_key);
1244 if (c == NULL) {
1245 c = (struct fuse_context_i *) malloc(sizeof(struct fuse_context_i));
1246 if (c == NULL) {
1247 /* This is hard to deal with properly, so just abort. If
1248 memory is so low that the context cannot be allocated,
1249 there's not much hope for the filesystem anyway */
1250 fprintf(stderr, "fuse: failed to allocate thread specific data\n");
1251 abort();
1252 }
1253 pthread_setspecific(fuse_context_key, c);
1254 }
1255 return c;
1256}
1257
1258static void fuse_freecontext(void *data)
1259{
1260 free(data);
1261}
1262
1263static int fuse_create_context_key(void)
1264{
1265 int err = 0;
1266 pthread_mutex_lock(&fuse_context_lock);
1267 if (!fuse_context_ref) {
1268 err = pthread_key_create(&fuse_context_key, fuse_freecontext);
1269 if (err) {
1270 fprintf(stderr, "fuse: failed to create thread specific key: %s\n",
1271 strerror(err));
1272 pthread_mutex_unlock(&fuse_context_lock);
1273 return -1;
1274 }
1275 }
1276 fuse_context_ref++;
1277 pthread_mutex_unlock(&fuse_context_lock);
1278 return 0;
1279}
1280
1281static void fuse_delete_context_key(void)
1282{
1283 pthread_mutex_lock(&fuse_context_lock);
1284 fuse_context_ref--;
1285 if (!fuse_context_ref) {
1286 free(pthread_getspecific(fuse_context_key));
1287 pthread_key_delete(fuse_context_key);
1288 }
1289 pthread_mutex_unlock(&fuse_context_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001290}
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001291
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001292static struct fuse *req_fuse_prepare(fuse_req_t req)
1293{
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001294 struct fuse_context_i *c = fuse_get_context_internal();
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001295 const struct fuse_ctx *ctx = fuse_req_ctx(req);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001296 c->req = req;
1297 c->ctx.fuse = req_fuse(req);
1298 c->ctx.uid = ctx->uid;
1299 c->ctx.gid = ctx->gid;
1300 c->ctx.pid = ctx->pid;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001301 return c->ctx.fuse;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001302}
1303
1304static inline void reply_err(fuse_req_t req, int err)
1305{
1306 /* fuse_reply_err() uses non-negated errno values */
1307 fuse_reply_err(req, -err);
1308}
1309
1310static void reply_entry(fuse_req_t req, const struct fuse_entry_param *e,
1311 int err)
1312{
1313 if (!err) {
Miklos Szeredib67f2162006-02-20 10:55:33 +00001314 struct fuse *f = req_fuse(req);
Miklos Szeredi9b813af2005-07-21 07:59:37 +00001315 if (fuse_reply_entry(req, e) == -ENOENT)
Miklos Szeredib67f2162006-02-20 10:55:33 +00001316 forget_node(f, e->ino, 1);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001317 } else
1318 reply_err(req, err);
1319}
1320
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001321void fuse_fs_init(struct fuse_fs *fs, struct fuse_conn_info *conn)
1322{
1323 fuse_get_context()->private_data = fs->user_data;
1324 if (fs->op.init)
1325 fs->user_data = fs->op.init(conn);
1326}
1327
1328static void fuse_lib_init(void *data, struct fuse_conn_info *conn)
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001329{
1330 struct fuse *f = (struct fuse *) data;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001331 struct fuse_context_i *c = fuse_get_context_internal();
Miklos Szeredi4f5df5e2005-10-07 12:39:58 +00001332
1333 memset(c, 0, sizeof(*c));
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001334 c->ctx.fuse = f;
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001335 fuse_fs_init(f->fs, conn);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001336}
1337
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001338void fuse_fs_destroy(struct fuse_fs *fs)
1339{
1340 fuse_get_context()->private_data = fs->user_data;
1341 if (fs->op.destroy)
1342 fs->op.destroy(fs->user_data);
1343 if (fs->m)
1344 fuse_put_module(fs->m);
1345 free(fs);
1346}
1347
1348static void fuse_lib_destroy(void *data)
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001349{
1350 struct fuse *f = (struct fuse *) data;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001351 struct fuse_context_i *c = fuse_get_context_internal();
Miklos Szeredi4f5df5e2005-10-07 12:39:58 +00001352
1353 memset(c, 0, sizeof(*c));
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001354 c->ctx.fuse = f;
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001355 fuse_fs_destroy(f->fs);
1356 f->fs = NULL;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001357}
1358
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001359static void fuse_lib_lookup(fuse_req_t req, fuse_ino_t parent,
1360 const char *name)
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001361{
1362 struct fuse *f = req_fuse_prepare(req);
1363 struct fuse_entry_param e;
1364 char *path;
1365 int err;
1366
1367 err = -ENOENT;
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001368 pthread_rwlock_rdlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001369 path = get_path_name(f, parent, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001370 if (path != NULL) {
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001371 struct fuse_intr_data d;
Miklos Szeredi659743b2005-12-09 17:41:42 +00001372 if (f->conf.debug) {
Miklos Szeredi6ebe2342002-01-06 21:44:16 +00001373 printf("LOOKUP %s\n", path);
1374 fflush(stdout);
1375 }
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001376 fuse_prepare_interrupt(f, req, &d);
1377 err = lookup_path(f, parent, name, path, &e, NULL);
1378 if (err == -ENOENT && f->conf.negative_timeout != 0.0) {
1379 e.ino = 0;
1380 e.entry_timeout = f->conf.negative_timeout;
1381 err = 0;
Miklos Szeredi2b478112005-11-28 13:27:10 +00001382 }
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001383 fuse_finish_interrupt(f, req, &d);
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001384 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001385 }
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001386 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001387 reply_entry(req, &e, err);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001388}
1389
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001390static void fuse_lib_forget(fuse_req_t req, fuse_ino_t ino,
1391 unsigned long nlookup)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001392{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001393 struct fuse *f = req_fuse(req);
Miklos Szeredi659743b2005-12-09 17:41:42 +00001394 if (f->conf.debug) {
Miklos Szeredi3a770472005-11-11 21:32:42 +00001395 printf("FORGET %llu/%lu\n", (unsigned long long) ino, nlookup);
Miklos Szeredi43696432001-11-18 19:15:05 +00001396 fflush(stdout);
1397 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001398 forget_node(f, ino, nlookup);
1399 fuse_reply_none(req);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001400}
1401
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001402static void fuse_lib_getattr(fuse_req_t req, fuse_ino_t ino,
1403 struct fuse_file_info *fi)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001404{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001405 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredi19dff1b2001-10-30 15:06:52 +00001406 struct stat buf;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001407 char *path;
1408 int err;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001409
Miklos Szerediecce1bf2005-08-25 15:19:06 +00001410 (void) fi;
Miklos Szeredi16dbf942006-09-02 13:20:40 +00001411 memset(&buf, 0, sizeof(buf));
Miklos Szerediecce1bf2005-08-25 15:19:06 +00001412
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001413 err = -ENOENT;
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001414 pthread_rwlock_rdlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001415 path = get_path(f, ino);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001416 if (path != NULL) {
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001417 struct fuse_intr_data d;
1418 fuse_prepare_interrupt(f, req, &d);
1419 err = fuse_fs_getattr(f->fs, path, &buf);
1420 fuse_finish_interrupt(f, req, &d);
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001421 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001422 }
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001423 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001424 if (!err) {
Miklos Szeredi08dab162006-02-01 13:39:15 +00001425 if (f->conf.auto_cache) {
1426 pthread_mutex_lock(&f->lock);
1427 update_stat(get_node(f, ino), &buf);
1428 pthread_mutex_unlock(&f->lock);
1429 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001430 set_stat(f, ino, &buf);
Miklos Szeredi659743b2005-12-09 17:41:42 +00001431 fuse_reply_attr(req, &buf, f->conf.attr_timeout);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001432 } else
1433 reply_err(req, err);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001434}
1435
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001436int fuse_fs_chmod(struct fuse_fs *fs, const char *path, mode_t mode)
Miklos Szeredif3ea83b2001-11-07 14:55:16 +00001437{
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001438 if (fs->op.chmod)
1439 return fs->op.chmod(path, mode);
1440 else
1441 return -ENOSYS;
Miklos Szeredie5183742005-02-02 11:14:04 +00001442}
Miklos Szeredif3ea83b2001-11-07 14:55:16 +00001443
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001444static void fuse_lib_setattr(fuse_req_t req, fuse_ino_t ino, struct stat *attr,
1445 int valid, struct fuse_file_info *fi)
Miklos Szeredi5e183482001-10-31 14:52:35 +00001446{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001447 struct fuse *f = req_fuse_prepare(req);
1448 struct stat buf;
Miklos Szeredi5e183482001-10-31 14:52:35 +00001449 char *path;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001450 int err;
Miklos Szeredi5e183482001-10-31 14:52:35 +00001451
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001452 err = -ENOENT;
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001453 pthread_rwlock_rdlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001454 path = get_path(f, ino);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001455 if (path != NULL) {
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001456 struct fuse_intr_data d;
1457 fuse_prepare_interrupt(f, req, &d);
1458 err = 0;
1459 if (!err && (valid & FUSE_SET_ATTR_MODE))
1460 err = fuse_fs_chmod(f->fs, path, attr->st_mode);
1461 if (!err && (valid & (FUSE_SET_ATTR_UID | FUSE_SET_ATTR_GID))) {
1462 uid_t uid =
1463 (valid & FUSE_SET_ATTR_UID) ? attr->st_uid : (uid_t) -1;
1464 gid_t gid =
1465 (valid & FUSE_SET_ATTR_GID) ? attr->st_gid : (gid_t) -1;
1466 err = fuse_fs_chown(f->fs, path, uid, gid);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001467 }
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001468 if (!err && (valid & FUSE_SET_ATTR_SIZE)) {
1469 if (fi)
1470 err = fuse_fs_ftruncate(f->fs, path, attr->st_size, fi);
1471 else
1472 err = fuse_fs_truncate(f->fs, path, attr->st_size);
1473 }
1474 if (!err && (valid & (FUSE_SET_ATTR_ATIME | FUSE_SET_ATTR_MTIME)) ==
1475 (FUSE_SET_ATTR_ATIME | FUSE_SET_ATTR_MTIME)) {
1476 struct timespec tv[2];
1477 tv[0].tv_sec = attr->st_atime;
1478 tv[0].tv_nsec = ST_ATIM_NSEC(attr);
1479 tv[1].tv_sec = attr->st_mtime;
1480 tv[1].tv_nsec = ST_MTIM_NSEC(attr);
1481 err = fuse_fs_utimens(f->fs, path, tv);
1482 }
1483 if (!err)
1484 err = fuse_fs_getattr(f->fs, path, &buf);
1485 fuse_finish_interrupt(f, req, &d);
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001486 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001487 }
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001488 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001489 if (!err) {
Miklos Szeredi08dab162006-02-01 13:39:15 +00001490 if (f->conf.auto_cache) {
1491 pthread_mutex_lock(&f->lock);
1492 update_stat(get_node(f, ino), &buf);
1493 pthread_mutex_unlock(&f->lock);
1494 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001495 set_stat(f, ino, &buf);
Miklos Szeredi659743b2005-12-09 17:41:42 +00001496 fuse_reply_attr(req, &buf, f->conf.attr_timeout);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001497 } else
1498 reply_err(req, err);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001499}
1500
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001501static void fuse_lib_access(fuse_req_t req, fuse_ino_t ino, int mask)
Miklos Szeredib0b13d12005-10-26 12:53:25 +00001502{
1503 struct fuse *f = req_fuse_prepare(req);
1504 char *path;
1505 int err;
1506
1507 err = -ENOENT;
1508 pthread_rwlock_rdlock(&f->tree_lock);
1509 path = get_path(f, ino);
1510 if (path != NULL) {
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001511 struct fuse_intr_data d;
Miklos Szeredi659743b2005-12-09 17:41:42 +00001512 if (f->conf.debug) {
Miklos Szeredib0b13d12005-10-26 12:53:25 +00001513 printf("ACCESS %s 0%o\n", path, mask);
1514 fflush(stdout);
1515 }
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001516 fuse_prepare_interrupt(f, req, &d);
1517 err = fuse_fs_access(f->fs, path, mask);
1518 fuse_finish_interrupt(f, req, &d);
Miklos Szeredib0b13d12005-10-26 12:53:25 +00001519 free(path);
1520 }
1521 pthread_rwlock_unlock(&f->tree_lock);
1522 reply_err(req, err);
1523}
1524
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001525static void fuse_lib_readlink(fuse_req_t req, fuse_ino_t ino)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001526{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001527 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredif6e0ec62005-08-03 09:11:06 +00001528 char linkname[PATH_MAX + 1];
Miklos Szeredib483c932001-10-29 14:57:57 +00001529 char *path;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001530 int err;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001531
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001532 err = -ENOENT;
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001533 pthread_rwlock_rdlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001534 path = get_path(f, ino);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001535 if (path != NULL) {
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001536 struct fuse_intr_data d;
1537 fuse_prepare_interrupt(f, req, &d);
1538 err = fuse_fs_readlink(f->fs, path, linkname, sizeof(linkname));
1539 fuse_finish_interrupt(f, req, &d);
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001540 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001541 }
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001542 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001543 if (!err) {
Miklos Szeredif6e0ec62005-08-03 09:11:06 +00001544 linkname[PATH_MAX] = '\0';
1545 fuse_reply_readlink(req, linkname);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001546 } else
1547 reply_err(req, err);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001548}
1549
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001550static void fuse_lib_mknod(fuse_req_t req, fuse_ino_t parent, const char *name,
1551 mode_t mode, dev_t rdev)
Miklos Szeredib483c932001-10-29 14:57:57 +00001552{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001553 struct fuse *f = req_fuse_prepare(req);
1554 struct fuse_entry_param e;
Miklos Szeredib483c932001-10-29 14:57:57 +00001555 char *path;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001556 int err;
Miklos Szeredib483c932001-10-29 14:57:57 +00001557
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001558 err = -ENOENT;
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001559 pthread_rwlock_rdlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001560 path = get_path_name(f, parent, name);
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001561 if (path) {
1562 struct fuse_intr_data d;
Miklos Szeredi659743b2005-12-09 17:41:42 +00001563 if (f->conf.debug) {
Miklos Szeredi76f65782004-02-19 16:55:40 +00001564 printf("MKNOD %s\n", path);
1565 fflush(stdout);
1566 }
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001567 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001568 err = -ENOSYS;
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001569 if (S_ISREG(mode)) {
Miklos Szeredib3f99722005-11-16 13:00:24 +00001570 struct fuse_file_info fi;
1571
1572 memset(&fi, 0, sizeof(fi));
1573 fi.flags = O_CREAT | O_EXCL | O_WRONLY;
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001574 err = fuse_fs_create(f->fs, path, mode, &fi);
Miklos Szeredib3f99722005-11-16 13:00:24 +00001575 if (!err) {
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001576 err = lookup_path(f, parent, name, path, &e, &fi);
1577 fuse_fs_release(f->fs, path, &fi);
Miklos Szeredib3f99722005-11-16 13:00:24 +00001578 }
Miklos Szeredi5e183482001-10-31 14:52:35 +00001579 }
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001580 if (err == -ENOSYS) {
1581 err = fuse_fs_mknod(f->fs, path, mode, rdev);
1582 if (!err)
1583 err = lookup_path(f, parent, name, path, &e, NULL);
1584 }
1585 fuse_finish_interrupt(f, req, &d);
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001586 free(path);
Miklos Szeredib483c932001-10-29 14:57:57 +00001587 }
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001588 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001589 reply_entry(req, &e, err);
Miklos Szeredib483c932001-10-29 14:57:57 +00001590}
1591
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001592static void fuse_lib_mkdir(fuse_req_t req, fuse_ino_t parent, const char *name,
1593 mode_t mode)
Miklos Szeredib483c932001-10-29 14:57:57 +00001594{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001595 struct fuse *f = req_fuse_prepare(req);
1596 struct fuse_entry_param e;
Miklos Szeredib483c932001-10-29 14:57:57 +00001597 char *path;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001598 int err;
Miklos Szeredib483c932001-10-29 14:57:57 +00001599
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001600 err = -ENOENT;
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001601 pthread_rwlock_rdlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001602 path = get_path_name(f, parent, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001603 if (path != NULL) {
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001604 struct fuse_intr_data d;
Miklos Szeredi659743b2005-12-09 17:41:42 +00001605 if (f->conf.debug) {
Miklos Szeredi76f65782004-02-19 16:55:40 +00001606 printf("MKDIR %s\n", path);
1607 fflush(stdout);
1608 }
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001609 fuse_prepare_interrupt(f, req, &d);
1610 err = fuse_fs_mkdir(f->fs, path, mode);
1611 if (!err)
1612 err = lookup_path(f, parent, name, path, &e, NULL);
1613 fuse_finish_interrupt(f, req, &d);
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001614 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001615 }
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001616 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001617 reply_entry(req, &e, err);
Miklos Szeredib483c932001-10-29 14:57:57 +00001618}
1619
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001620static void fuse_lib_unlink(fuse_req_t req, fuse_ino_t parent,
1621 const char *name)
Miklos Szeredib483c932001-10-29 14:57:57 +00001622{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001623 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredib483c932001-10-29 14:57:57 +00001624 char *path;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001625 int err;
Miklos Szeredib483c932001-10-29 14:57:57 +00001626
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001627 err = -ENOENT;
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001628 pthread_rwlock_wrlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001629 path = get_path_name(f, parent, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001630 if (path != NULL) {
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001631 struct fuse_intr_data d;
Miklos Szeredi659743b2005-12-09 17:41:42 +00001632 if (f->conf.debug) {
Miklos Szeredi209f5d02004-07-24 19:56:16 +00001633 printf("UNLINK %s\n", path);
1634 fflush(stdout);
1635 }
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001636 fuse_prepare_interrupt(f, req, &d);
1637 if (!f->conf.hard_remove && is_open(f, parent, name))
1638 err = hide_node(f, path, parent, name);
1639 else {
1640 err = fuse_fs_unlink(f->fs, path);
1641 if (!err)
1642 remove_node(f, parent, name);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001643 }
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001644 fuse_finish_interrupt(f, req, &d);
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001645 free(path);
Miklos Szeredib483c932001-10-29 14:57:57 +00001646 }
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001647 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001648 reply_err(req, err);
Miklos Szeredib5958612004-02-20 14:10:49 +00001649}
1650
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001651static void fuse_lib_rmdir(fuse_req_t req, fuse_ino_t parent, const char *name)
Miklos Szeredib5958612004-02-20 14:10:49 +00001652{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001653 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredib5958612004-02-20 14:10:49 +00001654 char *path;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001655 int err;
Miklos Szeredib5958612004-02-20 14:10:49 +00001656
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001657 err = -ENOENT;
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001658 pthread_rwlock_wrlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001659 path = get_path_name(f, parent, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001660 if (path != NULL) {
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001661 struct fuse_intr_data d;
Miklos Szeredi659743b2005-12-09 17:41:42 +00001662 if (f->conf.debug) {
Miklos Szeredi209f5d02004-07-24 19:56:16 +00001663 printf("RMDIR %s\n", path);
1664 fflush(stdout);
1665 }
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001666 fuse_prepare_interrupt(f, req, &d);
1667 err = fuse_fs_rmdir(f->fs, path);
1668 fuse_finish_interrupt(f, req, &d);
1669 if (!err)
1670 remove_node(f, parent, name);
Miklos Szeredib5958612004-02-20 14:10:49 +00001671 free(path);
1672 }
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001673 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001674 reply_err(req, err);
Miklos Szeredib483c932001-10-29 14:57:57 +00001675}
1676
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001677static void fuse_lib_symlink(fuse_req_t req, const char *linkname,
1678 fuse_ino_t parent, const char *name)
Miklos Szeredib483c932001-10-29 14:57:57 +00001679{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001680 struct fuse *f = req_fuse_prepare(req);
1681 struct fuse_entry_param e;
Miklos Szeredib483c932001-10-29 14:57:57 +00001682 char *path;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001683 int err;
Miklos Szeredib483c932001-10-29 14:57:57 +00001684
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001685 err = -ENOENT;
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001686 pthread_rwlock_rdlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001687 path = get_path_name(f, parent, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001688 if (path != NULL) {
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001689 struct fuse_intr_data d;
Miklos Szeredi659743b2005-12-09 17:41:42 +00001690 if (f->conf.debug) {
Miklos Szeredi76f65782004-02-19 16:55:40 +00001691 printf("SYMLINK %s\n", path);
1692 fflush(stdout);
1693 }
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001694 fuse_prepare_interrupt(f, req, &d);
1695 err = fuse_fs_symlink(f->fs, linkname, path);
1696 if (!err)
1697 err = lookup_path(f, parent, name, path, &e, NULL);
1698 fuse_finish_interrupt(f, req, &d);
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001699 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001700 }
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001701 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001702 reply_entry(req, &e, err);
Miklos Szeredib483c932001-10-29 14:57:57 +00001703}
1704
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001705static void fuse_lib_rename(fuse_req_t req, fuse_ino_t olddir,
1706 const char *oldname, fuse_ino_t newdir,
1707 const char *newname)
Miklos Szeredi19dff1b2001-10-30 15:06:52 +00001708{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001709 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001710 char *oldpath;
1711 char *newpath;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001712 int err;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +00001713
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001714 err = -ENOENT;
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001715 pthread_rwlock_wrlock(&f->tree_lock);
Miklos Szeredia181e612001-11-06 12:03:23 +00001716 oldpath = get_path_name(f, olddir, oldname);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001717 if (oldpath != NULL) {
Miklos Szeredia181e612001-11-06 12:03:23 +00001718 newpath = get_path_name(f, newdir, newname);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001719 if (newpath != NULL) {
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001720 struct fuse_intr_data d;
Miklos Szeredi659743b2005-12-09 17:41:42 +00001721 if (f->conf.debug) {
Miklos Szeredi209f5d02004-07-24 19:56:16 +00001722 printf("RENAME %s -> %s\n", oldpath, newpath);
1723 fflush(stdout);
1724 }
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001725 err = 0;
1726 fuse_prepare_interrupt(f, req, &d);
1727 if (!f->conf.hard_remove && is_open(f, newdir, newname))
1728 err = hide_node(f, newpath, newdir, newname);
1729 if (!err) {
1730 err = fuse_fs_rename(f->fs, oldpath, newpath);
1731 if (!err)
1732 err = rename_node(f, olddir, oldname, newdir, newname, 0);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001733 }
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001734 fuse_finish_interrupt(f, req, &d);
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001735 free(newpath);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001736 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001737 free(oldpath);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001738 }
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001739 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001740 reply_err(req, err);
Miklos Szeredi19dff1b2001-10-30 15:06:52 +00001741}
1742
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001743static void fuse_lib_link(fuse_req_t req, fuse_ino_t ino, fuse_ino_t newparent,
1744 const char *newname)
Miklos Szeredi19dff1b2001-10-30 15:06:52 +00001745{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001746 struct fuse *f = req_fuse_prepare(req);
1747 struct fuse_entry_param e;
Miklos Szeredi5e183482001-10-31 14:52:35 +00001748 char *oldpath;
1749 char *newpath;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001750 int err;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +00001751
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001752 err = -ENOENT;
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001753 pthread_rwlock_rdlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001754 oldpath = get_path(f, ino);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001755 if (oldpath != NULL) {
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001756 newpath = get_path_name(f, newparent, newname);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001757 if (newpath != NULL) {
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001758 struct fuse_intr_data d;
Miklos Szeredi659743b2005-12-09 17:41:42 +00001759 if (f->conf.debug) {
Miklos Szeredi76f65782004-02-19 16:55:40 +00001760 printf("LINK %s\n", newpath);
1761 fflush(stdout);
1762 }
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001763 fuse_prepare_interrupt(f, req, &d);
1764 err = fuse_fs_link(f->fs, oldpath, newpath);
1765 if (!err)
1766 err = lookup_path(f, newparent, newname, newpath, &e, NULL);
1767 fuse_finish_interrupt(f, req, &d);
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001768 free(newpath);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001769 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001770 free(oldpath);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001771 }
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001772 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001773 reply_entry(req, &e, err);
Miklos Szeredi19dff1b2001-10-30 15:06:52 +00001774}
1775
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001776static void fuse_do_release(struct fuse *f, fuse_ino_t ino, const char *path,
1777 struct fuse_file_info *fi)
1778{
1779 struct node *node;
1780 int unlink_hidden = 0;
1781
1782 fuse_fs_release(f->fs, path ? path : "-", fi);
1783
1784 pthread_mutex_lock(&f->lock);
1785 node = get_node(f, ino);
1786 assert(node->open_count > 0);
1787 --node->open_count;
1788 if (node->is_hidden && !node->open_count) {
1789 unlink_hidden = 1;
1790 node->is_hidden = 0;
1791 }
1792 pthread_mutex_unlock(&f->lock);
1793
1794 if(unlink_hidden && path)
1795 fuse_fs_unlink(f->fs, path);
1796}
1797
1798static void fuse_lib_create(fuse_req_t req, fuse_ino_t parent,
1799 const char *name, mode_t mode,
1800 struct fuse_file_info *fi)
Miklos Szeredid9079a72005-10-26 15:29:06 +00001801{
1802 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001803 struct fuse_intr_data d;
Miklos Szeredid9079a72005-10-26 15:29:06 +00001804 struct fuse_entry_param e;
1805 char *path;
1806 int err;
1807
1808 err = -ENOENT;
1809 pthread_rwlock_rdlock(&f->tree_lock);
1810 path = get_path_name(f, parent, name);
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001811 if (path) {
1812 fuse_prepare_interrupt(f, req, &d);
1813 err = fuse_fs_create(f->fs, path, mode, fi);
1814 if (!err) {
1815 err = lookup_path(f, parent, name, path, &e, fi);
1816 if (err)
1817 fuse_fs_release(f->fs, path, fi);
1818 else if (!S_ISREG(e.attr.st_mode)) {
1819 err = -EIO;
1820 fuse_fs_release(f->fs, path, fi);
1821 forget_node(f, e.ino, 1);
1822 } else {
1823 if (f->conf.direct_io)
1824 fi->direct_io = 1;
1825 if (f->conf.kernel_cache)
1826 fi->keep_cache = 1;
1827
Miklos Szeredid9079a72005-10-26 15:29:06 +00001828 }
1829 }
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001830 fuse_finish_interrupt(f, req, &d);
Miklos Szeredid9079a72005-10-26 15:29:06 +00001831 }
Miklos Szeredid9079a72005-10-26 15:29:06 +00001832 if (!err) {
Miklos Szeredid9079a72005-10-26 15:29:06 +00001833 pthread_mutex_lock(&f->lock);
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001834 get_node(f, e.ino)->open_count++;
1835 pthread_mutex_unlock(&f->lock);
Miklos Szeredid9079a72005-10-26 15:29:06 +00001836 if (fuse_reply_create(req, &e, fi) == -ENOENT) {
1837 /* The open syscall was interrupted, so it must be cancelled */
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001838 fuse_prepare_interrupt(f, req, &d);
1839 fuse_do_release(f, e.ino, path, fi);
1840 fuse_finish_interrupt(f, req, &d);
Miklos Szeredid9079a72005-10-26 15:29:06 +00001841 forget_node(f, e.ino, 1);
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001842 } else if (f->conf.debug) {
1843 printf(" CREATE[%llu] flags: 0x%x %s\n",
1844 (unsigned long long) fi->fh, fi->flags, path);
1845 fflush(stdout);
Miklos Szeredid9079a72005-10-26 15:29:06 +00001846 }
Miklos Szeredid9079a72005-10-26 15:29:06 +00001847 } else
1848 reply_err(req, err);
1849
1850 if (path)
1851 free(path);
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001852
Miklos Szeredid9079a72005-10-26 15:29:06 +00001853 pthread_rwlock_unlock(&f->tree_lock);
1854}
1855
Miklos Szeredi320abe42006-01-30 18:14:51 +00001856static double diff_timespec(const struct timespec *t1,
1857 const struct timespec *t2)
1858{
1859 return (t1->tv_sec - t2->tv_sec) +
1860 ((double) t1->tv_nsec - (double) t2->tv_nsec) / 1000000000.0;
1861}
1862
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001863static void open_auto_cache(struct fuse *f, fuse_ino_t ino, const char *path,
1864 struct fuse_file_info *fi)
Miklos Szeredi320abe42006-01-30 18:14:51 +00001865{
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001866 struct node *node;
1867
1868 pthread_mutex_lock(&f->lock);
1869 node = get_node(f, ino);
Miklos Szeredi08dab162006-02-01 13:39:15 +00001870 if (node->cache_valid) {
1871 struct timespec now;
Miklos Szeredi320abe42006-01-30 18:14:51 +00001872
Miklos Szeredi08dab162006-02-01 13:39:15 +00001873 curr_time(&now);
Miklos Szeredi6e806e92006-02-16 16:59:39 +00001874 if (diff_timespec(&now, &node->stat_updated) > f->conf.ac_attr_timeout) {
Miklos Szeredi08dab162006-02-01 13:39:15 +00001875 struct stat stbuf;
1876 int err;
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001877 pthread_mutex_unlock(&f->lock);
1878 err = fuse_fs_fgetattr(f->fs, path, &stbuf, fi);
1879 pthread_mutex_lock(&f->lock);
Miklos Szeredi08dab162006-02-01 13:39:15 +00001880 if (!err)
1881 update_stat(node, &stbuf);
1882 else
1883 node->cache_valid = 0;
1884 }
Miklos Szeredi320abe42006-01-30 18:14:51 +00001885 }
1886 if (node->cache_valid)
1887 fi->keep_cache = 1;
Miklos Szeredi08dab162006-02-01 13:39:15 +00001888
1889 node->cache_valid = 1;
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001890 pthread_mutex_unlock(&f->lock);
Miklos Szeredi320abe42006-01-30 18:14:51 +00001891}
1892
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001893static void fuse_lib_open(fuse_req_t req, fuse_ino_t ino,
1894 struct fuse_file_info *fi)
Miklos Szeredi5e183482001-10-31 14:52:35 +00001895{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001896 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001897 struct fuse_intr_data d;
Miklos Szeredi31066bb2005-08-01 14:49:31 +00001898 char *path = NULL;
1899 int err = 0;
Miklos Szeredi5e183482001-10-31 14:52:35 +00001900
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001901 err = -ENOENT;
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001902 pthread_rwlock_rdlock(&f->tree_lock);
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001903 path = get_path(f, ino);
1904 if (path) {
1905 fuse_prepare_interrupt(f, req, &d);
1906 err = fuse_fs_open(f->fs, path, fi);
1907 if (!err) {
1908 if (f->conf.direct_io)
1909 fi->direct_io = 1;
1910 if (f->conf.kernel_cache)
1911 fi->keep_cache = 1;
1912
1913 if (f->conf.auto_cache)
1914 open_auto_cache(f, ino, path, fi);
1915 }
1916 fuse_finish_interrupt(f, req, &d);
Miklos Szeredi40b9a5a2002-12-10 16:09:02 +00001917 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001918 if (!err) {
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001919 pthread_mutex_lock(&f->lock);
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001920 get_node(f, ino)->open_count++;
1921 pthread_mutex_unlock(&f->lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001922 if (fuse_reply_open(req, fi) == -ENOENT) {
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001923 /* The open syscall was interrupted, so it must be cancelled */
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001924 fuse_prepare_interrupt(f, req, &d);
1925 fuse_do_release(f, ino, path, fi);
1926 fuse_finish_interrupt(f, req, &d);
1927 } else if (f->conf.debug) {
1928 printf("OPEN[%llu] flags: 0x%x %s\n",
1929 (unsigned long long) fi->fh, fi->flags, path);
1930 fflush(stdout);
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001931 }
Miklos Szeredi73798f92004-07-12 15:55:11 +00001932 } else
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001933 reply_err(req, err);
Miklos Szeredi73798f92004-07-12 15:55:11 +00001934
Miklos Szeredi9a31cca2004-06-26 21:11:25 +00001935 if (path)
1936 free(path);
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001937 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001938}
1939
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001940static void fuse_lib_read(fuse_req_t req, fuse_ino_t ino, size_t size,
1941 off_t off, struct fuse_file_info *fi)
Miklos Szeredie2e4ac22004-05-18 08:45:28 +00001942{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001943 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredie2e4ac22004-05-18 08:45:28 +00001944 char *path;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001945 char *buf;
Miklos Szeredie2e4ac22004-05-18 08:45:28 +00001946 int res;
1947
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001948 buf = (char *) malloc(size);
1949 if (buf == NULL) {
1950 reply_err(req, -ENOMEM);
1951 return;
1952 }
1953
Miklos Szeredie2e4ac22004-05-18 08:45:28 +00001954 res = -ENOENT;
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001955 pthread_rwlock_rdlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001956 path = get_path(f, ino);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001957 if (path != NULL) {
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001958 struct fuse_intr_data d;
Miklos Szeredi659743b2005-12-09 17:41:42 +00001959 if (f->conf.debug) {
Miklos Szeredia039f8f2006-02-24 16:21:58 +00001960 printf("READ[%llu] %lu bytes from %llu\n",
1961 (unsigned long long) fi->fh, (unsigned long) size,
1962 (unsigned long long) off);
Miklos Szeredi209f5d02004-07-24 19:56:16 +00001963 fflush(stdout);
1964 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001965
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001966 fuse_prepare_interrupt(f, req, &d);
1967 res = fuse_fs_read(f->fs, path, buf, size, off, fi);
1968 fuse_finish_interrupt(f, req, &d);
Miklos Szeredie2e4ac22004-05-18 08:45:28 +00001969 free(path);
1970 }
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001971 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001972
1973 if (res >= 0) {
Miklos Szeredi659743b2005-12-09 17:41:42 +00001974 if (f->conf.debug) {
Miklos Szeredi3a770472005-11-11 21:32:42 +00001975 printf(" READ[%llu] %u bytes\n", (unsigned long long) fi->fh,
1976 res);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001977 fflush(stdout);
1978 }
Miklos Szeredif412d072005-10-14 21:24:32 +00001979 if ((size_t) res > size)
1980 fprintf(stderr, "fuse: read too many bytes");
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001981 fuse_reply_buf(req, buf, res);
1982 } else
1983 reply_err(req, res);
1984
1985 free(buf);
Miklos Szeredie2e4ac22004-05-18 08:45:28 +00001986}
1987
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001988static void fuse_lib_write(fuse_req_t req, fuse_ino_t ino, const char *buf,
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001989 size_t size, off_t off, struct fuse_file_info *fi)
Miklos Szeredic8ba2372002-12-10 12:26:00 +00001990{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001991 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001992 char *path;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001993 int res;
1994
1995 res = -ENOENT;
1996 pthread_rwlock_rdlock(&f->tree_lock);
1997 path = get_path(f, ino);
1998 if (path != NULL) {
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001999 struct fuse_intr_data d;
Miklos Szeredi659743b2005-12-09 17:41:42 +00002000 if (f->conf.debug) {
Miklos Szeredia039f8f2006-02-24 16:21:58 +00002001 printf("WRITE%s[%llu] %lu bytes to %llu\n",
Miklos Szeredi3a770472005-11-11 21:32:42 +00002002 fi->writepage ? "PAGE" : "", (unsigned long long) fi->fh,
Miklos Szeredia039f8f2006-02-24 16:21:58 +00002003 (unsigned long) size, (unsigned long long) off);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002004 fflush(stdout);
2005 }
2006
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002007 fuse_prepare_interrupt(f, req, &d);
2008 res = fuse_fs_write(f->fs, path, buf, size, off, fi);
2009 fuse_finish_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002010 free(path);
2011 }
2012 pthread_rwlock_unlock(&f->tree_lock);
2013
Miklos Szeredif412d072005-10-14 21:24:32 +00002014 if (res >= 0) {
Miklos Szeredi659743b2005-12-09 17:41:42 +00002015 if (f->conf.debug) {
Miklos Szeredi3a770472005-11-11 21:32:42 +00002016 printf(" WRITE%s[%llu] %u bytes\n",
2017 fi->writepage ? "PAGE" : "", (unsigned long long) fi->fh,
2018 res);
Miklos Szeredif412d072005-10-14 21:24:32 +00002019 fflush(stdout);
2020 }
2021 if ((size_t) res > size)
2022 fprintf(stderr, "fuse: wrote too many bytes");
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002023 fuse_reply_write(req, res);
Miklos Szeredif412d072005-10-14 21:24:32 +00002024 } else
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002025 reply_err(req, res);
2026}
2027
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002028static void fuse_lib_release(fuse_req_t req, fuse_ino_t ino,
2029 struct fuse_file_info *fi)
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002030{
2031 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002032 struct fuse_intr_data d;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002033 char *path;
Miklos Szeredi4fca4322006-10-01 14:41:04 +00002034 int err = 0;
Miklos Szeredifb28c5e2004-11-26 12:15:06 +00002035
Miklos Szerediaa8258e2006-02-25 14:42:03 +00002036 pthread_rwlock_rdlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002037 path = get_path(f, ino);
Miklos Szeredi659743b2005-12-09 17:41:42 +00002038 if (f->conf.debug) {
Miklos Szeredi4fca4322006-10-01 14:41:04 +00002039 printf("RELEASE%s[%llu] flags: 0x%x\n", fi->flush ? "+FLUSH" : "",
2040 (unsigned long long) fi->fh, fi->flags);
Miklos Szeredi0f62d722005-01-04 12:45:54 +00002041 fflush(stdout);
Miklos Szeredic8ba2372002-12-10 12:26:00 +00002042 }
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002043 fuse_prepare_interrupt(f, req, &d);
2044 if (fi->flush && path) {
2045 err = fuse_fs_flush(f->fs, path, fi);
2046 if (err == -ENOSYS)
2047 err = 0;
Miklos Szeredic3b76812006-09-16 08:52:09 +00002048 }
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002049 fuse_do_release(f, ino, path, fi);
2050 fuse_finish_interrupt(f, req, &d);
Miklos Szeredie5183742005-02-02 11:14:04 +00002051
Miklos Szeredi0f62d722005-01-04 12:45:54 +00002052 if (path)
2053 free(path);
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00002054 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredi0f62d722005-01-04 12:45:54 +00002055
Miklos Szeredi4fca4322006-10-01 14:41:04 +00002056 reply_err(req, err);
Miklos Szeredic8ba2372002-12-10 12:26:00 +00002057}
2058
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002059static void fuse_lib_fsync(fuse_req_t req, fuse_ino_t ino, int datasync,
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002060 struct fuse_file_info *fi)
Miklos Szeredi5e183482001-10-31 14:52:35 +00002061{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002062 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredi5e183482001-10-31 14:52:35 +00002063 char *path;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002064 int err;
Miklos Szerediab974562005-04-07 15:40:21 +00002065
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002066 err = -ENOENT;
2067 pthread_rwlock_rdlock(&f->tree_lock);
2068 path = get_path(f, ino);
2069 if (path != NULL) {
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002070 struct fuse_intr_data d;
Miklos Szeredi659743b2005-12-09 17:41:42 +00002071 if (f->conf.debug) {
Miklos Szeredi3a770472005-11-11 21:32:42 +00002072 printf("FSYNC[%llu]\n", (unsigned long long) fi->fh);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002073 fflush(stdout);
2074 }
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002075 fuse_prepare_interrupt(f, req, &d);
2076 err = fuse_fs_fsync(f->fs, path, datasync, fi);
2077 fuse_finish_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002078 free(path);
2079 }
2080 pthread_rwlock_unlock(&f->tree_lock);
2081 reply_err(req, err);
2082}
2083
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002084static struct fuse_dh *get_dirhandle(const struct fuse_file_info *llfi,
2085 struct fuse_file_info *fi)
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002086{
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002087 struct fuse_dh *dh = (struct fuse_dh *) (uintptr_t) llfi->fh;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002088 memset(fi, 0, sizeof(struct fuse_file_info));
2089 fi->fh = dh->fh;
Miklos Szerediead7f102005-11-28 16:02:27 +00002090 fi->fh_old = dh->fh;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002091 return dh;
2092}
2093
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002094static void fuse_lib_opendir(fuse_req_t req, fuse_ino_t ino,
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002095 struct fuse_file_info *llfi)
2096{
2097 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002098 struct fuse_intr_data d;
2099 struct fuse_dh *dh;
2100 struct fuse_file_info fi;
2101 char *path;
2102 int err;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002103
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002104 dh = (struct fuse_dh *) malloc(sizeof(struct fuse_dh));
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002105 if (dh == NULL) {
2106 reply_err(req, -ENOMEM);
Miklos Szerediab974562005-04-07 15:40:21 +00002107 return;
Miklos Szeredi5e183482001-10-31 14:52:35 +00002108 }
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002109 memset(dh, 0, sizeof(struct fuse_dh));
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002110 dh->fuse = f;
2111 dh->contents = NULL;
2112 dh->len = 0;
2113 dh->filled = 0;
2114 dh->nodeid = ino;
Miklos Szeredi38f152c2006-09-03 18:28:52 +00002115 fuse_mutex_init(&dh->lock);
Miklos Szerediab974562005-04-07 15:40:21 +00002116
Miklos Szeredi3a770472005-11-11 21:32:42 +00002117 llfi->fh = (uintptr_t) dh;
Miklos Szerediab974562005-04-07 15:40:21 +00002118
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002119 memset(&fi, 0, sizeof(fi));
2120 fi.flags = llfi->flags;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002121
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002122 err = -ENOENT;
2123 pthread_rwlock_rdlock(&f->tree_lock);
2124 path = get_path(f, ino);
2125 if (path != NULL) {
2126 fuse_prepare_interrupt(f, req, &d);
2127 err = fuse_fs_opendir(f->fs, path, &fi);
2128 fuse_finish_interrupt(f, req, &d);
2129 dh->fh = fi.fh;
2130 }
2131 if (!err) {
2132 if (fuse_reply_open(req, llfi) == -ENOENT) {
2133 /* The opendir syscall was interrupted, so it must be cancelled */
2134 fuse_prepare_interrupt(f, req, &d);
2135 fuse_fs_releasedir(f->fs, path, &fi);
2136 fuse_finish_interrupt(f, req, &d);
2137 pthread_mutex_destroy(&dh->lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002138 free(dh);
2139 }
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002140 } else {
2141 reply_err(req, err);
2142 free(dh);
2143 }
2144 free(path);
2145 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredi5e183482001-10-31 14:52:35 +00002146}
Miklos Szeredib483c932001-10-29 14:57:57 +00002147
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002148static int extend_contents(struct fuse_dh *dh, unsigned minsize)
Miklos Szeredi1bf64f42006-02-17 15:49:25 +00002149{
2150 if (minsize > dh->size) {
2151 char *newptr;
2152 unsigned newsize = dh->size;
2153 if (!newsize)
2154 newsize = 1024;
2155 while (newsize < minsize)
2156 newsize *= 2;
2157
2158 newptr = (char *) realloc(dh->contents, newsize);
2159 if (!newptr) {
2160 dh->error = -ENOMEM;
2161 return -1;
2162 }
2163 dh->contents = newptr;
2164 dh->size = newsize;
2165 }
2166 return 0;
2167}
2168
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002169static int fill_dir(void *dh_, const char *name, const struct stat *statp,
2170 off_t off)
Miklos Szeredia181e612001-11-06 12:03:23 +00002171{
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002172 struct fuse_dh *dh = (struct fuse_dh *) dh_;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002173 struct stat stbuf;
Miklos Szeredi1bf64f42006-02-17 15:49:25 +00002174 size_t newlen;
Miklos Szeredifb28c5e2004-11-26 12:15:06 +00002175
Miklos Szeredif6e0ec62005-08-03 09:11:06 +00002176 if (statp)
2177 stbuf = *statp;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002178 else {
2179 memset(&stbuf, 0, sizeof(stbuf));
Miklos Szeredie248e4b2005-12-14 16:18:32 +00002180 stbuf.st_ino = FUSE_UNKNOWN_INO;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002181 }
Miklos Szeredia181e612001-11-06 12:03:23 +00002182
Miklos Szeredi659743b2005-12-09 17:41:42 +00002183 if (!dh->fuse->conf.use_ino) {
Miklos Szeredie248e4b2005-12-14 16:18:32 +00002184 stbuf.st_ino = FUSE_UNKNOWN_INO;
Miklos Szeredi659743b2005-12-09 17:41:42 +00002185 if (dh->fuse->conf.readdir_ino) {
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002186 struct node *node;
2187 pthread_mutex_lock(&dh->fuse->lock);
2188 node = lookup_node(dh->fuse, dh->nodeid, name);
2189 if (node)
2190 stbuf.st_ino = (ino_t) node->nodeid;
2191 pthread_mutex_unlock(&dh->fuse->lock);
Miklos Szeredi6ebe2342002-01-06 21:44:16 +00002192 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002193 }
Miklos Szeredi6ebe2342002-01-06 21:44:16 +00002194
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002195 if (off) {
Miklos Szeredi1bf64f42006-02-17 15:49:25 +00002196 if (extend_contents(dh, dh->needlen) == -1)
2197 return 1;
2198
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002199 dh->filled = 0;
Miklos Szeredi1bf64f42006-02-17 15:49:25 +00002200 newlen = dh->len + fuse_add_direntry(dh->req, dh->contents + dh->len,
2201 dh->needlen - dh->len, name,
2202 &stbuf, off);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002203 if (newlen > dh->needlen)
2204 return 1;
Miklos Szeredi1bf64f42006-02-17 15:49:25 +00002205 } else {
2206 newlen = dh->len + fuse_add_direntry(dh->req, NULL, 0, name, NULL, 0);
2207 if (extend_contents(dh, newlen) == -1)
Miklos Szeredic4c12ae2005-10-20 14:48:50 +00002208 return 1;
Miklos Szeredi1bf64f42006-02-17 15:49:25 +00002209
2210 fuse_add_direntry(dh->req, dh->contents + dh->len, dh->size - dh->len,
2211 name, &stbuf, newlen);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002212 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002213 dh->len = newlen;
2214 return 0;
2215}
2216
Miklos Szeredi1bf64f42006-02-17 15:49:25 +00002217static int readdir_fill(struct fuse *f, fuse_req_t req, fuse_ino_t ino,
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002218 size_t size, off_t off, struct fuse_dh *dh,
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002219 struct fuse_file_info *fi)
2220{
2221 int err = -ENOENT;
2222 char *path;
2223 pthread_rwlock_rdlock(&f->tree_lock);
2224 path = get_path(f, ino);
2225 if (path != NULL) {
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002226 struct fuse_intr_data d;
2227
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002228 dh->len = 0;
2229 dh->error = 0;
2230 dh->needlen = size;
2231 dh->filled = 1;
Miklos Szeredi1bf64f42006-02-17 15:49:25 +00002232 dh->req = req;
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002233 fuse_prepare_interrupt(f, req, &d);
2234 err = fuse_fs_readdir(f->fs, path, dh, fill_dir, off, fi);
2235 fuse_finish_interrupt(f, req, &d);
Miklos Szeredi1bf64f42006-02-17 15:49:25 +00002236 dh->req = NULL;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002237 if (!err)
2238 err = dh->error;
2239 if (err)
2240 dh->filled = 0;
Miklos Szeredi97c61e92001-11-07 12:09:43 +00002241 free(path);
Miklos Szeredia181e612001-11-06 12:03:23 +00002242 }
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00002243 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002244 return err;
2245}
Miklos Szeredie5183742005-02-02 11:14:04 +00002246
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002247static void fuse_lib_readdir(fuse_req_t req, fuse_ino_t ino, size_t size,
2248 off_t off, struct fuse_file_info *llfi)
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002249{
2250 struct fuse *f = req_fuse_prepare(req);
2251 struct fuse_file_info fi;
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002252 struct fuse_dh *dh = get_dirhandle(llfi, &fi);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002253
2254 pthread_mutex_lock(&dh->lock);
Miklos Szeredi77ccf652005-08-19 14:40:27 +00002255 /* According to SUS, directory contents need to be refreshed on
2256 rewinddir() */
2257 if (!off)
2258 dh->filled = 0;
2259
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002260 if (!dh->filled) {
Miklos Szeredi1bf64f42006-02-17 15:49:25 +00002261 int err = readdir_fill(f, req, ino, size, off, dh, &fi);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002262 if (err) {
2263 reply_err(req, err);
2264 goto out;
2265 }
Miklos Szeredia181e612001-11-06 12:03:23 +00002266 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002267 if (dh->filled) {
2268 if (off < dh->len) {
2269 if (off + size > dh->len)
2270 size = dh->len - off;
2271 } else
2272 size = 0;
2273 } else {
2274 size = dh->len;
2275 off = 0;
2276 }
2277 fuse_reply_buf(req, dh->contents + off, size);
2278 out:
2279 pthread_mutex_unlock(&dh->lock);
2280}
Miklos Szeredia181e612001-11-06 12:03:23 +00002281
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002282static void fuse_lib_releasedir(fuse_req_t req, fuse_ino_t ino,
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002283 struct fuse_file_info *llfi)
2284{
2285 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002286 struct fuse_intr_data d;
Miklos Szeredi9b813af2005-07-21 07:59:37 +00002287 struct fuse_file_info fi;
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002288 struct fuse_dh *dh = get_dirhandle(llfi, &fi);
2289 char *path;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002290
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002291 pthread_rwlock_rdlock(&f->tree_lock);
2292 path = get_path(f, ino);
2293 fuse_prepare_interrupt(f, req, &d);
2294 fuse_fs_releasedir(f->fs, path ? path : "-", &fi);
2295 fuse_finish_interrupt(f, req, &d);
2296 if (path)
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002297 free(path);
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002298 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002299 pthread_mutex_lock(&dh->lock);
2300 pthread_mutex_unlock(&dh->lock);
2301 pthread_mutex_destroy(&dh->lock);
2302 free(dh->contents);
2303 free(dh);
2304 reply_err(req, 0);
2305}
2306
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002307static void fuse_lib_fsyncdir(fuse_req_t req, fuse_ino_t ino, int datasync,
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002308 struct fuse_file_info *llfi)
2309{
2310 struct fuse *f = req_fuse_prepare(req);
2311 struct fuse_file_info fi;
2312 char *path;
2313 int err;
2314
2315 get_dirhandle(llfi, &fi);
2316
2317 err = -ENOENT;
2318 pthread_rwlock_rdlock(&f->tree_lock);
2319 path = get_path(f, ino);
2320 if (path != NULL) {
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002321 struct fuse_intr_data d;
2322 fuse_prepare_interrupt(f, req, &d);
2323 err = fuse_fs_fsyncdir(f->fs, path, datasync, &fi);
2324 fuse_finish_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002325 free(path);
2326 }
2327 pthread_rwlock_unlock(&f->tree_lock);
2328 reply_err(req, err);
Miklos Szeredia181e612001-11-06 12:03:23 +00002329}
2330
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002331static void fuse_lib_statfs(fuse_req_t req, fuse_ino_t ino)
Miklos Szeredi18e75e42004-02-19 14:23:27 +00002332{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002333 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredi52cb09d2005-11-07 11:59:00 +00002334 struct statvfs buf;
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002335 char *path;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002336 int err;
Mark Glinesd84b39a2002-01-07 16:32:02 +00002337
Miklos Szeredi52cb09d2005-11-07 11:59:00 +00002338 memset(&buf, 0, sizeof(buf));
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002339 pthread_rwlock_rdlock(&f->tree_lock);
2340 if (!ino) {
2341 err = -ENOMEM;
2342 path = strdup("/");
2343 } else {
2344 err = -ENOENT;
2345 path = get_path(f, ino);
2346 }
2347 if (path) {
2348 struct fuse_intr_data d;
2349 fuse_prepare_interrupt(f, req, &d);
2350 err = fuse_fs_statfs(f->fs, path, &buf);
2351 fuse_finish_interrupt(f, req, &d);
2352 free(path);
2353 }
2354 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredi77f39942004-03-25 11:17:52 +00002355
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002356 if (!err)
2357 fuse_reply_statfs(req, &buf);
Miklos Szeredi03cebae2004-03-31 10:19:18 +00002358 else
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002359 reply_err(req, err);
Miklos Szeredi03cebae2004-03-31 10:19:18 +00002360}
2361
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002362static void fuse_lib_setxattr(fuse_req_t req, fuse_ino_t ino, const char *name,
2363 const char *value, size_t size, int flags)
Miklos Szeredi3ed84232004-03-30 15:17:26 +00002364{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002365 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredi3ed84232004-03-30 15:17:26 +00002366 char *path;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002367 int err;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00002368
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002369 err = -ENOENT;
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00002370 pthread_rwlock_rdlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002371 path = get_path(f, ino);
Miklos Szeredi3ed84232004-03-30 15:17:26 +00002372 if (path != NULL) {
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002373 struct fuse_intr_data d;
2374 fuse_prepare_interrupt(f, req, &d);
2375 err = fuse_fs_setxattr(f->fs, path, name, value, size, flags);
2376 fuse_finish_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002377 free(path);
2378 }
2379 pthread_rwlock_unlock(&f->tree_lock);
2380 reply_err(req, err);
2381}
2382
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002383static int common_getxattr(struct fuse *f, fuse_req_t req, fuse_ino_t ino,
2384 const char *name, char *value, size_t size)
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002385{
2386 int err;
2387 char *path;
2388
2389 err = -ENOENT;
2390 pthread_rwlock_rdlock(&f->tree_lock);
2391 path = get_path(f, ino);
2392 if (path != NULL) {
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002393 struct fuse_intr_data d;
2394 fuse_prepare_interrupt(f, req, &d);
2395 err = fuse_fs_getxattr(f->fs, path, name, value, size);
2396 fuse_finish_interrupt(f, req, &d);
Miklos Szerediab974562005-04-07 15:40:21 +00002397 free(path);
2398 }
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00002399 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szerediab974562005-04-07 15:40:21 +00002400 return err;
2401}
2402
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002403static void fuse_lib_getxattr(fuse_req_t req, fuse_ino_t ino, const char *name,
2404 size_t size)
Miklos Szeredi3ead28e2005-01-18 21:23:41 +00002405{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002406 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredi4283ee72005-03-21 12:09:04 +00002407 int res;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002408
2409 if (size) {
2410 char *value = (char *) malloc(size);
2411 if (value == NULL) {
2412 reply_err(req, -ENOMEM);
2413 return;
2414 }
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002415 res = common_getxattr(f, req, ino, name, value, size);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002416 if (res > 0)
2417 fuse_reply_buf(req, value, res);
2418 else
2419 reply_err(req, res);
2420 free(value);
2421 } else {
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002422 res = common_getxattr(f, req, ino, name, NULL, 0);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002423 if (res >= 0)
2424 fuse_reply_xattr(req, res);
2425 else
2426 reply_err(req, res);
2427 }
2428}
2429
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002430static int common_listxattr(struct fuse *f, fuse_req_t req, fuse_ino_t ino,
2431 char *list, size_t size)
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002432{
Miklos Szeredi4283ee72005-03-21 12:09:04 +00002433 char *path;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002434 int err;
Miklos Szeredi4283ee72005-03-21 12:09:04 +00002435
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002436 err = -ENOENT;
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00002437 pthread_rwlock_rdlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002438 path = get_path(f, ino);
Miklos Szeredi4283ee72005-03-21 12:09:04 +00002439 if (path != NULL) {
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002440 struct fuse_intr_data d;
2441 fuse_prepare_interrupt(f, req, &d);
2442 err = fuse_fs_listxattr(f->fs, path, list, size);
2443 fuse_finish_interrupt(f, req, &d);
Miklos Szeredi4283ee72005-03-21 12:09:04 +00002444 free(path);
2445 }
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00002446 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002447 return err;
Miklos Szeredi4283ee72005-03-21 12:09:04 +00002448}
Miklos Szeredi3ead28e2005-01-18 21:23:41 +00002449
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002450static void fuse_lib_listxattr(fuse_req_t req, fuse_ino_t ino, size_t size)
Miklos Szeredi43696432001-11-18 19:15:05 +00002451{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002452 struct fuse *f = req_fuse_prepare(req);
2453 int res;
2454
2455 if (size) {
2456 char *list = (char *) malloc(size);
2457 if (list == NULL) {
2458 reply_err(req, -ENOMEM);
2459 return;
2460 }
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002461 res = common_listxattr(f, req, ino, list, size);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002462 if (res > 0)
2463 fuse_reply_buf(req, list, res);
2464 else
2465 reply_err(req, res);
2466 free(list);
2467 } else {
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002468 res = common_listxattr(f, req, ino, NULL, 0);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002469 if (res >= 0)
2470 fuse_reply_xattr(req, res);
2471 else
2472 reply_err(req, res);
2473 }
Miklos Szeredi43696432001-11-18 19:15:05 +00002474}
2475
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002476static void fuse_lib_removexattr(fuse_req_t req, fuse_ino_t ino,
2477 const char *name)
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002478{
2479 struct fuse *f = req_fuse_prepare(req);
2480 char *path;
2481 int err;
2482
2483 err = -ENOENT;
2484 pthread_rwlock_rdlock(&f->tree_lock);
2485 path = get_path(f, ino);
2486 if (path != NULL) {
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002487 struct fuse_intr_data d;
2488 fuse_prepare_interrupt(f, req, &d);
2489 err = fuse_fs_removexattr(f->fs, path, name);
2490 fuse_finish_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002491 free(path);
2492 }
2493 pthread_rwlock_unlock(&f->tree_lock);
2494 reply_err(req, err);
2495}
2496
Miklos Szeredi0c59ebf2006-09-10 20:53:36 +00002497static struct lock *locks_conflict(struct node *node, const struct lock *lock)
2498{
2499 struct lock *l;
2500
2501 for (l = node->locks; l; l = l->next)
2502 if (l->owner != lock->owner &&
2503 lock->start <= l->end && l->start <= lock->end &&
2504 (l->type == F_WRLCK || lock->type == F_WRLCK))
2505 break;
2506
2507 return l;
2508}
2509
2510static void delete_lock(struct lock **lockp)
2511{
2512 struct lock *l = *lockp;
2513 *lockp = l->next;
2514 free(l);
2515}
2516
2517static void insert_lock(struct lock **pos, struct lock *lock)
2518{
2519 lock->next = *pos;
2520 *pos = lock;
2521}
2522
2523static int locks_insert(struct node *node, struct lock *lock)
2524{
2525 struct lock **lp;
2526 struct lock *newl1 = NULL;
2527 struct lock *newl2 = NULL;
2528
2529 if (lock->type != F_UNLCK || lock->start != 0 || lock->end != OFFSET_MAX) {
2530 newl1 = malloc(sizeof(struct lock));
2531 newl2 = malloc(sizeof(struct lock));
2532
2533 if (!newl1 || !newl2) {
2534 free(newl1);
2535 free(newl2);
2536 return -ENOLCK;
2537 }
2538 }
2539
2540 for (lp = &node->locks; *lp;) {
2541 struct lock *l = *lp;
2542 if (l->owner != lock->owner)
2543 goto skip;
2544
2545 if (lock->type == l->type) {
2546 if (l->end < lock->start - 1)
2547 goto skip;
2548 if (lock->end < l->start - 1)
2549 break;
2550 if (l->start <= lock->start && lock->end <= l->end)
2551 goto out;
2552 if (l->start < lock->start)
2553 lock->start = l->start;
2554 if (lock->end < l->end)
2555 lock->end = l->end;
2556 goto delete;
2557 } else {
2558 if (l->end < lock->start)
2559 goto skip;
2560 if (lock->end < l->start)
2561 break;
2562 if (lock->start <= l->start && l->end <= lock->end)
2563 goto delete;
2564 if (l->end <= lock->end) {
2565 l->end = lock->start - 1;
2566 goto skip;
2567 }
2568 if (lock->start <= l->start) {
2569 l->start = lock->end + 1;
2570 break;
2571 }
2572 *newl2 = *l;
2573 newl2->start = lock->end + 1;
2574 l->end = lock->start - 1;
2575 insert_lock(&l->next, newl2);
2576 newl2 = NULL;
2577 }
2578 skip:
2579 lp = &l->next;
2580 continue;
2581
2582 delete:
2583 delete_lock(lp);
2584 }
2585 if (lock->type != F_UNLCK) {
2586 *newl1 = *lock;
2587 insert_lock(lp, newl1);
2588 newl1 = NULL;
2589 }
2590out:
2591 free(newl1);
2592 free(newl2);
2593 return 0;
2594}
2595
2596static void flock_to_lock(struct flock *flock, struct lock *lock)
2597{
2598 memset(lock, 0, sizeof(struct lock));
2599 lock->type = flock->l_type;
2600 lock->start = flock->l_start;
2601 lock->end = flock->l_len ? flock->l_start + flock->l_len - 1 : OFFSET_MAX;
2602 lock->pid = flock->l_pid;
2603}
2604
2605static void lock_to_flock(struct lock *lock, struct flock *flock)
2606{
2607 flock->l_type = lock->type;
2608 flock->l_start = lock->start;
2609 flock->l_len = (lock->end == OFFSET_MAX) ? 0 : lock->end - lock->start + 1;
2610 flock->l_pid = lock->pid;
2611}
2612
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002613static void fuse_lib_flush(fuse_req_t req, fuse_ino_t ino,
Miklos Szeredi07407852006-09-30 20:03:52 +00002614 struct fuse_file_info *fi)
Miklos Szeredi0c59ebf2006-09-10 20:53:36 +00002615{
2616 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002617 struct fuse_intr_data d;
2618 struct flock lock;
2619 struct lock l;
Miklos Szeredi0c59ebf2006-09-10 20:53:36 +00002620 char *path;
2621 int err;
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002622 int errlock;
Miklos Szeredi0c59ebf2006-09-10 20:53:36 +00002623
2624 err = -ENOENT;
2625 pthread_rwlock_rdlock(&f->tree_lock);
2626 path = get_path(f, ino);
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002627 if (path && f->conf.debug) {
2628 printf("FLUSH[%llu]\n", (unsigned long long) fi->fh);
2629 fflush(stdout);
Miklos Szeredi0c59ebf2006-09-10 20:53:36 +00002630 }
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002631 fuse_prepare_interrupt(f, req, &d);
2632 if (path)
2633 err = fuse_fs_flush(f->fs, path, fi);
2634
2635 memset(&lock, 0, sizeof(lock));
2636 lock.l_type = F_UNLCK;
2637 lock.l_whence = SEEK_SET;
2638 errlock = fuse_fs_lock(f->fs, path, fi, F_SETLK, &lock);
2639 fuse_finish_interrupt(f, req, &d);
2640 if (errlock != ENOSYS) {
Miklos Szeredi0c59ebf2006-09-10 20:53:36 +00002641 flock_to_lock(&lock, &l);
Miklos Szeredi07407852006-09-30 20:03:52 +00002642 l.owner = fi->lock_owner;
Miklos Szeredi0c59ebf2006-09-10 20:53:36 +00002643 pthread_mutex_lock(&f->lock);
2644 locks_insert(get_node(f, ino), &l);
2645 pthread_mutex_unlock(&f->lock);
2646
2647 /* if op.lock() is defined FLUSH is needed regardless of op.flush() */
2648 if (err == -ENOSYS)
2649 err = 0;
2650 }
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002651 if (path)
2652 free(path);
Miklos Szeredi0c59ebf2006-09-10 20:53:36 +00002653 pthread_rwlock_unlock(&f->tree_lock);
2654 reply_err(req, err);
2655}
2656
Miklos Szeredi9a5c11d2006-07-30 17:33:40 +00002657static int fuse_lock_common(fuse_req_t req, fuse_ino_t ino,
2658 struct fuse_file_info *fi, struct flock *lock,
Miklos Szeredi07407852006-09-30 20:03:52 +00002659 int cmd)
Miklos Szeredi9a5c11d2006-07-30 17:33:40 +00002660{
2661 struct fuse *f = req_fuse_prepare(req);
2662 char *path;
2663 int err;
2664
2665 err = -ENOENT;
2666 pthread_rwlock_rdlock(&f->tree_lock);
2667 path = get_path(f, ino);
2668 if (path != NULL) {
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002669 struct fuse_intr_data d;
2670 fuse_prepare_interrupt(f, req, &d);
2671 err = fuse_fs_lock(f->fs, path, fi, cmd, lock);
2672 fuse_finish_interrupt(f, req, &d);
Miklos Szeredi9a5c11d2006-07-30 17:33:40 +00002673 free(path);
2674 }
2675 pthread_rwlock_unlock(&f->tree_lock);
2676 return err;
2677}
2678
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002679static void fuse_lib_getlk(fuse_req_t req, fuse_ino_t ino,
2680 struct fuse_file_info *fi, struct flock *lock)
Miklos Szeredi9a5c11d2006-07-30 17:33:40 +00002681{
Miklos Szeredi0c59ebf2006-09-10 20:53:36 +00002682 int err;
2683 struct lock l;
2684 struct lock *conflict;
2685 struct fuse *f = req_fuse(req);
2686
2687 flock_to_lock(lock, &l);
Miklos Szeredi07407852006-09-30 20:03:52 +00002688 l.owner = fi->lock_owner;
Miklos Szeredi0c59ebf2006-09-10 20:53:36 +00002689 pthread_mutex_lock(&f->lock);
2690 conflict = locks_conflict(get_node(f, ino), &l);
2691 if (conflict)
2692 lock_to_flock(conflict, lock);
2693 pthread_mutex_unlock(&f->lock);
2694 if (!conflict)
Miklos Szeredi07407852006-09-30 20:03:52 +00002695 err = fuse_lock_common(req, ino, fi, lock, F_GETLK);
Miklos Szeredi0c59ebf2006-09-10 20:53:36 +00002696 else
2697 err = 0;
2698
Miklos Szeredi9a5c11d2006-07-30 17:33:40 +00002699 if (!err)
2700 fuse_reply_lock(req, lock);
2701 else
2702 reply_err(req, err);
2703}
2704
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002705static void fuse_lib_setlk(fuse_req_t req, fuse_ino_t ino,
2706 struct fuse_file_info *fi, struct flock *lock,
2707 int sleep)
Miklos Szeredi9a5c11d2006-07-30 17:33:40 +00002708{
Miklos Szeredi07407852006-09-30 20:03:52 +00002709 int err = fuse_lock_common(req, ino, fi, lock, sleep ? F_SETLKW : F_SETLK);
Miklos Szeredi0c59ebf2006-09-10 20:53:36 +00002710 if (!err) {
2711 struct fuse *f = req_fuse(req);
2712 struct lock l;
2713 flock_to_lock(lock, &l);
Miklos Szeredi07407852006-09-30 20:03:52 +00002714 l.owner = fi->lock_owner;
Miklos Szeredi0c59ebf2006-09-10 20:53:36 +00002715 pthread_mutex_lock(&f->lock);
2716 locks_insert(get_node(f, ino), &l);
2717 pthread_mutex_unlock(&f->lock);
2718 }
2719 reply_err(req, err);
Miklos Szeredi9a5c11d2006-07-30 17:33:40 +00002720}
2721
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002722static void fuse_lib_bmap(fuse_req_t req, fuse_ino_t ino, size_t blocksize,
2723 uint64_t idx)
Miklos Szeredi708b4812006-09-30 16:02:25 +00002724{
2725 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002726 struct fuse_intr_data d;
Miklos Szeredi708b4812006-09-30 16:02:25 +00002727 char *path;
2728 int err;
2729
2730 err = -ENOENT;
2731 pthread_rwlock_rdlock(&f->tree_lock);
2732 path = get_path(f, ino);
2733 if (path != NULL) {
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002734 fuse_prepare_interrupt(f, req, &d);
2735 err = fuse_fs_bmap(f->fs, path, blocksize, &idx);
2736 fuse_finish_interrupt(f, req, &d);
Miklos Szeredi708b4812006-09-30 16:02:25 +00002737 free(path);
2738 }
2739 pthread_rwlock_unlock(&f->tree_lock);
2740 if (!err)
2741 fuse_reply_bmap(req, idx);
2742 else
2743 reply_err(req, err);
2744}
2745
Miklos Szeredia1482422005-08-14 23:00:27 +00002746static struct fuse_lowlevel_ops fuse_path_ops = {
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002747 .init = fuse_lib_init,
2748 .destroy = fuse_lib_destroy,
2749 .lookup = fuse_lib_lookup,
2750 .forget = fuse_lib_forget,
2751 .getattr = fuse_lib_getattr,
2752 .setattr = fuse_lib_setattr,
2753 .access = fuse_lib_access,
2754 .readlink = fuse_lib_readlink,
2755 .mknod = fuse_lib_mknod,
2756 .mkdir = fuse_lib_mkdir,
2757 .unlink = fuse_lib_unlink,
2758 .rmdir = fuse_lib_rmdir,
2759 .symlink = fuse_lib_symlink,
2760 .rename = fuse_lib_rename,
2761 .link = fuse_lib_link,
2762 .create = fuse_lib_create,
2763 .open = fuse_lib_open,
2764 .read = fuse_lib_read,
2765 .write = fuse_lib_write,
2766 .flush = fuse_lib_flush,
2767 .release = fuse_lib_release,
2768 .fsync = fuse_lib_fsync,
2769 .opendir = fuse_lib_opendir,
2770 .readdir = fuse_lib_readdir,
2771 .releasedir = fuse_lib_releasedir,
2772 .fsyncdir = fuse_lib_fsyncdir,
2773 .statfs = fuse_lib_statfs,
2774 .setxattr = fuse_lib_setxattr,
2775 .getxattr = fuse_lib_getxattr,
2776 .listxattr = fuse_lib_listxattr,
2777 .removexattr = fuse_lib_removexattr,
2778 .getlk = fuse_lib_getlk,
2779 .setlk = fuse_lib_setlk,
2780 .bmap = fuse_lib_bmap,
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002781};
2782
Miklos Szeredia1482422005-08-14 23:00:27 +00002783static void free_cmd(struct fuse_cmd *cmd)
2784{
2785 free(cmd->buf);
2786 free(cmd);
2787}
2788
Miklos Szeredif458b8c2004-12-07 16:46:42 +00002789void fuse_process_cmd(struct fuse *f, struct fuse_cmd *cmd)
Miklos Szeredia181e612001-11-06 12:03:23 +00002790{
Miklos Szeredi178451d2005-08-15 13:19:07 +00002791 fuse_session_process(f->se, cmd->buf, cmd->buflen, cmd->ch);
Miklos Szeredifa829b52005-12-02 11:05:41 +00002792 free_cmd(cmd);
Miklos Szeredia181e612001-11-06 12:03:23 +00002793}
2794
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002795int fuse_exited(struct fuse *f)
Miklos Szeredi65cf7c72004-06-30 11:34:56 +00002796{
Miklos Szeredia1482422005-08-14 23:00:27 +00002797 return fuse_session_exited(f->se);
2798}
2799
2800struct fuse_session *fuse_get_session(struct fuse *f)
2801{
2802 return f->se;
2803}
2804
2805static struct fuse_cmd *fuse_alloc_cmd(size_t bufsize)
2806{
2807 struct fuse_cmd *cmd = (struct fuse_cmd *) malloc(sizeof(*cmd));
2808 if (cmd == NULL) {
2809 fprintf(stderr, "fuse: failed to allocate cmd\n");
2810 return NULL;
2811 }
2812 cmd->buf = (char *) malloc(bufsize);
2813 if (cmd->buf == NULL) {
2814 fprintf(stderr, "fuse: failed to allocate read buffer\n");
2815 free(cmd);
2816 return NULL;
2817 }
2818 return cmd;
Miklos Szeredi65cf7c72004-06-30 11:34:56 +00002819}
2820
Miklos Szeredif458b8c2004-12-07 16:46:42 +00002821struct fuse_cmd *fuse_read_cmd(struct fuse *f)
Miklos Szeredi2df1c042001-11-06 15:07:17 +00002822{
Miklos Szeredia1482422005-08-14 23:00:27 +00002823 struct fuse_chan *ch = fuse_session_next_chan(f->se, NULL);
2824 size_t bufsize = fuse_chan_bufsize(ch);
2825 struct fuse_cmd *cmd = fuse_alloc_cmd(bufsize);
2826 if (cmd != NULL) {
Miklos Szeredi8d975f62006-03-17 15:56:05 +00002827 int res = fuse_chan_recv(&ch, cmd->buf, bufsize);
Miklos Szeredia1482422005-08-14 23:00:27 +00002828 if (res <= 0) {
2829 free_cmd(cmd);
Miklos Szeredi5d9ce362006-03-01 12:10:13 +00002830 if (res < 0 && res != -EINTR && res != -EAGAIN)
Miklos Szeredifa829b52005-12-02 11:05:41 +00002831 fuse_exit(f);
Miklos Szeredia1482422005-08-14 23:00:27 +00002832 return NULL;
2833 }
2834 cmd->buflen = res;
Miklos Szeredi178451d2005-08-15 13:19:07 +00002835 cmd->ch = ch;
Miklos Szeredia1482422005-08-14 23:00:27 +00002836 }
2837 return cmd;
Miklos Szeredi2df1c042001-11-06 15:07:17 +00002838}
2839
Miklos Szeredib2cf9562004-09-16 08:42:40 +00002840int fuse_loop(struct fuse *f)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00002841{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002842 if (f)
Miklos Szeredia1482422005-08-14 23:00:27 +00002843 return fuse_session_loop(f->se);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002844 else
Miklos Szeredib2cf9562004-09-16 08:42:40 +00002845 return -1;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00002846}
2847
Miklos Szeredi891b8742004-07-29 09:27:49 +00002848int fuse_invalidate(struct fuse *f, const char *path)
2849{
Miklos Szeredie56818b2004-12-12 11:45:24 +00002850 (void) f;
2851 (void) path;
2852 return -EINVAL;
Miklos Szeredi891b8742004-07-29 09:27:49 +00002853}
2854
Miklos Szeredi0f48a262002-12-05 14:23:01 +00002855void fuse_exit(struct fuse *f)
2856{
Miklos Szeredia1482422005-08-14 23:00:27 +00002857 fuse_session_exit(f->se);
Miklos Szeredi0f48a262002-12-05 14:23:01 +00002858}
2859
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002860struct fuse_context *fuse_get_context(void)
Miklos Szeredi2e50d432001-12-20 12:17:25 +00002861{
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002862 return &fuse_get_context_internal()->ctx;
2863}
2864
2865int fuse_interrupted(void)
2866{
2867 return fuse_req_interrupted(fuse_get_context_internal()->req);
Miklos Szeredid169f312004-09-22 08:48:26 +00002868}
2869
Miklos Szeredif458b8c2004-12-07 16:46:42 +00002870void fuse_set_getcontext_func(struct fuse_context *(*func)(void))
Miklos Szeredid169f312004-09-22 08:48:26 +00002871{
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002872 (void) func;
2873 /* no-op */
Miklos Szeredi2e50d432001-12-20 12:17:25 +00002874}
2875
Miklos Szerediad005972006-01-07 10:14:34 +00002876enum {
2877 KEY_HELP,
Miklos Szerediad005972006-01-07 10:14:34 +00002878};
2879
Miklos Szeredi659743b2005-12-09 17:41:42 +00002880#define FUSE_LIB_OPT(t, p, v) { t, offsetof(struct fuse_config, p), v }
2881
2882static const struct fuse_opt fuse_lib_opts[] = {
Miklos Szerediad005972006-01-07 10:14:34 +00002883 FUSE_OPT_KEY("-h", KEY_HELP),
2884 FUSE_OPT_KEY("--help", KEY_HELP),
Miklos Szeredi065f2222006-01-20 15:15:21 +00002885 FUSE_OPT_KEY("debug", FUSE_OPT_KEY_KEEP),
2886 FUSE_OPT_KEY("-d", FUSE_OPT_KEY_KEEP),
Miklos Szeredi659743b2005-12-09 17:41:42 +00002887 FUSE_LIB_OPT("debug", debug, 1),
Miklos Szeredi95da8602006-01-06 18:29:40 +00002888 FUSE_LIB_OPT("-d", debug, 1),
Miklos Szeredi659743b2005-12-09 17:41:42 +00002889 FUSE_LIB_OPT("hard_remove", hard_remove, 1),
2890 FUSE_LIB_OPT("use_ino", use_ino, 1),
2891 FUSE_LIB_OPT("readdir_ino", readdir_ino, 1),
2892 FUSE_LIB_OPT("direct_io", direct_io, 1),
2893 FUSE_LIB_OPT("kernel_cache", kernel_cache, 1),
Miklos Szeredi320abe42006-01-30 18:14:51 +00002894 FUSE_LIB_OPT("auto_cache", auto_cache, 1),
2895 FUSE_LIB_OPT("noauto_cache", auto_cache, 0),
Miklos Szeredi659743b2005-12-09 17:41:42 +00002896 FUSE_LIB_OPT("umask=", set_mode, 1),
2897 FUSE_LIB_OPT("umask=%o", umask, 0),
2898 FUSE_LIB_OPT("uid=", set_uid, 1),
2899 FUSE_LIB_OPT("uid=%d", uid, 0),
2900 FUSE_LIB_OPT("gid=", set_gid, 1),
2901 FUSE_LIB_OPT("gid=%d", gid, 0),
2902 FUSE_LIB_OPT("entry_timeout=%lf", entry_timeout, 0),
2903 FUSE_LIB_OPT("attr_timeout=%lf", attr_timeout, 0),
Miklos Szeredi6e806e92006-02-16 16:59:39 +00002904 FUSE_LIB_OPT("ac_attr_timeout=%lf", ac_attr_timeout, 0),
2905 FUSE_LIB_OPT("ac_attr_timeout=", ac_attr_timeout_set, 1),
Miklos Szeredi659743b2005-12-09 17:41:42 +00002906 FUSE_LIB_OPT("negative_timeout=%lf", negative_timeout, 0),
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002907 FUSE_LIB_OPT("intr", intr, 1),
2908 FUSE_LIB_OPT("intr_signal=%d", intr_signal, 0),
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002909 FUSE_LIB_OPT("modules=%s", modules, 0),
Miklos Szeredi659743b2005-12-09 17:41:42 +00002910 FUSE_OPT_END
2911};
2912
Miklos Szerediad005972006-01-07 10:14:34 +00002913static void fuse_lib_help(void)
2914{
2915 fprintf(stderr,
Miklos Szeredi06091462006-02-16 16:38:34 +00002916" -o hard_remove immediate removal (don't hide files)\n"
2917" -o use_ino let filesystem set inode numbers\n"
2918" -o readdir_ino try to fill in d_ino in readdir\n"
2919" -o direct_io use direct I/O\n"
2920" -o kernel_cache cache files in kernel\n"
2921" -o [no]auto_cache enable caching based on modification times\n"
2922" -o umask=M set file permissions (octal)\n"
2923" -o uid=N set file owner\n"
2924" -o gid=N set file group\n"
2925" -o entry_timeout=T cache timeout for names (1.0s)\n"
2926" -o negative_timeout=T cache timeout for deleted names (0.0s)\n"
Miklos Szeredi6e806e92006-02-16 16:59:39 +00002927" -o attr_timeout=T cache timeout for attributes (1.0s)\n"
2928" -o ac_attr_timeout=T auto cache timeout for attributes (attr_timeout)\n"
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002929" -o intr allow requests to be interrupted\n"
2930" -o intr_signal=NUM signal to send on interrupt (%i)\n"
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002931" -o modules=M1[:M2...] names of modules to push onto filesystem stack\n"
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002932"\n", FUSE_DEFAULT_INTR_SIGNAL);
Miklos Szerediad005972006-01-07 10:14:34 +00002933}
2934
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002935static void fuse_lib_help_modules(void)
2936{
2937 struct fuse_module *m;
2938 fprintf(stderr, "\nModule options:\n");
2939 pthread_mutex_lock(&fuse_context_lock);
2940 for (m = fuse_modules; m; m = m->next) {
2941 struct fuse_fs *fs = NULL;
2942 struct fuse_fs *newfs;
2943 struct fuse_args args = FUSE_ARGS_INIT(0, NULL);
2944 if (fuse_opt_add_arg(&args, "") != -1 &&
2945 fuse_opt_add_arg(&args, "-h") != -1) {
2946 fprintf(stderr, "\n[%s]\n", m->name);
2947 newfs = m->factory(&args, &fs);
2948 assert(newfs == NULL);
2949 }
2950 fuse_opt_free_args(&args);
2951 }
2952 pthread_mutex_unlock(&fuse_context_lock);
2953}
2954
Miklos Szerediad005972006-01-07 10:14:34 +00002955static int fuse_lib_opt_proc(void *data, const char *arg, int key,
2956 struct fuse_args *outargs)
2957{
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002958 (void) arg; (void) outargs;
Miklos Szerediad005972006-01-07 10:14:34 +00002959
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002960 if (key == KEY_HELP) {
2961 struct fuse_config *conf = (struct fuse_config *) data;
Miklos Szerediad005972006-01-07 10:14:34 +00002962 fuse_lib_help();
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002963 conf->help = 1;
2964 }
Miklos Szerediad005972006-01-07 10:14:34 +00002965
2966 return 1;
2967}
2968
Miklos Szeredibd7661b2004-07-23 17:16:29 +00002969int fuse_is_lib_option(const char *opt)
2970{
Miklos Szeredi659743b2005-12-09 17:41:42 +00002971 return fuse_lowlevel_is_lib_option(opt) ||
2972 fuse_opt_match(fuse_lib_opts, opt);
Miklos Szeredibd7661b2004-07-23 17:16:29 +00002973}
2974
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002975static int fuse_init_intr_signal(int signum, int *installed)
2976{
2977 struct sigaction old_sa;
2978
2979 if (sigaction(signum, NULL, &old_sa) == -1) {
2980 perror("fuse: cannot get old signal handler");
2981 return -1;
2982 }
2983
2984 if (old_sa.sa_handler == SIG_DFL) {
2985 struct sigaction sa;
2986
2987 memset(&sa, 0, sizeof(struct sigaction));
2988 sa.sa_handler = fuse_intr_sighandler;
Miklos Szeredi0c59ebf2006-09-10 20:53:36 +00002989 sigemptyset(&sa.sa_mask);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002990
2991 if (sigaction(signum, &sa, NULL) == -1) {
2992 perror("fuse: cannot set interrupt signal handler");
2993 return -1;
2994 }
2995 *installed = 1;
2996 }
2997 return 0;
2998}
2999
Miklos Szeredi349bdda2006-09-07 11:48:16 +00003000static void fuse_restore_intr_signal(int signum)
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00003001{
Miklos Szeredi349bdda2006-09-07 11:48:16 +00003002 struct sigaction sa;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00003003
Miklos Szeredi349bdda2006-09-07 11:48:16 +00003004 memset(&sa, 0, sizeof(struct sigaction));
3005 sa.sa_handler = SIG_DFL;
3006 sigaction(signum, &sa, NULL);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00003007}
3008
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00003009
3010static int fuse_push_module(struct fuse *f, const char *module,
3011 struct fuse_args *args)
3012{
3013 struct fuse_fs *fs[2] = { f->fs, NULL };
3014 struct fuse_fs *newfs;
3015 struct fuse_module *m = fuse_get_module(module);
3016
3017 if (!m)
3018 return -1;
3019
3020 newfs = m->factory(args, fs);
3021 if (!newfs) {
3022 fuse_put_module(m);
3023 return -1;
3024 }
3025 newfs->m = m;
3026 f->fs = newfs;
3027 return 0;
3028}
3029
3030struct fuse_fs *fuse_fs_new(const struct fuse_operations *op, size_t op_size,
3031 void *user_data)
3032{
3033 struct fuse_fs *fs;
3034
3035 if (sizeof(struct fuse_operations) < op_size) {
3036 fprintf(stderr, "fuse: warning: library too old, some operations may not not work\n");
3037 op_size = sizeof(struct fuse_operations);
3038 }
3039
3040 fs = (struct fuse_fs *) calloc(1, sizeof(struct fuse_fs));
3041 if (!fs) {
3042 fprintf(stderr, "fuse: failed to allocate fuse_fs object\n");
3043 return NULL;
3044 }
3045
3046 fs->user_data = user_data;
3047 memcpy(&fs->op, op, op_size);
3048 return fs;
3049}
3050
Miklos Szeredi6f385412006-03-17 15:05:40 +00003051struct fuse *fuse_new_common(struct fuse_chan *ch, struct fuse_args *args,
Miklos Szeredi0b6a0ad2004-12-04 00:40:50 +00003052 const struct fuse_operations *op,
Miklos Szeredi6f385412006-03-17 15:05:40 +00003053 size_t op_size, void *user_data, int compat)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00003054{
Miklos Szeredi97c61e92001-11-07 12:09:43 +00003055 struct fuse *f;
3056 struct node *root;
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00003057 struct fuse_fs *fs;
Miklos Szeredi9a5c11d2006-07-30 17:33:40 +00003058 struct fuse_lowlevel_ops llop = fuse_path_ops;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00003059
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00003060 if (fuse_create_context_key() == -1)
3061 goto out;
3062
Miklos Szeredi97c61e92001-11-07 12:09:43 +00003063 f = (struct fuse *) calloc(1, sizeof(struct fuse));
Miklos Szeredie56818b2004-12-12 11:45:24 +00003064 if (f == NULL) {
3065 fprintf(stderr, "fuse: failed to allocate fuse object\n");
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00003066 goto out_delete_context_key;
Miklos Szeredie56818b2004-12-12 11:45:24 +00003067 }
Miklos Szeredi2df1c042001-11-06 15:07:17 +00003068
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00003069 fs = fuse_fs_new(op, op_size, user_data);
3070 if (!fs)
3071 goto out_free;
3072
3073 fs->compat = compat;
3074 f->fs = fs;
3075
3076 /* Oh f**k, this is ugly! */
3077 if (!fs->op.lock) {
3078 llop.getlk = NULL;
3079 llop.setlk = NULL;
3080 }
3081
Miklos Szeredi659743b2005-12-09 17:41:42 +00003082 f->conf.entry_timeout = 1.0;
3083 f->conf.attr_timeout = 1.0;
3084 f->conf.negative_timeout = 0.0;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00003085 f->conf.intr_signal = FUSE_DEFAULT_INTR_SIGNAL;
Miklos Szeredi6c0209a2005-08-02 13:31:28 +00003086
Miklos Szerediad005972006-01-07 10:14:34 +00003087 if (fuse_opt_parse(args, &f->conf, fuse_lib_opts, fuse_lib_opt_proc) == -1)
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00003088 goto out_free_fs;
3089
3090 if (f->conf.modules) {
3091 char *module;
3092 char *next;
3093
3094 for (module = f->conf.modules; module; module = next) {
3095 char *p;
3096 for (p = module; *p && *p != ':'; p++);
3097 next = *p ? p + 1 : NULL;
3098 *p = '\0';
3099 if (module[0] && fuse_push_module(f, module, args) == -1)
3100 goto out_free_fs;
3101 }
3102 }
Miklos Szeredib2cf9562004-09-16 08:42:40 +00003103
Miklos Szeredi6e806e92006-02-16 16:59:39 +00003104 if (!f->conf.ac_attr_timeout_set)
3105 f->conf.ac_attr_timeout = f->conf.attr_timeout;
3106
Miklos Szeredi659743b2005-12-09 17:41:42 +00003107#ifdef __FreeBSD__
3108 /*
3109 * In FreeBSD, we always use these settings as inode numbers are needed to
3110 * make getcwd(3) work.
3111 */
Miklos Szeredi76fc3de2005-12-12 09:34:45 +00003112 f->conf.readdir_ino = 1;
Miklos Szeredi659743b2005-12-09 17:41:42 +00003113#endif
3114
Miklos Szeredi065f2222006-01-20 15:15:21 +00003115 if (compat && compat <= 25) {
3116 if (fuse_sync_compat_args(args) == -1)
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00003117 goto out_free_fs;
Miklos Szeredi9a5c11d2006-07-30 17:33:40 +00003118 }
3119
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00003120 f->se = fuse_lowlevel_new_common(args, &llop, sizeof(llop), f);
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00003121 if (f->se == NULL) {
3122 if (f->conf.help)
3123 fuse_lib_help_modules();
3124 goto out_free_fs;
3125 }
Miklos Szeredi2bb750e2005-10-03 14:54:24 +00003126
Miklos Szeredia1482422005-08-14 23:00:27 +00003127 fuse_session_add_chan(f->se, ch);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00003128
Miklos Szeredi97c61e92001-11-07 12:09:43 +00003129 f->ctr = 0;
Miklos Szeredi76f65782004-02-19 16:55:40 +00003130 f->generation = 0;
Miklos Szeredifff56ab2001-11-16 10:12:59 +00003131 /* FIXME: Dynamic hash table */
Miklos Szeredi97c61e92001-11-07 12:09:43 +00003132 f->name_table_size = 14057;
3133 f->name_table = (struct node **)
3134 calloc(1, sizeof(struct node *) * f->name_table_size);
Miklos Szeredie56818b2004-12-12 11:45:24 +00003135 if (f->name_table == NULL) {
3136 fprintf(stderr, "fuse: memory allocation failed\n");
Miklos Szeredia1482422005-08-14 23:00:27 +00003137 goto out_free_session;
Miklos Szeredie56818b2004-12-12 11:45:24 +00003138 }
Miklos Szeredib2cf9562004-09-16 08:42:40 +00003139
Miklos Szeredia13d9002004-11-02 17:32:03 +00003140 f->id_table_size = 14057;
3141 f->id_table = (struct node **)
3142 calloc(1, sizeof(struct node *) * f->id_table_size);
Miklos Szeredie56818b2004-12-12 11:45:24 +00003143 if (f->id_table == NULL) {
3144 fprintf(stderr, "fuse: memory allocation failed\n");
Miklos Szeredib2cf9562004-09-16 08:42:40 +00003145 goto out_free_name_table;
Miklos Szeredie56818b2004-12-12 11:45:24 +00003146 }
Miklos Szeredib2cf9562004-09-16 08:42:40 +00003147
Miklos Szeredi38f152c2006-09-03 18:28:52 +00003148 fuse_mutex_init(&f->lock);
Miklos Szeredid0a777a2006-04-05 07:18:00 +00003149 pthread_rwlock_init(&f->tree_lock, NULL);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00003150
Miklos Szeredi97c61e92001-11-07 12:09:43 +00003151 root = (struct node *) calloc(1, sizeof(struct node));
Miklos Szeredie56818b2004-12-12 11:45:24 +00003152 if (root == NULL) {
3153 fprintf(stderr, "fuse: memory allocation failed\n");
Miklos Szeredia13d9002004-11-02 17:32:03 +00003154 goto out_free_id_table;
Miklos Szeredie56818b2004-12-12 11:45:24 +00003155 }
Miklos Szeredib2cf9562004-09-16 08:42:40 +00003156
Miklos Szeredi97c61e92001-11-07 12:09:43 +00003157 root->name = strdup("/");
Miklos Szeredie56818b2004-12-12 11:45:24 +00003158 if (root->name == NULL) {
3159 fprintf(stderr, "fuse: memory allocation failed\n");
Miklos Szeredib2cf9562004-09-16 08:42:40 +00003160 goto out_free_root;
Miklos Szeredie56818b2004-12-12 11:45:24 +00003161 }
Miklos Szeredib2cf9562004-09-16 08:42:40 +00003162
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00003163 if (f->conf.intr &&
3164 fuse_init_intr_signal(f->conf.intr_signal, &f->intr_installed) == -1)
3165 goto out_free_root_name;
3166
Miklos Szeredi97c61e92001-11-07 12:09:43 +00003167 root->parent = 0;
Miklos Szeredia13d9002004-11-02 17:32:03 +00003168 root->nodeid = FUSE_ROOT_ID;
Miklos Szeredi76f65782004-02-19 16:55:40 +00003169 root->generation = 0;
Miklos Szeredi0f62d722005-01-04 12:45:54 +00003170 root->refctr = 1;
Miklos Szeredi38009022005-05-08 19:47:22 +00003171 root->nlookup = 1;
Miklos Szeredia13d9002004-11-02 17:32:03 +00003172 hash_id(f, root);
Miklos Szeredi97c61e92001-11-07 12:09:43 +00003173
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00003174 return f;
Miklos Szeredib2cf9562004-09-16 08:42:40 +00003175
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00003176 out_free_root_name:
3177 free(root->name);
Miklos Szeredib2cf9562004-09-16 08:42:40 +00003178 out_free_root:
3179 free(root);
Miklos Szeredia13d9002004-11-02 17:32:03 +00003180 out_free_id_table:
3181 free(f->id_table);
Miklos Szeredib2cf9562004-09-16 08:42:40 +00003182 out_free_name_table:
3183 free(f->name_table);
Miklos Szeredia1482422005-08-14 23:00:27 +00003184 out_free_session:
3185 fuse_session_destroy(f->se);
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00003186 out_free_fs:
3187 /* Horrible compatibility hack to stop the destructor from being
3188 called on the filesystem without init being called first */
3189 fs->op.destroy = NULL;
3190 fuse_fs_destroy(f->fs);
Miklos Szeredib2cf9562004-09-16 08:42:40 +00003191 out_free:
3192 free(f);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00003193 out_delete_context_key:
3194 fuse_delete_context_key();
Miklos Szeredib2cf9562004-09-16 08:42:40 +00003195 out:
Miklos Szeredib2cf9562004-09-16 08:42:40 +00003196 return NULL;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00003197}
3198
Miklos Szeredi6f385412006-03-17 15:05:40 +00003199struct fuse *fuse_new(struct fuse_chan *ch, struct fuse_args *args,
3200 const struct fuse_operations *op, size_t op_size,
3201 void *user_data)
Miklos Szeredi0b6a0ad2004-12-04 00:40:50 +00003202{
Miklos Szeredi6f385412006-03-17 15:05:40 +00003203 return fuse_new_common(ch, args, op, op_size, user_data, 0);
Miklos Szeredi0b6a0ad2004-12-04 00:40:50 +00003204}
3205
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00003206void fuse_destroy(struct fuse *f)
3207{
Miklos Szeredi97c61e92001-11-07 12:09:43 +00003208 size_t i;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00003209
3210 if (f->conf.intr && f->intr_installed)
3211 fuse_restore_intr_signal(f->conf.intr_signal);
Miklos Szerediad519562006-07-31 11:07:40 +00003212
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00003213 if (f->fs) {
3214 struct fuse_context_i *c = fuse_get_context_internal();
Miklos Szerediad519562006-07-31 11:07:40 +00003215
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00003216 memset(c, 0, sizeof(*c));
3217 c->ctx.fuse = f;
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00003218
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00003219 for (i = 0; i < f->id_table_size; i++) {
3220 struct node *node;
3221
3222 for (node = f->id_table[i]; node != NULL; node = node->id_next) {
3223 if (node->is_hidden) {
3224 char *path = get_path(f, node->nodeid);
3225 if (path) {
3226 fuse_fs_unlink(f->fs, path);
3227 free(path);
3228 }
Miklos Szeredi21019c92005-05-09 11:22:41 +00003229 }
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00003230 }
3231 }
3232 }
Miklos Szeredia13d9002004-11-02 17:32:03 +00003233 for (i = 0; i < f->id_table_size; i++) {
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00003234 struct node *node;
Miklos Szeredi97c61e92001-11-07 12:09:43 +00003235 struct node *next;
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00003236
Miklos Szeredia13d9002004-11-02 17:32:03 +00003237 for (node = f->id_table[i]; node != NULL; node = next) {
3238 next = node->id_next;
Miklos Szeredi97c61e92001-11-07 12:09:43 +00003239 free_node(node);
3240 }
3241 }
Miklos Szeredia13d9002004-11-02 17:32:03 +00003242 free(f->id_table);
Miklos Szeredi97c61e92001-11-07 12:09:43 +00003243 free(f->name_table);
Miklos Szeredia181e612001-11-06 12:03:23 +00003244 pthread_mutex_destroy(&f->lock);
Miklos Szeredi55a84102006-06-06 10:16:38 +00003245 pthread_rwlock_destroy(&f->tree_lock);
Miklos Szeredia1482422005-08-14 23:00:27 +00003246 fuse_session_destroy(f->se);
Miklos Szeredi97c61e92001-11-07 12:09:43 +00003247 free(f);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00003248 fuse_delete_context_key();
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00003249}
Miklos Szeredi0b6a0ad2004-12-04 00:40:50 +00003250
Miklos Szeredi6f385412006-03-17 15:05:40 +00003251static struct fuse *fuse_new_common_compat25(int fd, struct fuse_args *args,
3252 const struct fuse_operations *op,
3253 size_t op_size, int compat)
3254{
3255 struct fuse *f = NULL;
3256 struct fuse_chan *ch = fuse_kern_chan_new(fd);
3257
3258 if (ch)
3259 f = fuse_new_common(ch, args, op, op_size, NULL, compat);
3260
3261 return f;
3262}
3263
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00003264/* called with fuse_context_lock held or during initialization (before
3265 main() has been called) */
3266void fuse_register_module(struct fuse_module *mod)
3267{
Miklos Szeredi2f759e12007-03-14 09:13:27 +00003268 mod->ctr = 0;
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00003269 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");