blob: d756cf0655388a76f154867f60bda8662507deda [file] [log] [blame]
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001/*
2 FUSE: Filesystem in Userspace
Miklos Szeredi611ad932007-04-25 16:19:15 +00003 Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00004
Miklos Szeredi8b39a9f2002-10-25 12:41:16 +00005 This program can be distributed under the terms of the GNU LGPL.
6 See the file COPYING.LIB
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00007*/
8
Miklos Szeredie2aa2e22005-07-15 13:31:36 +00009
10/* For pthread_rwlock_t */
11#define _GNU_SOURCE
12
Miklos Szeredi178451d2005-08-15 13:19:07 +000013#include "fuse_i.h"
Miklos Szeredie2aa2e22005-07-15 13:31:36 +000014#include "fuse_lowlevel.h"
Miklos Szeredi659743b2005-12-09 17:41:42 +000015#include "fuse_opt.h"
Miklos Szeredi38f152c2006-09-03 18:28:52 +000016#include "fuse_misc.h"
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +000017#include "fuse_common_compat.h"
18#include "fuse_compat.h"
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000019
Miklos Szeredi0f62d722005-01-04 12:45:54 +000020#include <stdio.h>
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000021#include <string.h>
Miklos Szeredi97c61e92001-11-07 12:09:43 +000022#include <stdlib.h>
Miklos Szeredi659743b2005-12-09 17:41:42 +000023#include <stddef.h>
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000024#include <unistd.h>
Miklos Szeredi320abe42006-01-30 18:14:51 +000025#include <time.h>
Miklos Szeredib3f99722005-11-16 13:00:24 +000026#include <fcntl.h>
Miklos Szeredi97c61e92001-11-07 12:09:43 +000027#include <limits.h>
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000028#include <errno.h>
Miklos Szeredi288ed4e2006-09-07 06:02:44 +000029#include <signal.h>
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +000030#include <dlfcn.h>
Miklos Szeredi0f62d722005-01-04 12:45:54 +000031#include <assert.h>
Miklos Szeredi019b4e92001-12-26 18:08:09 +000032#include <sys/param.h>
Miklos Szerediab974562005-04-07 15:40:21 +000033#include <sys/uio.h>
Miklos Szeredi288ed4e2006-09-07 06:02:44 +000034#include <sys/time.h>
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000035
Miklos Szeredi97c61e92001-11-07 12:09:43 +000036#define FUSE_MAX_PATH 4096
Miklos Szeredi288ed4e2006-09-07 06:02:44 +000037#define FUSE_DEFAULT_INTR_SIGNAL SIGUSR1
Miklos Szeredi30e093a2005-04-03 17:44:54 +000038
Miklos Szeredie248e4b2005-12-14 16:18:32 +000039#define FUSE_UNKNOWN_INO 0xffffffff
Miklos Szeredi0c59ebf2006-09-10 20:53:36 +000040#define OFFSET_MAX 0x7fffffffffffffffLL
Miklos Szeredie248e4b2005-12-14 16:18:32 +000041
Miklos Szeredi659743b2005-12-09 17:41:42 +000042struct fuse_config {
Miklos Szeredi659743b2005-12-09 17:41:42 +000043 unsigned int uid;
44 unsigned int gid;
45 unsigned int umask;
46 double entry_timeout;
47 double negative_timeout;
48 double attr_timeout;
Miklos Szeredi6e806e92006-02-16 16:59:39 +000049 double ac_attr_timeout;
50 int ac_attr_timeout_set;
Miklos Szeredi659743b2005-12-09 17:41:42 +000051 int debug;
52 int hard_remove;
53 int use_ino;
54 int readdir_ino;
55 int set_mode;
56 int set_uid;
57 int set_gid;
58 int direct_io;
59 int kernel_cache;
Miklos Szeredi320abe42006-01-30 18:14:51 +000060 int auto_cache;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +000061 int intr;
62 int intr_signal;
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +000063 int help;
64 char *modules;
65};
66
67struct fuse_fs {
68 struct fuse_operations op;
69 struct fuse_module *m;
70 void *user_data;
71 int compat;
72};
73
74struct fusemod_so {
75 void *handle;
76 int ctr;
Miklos Szeredi659743b2005-12-09 17:41:42 +000077};
78
Miklos Szeredie2aa2e22005-07-15 13:31:36 +000079struct fuse {
Miklos Szeredia1482422005-08-14 23:00:27 +000080 struct fuse_session *se;
Miklos Szeredie2aa2e22005-07-15 13:31:36 +000081 struct node **name_table;
82 size_t name_table_size;
83 struct node **id_table;
84 size_t id_table_size;
85 fuse_ino_t ctr;
86 unsigned int generation;
87 unsigned int hidectr;
88 pthread_mutex_t lock;
89 pthread_rwlock_t tree_lock;
Miklos Szeredi659743b2005-12-09 17:41:42 +000090 struct fuse_config conf;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +000091 int intr_installed;
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +000092 struct fuse_fs *fs;
Miklos Szeredie2aa2e22005-07-15 13:31:36 +000093};
94
Miklos Szeredi0c59ebf2006-09-10 20:53:36 +000095struct lock {
96 int type;
97 off_t start;
98 off_t end;
99 pid_t pid;
100 uint64_t owner;
101 struct lock *next;
102};
103
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000104struct node {
105 struct node *name_next;
106 struct node *id_next;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000107 fuse_ino_t nodeid;
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000108 unsigned int generation;
109 int refctr;
Miklos Szeredi7bc05b02007-05-29 23:08:11 +0000110 struct node *parent;
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000111 char *name;
Miklos Szeredi38009022005-05-08 19:47:22 +0000112 uint64_t nlookup;
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000113 int open_count;
114 int is_hidden;
Miklos Szeredi320abe42006-01-30 18:14:51 +0000115 struct timespec stat_updated;
116 struct timespec mtime;
117 off_t size;
118 int cache_valid;
Miklos Szeredi0c59ebf2006-09-10 20:53:36 +0000119 struct lock *locks;
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000120};
121
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +0000122struct fuse_dh {
Miklos Szerediab974562005-04-07 15:40:21 +0000123 pthread_mutex_t lock;
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000124 struct fuse *fuse;
Miklos Szeredi1bf64f42006-02-17 15:49:25 +0000125 fuse_req_t req;
Miklos Szeredi1b188022005-07-28 11:07:29 +0000126 char *contents;
Miklos Szerediab974562005-04-07 15:40:21 +0000127 int allocated;
Miklos Szeredib92d9782005-02-07 16:10:49 +0000128 unsigned len;
Miklos Szeredic4c12ae2005-10-20 14:48:50 +0000129 unsigned size;
Miklos Szerediab974562005-04-07 15:40:21 +0000130 unsigned needlen;
Miklos Szeredi3ead28e2005-01-18 21:23:41 +0000131 int filled;
Miklos Szeredi3a770472005-11-11 21:32:42 +0000132 uint64_t fh;
Miklos Szerediab974562005-04-07 15:40:21 +0000133 int error;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000134 fuse_ino_t nodeid;
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000135};
136
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +0000137/* old dir handle */
138struct fuse_dirhandle {
139 fuse_fill_dir_t filler;
140 void *buf;
141};
142
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000143struct fuse_context_i {
144 struct fuse_context ctx;
145 fuse_req_t req;
146};
Miklos Szeredid169f312004-09-22 08:48:26 +0000147
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000148static pthread_key_t fuse_context_key;
149static pthread_mutex_t fuse_context_lock = PTHREAD_MUTEX_INITIALIZER;
150static int fuse_context_ref;
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +0000151static struct fusemod_so *fuse_current_so;
152static struct fuse_module *fuse_modules;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000153
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +0000154static int fuse_load_so_name(const char *soname)
155{
156 struct fusemod_so *so;
157
158 so = calloc(1, sizeof(struct fusemod_so));
159 if (!so) {
160 fprintf(stderr, "fuse: memory allocation failed\n");
161 return -1;
162 }
163
164 pthread_mutex_lock(&fuse_context_lock);
165 fuse_current_so = so;
166 so->handle = dlopen(soname, RTLD_NOW);
167 fuse_current_so = NULL;
168 pthread_mutex_unlock(&fuse_context_lock);
169 if (!so->handle) {
170 fprintf(stderr, "fuse: %s\n", dlerror());
171 goto err;
172 }
173 if (!so->ctr) {
174 fprintf(stderr, "fuse: %s did not register any modules", soname);
175 goto err;
176 }
177 return 0;
178
179 err:
180 if (so->handle)
181 dlclose(so->handle);
182 free(so);
183 return -1;
184}
185
186static int fuse_load_so_module(const char *module)
187{
188 int res;
189 char *soname = malloc(strlen(module) + 64);
190 if (!soname) {
191 fprintf(stderr, "fuse: memory allocation failed\n");
192 return -1;
193 }
194 if (soname)
195 sprintf(soname, "libfusemod_%s.so", module);
196
197 res = fuse_load_so_name(soname);
198 free(soname);
199 return res;
200}
201
202static struct fuse_module *fuse_find_module(const char *module)
203{
204 struct fuse_module *m;
205 for (m = fuse_modules; m; m = m->next) {
206 if (strcmp(module, m->name) == 0) {
207 m->ctr++;
208 break;
209 }
210 }
211 return m;
212}
213
214static struct fuse_module *fuse_get_module(const char *module)
215{
216 struct fuse_module *m;
217
218 pthread_mutex_lock(&fuse_context_lock);
219 m = fuse_find_module(module);
220 if (!m) {
221 int err = fuse_load_so_module(module);
222 if (!err)
223 m = fuse_find_module(module);
224 }
225 pthread_mutex_unlock(&fuse_context_lock);
226 return m;
227}
228
229static void fuse_put_module(struct fuse_module *m)
230{
231 pthread_mutex_lock(&fuse_context_lock);
232 assert(m->ctr > 0);
233 m->ctr--;
234 if (!m->ctr && m->so) {
235 struct fusemod_so *so = m->so;
236 assert(so->ctr > 0);
237 so->ctr--;
238 if (!so->ctr) {
239 struct fuse_module **mp;
240 for (mp = &fuse_modules; *mp;) {
241 if ((*mp)->so == so)
242 *mp = (*mp)->next;
243 else
244 mp = &(*mp)->next;
245 }
246 dlclose(so->handle);
247 free(so);
248 }
249 }
250 pthread_mutex_unlock(&fuse_context_lock);
251}
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +0000252
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000253static struct node *get_node_nocheck(struct fuse *f, fuse_ino_t nodeid)
Miklos Szeredia181e612001-11-06 12:03:23 +0000254{
Miklos Szeredia13d9002004-11-02 17:32:03 +0000255 size_t hash = nodeid % f->id_table_size;
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000256 struct node *node;
257
Miklos Szeredia13d9002004-11-02 17:32:03 +0000258 for (node = f->id_table[hash]; node != NULL; node = node->id_next)
259 if (node->nodeid == nodeid)
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000260 return node;
Miklos Szeredie5183742005-02-02 11:14:04 +0000261
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000262 return NULL;
Miklos Szeredia181e612001-11-06 12:03:23 +0000263}
264
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000265static struct node *get_node(struct fuse *f, fuse_ino_t nodeid)
Miklos Szeredia181e612001-11-06 12:03:23 +0000266{
Miklos Szeredif458b8c2004-12-07 16:46:42 +0000267 struct node *node = get_node_nocheck(f, nodeid);
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000268 if (!node) {
Miklos Szeredi3a770472005-11-11 21:32:42 +0000269 fprintf(stderr, "fuse internal error: node %llu not found\n",
270 (unsigned long long) nodeid);
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000271 abort();
272 }
273 return node;
Miklos Szeredia181e612001-11-06 12:03:23 +0000274}
275
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000276static void free_node(struct node *node)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000277{
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000278 free(node->name);
279 free(node);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000280}
281
Miklos Szeredia13d9002004-11-02 17:32:03 +0000282static void unhash_id(struct fuse *f, struct node *node)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000283{
Miklos Szeredia13d9002004-11-02 17:32:03 +0000284 size_t hash = node->nodeid % f->id_table_size;
285 struct node **nodep = &f->id_table[hash];
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000286
Miklos Szeredie5183742005-02-02 11:14:04 +0000287 for (; *nodep != NULL; nodep = &(*nodep)->id_next)
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000288 if (*nodep == node) {
Miklos Szeredia13d9002004-11-02 17:32:03 +0000289 *nodep = node->id_next;
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000290 return;
291 }
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000292}
293
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000294static void hash_id(struct fuse *f, struct node *node)
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000295{
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000296 size_t hash = node->nodeid % f->id_table_size;
297 node->id_next = f->id_table[hash];
Miklos Szeredie5183742005-02-02 11:14:04 +0000298 f->id_table[hash] = node;
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000299}
300
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +0000301static unsigned int name_hash(struct fuse *f, fuse_ino_t parent,
302 const char *name)
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000303{
304 unsigned int hash = *name;
305
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000306 if (hash)
307 for (name += 1; *name != '\0'; name++)
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000308 hash = (hash << 5) - hash + *name;
309
310 return (hash + parent) % f->name_table_size;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000311}
312
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000313static void unref_node(struct fuse *f, struct node *node);
314
315static void unhash_name(struct fuse *f, struct node *node)
316{
317 if (node->name) {
Miklos Szeredi7bc05b02007-05-29 23:08:11 +0000318 size_t hash = name_hash(f, node->parent->nodeid, node->name);
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000319 struct node **nodep = &f->name_table[hash];
Miklos Szeredie5183742005-02-02 11:14:04 +0000320
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000321 for (; *nodep != NULL; nodep = &(*nodep)->name_next)
322 if (*nodep == node) {
323 *nodep = node->name_next;
324 node->name_next = NULL;
Miklos Szeredi7bc05b02007-05-29 23:08:11 +0000325 unref_node(f, node->parent);
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000326 free(node->name);
327 node->name = NULL;
Miklos Szeredi7bc05b02007-05-29 23:08:11 +0000328 node->parent = NULL;
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000329 return;
330 }
Miklos Szeredi3a770472005-11-11 21:32:42 +0000331 fprintf(stderr, "fuse internal error: unable to unhash node: %llu\n",
332 (unsigned long long) node->nodeid);
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000333 abort();
334 }
335}
336
Miklos Szeredi7bc05b02007-05-29 23:08:11 +0000337static int hash_name(struct fuse *f, struct node *node, fuse_ino_t parentid,
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000338 const char *name)
339{
Miklos Szeredi7bc05b02007-05-29 23:08:11 +0000340 size_t hash = name_hash(f, parentid, name);
341 struct node *parent = get_node(f, parentid);
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000342 node->name = strdup(name);
343 if (node->name == NULL)
344 return -1;
345
Miklos Szeredi7bc05b02007-05-29 23:08:11 +0000346 parent->refctr ++;
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000347 node->parent = parent;
348 node->name_next = f->name_table[hash];
349 f->name_table[hash] = node;
350 return 0;
351}
352
353static void delete_node(struct fuse *f, struct node *node)
354{
Miklos Szeredi1f35c652007-06-18 14:27:47 +0000355 if (f->conf.debug)
356 fprintf(stderr, "delete: %llu\n", (unsigned long long) node->nodeid);
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)
Miklos Szeredi7bc05b02007-05-29 23:08:11 +0000389 if (node->parent->nodeid == 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;
Miklos Szeredi7bc05b02007-05-29 23:08:11 +0000456 node = 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 Szeredi1f35c652007-06-18 14:27:47 +00001230 if (f->conf.debug)
1231 fprintf(stderr, " NODEID: %lu\n", (unsigned long) e->ino);
Miklos Szeredi76f65782004-02-19 16:55:40 +00001232 }
1233 }
1234 return res;
1235}
1236
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001237static struct fuse_context_i *fuse_get_context_internal(void)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001238{
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001239 struct fuse_context_i *c;
1240
1241 c = (struct fuse_context_i *) pthread_getspecific(fuse_context_key);
1242 if (c == NULL) {
1243 c = (struct fuse_context_i *) malloc(sizeof(struct fuse_context_i));
1244 if (c == NULL) {
1245 /* This is hard to deal with properly, so just abort. If
1246 memory is so low that the context cannot be allocated,
1247 there's not much hope for the filesystem anyway */
1248 fprintf(stderr, "fuse: failed to allocate thread specific data\n");
1249 abort();
1250 }
1251 pthread_setspecific(fuse_context_key, c);
1252 }
1253 return c;
1254}
1255
1256static void fuse_freecontext(void *data)
1257{
1258 free(data);
1259}
1260
1261static int fuse_create_context_key(void)
1262{
1263 int err = 0;
1264 pthread_mutex_lock(&fuse_context_lock);
1265 if (!fuse_context_ref) {
1266 err = pthread_key_create(&fuse_context_key, fuse_freecontext);
1267 if (err) {
1268 fprintf(stderr, "fuse: failed to create thread specific key: %s\n",
1269 strerror(err));
1270 pthread_mutex_unlock(&fuse_context_lock);
1271 return -1;
1272 }
1273 }
1274 fuse_context_ref++;
1275 pthread_mutex_unlock(&fuse_context_lock);
1276 return 0;
1277}
1278
1279static void fuse_delete_context_key(void)
1280{
1281 pthread_mutex_lock(&fuse_context_lock);
1282 fuse_context_ref--;
1283 if (!fuse_context_ref) {
1284 free(pthread_getspecific(fuse_context_key));
1285 pthread_key_delete(fuse_context_key);
1286 }
1287 pthread_mutex_unlock(&fuse_context_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001288}
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001289
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001290static struct fuse *req_fuse_prepare(fuse_req_t req)
1291{
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001292 struct fuse_context_i *c = fuse_get_context_internal();
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001293 const struct fuse_ctx *ctx = fuse_req_ctx(req);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001294 c->req = req;
1295 c->ctx.fuse = req_fuse(req);
1296 c->ctx.uid = ctx->uid;
1297 c->ctx.gid = ctx->gid;
1298 c->ctx.pid = ctx->pid;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001299 return c->ctx.fuse;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001300}
1301
1302static inline void reply_err(fuse_req_t req, int err)
1303{
1304 /* fuse_reply_err() uses non-negated errno values */
1305 fuse_reply_err(req, -err);
1306}
1307
1308static void reply_entry(fuse_req_t req, const struct fuse_entry_param *e,
1309 int err)
1310{
1311 if (!err) {
Miklos Szeredib67f2162006-02-20 10:55:33 +00001312 struct fuse *f = req_fuse(req);
Miklos Szeredi9b813af2005-07-21 07:59:37 +00001313 if (fuse_reply_entry(req, e) == -ENOENT)
Miklos Szeredib67f2162006-02-20 10:55:33 +00001314 forget_node(f, e->ino, 1);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001315 } else
1316 reply_err(req, err);
1317}
1318
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001319void fuse_fs_init(struct fuse_fs *fs, struct fuse_conn_info *conn)
1320{
1321 fuse_get_context()->private_data = fs->user_data;
1322 if (fs->op.init)
1323 fs->user_data = fs->op.init(conn);
1324}
1325
1326static void fuse_lib_init(void *data, struct fuse_conn_info *conn)
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001327{
1328 struct fuse *f = (struct fuse *) data;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001329 struct fuse_context_i *c = fuse_get_context_internal();
Miklos Szeredi4f5df5e2005-10-07 12:39:58 +00001330
1331 memset(c, 0, sizeof(*c));
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001332 c->ctx.fuse = f;
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001333 fuse_fs_init(f->fs, conn);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001334}
1335
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001336void fuse_fs_destroy(struct fuse_fs *fs)
1337{
1338 fuse_get_context()->private_data = fs->user_data;
1339 if (fs->op.destroy)
1340 fs->op.destroy(fs->user_data);
1341 if (fs->m)
1342 fuse_put_module(fs->m);
1343 free(fs);
1344}
1345
1346static void fuse_lib_destroy(void *data)
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001347{
1348 struct fuse *f = (struct fuse *) data;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001349 struct fuse_context_i *c = fuse_get_context_internal();
Miklos Szeredi4f5df5e2005-10-07 12:39:58 +00001350
1351 memset(c, 0, sizeof(*c));
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001352 c->ctx.fuse = f;
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001353 fuse_fs_destroy(f->fs);
1354 f->fs = NULL;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001355}
1356
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001357static void fuse_lib_lookup(fuse_req_t req, fuse_ino_t parent,
1358 const char *name)
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001359{
1360 struct fuse *f = req_fuse_prepare(req);
1361 struct fuse_entry_param e;
1362 char *path;
1363 int err;
1364
1365 err = -ENOENT;
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001366 pthread_rwlock_rdlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001367 path = get_path_name(f, parent, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001368 if (path != NULL) {
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001369 struct fuse_intr_data d;
Miklos Szeredi1f35c652007-06-18 14:27:47 +00001370 if (f->conf.debug)
1371 fprintf(stderr, "LOOKUP %s\n", path);
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001372 fuse_prepare_interrupt(f, req, &d);
1373 err = lookup_path(f, parent, name, path, &e, NULL);
1374 if (err == -ENOENT && f->conf.negative_timeout != 0.0) {
1375 e.ino = 0;
1376 e.entry_timeout = f->conf.negative_timeout;
1377 err = 0;
Miklos Szeredi2b478112005-11-28 13:27:10 +00001378 }
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001379 fuse_finish_interrupt(f, req, &d);
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001380 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001381 }
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001382 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001383 reply_entry(req, &e, err);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001384}
1385
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001386static void fuse_lib_forget(fuse_req_t req, fuse_ino_t ino,
1387 unsigned long nlookup)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001388{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001389 struct fuse *f = req_fuse(req);
Miklos Szeredi1f35c652007-06-18 14:27:47 +00001390 if (f->conf.debug)
1391 fprintf(stderr, "FORGET %llu/%lu\n", (unsigned long long)ino, nlookup);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001392 forget_node(f, ino, nlookup);
1393 fuse_reply_none(req);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001394}
1395
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001396static void fuse_lib_getattr(fuse_req_t req, fuse_ino_t ino,
1397 struct fuse_file_info *fi)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001398{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001399 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredi19dff1b2001-10-30 15:06:52 +00001400 struct stat buf;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001401 char *path;
1402 int err;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001403
Miklos Szerediecce1bf2005-08-25 15:19:06 +00001404 (void) fi;
Miklos Szeredi16dbf942006-09-02 13:20:40 +00001405 memset(&buf, 0, sizeof(buf));
Miklos Szerediecce1bf2005-08-25 15:19:06 +00001406
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001407 err = -ENOENT;
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001408 pthread_rwlock_rdlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001409 path = get_path(f, ino);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001410 if (path != NULL) {
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001411 struct fuse_intr_data d;
1412 fuse_prepare_interrupt(f, req, &d);
1413 err = fuse_fs_getattr(f->fs, path, &buf);
1414 fuse_finish_interrupt(f, req, &d);
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001415 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001416 }
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001417 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001418 if (!err) {
Miklos Szeredi08dab162006-02-01 13:39:15 +00001419 if (f->conf.auto_cache) {
1420 pthread_mutex_lock(&f->lock);
1421 update_stat(get_node(f, ino), &buf);
1422 pthread_mutex_unlock(&f->lock);
1423 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001424 set_stat(f, ino, &buf);
Miklos Szeredi659743b2005-12-09 17:41:42 +00001425 fuse_reply_attr(req, &buf, f->conf.attr_timeout);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001426 } else
1427 reply_err(req, err);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001428}
1429
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001430int fuse_fs_chmod(struct fuse_fs *fs, const char *path, mode_t mode)
Miklos Szeredif3ea83b2001-11-07 14:55:16 +00001431{
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001432 if (fs->op.chmod)
1433 return fs->op.chmod(path, mode);
1434 else
1435 return -ENOSYS;
Miklos Szeredie5183742005-02-02 11:14:04 +00001436}
Miklos Szeredif3ea83b2001-11-07 14:55:16 +00001437
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001438static void fuse_lib_setattr(fuse_req_t req, fuse_ino_t ino, struct stat *attr,
1439 int valid, struct fuse_file_info *fi)
Miklos Szeredi5e183482001-10-31 14:52:35 +00001440{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001441 struct fuse *f = req_fuse_prepare(req);
1442 struct stat buf;
Miklos Szeredi5e183482001-10-31 14:52:35 +00001443 char *path;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001444 int err;
Miklos Szeredi5e183482001-10-31 14:52:35 +00001445
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001446 err = -ENOENT;
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001447 pthread_rwlock_rdlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001448 path = get_path(f, ino);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001449 if (path != NULL) {
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001450 struct fuse_intr_data d;
1451 fuse_prepare_interrupt(f, req, &d);
1452 err = 0;
1453 if (!err && (valid & FUSE_SET_ATTR_MODE))
1454 err = fuse_fs_chmod(f->fs, path, attr->st_mode);
1455 if (!err && (valid & (FUSE_SET_ATTR_UID | FUSE_SET_ATTR_GID))) {
1456 uid_t uid =
1457 (valid & FUSE_SET_ATTR_UID) ? attr->st_uid : (uid_t) -1;
1458 gid_t gid =
1459 (valid & FUSE_SET_ATTR_GID) ? attr->st_gid : (gid_t) -1;
1460 err = fuse_fs_chown(f->fs, path, uid, gid);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001461 }
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001462 if (!err && (valid & FUSE_SET_ATTR_SIZE)) {
1463 if (fi)
1464 err = fuse_fs_ftruncate(f->fs, path, attr->st_size, fi);
1465 else
1466 err = fuse_fs_truncate(f->fs, path, attr->st_size);
1467 }
1468 if (!err && (valid & (FUSE_SET_ATTR_ATIME | FUSE_SET_ATTR_MTIME)) ==
1469 (FUSE_SET_ATTR_ATIME | FUSE_SET_ATTR_MTIME)) {
1470 struct timespec tv[2];
1471 tv[0].tv_sec = attr->st_atime;
1472 tv[0].tv_nsec = ST_ATIM_NSEC(attr);
1473 tv[1].tv_sec = attr->st_mtime;
1474 tv[1].tv_nsec = ST_MTIM_NSEC(attr);
1475 err = fuse_fs_utimens(f->fs, path, tv);
1476 }
1477 if (!err)
1478 err = fuse_fs_getattr(f->fs, path, &buf);
1479 fuse_finish_interrupt(f, req, &d);
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001480 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001481 }
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001482 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001483 if (!err) {
Miklos Szeredi08dab162006-02-01 13:39:15 +00001484 if (f->conf.auto_cache) {
1485 pthread_mutex_lock(&f->lock);
1486 update_stat(get_node(f, ino), &buf);
1487 pthread_mutex_unlock(&f->lock);
1488 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001489 set_stat(f, ino, &buf);
Miklos Szeredi659743b2005-12-09 17:41:42 +00001490 fuse_reply_attr(req, &buf, f->conf.attr_timeout);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001491 } else
1492 reply_err(req, err);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001493}
1494
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001495static void fuse_lib_access(fuse_req_t req, fuse_ino_t ino, int mask)
Miklos Szeredib0b13d12005-10-26 12:53:25 +00001496{
1497 struct fuse *f = req_fuse_prepare(req);
1498 char *path;
1499 int err;
1500
1501 err = -ENOENT;
1502 pthread_rwlock_rdlock(&f->tree_lock);
1503 path = get_path(f, ino);
1504 if (path != NULL) {
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001505 struct fuse_intr_data d;
Miklos Szeredi1f35c652007-06-18 14:27:47 +00001506 if (f->conf.debug)
1507 fprintf(stderr, "ACCESS %s 0%o\n", path, mask);
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001508 fuse_prepare_interrupt(f, req, &d);
1509 err = fuse_fs_access(f->fs, path, mask);
1510 fuse_finish_interrupt(f, req, &d);
Miklos Szeredib0b13d12005-10-26 12:53:25 +00001511 free(path);
1512 }
1513 pthread_rwlock_unlock(&f->tree_lock);
1514 reply_err(req, err);
1515}
1516
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001517static void fuse_lib_readlink(fuse_req_t req, fuse_ino_t ino)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001518{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001519 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredif6e0ec62005-08-03 09:11:06 +00001520 char linkname[PATH_MAX + 1];
Miklos Szeredib483c932001-10-29 14:57:57 +00001521 char *path;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001522 int err;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001523
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001524 err = -ENOENT;
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001525 pthread_rwlock_rdlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001526 path = get_path(f, ino);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001527 if (path != NULL) {
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001528 struct fuse_intr_data d;
1529 fuse_prepare_interrupt(f, req, &d);
1530 err = fuse_fs_readlink(f->fs, path, linkname, sizeof(linkname));
1531 fuse_finish_interrupt(f, req, &d);
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001532 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001533 }
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001534 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001535 if (!err) {
Miklos Szeredif6e0ec62005-08-03 09:11:06 +00001536 linkname[PATH_MAX] = '\0';
1537 fuse_reply_readlink(req, linkname);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001538 } else
1539 reply_err(req, err);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001540}
1541
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001542static void fuse_lib_mknod(fuse_req_t req, fuse_ino_t parent, const char *name,
1543 mode_t mode, dev_t rdev)
Miklos Szeredib483c932001-10-29 14:57:57 +00001544{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001545 struct fuse *f = req_fuse_prepare(req);
1546 struct fuse_entry_param e;
Miklos Szeredib483c932001-10-29 14:57:57 +00001547 char *path;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001548 int err;
Miklos Szeredib483c932001-10-29 14:57:57 +00001549
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001550 err = -ENOENT;
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001551 pthread_rwlock_rdlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001552 path = get_path_name(f, parent, name);
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001553 if (path) {
1554 struct fuse_intr_data d;
Miklos Szeredi1f35c652007-06-18 14:27:47 +00001555 if (f->conf.debug)
1556 fprintf(stderr, "MKNOD %s\n", path);
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001557 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001558 err = -ENOSYS;
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001559 if (S_ISREG(mode)) {
Miklos Szeredib3f99722005-11-16 13:00:24 +00001560 struct fuse_file_info fi;
1561
1562 memset(&fi, 0, sizeof(fi));
1563 fi.flags = O_CREAT | O_EXCL | O_WRONLY;
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001564 err = fuse_fs_create(f->fs, path, mode, &fi);
Miklos Szeredib3f99722005-11-16 13:00:24 +00001565 if (!err) {
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001566 err = lookup_path(f, parent, name, path, &e, &fi);
1567 fuse_fs_release(f->fs, path, &fi);
Miklos Szeredib3f99722005-11-16 13:00:24 +00001568 }
Miklos Szeredi5e183482001-10-31 14:52:35 +00001569 }
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001570 if (err == -ENOSYS) {
1571 err = fuse_fs_mknod(f->fs, path, mode, rdev);
1572 if (!err)
1573 err = lookup_path(f, parent, name, path, &e, NULL);
1574 }
1575 fuse_finish_interrupt(f, req, &d);
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001576 free(path);
Miklos Szeredib483c932001-10-29 14:57:57 +00001577 }
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001578 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001579 reply_entry(req, &e, err);
Miklos Szeredib483c932001-10-29 14:57:57 +00001580}
1581
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001582static void fuse_lib_mkdir(fuse_req_t req, fuse_ino_t parent, const char *name,
1583 mode_t mode)
Miklos Szeredib483c932001-10-29 14:57:57 +00001584{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001585 struct fuse *f = req_fuse_prepare(req);
1586 struct fuse_entry_param e;
Miklos Szeredib483c932001-10-29 14:57:57 +00001587 char *path;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001588 int err;
Miklos Szeredib483c932001-10-29 14:57:57 +00001589
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001590 err = -ENOENT;
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001591 pthread_rwlock_rdlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001592 path = get_path_name(f, parent, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001593 if (path != NULL) {
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001594 struct fuse_intr_data d;
Miklos Szeredi1f35c652007-06-18 14:27:47 +00001595 if (f->conf.debug)
1596 fprintf(stderr, "MKDIR %s\n", path);
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001597 fuse_prepare_interrupt(f, req, &d);
1598 err = fuse_fs_mkdir(f->fs, path, mode);
1599 if (!err)
1600 err = lookup_path(f, parent, name, path, &e, NULL);
1601 fuse_finish_interrupt(f, req, &d);
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001602 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001603 }
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001604 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001605 reply_entry(req, &e, err);
Miklos Szeredib483c932001-10-29 14:57:57 +00001606}
1607
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001608static void fuse_lib_unlink(fuse_req_t req, fuse_ino_t parent,
1609 const char *name)
Miklos Szeredib483c932001-10-29 14:57:57 +00001610{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001611 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredib483c932001-10-29 14:57:57 +00001612 char *path;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001613 int err;
Miklos Szeredib483c932001-10-29 14:57:57 +00001614
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001615 err = -ENOENT;
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001616 pthread_rwlock_wrlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001617 path = get_path_name(f, parent, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001618 if (path != NULL) {
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001619 struct fuse_intr_data d;
Miklos Szeredi1f35c652007-06-18 14:27:47 +00001620 if (f->conf.debug)
1621 fprintf(stderr, "UNLINK %s\n", path);
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001622 fuse_prepare_interrupt(f, req, &d);
1623 if (!f->conf.hard_remove && is_open(f, parent, name))
1624 err = hide_node(f, path, parent, name);
1625 else {
1626 err = fuse_fs_unlink(f->fs, path);
1627 if (!err)
1628 remove_node(f, parent, name);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001629 }
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001630 fuse_finish_interrupt(f, req, &d);
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001631 free(path);
Miklos Szeredib483c932001-10-29 14:57:57 +00001632 }
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001633 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001634 reply_err(req, err);
Miklos Szeredib5958612004-02-20 14:10:49 +00001635}
1636
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001637static void fuse_lib_rmdir(fuse_req_t req, fuse_ino_t parent, const char *name)
Miklos Szeredib5958612004-02-20 14:10:49 +00001638{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001639 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredib5958612004-02-20 14:10:49 +00001640 char *path;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001641 int err;
Miklos Szeredib5958612004-02-20 14:10:49 +00001642
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001643 err = -ENOENT;
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001644 pthread_rwlock_wrlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001645 path = get_path_name(f, parent, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001646 if (path != NULL) {
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001647 struct fuse_intr_data d;
Miklos Szeredi1f35c652007-06-18 14:27:47 +00001648 if (f->conf.debug)
1649 fprintf(stderr, "RMDIR %s\n", path);
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001650 fuse_prepare_interrupt(f, req, &d);
1651 err = fuse_fs_rmdir(f->fs, path);
1652 fuse_finish_interrupt(f, req, &d);
1653 if (!err)
1654 remove_node(f, parent, name);
Miklos Szeredib5958612004-02-20 14:10:49 +00001655 free(path);
1656 }
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001657 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001658 reply_err(req, err);
Miklos Szeredib483c932001-10-29 14:57:57 +00001659}
1660
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001661static void fuse_lib_symlink(fuse_req_t req, const char *linkname,
1662 fuse_ino_t parent, const char *name)
Miklos Szeredib483c932001-10-29 14:57:57 +00001663{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001664 struct fuse *f = req_fuse_prepare(req);
1665 struct fuse_entry_param e;
Miklos Szeredib483c932001-10-29 14:57:57 +00001666 char *path;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001667 int err;
Miklos Szeredib483c932001-10-29 14:57:57 +00001668
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001669 err = -ENOENT;
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001670 pthread_rwlock_rdlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001671 path = get_path_name(f, parent, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001672 if (path != NULL) {
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001673 struct fuse_intr_data d;
Miklos Szeredi1f35c652007-06-18 14:27:47 +00001674 if (f->conf.debug)
1675 fprintf(stderr, "SYMLINK %s\n", path);
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001676 fuse_prepare_interrupt(f, req, &d);
1677 err = fuse_fs_symlink(f->fs, linkname, path);
1678 if (!err)
1679 err = lookup_path(f, parent, name, path, &e, NULL);
1680 fuse_finish_interrupt(f, req, &d);
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001681 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001682 }
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001683 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001684 reply_entry(req, &e, err);
Miklos Szeredib483c932001-10-29 14:57:57 +00001685}
1686
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001687static void fuse_lib_rename(fuse_req_t req, fuse_ino_t olddir,
1688 const char *oldname, fuse_ino_t newdir,
1689 const char *newname)
Miklos Szeredi19dff1b2001-10-30 15:06:52 +00001690{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001691 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001692 char *oldpath;
1693 char *newpath;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001694 int err;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +00001695
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001696 err = -ENOENT;
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001697 pthread_rwlock_wrlock(&f->tree_lock);
Miklos Szeredia181e612001-11-06 12:03:23 +00001698 oldpath = get_path_name(f, olddir, oldname);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001699 if (oldpath != NULL) {
Miklos Szeredia181e612001-11-06 12:03:23 +00001700 newpath = get_path_name(f, newdir, newname);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001701 if (newpath != NULL) {
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001702 struct fuse_intr_data d;
Miklos Szeredi1f35c652007-06-18 14:27:47 +00001703 if (f->conf.debug)
1704 fprintf(stderr, "RENAME %s -> %s\n", oldpath, newpath);
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001705 err = 0;
1706 fuse_prepare_interrupt(f, req, &d);
1707 if (!f->conf.hard_remove && is_open(f, newdir, newname))
1708 err = hide_node(f, newpath, newdir, newname);
1709 if (!err) {
1710 err = fuse_fs_rename(f->fs, oldpath, newpath);
1711 if (!err)
1712 err = rename_node(f, olddir, oldname, newdir, newname, 0);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001713 }
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001714 fuse_finish_interrupt(f, req, &d);
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001715 free(newpath);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001716 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001717 free(oldpath);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001718 }
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001719 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001720 reply_err(req, err);
Miklos Szeredi19dff1b2001-10-30 15:06:52 +00001721}
1722
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001723static void fuse_lib_link(fuse_req_t req, fuse_ino_t ino, fuse_ino_t newparent,
1724 const char *newname)
Miklos Szeredi19dff1b2001-10-30 15:06:52 +00001725{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001726 struct fuse *f = req_fuse_prepare(req);
1727 struct fuse_entry_param e;
Miklos Szeredi5e183482001-10-31 14:52:35 +00001728 char *oldpath;
1729 char *newpath;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001730 int err;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +00001731
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001732 err = -ENOENT;
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001733 pthread_rwlock_rdlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001734 oldpath = get_path(f, ino);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001735 if (oldpath != NULL) {
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001736 newpath = get_path_name(f, newparent, newname);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001737 if (newpath != NULL) {
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001738 struct fuse_intr_data d;
Miklos Szeredi1f35c652007-06-18 14:27:47 +00001739 if (f->conf.debug)
1740 fprintf(stderr, "LINK %s\n", newpath);
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001741 fuse_prepare_interrupt(f, req, &d);
1742 err = fuse_fs_link(f->fs, oldpath, newpath);
1743 if (!err)
1744 err = lookup_path(f, newparent, newname, newpath, &e, NULL);
1745 fuse_finish_interrupt(f, req, &d);
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001746 free(newpath);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001747 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001748 free(oldpath);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001749 }
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001750 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001751 reply_entry(req, &e, err);
Miklos Szeredi19dff1b2001-10-30 15:06:52 +00001752}
1753
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001754static void fuse_do_release(struct fuse *f, fuse_ino_t ino, const char *path,
1755 struct fuse_file_info *fi)
1756{
1757 struct node *node;
1758 int unlink_hidden = 0;
1759
1760 fuse_fs_release(f->fs, path ? path : "-", fi);
1761
1762 pthread_mutex_lock(&f->lock);
1763 node = get_node(f, ino);
1764 assert(node->open_count > 0);
1765 --node->open_count;
1766 if (node->is_hidden && !node->open_count) {
1767 unlink_hidden = 1;
1768 node->is_hidden = 0;
1769 }
1770 pthread_mutex_unlock(&f->lock);
1771
1772 if(unlink_hidden && path)
1773 fuse_fs_unlink(f->fs, path);
1774}
1775
1776static void fuse_lib_create(fuse_req_t req, fuse_ino_t parent,
1777 const char *name, mode_t mode,
1778 struct fuse_file_info *fi)
Miklos Szeredid9079a72005-10-26 15:29:06 +00001779{
1780 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001781 struct fuse_intr_data d;
Miklos Szeredid9079a72005-10-26 15:29:06 +00001782 struct fuse_entry_param e;
1783 char *path;
1784 int err;
1785
1786 err = -ENOENT;
1787 pthread_rwlock_rdlock(&f->tree_lock);
1788 path = get_path_name(f, parent, name);
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001789 if (path) {
1790 fuse_prepare_interrupt(f, req, &d);
1791 err = fuse_fs_create(f->fs, path, mode, fi);
1792 if (!err) {
1793 err = lookup_path(f, parent, name, path, &e, fi);
1794 if (err)
1795 fuse_fs_release(f->fs, path, fi);
1796 else if (!S_ISREG(e.attr.st_mode)) {
1797 err = -EIO;
1798 fuse_fs_release(f->fs, path, fi);
1799 forget_node(f, e.ino, 1);
1800 } else {
1801 if (f->conf.direct_io)
1802 fi->direct_io = 1;
1803 if (f->conf.kernel_cache)
1804 fi->keep_cache = 1;
1805
Miklos Szeredid9079a72005-10-26 15:29:06 +00001806 }
1807 }
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001808 fuse_finish_interrupt(f, req, &d);
Miklos Szeredid9079a72005-10-26 15:29:06 +00001809 }
Miklos Szeredid9079a72005-10-26 15:29:06 +00001810 if (!err) {
Miklos Szeredid9079a72005-10-26 15:29:06 +00001811 pthread_mutex_lock(&f->lock);
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001812 get_node(f, e.ino)->open_count++;
1813 pthread_mutex_unlock(&f->lock);
Miklos Szeredid9079a72005-10-26 15:29:06 +00001814 if (fuse_reply_create(req, &e, fi) == -ENOENT) {
1815 /* The open syscall was interrupted, so it must be cancelled */
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001816 fuse_prepare_interrupt(f, req, &d);
1817 fuse_do_release(f, e.ino, path, fi);
1818 fuse_finish_interrupt(f, req, &d);
Miklos Szeredid9079a72005-10-26 15:29:06 +00001819 forget_node(f, e.ino, 1);
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001820 } else if (f->conf.debug) {
Miklos Szeredi1f35c652007-06-18 14:27:47 +00001821 fprintf(stderr, " CREATE[%llu] flags: 0x%x %s\n",
1822 (unsigned long long) fi->fh, fi->flags, path);
Miklos Szeredid9079a72005-10-26 15:29:06 +00001823 }
Miklos Szeredid9079a72005-10-26 15:29:06 +00001824 } else
1825 reply_err(req, err);
1826
1827 if (path)
1828 free(path);
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001829
Miklos Szeredid9079a72005-10-26 15:29:06 +00001830 pthread_rwlock_unlock(&f->tree_lock);
1831}
1832
Miklos Szeredi320abe42006-01-30 18:14:51 +00001833static double diff_timespec(const struct timespec *t1,
1834 const struct timespec *t2)
1835{
1836 return (t1->tv_sec - t2->tv_sec) +
1837 ((double) t1->tv_nsec - (double) t2->tv_nsec) / 1000000000.0;
1838}
1839
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001840static void open_auto_cache(struct fuse *f, fuse_ino_t ino, const char *path,
1841 struct fuse_file_info *fi)
Miklos Szeredi320abe42006-01-30 18:14:51 +00001842{
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001843 struct node *node;
1844
1845 pthread_mutex_lock(&f->lock);
1846 node = get_node(f, ino);
Miklos Szeredi08dab162006-02-01 13:39:15 +00001847 if (node->cache_valid) {
1848 struct timespec now;
Miklos Szeredi320abe42006-01-30 18:14:51 +00001849
Miklos Szeredi08dab162006-02-01 13:39:15 +00001850 curr_time(&now);
Miklos Szeredi6e806e92006-02-16 16:59:39 +00001851 if (diff_timespec(&now, &node->stat_updated) > f->conf.ac_attr_timeout) {
Miklos Szeredi08dab162006-02-01 13:39:15 +00001852 struct stat stbuf;
1853 int err;
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001854 pthread_mutex_unlock(&f->lock);
1855 err = fuse_fs_fgetattr(f->fs, path, &stbuf, fi);
1856 pthread_mutex_lock(&f->lock);
Miklos Szeredi08dab162006-02-01 13:39:15 +00001857 if (!err)
1858 update_stat(node, &stbuf);
1859 else
1860 node->cache_valid = 0;
1861 }
Miklos Szeredi320abe42006-01-30 18:14:51 +00001862 }
1863 if (node->cache_valid)
1864 fi->keep_cache = 1;
Miklos Szeredi08dab162006-02-01 13:39:15 +00001865
1866 node->cache_valid = 1;
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001867 pthread_mutex_unlock(&f->lock);
Miklos Szeredi320abe42006-01-30 18:14:51 +00001868}
1869
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001870static void fuse_lib_open(fuse_req_t req, fuse_ino_t ino,
1871 struct fuse_file_info *fi)
Miklos Szeredi5e183482001-10-31 14:52:35 +00001872{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001873 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001874 struct fuse_intr_data d;
Miklos Szeredi31066bb2005-08-01 14:49:31 +00001875 char *path = NULL;
1876 int err = 0;
Miklos Szeredi5e183482001-10-31 14:52:35 +00001877
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001878 err = -ENOENT;
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001879 pthread_rwlock_rdlock(&f->tree_lock);
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001880 path = get_path(f, ino);
1881 if (path) {
1882 fuse_prepare_interrupt(f, req, &d);
1883 err = fuse_fs_open(f->fs, path, fi);
1884 if (!err) {
1885 if (f->conf.direct_io)
1886 fi->direct_io = 1;
1887 if (f->conf.kernel_cache)
1888 fi->keep_cache = 1;
1889
1890 if (f->conf.auto_cache)
1891 open_auto_cache(f, ino, path, fi);
1892 }
1893 fuse_finish_interrupt(f, req, &d);
Miklos Szeredi40b9a5a2002-12-10 16:09:02 +00001894 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001895 if (!err) {
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001896 pthread_mutex_lock(&f->lock);
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001897 get_node(f, ino)->open_count++;
1898 pthread_mutex_unlock(&f->lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001899 if (fuse_reply_open(req, fi) == -ENOENT) {
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001900 /* The open syscall was interrupted, so it must be cancelled */
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001901 fuse_prepare_interrupt(f, req, &d);
1902 fuse_do_release(f, ino, path, fi);
1903 fuse_finish_interrupt(f, req, &d);
1904 } else if (f->conf.debug) {
Miklos Szeredi1f35c652007-06-18 14:27:47 +00001905 fprintf(stderr, "OPEN[%llu] flags: 0x%x %s\n",
1906 (unsigned long long) fi->fh, fi->flags, path);
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001907 }
Miklos Szeredi73798f92004-07-12 15:55:11 +00001908 } else
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001909 reply_err(req, err);
Miklos Szeredi73798f92004-07-12 15:55:11 +00001910
Miklos Szeredi9a31cca2004-06-26 21:11:25 +00001911 if (path)
1912 free(path);
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001913 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001914}
1915
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001916static void fuse_lib_read(fuse_req_t req, fuse_ino_t ino, size_t size,
1917 off_t off, struct fuse_file_info *fi)
Miklos Szeredie2e4ac22004-05-18 08:45:28 +00001918{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001919 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredie2e4ac22004-05-18 08:45:28 +00001920 char *path;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001921 char *buf;
Miklos Szeredie2e4ac22004-05-18 08:45:28 +00001922 int res;
1923
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001924 buf = (char *) malloc(size);
1925 if (buf == NULL) {
1926 reply_err(req, -ENOMEM);
1927 return;
1928 }
1929
Miklos Szeredie2e4ac22004-05-18 08:45:28 +00001930 res = -ENOENT;
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001931 pthread_rwlock_rdlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001932 path = get_path(f, ino);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001933 if (path != NULL) {
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001934 struct fuse_intr_data d;
Miklos Szeredi1f35c652007-06-18 14:27:47 +00001935 if (f->conf.debug)
1936 fprintf(stderr, "READ[%llu] %lu bytes from %llu\n",
1937 (unsigned long long) fi->fh, (unsigned long) size,
1938 (unsigned long long) off);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001939
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001940 fuse_prepare_interrupt(f, req, &d);
1941 res = fuse_fs_read(f->fs, path, buf, size, off, fi);
1942 fuse_finish_interrupt(f, req, &d);
Miklos Szeredie2e4ac22004-05-18 08:45:28 +00001943 free(path);
1944 }
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001945 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001946
1947 if (res >= 0) {
Miklos Szeredi1f35c652007-06-18 14:27:47 +00001948 if (f->conf.debug)
1949 fprintf(stderr, " READ[%llu] %u bytes\n",
1950 (unsigned long long)fi->fh, res);
Miklos Szeredif412d072005-10-14 21:24:32 +00001951 if ((size_t) res > size)
1952 fprintf(stderr, "fuse: read too many bytes");
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001953 fuse_reply_buf(req, buf, res);
1954 } else
1955 reply_err(req, res);
1956
1957 free(buf);
Miklos Szeredie2e4ac22004-05-18 08:45:28 +00001958}
1959
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001960static void fuse_lib_write(fuse_req_t req, fuse_ino_t ino, const char *buf,
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001961 size_t size, off_t off, struct fuse_file_info *fi)
Miklos Szeredic8ba2372002-12-10 12:26:00 +00001962{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001963 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001964 char *path;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001965 int res;
1966
1967 res = -ENOENT;
1968 pthread_rwlock_rdlock(&f->tree_lock);
1969 path = get_path(f, ino);
1970 if (path != NULL) {
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001971 struct fuse_intr_data d;
Miklos Szeredi1f35c652007-06-18 14:27:47 +00001972 if (f->conf.debug)
1973 fprintf(stderr, "WRITE%s[%llu] %lu bytes to %llu\n",
1974 fi->writepage ? "PAGE" : "", (unsigned long long) fi->fh,
1975 (unsigned long) size, (unsigned long long) off);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001976
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001977 fuse_prepare_interrupt(f, req, &d);
1978 res = fuse_fs_write(f->fs, path, buf, size, off, fi);
1979 fuse_finish_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001980 free(path);
1981 }
1982 pthread_rwlock_unlock(&f->tree_lock);
1983
Miklos Szeredif412d072005-10-14 21:24:32 +00001984 if (res >= 0) {
Miklos Szeredi1f35c652007-06-18 14:27:47 +00001985 if (f->conf.debug)
1986 fprintf(stderr, " WRITE%s[%llu] %u bytes\n",
1987 fi->writepage ? "PAGE" : "", (unsigned long long) fi->fh,
1988 res);
Miklos Szeredif412d072005-10-14 21:24:32 +00001989 if ((size_t) res > size)
1990 fprintf(stderr, "fuse: wrote too many bytes");
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001991 fuse_reply_write(req, res);
Miklos Szeredif412d072005-10-14 21:24:32 +00001992 } else
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001993 reply_err(req, res);
1994}
1995
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001996static void fuse_lib_fsync(fuse_req_t req, fuse_ino_t ino, int datasync,
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001997 struct fuse_file_info *fi)
Miklos Szeredi5e183482001-10-31 14:52:35 +00001998{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001999 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredi5e183482001-10-31 14:52:35 +00002000 char *path;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002001 int err;
Miklos Szerediab974562005-04-07 15:40:21 +00002002
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002003 err = -ENOENT;
2004 pthread_rwlock_rdlock(&f->tree_lock);
2005 path = get_path(f, ino);
2006 if (path != NULL) {
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002007 struct fuse_intr_data d;
Miklos Szeredi1f35c652007-06-18 14:27:47 +00002008 if (f->conf.debug)
2009 fprintf(stderr, "FSYNC[%llu]\n", (unsigned long long) fi->fh);
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002010 fuse_prepare_interrupt(f, req, &d);
2011 err = fuse_fs_fsync(f->fs, path, datasync, fi);
2012 fuse_finish_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002013 free(path);
2014 }
2015 pthread_rwlock_unlock(&f->tree_lock);
2016 reply_err(req, err);
2017}
2018
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002019static struct fuse_dh *get_dirhandle(const struct fuse_file_info *llfi,
2020 struct fuse_file_info *fi)
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002021{
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002022 struct fuse_dh *dh = (struct fuse_dh *) (uintptr_t) llfi->fh;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002023 memset(fi, 0, sizeof(struct fuse_file_info));
2024 fi->fh = dh->fh;
Miklos Szerediead7f102005-11-28 16:02:27 +00002025 fi->fh_old = dh->fh;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002026 return dh;
2027}
2028
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002029static void fuse_lib_opendir(fuse_req_t req, fuse_ino_t ino,
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002030 struct fuse_file_info *llfi)
2031{
2032 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002033 struct fuse_intr_data d;
2034 struct fuse_dh *dh;
2035 struct fuse_file_info fi;
2036 char *path;
2037 int err;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002038
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002039 dh = (struct fuse_dh *) malloc(sizeof(struct fuse_dh));
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002040 if (dh == NULL) {
2041 reply_err(req, -ENOMEM);
Miklos Szerediab974562005-04-07 15:40:21 +00002042 return;
Miklos Szeredi5e183482001-10-31 14:52:35 +00002043 }
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002044 memset(dh, 0, sizeof(struct fuse_dh));
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002045 dh->fuse = f;
2046 dh->contents = NULL;
2047 dh->len = 0;
2048 dh->filled = 0;
2049 dh->nodeid = ino;
Miklos Szeredi38f152c2006-09-03 18:28:52 +00002050 fuse_mutex_init(&dh->lock);
Miklos Szerediab974562005-04-07 15:40:21 +00002051
Miklos Szeredi3a770472005-11-11 21:32:42 +00002052 llfi->fh = (uintptr_t) dh;
Miklos Szerediab974562005-04-07 15:40:21 +00002053
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002054 memset(&fi, 0, sizeof(fi));
2055 fi.flags = llfi->flags;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002056
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002057 err = -ENOENT;
2058 pthread_rwlock_rdlock(&f->tree_lock);
2059 path = get_path(f, ino);
2060 if (path != NULL) {
2061 fuse_prepare_interrupt(f, req, &d);
2062 err = fuse_fs_opendir(f->fs, path, &fi);
2063 fuse_finish_interrupt(f, req, &d);
2064 dh->fh = fi.fh;
2065 }
2066 if (!err) {
2067 if (fuse_reply_open(req, llfi) == -ENOENT) {
2068 /* The opendir syscall was interrupted, so it must be cancelled */
2069 fuse_prepare_interrupt(f, req, &d);
2070 fuse_fs_releasedir(f->fs, path, &fi);
2071 fuse_finish_interrupt(f, req, &d);
2072 pthread_mutex_destroy(&dh->lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002073 free(dh);
2074 }
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002075 } else {
2076 reply_err(req, err);
2077 free(dh);
2078 }
2079 free(path);
2080 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredi5e183482001-10-31 14:52:35 +00002081}
Miklos Szeredib483c932001-10-29 14:57:57 +00002082
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002083static int extend_contents(struct fuse_dh *dh, unsigned minsize)
Miklos Szeredi1bf64f42006-02-17 15:49:25 +00002084{
2085 if (minsize > dh->size) {
2086 char *newptr;
2087 unsigned newsize = dh->size;
2088 if (!newsize)
2089 newsize = 1024;
2090 while (newsize < minsize)
2091 newsize *= 2;
2092
2093 newptr = (char *) realloc(dh->contents, newsize);
2094 if (!newptr) {
2095 dh->error = -ENOMEM;
2096 return -1;
2097 }
2098 dh->contents = newptr;
2099 dh->size = newsize;
2100 }
2101 return 0;
2102}
2103
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002104static int fill_dir(void *dh_, const char *name, const struct stat *statp,
2105 off_t off)
Miklos Szeredia181e612001-11-06 12:03:23 +00002106{
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002107 struct fuse_dh *dh = (struct fuse_dh *) dh_;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002108 struct stat stbuf;
Miklos Szeredi1bf64f42006-02-17 15:49:25 +00002109 size_t newlen;
Miklos Szeredifb28c5e2004-11-26 12:15:06 +00002110
Miklos Szeredif6e0ec62005-08-03 09:11:06 +00002111 if (statp)
2112 stbuf = *statp;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002113 else {
2114 memset(&stbuf, 0, sizeof(stbuf));
Miklos Szeredie248e4b2005-12-14 16:18:32 +00002115 stbuf.st_ino = FUSE_UNKNOWN_INO;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002116 }
Miklos Szeredia181e612001-11-06 12:03:23 +00002117
Miklos Szeredi659743b2005-12-09 17:41:42 +00002118 if (!dh->fuse->conf.use_ino) {
Miklos Szeredie248e4b2005-12-14 16:18:32 +00002119 stbuf.st_ino = FUSE_UNKNOWN_INO;
Miklos Szeredi659743b2005-12-09 17:41:42 +00002120 if (dh->fuse->conf.readdir_ino) {
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002121 struct node *node;
2122 pthread_mutex_lock(&dh->fuse->lock);
2123 node = lookup_node(dh->fuse, dh->nodeid, name);
2124 if (node)
2125 stbuf.st_ino = (ino_t) node->nodeid;
2126 pthread_mutex_unlock(&dh->fuse->lock);
Miklos Szeredi6ebe2342002-01-06 21:44:16 +00002127 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002128 }
Miklos Szeredi6ebe2342002-01-06 21:44:16 +00002129
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002130 if (off) {
Miklos Szeredi1bf64f42006-02-17 15:49:25 +00002131 if (extend_contents(dh, dh->needlen) == -1)
2132 return 1;
2133
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002134 dh->filled = 0;
Miklos Szeredi1bf64f42006-02-17 15:49:25 +00002135 newlen = dh->len + fuse_add_direntry(dh->req, dh->contents + dh->len,
2136 dh->needlen - dh->len, name,
2137 &stbuf, off);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002138 if (newlen > dh->needlen)
2139 return 1;
Miklos Szeredi1bf64f42006-02-17 15:49:25 +00002140 } else {
2141 newlen = dh->len + fuse_add_direntry(dh->req, NULL, 0, name, NULL, 0);
2142 if (extend_contents(dh, newlen) == -1)
Miklos Szeredic4c12ae2005-10-20 14:48:50 +00002143 return 1;
Miklos Szeredi1bf64f42006-02-17 15:49:25 +00002144
2145 fuse_add_direntry(dh->req, dh->contents + dh->len, dh->size - dh->len,
2146 name, &stbuf, newlen);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002147 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002148 dh->len = newlen;
2149 return 0;
2150}
2151
Miklos Szeredi1bf64f42006-02-17 15:49:25 +00002152static int readdir_fill(struct fuse *f, fuse_req_t req, fuse_ino_t ino,
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002153 size_t size, off_t off, struct fuse_dh *dh,
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002154 struct fuse_file_info *fi)
2155{
2156 int err = -ENOENT;
2157 char *path;
2158 pthread_rwlock_rdlock(&f->tree_lock);
2159 path = get_path(f, ino);
2160 if (path != NULL) {
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002161 struct fuse_intr_data d;
2162
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002163 dh->len = 0;
2164 dh->error = 0;
2165 dh->needlen = size;
2166 dh->filled = 1;
Miklos Szeredi1bf64f42006-02-17 15:49:25 +00002167 dh->req = req;
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002168 fuse_prepare_interrupt(f, req, &d);
2169 err = fuse_fs_readdir(f->fs, path, dh, fill_dir, off, fi);
2170 fuse_finish_interrupt(f, req, &d);
Miklos Szeredi1bf64f42006-02-17 15:49:25 +00002171 dh->req = NULL;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002172 if (!err)
2173 err = dh->error;
2174 if (err)
2175 dh->filled = 0;
Miklos Szeredi97c61e92001-11-07 12:09:43 +00002176 free(path);
Miklos Szeredia181e612001-11-06 12:03:23 +00002177 }
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00002178 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002179 return err;
2180}
Miklos Szeredie5183742005-02-02 11:14:04 +00002181
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002182static void fuse_lib_readdir(fuse_req_t req, fuse_ino_t ino, size_t size,
2183 off_t off, struct fuse_file_info *llfi)
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002184{
2185 struct fuse *f = req_fuse_prepare(req);
2186 struct fuse_file_info fi;
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002187 struct fuse_dh *dh = get_dirhandle(llfi, &fi);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002188
2189 pthread_mutex_lock(&dh->lock);
Miklos Szeredi77ccf652005-08-19 14:40:27 +00002190 /* According to SUS, directory contents need to be refreshed on
2191 rewinddir() */
2192 if (!off)
2193 dh->filled = 0;
2194
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002195 if (!dh->filled) {
Miklos Szeredi1bf64f42006-02-17 15:49:25 +00002196 int err = readdir_fill(f, req, ino, size, off, dh, &fi);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002197 if (err) {
2198 reply_err(req, err);
2199 goto out;
2200 }
Miklos Szeredia181e612001-11-06 12:03:23 +00002201 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002202 if (dh->filled) {
2203 if (off < dh->len) {
2204 if (off + size > dh->len)
2205 size = dh->len - off;
2206 } else
2207 size = 0;
2208 } else {
2209 size = dh->len;
2210 off = 0;
2211 }
2212 fuse_reply_buf(req, dh->contents + off, size);
2213 out:
2214 pthread_mutex_unlock(&dh->lock);
2215}
Miklos Szeredia181e612001-11-06 12:03:23 +00002216
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002217static void fuse_lib_releasedir(fuse_req_t req, fuse_ino_t ino,
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002218 struct fuse_file_info *llfi)
2219{
2220 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002221 struct fuse_intr_data d;
Miklos Szeredi9b813af2005-07-21 07:59:37 +00002222 struct fuse_file_info fi;
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002223 struct fuse_dh *dh = get_dirhandle(llfi, &fi);
2224 char *path;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002225
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002226 pthread_rwlock_rdlock(&f->tree_lock);
2227 path = get_path(f, ino);
2228 fuse_prepare_interrupt(f, req, &d);
2229 fuse_fs_releasedir(f->fs, path ? path : "-", &fi);
2230 fuse_finish_interrupt(f, req, &d);
2231 if (path)
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002232 free(path);
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002233 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002234 pthread_mutex_lock(&dh->lock);
2235 pthread_mutex_unlock(&dh->lock);
2236 pthread_mutex_destroy(&dh->lock);
2237 free(dh->contents);
2238 free(dh);
2239 reply_err(req, 0);
2240}
2241
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002242static void fuse_lib_fsyncdir(fuse_req_t req, fuse_ino_t ino, int datasync,
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002243 struct fuse_file_info *llfi)
2244{
2245 struct fuse *f = req_fuse_prepare(req);
2246 struct fuse_file_info fi;
2247 char *path;
2248 int err;
2249
2250 get_dirhandle(llfi, &fi);
2251
2252 err = -ENOENT;
2253 pthread_rwlock_rdlock(&f->tree_lock);
2254 path = get_path(f, ino);
2255 if (path != NULL) {
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002256 struct fuse_intr_data d;
2257 fuse_prepare_interrupt(f, req, &d);
2258 err = fuse_fs_fsyncdir(f->fs, path, datasync, &fi);
2259 fuse_finish_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002260 free(path);
2261 }
2262 pthread_rwlock_unlock(&f->tree_lock);
2263 reply_err(req, err);
Miklos Szeredia181e612001-11-06 12:03:23 +00002264}
2265
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002266static void fuse_lib_statfs(fuse_req_t req, fuse_ino_t ino)
Miklos Szeredi18e75e42004-02-19 14:23:27 +00002267{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002268 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredi52cb09d2005-11-07 11:59:00 +00002269 struct statvfs buf;
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002270 char *path;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002271 int err;
Mark Glinesd84b39a2002-01-07 16:32:02 +00002272
Miklos Szeredi52cb09d2005-11-07 11:59:00 +00002273 memset(&buf, 0, sizeof(buf));
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002274 pthread_rwlock_rdlock(&f->tree_lock);
2275 if (!ino) {
2276 err = -ENOMEM;
2277 path = strdup("/");
2278 } else {
2279 err = -ENOENT;
2280 path = get_path(f, ino);
2281 }
2282 if (path) {
2283 struct fuse_intr_data d;
2284 fuse_prepare_interrupt(f, req, &d);
2285 err = fuse_fs_statfs(f->fs, path, &buf);
2286 fuse_finish_interrupt(f, req, &d);
2287 free(path);
2288 }
2289 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredi77f39942004-03-25 11:17:52 +00002290
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002291 if (!err)
2292 fuse_reply_statfs(req, &buf);
Miklos Szeredi03cebae2004-03-31 10:19:18 +00002293 else
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002294 reply_err(req, err);
Miklos Szeredi03cebae2004-03-31 10:19:18 +00002295}
2296
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002297static void fuse_lib_setxattr(fuse_req_t req, fuse_ino_t ino, const char *name,
2298 const char *value, size_t size, int flags)
Miklos Szeredi3ed84232004-03-30 15:17:26 +00002299{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002300 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredi3ed84232004-03-30 15:17:26 +00002301 char *path;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002302 int err;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00002303
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002304 err = -ENOENT;
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00002305 pthread_rwlock_rdlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002306 path = get_path(f, ino);
Miklos Szeredi3ed84232004-03-30 15:17:26 +00002307 if (path != NULL) {
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002308 struct fuse_intr_data d;
2309 fuse_prepare_interrupt(f, req, &d);
2310 err = fuse_fs_setxattr(f->fs, path, name, value, size, flags);
2311 fuse_finish_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002312 free(path);
2313 }
2314 pthread_rwlock_unlock(&f->tree_lock);
2315 reply_err(req, err);
2316}
2317
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002318static int common_getxattr(struct fuse *f, fuse_req_t req, fuse_ino_t ino,
2319 const char *name, char *value, size_t size)
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002320{
2321 int err;
2322 char *path;
2323
2324 err = -ENOENT;
2325 pthread_rwlock_rdlock(&f->tree_lock);
2326 path = get_path(f, ino);
2327 if (path != NULL) {
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002328 struct fuse_intr_data d;
2329 fuse_prepare_interrupt(f, req, &d);
2330 err = fuse_fs_getxattr(f->fs, path, name, value, size);
2331 fuse_finish_interrupt(f, req, &d);
Miklos Szerediab974562005-04-07 15:40:21 +00002332 free(path);
2333 }
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00002334 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szerediab974562005-04-07 15:40:21 +00002335 return err;
2336}
2337
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002338static void fuse_lib_getxattr(fuse_req_t req, fuse_ino_t ino, const char *name,
2339 size_t size)
Miklos Szeredi3ead28e2005-01-18 21:23:41 +00002340{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002341 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredi4283ee72005-03-21 12:09:04 +00002342 int res;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002343
2344 if (size) {
2345 char *value = (char *) malloc(size);
2346 if (value == NULL) {
2347 reply_err(req, -ENOMEM);
2348 return;
2349 }
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002350 res = common_getxattr(f, req, ino, name, value, size);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002351 if (res > 0)
2352 fuse_reply_buf(req, value, res);
2353 else
2354 reply_err(req, res);
2355 free(value);
2356 } else {
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002357 res = common_getxattr(f, req, ino, name, NULL, 0);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002358 if (res >= 0)
2359 fuse_reply_xattr(req, res);
2360 else
2361 reply_err(req, res);
2362 }
2363}
2364
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002365static int common_listxattr(struct fuse *f, fuse_req_t req, fuse_ino_t ino,
2366 char *list, size_t size)
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002367{
Miklos Szeredi4283ee72005-03-21 12:09:04 +00002368 char *path;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002369 int err;
Miklos Szeredi4283ee72005-03-21 12:09:04 +00002370
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002371 err = -ENOENT;
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00002372 pthread_rwlock_rdlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002373 path = get_path(f, ino);
Miklos Szeredi4283ee72005-03-21 12:09:04 +00002374 if (path != NULL) {
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002375 struct fuse_intr_data d;
2376 fuse_prepare_interrupt(f, req, &d);
2377 err = fuse_fs_listxattr(f->fs, path, list, size);
2378 fuse_finish_interrupt(f, req, &d);
Miklos Szeredi4283ee72005-03-21 12:09:04 +00002379 free(path);
2380 }
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00002381 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002382 return err;
Miklos Szeredi4283ee72005-03-21 12:09:04 +00002383}
Miklos Szeredi3ead28e2005-01-18 21:23:41 +00002384
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002385static void fuse_lib_listxattr(fuse_req_t req, fuse_ino_t ino, size_t size)
Miklos Szeredi43696432001-11-18 19:15:05 +00002386{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002387 struct fuse *f = req_fuse_prepare(req);
2388 int res;
2389
2390 if (size) {
2391 char *list = (char *) malloc(size);
2392 if (list == NULL) {
2393 reply_err(req, -ENOMEM);
2394 return;
2395 }
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002396 res = common_listxattr(f, req, ino, list, size);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002397 if (res > 0)
2398 fuse_reply_buf(req, list, res);
2399 else
2400 reply_err(req, res);
2401 free(list);
2402 } else {
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002403 res = common_listxattr(f, req, ino, NULL, 0);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002404 if (res >= 0)
2405 fuse_reply_xattr(req, res);
2406 else
2407 reply_err(req, res);
2408 }
Miklos Szeredi43696432001-11-18 19:15:05 +00002409}
2410
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002411static void fuse_lib_removexattr(fuse_req_t req, fuse_ino_t ino,
2412 const char *name)
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002413{
2414 struct fuse *f = req_fuse_prepare(req);
2415 char *path;
2416 int err;
2417
2418 err = -ENOENT;
2419 pthread_rwlock_rdlock(&f->tree_lock);
2420 path = get_path(f, ino);
2421 if (path != NULL) {
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002422 struct fuse_intr_data d;
2423 fuse_prepare_interrupt(f, req, &d);
2424 err = fuse_fs_removexattr(f->fs, path, name);
2425 fuse_finish_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002426 free(path);
2427 }
2428 pthread_rwlock_unlock(&f->tree_lock);
2429 reply_err(req, err);
2430}
2431
Miklos Szeredi0c59ebf2006-09-10 20:53:36 +00002432static struct lock *locks_conflict(struct node *node, const struct lock *lock)
2433{
2434 struct lock *l;
2435
2436 for (l = node->locks; l; l = l->next)
2437 if (l->owner != lock->owner &&
2438 lock->start <= l->end && l->start <= lock->end &&
2439 (l->type == F_WRLCK || lock->type == F_WRLCK))
2440 break;
2441
2442 return l;
2443}
2444
2445static void delete_lock(struct lock **lockp)
2446{
2447 struct lock *l = *lockp;
2448 *lockp = l->next;
2449 free(l);
2450}
2451
2452static void insert_lock(struct lock **pos, struct lock *lock)
2453{
2454 lock->next = *pos;
2455 *pos = lock;
2456}
2457
2458static int locks_insert(struct node *node, struct lock *lock)
2459{
2460 struct lock **lp;
2461 struct lock *newl1 = NULL;
2462 struct lock *newl2 = NULL;
2463
2464 if (lock->type != F_UNLCK || lock->start != 0 || lock->end != OFFSET_MAX) {
2465 newl1 = malloc(sizeof(struct lock));
2466 newl2 = malloc(sizeof(struct lock));
2467
2468 if (!newl1 || !newl2) {
2469 free(newl1);
2470 free(newl2);
2471 return -ENOLCK;
2472 }
2473 }
2474
2475 for (lp = &node->locks; *lp;) {
2476 struct lock *l = *lp;
2477 if (l->owner != lock->owner)
2478 goto skip;
2479
2480 if (lock->type == l->type) {
2481 if (l->end < lock->start - 1)
2482 goto skip;
2483 if (lock->end < l->start - 1)
2484 break;
2485 if (l->start <= lock->start && lock->end <= l->end)
2486 goto out;
2487 if (l->start < lock->start)
2488 lock->start = l->start;
2489 if (lock->end < l->end)
2490 lock->end = l->end;
2491 goto delete;
2492 } else {
2493 if (l->end < lock->start)
2494 goto skip;
2495 if (lock->end < l->start)
2496 break;
2497 if (lock->start <= l->start && l->end <= lock->end)
2498 goto delete;
2499 if (l->end <= lock->end) {
2500 l->end = lock->start - 1;
2501 goto skip;
2502 }
2503 if (lock->start <= l->start) {
2504 l->start = lock->end + 1;
2505 break;
2506 }
2507 *newl2 = *l;
2508 newl2->start = lock->end + 1;
2509 l->end = lock->start - 1;
2510 insert_lock(&l->next, newl2);
2511 newl2 = NULL;
2512 }
2513 skip:
2514 lp = &l->next;
2515 continue;
2516
2517 delete:
2518 delete_lock(lp);
2519 }
2520 if (lock->type != F_UNLCK) {
2521 *newl1 = *lock;
2522 insert_lock(lp, newl1);
2523 newl1 = NULL;
2524 }
2525out:
2526 free(newl1);
2527 free(newl2);
2528 return 0;
2529}
2530
2531static void flock_to_lock(struct flock *flock, struct lock *lock)
2532{
2533 memset(lock, 0, sizeof(struct lock));
2534 lock->type = flock->l_type;
2535 lock->start = flock->l_start;
2536 lock->end = flock->l_len ? flock->l_start + flock->l_len - 1 : OFFSET_MAX;
2537 lock->pid = flock->l_pid;
2538}
2539
2540static void lock_to_flock(struct lock *lock, struct flock *flock)
2541{
2542 flock->l_type = lock->type;
2543 flock->l_start = lock->start;
2544 flock->l_len = (lock->end == OFFSET_MAX) ? 0 : lock->end - lock->start + 1;
2545 flock->l_pid = lock->pid;
2546}
2547
Miklos Szeredi6353dca2007-05-11 09:19:36 +00002548static int fuse_flush_common(struct fuse *f, fuse_req_t req, fuse_ino_t ino,
2549 const char *path, struct fuse_file_info *fi)
Csaba Henk79b9e9f2007-05-10 22:56:46 +00002550{
Csaba Henk79b9e9f2007-05-10 22:56:46 +00002551 struct fuse_intr_data d;
2552 struct flock lock;
2553 struct lock l;
Miklos Szeredi0c59ebf2006-09-10 20:53:36 +00002554 int err;
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002555 int errlock;
Miklos Szeredi0c59ebf2006-09-10 20:53:36 +00002556
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002557 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredi6353dca2007-05-11 09:19:36 +00002558 memset(&lock, 0, sizeof(lock));
2559 lock.l_type = F_UNLCK;
2560 lock.l_whence = SEEK_SET;
2561 err = fuse_fs_flush(f->fs, path, fi);
2562 errlock = fuse_fs_lock(f->fs, path, fi, F_SETLK, &lock);
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002563 fuse_finish_interrupt(f, req, &d);
Miklos Szeredi6353dca2007-05-11 09:19:36 +00002564
Csaba Henk79b9e9f2007-05-10 22:56:46 +00002565 if (errlock != -ENOSYS) {
Miklos Szeredi0c59ebf2006-09-10 20:53:36 +00002566 flock_to_lock(&lock, &l);
Miklos Szeredi07407852006-09-30 20:03:52 +00002567 l.owner = fi->lock_owner;
Miklos Szeredi0c59ebf2006-09-10 20:53:36 +00002568 pthread_mutex_lock(&f->lock);
2569 locks_insert(get_node(f, ino), &l);
2570 pthread_mutex_unlock(&f->lock);
2571
2572 /* if op.lock() is defined FLUSH is needed regardless of op.flush() */
2573 if (err == -ENOSYS)
2574 err = 0;
2575 }
Miklos Szeredi6353dca2007-05-11 09:19:36 +00002576 return err;
2577}
2578
2579static void fuse_lib_release(fuse_req_t req, fuse_ino_t ino,
2580 struct fuse_file_info *fi)
2581{
2582 struct fuse *f = req_fuse_prepare(req);
2583 struct fuse_intr_data d;
2584 char *path;
2585 int err = 0;
2586
2587 pthread_rwlock_rdlock(&f->tree_lock);
2588 path = get_path(f, ino);
Miklos Szeredi1f35c652007-06-18 14:27:47 +00002589 if (f->conf.debug)
2590 fprintf(stderr, "RELEASE%s[%llu] flags: 0x%x\n",
2591 fi->flush ? "+FLUSH" : "",
2592 (unsigned long long) fi->fh, fi->flags);
Miklos Szeredi6353dca2007-05-11 09:19:36 +00002593
2594 if (fi->flush) {
2595 err = fuse_flush_common(f, req, ino, path, fi);
2596 if (err == -ENOSYS)
2597 err = 0;
2598 }
2599
2600 fuse_prepare_interrupt(f, req, &d);
2601 fuse_do_release(f, ino, path, fi);
2602 fuse_finish_interrupt(f, req, &d);
2603 free(path);
2604 pthread_rwlock_unlock(&f->tree_lock);
2605
2606 reply_err(req, err);
2607}
2608
2609static void fuse_lib_flush(fuse_req_t req, fuse_ino_t ino,
2610 struct fuse_file_info *fi)
2611{
2612 struct fuse *f = req_fuse_prepare(req);
2613 char *path;
2614 int err;
2615
2616 pthread_rwlock_rdlock(&f->tree_lock);
2617 path = get_path(f, ino);
Miklos Szeredi1f35c652007-06-18 14:27:47 +00002618 if (path && f->conf.debug)
2619 fprintf(stderr, "FLUSH[%llu]\n", (unsigned long long) fi->fh);
Miklos Szeredi6353dca2007-05-11 09:19:36 +00002620 err = fuse_flush_common(f, req, ino, path, fi);
2621 free(path);
Miklos Szeredi0c59ebf2006-09-10 20:53:36 +00002622 pthread_rwlock_unlock(&f->tree_lock);
2623 reply_err(req, err);
2624}
2625
Miklos Szeredi9a5c11d2006-07-30 17:33:40 +00002626static int fuse_lock_common(fuse_req_t req, fuse_ino_t ino,
2627 struct fuse_file_info *fi, struct flock *lock,
Miklos Szeredi07407852006-09-30 20:03:52 +00002628 int cmd)
Miklos Szeredi9a5c11d2006-07-30 17:33:40 +00002629{
2630 struct fuse *f = req_fuse_prepare(req);
2631 char *path;
2632 int err;
2633
2634 err = -ENOENT;
2635 pthread_rwlock_rdlock(&f->tree_lock);
2636 path = get_path(f, ino);
2637 if (path != NULL) {
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002638 struct fuse_intr_data d;
2639 fuse_prepare_interrupt(f, req, &d);
2640 err = fuse_fs_lock(f->fs, path, fi, cmd, lock);
2641 fuse_finish_interrupt(f, req, &d);
Miklos Szeredi9a5c11d2006-07-30 17:33:40 +00002642 free(path);
2643 }
2644 pthread_rwlock_unlock(&f->tree_lock);
2645 return err;
2646}
2647
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002648static void fuse_lib_getlk(fuse_req_t req, fuse_ino_t ino,
2649 struct fuse_file_info *fi, struct flock *lock)
Miklos Szeredi9a5c11d2006-07-30 17:33:40 +00002650{
Miklos Szeredi0c59ebf2006-09-10 20:53:36 +00002651 int err;
2652 struct lock l;
2653 struct lock *conflict;
2654 struct fuse *f = req_fuse(req);
2655
2656 flock_to_lock(lock, &l);
Miklos Szeredi07407852006-09-30 20:03:52 +00002657 l.owner = fi->lock_owner;
Miklos Szeredi0c59ebf2006-09-10 20:53:36 +00002658 pthread_mutex_lock(&f->lock);
2659 conflict = locks_conflict(get_node(f, ino), &l);
2660 if (conflict)
2661 lock_to_flock(conflict, lock);
2662 pthread_mutex_unlock(&f->lock);
2663 if (!conflict)
Miklos Szeredi07407852006-09-30 20:03:52 +00002664 err = fuse_lock_common(req, ino, fi, lock, F_GETLK);
Miklos Szeredi0c59ebf2006-09-10 20:53:36 +00002665 else
2666 err = 0;
2667
Miklos Szeredi9a5c11d2006-07-30 17:33:40 +00002668 if (!err)
2669 fuse_reply_lock(req, lock);
2670 else
2671 reply_err(req, err);
2672}
2673
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002674static void fuse_lib_setlk(fuse_req_t req, fuse_ino_t ino,
2675 struct fuse_file_info *fi, struct flock *lock,
2676 int sleep)
Miklos Szeredi9a5c11d2006-07-30 17:33:40 +00002677{
Miklos Szeredi07407852006-09-30 20:03:52 +00002678 int err = fuse_lock_common(req, ino, fi, lock, sleep ? F_SETLKW : F_SETLK);
Miklos Szeredi0c59ebf2006-09-10 20:53:36 +00002679 if (!err) {
2680 struct fuse *f = req_fuse(req);
2681 struct lock l;
2682 flock_to_lock(lock, &l);
Miklos Szeredi07407852006-09-30 20:03:52 +00002683 l.owner = fi->lock_owner;
Miklos Szeredi0c59ebf2006-09-10 20:53:36 +00002684 pthread_mutex_lock(&f->lock);
2685 locks_insert(get_node(f, ino), &l);
2686 pthread_mutex_unlock(&f->lock);
2687 }
2688 reply_err(req, err);
Miklos Szeredi9a5c11d2006-07-30 17:33:40 +00002689}
2690
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002691static void fuse_lib_bmap(fuse_req_t req, fuse_ino_t ino, size_t blocksize,
2692 uint64_t idx)
Miklos Szeredi708b4812006-09-30 16:02:25 +00002693{
2694 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002695 struct fuse_intr_data d;
Miklos Szeredi708b4812006-09-30 16:02:25 +00002696 char *path;
2697 int err;
2698
2699 err = -ENOENT;
2700 pthread_rwlock_rdlock(&f->tree_lock);
2701 path = get_path(f, ino);
2702 if (path != NULL) {
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002703 fuse_prepare_interrupt(f, req, &d);
2704 err = fuse_fs_bmap(f->fs, path, blocksize, &idx);
2705 fuse_finish_interrupt(f, req, &d);
Miklos Szeredi708b4812006-09-30 16:02:25 +00002706 free(path);
2707 }
2708 pthread_rwlock_unlock(&f->tree_lock);
2709 if (!err)
2710 fuse_reply_bmap(req, idx);
2711 else
2712 reply_err(req, err);
2713}
2714
Miklos Szeredia1482422005-08-14 23:00:27 +00002715static struct fuse_lowlevel_ops fuse_path_ops = {
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002716 .init = fuse_lib_init,
2717 .destroy = fuse_lib_destroy,
2718 .lookup = fuse_lib_lookup,
2719 .forget = fuse_lib_forget,
2720 .getattr = fuse_lib_getattr,
2721 .setattr = fuse_lib_setattr,
2722 .access = fuse_lib_access,
2723 .readlink = fuse_lib_readlink,
2724 .mknod = fuse_lib_mknod,
2725 .mkdir = fuse_lib_mkdir,
2726 .unlink = fuse_lib_unlink,
2727 .rmdir = fuse_lib_rmdir,
2728 .symlink = fuse_lib_symlink,
2729 .rename = fuse_lib_rename,
2730 .link = fuse_lib_link,
2731 .create = fuse_lib_create,
2732 .open = fuse_lib_open,
2733 .read = fuse_lib_read,
2734 .write = fuse_lib_write,
2735 .flush = fuse_lib_flush,
2736 .release = fuse_lib_release,
2737 .fsync = fuse_lib_fsync,
2738 .opendir = fuse_lib_opendir,
2739 .readdir = fuse_lib_readdir,
2740 .releasedir = fuse_lib_releasedir,
2741 .fsyncdir = fuse_lib_fsyncdir,
2742 .statfs = fuse_lib_statfs,
2743 .setxattr = fuse_lib_setxattr,
2744 .getxattr = fuse_lib_getxattr,
2745 .listxattr = fuse_lib_listxattr,
2746 .removexattr = fuse_lib_removexattr,
2747 .getlk = fuse_lib_getlk,
2748 .setlk = fuse_lib_setlk,
2749 .bmap = fuse_lib_bmap,
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002750};
2751
Miklos Szeredia1482422005-08-14 23:00:27 +00002752static void free_cmd(struct fuse_cmd *cmd)
2753{
2754 free(cmd->buf);
2755 free(cmd);
2756}
2757
Miklos Szeredif458b8c2004-12-07 16:46:42 +00002758void fuse_process_cmd(struct fuse *f, struct fuse_cmd *cmd)
Miklos Szeredia181e612001-11-06 12:03:23 +00002759{
Miklos Szeredi178451d2005-08-15 13:19:07 +00002760 fuse_session_process(f->se, cmd->buf, cmd->buflen, cmd->ch);
Miklos Szeredifa829b52005-12-02 11:05:41 +00002761 free_cmd(cmd);
Miklos Szeredia181e612001-11-06 12:03:23 +00002762}
2763
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002764int fuse_exited(struct fuse *f)
Miklos Szeredi65cf7c72004-06-30 11:34:56 +00002765{
Miklos Szeredia1482422005-08-14 23:00:27 +00002766 return fuse_session_exited(f->se);
2767}
2768
2769struct fuse_session *fuse_get_session(struct fuse *f)
2770{
2771 return f->se;
2772}
2773
2774static struct fuse_cmd *fuse_alloc_cmd(size_t bufsize)
2775{
2776 struct fuse_cmd *cmd = (struct fuse_cmd *) malloc(sizeof(*cmd));
2777 if (cmd == NULL) {
2778 fprintf(stderr, "fuse: failed to allocate cmd\n");
2779 return NULL;
2780 }
2781 cmd->buf = (char *) malloc(bufsize);
2782 if (cmd->buf == NULL) {
2783 fprintf(stderr, "fuse: failed to allocate read buffer\n");
2784 free(cmd);
2785 return NULL;
2786 }
2787 return cmd;
Miklos Szeredi65cf7c72004-06-30 11:34:56 +00002788}
2789
Miklos Szeredif458b8c2004-12-07 16:46:42 +00002790struct fuse_cmd *fuse_read_cmd(struct fuse *f)
Miklos Szeredi2df1c042001-11-06 15:07:17 +00002791{
Miklos Szeredia1482422005-08-14 23:00:27 +00002792 struct fuse_chan *ch = fuse_session_next_chan(f->se, NULL);
2793 size_t bufsize = fuse_chan_bufsize(ch);
2794 struct fuse_cmd *cmd = fuse_alloc_cmd(bufsize);
2795 if (cmd != NULL) {
Miklos Szeredi8d975f62006-03-17 15:56:05 +00002796 int res = fuse_chan_recv(&ch, cmd->buf, bufsize);
Miklos Szeredia1482422005-08-14 23:00:27 +00002797 if (res <= 0) {
2798 free_cmd(cmd);
Miklos Szeredi5d9ce362006-03-01 12:10:13 +00002799 if (res < 0 && res != -EINTR && res != -EAGAIN)
Miklos Szeredifa829b52005-12-02 11:05:41 +00002800 fuse_exit(f);
Miklos Szeredia1482422005-08-14 23:00:27 +00002801 return NULL;
2802 }
2803 cmd->buflen = res;
Miklos Szeredi178451d2005-08-15 13:19:07 +00002804 cmd->ch = ch;
Miklos Szeredia1482422005-08-14 23:00:27 +00002805 }
2806 return cmd;
Miklos Szeredi2df1c042001-11-06 15:07:17 +00002807}
2808
Miklos Szeredib2cf9562004-09-16 08:42:40 +00002809int fuse_loop(struct fuse *f)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00002810{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002811 if (f)
Miklos Szeredia1482422005-08-14 23:00:27 +00002812 return fuse_session_loop(f->se);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002813 else
Miklos Szeredib2cf9562004-09-16 08:42:40 +00002814 return -1;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00002815}
2816
Miklos Szeredi891b8742004-07-29 09:27:49 +00002817int fuse_invalidate(struct fuse *f, const char *path)
2818{
Miklos Szeredie56818b2004-12-12 11:45:24 +00002819 (void) f;
2820 (void) path;
2821 return -EINVAL;
Miklos Szeredi891b8742004-07-29 09:27:49 +00002822}
2823
Miklos Szeredi0f48a262002-12-05 14:23:01 +00002824void fuse_exit(struct fuse *f)
2825{
Miklos Szeredia1482422005-08-14 23:00:27 +00002826 fuse_session_exit(f->se);
Miklos Szeredi0f48a262002-12-05 14:23:01 +00002827}
2828
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002829struct fuse_context *fuse_get_context(void)
Miklos Szeredi2e50d432001-12-20 12:17:25 +00002830{
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002831 return &fuse_get_context_internal()->ctx;
2832}
2833
2834int fuse_interrupted(void)
2835{
2836 return fuse_req_interrupted(fuse_get_context_internal()->req);
Miklos Szeredid169f312004-09-22 08:48:26 +00002837}
2838
Miklos Szeredif458b8c2004-12-07 16:46:42 +00002839void fuse_set_getcontext_func(struct fuse_context *(*func)(void))
Miklos Szeredid169f312004-09-22 08:48:26 +00002840{
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002841 (void) func;
2842 /* no-op */
Miklos Szeredi2e50d432001-12-20 12:17:25 +00002843}
2844
Miklos Szerediad005972006-01-07 10:14:34 +00002845enum {
2846 KEY_HELP,
Miklos Szerediad005972006-01-07 10:14:34 +00002847};
2848
Miklos Szeredi659743b2005-12-09 17:41:42 +00002849#define FUSE_LIB_OPT(t, p, v) { t, offsetof(struct fuse_config, p), v }
2850
2851static const struct fuse_opt fuse_lib_opts[] = {
Miklos Szerediad005972006-01-07 10:14:34 +00002852 FUSE_OPT_KEY("-h", KEY_HELP),
2853 FUSE_OPT_KEY("--help", KEY_HELP),
Miklos Szeredi065f2222006-01-20 15:15:21 +00002854 FUSE_OPT_KEY("debug", FUSE_OPT_KEY_KEEP),
2855 FUSE_OPT_KEY("-d", FUSE_OPT_KEY_KEEP),
Miklos Szeredi659743b2005-12-09 17:41:42 +00002856 FUSE_LIB_OPT("debug", debug, 1),
Miklos Szeredi95da8602006-01-06 18:29:40 +00002857 FUSE_LIB_OPT("-d", debug, 1),
Miklos Szeredi659743b2005-12-09 17:41:42 +00002858 FUSE_LIB_OPT("hard_remove", hard_remove, 1),
2859 FUSE_LIB_OPT("use_ino", use_ino, 1),
2860 FUSE_LIB_OPT("readdir_ino", readdir_ino, 1),
2861 FUSE_LIB_OPT("direct_io", direct_io, 1),
2862 FUSE_LIB_OPT("kernel_cache", kernel_cache, 1),
Miklos Szeredi320abe42006-01-30 18:14:51 +00002863 FUSE_LIB_OPT("auto_cache", auto_cache, 1),
2864 FUSE_LIB_OPT("noauto_cache", auto_cache, 0),
Miklos Szeredi659743b2005-12-09 17:41:42 +00002865 FUSE_LIB_OPT("umask=", set_mode, 1),
2866 FUSE_LIB_OPT("umask=%o", umask, 0),
2867 FUSE_LIB_OPT("uid=", set_uid, 1),
2868 FUSE_LIB_OPT("uid=%d", uid, 0),
2869 FUSE_LIB_OPT("gid=", set_gid, 1),
2870 FUSE_LIB_OPT("gid=%d", gid, 0),
2871 FUSE_LIB_OPT("entry_timeout=%lf", entry_timeout, 0),
2872 FUSE_LIB_OPT("attr_timeout=%lf", attr_timeout, 0),
Miklos Szeredi6e806e92006-02-16 16:59:39 +00002873 FUSE_LIB_OPT("ac_attr_timeout=%lf", ac_attr_timeout, 0),
2874 FUSE_LIB_OPT("ac_attr_timeout=", ac_attr_timeout_set, 1),
Miklos Szeredi659743b2005-12-09 17:41:42 +00002875 FUSE_LIB_OPT("negative_timeout=%lf", negative_timeout, 0),
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002876 FUSE_LIB_OPT("intr", intr, 1),
2877 FUSE_LIB_OPT("intr_signal=%d", intr_signal, 0),
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002878 FUSE_LIB_OPT("modules=%s", modules, 0),
Miklos Szeredi659743b2005-12-09 17:41:42 +00002879 FUSE_OPT_END
2880};
2881
Miklos Szerediad005972006-01-07 10:14:34 +00002882static void fuse_lib_help(void)
2883{
2884 fprintf(stderr,
Miklos Szeredi06091462006-02-16 16:38:34 +00002885" -o hard_remove immediate removal (don't hide files)\n"
2886" -o use_ino let filesystem set inode numbers\n"
2887" -o readdir_ino try to fill in d_ino in readdir\n"
2888" -o direct_io use direct I/O\n"
2889" -o kernel_cache cache files in kernel\n"
2890" -o [no]auto_cache enable caching based on modification times\n"
2891" -o umask=M set file permissions (octal)\n"
2892" -o uid=N set file owner\n"
2893" -o gid=N set file group\n"
2894" -o entry_timeout=T cache timeout for names (1.0s)\n"
2895" -o negative_timeout=T cache timeout for deleted names (0.0s)\n"
Miklos Szeredi6e806e92006-02-16 16:59:39 +00002896" -o attr_timeout=T cache timeout for attributes (1.0s)\n"
2897" -o ac_attr_timeout=T auto cache timeout for attributes (attr_timeout)\n"
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002898" -o intr allow requests to be interrupted\n"
2899" -o intr_signal=NUM signal to send on interrupt (%i)\n"
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002900" -o modules=M1[:M2...] names of modules to push onto filesystem stack\n"
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002901"\n", FUSE_DEFAULT_INTR_SIGNAL);
Miklos Szerediad005972006-01-07 10:14:34 +00002902}
2903
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002904static void fuse_lib_help_modules(void)
2905{
2906 struct fuse_module *m;
2907 fprintf(stderr, "\nModule options:\n");
2908 pthread_mutex_lock(&fuse_context_lock);
2909 for (m = fuse_modules; m; m = m->next) {
2910 struct fuse_fs *fs = NULL;
2911 struct fuse_fs *newfs;
2912 struct fuse_args args = FUSE_ARGS_INIT(0, NULL);
2913 if (fuse_opt_add_arg(&args, "") != -1 &&
2914 fuse_opt_add_arg(&args, "-h") != -1) {
2915 fprintf(stderr, "\n[%s]\n", m->name);
2916 newfs = m->factory(&args, &fs);
2917 assert(newfs == NULL);
2918 }
2919 fuse_opt_free_args(&args);
2920 }
2921 pthread_mutex_unlock(&fuse_context_lock);
2922}
2923
Miklos Szerediad005972006-01-07 10:14:34 +00002924static int fuse_lib_opt_proc(void *data, const char *arg, int key,
2925 struct fuse_args *outargs)
2926{
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002927 (void) arg; (void) outargs;
Miklos Szerediad005972006-01-07 10:14:34 +00002928
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002929 if (key == KEY_HELP) {
2930 struct fuse_config *conf = (struct fuse_config *) data;
Miklos Szerediad005972006-01-07 10:14:34 +00002931 fuse_lib_help();
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002932 conf->help = 1;
2933 }
Miklos Szerediad005972006-01-07 10:14:34 +00002934
2935 return 1;
2936}
2937
Miklos Szeredibd7661b2004-07-23 17:16:29 +00002938int fuse_is_lib_option(const char *opt)
2939{
Miklos Szeredi659743b2005-12-09 17:41:42 +00002940 return fuse_lowlevel_is_lib_option(opt) ||
2941 fuse_opt_match(fuse_lib_opts, opt);
Miklos Szeredibd7661b2004-07-23 17:16:29 +00002942}
2943
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002944static int fuse_init_intr_signal(int signum, int *installed)
2945{
2946 struct sigaction old_sa;
2947
2948 if (sigaction(signum, NULL, &old_sa) == -1) {
2949 perror("fuse: cannot get old signal handler");
2950 return -1;
2951 }
2952
2953 if (old_sa.sa_handler == SIG_DFL) {
2954 struct sigaction sa;
2955
2956 memset(&sa, 0, sizeof(struct sigaction));
2957 sa.sa_handler = fuse_intr_sighandler;
Miklos Szeredi0c59ebf2006-09-10 20:53:36 +00002958 sigemptyset(&sa.sa_mask);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002959
2960 if (sigaction(signum, &sa, NULL) == -1) {
2961 perror("fuse: cannot set interrupt signal handler");
2962 return -1;
2963 }
2964 *installed = 1;
2965 }
2966 return 0;
2967}
2968
Miklos Szeredi349bdda2006-09-07 11:48:16 +00002969static void fuse_restore_intr_signal(int signum)
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002970{
Miklos Szeredi349bdda2006-09-07 11:48:16 +00002971 struct sigaction sa;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002972
Miklos Szeredi349bdda2006-09-07 11:48:16 +00002973 memset(&sa, 0, sizeof(struct sigaction));
2974 sa.sa_handler = SIG_DFL;
2975 sigaction(signum, &sa, NULL);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002976}
2977
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002978
2979static int fuse_push_module(struct fuse *f, const char *module,
2980 struct fuse_args *args)
2981{
2982 struct fuse_fs *fs[2] = { f->fs, NULL };
2983 struct fuse_fs *newfs;
2984 struct fuse_module *m = fuse_get_module(module);
2985
2986 if (!m)
2987 return -1;
2988
2989 newfs = m->factory(args, fs);
2990 if (!newfs) {
2991 fuse_put_module(m);
2992 return -1;
2993 }
2994 newfs->m = m;
2995 f->fs = newfs;
2996 return 0;
2997}
2998
2999struct fuse_fs *fuse_fs_new(const struct fuse_operations *op, size_t op_size,
3000 void *user_data)
3001{
3002 struct fuse_fs *fs;
3003
3004 if (sizeof(struct fuse_operations) < op_size) {
3005 fprintf(stderr, "fuse: warning: library too old, some operations may not not work\n");
3006 op_size = sizeof(struct fuse_operations);
3007 }
3008
3009 fs = (struct fuse_fs *) calloc(1, sizeof(struct fuse_fs));
3010 if (!fs) {
3011 fprintf(stderr, "fuse: failed to allocate fuse_fs object\n");
3012 return NULL;
3013 }
3014
3015 fs->user_data = user_data;
3016 memcpy(&fs->op, op, op_size);
3017 return fs;
3018}
3019
Miklos Szeredi6f385412006-03-17 15:05:40 +00003020struct fuse *fuse_new_common(struct fuse_chan *ch, struct fuse_args *args,
Miklos Szeredi0b6a0ad2004-12-04 00:40:50 +00003021 const struct fuse_operations *op,
Miklos Szeredi6f385412006-03-17 15:05:40 +00003022 size_t op_size, void *user_data, int compat)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00003023{
Miklos Szeredi97c61e92001-11-07 12:09:43 +00003024 struct fuse *f;
3025 struct node *root;
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00003026 struct fuse_fs *fs;
Miklos Szeredi9a5c11d2006-07-30 17:33:40 +00003027 struct fuse_lowlevel_ops llop = fuse_path_ops;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00003028
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00003029 if (fuse_create_context_key() == -1)
3030 goto out;
3031
Miklos Szeredi97c61e92001-11-07 12:09:43 +00003032 f = (struct fuse *) calloc(1, sizeof(struct fuse));
Miklos Szeredie56818b2004-12-12 11:45:24 +00003033 if (f == NULL) {
3034 fprintf(stderr, "fuse: failed to allocate fuse object\n");
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00003035 goto out_delete_context_key;
Miklos Szeredie56818b2004-12-12 11:45:24 +00003036 }
Miklos Szeredi2df1c042001-11-06 15:07:17 +00003037
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00003038 fs = fuse_fs_new(op, op_size, user_data);
3039 if (!fs)
3040 goto out_free;
3041
3042 fs->compat = compat;
3043 f->fs = fs;
3044
3045 /* Oh f**k, this is ugly! */
3046 if (!fs->op.lock) {
3047 llop.getlk = NULL;
3048 llop.setlk = NULL;
3049 }
3050
Miklos Szeredi659743b2005-12-09 17:41:42 +00003051 f->conf.entry_timeout = 1.0;
3052 f->conf.attr_timeout = 1.0;
3053 f->conf.negative_timeout = 0.0;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00003054 f->conf.intr_signal = FUSE_DEFAULT_INTR_SIGNAL;
Miklos Szeredi6c0209a2005-08-02 13:31:28 +00003055
Miklos Szerediad005972006-01-07 10:14:34 +00003056 if (fuse_opt_parse(args, &f->conf, fuse_lib_opts, fuse_lib_opt_proc) == -1)
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00003057 goto out_free_fs;
3058
3059 if (f->conf.modules) {
3060 char *module;
3061 char *next;
3062
3063 for (module = f->conf.modules; module; module = next) {
3064 char *p;
3065 for (p = module; *p && *p != ':'; p++);
3066 next = *p ? p + 1 : NULL;
3067 *p = '\0';
3068 if (module[0] && fuse_push_module(f, module, args) == -1)
3069 goto out_free_fs;
3070 }
3071 }
Miklos Szeredib2cf9562004-09-16 08:42:40 +00003072
Miklos Szeredi6e806e92006-02-16 16:59:39 +00003073 if (!f->conf.ac_attr_timeout_set)
3074 f->conf.ac_attr_timeout = f->conf.attr_timeout;
3075
Miklos Szeredi659743b2005-12-09 17:41:42 +00003076#ifdef __FreeBSD__
3077 /*
3078 * In FreeBSD, we always use these settings as inode numbers are needed to
3079 * make getcwd(3) work.
3080 */
Miklos Szeredi76fc3de2005-12-12 09:34:45 +00003081 f->conf.readdir_ino = 1;
Miklos Szeredi659743b2005-12-09 17:41:42 +00003082#endif
3083
Miklos Szeredi065f2222006-01-20 15:15:21 +00003084 if (compat && compat <= 25) {
3085 if (fuse_sync_compat_args(args) == -1)
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00003086 goto out_free_fs;
Miklos Szeredi9a5c11d2006-07-30 17:33:40 +00003087 }
3088
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00003089 f->se = fuse_lowlevel_new_common(args, &llop, sizeof(llop), f);
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00003090 if (f->se == NULL) {
3091 if (f->conf.help)
3092 fuse_lib_help_modules();
3093 goto out_free_fs;
3094 }
Miklos Szeredi2bb750e2005-10-03 14:54:24 +00003095
Miklos Szeredia1482422005-08-14 23:00:27 +00003096 fuse_session_add_chan(f->se, ch);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00003097
Miklos Szeredi97c61e92001-11-07 12:09:43 +00003098 f->ctr = 0;
Miklos Szeredi76f65782004-02-19 16:55:40 +00003099 f->generation = 0;
Miklos Szeredifff56ab2001-11-16 10:12:59 +00003100 /* FIXME: Dynamic hash table */
Miklos Szeredi97c61e92001-11-07 12:09:43 +00003101 f->name_table_size = 14057;
3102 f->name_table = (struct node **)
3103 calloc(1, sizeof(struct node *) * f->name_table_size);
Miklos Szeredie56818b2004-12-12 11:45:24 +00003104 if (f->name_table == NULL) {
3105 fprintf(stderr, "fuse: memory allocation failed\n");
Miklos Szeredia1482422005-08-14 23:00:27 +00003106 goto out_free_session;
Miklos Szeredie56818b2004-12-12 11:45:24 +00003107 }
Miklos Szeredib2cf9562004-09-16 08:42:40 +00003108
Miklos Szeredia13d9002004-11-02 17:32:03 +00003109 f->id_table_size = 14057;
3110 f->id_table = (struct node **)
3111 calloc(1, sizeof(struct node *) * f->id_table_size);
Miklos Szeredie56818b2004-12-12 11:45:24 +00003112 if (f->id_table == NULL) {
3113 fprintf(stderr, "fuse: memory allocation failed\n");
Miklos Szeredib2cf9562004-09-16 08:42:40 +00003114 goto out_free_name_table;
Miklos Szeredie56818b2004-12-12 11:45:24 +00003115 }
Miklos Szeredib2cf9562004-09-16 08:42:40 +00003116
Miklos Szeredi38f152c2006-09-03 18:28:52 +00003117 fuse_mutex_init(&f->lock);
Miklos Szeredid0a777a2006-04-05 07:18:00 +00003118 pthread_rwlock_init(&f->tree_lock, NULL);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00003119
Miklos Szeredi97c61e92001-11-07 12:09:43 +00003120 root = (struct node *) calloc(1, sizeof(struct node));
Miklos Szeredie56818b2004-12-12 11:45:24 +00003121 if (root == NULL) {
3122 fprintf(stderr, "fuse: memory allocation failed\n");
Miklos Szeredia13d9002004-11-02 17:32:03 +00003123 goto out_free_id_table;
Miklos Szeredie56818b2004-12-12 11:45:24 +00003124 }
Miklos Szeredib2cf9562004-09-16 08:42:40 +00003125
Miklos Szeredi97c61e92001-11-07 12:09:43 +00003126 root->name = strdup("/");
Miklos Szeredie56818b2004-12-12 11:45:24 +00003127 if (root->name == NULL) {
3128 fprintf(stderr, "fuse: memory allocation failed\n");
Miklos Szeredib2cf9562004-09-16 08:42:40 +00003129 goto out_free_root;
Miklos Szeredie56818b2004-12-12 11:45:24 +00003130 }
Miklos Szeredib2cf9562004-09-16 08:42:40 +00003131
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00003132 if (f->conf.intr &&
3133 fuse_init_intr_signal(f->conf.intr_signal, &f->intr_installed) == -1)
3134 goto out_free_root_name;
3135
Miklos Szeredi7bc05b02007-05-29 23:08:11 +00003136 root->parent = NULL;
Miklos Szeredia13d9002004-11-02 17:32:03 +00003137 root->nodeid = FUSE_ROOT_ID;
Miklos Szeredi76f65782004-02-19 16:55:40 +00003138 root->generation = 0;
Miklos Szeredi0f62d722005-01-04 12:45:54 +00003139 root->refctr = 1;
Miklos Szeredi38009022005-05-08 19:47:22 +00003140 root->nlookup = 1;
Miklos Szeredia13d9002004-11-02 17:32:03 +00003141 hash_id(f, root);
Miklos Szeredi97c61e92001-11-07 12:09:43 +00003142
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00003143 return f;
Miklos Szeredib2cf9562004-09-16 08:42:40 +00003144
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00003145 out_free_root_name:
3146 free(root->name);
Miklos Szeredib2cf9562004-09-16 08:42:40 +00003147 out_free_root:
3148 free(root);
Miklos Szeredia13d9002004-11-02 17:32:03 +00003149 out_free_id_table:
3150 free(f->id_table);
Miklos Szeredib2cf9562004-09-16 08:42:40 +00003151 out_free_name_table:
3152 free(f->name_table);
Miklos Szeredia1482422005-08-14 23:00:27 +00003153 out_free_session:
3154 fuse_session_destroy(f->se);
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00003155 out_free_fs:
3156 /* Horrible compatibility hack to stop the destructor from being
3157 called on the filesystem without init being called first */
3158 fs->op.destroy = NULL;
3159 fuse_fs_destroy(f->fs);
Miklos Szeredib2cf9562004-09-16 08:42:40 +00003160 out_free:
3161 free(f);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00003162 out_delete_context_key:
3163 fuse_delete_context_key();
Miklos Szeredib2cf9562004-09-16 08:42:40 +00003164 out:
Miklos Szeredib2cf9562004-09-16 08:42:40 +00003165 return NULL;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00003166}
3167
Miklos Szeredi6f385412006-03-17 15:05:40 +00003168struct fuse *fuse_new(struct fuse_chan *ch, struct fuse_args *args,
3169 const struct fuse_operations *op, size_t op_size,
3170 void *user_data)
Miklos Szeredi0b6a0ad2004-12-04 00:40:50 +00003171{
Miklos Szeredi6f385412006-03-17 15:05:40 +00003172 return fuse_new_common(ch, args, op, op_size, user_data, 0);
Miklos Szeredi0b6a0ad2004-12-04 00:40:50 +00003173}
3174
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00003175void fuse_destroy(struct fuse *f)
3176{
Miklos Szeredi97c61e92001-11-07 12:09:43 +00003177 size_t i;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00003178
3179 if (f->conf.intr && f->intr_installed)
3180 fuse_restore_intr_signal(f->conf.intr_signal);
Miklos Szerediad519562006-07-31 11:07:40 +00003181
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00003182 if (f->fs) {
3183 struct fuse_context_i *c = fuse_get_context_internal();
Miklos Szerediad519562006-07-31 11:07:40 +00003184
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00003185 memset(c, 0, sizeof(*c));
3186 c->ctx.fuse = f;
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00003187
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00003188 for (i = 0; i < f->id_table_size; i++) {
3189 struct node *node;
3190
3191 for (node = f->id_table[i]; node != NULL; node = node->id_next) {
3192 if (node->is_hidden) {
3193 char *path = get_path(f, node->nodeid);
3194 if (path) {
3195 fuse_fs_unlink(f->fs, path);
3196 free(path);
3197 }
Miklos Szeredi21019c92005-05-09 11:22:41 +00003198 }
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00003199 }
3200 }
3201 }
Miklos Szeredia13d9002004-11-02 17:32:03 +00003202 for (i = 0; i < f->id_table_size; i++) {
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00003203 struct node *node;
Miklos Szeredi97c61e92001-11-07 12:09:43 +00003204 struct node *next;
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00003205
Miklos Szeredia13d9002004-11-02 17:32:03 +00003206 for (node = f->id_table[i]; node != NULL; node = next) {
3207 next = node->id_next;
Miklos Szeredi97c61e92001-11-07 12:09:43 +00003208 free_node(node);
3209 }
3210 }
Miklos Szeredia13d9002004-11-02 17:32:03 +00003211 free(f->id_table);
Miklos Szeredi97c61e92001-11-07 12:09:43 +00003212 free(f->name_table);
Miklos Szeredia181e612001-11-06 12:03:23 +00003213 pthread_mutex_destroy(&f->lock);
Miklos Szeredi55a84102006-06-06 10:16:38 +00003214 pthread_rwlock_destroy(&f->tree_lock);
Miklos Szeredia1482422005-08-14 23:00:27 +00003215 fuse_session_destroy(f->se);
Miklos Szeredi97c61e92001-11-07 12:09:43 +00003216 free(f);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00003217 fuse_delete_context_key();
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00003218}
Miklos Szeredi0b6a0ad2004-12-04 00:40:50 +00003219
Miklos Szeredi6f385412006-03-17 15:05:40 +00003220static struct fuse *fuse_new_common_compat25(int fd, struct fuse_args *args,
3221 const struct fuse_operations *op,
3222 size_t op_size, int compat)
3223{
3224 struct fuse *f = NULL;
3225 struct fuse_chan *ch = fuse_kern_chan_new(fd);
3226
3227 if (ch)
3228 f = fuse_new_common(ch, args, op, op_size, NULL, compat);
3229
3230 return f;
3231}
3232
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00003233/* called with fuse_context_lock held or during initialization (before
3234 main() has been called) */
3235void fuse_register_module(struct fuse_module *mod)
3236{
Miklos Szeredi2f759e12007-03-14 09:13:27 +00003237 mod->ctr = 0;
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00003238 mod->so = fuse_current_so;
3239 if (mod->so)
3240 mod->so->ctr++;
3241 mod->next = fuse_modules;
3242 fuse_modules = mod;
3243}
3244
Miklos Szeredi065f2222006-01-20 15:15:21 +00003245#ifndef __FreeBSD__
3246
Miklos Szeredi95da8602006-01-06 18:29:40 +00003247static struct fuse *fuse_new_common_compat(int fd, const char *opts,
3248 const struct fuse_operations *op,
3249 size_t op_size, int compat)
3250{
3251 struct fuse *f;
3252 struct fuse_args args = FUSE_ARGS_INIT(0, NULL);
3253
Miklos Szeredi6e7d0182007-01-19 22:11:40 +00003254 if (fuse_opt_add_arg(&args, "") == -1)
3255 return NULL;
Miklos Szeredi95da8602006-01-06 18:29:40 +00003256 if (opts &&
Miklos Szeredi6e7d0182007-01-19 22:11:40 +00003257 (fuse_opt_add_arg(&args, "-o") == -1 ||
Miklos Szeredi95da8602006-01-06 18:29:40 +00003258 fuse_opt_add_arg(&args, opts) == -1)) {
3259 fuse_opt_free_args(&args);
3260 return NULL;
3261 }
Miklos Szeredi6f385412006-03-17 15:05:40 +00003262 f = fuse_new_common_compat25(fd, &args, op, op_size, compat);
Miklos Szeredi95da8602006-01-06 18:29:40 +00003263 fuse_opt_free_args(&args);
3264
3265 return f;
3266}
3267
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00003268struct fuse *fuse_new_compat22(int fd, const char *opts,
3269 const struct fuse_operations_compat22 *op,
3270 size_t op_size)
3271{
Miklos Szeredi95da8602006-01-06 18:29:40 +00003272 return fuse_new_common_compat(fd, opts, (struct fuse_operations *) op,
3273 op_size, 22);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00003274}
3275
3276struct fuse *fuse_new_compat2(int fd, const char *opts,
3277 const struct fuse_operations_compat2 *op)
3278{
Miklos Szeredi95da8602006-01-06 18:29:40 +00003279 return fuse_new_common_compat(fd, opts, (struct fuse_operations *) op,
3280 sizeof(struct fuse_operations_compat2), 21);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00003281}
3282
3283struct fuse *fuse_new_compat1(int fd, int flags,
3284 const struct fuse_operations_compat1 *op)
3285{
3286 const char *opts = NULL;
3287 if (flags & FUSE_DEBUG_COMPAT1)
3288 opts = "debug";
Miklos Szeredi95da8602006-01-06 18:29:40 +00003289 return fuse_new_common_compat(fd, opts, (struct fuse_operations *) op,
3290 sizeof(struct fuse_operations_compat1), 11);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00003291}
3292
Miklos Szeredif458b8c2004-12-07 16:46:42 +00003293__asm__(".symver fuse_exited,__fuse_exited@");
3294__asm__(".symver fuse_process_cmd,__fuse_process_cmd@");
3295__asm__(".symver fuse_read_cmd,__fuse_read_cmd@");
3296__asm__(".symver fuse_set_getcontext_func,__fuse_set_getcontext_func@");
3297__asm__(".symver fuse_new_compat2,fuse_new@");
Miklos Szeredi3a770472005-11-11 21:32:42 +00003298__asm__(".symver fuse_new_compat22,fuse_new@FUSE_2.2");
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00003299
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00003300#endif /* __FreeBSD__ */
Miklos Szeredi065f2222006-01-20 15:15:21 +00003301
3302struct fuse *fuse_new_compat25(int fd, struct fuse_args *args,
3303 const struct fuse_operations_compat25 *op,
3304 size_t op_size)
3305{
Miklos Szeredi6f385412006-03-17 15:05:40 +00003306 return fuse_new_common_compat25(fd, args, (struct fuse_operations *) op,
3307 op_size, 25);
Miklos Szeredi065f2222006-01-20 15:15:21 +00003308}
3309
3310__asm__(".symver fuse_new_compat25,fuse_new@FUSE_2.5");