blob: 817b16f6b3a53236fe7acbb0900d6cf832ae16c1 [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_fsync(fuse_req_t req, fuse_ino_t ino, int datasync,
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002029 struct fuse_file_info *fi)
Miklos Szeredi5e183482001-10-31 14:52:35 +00002030{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002031 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredi5e183482001-10-31 14:52:35 +00002032 char *path;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002033 int err;
Miklos Szerediab974562005-04-07 15:40:21 +00002034
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002035 err = -ENOENT;
2036 pthread_rwlock_rdlock(&f->tree_lock);
2037 path = get_path(f, ino);
2038 if (path != NULL) {
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002039 struct fuse_intr_data d;
Miklos Szeredi659743b2005-12-09 17:41:42 +00002040 if (f->conf.debug) {
Miklos Szeredi3a770472005-11-11 21:32:42 +00002041 printf("FSYNC[%llu]\n", (unsigned long long) fi->fh);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002042 fflush(stdout);
2043 }
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002044 fuse_prepare_interrupt(f, req, &d);
2045 err = fuse_fs_fsync(f->fs, path, datasync, fi);
2046 fuse_finish_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002047 free(path);
2048 }
2049 pthread_rwlock_unlock(&f->tree_lock);
2050 reply_err(req, err);
2051}
2052
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002053static struct fuse_dh *get_dirhandle(const struct fuse_file_info *llfi,
2054 struct fuse_file_info *fi)
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002055{
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002056 struct fuse_dh *dh = (struct fuse_dh *) (uintptr_t) llfi->fh;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002057 memset(fi, 0, sizeof(struct fuse_file_info));
2058 fi->fh = dh->fh;
Miklos Szerediead7f102005-11-28 16:02:27 +00002059 fi->fh_old = dh->fh;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002060 return dh;
2061}
2062
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002063static void fuse_lib_opendir(fuse_req_t req, fuse_ino_t ino,
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002064 struct fuse_file_info *llfi)
2065{
2066 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002067 struct fuse_intr_data d;
2068 struct fuse_dh *dh;
2069 struct fuse_file_info fi;
2070 char *path;
2071 int err;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002072
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002073 dh = (struct fuse_dh *) malloc(sizeof(struct fuse_dh));
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002074 if (dh == NULL) {
2075 reply_err(req, -ENOMEM);
Miklos Szerediab974562005-04-07 15:40:21 +00002076 return;
Miklos Szeredi5e183482001-10-31 14:52:35 +00002077 }
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002078 memset(dh, 0, sizeof(struct fuse_dh));
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002079 dh->fuse = f;
2080 dh->contents = NULL;
2081 dh->len = 0;
2082 dh->filled = 0;
2083 dh->nodeid = ino;
Miklos Szeredi38f152c2006-09-03 18:28:52 +00002084 fuse_mutex_init(&dh->lock);
Miklos Szerediab974562005-04-07 15:40:21 +00002085
Miklos Szeredi3a770472005-11-11 21:32:42 +00002086 llfi->fh = (uintptr_t) dh;
Miklos Szerediab974562005-04-07 15:40:21 +00002087
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002088 memset(&fi, 0, sizeof(fi));
2089 fi.flags = llfi->flags;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002090
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002091 err = -ENOENT;
2092 pthread_rwlock_rdlock(&f->tree_lock);
2093 path = get_path(f, ino);
2094 if (path != NULL) {
2095 fuse_prepare_interrupt(f, req, &d);
2096 err = fuse_fs_opendir(f->fs, path, &fi);
2097 fuse_finish_interrupt(f, req, &d);
2098 dh->fh = fi.fh;
2099 }
2100 if (!err) {
2101 if (fuse_reply_open(req, llfi) == -ENOENT) {
2102 /* The opendir syscall was interrupted, so it must be cancelled */
2103 fuse_prepare_interrupt(f, req, &d);
2104 fuse_fs_releasedir(f->fs, path, &fi);
2105 fuse_finish_interrupt(f, req, &d);
2106 pthread_mutex_destroy(&dh->lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002107 free(dh);
2108 }
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002109 } else {
2110 reply_err(req, err);
2111 free(dh);
2112 }
2113 free(path);
2114 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredi5e183482001-10-31 14:52:35 +00002115}
Miklos Szeredib483c932001-10-29 14:57:57 +00002116
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002117static int extend_contents(struct fuse_dh *dh, unsigned minsize)
Miklos Szeredi1bf64f42006-02-17 15:49:25 +00002118{
2119 if (minsize > dh->size) {
2120 char *newptr;
2121 unsigned newsize = dh->size;
2122 if (!newsize)
2123 newsize = 1024;
2124 while (newsize < minsize)
2125 newsize *= 2;
2126
2127 newptr = (char *) realloc(dh->contents, newsize);
2128 if (!newptr) {
2129 dh->error = -ENOMEM;
2130 return -1;
2131 }
2132 dh->contents = newptr;
2133 dh->size = newsize;
2134 }
2135 return 0;
2136}
2137
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002138static int fill_dir(void *dh_, const char *name, const struct stat *statp,
2139 off_t off)
Miklos Szeredia181e612001-11-06 12:03:23 +00002140{
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002141 struct fuse_dh *dh = (struct fuse_dh *) dh_;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002142 struct stat stbuf;
Miklos Szeredi1bf64f42006-02-17 15:49:25 +00002143 size_t newlen;
Miklos Szeredifb28c5e2004-11-26 12:15:06 +00002144
Miklos Szeredif6e0ec62005-08-03 09:11:06 +00002145 if (statp)
2146 stbuf = *statp;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002147 else {
2148 memset(&stbuf, 0, sizeof(stbuf));
Miklos Szeredie248e4b2005-12-14 16:18:32 +00002149 stbuf.st_ino = FUSE_UNKNOWN_INO;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002150 }
Miklos Szeredia181e612001-11-06 12:03:23 +00002151
Miklos Szeredi659743b2005-12-09 17:41:42 +00002152 if (!dh->fuse->conf.use_ino) {
Miklos Szeredie248e4b2005-12-14 16:18:32 +00002153 stbuf.st_ino = FUSE_UNKNOWN_INO;
Miklos Szeredi659743b2005-12-09 17:41:42 +00002154 if (dh->fuse->conf.readdir_ino) {
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002155 struct node *node;
2156 pthread_mutex_lock(&dh->fuse->lock);
2157 node = lookup_node(dh->fuse, dh->nodeid, name);
2158 if (node)
2159 stbuf.st_ino = (ino_t) node->nodeid;
2160 pthread_mutex_unlock(&dh->fuse->lock);
Miklos Szeredi6ebe2342002-01-06 21:44:16 +00002161 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002162 }
Miklos Szeredi6ebe2342002-01-06 21:44:16 +00002163
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002164 if (off) {
Miklos Szeredi1bf64f42006-02-17 15:49:25 +00002165 if (extend_contents(dh, dh->needlen) == -1)
2166 return 1;
2167
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002168 dh->filled = 0;
Miklos Szeredi1bf64f42006-02-17 15:49:25 +00002169 newlen = dh->len + fuse_add_direntry(dh->req, dh->contents + dh->len,
2170 dh->needlen - dh->len, name,
2171 &stbuf, off);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002172 if (newlen > dh->needlen)
2173 return 1;
Miklos Szeredi1bf64f42006-02-17 15:49:25 +00002174 } else {
2175 newlen = dh->len + fuse_add_direntry(dh->req, NULL, 0, name, NULL, 0);
2176 if (extend_contents(dh, newlen) == -1)
Miklos Szeredic4c12ae2005-10-20 14:48:50 +00002177 return 1;
Miklos Szeredi1bf64f42006-02-17 15:49:25 +00002178
2179 fuse_add_direntry(dh->req, dh->contents + dh->len, dh->size - dh->len,
2180 name, &stbuf, newlen);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002181 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002182 dh->len = newlen;
2183 return 0;
2184}
2185
Miklos Szeredi1bf64f42006-02-17 15:49:25 +00002186static int readdir_fill(struct fuse *f, fuse_req_t req, fuse_ino_t ino,
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002187 size_t size, off_t off, struct fuse_dh *dh,
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002188 struct fuse_file_info *fi)
2189{
2190 int err = -ENOENT;
2191 char *path;
2192 pthread_rwlock_rdlock(&f->tree_lock);
2193 path = get_path(f, ino);
2194 if (path != NULL) {
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002195 struct fuse_intr_data d;
2196
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002197 dh->len = 0;
2198 dh->error = 0;
2199 dh->needlen = size;
2200 dh->filled = 1;
Miklos Szeredi1bf64f42006-02-17 15:49:25 +00002201 dh->req = req;
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002202 fuse_prepare_interrupt(f, req, &d);
2203 err = fuse_fs_readdir(f->fs, path, dh, fill_dir, off, fi);
2204 fuse_finish_interrupt(f, req, &d);
Miklos Szeredi1bf64f42006-02-17 15:49:25 +00002205 dh->req = NULL;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002206 if (!err)
2207 err = dh->error;
2208 if (err)
2209 dh->filled = 0;
Miklos Szeredi97c61e92001-11-07 12:09:43 +00002210 free(path);
Miklos Szeredia181e612001-11-06 12:03:23 +00002211 }
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00002212 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002213 return err;
2214}
Miklos Szeredie5183742005-02-02 11:14:04 +00002215
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002216static void fuse_lib_readdir(fuse_req_t req, fuse_ino_t ino, size_t size,
2217 off_t off, struct fuse_file_info *llfi)
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002218{
2219 struct fuse *f = req_fuse_prepare(req);
2220 struct fuse_file_info fi;
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002221 struct fuse_dh *dh = get_dirhandle(llfi, &fi);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002222
2223 pthread_mutex_lock(&dh->lock);
Miklos Szeredi77ccf652005-08-19 14:40:27 +00002224 /* According to SUS, directory contents need to be refreshed on
2225 rewinddir() */
2226 if (!off)
2227 dh->filled = 0;
2228
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002229 if (!dh->filled) {
Miklos Szeredi1bf64f42006-02-17 15:49:25 +00002230 int err = readdir_fill(f, req, ino, size, off, dh, &fi);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002231 if (err) {
2232 reply_err(req, err);
2233 goto out;
2234 }
Miklos Szeredia181e612001-11-06 12:03:23 +00002235 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002236 if (dh->filled) {
2237 if (off < dh->len) {
2238 if (off + size > dh->len)
2239 size = dh->len - off;
2240 } else
2241 size = 0;
2242 } else {
2243 size = dh->len;
2244 off = 0;
2245 }
2246 fuse_reply_buf(req, dh->contents + off, size);
2247 out:
2248 pthread_mutex_unlock(&dh->lock);
2249}
Miklos Szeredia181e612001-11-06 12:03:23 +00002250
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002251static void fuse_lib_releasedir(fuse_req_t req, fuse_ino_t ino,
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002252 struct fuse_file_info *llfi)
2253{
2254 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002255 struct fuse_intr_data d;
Miklos Szeredi9b813af2005-07-21 07:59:37 +00002256 struct fuse_file_info fi;
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002257 struct fuse_dh *dh = get_dirhandle(llfi, &fi);
2258 char *path;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002259
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002260 pthread_rwlock_rdlock(&f->tree_lock);
2261 path = get_path(f, ino);
2262 fuse_prepare_interrupt(f, req, &d);
2263 fuse_fs_releasedir(f->fs, path ? path : "-", &fi);
2264 fuse_finish_interrupt(f, req, &d);
2265 if (path)
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002266 free(path);
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002267 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002268 pthread_mutex_lock(&dh->lock);
2269 pthread_mutex_unlock(&dh->lock);
2270 pthread_mutex_destroy(&dh->lock);
2271 free(dh->contents);
2272 free(dh);
2273 reply_err(req, 0);
2274}
2275
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002276static void fuse_lib_fsyncdir(fuse_req_t req, fuse_ino_t ino, int datasync,
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002277 struct fuse_file_info *llfi)
2278{
2279 struct fuse *f = req_fuse_prepare(req);
2280 struct fuse_file_info fi;
2281 char *path;
2282 int err;
2283
2284 get_dirhandle(llfi, &fi);
2285
2286 err = -ENOENT;
2287 pthread_rwlock_rdlock(&f->tree_lock);
2288 path = get_path(f, ino);
2289 if (path != NULL) {
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002290 struct fuse_intr_data d;
2291 fuse_prepare_interrupt(f, req, &d);
2292 err = fuse_fs_fsyncdir(f->fs, path, datasync, &fi);
2293 fuse_finish_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002294 free(path);
2295 }
2296 pthread_rwlock_unlock(&f->tree_lock);
2297 reply_err(req, err);
Miklos Szeredia181e612001-11-06 12:03:23 +00002298}
2299
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002300static void fuse_lib_statfs(fuse_req_t req, fuse_ino_t ino)
Miklos Szeredi18e75e42004-02-19 14:23:27 +00002301{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002302 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredi52cb09d2005-11-07 11:59:00 +00002303 struct statvfs buf;
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002304 char *path;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002305 int err;
Mark Glinesd84b39a2002-01-07 16:32:02 +00002306
Miklos Szeredi52cb09d2005-11-07 11:59:00 +00002307 memset(&buf, 0, sizeof(buf));
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002308 pthread_rwlock_rdlock(&f->tree_lock);
2309 if (!ino) {
2310 err = -ENOMEM;
2311 path = strdup("/");
2312 } else {
2313 err = -ENOENT;
2314 path = get_path(f, ino);
2315 }
2316 if (path) {
2317 struct fuse_intr_data d;
2318 fuse_prepare_interrupt(f, req, &d);
2319 err = fuse_fs_statfs(f->fs, path, &buf);
2320 fuse_finish_interrupt(f, req, &d);
2321 free(path);
2322 }
2323 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredi77f39942004-03-25 11:17:52 +00002324
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002325 if (!err)
2326 fuse_reply_statfs(req, &buf);
Miklos Szeredi03cebae2004-03-31 10:19:18 +00002327 else
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002328 reply_err(req, err);
Miklos Szeredi03cebae2004-03-31 10:19:18 +00002329}
2330
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002331static void fuse_lib_setxattr(fuse_req_t req, fuse_ino_t ino, const char *name,
2332 const char *value, size_t size, int flags)
Miklos Szeredi3ed84232004-03-30 15:17:26 +00002333{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002334 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredi3ed84232004-03-30 15:17:26 +00002335 char *path;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002336 int err;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00002337
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002338 err = -ENOENT;
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00002339 pthread_rwlock_rdlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002340 path = get_path(f, ino);
Miklos Szeredi3ed84232004-03-30 15:17:26 +00002341 if (path != NULL) {
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002342 struct fuse_intr_data d;
2343 fuse_prepare_interrupt(f, req, &d);
2344 err = fuse_fs_setxattr(f->fs, path, name, value, size, flags);
2345 fuse_finish_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002346 free(path);
2347 }
2348 pthread_rwlock_unlock(&f->tree_lock);
2349 reply_err(req, err);
2350}
2351
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002352static int common_getxattr(struct fuse *f, fuse_req_t req, fuse_ino_t ino,
2353 const char *name, char *value, size_t size)
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002354{
2355 int err;
2356 char *path;
2357
2358 err = -ENOENT;
2359 pthread_rwlock_rdlock(&f->tree_lock);
2360 path = get_path(f, ino);
2361 if (path != NULL) {
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002362 struct fuse_intr_data d;
2363 fuse_prepare_interrupt(f, req, &d);
2364 err = fuse_fs_getxattr(f->fs, path, name, value, size);
2365 fuse_finish_interrupt(f, req, &d);
Miklos Szerediab974562005-04-07 15:40:21 +00002366 free(path);
2367 }
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00002368 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szerediab974562005-04-07 15:40:21 +00002369 return err;
2370}
2371
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002372static void fuse_lib_getxattr(fuse_req_t req, fuse_ino_t ino, const char *name,
2373 size_t size)
Miklos Szeredi3ead28e2005-01-18 21:23:41 +00002374{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002375 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredi4283ee72005-03-21 12:09:04 +00002376 int res;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002377
2378 if (size) {
2379 char *value = (char *) malloc(size);
2380 if (value == NULL) {
2381 reply_err(req, -ENOMEM);
2382 return;
2383 }
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002384 res = common_getxattr(f, req, ino, name, value, size);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002385 if (res > 0)
2386 fuse_reply_buf(req, value, res);
2387 else
2388 reply_err(req, res);
2389 free(value);
2390 } else {
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002391 res = common_getxattr(f, req, ino, name, NULL, 0);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002392 if (res >= 0)
2393 fuse_reply_xattr(req, res);
2394 else
2395 reply_err(req, res);
2396 }
2397}
2398
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002399static int common_listxattr(struct fuse *f, fuse_req_t req, fuse_ino_t ino,
2400 char *list, size_t size)
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002401{
Miklos Szeredi4283ee72005-03-21 12:09:04 +00002402 char *path;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002403 int err;
Miklos Szeredi4283ee72005-03-21 12:09:04 +00002404
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002405 err = -ENOENT;
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00002406 pthread_rwlock_rdlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002407 path = get_path(f, ino);
Miklos Szeredi4283ee72005-03-21 12:09:04 +00002408 if (path != NULL) {
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002409 struct fuse_intr_data d;
2410 fuse_prepare_interrupt(f, req, &d);
2411 err = fuse_fs_listxattr(f->fs, path, list, size);
2412 fuse_finish_interrupt(f, req, &d);
Miklos Szeredi4283ee72005-03-21 12:09:04 +00002413 free(path);
2414 }
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00002415 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002416 return err;
Miklos Szeredi4283ee72005-03-21 12:09:04 +00002417}
Miklos Szeredi3ead28e2005-01-18 21:23:41 +00002418
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002419static void fuse_lib_listxattr(fuse_req_t req, fuse_ino_t ino, size_t size)
Miklos Szeredi43696432001-11-18 19:15:05 +00002420{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002421 struct fuse *f = req_fuse_prepare(req);
2422 int res;
2423
2424 if (size) {
2425 char *list = (char *) malloc(size);
2426 if (list == NULL) {
2427 reply_err(req, -ENOMEM);
2428 return;
2429 }
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002430 res = common_listxattr(f, req, ino, list, size);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002431 if (res > 0)
2432 fuse_reply_buf(req, list, res);
2433 else
2434 reply_err(req, res);
2435 free(list);
2436 } else {
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002437 res = common_listxattr(f, req, ino, NULL, 0);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002438 if (res >= 0)
2439 fuse_reply_xattr(req, res);
2440 else
2441 reply_err(req, res);
2442 }
Miklos Szeredi43696432001-11-18 19:15:05 +00002443}
2444
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002445static void fuse_lib_removexattr(fuse_req_t req, fuse_ino_t ino,
2446 const char *name)
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002447{
2448 struct fuse *f = req_fuse_prepare(req);
2449 char *path;
2450 int err;
2451
2452 err = -ENOENT;
2453 pthread_rwlock_rdlock(&f->tree_lock);
2454 path = get_path(f, ino);
2455 if (path != NULL) {
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002456 struct fuse_intr_data d;
2457 fuse_prepare_interrupt(f, req, &d);
2458 err = fuse_fs_removexattr(f->fs, path, name);
2459 fuse_finish_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002460 free(path);
2461 }
2462 pthread_rwlock_unlock(&f->tree_lock);
2463 reply_err(req, err);
2464}
2465
Miklos Szeredi0c59ebf2006-09-10 20:53:36 +00002466static struct lock *locks_conflict(struct node *node, const struct lock *lock)
2467{
2468 struct lock *l;
2469
2470 for (l = node->locks; l; l = l->next)
2471 if (l->owner != lock->owner &&
2472 lock->start <= l->end && l->start <= lock->end &&
2473 (l->type == F_WRLCK || lock->type == F_WRLCK))
2474 break;
2475
2476 return l;
2477}
2478
2479static void delete_lock(struct lock **lockp)
2480{
2481 struct lock *l = *lockp;
2482 *lockp = l->next;
2483 free(l);
2484}
2485
2486static void insert_lock(struct lock **pos, struct lock *lock)
2487{
2488 lock->next = *pos;
2489 *pos = lock;
2490}
2491
2492static int locks_insert(struct node *node, struct lock *lock)
2493{
2494 struct lock **lp;
2495 struct lock *newl1 = NULL;
2496 struct lock *newl2 = NULL;
2497
2498 if (lock->type != F_UNLCK || lock->start != 0 || lock->end != OFFSET_MAX) {
2499 newl1 = malloc(sizeof(struct lock));
2500 newl2 = malloc(sizeof(struct lock));
2501
2502 if (!newl1 || !newl2) {
2503 free(newl1);
2504 free(newl2);
2505 return -ENOLCK;
2506 }
2507 }
2508
2509 for (lp = &node->locks; *lp;) {
2510 struct lock *l = *lp;
2511 if (l->owner != lock->owner)
2512 goto skip;
2513
2514 if (lock->type == l->type) {
2515 if (l->end < lock->start - 1)
2516 goto skip;
2517 if (lock->end < l->start - 1)
2518 break;
2519 if (l->start <= lock->start && lock->end <= l->end)
2520 goto out;
2521 if (l->start < lock->start)
2522 lock->start = l->start;
2523 if (lock->end < l->end)
2524 lock->end = l->end;
2525 goto delete;
2526 } else {
2527 if (l->end < lock->start)
2528 goto skip;
2529 if (lock->end < l->start)
2530 break;
2531 if (lock->start <= l->start && l->end <= lock->end)
2532 goto delete;
2533 if (l->end <= lock->end) {
2534 l->end = lock->start - 1;
2535 goto skip;
2536 }
2537 if (lock->start <= l->start) {
2538 l->start = lock->end + 1;
2539 break;
2540 }
2541 *newl2 = *l;
2542 newl2->start = lock->end + 1;
2543 l->end = lock->start - 1;
2544 insert_lock(&l->next, newl2);
2545 newl2 = NULL;
2546 }
2547 skip:
2548 lp = &l->next;
2549 continue;
2550
2551 delete:
2552 delete_lock(lp);
2553 }
2554 if (lock->type != F_UNLCK) {
2555 *newl1 = *lock;
2556 insert_lock(lp, newl1);
2557 newl1 = NULL;
2558 }
2559out:
2560 free(newl1);
2561 free(newl2);
2562 return 0;
2563}
2564
2565static void flock_to_lock(struct flock *flock, struct lock *lock)
2566{
2567 memset(lock, 0, sizeof(struct lock));
2568 lock->type = flock->l_type;
2569 lock->start = flock->l_start;
2570 lock->end = flock->l_len ? flock->l_start + flock->l_len - 1 : OFFSET_MAX;
2571 lock->pid = flock->l_pid;
2572}
2573
2574static void lock_to_flock(struct lock *lock, struct flock *flock)
2575{
2576 flock->l_type = lock->type;
2577 flock->l_start = lock->start;
2578 flock->l_len = (lock->end == OFFSET_MAX) ? 0 : lock->end - lock->start + 1;
2579 flock->l_pid = lock->pid;
2580}
2581
Csaba Henk79b9e9f2007-05-10 22:56:46 +00002582static void fuse_flush_common(struct fuse_fs *fs, const char *path,
2583 struct fuse_file_info *fi,
2584 struct flock *lock, int *err, int *errlock)
2585{
2586 *err = fuse_fs_flush(fs, path, fi);
2587
2588 memset(lock, 0, sizeof(*lock));
2589 lock->l_type = F_UNLCK;
2590 lock->l_whence = SEEK_SET;
2591 *errlock = fuse_fs_lock(fs, path, fi, F_SETLK, lock);
2592}
2593
2594static void fuse_lib_release(fuse_req_t req, fuse_ino_t ino,
2595 struct fuse_file_info *fi)
2596{
2597 struct fuse *f = req_fuse_prepare(req);
2598 struct fuse_intr_data d;
2599 struct flock lock;
2600 struct lock l;
2601 char *path;
2602 int err = 0;
2603 int errlock = -ENOSYS;
2604
2605 pthread_rwlock_rdlock(&f->tree_lock);
2606 path = get_path(f, ino);
2607 if (!path)
2608 path = "-";
2609 if (f->conf.debug) {
2610 printf("RELEASE%s[%llu] flags: 0x%x\n", fi->flush ? "+FLUSH" : "",
2611 (unsigned long long) fi->fh, fi->flags);
2612 fflush(stdout);
2613 }
2614 fuse_prepare_interrupt(f, req, &d);
2615 if (fi->flush) {
2616 fuse_flush_common(f->fs, path, fi, &lock, &err, &errlock);
2617 if (err == -ENOSYS && errlock == -ENOSYS)
2618 err = 0;
2619 else if (err == -ENOSYS || !err)
2620 err = errlock;
2621 }
2622 fuse_do_release(f, ino, path, fi);
2623 fuse_finish_interrupt(f, req, &d);
2624 if (errlock != -ENOSYS) {
2625 flock_to_lock(&lock, &l);
2626 l.owner = fi->lock_owner;
2627 pthread_mutex_lock(&f->lock);
2628 locks_insert(get_node(f, ino), &l);
2629 pthread_mutex_unlock(&f->lock);
2630 }
2631
2632 if (path)
2633 free(path);
2634 pthread_rwlock_unlock(&f->tree_lock);
2635
2636 reply_err(req, err);
2637}
2638
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002639static void fuse_lib_flush(fuse_req_t req, fuse_ino_t ino,
Miklos Szeredi07407852006-09-30 20:03:52 +00002640 struct fuse_file_info *fi)
Miklos Szeredi0c59ebf2006-09-10 20:53:36 +00002641{
2642 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002643 struct fuse_intr_data d;
2644 struct flock lock;
2645 struct lock l;
Miklos Szeredi0c59ebf2006-09-10 20:53:36 +00002646 char *path;
2647 int err;
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002648 int errlock;
Miklos Szeredi0c59ebf2006-09-10 20:53:36 +00002649
2650 err = -ENOENT;
2651 pthread_rwlock_rdlock(&f->tree_lock);
2652 path = get_path(f, ino);
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002653 if (path && f->conf.debug) {
2654 printf("FLUSH[%llu]\n", (unsigned long long) fi->fh);
2655 fflush(stdout);
Miklos Szeredi0c59ebf2006-09-10 20:53:36 +00002656 }
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002657 fuse_prepare_interrupt(f, req, &d);
Csaba Henk79b9e9f2007-05-10 22:56:46 +00002658 fuse_flush_common(f->fs, path ? path : "-" , fi, &lock, &err, &errlock);
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002659 fuse_finish_interrupt(f, req, &d);
Csaba Henk79b9e9f2007-05-10 22:56:46 +00002660 if (errlock != -ENOSYS) {
Miklos Szeredi0c59ebf2006-09-10 20:53:36 +00002661 flock_to_lock(&lock, &l);
Miklos Szeredi07407852006-09-30 20:03:52 +00002662 l.owner = fi->lock_owner;
Miklos Szeredi0c59ebf2006-09-10 20:53:36 +00002663 pthread_mutex_lock(&f->lock);
2664 locks_insert(get_node(f, ino), &l);
2665 pthread_mutex_unlock(&f->lock);
2666
2667 /* if op.lock() is defined FLUSH is needed regardless of op.flush() */
2668 if (err == -ENOSYS)
2669 err = 0;
2670 }
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002671 if (path)
2672 free(path);
Miklos Szeredi0c59ebf2006-09-10 20:53:36 +00002673 pthread_rwlock_unlock(&f->tree_lock);
2674 reply_err(req, err);
2675}
2676
Miklos Szeredi9a5c11d2006-07-30 17:33:40 +00002677static int fuse_lock_common(fuse_req_t req, fuse_ino_t ino,
2678 struct fuse_file_info *fi, struct flock *lock,
Miklos Szeredi07407852006-09-30 20:03:52 +00002679 int cmd)
Miklos Szeredi9a5c11d2006-07-30 17:33:40 +00002680{
2681 struct fuse *f = req_fuse_prepare(req);
2682 char *path;
2683 int err;
2684
2685 err = -ENOENT;
2686 pthread_rwlock_rdlock(&f->tree_lock);
2687 path = get_path(f, ino);
2688 if (path != NULL) {
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002689 struct fuse_intr_data d;
2690 fuse_prepare_interrupt(f, req, &d);
2691 err = fuse_fs_lock(f->fs, path, fi, cmd, lock);
2692 fuse_finish_interrupt(f, req, &d);
Miklos Szeredi9a5c11d2006-07-30 17:33:40 +00002693 free(path);
2694 }
2695 pthread_rwlock_unlock(&f->tree_lock);
2696 return err;
2697}
2698
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002699static void fuse_lib_getlk(fuse_req_t req, fuse_ino_t ino,
2700 struct fuse_file_info *fi, struct flock *lock)
Miklos Szeredi9a5c11d2006-07-30 17:33:40 +00002701{
Miklos Szeredi0c59ebf2006-09-10 20:53:36 +00002702 int err;
2703 struct lock l;
2704 struct lock *conflict;
2705 struct fuse *f = req_fuse(req);
2706
2707 flock_to_lock(lock, &l);
Miklos Szeredi07407852006-09-30 20:03:52 +00002708 l.owner = fi->lock_owner;
Miklos Szeredi0c59ebf2006-09-10 20:53:36 +00002709 pthread_mutex_lock(&f->lock);
2710 conflict = locks_conflict(get_node(f, ino), &l);
2711 if (conflict)
2712 lock_to_flock(conflict, lock);
2713 pthread_mutex_unlock(&f->lock);
2714 if (!conflict)
Miklos Szeredi07407852006-09-30 20:03:52 +00002715 err = fuse_lock_common(req, ino, fi, lock, F_GETLK);
Miklos Szeredi0c59ebf2006-09-10 20:53:36 +00002716 else
2717 err = 0;
2718
Miklos Szeredi9a5c11d2006-07-30 17:33:40 +00002719 if (!err)
2720 fuse_reply_lock(req, lock);
2721 else
2722 reply_err(req, err);
2723}
2724
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002725static void fuse_lib_setlk(fuse_req_t req, fuse_ino_t ino,
2726 struct fuse_file_info *fi, struct flock *lock,
2727 int sleep)
Miklos Szeredi9a5c11d2006-07-30 17:33:40 +00002728{
Miklos Szeredi07407852006-09-30 20:03:52 +00002729 int err = fuse_lock_common(req, ino, fi, lock, sleep ? F_SETLKW : F_SETLK);
Miklos Szeredi0c59ebf2006-09-10 20:53:36 +00002730 if (!err) {
2731 struct fuse *f = req_fuse(req);
2732 struct lock l;
2733 flock_to_lock(lock, &l);
Miklos Szeredi07407852006-09-30 20:03:52 +00002734 l.owner = fi->lock_owner;
Miklos Szeredi0c59ebf2006-09-10 20:53:36 +00002735 pthread_mutex_lock(&f->lock);
2736 locks_insert(get_node(f, ino), &l);
2737 pthread_mutex_unlock(&f->lock);
2738 }
2739 reply_err(req, err);
Miklos Szeredi9a5c11d2006-07-30 17:33:40 +00002740}
2741
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002742static void fuse_lib_bmap(fuse_req_t req, fuse_ino_t ino, size_t blocksize,
2743 uint64_t idx)
Miklos Szeredi708b4812006-09-30 16:02:25 +00002744{
2745 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002746 struct fuse_intr_data d;
Miklos Szeredi708b4812006-09-30 16:02:25 +00002747 char *path;
2748 int err;
2749
2750 err = -ENOENT;
2751 pthread_rwlock_rdlock(&f->tree_lock);
2752 path = get_path(f, ino);
2753 if (path != NULL) {
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002754 fuse_prepare_interrupt(f, req, &d);
2755 err = fuse_fs_bmap(f->fs, path, blocksize, &idx);
2756 fuse_finish_interrupt(f, req, &d);
Miklos Szeredi708b4812006-09-30 16:02:25 +00002757 free(path);
2758 }
2759 pthread_rwlock_unlock(&f->tree_lock);
2760 if (!err)
2761 fuse_reply_bmap(req, idx);
2762 else
2763 reply_err(req, err);
2764}
2765
Miklos Szeredia1482422005-08-14 23:00:27 +00002766static struct fuse_lowlevel_ops fuse_path_ops = {
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002767 .init = fuse_lib_init,
2768 .destroy = fuse_lib_destroy,
2769 .lookup = fuse_lib_lookup,
2770 .forget = fuse_lib_forget,
2771 .getattr = fuse_lib_getattr,
2772 .setattr = fuse_lib_setattr,
2773 .access = fuse_lib_access,
2774 .readlink = fuse_lib_readlink,
2775 .mknod = fuse_lib_mknod,
2776 .mkdir = fuse_lib_mkdir,
2777 .unlink = fuse_lib_unlink,
2778 .rmdir = fuse_lib_rmdir,
2779 .symlink = fuse_lib_symlink,
2780 .rename = fuse_lib_rename,
2781 .link = fuse_lib_link,
2782 .create = fuse_lib_create,
2783 .open = fuse_lib_open,
2784 .read = fuse_lib_read,
2785 .write = fuse_lib_write,
2786 .flush = fuse_lib_flush,
2787 .release = fuse_lib_release,
2788 .fsync = fuse_lib_fsync,
2789 .opendir = fuse_lib_opendir,
2790 .readdir = fuse_lib_readdir,
2791 .releasedir = fuse_lib_releasedir,
2792 .fsyncdir = fuse_lib_fsyncdir,
2793 .statfs = fuse_lib_statfs,
2794 .setxattr = fuse_lib_setxattr,
2795 .getxattr = fuse_lib_getxattr,
2796 .listxattr = fuse_lib_listxattr,
2797 .removexattr = fuse_lib_removexattr,
2798 .getlk = fuse_lib_getlk,
2799 .setlk = fuse_lib_setlk,
2800 .bmap = fuse_lib_bmap,
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002801};
2802
Miklos Szeredia1482422005-08-14 23:00:27 +00002803static void free_cmd(struct fuse_cmd *cmd)
2804{
2805 free(cmd->buf);
2806 free(cmd);
2807}
2808
Miklos Szeredif458b8c2004-12-07 16:46:42 +00002809void fuse_process_cmd(struct fuse *f, struct fuse_cmd *cmd)
Miklos Szeredia181e612001-11-06 12:03:23 +00002810{
Miklos Szeredi178451d2005-08-15 13:19:07 +00002811 fuse_session_process(f->se, cmd->buf, cmd->buflen, cmd->ch);
Miklos Szeredifa829b52005-12-02 11:05:41 +00002812 free_cmd(cmd);
Miklos Szeredia181e612001-11-06 12:03:23 +00002813}
2814
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002815int fuse_exited(struct fuse *f)
Miklos Szeredi65cf7c72004-06-30 11:34:56 +00002816{
Miklos Szeredia1482422005-08-14 23:00:27 +00002817 return fuse_session_exited(f->se);
2818}
2819
2820struct fuse_session *fuse_get_session(struct fuse *f)
2821{
2822 return f->se;
2823}
2824
2825static struct fuse_cmd *fuse_alloc_cmd(size_t bufsize)
2826{
2827 struct fuse_cmd *cmd = (struct fuse_cmd *) malloc(sizeof(*cmd));
2828 if (cmd == NULL) {
2829 fprintf(stderr, "fuse: failed to allocate cmd\n");
2830 return NULL;
2831 }
2832 cmd->buf = (char *) malloc(bufsize);
2833 if (cmd->buf == NULL) {
2834 fprintf(stderr, "fuse: failed to allocate read buffer\n");
2835 free(cmd);
2836 return NULL;
2837 }
2838 return cmd;
Miklos Szeredi65cf7c72004-06-30 11:34:56 +00002839}
2840
Miklos Szeredif458b8c2004-12-07 16:46:42 +00002841struct fuse_cmd *fuse_read_cmd(struct fuse *f)
Miklos Szeredi2df1c042001-11-06 15:07:17 +00002842{
Miklos Szeredia1482422005-08-14 23:00:27 +00002843 struct fuse_chan *ch = fuse_session_next_chan(f->se, NULL);
2844 size_t bufsize = fuse_chan_bufsize(ch);
2845 struct fuse_cmd *cmd = fuse_alloc_cmd(bufsize);
2846 if (cmd != NULL) {
Miklos Szeredi8d975f62006-03-17 15:56:05 +00002847 int res = fuse_chan_recv(&ch, cmd->buf, bufsize);
Miklos Szeredia1482422005-08-14 23:00:27 +00002848 if (res <= 0) {
2849 free_cmd(cmd);
Miklos Szeredi5d9ce362006-03-01 12:10:13 +00002850 if (res < 0 && res != -EINTR && res != -EAGAIN)
Miklos Szeredifa829b52005-12-02 11:05:41 +00002851 fuse_exit(f);
Miklos Szeredia1482422005-08-14 23:00:27 +00002852 return NULL;
2853 }
2854 cmd->buflen = res;
Miklos Szeredi178451d2005-08-15 13:19:07 +00002855 cmd->ch = ch;
Miklos Szeredia1482422005-08-14 23:00:27 +00002856 }
2857 return cmd;
Miklos Szeredi2df1c042001-11-06 15:07:17 +00002858}
2859
Miklos Szeredib2cf9562004-09-16 08:42:40 +00002860int fuse_loop(struct fuse *f)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00002861{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002862 if (f)
Miklos Szeredia1482422005-08-14 23:00:27 +00002863 return fuse_session_loop(f->se);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002864 else
Miklos Szeredib2cf9562004-09-16 08:42:40 +00002865 return -1;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00002866}
2867
Miklos Szeredi891b8742004-07-29 09:27:49 +00002868int fuse_invalidate(struct fuse *f, const char *path)
2869{
Miklos Szeredie56818b2004-12-12 11:45:24 +00002870 (void) f;
2871 (void) path;
2872 return -EINVAL;
Miklos Szeredi891b8742004-07-29 09:27:49 +00002873}
2874
Miklos Szeredi0f48a262002-12-05 14:23:01 +00002875void fuse_exit(struct fuse *f)
2876{
Miklos Szeredia1482422005-08-14 23:00:27 +00002877 fuse_session_exit(f->se);
Miklos Szeredi0f48a262002-12-05 14:23:01 +00002878}
2879
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002880struct fuse_context *fuse_get_context(void)
Miklos Szeredi2e50d432001-12-20 12:17:25 +00002881{
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002882 return &fuse_get_context_internal()->ctx;
2883}
2884
2885int fuse_interrupted(void)
2886{
2887 return fuse_req_interrupted(fuse_get_context_internal()->req);
Miklos Szeredid169f312004-09-22 08:48:26 +00002888}
2889
Miklos Szeredif458b8c2004-12-07 16:46:42 +00002890void fuse_set_getcontext_func(struct fuse_context *(*func)(void))
Miklos Szeredid169f312004-09-22 08:48:26 +00002891{
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002892 (void) func;
2893 /* no-op */
Miklos Szeredi2e50d432001-12-20 12:17:25 +00002894}
2895
Miklos Szerediad005972006-01-07 10:14:34 +00002896enum {
2897 KEY_HELP,
Miklos Szerediad005972006-01-07 10:14:34 +00002898};
2899
Miklos Szeredi659743b2005-12-09 17:41:42 +00002900#define FUSE_LIB_OPT(t, p, v) { t, offsetof(struct fuse_config, p), v }
2901
2902static const struct fuse_opt fuse_lib_opts[] = {
Miklos Szerediad005972006-01-07 10:14:34 +00002903 FUSE_OPT_KEY("-h", KEY_HELP),
2904 FUSE_OPT_KEY("--help", KEY_HELP),
Miklos Szeredi065f2222006-01-20 15:15:21 +00002905 FUSE_OPT_KEY("debug", FUSE_OPT_KEY_KEEP),
2906 FUSE_OPT_KEY("-d", FUSE_OPT_KEY_KEEP),
Miklos Szeredi659743b2005-12-09 17:41:42 +00002907 FUSE_LIB_OPT("debug", debug, 1),
Miklos Szeredi95da8602006-01-06 18:29:40 +00002908 FUSE_LIB_OPT("-d", debug, 1),
Miklos Szeredi659743b2005-12-09 17:41:42 +00002909 FUSE_LIB_OPT("hard_remove", hard_remove, 1),
2910 FUSE_LIB_OPT("use_ino", use_ino, 1),
2911 FUSE_LIB_OPT("readdir_ino", readdir_ino, 1),
2912 FUSE_LIB_OPT("direct_io", direct_io, 1),
2913 FUSE_LIB_OPT("kernel_cache", kernel_cache, 1),
Miklos Szeredi320abe42006-01-30 18:14:51 +00002914 FUSE_LIB_OPT("auto_cache", auto_cache, 1),
2915 FUSE_LIB_OPT("noauto_cache", auto_cache, 0),
Miklos Szeredi659743b2005-12-09 17:41:42 +00002916 FUSE_LIB_OPT("umask=", set_mode, 1),
2917 FUSE_LIB_OPT("umask=%o", umask, 0),
2918 FUSE_LIB_OPT("uid=", set_uid, 1),
2919 FUSE_LIB_OPT("uid=%d", uid, 0),
2920 FUSE_LIB_OPT("gid=", set_gid, 1),
2921 FUSE_LIB_OPT("gid=%d", gid, 0),
2922 FUSE_LIB_OPT("entry_timeout=%lf", entry_timeout, 0),
2923 FUSE_LIB_OPT("attr_timeout=%lf", attr_timeout, 0),
Miklos Szeredi6e806e92006-02-16 16:59:39 +00002924 FUSE_LIB_OPT("ac_attr_timeout=%lf", ac_attr_timeout, 0),
2925 FUSE_LIB_OPT("ac_attr_timeout=", ac_attr_timeout_set, 1),
Miklos Szeredi659743b2005-12-09 17:41:42 +00002926 FUSE_LIB_OPT("negative_timeout=%lf", negative_timeout, 0),
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002927 FUSE_LIB_OPT("intr", intr, 1),
2928 FUSE_LIB_OPT("intr_signal=%d", intr_signal, 0),
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002929 FUSE_LIB_OPT("modules=%s", modules, 0),
Miklos Szeredi659743b2005-12-09 17:41:42 +00002930 FUSE_OPT_END
2931};
2932
Miklos Szerediad005972006-01-07 10:14:34 +00002933static void fuse_lib_help(void)
2934{
2935 fprintf(stderr,
Miklos Szeredi06091462006-02-16 16:38:34 +00002936" -o hard_remove immediate removal (don't hide files)\n"
2937" -o use_ino let filesystem set inode numbers\n"
2938" -o readdir_ino try to fill in d_ino in readdir\n"
2939" -o direct_io use direct I/O\n"
2940" -o kernel_cache cache files in kernel\n"
2941" -o [no]auto_cache enable caching based on modification times\n"
2942" -o umask=M set file permissions (octal)\n"
2943" -o uid=N set file owner\n"
2944" -o gid=N set file group\n"
2945" -o entry_timeout=T cache timeout for names (1.0s)\n"
2946" -o negative_timeout=T cache timeout for deleted names (0.0s)\n"
Miklos Szeredi6e806e92006-02-16 16:59:39 +00002947" -o attr_timeout=T cache timeout for attributes (1.0s)\n"
2948" -o ac_attr_timeout=T auto cache timeout for attributes (attr_timeout)\n"
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002949" -o intr allow requests to be interrupted\n"
2950" -o intr_signal=NUM signal to send on interrupt (%i)\n"
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002951" -o modules=M1[:M2...] names of modules to push onto filesystem stack\n"
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002952"\n", FUSE_DEFAULT_INTR_SIGNAL);
Miklos Szerediad005972006-01-07 10:14:34 +00002953}
2954
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002955static void fuse_lib_help_modules(void)
2956{
2957 struct fuse_module *m;
2958 fprintf(stderr, "\nModule options:\n");
2959 pthread_mutex_lock(&fuse_context_lock);
2960 for (m = fuse_modules; m; m = m->next) {
2961 struct fuse_fs *fs = NULL;
2962 struct fuse_fs *newfs;
2963 struct fuse_args args = FUSE_ARGS_INIT(0, NULL);
2964 if (fuse_opt_add_arg(&args, "") != -1 &&
2965 fuse_opt_add_arg(&args, "-h") != -1) {
2966 fprintf(stderr, "\n[%s]\n", m->name);
2967 newfs = m->factory(&args, &fs);
2968 assert(newfs == NULL);
2969 }
2970 fuse_opt_free_args(&args);
2971 }
2972 pthread_mutex_unlock(&fuse_context_lock);
2973}
2974
Miklos Szerediad005972006-01-07 10:14:34 +00002975static int fuse_lib_opt_proc(void *data, const char *arg, int key,
2976 struct fuse_args *outargs)
2977{
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002978 (void) arg; (void) outargs;
Miklos Szerediad005972006-01-07 10:14:34 +00002979
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002980 if (key == KEY_HELP) {
2981 struct fuse_config *conf = (struct fuse_config *) data;
Miklos Szerediad005972006-01-07 10:14:34 +00002982 fuse_lib_help();
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002983 conf->help = 1;
2984 }
Miklos Szerediad005972006-01-07 10:14:34 +00002985
2986 return 1;
2987}
2988
Miklos Szeredibd7661b2004-07-23 17:16:29 +00002989int fuse_is_lib_option(const char *opt)
2990{
Miklos Szeredi659743b2005-12-09 17:41:42 +00002991 return fuse_lowlevel_is_lib_option(opt) ||
2992 fuse_opt_match(fuse_lib_opts, opt);
Miklos Szeredibd7661b2004-07-23 17:16:29 +00002993}
2994
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002995static int fuse_init_intr_signal(int signum, int *installed)
2996{
2997 struct sigaction old_sa;
2998
2999 if (sigaction(signum, NULL, &old_sa) == -1) {
3000 perror("fuse: cannot get old signal handler");
3001 return -1;
3002 }
3003
3004 if (old_sa.sa_handler == SIG_DFL) {
3005 struct sigaction sa;
3006
3007 memset(&sa, 0, sizeof(struct sigaction));
3008 sa.sa_handler = fuse_intr_sighandler;
Miklos Szeredi0c59ebf2006-09-10 20:53:36 +00003009 sigemptyset(&sa.sa_mask);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00003010
3011 if (sigaction(signum, &sa, NULL) == -1) {
3012 perror("fuse: cannot set interrupt signal handler");
3013 return -1;
3014 }
3015 *installed = 1;
3016 }
3017 return 0;
3018}
3019
Miklos Szeredi349bdda2006-09-07 11:48:16 +00003020static void fuse_restore_intr_signal(int signum)
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00003021{
Miklos Szeredi349bdda2006-09-07 11:48:16 +00003022 struct sigaction sa;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00003023
Miklos Szeredi349bdda2006-09-07 11:48:16 +00003024 memset(&sa, 0, sizeof(struct sigaction));
3025 sa.sa_handler = SIG_DFL;
3026 sigaction(signum, &sa, NULL);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00003027}
3028
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00003029
3030static int fuse_push_module(struct fuse *f, const char *module,
3031 struct fuse_args *args)
3032{
3033 struct fuse_fs *fs[2] = { f->fs, NULL };
3034 struct fuse_fs *newfs;
3035 struct fuse_module *m = fuse_get_module(module);
3036
3037 if (!m)
3038 return -1;
3039
3040 newfs = m->factory(args, fs);
3041 if (!newfs) {
3042 fuse_put_module(m);
3043 return -1;
3044 }
3045 newfs->m = m;
3046 f->fs = newfs;
3047 return 0;
3048}
3049
3050struct fuse_fs *fuse_fs_new(const struct fuse_operations *op, size_t op_size,
3051 void *user_data)
3052{
3053 struct fuse_fs *fs;
3054
3055 if (sizeof(struct fuse_operations) < op_size) {
3056 fprintf(stderr, "fuse: warning: library too old, some operations may not not work\n");
3057 op_size = sizeof(struct fuse_operations);
3058 }
3059
3060 fs = (struct fuse_fs *) calloc(1, sizeof(struct fuse_fs));
3061 if (!fs) {
3062 fprintf(stderr, "fuse: failed to allocate fuse_fs object\n");
3063 return NULL;
3064 }
3065
3066 fs->user_data = user_data;
3067 memcpy(&fs->op, op, op_size);
3068 return fs;
3069}
3070
Miklos Szeredi6f385412006-03-17 15:05:40 +00003071struct fuse *fuse_new_common(struct fuse_chan *ch, struct fuse_args *args,
Miklos Szeredi0b6a0ad2004-12-04 00:40:50 +00003072 const struct fuse_operations *op,
Miklos Szeredi6f385412006-03-17 15:05:40 +00003073 size_t op_size, void *user_data, int compat)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00003074{
Miklos Szeredi97c61e92001-11-07 12:09:43 +00003075 struct fuse *f;
3076 struct node *root;
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00003077 struct fuse_fs *fs;
Miklos Szeredi9a5c11d2006-07-30 17:33:40 +00003078 struct fuse_lowlevel_ops llop = fuse_path_ops;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00003079
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00003080 if (fuse_create_context_key() == -1)
3081 goto out;
3082
Miklos Szeredi97c61e92001-11-07 12:09:43 +00003083 f = (struct fuse *) calloc(1, sizeof(struct fuse));
Miklos Szeredie56818b2004-12-12 11:45:24 +00003084 if (f == NULL) {
3085 fprintf(stderr, "fuse: failed to allocate fuse object\n");
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00003086 goto out_delete_context_key;
Miklos Szeredie56818b2004-12-12 11:45:24 +00003087 }
Miklos Szeredi2df1c042001-11-06 15:07:17 +00003088
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00003089 fs = fuse_fs_new(op, op_size, user_data);
3090 if (!fs)
3091 goto out_free;
3092
3093 fs->compat = compat;
3094 f->fs = fs;
3095
3096 /* Oh f**k, this is ugly! */
3097 if (!fs->op.lock) {
3098 llop.getlk = NULL;
3099 llop.setlk = NULL;
3100 }
3101
Miklos Szeredi659743b2005-12-09 17:41:42 +00003102 f->conf.entry_timeout = 1.0;
3103 f->conf.attr_timeout = 1.0;
3104 f->conf.negative_timeout = 0.0;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00003105 f->conf.intr_signal = FUSE_DEFAULT_INTR_SIGNAL;
Miklos Szeredi6c0209a2005-08-02 13:31:28 +00003106
Miklos Szerediad005972006-01-07 10:14:34 +00003107 if (fuse_opt_parse(args, &f->conf, fuse_lib_opts, fuse_lib_opt_proc) == -1)
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00003108 goto out_free_fs;
3109
3110 if (f->conf.modules) {
3111 char *module;
3112 char *next;
3113
3114 for (module = f->conf.modules; module; module = next) {
3115 char *p;
3116 for (p = module; *p && *p != ':'; p++);
3117 next = *p ? p + 1 : NULL;
3118 *p = '\0';
3119 if (module[0] && fuse_push_module(f, module, args) == -1)
3120 goto out_free_fs;
3121 }
3122 }
Miklos Szeredib2cf9562004-09-16 08:42:40 +00003123
Miklos Szeredi6e806e92006-02-16 16:59:39 +00003124 if (!f->conf.ac_attr_timeout_set)
3125 f->conf.ac_attr_timeout = f->conf.attr_timeout;
3126
Miklos Szeredi659743b2005-12-09 17:41:42 +00003127#ifdef __FreeBSD__
3128 /*
3129 * In FreeBSD, we always use these settings as inode numbers are needed to
3130 * make getcwd(3) work.
3131 */
Miklos Szeredi76fc3de2005-12-12 09:34:45 +00003132 f->conf.readdir_ino = 1;
Miklos Szeredi659743b2005-12-09 17:41:42 +00003133#endif
3134
Miklos Szeredi065f2222006-01-20 15:15:21 +00003135 if (compat && compat <= 25) {
3136 if (fuse_sync_compat_args(args) == -1)
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00003137 goto out_free_fs;
Miklos Szeredi9a5c11d2006-07-30 17:33:40 +00003138 }
3139
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00003140 f->se = fuse_lowlevel_new_common(args, &llop, sizeof(llop), f);
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00003141 if (f->se == NULL) {
3142 if (f->conf.help)
3143 fuse_lib_help_modules();
3144 goto out_free_fs;
3145 }
Miklos Szeredi2bb750e2005-10-03 14:54:24 +00003146
Miklos Szeredia1482422005-08-14 23:00:27 +00003147 fuse_session_add_chan(f->se, ch);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00003148
Miklos Szeredi97c61e92001-11-07 12:09:43 +00003149 f->ctr = 0;
Miklos Szeredi76f65782004-02-19 16:55:40 +00003150 f->generation = 0;
Miklos Szeredifff56ab2001-11-16 10:12:59 +00003151 /* FIXME: Dynamic hash table */
Miklos Szeredi97c61e92001-11-07 12:09:43 +00003152 f->name_table_size = 14057;
3153 f->name_table = (struct node **)
3154 calloc(1, sizeof(struct node *) * f->name_table_size);
Miklos Szeredie56818b2004-12-12 11:45:24 +00003155 if (f->name_table == NULL) {
3156 fprintf(stderr, "fuse: memory allocation failed\n");
Miklos Szeredia1482422005-08-14 23:00:27 +00003157 goto out_free_session;
Miklos Szeredie56818b2004-12-12 11:45:24 +00003158 }
Miklos Szeredib2cf9562004-09-16 08:42:40 +00003159
Miklos Szeredia13d9002004-11-02 17:32:03 +00003160 f->id_table_size = 14057;
3161 f->id_table = (struct node **)
3162 calloc(1, sizeof(struct node *) * f->id_table_size);
Miklos Szeredie56818b2004-12-12 11:45:24 +00003163 if (f->id_table == NULL) {
3164 fprintf(stderr, "fuse: memory allocation failed\n");
Miklos Szeredib2cf9562004-09-16 08:42:40 +00003165 goto out_free_name_table;
Miklos Szeredie56818b2004-12-12 11:45:24 +00003166 }
Miklos Szeredib2cf9562004-09-16 08:42:40 +00003167
Miklos Szeredi38f152c2006-09-03 18:28:52 +00003168 fuse_mutex_init(&f->lock);
Miklos Szeredid0a777a2006-04-05 07:18:00 +00003169 pthread_rwlock_init(&f->tree_lock, NULL);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00003170
Miklos Szeredi97c61e92001-11-07 12:09:43 +00003171 root = (struct node *) calloc(1, sizeof(struct node));
Miklos Szeredie56818b2004-12-12 11:45:24 +00003172 if (root == NULL) {
3173 fprintf(stderr, "fuse: memory allocation failed\n");
Miklos Szeredia13d9002004-11-02 17:32:03 +00003174 goto out_free_id_table;
Miklos Szeredie56818b2004-12-12 11:45:24 +00003175 }
Miklos Szeredib2cf9562004-09-16 08:42:40 +00003176
Miklos Szeredi97c61e92001-11-07 12:09:43 +00003177 root->name = strdup("/");
Miklos Szeredie56818b2004-12-12 11:45:24 +00003178 if (root->name == NULL) {
3179 fprintf(stderr, "fuse: memory allocation failed\n");
Miklos Szeredib2cf9562004-09-16 08:42:40 +00003180 goto out_free_root;
Miklos Szeredie56818b2004-12-12 11:45:24 +00003181 }
Miklos Szeredib2cf9562004-09-16 08:42:40 +00003182
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00003183 if (f->conf.intr &&
3184 fuse_init_intr_signal(f->conf.intr_signal, &f->intr_installed) == -1)
3185 goto out_free_root_name;
3186
Miklos Szeredi97c61e92001-11-07 12:09:43 +00003187 root->parent = 0;
Miklos Szeredia13d9002004-11-02 17:32:03 +00003188 root->nodeid = FUSE_ROOT_ID;
Miklos Szeredi76f65782004-02-19 16:55:40 +00003189 root->generation = 0;
Miklos Szeredi0f62d722005-01-04 12:45:54 +00003190 root->refctr = 1;
Miklos Szeredi38009022005-05-08 19:47:22 +00003191 root->nlookup = 1;
Miklos Szeredia13d9002004-11-02 17:32:03 +00003192 hash_id(f, root);
Miklos Szeredi97c61e92001-11-07 12:09:43 +00003193
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00003194 return f;
Miklos Szeredib2cf9562004-09-16 08:42:40 +00003195
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00003196 out_free_root_name:
3197 free(root->name);
Miklos Szeredib2cf9562004-09-16 08:42:40 +00003198 out_free_root:
3199 free(root);
Miklos Szeredia13d9002004-11-02 17:32:03 +00003200 out_free_id_table:
3201 free(f->id_table);
Miklos Szeredib2cf9562004-09-16 08:42:40 +00003202 out_free_name_table:
3203 free(f->name_table);
Miklos Szeredia1482422005-08-14 23:00:27 +00003204 out_free_session:
3205 fuse_session_destroy(f->se);
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00003206 out_free_fs:
3207 /* Horrible compatibility hack to stop the destructor from being
3208 called on the filesystem without init being called first */
3209 fs->op.destroy = NULL;
3210 fuse_fs_destroy(f->fs);
Miklos Szeredib2cf9562004-09-16 08:42:40 +00003211 out_free:
3212 free(f);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00003213 out_delete_context_key:
3214 fuse_delete_context_key();
Miklos Szeredib2cf9562004-09-16 08:42:40 +00003215 out:
Miklos Szeredib2cf9562004-09-16 08:42:40 +00003216 return NULL;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00003217}
3218
Miklos Szeredi6f385412006-03-17 15:05:40 +00003219struct fuse *fuse_new(struct fuse_chan *ch, struct fuse_args *args,
3220 const struct fuse_operations *op, size_t op_size,
3221 void *user_data)
Miklos Szeredi0b6a0ad2004-12-04 00:40:50 +00003222{
Miklos Szeredi6f385412006-03-17 15:05:40 +00003223 return fuse_new_common(ch, args, op, op_size, user_data, 0);
Miklos Szeredi0b6a0ad2004-12-04 00:40:50 +00003224}
3225
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00003226void fuse_destroy(struct fuse *f)
3227{
Miklos Szeredi97c61e92001-11-07 12:09:43 +00003228 size_t i;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00003229
3230 if (f->conf.intr && f->intr_installed)
3231 fuse_restore_intr_signal(f->conf.intr_signal);
Miklos Szerediad519562006-07-31 11:07:40 +00003232
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00003233 if (f->fs) {
3234 struct fuse_context_i *c = fuse_get_context_internal();
Miklos Szerediad519562006-07-31 11:07:40 +00003235
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00003236 memset(c, 0, sizeof(*c));
3237 c->ctx.fuse = f;
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00003238
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00003239 for (i = 0; i < f->id_table_size; i++) {
3240 struct node *node;
3241
3242 for (node = f->id_table[i]; node != NULL; node = node->id_next) {
3243 if (node->is_hidden) {
3244 char *path = get_path(f, node->nodeid);
3245 if (path) {
3246 fuse_fs_unlink(f->fs, path);
3247 free(path);
3248 }
Miklos Szeredi21019c92005-05-09 11:22:41 +00003249 }
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00003250 }
3251 }
3252 }
Miklos Szeredia13d9002004-11-02 17:32:03 +00003253 for (i = 0; i < f->id_table_size; i++) {
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00003254 struct node *node;
Miklos Szeredi97c61e92001-11-07 12:09:43 +00003255 struct node *next;
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00003256
Miklos Szeredia13d9002004-11-02 17:32:03 +00003257 for (node = f->id_table[i]; node != NULL; node = next) {
3258 next = node->id_next;
Miklos Szeredi97c61e92001-11-07 12:09:43 +00003259 free_node(node);
3260 }
3261 }
Miklos Szeredia13d9002004-11-02 17:32:03 +00003262 free(f->id_table);
Miklos Szeredi97c61e92001-11-07 12:09:43 +00003263 free(f->name_table);
Miklos Szeredia181e612001-11-06 12:03:23 +00003264 pthread_mutex_destroy(&f->lock);
Miklos Szeredi55a84102006-06-06 10:16:38 +00003265 pthread_rwlock_destroy(&f->tree_lock);
Miklos Szeredia1482422005-08-14 23:00:27 +00003266 fuse_session_destroy(f->se);
Miklos Szeredi97c61e92001-11-07 12:09:43 +00003267 free(f);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00003268 fuse_delete_context_key();
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00003269}
Miklos Szeredi0b6a0ad2004-12-04 00:40:50 +00003270
Miklos Szeredi6f385412006-03-17 15:05:40 +00003271static struct fuse *fuse_new_common_compat25(int fd, struct fuse_args *args,
3272 const struct fuse_operations *op,
3273 size_t op_size, int compat)
3274{
3275 struct fuse *f = NULL;
3276 struct fuse_chan *ch = fuse_kern_chan_new(fd);
3277
3278 if (ch)
3279 f = fuse_new_common(ch, args, op, op_size, NULL, compat);
3280
3281 return f;
3282}
3283
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00003284/* called with fuse_context_lock held or during initialization (before
3285 main() has been called) */
3286void fuse_register_module(struct fuse_module *mod)
3287{
Miklos Szeredi2f759e12007-03-14 09:13:27 +00003288 mod->ctr = 0;
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00003289 mod->so = fuse_current_so;
3290 if (mod->so)
3291 mod->so->ctr++;
3292 mod->next = fuse_modules;
3293 fuse_modules = mod;
3294}
3295
Miklos Szeredi065f2222006-01-20 15:15:21 +00003296#ifndef __FreeBSD__
3297
Miklos Szeredi95da8602006-01-06 18:29:40 +00003298static struct fuse *fuse_new_common_compat(int fd, const char *opts,
3299 const struct fuse_operations *op,
3300 size_t op_size, int compat)
3301{
3302 struct fuse *f;
3303 struct fuse_args args = FUSE_ARGS_INIT(0, NULL);
3304
Miklos Szeredi6e7d0182007-01-19 22:11:40 +00003305 if (fuse_opt_add_arg(&args, "") == -1)
3306 return NULL;
Miklos Szeredi95da8602006-01-06 18:29:40 +00003307 if (opts &&
Miklos Szeredi6e7d0182007-01-19 22:11:40 +00003308 (fuse_opt_add_arg(&args, "-o") == -1 ||
Miklos Szeredi95da8602006-01-06 18:29:40 +00003309 fuse_opt_add_arg(&args, opts) == -1)) {
3310 fuse_opt_free_args(&args);
3311 return NULL;
3312 }
Miklos Szeredi6f385412006-03-17 15:05:40 +00003313 f = fuse_new_common_compat25(fd, &args, op, op_size, compat);
Miklos Szeredi95da8602006-01-06 18:29:40 +00003314 fuse_opt_free_args(&args);
3315
3316 return f;
3317}
3318
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00003319struct fuse *fuse_new_compat22(int fd, const char *opts,
3320 const struct fuse_operations_compat22 *op,
3321 size_t op_size)
3322{
Miklos Szeredi95da8602006-01-06 18:29:40 +00003323 return fuse_new_common_compat(fd, opts, (struct fuse_operations *) op,
3324 op_size, 22);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00003325}
3326
3327struct fuse *fuse_new_compat2(int fd, const char *opts,
3328 const struct fuse_operations_compat2 *op)
3329{
Miklos Szeredi95da8602006-01-06 18:29:40 +00003330 return fuse_new_common_compat(fd, opts, (struct fuse_operations *) op,
3331 sizeof(struct fuse_operations_compat2), 21);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00003332}
3333
3334struct fuse *fuse_new_compat1(int fd, int flags,
3335 const struct fuse_operations_compat1 *op)
3336{
3337 const char *opts = NULL;
3338 if (flags & FUSE_DEBUG_COMPAT1)
3339 opts = "debug";
Miklos Szeredi95da8602006-01-06 18:29:40 +00003340 return fuse_new_common_compat(fd, opts, (struct fuse_operations *) op,
3341 sizeof(struct fuse_operations_compat1), 11);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00003342}
3343
Miklos Szeredif458b8c2004-12-07 16:46:42 +00003344__asm__(".symver fuse_exited,__fuse_exited@");
3345__asm__(".symver fuse_process_cmd,__fuse_process_cmd@");
3346__asm__(".symver fuse_read_cmd,__fuse_read_cmd@");
3347__asm__(".symver fuse_set_getcontext_func,__fuse_set_getcontext_func@");
3348__asm__(".symver fuse_new_compat2,fuse_new@");
Miklos Szeredi3a770472005-11-11 21:32:42 +00003349__asm__(".symver fuse_new_compat22,fuse_new@FUSE_2.2");
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00003350
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00003351#endif /* __FreeBSD__ */
Miklos Szeredi065f2222006-01-20 15:15:21 +00003352
3353struct fuse *fuse_new_compat25(int fd, struct fuse_args *args,
3354 const struct fuse_operations_compat25 *op,
3355 size_t op_size)
3356{
Miklos Szeredi6f385412006-03-17 15:05:40 +00003357 return fuse_new_common_compat25(fd, args, (struct fuse_operations *) op,
3358 op_size, 25);
Miklos Szeredi065f2222006-01-20 15:15:21 +00003359}
3360
3361__asm__(".symver fuse_new_compat25,fuse_new@FUSE_2.5");