blob: 69fd737bdda9a115a73f5e6f8ae1cd1f8bc32da8 [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
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +0000164 fuse_current_so = so;
165 so->handle = dlopen(soname, RTLD_NOW);
166 fuse_current_so = NULL;
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +0000167 if (!so->handle) {
168 fprintf(stderr, "fuse: %s\n", dlerror());
169 goto err;
170 }
171 if (!so->ctr) {
172 fprintf(stderr, "fuse: %s did not register any modules", soname);
173 goto err;
174 }
175 return 0;
176
177 err:
178 if (so->handle)
179 dlclose(so->handle);
180 free(so);
181 return -1;
182}
183
184static int fuse_load_so_module(const char *module)
185{
186 int res;
187 char *soname = malloc(strlen(module) + 64);
188 if (!soname) {
189 fprintf(stderr, "fuse: memory allocation failed\n");
190 return -1;
191 }
Miklos Szeredi37fb19c2007-06-22 20:41:26 +0000192 sprintf(soname, "libfusemod_%s.so", module);
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +0000193 res = fuse_load_so_name(soname);
194 free(soname);
195 return res;
196}
197
198static struct fuse_module *fuse_find_module(const char *module)
199{
200 struct fuse_module *m;
201 for (m = fuse_modules; m; m = m->next) {
202 if (strcmp(module, m->name) == 0) {
203 m->ctr++;
204 break;
205 }
206 }
207 return m;
208}
209
210static struct fuse_module *fuse_get_module(const char *module)
211{
212 struct fuse_module *m;
213
214 pthread_mutex_lock(&fuse_context_lock);
215 m = fuse_find_module(module);
216 if (!m) {
217 int err = fuse_load_so_module(module);
218 if (!err)
219 m = fuse_find_module(module);
220 }
221 pthread_mutex_unlock(&fuse_context_lock);
222 return m;
223}
224
225static void fuse_put_module(struct fuse_module *m)
226{
227 pthread_mutex_lock(&fuse_context_lock);
228 assert(m->ctr > 0);
229 m->ctr--;
230 if (!m->ctr && m->so) {
231 struct fusemod_so *so = m->so;
232 assert(so->ctr > 0);
233 so->ctr--;
234 if (!so->ctr) {
235 struct fuse_module **mp;
236 for (mp = &fuse_modules; *mp;) {
237 if ((*mp)->so == so)
238 *mp = (*mp)->next;
239 else
240 mp = &(*mp)->next;
241 }
242 dlclose(so->handle);
243 free(so);
244 }
245 }
246 pthread_mutex_unlock(&fuse_context_lock);
247}
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +0000248
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000249static struct node *get_node_nocheck(struct fuse *f, fuse_ino_t nodeid)
Miklos Szeredia181e612001-11-06 12:03:23 +0000250{
Miklos Szeredia13d9002004-11-02 17:32:03 +0000251 size_t hash = nodeid % f->id_table_size;
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000252 struct node *node;
253
Miklos Szeredia13d9002004-11-02 17:32:03 +0000254 for (node = f->id_table[hash]; node != NULL; node = node->id_next)
255 if (node->nodeid == nodeid)
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000256 return node;
Miklos Szeredie5183742005-02-02 11:14:04 +0000257
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000258 return NULL;
Miklos Szeredia181e612001-11-06 12:03:23 +0000259}
260
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000261static struct node *get_node(struct fuse *f, fuse_ino_t nodeid)
Miklos Szeredia181e612001-11-06 12:03:23 +0000262{
Miklos Szeredif458b8c2004-12-07 16:46:42 +0000263 struct node *node = get_node_nocheck(f, nodeid);
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000264 if (!node) {
Miklos Szeredi3a770472005-11-11 21:32:42 +0000265 fprintf(stderr, "fuse internal error: node %llu not found\n",
266 (unsigned long long) nodeid);
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000267 abort();
268 }
269 return node;
Miklos Szeredia181e612001-11-06 12:03:23 +0000270}
271
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000272static void free_node(struct node *node)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000273{
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000274 free(node->name);
275 free(node);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000276}
277
Miklos Szeredia13d9002004-11-02 17:32:03 +0000278static void unhash_id(struct fuse *f, struct node *node)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000279{
Miklos Szeredia13d9002004-11-02 17:32:03 +0000280 size_t hash = node->nodeid % f->id_table_size;
281 struct node **nodep = &f->id_table[hash];
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000282
Miklos Szeredie5183742005-02-02 11:14:04 +0000283 for (; *nodep != NULL; nodep = &(*nodep)->id_next)
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000284 if (*nodep == node) {
Miklos Szeredia13d9002004-11-02 17:32:03 +0000285 *nodep = node->id_next;
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000286 return;
287 }
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000288}
289
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000290static void hash_id(struct fuse *f, struct node *node)
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000291{
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000292 size_t hash = node->nodeid % f->id_table_size;
293 node->id_next = f->id_table[hash];
Miklos Szeredie5183742005-02-02 11:14:04 +0000294 f->id_table[hash] = node;
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000295}
296
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +0000297static unsigned int name_hash(struct fuse *f, fuse_ino_t parent,
298 const char *name)
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000299{
300 unsigned int hash = *name;
301
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000302 if (hash)
303 for (name += 1; *name != '\0'; name++)
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000304 hash = (hash << 5) - hash + *name;
305
306 return (hash + parent) % f->name_table_size;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000307}
308
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000309static void unref_node(struct fuse *f, struct node *node);
310
311static void unhash_name(struct fuse *f, struct node *node)
312{
313 if (node->name) {
Miklos Szeredi7bc05b02007-05-29 23:08:11 +0000314 size_t hash = name_hash(f, node->parent->nodeid, node->name);
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000315 struct node **nodep = &f->name_table[hash];
Miklos Szeredie5183742005-02-02 11:14:04 +0000316
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000317 for (; *nodep != NULL; nodep = &(*nodep)->name_next)
318 if (*nodep == node) {
319 *nodep = node->name_next;
320 node->name_next = NULL;
Miklos Szeredi7bc05b02007-05-29 23:08:11 +0000321 unref_node(f, node->parent);
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000322 free(node->name);
323 node->name = NULL;
Miklos Szeredi7bc05b02007-05-29 23:08:11 +0000324 node->parent = NULL;
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000325 return;
326 }
Miklos Szeredi3a770472005-11-11 21:32:42 +0000327 fprintf(stderr, "fuse internal error: unable to unhash node: %llu\n",
328 (unsigned long long) node->nodeid);
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000329 abort();
330 }
331}
332
Miklos Szeredi7bc05b02007-05-29 23:08:11 +0000333static int hash_name(struct fuse *f, struct node *node, fuse_ino_t parentid,
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000334 const char *name)
335{
Miklos Szeredi7bc05b02007-05-29 23:08:11 +0000336 size_t hash = name_hash(f, parentid, name);
337 struct node *parent = get_node(f, parentid);
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000338 node->name = strdup(name);
339 if (node->name == NULL)
340 return -1;
341
Miklos Szeredi7bc05b02007-05-29 23:08:11 +0000342 parent->refctr ++;
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000343 node->parent = parent;
344 node->name_next = f->name_table[hash];
345 f->name_table[hash] = node;
346 return 0;
347}
348
349static void delete_node(struct fuse *f, struct node *node)
350{
Miklos Szeredi1f35c652007-06-18 14:27:47 +0000351 if (f->conf.debug)
352 fprintf(stderr, "delete: %llu\n", (unsigned long long) node->nodeid);
353
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000354 assert(!node->name);
355 unhash_id(f, node);
356 free_node(node);
357}
358
359static void unref_node(struct fuse *f, struct node *node)
360{
361 assert(node->refctr > 0);
362 node->refctr --;
363 if (!node->refctr)
364 delete_node(f, node);
365}
366
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000367static fuse_ino_t next_id(struct fuse *f)
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000368{
369 do {
Miklos Szeredi7e7fa1f2006-10-08 15:41:20 +0000370 f->ctr = (f->ctr + 1) & 0xffffffff;
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000371 if (!f->ctr)
372 f->generation ++;
Miklos Szeredi7e7fa1f2006-10-08 15:41:20 +0000373 } while (f->ctr == 0 || f->ctr == FUSE_UNKNOWN_INO ||
374 get_node_nocheck(f, f->ctr) != NULL);
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000375 return f->ctr;
376}
377
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000378static struct node *lookup_node(struct fuse *f, fuse_ino_t parent,
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000379 const char *name)
380{
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000381 size_t hash = name_hash(f, parent, name);
382 struct node *node;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000383
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000384 for (node = f->name_table[hash]; node != NULL; node = node->name_next)
Miklos Szeredi7bc05b02007-05-29 23:08:11 +0000385 if (node->parent->nodeid == parent && strcmp(node->name, name) == 0)
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000386 return node;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000387
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000388 return NULL;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000389}
390
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000391static struct node *find_node(struct fuse *f, fuse_ino_t parent,
392 const char *name)
Miklos Szeredi5e183482001-10-31 14:52:35 +0000393{
394 struct node *node;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000395
Miklos Szeredia181e612001-11-06 12:03:23 +0000396 pthread_mutex_lock(&f->lock);
Miklos Szeredif458b8c2004-12-07 16:46:42 +0000397 node = lookup_node(f, parent, name);
Miklos Szeredie331c4b2005-07-06 13:34:02 +0000398 if (node == NULL) {
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000399 node = (struct node *) calloc(1, sizeof(struct node));
400 if (node == NULL)
401 goto out_err;
Miklos Szeredie5183742005-02-02 11:14:04 +0000402
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000403 node->refctr = 1;
404 node->nodeid = next_id(f);
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000405 node->open_count = 0;
406 node->is_hidden = 0;
407 node->generation = f->generation;
408 if (hash_name(f, node, parent, name) == -1) {
409 free(node);
410 node = NULL;
411 goto out_err;
412 }
413 hash_id(f, node);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000414 }
Miklos Szeredi38009022005-05-08 19:47:22 +0000415 node->nlookup ++;
Miklos Szeredic2309912004-09-21 13:40:38 +0000416 out_err:
Miklos Szeredia181e612001-11-06 12:03:23 +0000417 pthread_mutex_unlock(&f->lock);
Miklos Szeredi76f65782004-02-19 16:55:40 +0000418 return node;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000419}
420
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000421static char *add_name(char *buf, char *s, const char *name)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000422{
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000423 size_t len = strlen(name);
424 s -= len;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000425 if (s <= buf) {
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000426 fprintf(stderr, "fuse: path too long: ...%s\n", s + len);
427 return NULL;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000428 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000429 strncpy(s, name, len);
430 s--;
431 *s = '/';
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000432
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000433 return s;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000434}
435
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000436static char *get_path_name(struct fuse *f, fuse_ino_t nodeid, const char *name)
Miklos Szeredib483c932001-10-29 14:57:57 +0000437{
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000438 char buf[FUSE_MAX_PATH];
439 char *s = buf + FUSE_MAX_PATH - 1;
440 struct node *node;
Miklos Szeredie5183742005-02-02 11:14:04 +0000441
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000442 *s = '\0';
Miklos Szeredia181e612001-11-06 12:03:23 +0000443
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000444 if (name != NULL) {
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000445 s = add_name(buf, s, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000446 if (s == NULL)
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000447 return NULL;
448 }
449
450 pthread_mutex_lock(&f->lock);
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000451 for (node = get_node(f, nodeid); node && node->nodeid != FUSE_ROOT_ID;
Miklos Szeredi7bc05b02007-05-29 23:08:11 +0000452 node = node->parent) {
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000453 if (node->name == NULL) {
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000454 s = NULL;
455 break;
456 }
Miklos Szeredie5183742005-02-02 11:14:04 +0000457
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000458 s = add_name(buf, s, node->name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000459 if (s == NULL)
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000460 break;
461 }
462 pthread_mutex_unlock(&f->lock);
463
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000464 if (node == NULL || s == NULL)
Miklos Szeredi5e183482001-10-31 14:52:35 +0000465 return NULL;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000466 else if (*s == '\0')
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000467 return strdup("/");
468 else
469 return strdup(s);
470}
Miklos Szeredia181e612001-11-06 12:03:23 +0000471
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000472static char *get_path(struct fuse *f, fuse_ino_t nodeid)
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000473{
Miklos Szeredia13d9002004-11-02 17:32:03 +0000474 return get_path_name(f, nodeid, NULL);
Miklos Szeredib483c932001-10-29 14:57:57 +0000475}
476
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000477static void forget_node(struct fuse *f, fuse_ino_t nodeid, uint64_t nlookup)
Miklos Szeredi38009022005-05-08 19:47:22 +0000478{
479 struct node *node;
480 if (nodeid == FUSE_ROOT_ID)
481 return;
482 pthread_mutex_lock(&f->lock);
483 node = get_node(f, nodeid);
484 assert(node->nlookup >= nlookup);
485 node->nlookup -= nlookup;
486 if (!node->nlookup) {
487 unhash_name(f, node);
488 unref_node(f, node);
489 }
490 pthread_mutex_unlock(&f->lock);
491}
492
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000493static void remove_node(struct fuse *f, fuse_ino_t dir, const char *name)
Miklos Szeredi5e183482001-10-31 14:52:35 +0000494{
Miklos Szeredia181e612001-11-06 12:03:23 +0000495 struct node *node;
496
497 pthread_mutex_lock(&f->lock);
Miklos Szeredif458b8c2004-12-07 16:46:42 +0000498 node = lookup_node(f, dir, name);
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000499 if (node != NULL)
500 unhash_name(f, node);
Miklos Szeredia181e612001-11-06 12:03:23 +0000501 pthread_mutex_unlock(&f->lock);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000502}
503
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000504static int rename_node(struct fuse *f, fuse_ino_t olddir, const char *oldname,
505 fuse_ino_t newdir, const char *newname, int hide)
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000506{
Miklos Szeredia181e612001-11-06 12:03:23 +0000507 struct node *node;
508 struct node *newnode;
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000509 int err = 0;
Miklos Szeredie5183742005-02-02 11:14:04 +0000510
Miklos Szeredia181e612001-11-06 12:03:23 +0000511 pthread_mutex_lock(&f->lock);
Miklos Szeredif458b8c2004-12-07 16:46:42 +0000512 node = lookup_node(f, olddir, oldname);
513 newnode = lookup_node(f, newdir, newname);
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000514 if (node == NULL)
515 goto out;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000516
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000517 if (newnode != NULL) {
518 if (hide) {
519 fprintf(stderr, "fuse: hidden file got created during hiding\n");
Miklos Szeredib2cf9562004-09-16 08:42:40 +0000520 err = -EBUSY;
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000521 goto out;
522 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000523 unhash_name(f, newnode);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000524 }
Miklos Szeredie5183742005-02-02 11:14:04 +0000525
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000526 unhash_name(f, node);
Miklos Szeredib2cf9562004-09-16 08:42:40 +0000527 if (hash_name(f, node, newdir, newname) == -1) {
528 err = -ENOMEM;
529 goto out;
530 }
Miklos Szeredie5183742005-02-02 11:14:04 +0000531
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000532 if (hide)
533 node->is_hidden = 1;
534
535 out:
Miklos Szeredia181e612001-11-06 12:03:23 +0000536 pthread_mutex_unlock(&f->lock);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000537 return err;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000538}
539
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000540static void set_stat(struct fuse *f, fuse_ino_t nodeid, struct stat *stbuf)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000541{
Miklos Szeredi659743b2005-12-09 17:41:42 +0000542 if (!f->conf.use_ino)
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000543 stbuf->st_ino = nodeid;
Miklos Szeredi659743b2005-12-09 17:41:42 +0000544 if (f->conf.set_mode)
545 stbuf->st_mode = (stbuf->st_mode & S_IFMT) | (0777 & ~f->conf.umask);
546 if (f->conf.set_uid)
547 stbuf->st_uid = f->conf.uid;
548 if (f->conf.set_gid)
549 stbuf->st_gid = f->conf.gid;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000550}
551
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000552static struct fuse *req_fuse(fuse_req_t req)
553{
554 return (struct fuse *) fuse_req_userdata(req);
555}
556
557static void fuse_intr_sighandler(int sig)
558{
559 (void) sig;
560 /* Nothing to do */
561}
562
563struct fuse_intr_data {
564 pthread_t id;
565 pthread_cond_t cond;
566 int finished;
567};
568
569static void fuse_interrupt(fuse_req_t req, void *d_)
570{
571 struct fuse_intr_data *d = d_;
572 struct fuse *f = req_fuse(req);
573
574 if (d->id == pthread_self())
575 return;
576
577 pthread_mutex_lock(&f->lock);
578 while (!d->finished) {
579 struct timeval now;
580 struct timespec timeout;
581
582 pthread_kill(d->id, f->conf.intr_signal);
583 gettimeofday(&now, NULL);
584 timeout.tv_sec = now.tv_sec + 1;
585 timeout.tv_nsec = now.tv_usec * 1000;
586 pthread_cond_timedwait(&d->cond, &f->lock, &timeout);
587 }
588 pthread_mutex_unlock(&f->lock);
589}
590
591static void fuse_do_finish_interrupt(struct fuse *f, fuse_req_t req,
592 struct fuse_intr_data *d)
593{
594 pthread_mutex_lock(&f->lock);
595 d->finished = 1;
596 pthread_cond_broadcast(&d->cond);
597 pthread_mutex_unlock(&f->lock);
598 fuse_req_interrupt_func(req, NULL, NULL);
599 pthread_cond_destroy(&d->cond);
600}
601
602static void fuse_do_prepare_interrupt(fuse_req_t req, struct fuse_intr_data *d)
603{
604 d->id = pthread_self();
605 pthread_cond_init(&d->cond, NULL);
606 d->finished = 0;
607 fuse_req_interrupt_func(req, fuse_interrupt, d);
608}
609
610static inline void fuse_finish_interrupt(struct fuse *f, fuse_req_t req,
611 struct fuse_intr_data *d)
612{
613 if (f->conf.intr)
614 fuse_do_finish_interrupt(f, req, d);
615}
616
617static inline void fuse_prepare_interrupt(struct fuse *f, fuse_req_t req,
618 struct fuse_intr_data *d)
619{
620 if (f->conf.intr)
621 fuse_do_prepare_interrupt(req, d);
622}
623
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +0000624#ifndef __FreeBSD__
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000625
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +0000626static int fuse_compat_open(struct fuse_fs *fs, const char *path,
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000627 struct fuse_file_info *fi)
628{
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +0000629 int err;
630 if (!fs->compat || fs->compat >= 25)
631 err = fs->op.open(path, fi);
632 else if (fs->compat == 22) {
633 struct fuse_file_info_compat tmp;
634 memcpy(&tmp, fi, sizeof(tmp));
635 err = ((struct fuse_operations_compat22 *) &fs->op)->open(path, &tmp);
636 memcpy(fi, &tmp, sizeof(tmp));
637 fi->fh = tmp.fh;
638 } else
639 err = ((struct fuse_operations_compat2 *) &fs->op)
640 ->open(path, fi->flags);
641 return err;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000642}
643
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +0000644static int fuse_compat_release(struct fuse_fs *fs, const char *path,
645 struct fuse_file_info *fi)
646{
647 if (!fs->compat || fs->compat >= 22)
648 return fs->op.release(path, fi);
649 else
650 return ((struct fuse_operations_compat2 *) &fs->op)
651 ->release(path, fi->flags);
652}
653
654static int fuse_compat_opendir(struct fuse_fs *fs, const char *path,
655 struct fuse_file_info *fi)
656{
657 if (!fs->compat || fs->compat >= 25)
658 return fs->op.opendir(path, fi);
659 else {
660 int err;
661 struct fuse_file_info_compat tmp;
662 memcpy(&tmp, fi, sizeof(tmp));
663 err = ((struct fuse_operations_compat22 *) &fs->op)
664 ->opendir(path, &tmp);
665 memcpy(fi, &tmp, sizeof(tmp));
666 fi->fh = tmp.fh;
667 return err;
668 }
669}
670
671static void convert_statfs_compat(struct fuse_statfs_compat1 *compatbuf,
672 struct statvfs *stbuf)
673{
674 stbuf->f_bsize = compatbuf->block_size;
675 stbuf->f_blocks = compatbuf->blocks;
676 stbuf->f_bfree = compatbuf->blocks_free;
677 stbuf->f_bavail = compatbuf->blocks_free;
678 stbuf->f_files = compatbuf->files;
679 stbuf->f_ffree = compatbuf->files_free;
680 stbuf->f_namemax = compatbuf->namelen;
681}
682
683static void convert_statfs_old(struct statfs *oldbuf, struct statvfs *stbuf)
684{
685 stbuf->f_bsize = oldbuf->f_bsize;
686 stbuf->f_blocks = oldbuf->f_blocks;
687 stbuf->f_bfree = oldbuf->f_bfree;
688 stbuf->f_bavail = oldbuf->f_bavail;
689 stbuf->f_files = oldbuf->f_files;
690 stbuf->f_ffree = oldbuf->f_ffree;
691 stbuf->f_namemax = oldbuf->f_namelen;
692}
693
694static int fuse_compat_statfs(struct fuse_fs *fs, const char *path,
695 struct statvfs *buf)
696{
697 int err;
698
699 if (!fs->compat || fs->compat >= 25) {
700 err = fs->op.statfs(fs->compat == 25 ? "/" : path, buf);
701 } else if (fs->compat > 11) {
702 struct statfs oldbuf;
703 err = ((struct fuse_operations_compat22 *) &fs->op)
704 ->statfs("/", &oldbuf);
705 if (!err)
706 convert_statfs_old(&oldbuf, buf);
707 } else {
708 struct fuse_statfs_compat1 compatbuf;
709 memset(&compatbuf, 0, sizeof(struct fuse_statfs_compat1));
710 err = ((struct fuse_operations_compat1 *) &fs->op)->statfs(&compatbuf);
711 if (!err)
712 convert_statfs_compat(&compatbuf, buf);
713 }
714 return err;
715}
716
717#else /* __FreeBSD__ */
718
719static inline int fuse_compat_open(struct fuse_fs *fs, char *path,
720 struct fuse_file_info *fi)
721{
722 return fs->op.open(path, fi);
723}
724
725static inline int fuse_compat_release(struct fuse_fs *fs, const char *path,
726 struct fuse_file_info *fi)
727{
728 return fs->op.release(path, fi);
729}
730
731static inline int fuse_compat_opendir(struct fuse_fs *fs, const char *path,
732 struct fuse_file_info *fi)
733{
734 return fs->op.opendir(path, fi);
735}
736
737static inline int fuse_compat_statfs(struct fuse_fs *fs, const char *path,
738 struct statvfs *buf)
739{
740 return fs->op.statfs(fs->compat == 25 ? "/" : path, buf);
741}
742
743#endif /* __FreeBSD__ */
744
745int fuse_fs_getattr(struct fuse_fs *fs, const char *path, struct stat *buf)
746{
747 fuse_get_context()->private_data = fs->user_data;
748 if (fs->op.getattr)
749 return fs->op.getattr(path, buf);
750 else
751 return -ENOSYS;
752}
753
754int fuse_fs_fgetattr(struct fuse_fs *fs, const char *path, struct stat *buf,
755 struct fuse_file_info *fi)
756{
757 fuse_get_context()->private_data = fs->user_data;
758 if (fs->op.fgetattr)
759 return fs->op.fgetattr(path, buf, fi);
760 else if (fs->op.getattr)
761 return fs->op.getattr(path, buf);
762 else
763 return -ENOSYS;
764}
765
766int fuse_fs_rename(struct fuse_fs *fs, const char *oldpath,
767 const char *newpath)
768{
769 fuse_get_context()->private_data = fs->user_data;
770 if (fs->op.rename)
771 return fs->op.rename(oldpath, newpath);
772 else
773 return -ENOSYS;
774}
775
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +0000776int fuse_fs_unlink(struct fuse_fs *fs, const char *path)
777{
778 fuse_get_context()->private_data = fs->user_data;
779 if (fs->op.unlink)
780 return fs->op.unlink(path);
781 else
782 return -ENOSYS;
783}
784
785int fuse_fs_rmdir(struct fuse_fs *fs, const char *path)
786{
787 fuse_get_context()->private_data = fs->user_data;
788 if (fs->op.rmdir)
789 return fs->op.rmdir(path);
790 else
791 return -ENOSYS;
792}
793
794int fuse_fs_symlink(struct fuse_fs *fs, const char *linkname, const char *path)
795{
796 fuse_get_context()->private_data = fs->user_data;
797 if (fs->op.symlink)
798 return fs->op.symlink(linkname, path);
799 else
800 return -ENOSYS;
801}
802
803int fuse_fs_link(struct fuse_fs *fs, const char *oldpath, const char *newpath)
804{
805 fuse_get_context()->private_data = fs->user_data;
806 if (fs->op.link)
807 return fs->op.link(oldpath, newpath);
808 else
809 return -ENOSYS;
810}
811
812int fuse_fs_release(struct fuse_fs *fs, const char *path,
813 struct fuse_file_info *fi)
814{
815 fuse_get_context()->private_data = fs->user_data;
816 if (fs->op.release)
817 return fuse_compat_release(fs, path, fi);
818 else
819 return 0;
820}
821
822int fuse_fs_opendir(struct fuse_fs *fs, const char *path,
823 struct fuse_file_info *fi)
824{
825 fuse_get_context()->private_data = fs->user_data;
826 if (fs->op.opendir)
827 return fuse_compat_opendir(fs, path, fi);
828 else
829 return 0;
830}
831
832int fuse_fs_open(struct fuse_fs *fs, const char *path,
833 struct fuse_file_info *fi)
834{
835 fuse_get_context()->private_data = fs->user_data;
836 if (fs->op.open)
837 return fuse_compat_open(fs, path, fi);
838 else
839 return 0;
840}
841
842int fuse_fs_read(struct fuse_fs *fs, const char *path, char *buf, size_t size,
843 off_t off, struct fuse_file_info *fi)
844{
845 fuse_get_context()->private_data = fs->user_data;
846 if (fs->op.read)
847 return fs->op.read(path, buf, size, off, fi);
848 else
849 return -ENOSYS;
850}
851
852int fuse_fs_write(struct fuse_fs *fs, const char *path, const char *buf,
853 size_t size, off_t off, struct fuse_file_info *fi)
854{
855 fuse_get_context()->private_data = fs->user_data;
856 if (fs->op.write)
857 return fs->op.write(path, buf, size, off, fi);
858 else
859 return -ENOSYS;
860}
861
862int fuse_fs_fsync(struct fuse_fs *fs, const char *path, int datasync,
863 struct fuse_file_info *fi)
864{
865 fuse_get_context()->private_data = fs->user_data;
866 if (fs->op.fsync)
867 return fs->op.fsync(path, datasync, fi);
868 else
869 return -ENOSYS;
870}
871
872int fuse_fs_fsyncdir(struct fuse_fs *fs, const char *path, int datasync,
873 struct fuse_file_info *fi)
874{
875 fuse_get_context()->private_data = fs->user_data;
876 if (fs->op.fsyncdir)
877 return fs->op.fsyncdir(path, datasync, fi);
878 else
879 return -ENOSYS;
880}
881
882int fuse_fs_flush(struct fuse_fs *fs, const char *path,
883 struct fuse_file_info *fi)
884{
885 fuse_get_context()->private_data = fs->user_data;
886 if (fs->op.flush)
887 return fs->op.flush(path, fi);
888 else
889 return -ENOSYS;
890}
891
892int fuse_fs_statfs(struct fuse_fs *fs, const char *path, struct statvfs *buf)
893{
894 fuse_get_context()->private_data = fs->user_data;
895 if (fs->op.statfs)
896 return fuse_compat_statfs(fs, path, buf);
897 else {
898 buf->f_namemax = 255;
899 buf->f_bsize = 512;
900 return 0;
901 }
902}
903
904int fuse_fs_releasedir(struct fuse_fs *fs, const char *path,
905 struct fuse_file_info *fi)
906{
907 fuse_get_context()->private_data = fs->user_data;
908 if (fs->op.releasedir)
909 return fs->op.releasedir(path, fi);
910 else
911 return 0;
912}
913
914static int fill_dir_old(struct fuse_dirhandle *dh, const char *name, int type,
915 ino_t ino)
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000916{
917 int res;
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +0000918 struct stat stbuf;
919
920 memset(&stbuf, 0, sizeof(stbuf));
921 stbuf.st_mode = type << 12;
922 stbuf.st_ino = ino;
923
924 res = dh->filler(dh->buf, name, &stbuf, 0);
925 return res ? -ENOMEM : 0;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000926}
927
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +0000928int fuse_fs_readdir(struct fuse_fs *fs, const char *path, void *buf,
929 fuse_fill_dir_t filler, off_t off,
930 struct fuse_file_info *fi)
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000931{
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +0000932 fuse_get_context()->private_data = fs->user_data;
933 if (fs->op.readdir)
934 return fs->op.readdir(path, buf, filler, off, fi);
935 else if (fs->op.getdir) {
936 struct fuse_dirhandle dh;
937 dh.filler = filler;
938 dh.buf = buf;
939 return fs->op.getdir(path, &dh, fill_dir_old);
940 } else
941 return -ENOSYS;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000942}
943
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +0000944int fuse_fs_create(struct fuse_fs *fs, const char *path, mode_t mode,
945 struct fuse_file_info *fi)
Miklos Szeredi4fca4322006-10-01 14:41:04 +0000946{
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +0000947 fuse_get_context()->private_data = fs->user_data;
948 if (fs->op.create)
949 return fs->op.create(path, mode, fi);
950 else
951 return -ENOSYS;
Miklos Szeredi4fca4322006-10-01 14:41:04 +0000952}
953
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +0000954int fuse_fs_lock(struct fuse_fs *fs, const char *path,
955 struct fuse_file_info *fi, int cmd, struct flock *lock)
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000956{
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +0000957 fuse_get_context()->private_data = fs->user_data;
958 if (fs->op.lock)
959 return fs->op.lock(path, fi, cmd, lock);
960 else
961 return -ENOSYS;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000962}
963
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +0000964int fuse_fs_chown(struct fuse_fs *fs, const char *path, uid_t uid, gid_t gid)
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000965{
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +0000966 fuse_get_context()->private_data = fs->user_data;
967 if (fs->op.chown)
968 return fs->op.chown(path, uid, gid);
969 else
970 return -ENOSYS;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000971}
972
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +0000973int fuse_fs_truncate(struct fuse_fs *fs, const char *path, off_t size)
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000974{
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +0000975 fuse_get_context()->private_data = fs->user_data;
976 if (fs->op.truncate)
977 return fs->op.truncate(path, size);
978 else
979 return -ENOSYS;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000980}
981
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +0000982int fuse_fs_ftruncate(struct fuse_fs *fs, const char *path, off_t size,
983 struct fuse_file_info *fi)
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000984{
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +0000985 fuse_get_context()->private_data = fs->user_data;
986 if (fs->op.ftruncate)
987 return fs->op.ftruncate(path, size, fi);
988 else if (fs->op.truncate)
989 return fs->op.truncate(path, size);
990 else
991 return -ENOSYS;
992}
993
994int fuse_fs_utimens(struct fuse_fs *fs, const char *path,
995 const struct timespec tv[2])
996{
997 fuse_get_context()->private_data = fs->user_data;
998 if (fs->op.utimens)
999 return fs->op.utimens(path, tv);
1000 else if(fs->op.utime) {
1001 struct utimbuf buf;
1002 buf.actime = tv[0].tv_sec;
1003 buf.modtime = tv[1].tv_sec;
1004 return fs->op.utime(path, &buf);
1005 } else
1006 return -ENOSYS;
1007}
1008
1009int fuse_fs_access(struct fuse_fs *fs, const char *path, int mask)
1010{
1011 fuse_get_context()->private_data = fs->user_data;
1012 if (fs->op.access)
1013 return fs->op.access(path, mask);
1014 else
1015 return -ENOSYS;
1016}
1017
1018int fuse_fs_readlink(struct fuse_fs *fs, const char *path, char *buf,
1019 size_t len)
1020{
1021 fuse_get_context()->private_data = fs->user_data;
1022 if (fs->op.readlink)
1023 return fs->op.readlink(path, buf, len);
1024 else
1025 return -ENOSYS;
1026}
1027
1028int fuse_fs_mknod(struct fuse_fs *fs, const char *path, mode_t mode,
1029 dev_t rdev)
1030{
1031 fuse_get_context()->private_data = fs->user_data;
1032 if (fs->op.mknod)
1033 return fs->op.mknod(path, mode, rdev);
1034 else
1035 return -ENOSYS;
1036}
1037
1038int fuse_fs_mkdir(struct fuse_fs *fs, const char *path, mode_t mode)
1039{
1040 fuse_get_context()->private_data = fs->user_data;
1041 if (fs->op.mkdir)
1042 return fs->op.mkdir(path, mode);
1043 else
1044 return -ENOSYS;
1045}
1046
1047int fuse_fs_setxattr(struct fuse_fs *fs, const char *path, const char *name,
1048 const char *value, size_t size, int flags)
1049{
1050 fuse_get_context()->private_data = fs->user_data;
1051 if (fs->op.setxattr)
1052 return fs->op.setxattr(path, name, value, size, flags);
1053 else
1054 return -ENOSYS;
1055}
1056
1057int fuse_fs_getxattr(struct fuse_fs *fs, const char *path, const char *name,
1058 char *value, size_t size)
1059{
1060 fuse_get_context()->private_data = fs->user_data;
1061 if (fs->op.getxattr)
1062 return fs->op.getxattr(path, name, value, size);
1063 else
1064 return -ENOSYS;
1065}
1066
1067int fuse_fs_listxattr(struct fuse_fs *fs, const char *path, char *list,
1068 size_t size)
1069{
1070 fuse_get_context()->private_data = fs->user_data;
1071 if (fs->op.listxattr)
1072 return fs->op.listxattr(path, list, size);
1073 else
1074 return -ENOSYS;
1075}
1076
1077int fuse_fs_bmap(struct fuse_fs *fs, const char *path, size_t blocksize,
1078 uint64_t *idx)
1079{
1080 fuse_get_context()->private_data = fs->user_data;
1081 if (fs->op.bmap)
1082 return fs->op.bmap(path, blocksize, idx);
1083 else
1084 return -ENOSYS;
1085}
1086
1087int fuse_fs_removexattr(struct fuse_fs *fs, const char *path, const char *name)
1088{
1089 fuse_get_context()->private_data = fs->user_data;
1090 if (fs->op.removexattr)
1091 return fs->op.removexattr(path, name);
1092 else
1093 return -ENOSYS;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001094}
1095
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001096static int is_open(struct fuse *f, fuse_ino_t dir, const char *name)
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001097{
1098 struct node *node;
1099 int isopen = 0;
1100 pthread_mutex_lock(&f->lock);
Miklos Szeredif458b8c2004-12-07 16:46:42 +00001101 node = lookup_node(f, dir, name);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001102 if (node && node->open_count > 0)
1103 isopen = 1;
1104 pthread_mutex_unlock(&f->lock);
1105 return isopen;
1106}
1107
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001108static char *hidden_name(struct fuse *f, fuse_ino_t dir, const char *oldname,
1109 char *newname, size_t bufsize)
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001110{
1111 struct stat buf;
1112 struct node *node;
1113 struct node *newnode;
1114 char *newpath;
1115 int res;
1116 int failctr = 10;
1117
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001118 do {
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001119 pthread_mutex_lock(&f->lock);
Miklos Szeredif458b8c2004-12-07 16:46:42 +00001120 node = lookup_node(f, dir, oldname);
1121 if (node == NULL) {
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001122 pthread_mutex_unlock(&f->lock);
1123 return NULL;
Miklos Szeredif458b8c2004-12-07 16:46:42 +00001124 }
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001125 do {
1126 f->hidectr ++;
1127 snprintf(newname, bufsize, ".fuse_hidden%08x%08x",
Miklos Szeredia13d9002004-11-02 17:32:03 +00001128 (unsigned int) node->nodeid, f->hidectr);
Miklos Szeredif458b8c2004-12-07 16:46:42 +00001129 newnode = lookup_node(f, dir, newname);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001130 } while(newnode);
1131 pthread_mutex_unlock(&f->lock);
Miklos Szeredie5183742005-02-02 11:14:04 +00001132
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001133 newpath = get_path_name(f, dir, newname);
1134 if (!newpath)
1135 break;
Miklos Szeredie5183742005-02-02 11:14:04 +00001136
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001137 res = fuse_fs_getattr(f->fs, newpath, &buf);
1138 if (res == -ENOENT)
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001139 break;
1140 free(newpath);
1141 newpath = NULL;
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001142 } while(res == 0 && --failctr);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001143
1144 return newpath;
1145}
1146
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001147static int hide_node(struct fuse *f, const char *oldpath,
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001148 fuse_ino_t dir, const char *oldname)
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001149{
1150 char newname[64];
1151 char *newpath;
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001152 int err = -EBUSY;
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001153
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001154 newpath = hidden_name(f, dir, oldname, newname, sizeof(newname));
1155 if (newpath) {
1156 err = fuse_fs_rename(f->fs, oldpath, newpath);
1157 if (!err)
1158 err = rename_node(f, dir, oldname, dir, newname, 1);
1159 free(newpath);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001160 }
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001161 return err;
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001162}
1163
Miklos Szeredi320abe42006-01-30 18:14:51 +00001164static int mtime_eq(const struct stat *stbuf, const struct timespec *ts)
1165{
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001166 return stbuf->st_mtime == ts->tv_sec && ST_MTIM_NSEC(stbuf) == ts->tv_nsec;
Miklos Szeredi320abe42006-01-30 18:14:51 +00001167}
1168
Miklos Szeredi2512aaa2006-05-03 14:54:59 +00001169#ifndef CLOCK_MONOTONIC
1170#define CLOCK_MONOTONIC CLOCK_REALTIME
1171#endif
1172
Miklos Szeredi320abe42006-01-30 18:14:51 +00001173static void curr_time(struct timespec *now)
1174{
1175 static clockid_t clockid = CLOCK_MONOTONIC;
1176 int res = clock_gettime(clockid, now);
1177 if (res == -1 && errno == EINVAL) {
1178 clockid = CLOCK_REALTIME;
1179 res = clock_gettime(clockid, now);
1180 }
1181 if (res == -1) {
1182 perror("fuse: clock_gettime");
1183 abort();
1184 }
1185}
1186
1187static void update_stat(struct node *node, const struct stat *stbuf)
1188{
1189 if (node->cache_valid && (!mtime_eq(stbuf, &node->mtime) ||
1190 stbuf->st_size != node->size))
1191 node->cache_valid = 0;
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001192 node->mtime.tv_sec = stbuf->st_mtime;
1193 node->mtime.tv_nsec = ST_MTIM_NSEC(stbuf);
Miklos Szeredi320abe42006-01-30 18:14:51 +00001194 node->size = stbuf->st_size;
1195 curr_time(&node->stat_updated);
1196}
1197
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001198static int lookup_path(struct fuse *f, fuse_ino_t nodeid,
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001199 const char *name, const char *path,
1200 struct fuse_entry_param *e, struct fuse_file_info *fi)
Miklos Szeredi76f65782004-02-19 16:55:40 +00001201{
1202 int res;
Miklos Szeredi76f65782004-02-19 16:55:40 +00001203
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001204 memset(e, 0, sizeof(struct fuse_entry_param));
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001205 if (fi)
1206 res = fuse_fs_fgetattr(f->fs, path, &e->attr, fi);
Miklos Szeredif7eec032005-10-28 13:09:50 +00001207 else
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001208 res = fuse_fs_getattr(f->fs, path, &e->attr);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001209 if (res == 0) {
Miklos Szeredi76f65782004-02-19 16:55:40 +00001210 struct node *node;
1211
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001212 node = find_node(f, nodeid, name);
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001213 if (node == NULL)
1214 res = -ENOMEM;
1215 else {
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001216 e->ino = node->nodeid;
1217 e->generation = node->generation;
Miklos Szeredi659743b2005-12-09 17:41:42 +00001218 e->entry_timeout = f->conf.entry_timeout;
1219 e->attr_timeout = f->conf.attr_timeout;
Miklos Szeredi320abe42006-01-30 18:14:51 +00001220 if (f->conf.auto_cache) {
1221 pthread_mutex_lock(&f->lock);
1222 update_stat(node, &e->attr);
1223 pthread_mutex_unlock(&f->lock);
1224 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001225 set_stat(f, e->ino, &e->attr);
Miklos Szeredi1f35c652007-06-18 14:27:47 +00001226 if (f->conf.debug)
1227 fprintf(stderr, " NODEID: %lu\n", (unsigned long) e->ino);
Miklos Szeredi76f65782004-02-19 16:55:40 +00001228 }
1229 }
1230 return res;
1231}
1232
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001233static struct fuse_context_i *fuse_get_context_internal(void)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001234{
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001235 struct fuse_context_i *c;
1236
1237 c = (struct fuse_context_i *) pthread_getspecific(fuse_context_key);
1238 if (c == NULL) {
1239 c = (struct fuse_context_i *) malloc(sizeof(struct fuse_context_i));
1240 if (c == NULL) {
1241 /* This is hard to deal with properly, so just abort. If
1242 memory is so low that the context cannot be allocated,
1243 there's not much hope for the filesystem anyway */
1244 fprintf(stderr, "fuse: failed to allocate thread specific data\n");
1245 abort();
1246 }
1247 pthread_setspecific(fuse_context_key, c);
1248 }
1249 return c;
1250}
1251
1252static void fuse_freecontext(void *data)
1253{
1254 free(data);
1255}
1256
1257static int fuse_create_context_key(void)
1258{
1259 int err = 0;
1260 pthread_mutex_lock(&fuse_context_lock);
1261 if (!fuse_context_ref) {
1262 err = pthread_key_create(&fuse_context_key, fuse_freecontext);
1263 if (err) {
1264 fprintf(stderr, "fuse: failed to create thread specific key: %s\n",
1265 strerror(err));
1266 pthread_mutex_unlock(&fuse_context_lock);
1267 return -1;
1268 }
1269 }
1270 fuse_context_ref++;
1271 pthread_mutex_unlock(&fuse_context_lock);
1272 return 0;
1273}
1274
1275static void fuse_delete_context_key(void)
1276{
1277 pthread_mutex_lock(&fuse_context_lock);
1278 fuse_context_ref--;
1279 if (!fuse_context_ref) {
1280 free(pthread_getspecific(fuse_context_key));
1281 pthread_key_delete(fuse_context_key);
1282 }
1283 pthread_mutex_unlock(&fuse_context_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001284}
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001285
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001286static struct fuse *req_fuse_prepare(fuse_req_t req)
1287{
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001288 struct fuse_context_i *c = fuse_get_context_internal();
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001289 const struct fuse_ctx *ctx = fuse_req_ctx(req);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001290 c->req = req;
1291 c->ctx.fuse = req_fuse(req);
1292 c->ctx.uid = ctx->uid;
1293 c->ctx.gid = ctx->gid;
1294 c->ctx.pid = ctx->pid;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001295 return c->ctx.fuse;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001296}
1297
1298static inline void reply_err(fuse_req_t req, int err)
1299{
1300 /* fuse_reply_err() uses non-negated errno values */
1301 fuse_reply_err(req, -err);
1302}
1303
1304static void reply_entry(fuse_req_t req, const struct fuse_entry_param *e,
1305 int err)
1306{
1307 if (!err) {
Miklos Szeredib67f2162006-02-20 10:55:33 +00001308 struct fuse *f = req_fuse(req);
Miklos Szeredi9b813af2005-07-21 07:59:37 +00001309 if (fuse_reply_entry(req, e) == -ENOENT)
Miklos Szeredib67f2162006-02-20 10:55:33 +00001310 forget_node(f, e->ino, 1);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001311 } else
1312 reply_err(req, err);
1313}
1314
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001315void fuse_fs_init(struct fuse_fs *fs, struct fuse_conn_info *conn)
1316{
1317 fuse_get_context()->private_data = fs->user_data;
1318 if (fs->op.init)
1319 fs->user_data = fs->op.init(conn);
1320}
1321
1322static void fuse_lib_init(void *data, struct fuse_conn_info *conn)
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001323{
1324 struct fuse *f = (struct fuse *) data;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001325 struct fuse_context_i *c = fuse_get_context_internal();
Miklos Szeredi4f5df5e2005-10-07 12:39:58 +00001326
1327 memset(c, 0, sizeof(*c));
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001328 c->ctx.fuse = f;
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001329 fuse_fs_init(f->fs, conn);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001330}
1331
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001332void fuse_fs_destroy(struct fuse_fs *fs)
1333{
1334 fuse_get_context()->private_data = fs->user_data;
1335 if (fs->op.destroy)
1336 fs->op.destroy(fs->user_data);
1337 if (fs->m)
1338 fuse_put_module(fs->m);
1339 free(fs);
1340}
1341
1342static void fuse_lib_destroy(void *data)
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001343{
1344 struct fuse *f = (struct fuse *) data;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001345 struct fuse_context_i *c = fuse_get_context_internal();
Miklos Szeredi4f5df5e2005-10-07 12:39:58 +00001346
1347 memset(c, 0, sizeof(*c));
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001348 c->ctx.fuse = f;
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001349 fuse_fs_destroy(f->fs);
1350 f->fs = NULL;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001351}
1352
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001353static void fuse_lib_lookup(fuse_req_t req, fuse_ino_t parent,
1354 const char *name)
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001355{
1356 struct fuse *f = req_fuse_prepare(req);
1357 struct fuse_entry_param e;
1358 char *path;
1359 int err;
1360
1361 err = -ENOENT;
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001362 pthread_rwlock_rdlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001363 path = get_path_name(f, parent, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001364 if (path != NULL) {
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001365 struct fuse_intr_data d;
Miklos Szeredi1f35c652007-06-18 14:27:47 +00001366 if (f->conf.debug)
1367 fprintf(stderr, "LOOKUP %s\n", path);
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001368 fuse_prepare_interrupt(f, req, &d);
1369 err = lookup_path(f, parent, name, path, &e, NULL);
1370 if (err == -ENOENT && f->conf.negative_timeout != 0.0) {
1371 e.ino = 0;
1372 e.entry_timeout = f->conf.negative_timeout;
1373 err = 0;
Miklos Szeredi2b478112005-11-28 13:27:10 +00001374 }
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001375 fuse_finish_interrupt(f, req, &d);
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001376 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001377 }
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001378 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001379 reply_entry(req, &e, err);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001380}
1381
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001382static void fuse_lib_forget(fuse_req_t req, fuse_ino_t ino,
1383 unsigned long nlookup)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001384{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001385 struct fuse *f = req_fuse(req);
Miklos Szeredi1f35c652007-06-18 14:27:47 +00001386 if (f->conf.debug)
1387 fprintf(stderr, "FORGET %llu/%lu\n", (unsigned long long)ino, nlookup);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001388 forget_node(f, ino, nlookup);
1389 fuse_reply_none(req);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001390}
1391
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001392static void fuse_lib_getattr(fuse_req_t req, fuse_ino_t ino,
1393 struct fuse_file_info *fi)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001394{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001395 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredi19dff1b2001-10-30 15:06:52 +00001396 struct stat buf;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001397 char *path;
1398 int err;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001399
Miklos Szerediecce1bf2005-08-25 15:19:06 +00001400 (void) fi;
Miklos Szeredi16dbf942006-09-02 13:20:40 +00001401 memset(&buf, 0, sizeof(buf));
Miklos Szerediecce1bf2005-08-25 15:19:06 +00001402
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001403 err = -ENOENT;
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001404 pthread_rwlock_rdlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001405 path = get_path(f, ino);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001406 if (path != NULL) {
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001407 struct fuse_intr_data d;
1408 fuse_prepare_interrupt(f, req, &d);
1409 err = fuse_fs_getattr(f->fs, path, &buf);
1410 fuse_finish_interrupt(f, req, &d);
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001411 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001412 }
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001413 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001414 if (!err) {
Miklos Szeredi08dab162006-02-01 13:39:15 +00001415 if (f->conf.auto_cache) {
1416 pthread_mutex_lock(&f->lock);
1417 update_stat(get_node(f, ino), &buf);
1418 pthread_mutex_unlock(&f->lock);
1419 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001420 set_stat(f, ino, &buf);
Miklos Szeredi659743b2005-12-09 17:41:42 +00001421 fuse_reply_attr(req, &buf, f->conf.attr_timeout);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001422 } else
1423 reply_err(req, err);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001424}
1425
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001426int fuse_fs_chmod(struct fuse_fs *fs, const char *path, mode_t mode)
Miklos Szeredif3ea83b2001-11-07 14:55:16 +00001427{
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001428 if (fs->op.chmod)
1429 return fs->op.chmod(path, mode);
1430 else
1431 return -ENOSYS;
Miklos Szeredie5183742005-02-02 11:14:04 +00001432}
Miklos Szeredif3ea83b2001-11-07 14:55:16 +00001433
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001434static void fuse_lib_setattr(fuse_req_t req, fuse_ino_t ino, struct stat *attr,
1435 int valid, struct fuse_file_info *fi)
Miklos Szeredi5e183482001-10-31 14:52:35 +00001436{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001437 struct fuse *f = req_fuse_prepare(req);
1438 struct stat buf;
Miklos Szeredi5e183482001-10-31 14:52:35 +00001439 char *path;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001440 int err;
Miklos Szeredi5e183482001-10-31 14:52:35 +00001441
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001442 err = -ENOENT;
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001443 pthread_rwlock_rdlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001444 path = get_path(f, ino);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001445 if (path != NULL) {
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001446 struct fuse_intr_data d;
1447 fuse_prepare_interrupt(f, req, &d);
1448 err = 0;
1449 if (!err && (valid & FUSE_SET_ATTR_MODE))
1450 err = fuse_fs_chmod(f->fs, path, attr->st_mode);
1451 if (!err && (valid & (FUSE_SET_ATTR_UID | FUSE_SET_ATTR_GID))) {
1452 uid_t uid =
1453 (valid & FUSE_SET_ATTR_UID) ? attr->st_uid : (uid_t) -1;
1454 gid_t gid =
1455 (valid & FUSE_SET_ATTR_GID) ? attr->st_gid : (gid_t) -1;
1456 err = fuse_fs_chown(f->fs, path, uid, gid);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001457 }
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001458 if (!err && (valid & FUSE_SET_ATTR_SIZE)) {
1459 if (fi)
1460 err = fuse_fs_ftruncate(f->fs, path, attr->st_size, fi);
1461 else
1462 err = fuse_fs_truncate(f->fs, path, attr->st_size);
1463 }
1464 if (!err && (valid & (FUSE_SET_ATTR_ATIME | FUSE_SET_ATTR_MTIME)) ==
1465 (FUSE_SET_ATTR_ATIME | FUSE_SET_ATTR_MTIME)) {
1466 struct timespec tv[2];
1467 tv[0].tv_sec = attr->st_atime;
1468 tv[0].tv_nsec = ST_ATIM_NSEC(attr);
1469 tv[1].tv_sec = attr->st_mtime;
1470 tv[1].tv_nsec = ST_MTIM_NSEC(attr);
1471 err = fuse_fs_utimens(f->fs, path, tv);
1472 }
1473 if (!err)
1474 err = fuse_fs_getattr(f->fs, path, &buf);
1475 fuse_finish_interrupt(f, req, &d);
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001476 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001477 }
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001478 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001479 if (!err) {
Miklos Szeredi08dab162006-02-01 13:39:15 +00001480 if (f->conf.auto_cache) {
1481 pthread_mutex_lock(&f->lock);
1482 update_stat(get_node(f, ino), &buf);
1483 pthread_mutex_unlock(&f->lock);
1484 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001485 set_stat(f, ino, &buf);
Miklos Szeredi659743b2005-12-09 17:41:42 +00001486 fuse_reply_attr(req, &buf, f->conf.attr_timeout);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001487 } else
1488 reply_err(req, err);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001489}
1490
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001491static void fuse_lib_access(fuse_req_t req, fuse_ino_t ino, int mask)
Miklos Szeredib0b13d12005-10-26 12:53:25 +00001492{
1493 struct fuse *f = req_fuse_prepare(req);
1494 char *path;
1495 int err;
1496
1497 err = -ENOENT;
1498 pthread_rwlock_rdlock(&f->tree_lock);
1499 path = get_path(f, ino);
1500 if (path != NULL) {
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001501 struct fuse_intr_data d;
Miklos Szeredi1f35c652007-06-18 14:27:47 +00001502 if (f->conf.debug)
1503 fprintf(stderr, "ACCESS %s 0%o\n", path, mask);
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001504 fuse_prepare_interrupt(f, req, &d);
1505 err = fuse_fs_access(f->fs, path, mask);
1506 fuse_finish_interrupt(f, req, &d);
Miklos Szeredib0b13d12005-10-26 12:53:25 +00001507 free(path);
1508 }
1509 pthread_rwlock_unlock(&f->tree_lock);
1510 reply_err(req, err);
1511}
1512
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001513static void fuse_lib_readlink(fuse_req_t req, fuse_ino_t ino)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001514{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001515 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredif6e0ec62005-08-03 09:11:06 +00001516 char linkname[PATH_MAX + 1];
Miklos Szeredib483c932001-10-29 14:57:57 +00001517 char *path;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001518 int err;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001519
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001520 err = -ENOENT;
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001521 pthread_rwlock_rdlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001522 path = get_path(f, ino);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001523 if (path != NULL) {
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001524 struct fuse_intr_data d;
1525 fuse_prepare_interrupt(f, req, &d);
1526 err = fuse_fs_readlink(f->fs, path, linkname, sizeof(linkname));
1527 fuse_finish_interrupt(f, req, &d);
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001528 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001529 }
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001530 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001531 if (!err) {
Miklos Szeredif6e0ec62005-08-03 09:11:06 +00001532 linkname[PATH_MAX] = '\0';
1533 fuse_reply_readlink(req, linkname);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001534 } else
1535 reply_err(req, err);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001536}
1537
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001538static void fuse_lib_mknod(fuse_req_t req, fuse_ino_t parent, const char *name,
1539 mode_t mode, dev_t rdev)
Miklos Szeredib483c932001-10-29 14:57:57 +00001540{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001541 struct fuse *f = req_fuse_prepare(req);
1542 struct fuse_entry_param e;
Miklos Szeredib483c932001-10-29 14:57:57 +00001543 char *path;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001544 int err;
Miklos Szeredib483c932001-10-29 14:57:57 +00001545
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001546 err = -ENOENT;
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001547 pthread_rwlock_rdlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001548 path = get_path_name(f, parent, name);
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001549 if (path) {
1550 struct fuse_intr_data d;
Miklos Szeredi1f35c652007-06-18 14:27:47 +00001551 if (f->conf.debug)
1552 fprintf(stderr, "MKNOD %s\n", path);
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001553 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001554 err = -ENOSYS;
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001555 if (S_ISREG(mode)) {
Miklos Szeredib3f99722005-11-16 13:00:24 +00001556 struct fuse_file_info fi;
1557
1558 memset(&fi, 0, sizeof(fi));
1559 fi.flags = O_CREAT | O_EXCL | O_WRONLY;
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001560 err = fuse_fs_create(f->fs, path, mode, &fi);
Miklos Szeredib3f99722005-11-16 13:00:24 +00001561 if (!err) {
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001562 err = lookup_path(f, parent, name, path, &e, &fi);
1563 fuse_fs_release(f->fs, path, &fi);
Miklos Szeredib3f99722005-11-16 13:00:24 +00001564 }
Miklos Szeredi5e183482001-10-31 14:52:35 +00001565 }
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001566 if (err == -ENOSYS) {
1567 err = fuse_fs_mknod(f->fs, path, mode, rdev);
1568 if (!err)
1569 err = lookup_path(f, parent, name, path, &e, NULL);
1570 }
1571 fuse_finish_interrupt(f, req, &d);
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001572 free(path);
Miklos Szeredib483c932001-10-29 14:57:57 +00001573 }
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001574 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001575 reply_entry(req, &e, err);
Miklos Szeredib483c932001-10-29 14:57:57 +00001576}
1577
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001578static void fuse_lib_mkdir(fuse_req_t req, fuse_ino_t parent, const char *name,
1579 mode_t mode)
Miklos Szeredib483c932001-10-29 14:57:57 +00001580{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001581 struct fuse *f = req_fuse_prepare(req);
1582 struct fuse_entry_param e;
Miklos Szeredib483c932001-10-29 14:57:57 +00001583 char *path;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001584 int err;
Miklos Szeredib483c932001-10-29 14:57:57 +00001585
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001586 err = -ENOENT;
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001587 pthread_rwlock_rdlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001588 path = get_path_name(f, parent, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001589 if (path != NULL) {
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001590 struct fuse_intr_data d;
Miklos Szeredi1f35c652007-06-18 14:27:47 +00001591 if (f->conf.debug)
1592 fprintf(stderr, "MKDIR %s\n", path);
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001593 fuse_prepare_interrupt(f, req, &d);
1594 err = fuse_fs_mkdir(f->fs, path, mode);
1595 if (!err)
1596 err = lookup_path(f, parent, name, path, &e, NULL);
1597 fuse_finish_interrupt(f, req, &d);
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001598 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001599 }
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001600 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001601 reply_entry(req, &e, err);
Miklos Szeredib483c932001-10-29 14:57:57 +00001602}
1603
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001604static void fuse_lib_unlink(fuse_req_t req, fuse_ino_t parent,
1605 const char *name)
Miklos Szeredib483c932001-10-29 14:57:57 +00001606{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001607 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredib483c932001-10-29 14:57:57 +00001608 char *path;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001609 int err;
Miklos Szeredib483c932001-10-29 14:57:57 +00001610
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001611 err = -ENOENT;
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001612 pthread_rwlock_wrlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001613 path = get_path_name(f, parent, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001614 if (path != NULL) {
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001615 struct fuse_intr_data d;
Miklos Szeredi1f35c652007-06-18 14:27:47 +00001616 if (f->conf.debug)
1617 fprintf(stderr, "UNLINK %s\n", path);
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001618 fuse_prepare_interrupt(f, req, &d);
1619 if (!f->conf.hard_remove && is_open(f, parent, name))
1620 err = hide_node(f, path, parent, name);
1621 else {
1622 err = fuse_fs_unlink(f->fs, path);
1623 if (!err)
1624 remove_node(f, parent, name);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001625 }
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001626 fuse_finish_interrupt(f, req, &d);
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001627 free(path);
Miklos Szeredib483c932001-10-29 14:57:57 +00001628 }
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001629 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001630 reply_err(req, err);
Miklos Szeredib5958612004-02-20 14:10:49 +00001631}
1632
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001633static void fuse_lib_rmdir(fuse_req_t req, fuse_ino_t parent, const char *name)
Miklos Szeredib5958612004-02-20 14:10:49 +00001634{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001635 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredib5958612004-02-20 14:10:49 +00001636 char *path;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001637 int err;
Miklos Szeredib5958612004-02-20 14:10:49 +00001638
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001639 err = -ENOENT;
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001640 pthread_rwlock_wrlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001641 path = get_path_name(f, parent, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001642 if (path != NULL) {
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001643 struct fuse_intr_data d;
Miklos Szeredi1f35c652007-06-18 14:27:47 +00001644 if (f->conf.debug)
1645 fprintf(stderr, "RMDIR %s\n", path);
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001646 fuse_prepare_interrupt(f, req, &d);
1647 err = fuse_fs_rmdir(f->fs, path);
1648 fuse_finish_interrupt(f, req, &d);
1649 if (!err)
1650 remove_node(f, parent, name);
Miklos Szeredib5958612004-02-20 14:10:49 +00001651 free(path);
1652 }
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001653 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001654 reply_err(req, err);
Miklos Szeredib483c932001-10-29 14:57:57 +00001655}
1656
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001657static void fuse_lib_symlink(fuse_req_t req, const char *linkname,
1658 fuse_ino_t parent, const char *name)
Miklos Szeredib483c932001-10-29 14:57:57 +00001659{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001660 struct fuse *f = req_fuse_prepare(req);
1661 struct fuse_entry_param e;
Miklos Szeredib483c932001-10-29 14:57:57 +00001662 char *path;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001663 int err;
Miklos Szeredib483c932001-10-29 14:57:57 +00001664
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001665 err = -ENOENT;
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001666 pthread_rwlock_rdlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001667 path = get_path_name(f, parent, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001668 if (path != NULL) {
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001669 struct fuse_intr_data d;
Miklos Szeredi1f35c652007-06-18 14:27:47 +00001670 if (f->conf.debug)
1671 fprintf(stderr, "SYMLINK %s\n", path);
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001672 fuse_prepare_interrupt(f, req, &d);
1673 err = fuse_fs_symlink(f->fs, linkname, path);
1674 if (!err)
1675 err = lookup_path(f, parent, name, path, &e, NULL);
1676 fuse_finish_interrupt(f, req, &d);
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001677 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001678 }
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001679 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001680 reply_entry(req, &e, err);
Miklos Szeredib483c932001-10-29 14:57:57 +00001681}
1682
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001683static void fuse_lib_rename(fuse_req_t req, fuse_ino_t olddir,
1684 const char *oldname, fuse_ino_t newdir,
1685 const char *newname)
Miklos Szeredi19dff1b2001-10-30 15:06:52 +00001686{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001687 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001688 char *oldpath;
1689 char *newpath;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001690 int err;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +00001691
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001692 err = -ENOENT;
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001693 pthread_rwlock_wrlock(&f->tree_lock);
Miklos Szeredia181e612001-11-06 12:03:23 +00001694 oldpath = get_path_name(f, olddir, oldname);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001695 if (oldpath != NULL) {
Miklos Szeredia181e612001-11-06 12:03:23 +00001696 newpath = get_path_name(f, newdir, newname);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001697 if (newpath != NULL) {
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001698 struct fuse_intr_data d;
Miklos Szeredi1f35c652007-06-18 14:27:47 +00001699 if (f->conf.debug)
1700 fprintf(stderr, "RENAME %s -> %s\n", oldpath, newpath);
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001701 err = 0;
1702 fuse_prepare_interrupt(f, req, &d);
1703 if (!f->conf.hard_remove && is_open(f, newdir, newname))
1704 err = hide_node(f, newpath, newdir, newname);
1705 if (!err) {
1706 err = fuse_fs_rename(f->fs, oldpath, newpath);
1707 if (!err)
1708 err = rename_node(f, olddir, oldname, newdir, newname, 0);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001709 }
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001710 fuse_finish_interrupt(f, req, &d);
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001711 free(newpath);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001712 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001713 free(oldpath);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001714 }
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001715 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001716 reply_err(req, err);
Miklos Szeredi19dff1b2001-10-30 15:06:52 +00001717}
1718
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001719static void fuse_lib_link(fuse_req_t req, fuse_ino_t ino, fuse_ino_t newparent,
1720 const char *newname)
Miklos Szeredi19dff1b2001-10-30 15:06:52 +00001721{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001722 struct fuse *f = req_fuse_prepare(req);
1723 struct fuse_entry_param e;
Miklos Szeredi5e183482001-10-31 14:52:35 +00001724 char *oldpath;
1725 char *newpath;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001726 int err;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +00001727
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001728 err = -ENOENT;
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001729 pthread_rwlock_rdlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001730 oldpath = get_path(f, ino);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001731 if (oldpath != NULL) {
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001732 newpath = get_path_name(f, newparent, newname);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001733 if (newpath != NULL) {
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001734 struct fuse_intr_data d;
Miklos Szeredi1f35c652007-06-18 14:27:47 +00001735 if (f->conf.debug)
1736 fprintf(stderr, "LINK %s\n", newpath);
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001737 fuse_prepare_interrupt(f, req, &d);
1738 err = fuse_fs_link(f->fs, oldpath, newpath);
1739 if (!err)
1740 err = lookup_path(f, newparent, newname, newpath, &e, NULL);
1741 fuse_finish_interrupt(f, req, &d);
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001742 free(newpath);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001743 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001744 free(oldpath);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001745 }
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001746 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001747 reply_entry(req, &e, err);
Miklos Szeredi19dff1b2001-10-30 15:06:52 +00001748}
1749
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001750static void fuse_do_release(struct fuse *f, fuse_ino_t ino, const char *path,
1751 struct fuse_file_info *fi)
1752{
1753 struct node *node;
1754 int unlink_hidden = 0;
1755
1756 fuse_fs_release(f->fs, path ? path : "-", fi);
1757
1758 pthread_mutex_lock(&f->lock);
1759 node = get_node(f, ino);
1760 assert(node->open_count > 0);
1761 --node->open_count;
1762 if (node->is_hidden && !node->open_count) {
1763 unlink_hidden = 1;
1764 node->is_hidden = 0;
1765 }
1766 pthread_mutex_unlock(&f->lock);
1767
1768 if(unlink_hidden && path)
1769 fuse_fs_unlink(f->fs, path);
1770}
1771
1772static void fuse_lib_create(fuse_req_t req, fuse_ino_t parent,
1773 const char *name, mode_t mode,
1774 struct fuse_file_info *fi)
Miklos Szeredid9079a72005-10-26 15:29:06 +00001775{
1776 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001777 struct fuse_intr_data d;
Miklos Szeredid9079a72005-10-26 15:29:06 +00001778 struct fuse_entry_param e;
1779 char *path;
1780 int err;
1781
1782 err = -ENOENT;
1783 pthread_rwlock_rdlock(&f->tree_lock);
1784 path = get_path_name(f, parent, name);
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001785 if (path) {
1786 fuse_prepare_interrupt(f, req, &d);
1787 err = fuse_fs_create(f->fs, path, mode, fi);
1788 if (!err) {
1789 err = lookup_path(f, parent, name, path, &e, fi);
1790 if (err)
1791 fuse_fs_release(f->fs, path, fi);
1792 else if (!S_ISREG(e.attr.st_mode)) {
1793 err = -EIO;
1794 fuse_fs_release(f->fs, path, fi);
1795 forget_node(f, e.ino, 1);
1796 } else {
1797 if (f->conf.direct_io)
1798 fi->direct_io = 1;
1799 if (f->conf.kernel_cache)
1800 fi->keep_cache = 1;
1801
Miklos Szeredid9079a72005-10-26 15:29:06 +00001802 }
1803 }
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001804 fuse_finish_interrupt(f, req, &d);
Miklos Szeredid9079a72005-10-26 15:29:06 +00001805 }
Miklos Szeredid9079a72005-10-26 15:29:06 +00001806 if (!err) {
Miklos Szeredid9079a72005-10-26 15:29:06 +00001807 pthread_mutex_lock(&f->lock);
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001808 get_node(f, e.ino)->open_count++;
1809 pthread_mutex_unlock(&f->lock);
Miklos Szeredid9079a72005-10-26 15:29:06 +00001810 if (fuse_reply_create(req, &e, fi) == -ENOENT) {
1811 /* The open syscall was interrupted, so it must be cancelled */
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001812 fuse_prepare_interrupt(f, req, &d);
1813 fuse_do_release(f, e.ino, path, fi);
1814 fuse_finish_interrupt(f, req, &d);
Miklos Szeredid9079a72005-10-26 15:29:06 +00001815 forget_node(f, e.ino, 1);
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001816 } else if (f->conf.debug) {
Miklos Szeredi1f35c652007-06-18 14:27:47 +00001817 fprintf(stderr, " CREATE[%llu] flags: 0x%x %s\n",
1818 (unsigned long long) fi->fh, fi->flags, path);
Miklos Szeredid9079a72005-10-26 15:29:06 +00001819 }
Miklos Szeredid9079a72005-10-26 15:29:06 +00001820 } else
1821 reply_err(req, err);
1822
1823 if (path)
1824 free(path);
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001825
Miklos Szeredid9079a72005-10-26 15:29:06 +00001826 pthread_rwlock_unlock(&f->tree_lock);
1827}
1828
Miklos Szeredi320abe42006-01-30 18:14:51 +00001829static double diff_timespec(const struct timespec *t1,
1830 const struct timespec *t2)
1831{
1832 return (t1->tv_sec - t2->tv_sec) +
1833 ((double) t1->tv_nsec - (double) t2->tv_nsec) / 1000000000.0;
1834}
1835
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001836static void open_auto_cache(struct fuse *f, fuse_ino_t ino, const char *path,
1837 struct fuse_file_info *fi)
Miklos Szeredi320abe42006-01-30 18:14:51 +00001838{
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001839 struct node *node;
1840
1841 pthread_mutex_lock(&f->lock);
1842 node = get_node(f, ino);
Miklos Szeredi08dab162006-02-01 13:39:15 +00001843 if (node->cache_valid) {
1844 struct timespec now;
Miklos Szeredi320abe42006-01-30 18:14:51 +00001845
Miklos Szeredi08dab162006-02-01 13:39:15 +00001846 curr_time(&now);
Miklos Szeredi6e806e92006-02-16 16:59:39 +00001847 if (diff_timespec(&now, &node->stat_updated) > f->conf.ac_attr_timeout) {
Miklos Szeredi08dab162006-02-01 13:39:15 +00001848 struct stat stbuf;
1849 int err;
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001850 pthread_mutex_unlock(&f->lock);
1851 err = fuse_fs_fgetattr(f->fs, path, &stbuf, fi);
1852 pthread_mutex_lock(&f->lock);
Miklos Szeredi08dab162006-02-01 13:39:15 +00001853 if (!err)
1854 update_stat(node, &stbuf);
1855 else
1856 node->cache_valid = 0;
1857 }
Miklos Szeredi320abe42006-01-30 18:14:51 +00001858 }
1859 if (node->cache_valid)
1860 fi->keep_cache = 1;
Miklos Szeredi08dab162006-02-01 13:39:15 +00001861
1862 node->cache_valid = 1;
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001863 pthread_mutex_unlock(&f->lock);
Miklos Szeredi320abe42006-01-30 18:14:51 +00001864}
1865
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001866static void fuse_lib_open(fuse_req_t req, fuse_ino_t ino,
1867 struct fuse_file_info *fi)
Miklos Szeredi5e183482001-10-31 14:52:35 +00001868{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001869 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001870 struct fuse_intr_data d;
Miklos Szeredi31066bb2005-08-01 14:49:31 +00001871 char *path = NULL;
1872 int err = 0;
Miklos Szeredi5e183482001-10-31 14:52:35 +00001873
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001874 err = -ENOENT;
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001875 pthread_rwlock_rdlock(&f->tree_lock);
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001876 path = get_path(f, ino);
1877 if (path) {
1878 fuse_prepare_interrupt(f, req, &d);
1879 err = fuse_fs_open(f->fs, path, fi);
1880 if (!err) {
1881 if (f->conf.direct_io)
1882 fi->direct_io = 1;
1883 if (f->conf.kernel_cache)
1884 fi->keep_cache = 1;
1885
1886 if (f->conf.auto_cache)
1887 open_auto_cache(f, ino, path, fi);
1888 }
1889 fuse_finish_interrupt(f, req, &d);
Miklos Szeredi40b9a5a2002-12-10 16:09:02 +00001890 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001891 if (!err) {
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001892 pthread_mutex_lock(&f->lock);
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001893 get_node(f, ino)->open_count++;
1894 pthread_mutex_unlock(&f->lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001895 if (fuse_reply_open(req, fi) == -ENOENT) {
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001896 /* The open syscall was interrupted, so it must be cancelled */
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001897 fuse_prepare_interrupt(f, req, &d);
1898 fuse_do_release(f, ino, path, fi);
1899 fuse_finish_interrupt(f, req, &d);
1900 } else if (f->conf.debug) {
Miklos Szeredi1f35c652007-06-18 14:27:47 +00001901 fprintf(stderr, "OPEN[%llu] flags: 0x%x %s\n",
1902 (unsigned long long) fi->fh, fi->flags, path);
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001903 }
Miklos Szeredi73798f92004-07-12 15:55:11 +00001904 } else
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001905 reply_err(req, err);
Miklos Szeredi73798f92004-07-12 15:55:11 +00001906
Miklos Szeredi9a31cca2004-06-26 21:11:25 +00001907 if (path)
1908 free(path);
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001909 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001910}
1911
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001912static void fuse_lib_read(fuse_req_t req, fuse_ino_t ino, size_t size,
1913 off_t off, struct fuse_file_info *fi)
Miklos Szeredie2e4ac22004-05-18 08:45:28 +00001914{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001915 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredie2e4ac22004-05-18 08:45:28 +00001916 char *path;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001917 char *buf;
Miklos Szeredie2e4ac22004-05-18 08:45:28 +00001918 int res;
1919
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001920 buf = (char *) malloc(size);
1921 if (buf == NULL) {
1922 reply_err(req, -ENOMEM);
1923 return;
1924 }
1925
Miklos Szeredie2e4ac22004-05-18 08:45:28 +00001926 res = -ENOENT;
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001927 pthread_rwlock_rdlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001928 path = get_path(f, ino);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001929 if (path != NULL) {
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001930 struct fuse_intr_data d;
Miklos Szeredi1f35c652007-06-18 14:27:47 +00001931 if (f->conf.debug)
1932 fprintf(stderr, "READ[%llu] %lu bytes from %llu\n",
1933 (unsigned long long) fi->fh, (unsigned long) size,
1934 (unsigned long long) off);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001935
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001936 fuse_prepare_interrupt(f, req, &d);
1937 res = fuse_fs_read(f->fs, path, buf, size, off, fi);
1938 fuse_finish_interrupt(f, req, &d);
Miklos Szeredie2e4ac22004-05-18 08:45:28 +00001939 free(path);
1940 }
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001941 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001942
1943 if (res >= 0) {
Miklos Szeredi1f35c652007-06-18 14:27:47 +00001944 if (f->conf.debug)
1945 fprintf(stderr, " READ[%llu] %u bytes\n",
1946 (unsigned long long)fi->fh, res);
Miklos Szeredif412d072005-10-14 21:24:32 +00001947 if ((size_t) res > size)
1948 fprintf(stderr, "fuse: read too many bytes");
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001949 fuse_reply_buf(req, buf, res);
1950 } else
1951 reply_err(req, res);
1952
1953 free(buf);
Miklos Szeredie2e4ac22004-05-18 08:45:28 +00001954}
1955
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001956static void fuse_lib_write(fuse_req_t req, fuse_ino_t ino, const char *buf,
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001957 size_t size, off_t off, struct fuse_file_info *fi)
Miklos Szeredic8ba2372002-12-10 12:26:00 +00001958{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001959 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001960 char *path;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001961 int res;
1962
1963 res = -ENOENT;
1964 pthread_rwlock_rdlock(&f->tree_lock);
1965 path = get_path(f, ino);
1966 if (path != NULL) {
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001967 struct fuse_intr_data d;
Miklos Szeredi1f35c652007-06-18 14:27:47 +00001968 if (f->conf.debug)
1969 fprintf(stderr, "WRITE%s[%llu] %lu bytes to %llu\n",
1970 fi->writepage ? "PAGE" : "", (unsigned long long) fi->fh,
1971 (unsigned long) size, (unsigned long long) off);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001972
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001973 fuse_prepare_interrupt(f, req, &d);
1974 res = fuse_fs_write(f->fs, path, buf, size, off, fi);
1975 fuse_finish_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001976 free(path);
1977 }
1978 pthread_rwlock_unlock(&f->tree_lock);
1979
Miklos Szeredif412d072005-10-14 21:24:32 +00001980 if (res >= 0) {
Miklos Szeredi1f35c652007-06-18 14:27:47 +00001981 if (f->conf.debug)
1982 fprintf(stderr, " WRITE%s[%llu] %u bytes\n",
1983 fi->writepage ? "PAGE" : "", (unsigned long long) fi->fh,
1984 res);
Miklos Szeredif412d072005-10-14 21:24:32 +00001985 if ((size_t) res > size)
1986 fprintf(stderr, "fuse: wrote too many bytes");
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001987 fuse_reply_write(req, res);
Miklos Szeredif412d072005-10-14 21:24:32 +00001988 } else
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001989 reply_err(req, res);
1990}
1991
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00001992static void fuse_lib_fsync(fuse_req_t req, fuse_ino_t ino, int datasync,
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001993 struct fuse_file_info *fi)
Miklos Szeredi5e183482001-10-31 14:52:35 +00001994{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001995 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001996 char *path;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001997 int err;
Miklos Szerediab974562005-04-07 15:40:21 +00001998
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001999 err = -ENOENT;
2000 pthread_rwlock_rdlock(&f->tree_lock);
2001 path = get_path(f, ino);
2002 if (path != NULL) {
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002003 struct fuse_intr_data d;
Miklos Szeredi1f35c652007-06-18 14:27:47 +00002004 if (f->conf.debug)
2005 fprintf(stderr, "FSYNC[%llu]\n", (unsigned long long) fi->fh);
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002006 fuse_prepare_interrupt(f, req, &d);
2007 err = fuse_fs_fsync(f->fs, path, datasync, fi);
2008 fuse_finish_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002009 free(path);
2010 }
2011 pthread_rwlock_unlock(&f->tree_lock);
2012 reply_err(req, err);
2013}
2014
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002015static struct fuse_dh *get_dirhandle(const struct fuse_file_info *llfi,
2016 struct fuse_file_info *fi)
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002017{
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002018 struct fuse_dh *dh = (struct fuse_dh *) (uintptr_t) llfi->fh;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002019 memset(fi, 0, sizeof(struct fuse_file_info));
2020 fi->fh = dh->fh;
Miklos Szerediead7f102005-11-28 16:02:27 +00002021 fi->fh_old = dh->fh;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002022 return dh;
2023}
2024
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002025static void fuse_lib_opendir(fuse_req_t req, fuse_ino_t ino,
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002026 struct fuse_file_info *llfi)
2027{
2028 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002029 struct fuse_intr_data d;
2030 struct fuse_dh *dh;
2031 struct fuse_file_info fi;
2032 char *path;
2033 int err;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002034
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002035 dh = (struct fuse_dh *) malloc(sizeof(struct fuse_dh));
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002036 if (dh == NULL) {
2037 reply_err(req, -ENOMEM);
Miklos Szerediab974562005-04-07 15:40:21 +00002038 return;
Miklos Szeredi5e183482001-10-31 14:52:35 +00002039 }
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002040 memset(dh, 0, sizeof(struct fuse_dh));
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002041 dh->fuse = f;
2042 dh->contents = NULL;
2043 dh->len = 0;
2044 dh->filled = 0;
2045 dh->nodeid = ino;
Miklos Szeredi38f152c2006-09-03 18:28:52 +00002046 fuse_mutex_init(&dh->lock);
Miklos Szerediab974562005-04-07 15:40:21 +00002047
Miklos Szeredi3a770472005-11-11 21:32:42 +00002048 llfi->fh = (uintptr_t) dh;
Miklos Szerediab974562005-04-07 15:40:21 +00002049
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002050 memset(&fi, 0, sizeof(fi));
2051 fi.flags = llfi->flags;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002052
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002053 err = -ENOENT;
2054 pthread_rwlock_rdlock(&f->tree_lock);
2055 path = get_path(f, ino);
2056 if (path != NULL) {
2057 fuse_prepare_interrupt(f, req, &d);
2058 err = fuse_fs_opendir(f->fs, path, &fi);
2059 fuse_finish_interrupt(f, req, &d);
2060 dh->fh = fi.fh;
2061 }
2062 if (!err) {
2063 if (fuse_reply_open(req, llfi) == -ENOENT) {
2064 /* The opendir syscall was interrupted, so it must be cancelled */
2065 fuse_prepare_interrupt(f, req, &d);
2066 fuse_fs_releasedir(f->fs, path, &fi);
2067 fuse_finish_interrupt(f, req, &d);
2068 pthread_mutex_destroy(&dh->lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002069 free(dh);
2070 }
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002071 } else {
2072 reply_err(req, err);
2073 free(dh);
2074 }
2075 free(path);
2076 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredi5e183482001-10-31 14:52:35 +00002077}
Miklos Szeredib483c932001-10-29 14:57:57 +00002078
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002079static int extend_contents(struct fuse_dh *dh, unsigned minsize)
Miklos Szeredi1bf64f42006-02-17 15:49:25 +00002080{
2081 if (minsize > dh->size) {
2082 char *newptr;
2083 unsigned newsize = dh->size;
2084 if (!newsize)
2085 newsize = 1024;
2086 while (newsize < minsize)
2087 newsize *= 2;
2088
2089 newptr = (char *) realloc(dh->contents, newsize);
2090 if (!newptr) {
2091 dh->error = -ENOMEM;
2092 return -1;
2093 }
2094 dh->contents = newptr;
2095 dh->size = newsize;
2096 }
2097 return 0;
2098}
2099
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002100static int fill_dir(void *dh_, const char *name, const struct stat *statp,
2101 off_t off)
Miklos Szeredia181e612001-11-06 12:03:23 +00002102{
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002103 struct fuse_dh *dh = (struct fuse_dh *) dh_;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002104 struct stat stbuf;
Miklos Szeredi1bf64f42006-02-17 15:49:25 +00002105 size_t newlen;
Miklos Szeredifb28c5e2004-11-26 12:15:06 +00002106
Miklos Szeredif6e0ec62005-08-03 09:11:06 +00002107 if (statp)
2108 stbuf = *statp;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002109 else {
2110 memset(&stbuf, 0, sizeof(stbuf));
Miklos Szeredie248e4b2005-12-14 16:18:32 +00002111 stbuf.st_ino = FUSE_UNKNOWN_INO;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002112 }
Miklos Szeredia181e612001-11-06 12:03:23 +00002113
Miklos Szeredi659743b2005-12-09 17:41:42 +00002114 if (!dh->fuse->conf.use_ino) {
Miklos Szeredie248e4b2005-12-14 16:18:32 +00002115 stbuf.st_ino = FUSE_UNKNOWN_INO;
Miklos Szeredi659743b2005-12-09 17:41:42 +00002116 if (dh->fuse->conf.readdir_ino) {
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002117 struct node *node;
2118 pthread_mutex_lock(&dh->fuse->lock);
2119 node = lookup_node(dh->fuse, dh->nodeid, name);
2120 if (node)
2121 stbuf.st_ino = (ino_t) node->nodeid;
2122 pthread_mutex_unlock(&dh->fuse->lock);
Miklos Szeredi6ebe2342002-01-06 21:44:16 +00002123 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002124 }
Miklos Szeredi6ebe2342002-01-06 21:44:16 +00002125
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002126 if (off) {
Miklos Szeredi1bf64f42006-02-17 15:49:25 +00002127 if (extend_contents(dh, dh->needlen) == -1)
2128 return 1;
2129
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002130 dh->filled = 0;
Miklos Szeredi1bf64f42006-02-17 15:49:25 +00002131 newlen = dh->len + fuse_add_direntry(dh->req, dh->contents + dh->len,
2132 dh->needlen - dh->len, name,
2133 &stbuf, off);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002134 if (newlen > dh->needlen)
2135 return 1;
Miklos Szeredi1bf64f42006-02-17 15:49:25 +00002136 } else {
2137 newlen = dh->len + fuse_add_direntry(dh->req, NULL, 0, name, NULL, 0);
2138 if (extend_contents(dh, newlen) == -1)
Miklos Szeredic4c12ae2005-10-20 14:48:50 +00002139 return 1;
Miklos Szeredi1bf64f42006-02-17 15:49:25 +00002140
2141 fuse_add_direntry(dh->req, dh->contents + dh->len, dh->size - dh->len,
2142 name, &stbuf, newlen);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002143 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002144 dh->len = newlen;
2145 return 0;
2146}
2147
Miklos Szeredi1bf64f42006-02-17 15:49:25 +00002148static int readdir_fill(struct fuse *f, fuse_req_t req, fuse_ino_t ino,
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002149 size_t size, off_t off, struct fuse_dh *dh,
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002150 struct fuse_file_info *fi)
2151{
2152 int err = -ENOENT;
2153 char *path;
2154 pthread_rwlock_rdlock(&f->tree_lock);
2155 path = get_path(f, ino);
2156 if (path != NULL) {
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002157 struct fuse_intr_data d;
2158
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002159 dh->len = 0;
2160 dh->error = 0;
2161 dh->needlen = size;
2162 dh->filled = 1;
Miklos Szeredi1bf64f42006-02-17 15:49:25 +00002163 dh->req = req;
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002164 fuse_prepare_interrupt(f, req, &d);
2165 err = fuse_fs_readdir(f->fs, path, dh, fill_dir, off, fi);
2166 fuse_finish_interrupt(f, req, &d);
Miklos Szeredi1bf64f42006-02-17 15:49:25 +00002167 dh->req = NULL;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002168 if (!err)
2169 err = dh->error;
2170 if (err)
2171 dh->filled = 0;
Miklos Szeredi97c61e92001-11-07 12:09:43 +00002172 free(path);
Miklos Szeredia181e612001-11-06 12:03:23 +00002173 }
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00002174 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002175 return err;
2176}
Miklos Szeredie5183742005-02-02 11:14:04 +00002177
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002178static void fuse_lib_readdir(fuse_req_t req, fuse_ino_t ino, size_t size,
2179 off_t off, struct fuse_file_info *llfi)
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002180{
2181 struct fuse *f = req_fuse_prepare(req);
2182 struct fuse_file_info fi;
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002183 struct fuse_dh *dh = get_dirhandle(llfi, &fi);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002184
2185 pthread_mutex_lock(&dh->lock);
Miklos Szeredi77ccf652005-08-19 14:40:27 +00002186 /* According to SUS, directory contents need to be refreshed on
2187 rewinddir() */
2188 if (!off)
2189 dh->filled = 0;
2190
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002191 if (!dh->filled) {
Miklos Szeredi1bf64f42006-02-17 15:49:25 +00002192 int err = readdir_fill(f, req, ino, size, off, dh, &fi);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002193 if (err) {
2194 reply_err(req, err);
2195 goto out;
2196 }
Miklos Szeredia181e612001-11-06 12:03:23 +00002197 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002198 if (dh->filled) {
2199 if (off < dh->len) {
2200 if (off + size > dh->len)
2201 size = dh->len - off;
2202 } else
2203 size = 0;
2204 } else {
2205 size = dh->len;
2206 off = 0;
2207 }
2208 fuse_reply_buf(req, dh->contents + off, size);
2209 out:
2210 pthread_mutex_unlock(&dh->lock);
2211}
Miklos Szeredia181e612001-11-06 12:03:23 +00002212
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002213static void fuse_lib_releasedir(fuse_req_t req, fuse_ino_t ino,
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002214 struct fuse_file_info *llfi)
2215{
2216 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002217 struct fuse_intr_data d;
Miklos Szeredi9b813af2005-07-21 07:59:37 +00002218 struct fuse_file_info fi;
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002219 struct fuse_dh *dh = get_dirhandle(llfi, &fi);
2220 char *path;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002221
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002222 pthread_rwlock_rdlock(&f->tree_lock);
2223 path = get_path(f, ino);
2224 fuse_prepare_interrupt(f, req, &d);
2225 fuse_fs_releasedir(f->fs, path ? path : "-", &fi);
2226 fuse_finish_interrupt(f, req, &d);
2227 if (path)
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002228 free(path);
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002229 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002230 pthread_mutex_lock(&dh->lock);
2231 pthread_mutex_unlock(&dh->lock);
2232 pthread_mutex_destroy(&dh->lock);
2233 free(dh->contents);
2234 free(dh);
2235 reply_err(req, 0);
2236}
2237
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002238static void fuse_lib_fsyncdir(fuse_req_t req, fuse_ino_t ino, int datasync,
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002239 struct fuse_file_info *llfi)
2240{
2241 struct fuse *f = req_fuse_prepare(req);
2242 struct fuse_file_info fi;
2243 char *path;
2244 int err;
2245
2246 get_dirhandle(llfi, &fi);
2247
2248 err = -ENOENT;
2249 pthread_rwlock_rdlock(&f->tree_lock);
2250 path = get_path(f, ino);
2251 if (path != NULL) {
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002252 struct fuse_intr_data d;
2253 fuse_prepare_interrupt(f, req, &d);
2254 err = fuse_fs_fsyncdir(f->fs, path, datasync, &fi);
2255 fuse_finish_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002256 free(path);
2257 }
2258 pthread_rwlock_unlock(&f->tree_lock);
2259 reply_err(req, err);
Miklos Szeredia181e612001-11-06 12:03:23 +00002260}
2261
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002262static void fuse_lib_statfs(fuse_req_t req, fuse_ino_t ino)
Miklos Szeredi18e75e42004-02-19 14:23:27 +00002263{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002264 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredi52cb09d2005-11-07 11:59:00 +00002265 struct statvfs buf;
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002266 char *path;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002267 int err;
Mark Glinesd84b39a2002-01-07 16:32:02 +00002268
Miklos Szeredi52cb09d2005-11-07 11:59:00 +00002269 memset(&buf, 0, sizeof(buf));
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002270 pthread_rwlock_rdlock(&f->tree_lock);
2271 if (!ino) {
2272 err = -ENOMEM;
2273 path = strdup("/");
2274 } else {
2275 err = -ENOENT;
2276 path = get_path(f, ino);
2277 }
2278 if (path) {
2279 struct fuse_intr_data d;
2280 fuse_prepare_interrupt(f, req, &d);
2281 err = fuse_fs_statfs(f->fs, path, &buf);
2282 fuse_finish_interrupt(f, req, &d);
2283 free(path);
2284 }
2285 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredi77f39942004-03-25 11:17:52 +00002286
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002287 if (!err)
2288 fuse_reply_statfs(req, &buf);
Miklos Szeredi03cebae2004-03-31 10:19:18 +00002289 else
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002290 reply_err(req, err);
Miklos Szeredi03cebae2004-03-31 10:19:18 +00002291}
2292
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002293static void fuse_lib_setxattr(fuse_req_t req, fuse_ino_t ino, const char *name,
2294 const char *value, size_t size, int flags)
Miklos Szeredi3ed84232004-03-30 15:17:26 +00002295{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002296 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredi3ed84232004-03-30 15:17:26 +00002297 char *path;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002298 int err;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00002299
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002300 err = -ENOENT;
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00002301 pthread_rwlock_rdlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002302 path = get_path(f, ino);
Miklos Szeredi3ed84232004-03-30 15:17:26 +00002303 if (path != NULL) {
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002304 struct fuse_intr_data d;
2305 fuse_prepare_interrupt(f, req, &d);
2306 err = fuse_fs_setxattr(f->fs, path, name, value, size, flags);
2307 fuse_finish_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002308 free(path);
2309 }
2310 pthread_rwlock_unlock(&f->tree_lock);
2311 reply_err(req, err);
2312}
2313
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002314static int common_getxattr(struct fuse *f, fuse_req_t req, fuse_ino_t ino,
2315 const char *name, char *value, size_t size)
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002316{
2317 int err;
2318 char *path;
2319
2320 err = -ENOENT;
2321 pthread_rwlock_rdlock(&f->tree_lock);
2322 path = get_path(f, ino);
2323 if (path != NULL) {
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002324 struct fuse_intr_data d;
2325 fuse_prepare_interrupt(f, req, &d);
2326 err = fuse_fs_getxattr(f->fs, path, name, value, size);
2327 fuse_finish_interrupt(f, req, &d);
Miklos Szerediab974562005-04-07 15:40:21 +00002328 free(path);
2329 }
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00002330 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szerediab974562005-04-07 15:40:21 +00002331 return err;
2332}
2333
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002334static void fuse_lib_getxattr(fuse_req_t req, fuse_ino_t ino, const char *name,
2335 size_t size)
Miklos Szeredi3ead28e2005-01-18 21:23:41 +00002336{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002337 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredi4283ee72005-03-21 12:09:04 +00002338 int res;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002339
2340 if (size) {
2341 char *value = (char *) malloc(size);
2342 if (value == NULL) {
2343 reply_err(req, -ENOMEM);
2344 return;
2345 }
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002346 res = common_getxattr(f, req, ino, name, value, size);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002347 if (res > 0)
2348 fuse_reply_buf(req, value, res);
2349 else
2350 reply_err(req, res);
2351 free(value);
2352 } else {
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002353 res = common_getxattr(f, req, ino, name, NULL, 0);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002354 if (res >= 0)
2355 fuse_reply_xattr(req, res);
2356 else
2357 reply_err(req, res);
2358 }
2359}
2360
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002361static int common_listxattr(struct fuse *f, fuse_req_t req, fuse_ino_t ino,
2362 char *list, size_t size)
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002363{
Miklos Szeredi4283ee72005-03-21 12:09:04 +00002364 char *path;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002365 int err;
Miklos Szeredi4283ee72005-03-21 12:09:04 +00002366
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002367 err = -ENOENT;
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00002368 pthread_rwlock_rdlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002369 path = get_path(f, ino);
Miklos Szeredi4283ee72005-03-21 12:09:04 +00002370 if (path != NULL) {
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002371 struct fuse_intr_data d;
2372 fuse_prepare_interrupt(f, req, &d);
2373 err = fuse_fs_listxattr(f->fs, path, list, size);
2374 fuse_finish_interrupt(f, req, &d);
Miklos Szeredi4283ee72005-03-21 12:09:04 +00002375 free(path);
2376 }
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00002377 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002378 return err;
Miklos Szeredi4283ee72005-03-21 12:09:04 +00002379}
Miklos Szeredi3ead28e2005-01-18 21:23:41 +00002380
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002381static void fuse_lib_listxattr(fuse_req_t req, fuse_ino_t ino, size_t size)
Miklos Szeredi43696432001-11-18 19:15:05 +00002382{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002383 struct fuse *f = req_fuse_prepare(req);
2384 int res;
2385
2386 if (size) {
2387 char *list = (char *) malloc(size);
2388 if (list == NULL) {
2389 reply_err(req, -ENOMEM);
2390 return;
2391 }
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002392 res = common_listxattr(f, req, ino, list, size);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002393 if (res > 0)
2394 fuse_reply_buf(req, list, res);
2395 else
2396 reply_err(req, res);
2397 free(list);
2398 } else {
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002399 res = common_listxattr(f, req, ino, NULL, 0);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002400 if (res >= 0)
2401 fuse_reply_xattr(req, res);
2402 else
2403 reply_err(req, res);
2404 }
Miklos Szeredi43696432001-11-18 19:15:05 +00002405}
2406
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002407static void fuse_lib_removexattr(fuse_req_t req, fuse_ino_t ino,
2408 const char *name)
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002409{
2410 struct fuse *f = req_fuse_prepare(req);
2411 char *path;
2412 int err;
2413
2414 err = -ENOENT;
2415 pthread_rwlock_rdlock(&f->tree_lock);
2416 path = get_path(f, ino);
2417 if (path != NULL) {
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002418 struct fuse_intr_data d;
2419 fuse_prepare_interrupt(f, req, &d);
2420 err = fuse_fs_removexattr(f->fs, path, name);
2421 fuse_finish_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002422 free(path);
2423 }
2424 pthread_rwlock_unlock(&f->tree_lock);
2425 reply_err(req, err);
2426}
2427
Miklos Szeredi0c59ebf2006-09-10 20:53:36 +00002428static struct lock *locks_conflict(struct node *node, const struct lock *lock)
2429{
2430 struct lock *l;
2431
2432 for (l = node->locks; l; l = l->next)
2433 if (l->owner != lock->owner &&
2434 lock->start <= l->end && l->start <= lock->end &&
2435 (l->type == F_WRLCK || lock->type == F_WRLCK))
2436 break;
2437
2438 return l;
2439}
2440
2441static void delete_lock(struct lock **lockp)
2442{
2443 struct lock *l = *lockp;
2444 *lockp = l->next;
2445 free(l);
2446}
2447
2448static void insert_lock(struct lock **pos, struct lock *lock)
2449{
2450 lock->next = *pos;
2451 *pos = lock;
2452}
2453
2454static int locks_insert(struct node *node, struct lock *lock)
2455{
2456 struct lock **lp;
2457 struct lock *newl1 = NULL;
2458 struct lock *newl2 = NULL;
2459
2460 if (lock->type != F_UNLCK || lock->start != 0 || lock->end != OFFSET_MAX) {
2461 newl1 = malloc(sizeof(struct lock));
2462 newl2 = malloc(sizeof(struct lock));
2463
2464 if (!newl1 || !newl2) {
2465 free(newl1);
2466 free(newl2);
2467 return -ENOLCK;
2468 }
2469 }
2470
2471 for (lp = &node->locks; *lp;) {
2472 struct lock *l = *lp;
2473 if (l->owner != lock->owner)
2474 goto skip;
2475
2476 if (lock->type == l->type) {
2477 if (l->end < lock->start - 1)
2478 goto skip;
2479 if (lock->end < l->start - 1)
2480 break;
2481 if (l->start <= lock->start && lock->end <= l->end)
2482 goto out;
2483 if (l->start < lock->start)
2484 lock->start = l->start;
2485 if (lock->end < l->end)
2486 lock->end = l->end;
2487 goto delete;
2488 } else {
2489 if (l->end < lock->start)
2490 goto skip;
2491 if (lock->end < l->start)
2492 break;
2493 if (lock->start <= l->start && l->end <= lock->end)
2494 goto delete;
2495 if (l->end <= lock->end) {
2496 l->end = lock->start - 1;
2497 goto skip;
2498 }
2499 if (lock->start <= l->start) {
2500 l->start = lock->end + 1;
2501 break;
2502 }
2503 *newl2 = *l;
2504 newl2->start = lock->end + 1;
2505 l->end = lock->start - 1;
2506 insert_lock(&l->next, newl2);
2507 newl2 = NULL;
2508 }
2509 skip:
2510 lp = &l->next;
2511 continue;
2512
2513 delete:
2514 delete_lock(lp);
2515 }
2516 if (lock->type != F_UNLCK) {
2517 *newl1 = *lock;
2518 insert_lock(lp, newl1);
2519 newl1 = NULL;
2520 }
2521out:
2522 free(newl1);
2523 free(newl2);
2524 return 0;
2525}
2526
2527static void flock_to_lock(struct flock *flock, struct lock *lock)
2528{
2529 memset(lock, 0, sizeof(struct lock));
2530 lock->type = flock->l_type;
2531 lock->start = flock->l_start;
2532 lock->end = flock->l_len ? flock->l_start + flock->l_len - 1 : OFFSET_MAX;
2533 lock->pid = flock->l_pid;
2534}
2535
2536static void lock_to_flock(struct lock *lock, struct flock *flock)
2537{
2538 flock->l_type = lock->type;
2539 flock->l_start = lock->start;
2540 flock->l_len = (lock->end == OFFSET_MAX) ? 0 : lock->end - lock->start + 1;
2541 flock->l_pid = lock->pid;
2542}
2543
Miklos Szeredi6353dca2007-05-11 09:19:36 +00002544static int fuse_flush_common(struct fuse *f, fuse_req_t req, fuse_ino_t ino,
2545 const char *path, struct fuse_file_info *fi)
Csaba Henk79b9e9f2007-05-10 22:56:46 +00002546{
Csaba Henk79b9e9f2007-05-10 22:56:46 +00002547 struct fuse_intr_data d;
2548 struct flock lock;
2549 struct lock l;
Miklos Szeredi0c59ebf2006-09-10 20:53:36 +00002550 int err;
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002551 int errlock;
Miklos Szeredi0c59ebf2006-09-10 20:53:36 +00002552
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002553 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredi6353dca2007-05-11 09:19:36 +00002554 memset(&lock, 0, sizeof(lock));
2555 lock.l_type = F_UNLCK;
2556 lock.l_whence = SEEK_SET;
2557 err = fuse_fs_flush(f->fs, path, fi);
2558 errlock = fuse_fs_lock(f->fs, path, fi, F_SETLK, &lock);
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002559 fuse_finish_interrupt(f, req, &d);
Miklos Szeredi6353dca2007-05-11 09:19:36 +00002560
Csaba Henk79b9e9f2007-05-10 22:56:46 +00002561 if (errlock != -ENOSYS) {
Miklos Szeredi0c59ebf2006-09-10 20:53:36 +00002562 flock_to_lock(&lock, &l);
Miklos Szeredi07407852006-09-30 20:03:52 +00002563 l.owner = fi->lock_owner;
Miklos Szeredi0c59ebf2006-09-10 20:53:36 +00002564 pthread_mutex_lock(&f->lock);
2565 locks_insert(get_node(f, ino), &l);
2566 pthread_mutex_unlock(&f->lock);
2567
2568 /* if op.lock() is defined FLUSH is needed regardless of op.flush() */
2569 if (err == -ENOSYS)
2570 err = 0;
2571 }
Miklos Szeredi6353dca2007-05-11 09:19:36 +00002572 return err;
2573}
2574
2575static void fuse_lib_release(fuse_req_t req, fuse_ino_t ino,
2576 struct fuse_file_info *fi)
2577{
2578 struct fuse *f = req_fuse_prepare(req);
2579 struct fuse_intr_data d;
2580 char *path;
2581 int err = 0;
2582
2583 pthread_rwlock_rdlock(&f->tree_lock);
2584 path = get_path(f, ino);
Miklos Szeredi1f35c652007-06-18 14:27:47 +00002585 if (f->conf.debug)
2586 fprintf(stderr, "RELEASE%s[%llu] flags: 0x%x\n",
2587 fi->flush ? "+FLUSH" : "",
2588 (unsigned long long) fi->fh, fi->flags);
Miklos Szeredi6353dca2007-05-11 09:19:36 +00002589
2590 if (fi->flush) {
2591 err = fuse_flush_common(f, req, ino, path, fi);
2592 if (err == -ENOSYS)
2593 err = 0;
2594 }
2595
2596 fuse_prepare_interrupt(f, req, &d);
2597 fuse_do_release(f, ino, path, fi);
2598 fuse_finish_interrupt(f, req, &d);
2599 free(path);
2600 pthread_rwlock_unlock(&f->tree_lock);
2601
2602 reply_err(req, err);
2603}
2604
2605static void fuse_lib_flush(fuse_req_t req, fuse_ino_t ino,
2606 struct fuse_file_info *fi)
2607{
2608 struct fuse *f = req_fuse_prepare(req);
2609 char *path;
2610 int err;
2611
2612 pthread_rwlock_rdlock(&f->tree_lock);
2613 path = get_path(f, ino);
Miklos Szeredi1f35c652007-06-18 14:27:47 +00002614 if (path && f->conf.debug)
2615 fprintf(stderr, "FLUSH[%llu]\n", (unsigned long long) fi->fh);
Miklos Szeredi6353dca2007-05-11 09:19:36 +00002616 err = fuse_flush_common(f, req, ino, path, fi);
2617 free(path);
Miklos Szeredi0c59ebf2006-09-10 20:53:36 +00002618 pthread_rwlock_unlock(&f->tree_lock);
2619 reply_err(req, err);
2620}
2621
Miklos Szeredi9a5c11d2006-07-30 17:33:40 +00002622static int fuse_lock_common(fuse_req_t req, fuse_ino_t ino,
2623 struct fuse_file_info *fi, struct flock *lock,
Miklos Szeredi07407852006-09-30 20:03:52 +00002624 int cmd)
Miklos Szeredi9a5c11d2006-07-30 17:33:40 +00002625{
2626 struct fuse *f = req_fuse_prepare(req);
2627 char *path;
2628 int err;
2629
2630 err = -ENOENT;
2631 pthread_rwlock_rdlock(&f->tree_lock);
2632 path = get_path(f, ino);
2633 if (path != NULL) {
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002634 struct fuse_intr_data d;
2635 fuse_prepare_interrupt(f, req, &d);
2636 err = fuse_fs_lock(f->fs, path, fi, cmd, lock);
2637 fuse_finish_interrupt(f, req, &d);
Miklos Szeredi9a5c11d2006-07-30 17:33:40 +00002638 free(path);
2639 }
2640 pthread_rwlock_unlock(&f->tree_lock);
2641 return err;
2642}
2643
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002644static void fuse_lib_getlk(fuse_req_t req, fuse_ino_t ino,
2645 struct fuse_file_info *fi, struct flock *lock)
Miklos Szeredi9a5c11d2006-07-30 17:33:40 +00002646{
Miklos Szeredi0c59ebf2006-09-10 20:53:36 +00002647 int err;
2648 struct lock l;
2649 struct lock *conflict;
2650 struct fuse *f = req_fuse(req);
2651
2652 flock_to_lock(lock, &l);
Miklos Szeredi07407852006-09-30 20:03:52 +00002653 l.owner = fi->lock_owner;
Miklos Szeredi0c59ebf2006-09-10 20:53:36 +00002654 pthread_mutex_lock(&f->lock);
2655 conflict = locks_conflict(get_node(f, ino), &l);
2656 if (conflict)
2657 lock_to_flock(conflict, lock);
2658 pthread_mutex_unlock(&f->lock);
2659 if (!conflict)
Miklos Szeredi07407852006-09-30 20:03:52 +00002660 err = fuse_lock_common(req, ino, fi, lock, F_GETLK);
Miklos Szeredi0c59ebf2006-09-10 20:53:36 +00002661 else
2662 err = 0;
2663
Miklos Szeredi9a5c11d2006-07-30 17:33:40 +00002664 if (!err)
2665 fuse_reply_lock(req, lock);
2666 else
2667 reply_err(req, err);
2668}
2669
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002670static void fuse_lib_setlk(fuse_req_t req, fuse_ino_t ino,
2671 struct fuse_file_info *fi, struct flock *lock,
2672 int sleep)
Miklos Szeredi9a5c11d2006-07-30 17:33:40 +00002673{
Miklos Szeredi07407852006-09-30 20:03:52 +00002674 int err = fuse_lock_common(req, ino, fi, lock, sleep ? F_SETLKW : F_SETLK);
Miklos Szeredi0c59ebf2006-09-10 20:53:36 +00002675 if (!err) {
2676 struct fuse *f = req_fuse(req);
2677 struct lock l;
2678 flock_to_lock(lock, &l);
Miklos Szeredi07407852006-09-30 20:03:52 +00002679 l.owner = fi->lock_owner;
Miklos Szeredi0c59ebf2006-09-10 20:53:36 +00002680 pthread_mutex_lock(&f->lock);
2681 locks_insert(get_node(f, ino), &l);
2682 pthread_mutex_unlock(&f->lock);
2683 }
2684 reply_err(req, err);
Miklos Szeredi9a5c11d2006-07-30 17:33:40 +00002685}
2686
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002687static void fuse_lib_bmap(fuse_req_t req, fuse_ino_t ino, size_t blocksize,
2688 uint64_t idx)
Miklos Szeredi708b4812006-09-30 16:02:25 +00002689{
2690 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002691 struct fuse_intr_data d;
Miklos Szeredi708b4812006-09-30 16:02:25 +00002692 char *path;
2693 int err;
2694
2695 err = -ENOENT;
2696 pthread_rwlock_rdlock(&f->tree_lock);
2697 path = get_path(f, ino);
2698 if (path != NULL) {
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002699 fuse_prepare_interrupt(f, req, &d);
2700 err = fuse_fs_bmap(f->fs, path, blocksize, &idx);
2701 fuse_finish_interrupt(f, req, &d);
Miklos Szeredi708b4812006-09-30 16:02:25 +00002702 free(path);
2703 }
2704 pthread_rwlock_unlock(&f->tree_lock);
2705 if (!err)
2706 fuse_reply_bmap(req, idx);
2707 else
2708 reply_err(req, err);
2709}
2710
Miklos Szeredia1482422005-08-14 23:00:27 +00002711static struct fuse_lowlevel_ops fuse_path_ops = {
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002712 .init = fuse_lib_init,
2713 .destroy = fuse_lib_destroy,
2714 .lookup = fuse_lib_lookup,
2715 .forget = fuse_lib_forget,
2716 .getattr = fuse_lib_getattr,
2717 .setattr = fuse_lib_setattr,
2718 .access = fuse_lib_access,
2719 .readlink = fuse_lib_readlink,
2720 .mknod = fuse_lib_mknod,
2721 .mkdir = fuse_lib_mkdir,
2722 .unlink = fuse_lib_unlink,
2723 .rmdir = fuse_lib_rmdir,
2724 .symlink = fuse_lib_symlink,
2725 .rename = fuse_lib_rename,
2726 .link = fuse_lib_link,
2727 .create = fuse_lib_create,
2728 .open = fuse_lib_open,
2729 .read = fuse_lib_read,
2730 .write = fuse_lib_write,
2731 .flush = fuse_lib_flush,
2732 .release = fuse_lib_release,
2733 .fsync = fuse_lib_fsync,
2734 .opendir = fuse_lib_opendir,
2735 .readdir = fuse_lib_readdir,
2736 .releasedir = fuse_lib_releasedir,
2737 .fsyncdir = fuse_lib_fsyncdir,
2738 .statfs = fuse_lib_statfs,
2739 .setxattr = fuse_lib_setxattr,
2740 .getxattr = fuse_lib_getxattr,
2741 .listxattr = fuse_lib_listxattr,
2742 .removexattr = fuse_lib_removexattr,
2743 .getlk = fuse_lib_getlk,
2744 .setlk = fuse_lib_setlk,
2745 .bmap = fuse_lib_bmap,
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002746};
2747
Miklos Szeredia1482422005-08-14 23:00:27 +00002748static void free_cmd(struct fuse_cmd *cmd)
2749{
2750 free(cmd->buf);
2751 free(cmd);
2752}
2753
Miklos Szeredif458b8c2004-12-07 16:46:42 +00002754void fuse_process_cmd(struct fuse *f, struct fuse_cmd *cmd)
Miklos Szeredia181e612001-11-06 12:03:23 +00002755{
Miklos Szeredi178451d2005-08-15 13:19:07 +00002756 fuse_session_process(f->se, cmd->buf, cmd->buflen, cmd->ch);
Miklos Szeredifa829b52005-12-02 11:05:41 +00002757 free_cmd(cmd);
Miklos Szeredia181e612001-11-06 12:03:23 +00002758}
2759
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002760int fuse_exited(struct fuse *f)
Miklos Szeredi65cf7c72004-06-30 11:34:56 +00002761{
Miklos Szeredia1482422005-08-14 23:00:27 +00002762 return fuse_session_exited(f->se);
2763}
2764
2765struct fuse_session *fuse_get_session(struct fuse *f)
2766{
2767 return f->se;
2768}
2769
2770static struct fuse_cmd *fuse_alloc_cmd(size_t bufsize)
2771{
2772 struct fuse_cmd *cmd = (struct fuse_cmd *) malloc(sizeof(*cmd));
2773 if (cmd == NULL) {
2774 fprintf(stderr, "fuse: failed to allocate cmd\n");
2775 return NULL;
2776 }
2777 cmd->buf = (char *) malloc(bufsize);
2778 if (cmd->buf == NULL) {
2779 fprintf(stderr, "fuse: failed to allocate read buffer\n");
2780 free(cmd);
2781 return NULL;
2782 }
2783 return cmd;
Miklos Szeredi65cf7c72004-06-30 11:34:56 +00002784}
2785
Miklos Szeredif458b8c2004-12-07 16:46:42 +00002786struct fuse_cmd *fuse_read_cmd(struct fuse *f)
Miklos Szeredi2df1c042001-11-06 15:07:17 +00002787{
Miklos Szeredia1482422005-08-14 23:00:27 +00002788 struct fuse_chan *ch = fuse_session_next_chan(f->se, NULL);
2789 size_t bufsize = fuse_chan_bufsize(ch);
2790 struct fuse_cmd *cmd = fuse_alloc_cmd(bufsize);
2791 if (cmd != NULL) {
Miklos Szeredi8d975f62006-03-17 15:56:05 +00002792 int res = fuse_chan_recv(&ch, cmd->buf, bufsize);
Miklos Szeredia1482422005-08-14 23:00:27 +00002793 if (res <= 0) {
2794 free_cmd(cmd);
Miklos Szeredi5d9ce362006-03-01 12:10:13 +00002795 if (res < 0 && res != -EINTR && res != -EAGAIN)
Miklos Szeredifa829b52005-12-02 11:05:41 +00002796 fuse_exit(f);
Miklos Szeredia1482422005-08-14 23:00:27 +00002797 return NULL;
2798 }
2799 cmd->buflen = res;
Miklos Szeredi178451d2005-08-15 13:19:07 +00002800 cmd->ch = ch;
Miklos Szeredia1482422005-08-14 23:00:27 +00002801 }
2802 return cmd;
Miklos Szeredi2df1c042001-11-06 15:07:17 +00002803}
2804
Miklos Szeredib2cf9562004-09-16 08:42:40 +00002805int fuse_loop(struct fuse *f)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00002806{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002807 if (f)
Miklos Szeredia1482422005-08-14 23:00:27 +00002808 return fuse_session_loop(f->se);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002809 else
Miklos Szeredib2cf9562004-09-16 08:42:40 +00002810 return -1;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00002811}
2812
Miklos Szeredi891b8742004-07-29 09:27:49 +00002813int fuse_invalidate(struct fuse *f, const char *path)
2814{
Miklos Szeredie56818b2004-12-12 11:45:24 +00002815 (void) f;
2816 (void) path;
2817 return -EINVAL;
Miklos Szeredi891b8742004-07-29 09:27:49 +00002818}
2819
Miklos Szeredi0f48a262002-12-05 14:23:01 +00002820void fuse_exit(struct fuse *f)
2821{
Miklos Szeredia1482422005-08-14 23:00:27 +00002822 fuse_session_exit(f->se);
Miklos Szeredi0f48a262002-12-05 14:23:01 +00002823}
2824
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002825struct fuse_context *fuse_get_context(void)
Miklos Szeredi2e50d432001-12-20 12:17:25 +00002826{
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002827 return &fuse_get_context_internal()->ctx;
2828}
2829
2830int fuse_interrupted(void)
2831{
2832 return fuse_req_interrupted(fuse_get_context_internal()->req);
Miklos Szeredid169f312004-09-22 08:48:26 +00002833}
2834
Miklos Szeredif458b8c2004-12-07 16:46:42 +00002835void fuse_set_getcontext_func(struct fuse_context *(*func)(void))
Miklos Szeredid169f312004-09-22 08:48:26 +00002836{
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002837 (void) func;
2838 /* no-op */
Miklos Szeredi2e50d432001-12-20 12:17:25 +00002839}
2840
Miklos Szerediad005972006-01-07 10:14:34 +00002841enum {
2842 KEY_HELP,
Miklos Szerediad005972006-01-07 10:14:34 +00002843};
2844
Miklos Szeredi659743b2005-12-09 17:41:42 +00002845#define FUSE_LIB_OPT(t, p, v) { t, offsetof(struct fuse_config, p), v }
2846
2847static const struct fuse_opt fuse_lib_opts[] = {
Miklos Szerediad005972006-01-07 10:14:34 +00002848 FUSE_OPT_KEY("-h", KEY_HELP),
2849 FUSE_OPT_KEY("--help", KEY_HELP),
Miklos Szeredi065f2222006-01-20 15:15:21 +00002850 FUSE_OPT_KEY("debug", FUSE_OPT_KEY_KEEP),
2851 FUSE_OPT_KEY("-d", FUSE_OPT_KEY_KEEP),
Miklos Szeredi659743b2005-12-09 17:41:42 +00002852 FUSE_LIB_OPT("debug", debug, 1),
Miklos Szeredi95da8602006-01-06 18:29:40 +00002853 FUSE_LIB_OPT("-d", debug, 1),
Miklos Szeredi659743b2005-12-09 17:41:42 +00002854 FUSE_LIB_OPT("hard_remove", hard_remove, 1),
2855 FUSE_LIB_OPT("use_ino", use_ino, 1),
2856 FUSE_LIB_OPT("readdir_ino", readdir_ino, 1),
2857 FUSE_LIB_OPT("direct_io", direct_io, 1),
2858 FUSE_LIB_OPT("kernel_cache", kernel_cache, 1),
Miklos Szeredi320abe42006-01-30 18:14:51 +00002859 FUSE_LIB_OPT("auto_cache", auto_cache, 1),
2860 FUSE_LIB_OPT("noauto_cache", auto_cache, 0),
Miklos Szeredi659743b2005-12-09 17:41:42 +00002861 FUSE_LIB_OPT("umask=", set_mode, 1),
2862 FUSE_LIB_OPT("umask=%o", umask, 0),
2863 FUSE_LIB_OPT("uid=", set_uid, 1),
2864 FUSE_LIB_OPT("uid=%d", uid, 0),
2865 FUSE_LIB_OPT("gid=", set_gid, 1),
2866 FUSE_LIB_OPT("gid=%d", gid, 0),
2867 FUSE_LIB_OPT("entry_timeout=%lf", entry_timeout, 0),
2868 FUSE_LIB_OPT("attr_timeout=%lf", attr_timeout, 0),
Miklos Szeredi6e806e92006-02-16 16:59:39 +00002869 FUSE_LIB_OPT("ac_attr_timeout=%lf", ac_attr_timeout, 0),
2870 FUSE_LIB_OPT("ac_attr_timeout=", ac_attr_timeout_set, 1),
Miklos Szeredi659743b2005-12-09 17:41:42 +00002871 FUSE_LIB_OPT("negative_timeout=%lf", negative_timeout, 0),
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002872 FUSE_LIB_OPT("intr", intr, 1),
2873 FUSE_LIB_OPT("intr_signal=%d", intr_signal, 0),
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002874 FUSE_LIB_OPT("modules=%s", modules, 0),
Miklos Szeredi659743b2005-12-09 17:41:42 +00002875 FUSE_OPT_END
2876};
2877
Miklos Szerediad005972006-01-07 10:14:34 +00002878static void fuse_lib_help(void)
2879{
2880 fprintf(stderr,
Miklos Szeredi06091462006-02-16 16:38:34 +00002881" -o hard_remove immediate removal (don't hide files)\n"
2882" -o use_ino let filesystem set inode numbers\n"
2883" -o readdir_ino try to fill in d_ino in readdir\n"
2884" -o direct_io use direct I/O\n"
2885" -o kernel_cache cache files in kernel\n"
2886" -o [no]auto_cache enable caching based on modification times\n"
2887" -o umask=M set file permissions (octal)\n"
2888" -o uid=N set file owner\n"
2889" -o gid=N set file group\n"
2890" -o entry_timeout=T cache timeout for names (1.0s)\n"
2891" -o negative_timeout=T cache timeout for deleted names (0.0s)\n"
Miklos Szeredi6e806e92006-02-16 16:59:39 +00002892" -o attr_timeout=T cache timeout for attributes (1.0s)\n"
2893" -o ac_attr_timeout=T auto cache timeout for attributes (attr_timeout)\n"
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002894" -o intr allow requests to be interrupted\n"
2895" -o intr_signal=NUM signal to send on interrupt (%i)\n"
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002896" -o modules=M1[:M2...] names of modules to push onto filesystem stack\n"
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002897"\n", FUSE_DEFAULT_INTR_SIGNAL);
Miklos Szerediad005972006-01-07 10:14:34 +00002898}
2899
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002900static void fuse_lib_help_modules(void)
2901{
2902 struct fuse_module *m;
2903 fprintf(stderr, "\nModule options:\n");
2904 pthread_mutex_lock(&fuse_context_lock);
2905 for (m = fuse_modules; m; m = m->next) {
2906 struct fuse_fs *fs = NULL;
2907 struct fuse_fs *newfs;
2908 struct fuse_args args = FUSE_ARGS_INIT(0, NULL);
2909 if (fuse_opt_add_arg(&args, "") != -1 &&
2910 fuse_opt_add_arg(&args, "-h") != -1) {
2911 fprintf(stderr, "\n[%s]\n", m->name);
2912 newfs = m->factory(&args, &fs);
2913 assert(newfs == NULL);
2914 }
2915 fuse_opt_free_args(&args);
2916 }
2917 pthread_mutex_unlock(&fuse_context_lock);
2918}
2919
Miklos Szerediad005972006-01-07 10:14:34 +00002920static int fuse_lib_opt_proc(void *data, const char *arg, int key,
2921 struct fuse_args *outargs)
2922{
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002923 (void) arg; (void) outargs;
Miklos Szerediad005972006-01-07 10:14:34 +00002924
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002925 if (key == KEY_HELP) {
2926 struct fuse_config *conf = (struct fuse_config *) data;
Miklos Szerediad005972006-01-07 10:14:34 +00002927 fuse_lib_help();
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002928 conf->help = 1;
2929 }
Miklos Szerediad005972006-01-07 10:14:34 +00002930
2931 return 1;
2932}
2933
Miklos Szeredibd7661b2004-07-23 17:16:29 +00002934int fuse_is_lib_option(const char *opt)
2935{
Miklos Szeredi659743b2005-12-09 17:41:42 +00002936 return fuse_lowlevel_is_lib_option(opt) ||
2937 fuse_opt_match(fuse_lib_opts, opt);
Miklos Szeredibd7661b2004-07-23 17:16:29 +00002938}
2939
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002940static int fuse_init_intr_signal(int signum, int *installed)
2941{
2942 struct sigaction old_sa;
2943
2944 if (sigaction(signum, NULL, &old_sa) == -1) {
2945 perror("fuse: cannot get old signal handler");
2946 return -1;
2947 }
2948
2949 if (old_sa.sa_handler == SIG_DFL) {
2950 struct sigaction sa;
2951
2952 memset(&sa, 0, sizeof(struct sigaction));
2953 sa.sa_handler = fuse_intr_sighandler;
Miklos Szeredi0c59ebf2006-09-10 20:53:36 +00002954 sigemptyset(&sa.sa_mask);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002955
2956 if (sigaction(signum, &sa, NULL) == -1) {
2957 perror("fuse: cannot set interrupt signal handler");
2958 return -1;
2959 }
2960 *installed = 1;
2961 }
2962 return 0;
2963}
2964
Miklos Szeredi349bdda2006-09-07 11:48:16 +00002965static void fuse_restore_intr_signal(int signum)
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002966{
Miklos Szeredi349bdda2006-09-07 11:48:16 +00002967 struct sigaction sa;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002968
Miklos Szeredi349bdda2006-09-07 11:48:16 +00002969 memset(&sa, 0, sizeof(struct sigaction));
2970 sa.sa_handler = SIG_DFL;
2971 sigaction(signum, &sa, NULL);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002972}
2973
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00002974
2975static int fuse_push_module(struct fuse *f, const char *module,
2976 struct fuse_args *args)
2977{
2978 struct fuse_fs *fs[2] = { f->fs, NULL };
2979 struct fuse_fs *newfs;
2980 struct fuse_module *m = fuse_get_module(module);
2981
2982 if (!m)
2983 return -1;
2984
2985 newfs = m->factory(args, fs);
2986 if (!newfs) {
2987 fuse_put_module(m);
2988 return -1;
2989 }
2990 newfs->m = m;
2991 f->fs = newfs;
2992 return 0;
2993}
2994
2995struct fuse_fs *fuse_fs_new(const struct fuse_operations *op, size_t op_size,
2996 void *user_data)
2997{
2998 struct fuse_fs *fs;
2999
3000 if (sizeof(struct fuse_operations) < op_size) {
3001 fprintf(stderr, "fuse: warning: library too old, some operations may not not work\n");
3002 op_size = sizeof(struct fuse_operations);
3003 }
3004
3005 fs = (struct fuse_fs *) calloc(1, sizeof(struct fuse_fs));
3006 if (!fs) {
3007 fprintf(stderr, "fuse: failed to allocate fuse_fs object\n");
3008 return NULL;
3009 }
3010
3011 fs->user_data = user_data;
3012 memcpy(&fs->op, op, op_size);
3013 return fs;
3014}
3015
Miklos Szeredi6f385412006-03-17 15:05:40 +00003016struct fuse *fuse_new_common(struct fuse_chan *ch, struct fuse_args *args,
Miklos Szeredi0b6a0ad2004-12-04 00:40:50 +00003017 const struct fuse_operations *op,
Miklos Szeredi6f385412006-03-17 15:05:40 +00003018 size_t op_size, void *user_data, int compat)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00003019{
Miklos Szeredi97c61e92001-11-07 12:09:43 +00003020 struct fuse *f;
3021 struct node *root;
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00003022 struct fuse_fs *fs;
Miklos Szeredi9a5c11d2006-07-30 17:33:40 +00003023 struct fuse_lowlevel_ops llop = fuse_path_ops;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00003024
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00003025 if (fuse_create_context_key() == -1)
3026 goto out;
3027
Miklos Szeredi97c61e92001-11-07 12:09:43 +00003028 f = (struct fuse *) calloc(1, sizeof(struct fuse));
Miklos Szeredie56818b2004-12-12 11:45:24 +00003029 if (f == NULL) {
3030 fprintf(stderr, "fuse: failed to allocate fuse object\n");
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00003031 goto out_delete_context_key;
Miklos Szeredie56818b2004-12-12 11:45:24 +00003032 }
Miklos Szeredi2df1c042001-11-06 15:07:17 +00003033
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00003034 fs = fuse_fs_new(op, op_size, user_data);
3035 if (!fs)
3036 goto out_free;
3037
3038 fs->compat = compat;
3039 f->fs = fs;
3040
3041 /* Oh f**k, this is ugly! */
3042 if (!fs->op.lock) {
3043 llop.getlk = NULL;
3044 llop.setlk = NULL;
3045 }
3046
Miklos Szeredi659743b2005-12-09 17:41:42 +00003047 f->conf.entry_timeout = 1.0;
3048 f->conf.attr_timeout = 1.0;
3049 f->conf.negative_timeout = 0.0;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00003050 f->conf.intr_signal = FUSE_DEFAULT_INTR_SIGNAL;
Miklos Szeredi6c0209a2005-08-02 13:31:28 +00003051
Miklos Szerediad005972006-01-07 10:14:34 +00003052 if (fuse_opt_parse(args, &f->conf, fuse_lib_opts, fuse_lib_opt_proc) == -1)
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00003053 goto out_free_fs;
3054
3055 if (f->conf.modules) {
3056 char *module;
3057 char *next;
3058
3059 for (module = f->conf.modules; module; module = next) {
3060 char *p;
3061 for (p = module; *p && *p != ':'; p++);
3062 next = *p ? p + 1 : NULL;
3063 *p = '\0';
3064 if (module[0] && fuse_push_module(f, module, args) == -1)
3065 goto out_free_fs;
3066 }
3067 }
Miklos Szeredib2cf9562004-09-16 08:42:40 +00003068
Miklos Szeredi6e806e92006-02-16 16:59:39 +00003069 if (!f->conf.ac_attr_timeout_set)
3070 f->conf.ac_attr_timeout = f->conf.attr_timeout;
3071
Miklos Szeredi659743b2005-12-09 17:41:42 +00003072#ifdef __FreeBSD__
3073 /*
3074 * In FreeBSD, we always use these settings as inode numbers are needed to
3075 * make getcwd(3) work.
3076 */
Miklos Szeredi76fc3de2005-12-12 09:34:45 +00003077 f->conf.readdir_ino = 1;
Miklos Szeredi659743b2005-12-09 17:41:42 +00003078#endif
3079
Miklos Szeredi065f2222006-01-20 15:15:21 +00003080 if (compat && compat <= 25) {
3081 if (fuse_sync_compat_args(args) == -1)
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00003082 goto out_free_fs;
Miklos Szeredi9a5c11d2006-07-30 17:33:40 +00003083 }
3084
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00003085 f->se = fuse_lowlevel_new_common(args, &llop, sizeof(llop), f);
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00003086 if (f->se == NULL) {
3087 if (f->conf.help)
3088 fuse_lib_help_modules();
3089 goto out_free_fs;
3090 }
Miklos Szeredi2bb750e2005-10-03 14:54:24 +00003091
Miklos Szeredia1482422005-08-14 23:00:27 +00003092 fuse_session_add_chan(f->se, ch);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00003093
Miklos Szeredi97c61e92001-11-07 12:09:43 +00003094 f->ctr = 0;
Miklos Szeredi76f65782004-02-19 16:55:40 +00003095 f->generation = 0;
Miklos Szeredifff56ab2001-11-16 10:12:59 +00003096 /* FIXME: Dynamic hash table */
Miklos Szeredi97c61e92001-11-07 12:09:43 +00003097 f->name_table_size = 14057;
3098 f->name_table = (struct node **)
3099 calloc(1, sizeof(struct node *) * f->name_table_size);
Miklos Szeredie56818b2004-12-12 11:45:24 +00003100 if (f->name_table == NULL) {
3101 fprintf(stderr, "fuse: memory allocation failed\n");
Miklos Szeredia1482422005-08-14 23:00:27 +00003102 goto out_free_session;
Miklos Szeredie56818b2004-12-12 11:45:24 +00003103 }
Miklos Szeredib2cf9562004-09-16 08:42:40 +00003104
Miklos Szeredia13d9002004-11-02 17:32:03 +00003105 f->id_table_size = 14057;
3106 f->id_table = (struct node **)
3107 calloc(1, sizeof(struct node *) * f->id_table_size);
Miklos Szeredie56818b2004-12-12 11:45:24 +00003108 if (f->id_table == NULL) {
3109 fprintf(stderr, "fuse: memory allocation failed\n");
Miklos Szeredib2cf9562004-09-16 08:42:40 +00003110 goto out_free_name_table;
Miklos Szeredie56818b2004-12-12 11:45:24 +00003111 }
Miklos Szeredib2cf9562004-09-16 08:42:40 +00003112
Miklos Szeredi38f152c2006-09-03 18:28:52 +00003113 fuse_mutex_init(&f->lock);
Miklos Szeredid0a777a2006-04-05 07:18:00 +00003114 pthread_rwlock_init(&f->tree_lock, NULL);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00003115
Miklos Szeredi97c61e92001-11-07 12:09:43 +00003116 root = (struct node *) calloc(1, sizeof(struct node));
Miklos Szeredie56818b2004-12-12 11:45:24 +00003117 if (root == NULL) {
3118 fprintf(stderr, "fuse: memory allocation failed\n");
Miklos Szeredia13d9002004-11-02 17:32:03 +00003119 goto out_free_id_table;
Miklos Szeredie56818b2004-12-12 11:45:24 +00003120 }
Miklos Szeredib2cf9562004-09-16 08:42:40 +00003121
Miklos Szeredi97c61e92001-11-07 12:09:43 +00003122 root->name = strdup("/");
Miklos Szeredie56818b2004-12-12 11:45:24 +00003123 if (root->name == NULL) {
3124 fprintf(stderr, "fuse: memory allocation failed\n");
Miklos Szeredib2cf9562004-09-16 08:42:40 +00003125 goto out_free_root;
Miklos Szeredie56818b2004-12-12 11:45:24 +00003126 }
Miklos Szeredib2cf9562004-09-16 08:42:40 +00003127
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00003128 if (f->conf.intr &&
3129 fuse_init_intr_signal(f->conf.intr_signal, &f->intr_installed) == -1)
3130 goto out_free_root_name;
3131
Miklos Szeredi7bc05b02007-05-29 23:08:11 +00003132 root->parent = NULL;
Miklos Szeredia13d9002004-11-02 17:32:03 +00003133 root->nodeid = FUSE_ROOT_ID;
Miklos Szeredi76f65782004-02-19 16:55:40 +00003134 root->generation = 0;
Miklos Szeredi0f62d722005-01-04 12:45:54 +00003135 root->refctr = 1;
Miklos Szeredi38009022005-05-08 19:47:22 +00003136 root->nlookup = 1;
Miklos Szeredia13d9002004-11-02 17:32:03 +00003137 hash_id(f, root);
Miklos Szeredi97c61e92001-11-07 12:09:43 +00003138
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00003139 return f;
Miklos Szeredib2cf9562004-09-16 08:42:40 +00003140
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00003141 out_free_root_name:
3142 free(root->name);
Miklos Szeredib2cf9562004-09-16 08:42:40 +00003143 out_free_root:
3144 free(root);
Miklos Szeredia13d9002004-11-02 17:32:03 +00003145 out_free_id_table:
3146 free(f->id_table);
Miklos Szeredib2cf9562004-09-16 08:42:40 +00003147 out_free_name_table:
3148 free(f->name_table);
Miklos Szeredia1482422005-08-14 23:00:27 +00003149 out_free_session:
3150 fuse_session_destroy(f->se);
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00003151 out_free_fs:
3152 /* Horrible compatibility hack to stop the destructor from being
3153 called on the filesystem without init being called first */
3154 fs->op.destroy = NULL;
3155 fuse_fs_destroy(f->fs);
Miklos Szeredi37fb19c2007-06-22 20:41:26 +00003156 free(f->conf.modules);
Miklos Szeredib2cf9562004-09-16 08:42:40 +00003157 out_free:
3158 free(f);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00003159 out_delete_context_key:
3160 fuse_delete_context_key();
Miklos Szeredib2cf9562004-09-16 08:42:40 +00003161 out:
Miklos Szeredib2cf9562004-09-16 08:42:40 +00003162 return NULL;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00003163}
3164
Miklos Szeredi6f385412006-03-17 15:05:40 +00003165struct fuse *fuse_new(struct fuse_chan *ch, struct fuse_args *args,
3166 const struct fuse_operations *op, size_t op_size,
3167 void *user_data)
Miklos Szeredi0b6a0ad2004-12-04 00:40:50 +00003168{
Miklos Szeredi6f385412006-03-17 15:05:40 +00003169 return fuse_new_common(ch, args, op, op_size, user_data, 0);
Miklos Szeredi0b6a0ad2004-12-04 00:40:50 +00003170}
3171
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00003172void fuse_destroy(struct fuse *f)
3173{
Miklos Szeredi97c61e92001-11-07 12:09:43 +00003174 size_t i;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00003175
3176 if (f->conf.intr && f->intr_installed)
3177 fuse_restore_intr_signal(f->conf.intr_signal);
Miklos Szerediad519562006-07-31 11:07:40 +00003178
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00003179 if (f->fs) {
3180 struct fuse_context_i *c = fuse_get_context_internal();
Miklos Szerediad519562006-07-31 11:07:40 +00003181
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00003182 memset(c, 0, sizeof(*c));
3183 c->ctx.fuse = f;
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00003184
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00003185 for (i = 0; i < f->id_table_size; i++) {
3186 struct node *node;
3187
3188 for (node = f->id_table[i]; node != NULL; node = node->id_next) {
3189 if (node->is_hidden) {
3190 char *path = get_path(f, node->nodeid);
3191 if (path) {
3192 fuse_fs_unlink(f->fs, path);
3193 free(path);
3194 }
Miklos Szeredi21019c92005-05-09 11:22:41 +00003195 }
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00003196 }
3197 }
3198 }
Miklos Szeredia13d9002004-11-02 17:32:03 +00003199 for (i = 0; i < f->id_table_size; i++) {
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00003200 struct node *node;
Miklos Szeredi97c61e92001-11-07 12:09:43 +00003201 struct node *next;
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00003202
Miklos Szeredia13d9002004-11-02 17:32:03 +00003203 for (node = f->id_table[i]; node != NULL; node = next) {
3204 next = node->id_next;
Miklos Szeredi97c61e92001-11-07 12:09:43 +00003205 free_node(node);
3206 }
3207 }
Miklos Szeredia13d9002004-11-02 17:32:03 +00003208 free(f->id_table);
Miklos Szeredi97c61e92001-11-07 12:09:43 +00003209 free(f->name_table);
Miklos Szeredia181e612001-11-06 12:03:23 +00003210 pthread_mutex_destroy(&f->lock);
Miklos Szeredi55a84102006-06-06 10:16:38 +00003211 pthread_rwlock_destroy(&f->tree_lock);
Miklos Szeredia1482422005-08-14 23:00:27 +00003212 fuse_session_destroy(f->se);
Miklos Szeredi37fb19c2007-06-22 20:41:26 +00003213 free(f->conf.modules);
Miklos Szeredi97c61e92001-11-07 12:09:43 +00003214 free(f);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00003215 fuse_delete_context_key();
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00003216}
Miklos Szeredi0b6a0ad2004-12-04 00:40:50 +00003217
Miklos Szeredi6f385412006-03-17 15:05:40 +00003218static struct fuse *fuse_new_common_compat25(int fd, struct fuse_args *args,
3219 const struct fuse_operations *op,
3220 size_t op_size, int compat)
3221{
3222 struct fuse *f = NULL;
3223 struct fuse_chan *ch = fuse_kern_chan_new(fd);
3224
3225 if (ch)
3226 f = fuse_new_common(ch, args, op, op_size, NULL, compat);
3227
3228 return f;
3229}
3230
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00003231/* called with fuse_context_lock held or during initialization (before
3232 main() has been called) */
3233void fuse_register_module(struct fuse_module *mod)
3234{
Miklos Szeredi2f759e12007-03-14 09:13:27 +00003235 mod->ctr = 0;
Miklos Szeredi3a7c00e2007-02-03 23:32:47 +00003236 mod->so = fuse_current_so;
3237 if (mod->so)
3238 mod->so->ctr++;
3239 mod->next = fuse_modules;
3240 fuse_modules = mod;
3241}
3242
Miklos Szeredi065f2222006-01-20 15:15:21 +00003243#ifndef __FreeBSD__
3244
Miklos Szeredi95da8602006-01-06 18:29:40 +00003245static struct fuse *fuse_new_common_compat(int fd, const char *opts,
3246 const struct fuse_operations *op,
3247 size_t op_size, int compat)
3248{
3249 struct fuse *f;
3250 struct fuse_args args = FUSE_ARGS_INIT(0, NULL);
3251
Miklos Szeredi6e7d0182007-01-19 22:11:40 +00003252 if (fuse_opt_add_arg(&args, "") == -1)
3253 return NULL;
Miklos Szeredi95da8602006-01-06 18:29:40 +00003254 if (opts &&
Miklos Szeredi6e7d0182007-01-19 22:11:40 +00003255 (fuse_opt_add_arg(&args, "-o") == -1 ||
Miklos Szeredi95da8602006-01-06 18:29:40 +00003256 fuse_opt_add_arg(&args, opts) == -1)) {
3257 fuse_opt_free_args(&args);
3258 return NULL;
3259 }
Miklos Szeredi6f385412006-03-17 15:05:40 +00003260 f = fuse_new_common_compat25(fd, &args, op, op_size, compat);
Miklos Szeredi95da8602006-01-06 18:29:40 +00003261 fuse_opt_free_args(&args);
3262
3263 return f;
3264}
3265
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00003266struct fuse *fuse_new_compat22(int fd, const char *opts,
3267 const struct fuse_operations_compat22 *op,
3268 size_t op_size)
3269{
Miklos Szeredi95da8602006-01-06 18:29:40 +00003270 return fuse_new_common_compat(fd, opts, (struct fuse_operations *) op,
3271 op_size, 22);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00003272}
3273
3274struct fuse *fuse_new_compat2(int fd, const char *opts,
3275 const struct fuse_operations_compat2 *op)
3276{
Miklos Szeredi95da8602006-01-06 18:29:40 +00003277 return fuse_new_common_compat(fd, opts, (struct fuse_operations *) op,
3278 sizeof(struct fuse_operations_compat2), 21);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00003279}
3280
3281struct fuse *fuse_new_compat1(int fd, int flags,
3282 const struct fuse_operations_compat1 *op)
3283{
3284 const char *opts = NULL;
3285 if (flags & FUSE_DEBUG_COMPAT1)
3286 opts = "debug";
Miklos Szeredi95da8602006-01-06 18:29:40 +00003287 return fuse_new_common_compat(fd, opts, (struct fuse_operations *) op,
3288 sizeof(struct fuse_operations_compat1), 11);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00003289}
3290
Miklos Szeredif458b8c2004-12-07 16:46:42 +00003291__asm__(".symver fuse_exited,__fuse_exited@");
3292__asm__(".symver fuse_process_cmd,__fuse_process_cmd@");
3293__asm__(".symver fuse_read_cmd,__fuse_read_cmd@");
3294__asm__(".symver fuse_set_getcontext_func,__fuse_set_getcontext_func@");
3295__asm__(".symver fuse_new_compat2,fuse_new@");
Miklos Szeredi3a770472005-11-11 21:32:42 +00003296__asm__(".symver fuse_new_compat22,fuse_new@FUSE_2.2");
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00003297
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00003298#endif /* __FreeBSD__ */
Miklos Szeredi065f2222006-01-20 15:15:21 +00003299
3300struct fuse *fuse_new_compat25(int fd, struct fuse_args *args,
3301 const struct fuse_operations_compat25 *op,
3302 size_t op_size)
3303{
Miklos Szeredi6f385412006-03-17 15:05:40 +00003304 return fuse_new_common_compat25(fd, args, (struct fuse_operations *) op,
3305 op_size, 25);
Miklos Szeredi065f2222006-01-20 15:15:21 +00003306}
3307
3308__asm__(".symver fuse_new_compat25,fuse_new@FUSE_2.5");