blob: 434e40cbadbcc2556feacad96686c99c0deb3965 [file] [log] [blame]
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001/*
2 FUSE: Filesystem in Userspace
Miklos Szeredi95da8602006-01-06 18:29:40 +00003 Copyright (C) 2001-2006 Miklos Szeredi <miklos@szeredi.hu>
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00004
Miklos Szeredi8b39a9f2002-10-25 12:41:16 +00005 This program can be distributed under the terms of the GNU LGPL.
6 See the file COPYING.LIB
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00007*/
8
Miklos Szeredie2aa2e22005-07-15 13:31:36 +00009
10/* For pthread_rwlock_t */
11#define _GNU_SOURCE
12
Miklos Szeredi178451d2005-08-15 13:19:07 +000013#include "fuse_i.h"
Miklos Szeredie2aa2e22005-07-15 13:31:36 +000014#include "fuse_lowlevel.h"
Miklos Szeredi659743b2005-12-09 17:41:42 +000015#include "fuse_opt.h"
Miklos Szeredi38f152c2006-09-03 18:28:52 +000016#include "fuse_misc.h"
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000017
Miklos Szeredi0f62d722005-01-04 12:45:54 +000018#include <stdio.h>
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000019#include <string.h>
Miklos Szeredi97c61e92001-11-07 12:09:43 +000020#include <stdlib.h>
Miklos Szeredi659743b2005-12-09 17:41:42 +000021#include <stddef.h>
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000022#include <unistd.h>
Miklos Szeredi320abe42006-01-30 18:14:51 +000023#include <time.h>
Miklos Szeredib3f99722005-11-16 13:00:24 +000024#include <fcntl.h>
Miklos Szeredi97c61e92001-11-07 12:09:43 +000025#include <limits.h>
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000026#include <errno.h>
Miklos Szeredi288ed4e2006-09-07 06:02:44 +000027#include <signal.h>
Miklos Szeredi0f62d722005-01-04 12:45:54 +000028#include <assert.h>
Miklos Szeredi019b4e92001-12-26 18:08:09 +000029#include <sys/param.h>
Miklos Szerediab974562005-04-07 15:40:21 +000030#include <sys/uio.h>
Miklos Szeredi288ed4e2006-09-07 06:02:44 +000031#include <sys/time.h>
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000032
Miklos Szeredi97c61e92001-11-07 12:09:43 +000033#define FUSE_MAX_PATH 4096
Miklos Szeredi288ed4e2006-09-07 06:02:44 +000034#define FUSE_DEFAULT_INTR_SIGNAL SIGUSR1
Miklos Szeredi30e093a2005-04-03 17:44:54 +000035
Miklos Szeredie248e4b2005-12-14 16:18:32 +000036#define FUSE_UNKNOWN_INO 0xffffffff
37
Miklos Szeredi659743b2005-12-09 17:41:42 +000038struct fuse_config {
Miklos Szeredi659743b2005-12-09 17:41:42 +000039 unsigned int uid;
40 unsigned int gid;
41 unsigned int umask;
42 double entry_timeout;
43 double negative_timeout;
44 double attr_timeout;
Miklos Szeredi6e806e92006-02-16 16:59:39 +000045 double ac_attr_timeout;
46 int ac_attr_timeout_set;
Miklos Szeredi659743b2005-12-09 17:41:42 +000047 int debug;
48 int hard_remove;
49 int use_ino;
50 int readdir_ino;
51 int set_mode;
52 int set_uid;
53 int set_gid;
54 int direct_io;
55 int kernel_cache;
Miklos Szeredi320abe42006-01-30 18:14:51 +000056 int auto_cache;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +000057 int intr;
58 int intr_signal;
Miklos Szeredi659743b2005-12-09 17:41:42 +000059};
60
Miklos Szeredie2aa2e22005-07-15 13:31:36 +000061struct fuse {
Miklos Szeredia1482422005-08-14 23:00:27 +000062 struct fuse_session *se;
Miklos Szeredie2aa2e22005-07-15 13:31:36 +000063 struct fuse_operations op;
64 int compat;
65 struct node **name_table;
66 size_t name_table_size;
67 struct node **id_table;
68 size_t id_table_size;
69 fuse_ino_t ctr;
70 unsigned int generation;
71 unsigned int hidectr;
72 pthread_mutex_t lock;
73 pthread_rwlock_t tree_lock;
74 void *user_data;
Miklos Szeredi659743b2005-12-09 17:41:42 +000075 struct fuse_config conf;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +000076 int intr_installed;
Miklos Szeredie2aa2e22005-07-15 13:31:36 +000077};
78
Miklos Szeredi0f62d722005-01-04 12:45:54 +000079struct node {
80 struct node *name_next;
81 struct node *id_next;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +000082 fuse_ino_t nodeid;
Miklos Szeredi0f62d722005-01-04 12:45:54 +000083 unsigned int generation;
84 int refctr;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +000085 fuse_ino_t parent;
Miklos Szeredi0f62d722005-01-04 12:45:54 +000086 char *name;
Miklos Szeredi38009022005-05-08 19:47:22 +000087 uint64_t nlookup;
Miklos Szeredi0f62d722005-01-04 12:45:54 +000088 int open_count;
89 int is_hidden;
Miklos Szeredi320abe42006-01-30 18:14:51 +000090 struct timespec stat_updated;
91 struct timespec mtime;
92 off_t size;
93 int cache_valid;
Miklos Szeredi0f62d722005-01-04 12:45:54 +000094};
95
96struct fuse_dirhandle {
Miklos Szerediab974562005-04-07 15:40:21 +000097 pthread_mutex_t lock;
Miklos Szeredi0f62d722005-01-04 12:45:54 +000098 struct fuse *fuse;
Miklos Szeredi1bf64f42006-02-17 15:49:25 +000099 fuse_req_t req;
Miklos Szeredi1b188022005-07-28 11:07:29 +0000100 char *contents;
Miklos Szerediab974562005-04-07 15:40:21 +0000101 int allocated;
Miklos Szeredib92d9782005-02-07 16:10:49 +0000102 unsigned len;
Miklos Szeredic4c12ae2005-10-20 14:48:50 +0000103 unsigned size;
Miklos Szerediab974562005-04-07 15:40:21 +0000104 unsigned needlen;
Miklos Szeredi3ead28e2005-01-18 21:23:41 +0000105 int filled;
Miklos Szeredi3a770472005-11-11 21:32:42 +0000106 uint64_t fh;
Miklos Szerediab974562005-04-07 15:40:21 +0000107 int error;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000108 fuse_ino_t nodeid;
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000109};
110
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000111struct fuse_context_i {
112 struct fuse_context ctx;
113 fuse_req_t req;
114};
Miklos Szeredid169f312004-09-22 08:48:26 +0000115
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000116static pthread_key_t fuse_context_key;
117static pthread_mutex_t fuse_context_lock = PTHREAD_MUTEX_INITIALIZER;
118static int fuse_context_ref;
119
120static int fuse_compat_open(struct fuse *, fuse_req_t, char *,
121 struct fuse_file_info *);
122static void fuse_compat_release(struct fuse *, fuse_req_t, char *,
123 struct fuse_file_info *);
124static int fuse_compat_opendir(struct fuse *, fuse_req_t, char *,
125 struct fuse_file_info *);
126static int fuse_compat_statfs(struct fuse *, fuse_req_t, struct statvfs *);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +0000127
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000128static struct node *get_node_nocheck(struct fuse *f, fuse_ino_t nodeid)
Miklos Szeredia181e612001-11-06 12:03:23 +0000129{
Miklos Szeredia13d9002004-11-02 17:32:03 +0000130 size_t hash = nodeid % f->id_table_size;
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000131 struct node *node;
132
Miklos Szeredia13d9002004-11-02 17:32:03 +0000133 for (node = f->id_table[hash]; node != NULL; node = node->id_next)
134 if (node->nodeid == nodeid)
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000135 return node;
Miklos Szeredie5183742005-02-02 11:14:04 +0000136
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000137 return NULL;
Miklos Szeredia181e612001-11-06 12:03:23 +0000138}
139
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000140static struct node *get_node(struct fuse *f, fuse_ino_t nodeid)
Miklos Szeredia181e612001-11-06 12:03:23 +0000141{
Miklos Szeredif458b8c2004-12-07 16:46:42 +0000142 struct node *node = get_node_nocheck(f, nodeid);
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000143 if (!node) {
Miklos Szeredi3a770472005-11-11 21:32:42 +0000144 fprintf(stderr, "fuse internal error: node %llu not found\n",
145 (unsigned long long) nodeid);
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000146 abort();
147 }
148 return node;
Miklos Szeredia181e612001-11-06 12:03:23 +0000149}
150
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000151static void free_node(struct node *node)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000152{
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000153 free(node->name);
154 free(node);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000155}
156
Miklos Szeredia13d9002004-11-02 17:32:03 +0000157static void unhash_id(struct fuse *f, struct node *node)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000158{
Miklos Szeredia13d9002004-11-02 17:32:03 +0000159 size_t hash = node->nodeid % f->id_table_size;
160 struct node **nodep = &f->id_table[hash];
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000161
Miklos Szeredie5183742005-02-02 11:14:04 +0000162 for (; *nodep != NULL; nodep = &(*nodep)->id_next)
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000163 if (*nodep == node) {
Miklos Szeredia13d9002004-11-02 17:32:03 +0000164 *nodep = node->id_next;
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000165 return;
166 }
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000167}
168
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000169static void hash_id(struct fuse *f, struct node *node)
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000170{
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000171 size_t hash = node->nodeid % f->id_table_size;
172 node->id_next = f->id_table[hash];
Miklos Szeredie5183742005-02-02 11:14:04 +0000173 f->id_table[hash] = node;
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000174}
175
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000176static unsigned int name_hash(struct fuse *f, fuse_ino_t parent, const char *name)
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000177{
178 unsigned int hash = *name;
179
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000180 if (hash)
181 for (name += 1; *name != '\0'; name++)
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000182 hash = (hash << 5) - hash + *name;
183
184 return (hash + parent) % f->name_table_size;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000185}
186
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000187static void unref_node(struct fuse *f, struct node *node);
188
189static void unhash_name(struct fuse *f, struct node *node)
190{
191 if (node->name) {
192 size_t hash = name_hash(f, node->parent, node->name);
193 struct node **nodep = &f->name_table[hash];
Miklos Szeredie5183742005-02-02 11:14:04 +0000194
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000195 for (; *nodep != NULL; nodep = &(*nodep)->name_next)
196 if (*nodep == node) {
197 *nodep = node->name_next;
198 node->name_next = NULL;
199 unref_node(f, get_node(f, node->parent));
200 free(node->name);
201 node->name = NULL;
202 node->parent = 0;
203 return;
204 }
Miklos Szeredi3a770472005-11-11 21:32:42 +0000205 fprintf(stderr, "fuse internal error: unable to unhash node: %llu\n",
206 (unsigned long long) node->nodeid);
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000207 abort();
208 }
209}
210
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000211static int hash_name(struct fuse *f, struct node *node, fuse_ino_t parent,
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000212 const char *name)
213{
214 size_t hash = name_hash(f, parent, name);
215 node->name = strdup(name);
216 if (node->name == NULL)
217 return -1;
218
219 get_node(f, parent)->refctr ++;
220 node->parent = parent;
221 node->name_next = f->name_table[hash];
222 f->name_table[hash] = node;
223 return 0;
224}
225
226static void delete_node(struct fuse *f, struct node *node)
227{
Miklos Szeredi659743b2005-12-09 17:41:42 +0000228 if (f->conf.debug) {
Miklos Szeredi3a770472005-11-11 21:32:42 +0000229 printf("delete: %llu\n", (unsigned long long) node->nodeid);
Miklos Szeredi38009022005-05-08 19:47:22 +0000230 fflush(stdout);
231 }
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000232 assert(!node->name);
233 unhash_id(f, node);
234 free_node(node);
235}
236
237static void unref_node(struct fuse *f, struct node *node)
238{
239 assert(node->refctr > 0);
240 node->refctr --;
241 if (!node->refctr)
242 delete_node(f, node);
243}
244
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000245static fuse_ino_t next_id(struct fuse *f)
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000246{
247 do {
248 f->ctr++;
249 if (!f->ctr)
250 f->generation ++;
251 } while (f->ctr == 0 || get_node_nocheck(f, f->ctr) != NULL);
252 return f->ctr;
253}
254
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000255static struct node *lookup_node(struct fuse *f, fuse_ino_t parent,
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000256 const char *name)
257{
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000258 size_t hash = name_hash(f, parent, name);
259 struct node *node;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000260
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000261 for (node = f->name_table[hash]; node != NULL; node = node->name_next)
262 if (node->parent == parent && strcmp(node->name, name) == 0)
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000263 return node;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000264
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000265 return NULL;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000266}
267
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000268static struct node *find_node(struct fuse *f, fuse_ino_t parent,
269 const char *name)
Miklos Szeredi5e183482001-10-31 14:52:35 +0000270{
271 struct node *node;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000272
Miklos Szeredia181e612001-11-06 12:03:23 +0000273 pthread_mutex_lock(&f->lock);
Miklos Szeredif458b8c2004-12-07 16:46:42 +0000274 node = lookup_node(f, parent, name);
Miklos Szeredie331c4b2005-07-06 13:34:02 +0000275 if (node == NULL) {
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000276 node = (struct node *) calloc(1, sizeof(struct node));
277 if (node == NULL)
278 goto out_err;
Miklos Szeredie5183742005-02-02 11:14:04 +0000279
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000280 node->refctr = 1;
281 node->nodeid = next_id(f);
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000282 node->open_count = 0;
283 node->is_hidden = 0;
284 node->generation = f->generation;
285 if (hash_name(f, node, parent, name) == -1) {
286 free(node);
287 node = NULL;
288 goto out_err;
289 }
290 hash_id(f, node);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000291 }
Miklos Szeredi38009022005-05-08 19:47:22 +0000292 node->nlookup ++;
Miklos Szeredic2309912004-09-21 13:40:38 +0000293 out_err:
Miklos Szeredia181e612001-11-06 12:03:23 +0000294 pthread_mutex_unlock(&f->lock);
Miklos Szeredi76f65782004-02-19 16:55:40 +0000295 return node;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000296}
297
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000298static char *add_name(char *buf, char *s, const char *name)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000299{
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000300 size_t len = strlen(name);
301 s -= len;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000302 if (s <= buf) {
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000303 fprintf(stderr, "fuse: path too long: ...%s\n", s + len);
304 return NULL;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000305 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000306 strncpy(s, name, len);
307 s--;
308 *s = '/';
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000309
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000310 return s;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000311}
312
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000313static char *get_path_name(struct fuse *f, fuse_ino_t nodeid, const char *name)
Miklos Szeredib483c932001-10-29 14:57:57 +0000314{
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000315 char buf[FUSE_MAX_PATH];
316 char *s = buf + FUSE_MAX_PATH - 1;
317 struct node *node;
Miklos Szeredie5183742005-02-02 11:14:04 +0000318
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000319 *s = '\0';
Miklos Szeredia181e612001-11-06 12:03:23 +0000320
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000321 if (name != NULL) {
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000322 s = add_name(buf, s, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000323 if (s == NULL)
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000324 return NULL;
325 }
326
327 pthread_mutex_lock(&f->lock);
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000328 for (node = get_node(f, nodeid); node && node->nodeid != FUSE_ROOT_ID;
329 node = get_node(f, node->parent)) {
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000330 if (node->name == NULL) {
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000331 s = NULL;
332 break;
333 }
Miklos Szeredie5183742005-02-02 11:14:04 +0000334
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000335 s = add_name(buf, s, node->name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000336 if (s == NULL)
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000337 break;
338 }
339 pthread_mutex_unlock(&f->lock);
340
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000341 if (node == NULL || s == NULL)
Miklos Szeredi5e183482001-10-31 14:52:35 +0000342 return NULL;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000343 else if (*s == '\0')
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000344 return strdup("/");
345 else
346 return strdup(s);
347}
Miklos Szeredia181e612001-11-06 12:03:23 +0000348
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000349static char *get_path(struct fuse *f, fuse_ino_t nodeid)
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000350{
Miklos Szeredia13d9002004-11-02 17:32:03 +0000351 return get_path_name(f, nodeid, NULL);
Miklos Szeredib483c932001-10-29 14:57:57 +0000352}
353
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000354static void forget_node(struct fuse *f, fuse_ino_t nodeid, uint64_t nlookup)
Miklos Szeredi38009022005-05-08 19:47:22 +0000355{
356 struct node *node;
357 if (nodeid == FUSE_ROOT_ID)
358 return;
359 pthread_mutex_lock(&f->lock);
360 node = get_node(f, nodeid);
361 assert(node->nlookup >= nlookup);
362 node->nlookup -= nlookup;
363 if (!node->nlookup) {
364 unhash_name(f, node);
365 unref_node(f, node);
366 }
367 pthread_mutex_unlock(&f->lock);
368}
369
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000370static void remove_node(struct fuse *f, fuse_ino_t dir, const char *name)
Miklos Szeredi5e183482001-10-31 14:52:35 +0000371{
Miklos Szeredia181e612001-11-06 12:03:23 +0000372 struct node *node;
373
374 pthread_mutex_lock(&f->lock);
Miklos Szeredif458b8c2004-12-07 16:46:42 +0000375 node = lookup_node(f, dir, name);
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000376 if (node != NULL)
377 unhash_name(f, node);
Miklos Szeredia181e612001-11-06 12:03:23 +0000378 pthread_mutex_unlock(&f->lock);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000379}
380
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000381static int rename_node(struct fuse *f, fuse_ino_t olddir, const char *oldname,
382 fuse_ino_t newdir, const char *newname, int hide)
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000383{
Miklos Szeredia181e612001-11-06 12:03:23 +0000384 struct node *node;
385 struct node *newnode;
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000386 int err = 0;
Miklos Szeredie5183742005-02-02 11:14:04 +0000387
Miklos Szeredia181e612001-11-06 12:03:23 +0000388 pthread_mutex_lock(&f->lock);
Miklos Szeredif458b8c2004-12-07 16:46:42 +0000389 node = lookup_node(f, olddir, oldname);
390 newnode = lookup_node(f, newdir, newname);
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000391 if (node == NULL)
392 goto out;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000393
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000394 if (newnode != NULL) {
395 if (hide) {
396 fprintf(stderr, "fuse: hidden file got created during hiding\n");
Miklos Szeredib2cf9562004-09-16 08:42:40 +0000397 err = -EBUSY;
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000398 goto out;
399 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000400 unhash_name(f, newnode);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000401 }
Miklos Szeredie5183742005-02-02 11:14:04 +0000402
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000403 unhash_name(f, node);
Miklos Szeredib2cf9562004-09-16 08:42:40 +0000404 if (hash_name(f, node, newdir, newname) == -1) {
405 err = -ENOMEM;
406 goto out;
407 }
Miklos Szeredie5183742005-02-02 11:14:04 +0000408
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000409 if (hide)
410 node->is_hidden = 1;
411
412 out:
Miklos Szeredia181e612001-11-06 12:03:23 +0000413 pthread_mutex_unlock(&f->lock);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000414 return err;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000415}
416
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000417static void set_stat(struct fuse *f, fuse_ino_t nodeid, struct stat *stbuf)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000418{
Miklos Szeredi659743b2005-12-09 17:41:42 +0000419 if (!f->conf.use_ino)
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000420 stbuf->st_ino = nodeid;
Miklos Szeredi659743b2005-12-09 17:41:42 +0000421 if (f->conf.set_mode)
422 stbuf->st_mode = (stbuf->st_mode & S_IFMT) | (0777 & ~f->conf.umask);
423 if (f->conf.set_uid)
424 stbuf->st_uid = f->conf.uid;
425 if (f->conf.set_gid)
426 stbuf->st_gid = f->conf.gid;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000427}
428
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000429static struct fuse *req_fuse(fuse_req_t req)
430{
431 return (struct fuse *) fuse_req_userdata(req);
432}
433
434static void fuse_intr_sighandler(int sig)
435{
436 (void) sig;
437 /* Nothing to do */
438}
439
440struct fuse_intr_data {
441 pthread_t id;
442 pthread_cond_t cond;
443 int finished;
444};
445
446static void fuse_interrupt(fuse_req_t req, void *d_)
447{
448 struct fuse_intr_data *d = d_;
449 struct fuse *f = req_fuse(req);
450
451 if (d->id == pthread_self())
452 return;
453
454 pthread_mutex_lock(&f->lock);
455 while (!d->finished) {
456 struct timeval now;
457 struct timespec timeout;
458
459 pthread_kill(d->id, f->conf.intr_signal);
460 gettimeofday(&now, NULL);
461 timeout.tv_sec = now.tv_sec + 1;
462 timeout.tv_nsec = now.tv_usec * 1000;
463 pthread_cond_timedwait(&d->cond, &f->lock, &timeout);
464 }
465 pthread_mutex_unlock(&f->lock);
466}
467
468static void fuse_do_finish_interrupt(struct fuse *f, fuse_req_t req,
469 struct fuse_intr_data *d)
470{
471 pthread_mutex_lock(&f->lock);
472 d->finished = 1;
473 pthread_cond_broadcast(&d->cond);
474 pthread_mutex_unlock(&f->lock);
475 fuse_req_interrupt_func(req, NULL, NULL);
476 pthread_cond_destroy(&d->cond);
477}
478
479static void fuse_do_prepare_interrupt(fuse_req_t req, struct fuse_intr_data *d)
480{
481 d->id = pthread_self();
482 pthread_cond_init(&d->cond, NULL);
483 d->finished = 0;
484 fuse_req_interrupt_func(req, fuse_interrupt, d);
485}
486
487static inline void fuse_finish_interrupt(struct fuse *f, fuse_req_t req,
488 struct fuse_intr_data *d)
489{
490 if (f->conf.intr)
491 fuse_do_finish_interrupt(f, req, d);
492}
493
494static inline void fuse_prepare_interrupt(struct fuse *f, fuse_req_t req,
495 struct fuse_intr_data *d)
496{
497 if (f->conf.intr)
498 fuse_do_prepare_interrupt(req, d);
499}
500
501static int fuse_do_getattr(struct fuse *f, fuse_req_t req, const char *path,
502 struct stat *buf)
503{
504 int res;
505 struct fuse_intr_data d;
506 fuse_prepare_interrupt(f, req, &d);
507 res = f->op.getattr(path, buf);
508 fuse_finish_interrupt(f, req, &d);
509 return res;
510}
511
512static int fuse_do_fgetattr(struct fuse *f, fuse_req_t req, const char *path,
513 struct stat *buf, struct fuse_file_info *fi)
514{
515 int res;
516 struct fuse_intr_data d;
517 fuse_prepare_interrupt(f, req, &d);
518 res = f->op.fgetattr(path, buf, fi);
519 fuse_finish_interrupt(f, req, &d);
520 return res;
521}
522
523static int fuse_do_rename(struct fuse *f, fuse_req_t req, const char *oldpath,
524 const char *newpath)
525{
526 int res;
527 struct fuse_intr_data d;
528 fuse_prepare_interrupt(f, req, &d);
529 res = f->op.rename(oldpath, newpath);
530 fuse_finish_interrupt(f, req, &d);
531 return res;
532}
533
534static int fuse_do_unlink(struct fuse *f, fuse_req_t req, const char *path)
535{
536 int res;
537 struct fuse_intr_data d;
538 fuse_prepare_interrupt(f, req, &d);
539 res = f->op.unlink(path);
540 fuse_finish_interrupt(f, req, &d);
541 return res;
542}
543
544static void fuse_do_release(struct fuse *f, fuse_req_t req, const char *path,
545 struct fuse_file_info *fi)
546{
547 struct fuse_intr_data d;
548 fuse_prepare_interrupt(f, req, &d);
549 f->op.release(path, fi);
550 fuse_finish_interrupt(f, req, &d);
551}
552
553static int fuse_do_opendir(struct fuse *f, fuse_req_t req, char *path,
554 struct fuse_file_info *fi)
555{
556 int res;
557 struct fuse_intr_data d;
558 fuse_prepare_interrupt(f, req, &d);
559 res = f->op.opendir(path, fi);
560 fuse_finish_interrupt(f, req, &d);
561 return res;
562}
563
564static int fuse_do_open(struct fuse *f, fuse_req_t req, char *path,
565 struct fuse_file_info *fi)
566{
567 int res;
568 struct fuse_intr_data d;
569 fuse_prepare_interrupt(f, req, &d);
570 res = f->op.open(path, fi);
571 fuse_finish_interrupt(f, req, &d);
572 return res;
573}
574
575static int fuse_do_statfs(struct fuse *f, fuse_req_t req, const char *path,
576 struct statvfs *buf)
577{
578 int res;
579 struct fuse_intr_data d;
580 fuse_prepare_interrupt(f, req, &d);
581 res = f->op.statfs(path, buf);
582 fuse_finish_interrupt(f, req, &d);
583 return res;
584}
585
586static void fuse_do_releasedir(struct fuse *f, fuse_req_t req,
587 const char *path, struct fuse_file_info *fi)
588{
589 struct fuse_intr_data d;
590 fuse_prepare_interrupt(f, req, &d);
591 f->op.releasedir(path, fi);
592 fuse_finish_interrupt(f, req, &d);
593}
594
595static int fuse_do_create(struct fuse *f, fuse_req_t req, const char *path,
596 mode_t mode, struct fuse_file_info *fi)
597{
598 int res;
599 struct fuse_intr_data d;
600 fuse_prepare_interrupt(f, req, &d);
601 res = f->op.create(path, mode, fi);
602 fuse_finish_interrupt(f, req, &d);
603 return res;
604}
605
606static int fuse_do_lock(struct fuse *f, fuse_req_t req, const char *path,
607 struct fuse_file_info *fi, int cmd, struct flock *lock,
608 uint64_t owner)
609{
610 int res;
611 struct fuse_intr_data d;
612 fuse_prepare_interrupt(f, req, &d);
613 res = f->op.lock(path, fi, cmd, lock, owner);
614 fuse_finish_interrupt(f, req, &d);
615 return res;
616}
617
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000618static int is_open(struct fuse *f, fuse_ino_t dir, const char *name)
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000619{
620 struct node *node;
621 int isopen = 0;
622 pthread_mutex_lock(&f->lock);
Miklos Szeredif458b8c2004-12-07 16:46:42 +0000623 node = lookup_node(f, dir, name);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000624 if (node && node->open_count > 0)
625 isopen = 1;
626 pthread_mutex_unlock(&f->lock);
627 return isopen;
628}
629
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000630static char *hidden_name(struct fuse *f, fuse_req_t req, fuse_ino_t dir,
631 const char *oldname, char *newname, size_t bufsize)
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000632{
633 struct stat buf;
634 struct node *node;
635 struct node *newnode;
636 char *newpath;
637 int res;
638 int failctr = 10;
639
640 if (!f->op.getattr)
641 return NULL;
642
643 do {
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000644 pthread_mutex_lock(&f->lock);
Miklos Szeredif458b8c2004-12-07 16:46:42 +0000645 node = lookup_node(f, dir, oldname);
646 if (node == NULL) {
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000647 pthread_mutex_unlock(&f->lock);
648 return NULL;
Miklos Szeredif458b8c2004-12-07 16:46:42 +0000649 }
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000650 do {
651 f->hidectr ++;
652 snprintf(newname, bufsize, ".fuse_hidden%08x%08x",
Miklos Szeredia13d9002004-11-02 17:32:03 +0000653 (unsigned int) node->nodeid, f->hidectr);
Miklos Szeredif458b8c2004-12-07 16:46:42 +0000654 newnode = lookup_node(f, dir, newname);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000655 } while(newnode);
656 pthread_mutex_unlock(&f->lock);
Miklos Szeredie5183742005-02-02 11:14:04 +0000657
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000658 newpath = get_path_name(f, dir, newname);
659 if (!newpath)
660 break;
Miklos Szeredie5183742005-02-02 11:14:04 +0000661
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000662 res = fuse_do_getattr(f, req, newpath, &buf);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000663 if (res != 0)
664 break;
665 free(newpath);
666 newpath = NULL;
667 } while(--failctr);
668
669 return newpath;
670}
671
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000672static int hide_node(struct fuse *f, fuse_req_t req, const char *oldpath,
673 fuse_ino_t dir, const char *oldname)
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000674{
675 char newname[64];
676 char *newpath;
Miklos Szeredib2cf9562004-09-16 08:42:40 +0000677 int err = -EBUSY;
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000678
Miklos Szeredib2cf9562004-09-16 08:42:40 +0000679 if (f->op.rename && f->op.unlink) {
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000680 newpath = hidden_name(f, req, dir, oldname, newname, sizeof(newname));
Miklos Szeredib2cf9562004-09-16 08:42:40 +0000681 if (newpath) {
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000682 int res = fuse_do_rename(f, req, oldpath, newpath);
Miklos Szeredib2cf9562004-09-16 08:42:40 +0000683 if (res == 0)
684 err = rename_node(f, dir, oldname, dir, newname, 1);
685 free(newpath);
686 }
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000687 }
Miklos Szeredib2cf9562004-09-16 08:42:40 +0000688 return err;
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000689}
690
Miklos Szeredi320abe42006-01-30 18:14:51 +0000691static int mtime_eq(const struct stat *stbuf, const struct timespec *ts)
692{
693 return stbuf->st_mtime == ts->tv_sec
694#ifdef HAVE_STRUCT_STAT_ST_ATIM
695 && stbuf->st_mtim.tv_nsec == ts->tv_nsec
696#endif
697 ;
698}
699
700static void mtime_set(const struct stat *stbuf, struct timespec *ts)
701{
702#ifdef HAVE_STRUCT_STAT_ST_ATIM
703 *ts = stbuf->st_mtim;
704#else
705 ts->tv_sec = stbuf->st_mtime;
706#endif
707}
708
Miklos Szeredi2512aaa2006-05-03 14:54:59 +0000709#ifndef CLOCK_MONOTONIC
710#define CLOCK_MONOTONIC CLOCK_REALTIME
711#endif
712
Miklos Szeredi320abe42006-01-30 18:14:51 +0000713static void curr_time(struct timespec *now)
714{
715 static clockid_t clockid = CLOCK_MONOTONIC;
716 int res = clock_gettime(clockid, now);
717 if (res == -1 && errno == EINVAL) {
718 clockid = CLOCK_REALTIME;
719 res = clock_gettime(clockid, now);
720 }
721 if (res == -1) {
722 perror("fuse: clock_gettime");
723 abort();
724 }
725}
726
727static void update_stat(struct node *node, const struct stat *stbuf)
728{
729 if (node->cache_valid && (!mtime_eq(stbuf, &node->mtime) ||
730 stbuf->st_size != node->size))
731 node->cache_valid = 0;
732 mtime_set(stbuf, &node->mtime);
733 node->size = stbuf->st_size;
734 curr_time(&node->stat_updated);
735}
736
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000737static int lookup_path(struct fuse *f, fuse_req_t req, fuse_ino_t nodeid,
738 const char *name, const char *path,
739 struct fuse_entry_param *e, struct fuse_file_info *fi)
Miklos Szeredi76f65782004-02-19 16:55:40 +0000740{
741 int res;
Miklos Szeredi76f65782004-02-19 16:55:40 +0000742
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000743 memset(e, 0, sizeof(struct fuse_entry_param));
Miklos Szeredif7eec032005-10-28 13:09:50 +0000744 if (fi && f->op.fgetattr)
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000745 res = fuse_do_fgetattr(f, req, path, &e->attr, fi);
Miklos Szeredif7eec032005-10-28 13:09:50 +0000746 else
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000747 res = fuse_do_getattr(f, req, path, &e->attr);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000748 if (res == 0) {
Miklos Szeredi76f65782004-02-19 16:55:40 +0000749 struct node *node;
750
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000751 node = find_node(f, nodeid, name);
Miklos Szeredib2cf9562004-09-16 08:42:40 +0000752 if (node == NULL)
753 res = -ENOMEM;
754 else {
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000755 e->ino = node->nodeid;
756 e->generation = node->generation;
Miklos Szeredi659743b2005-12-09 17:41:42 +0000757 e->entry_timeout = f->conf.entry_timeout;
758 e->attr_timeout = f->conf.attr_timeout;
Miklos Szeredi320abe42006-01-30 18:14:51 +0000759 if (f->conf.auto_cache) {
760 pthread_mutex_lock(&f->lock);
761 update_stat(node, &e->attr);
762 pthread_mutex_unlock(&f->lock);
763 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000764 set_stat(f, e->ino, &e->attr);
Miklos Szeredi659743b2005-12-09 17:41:42 +0000765 if (f->conf.debug) {
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000766 printf(" NODEID: %lu\n", (unsigned long) e->ino);
Miklos Szeredib2cf9562004-09-16 08:42:40 +0000767 fflush(stdout);
768 }
Miklos Szeredi76f65782004-02-19 16:55:40 +0000769 }
770 }
771 return res;
772}
773
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000774static struct fuse_context_i *fuse_get_context_internal(void)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000775{
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000776 struct fuse_context_i *c;
777
778 c = (struct fuse_context_i *) pthread_getspecific(fuse_context_key);
779 if (c == NULL) {
780 c = (struct fuse_context_i *) malloc(sizeof(struct fuse_context_i));
781 if (c == NULL) {
782 /* This is hard to deal with properly, so just abort. If
783 memory is so low that the context cannot be allocated,
784 there's not much hope for the filesystem anyway */
785 fprintf(stderr, "fuse: failed to allocate thread specific data\n");
786 abort();
787 }
788 pthread_setspecific(fuse_context_key, c);
789 }
790 return c;
791}
792
793static void fuse_freecontext(void *data)
794{
795 free(data);
796}
797
798static int fuse_create_context_key(void)
799{
800 int err = 0;
801 pthread_mutex_lock(&fuse_context_lock);
802 if (!fuse_context_ref) {
803 err = pthread_key_create(&fuse_context_key, fuse_freecontext);
804 if (err) {
805 fprintf(stderr, "fuse: failed to create thread specific key: %s\n",
806 strerror(err));
807 pthread_mutex_unlock(&fuse_context_lock);
808 return -1;
809 }
810 }
811 fuse_context_ref++;
812 pthread_mutex_unlock(&fuse_context_lock);
813 return 0;
814}
815
816static void fuse_delete_context_key(void)
817{
818 pthread_mutex_lock(&fuse_context_lock);
819 fuse_context_ref--;
820 if (!fuse_context_ref) {
821 free(pthread_getspecific(fuse_context_key));
822 pthread_key_delete(fuse_context_key);
823 }
824 pthread_mutex_unlock(&fuse_context_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000825}
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000826
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000827static struct fuse *req_fuse_prepare(fuse_req_t req)
828{
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000829 struct fuse_context_i *c = fuse_get_context_internal();
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000830 const struct fuse_ctx *ctx = fuse_req_ctx(req);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000831 c->req = req;
832 c->ctx.fuse = req_fuse(req);
833 c->ctx.uid = ctx->uid;
834 c->ctx.gid = ctx->gid;
835 c->ctx.pid = ctx->pid;
836 c->ctx.private_data = c->ctx.fuse->user_data;
837 return c->ctx.fuse;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000838}
839
840static inline void reply_err(fuse_req_t req, int err)
841{
842 /* fuse_reply_err() uses non-negated errno values */
843 fuse_reply_err(req, -err);
844}
845
846static void reply_entry(fuse_req_t req, const struct fuse_entry_param *e,
847 int err)
848{
849 if (!err) {
Miklos Szeredib67f2162006-02-20 10:55:33 +0000850 struct fuse *f = req_fuse(req);
Miklos Szeredi9b813af2005-07-21 07:59:37 +0000851 if (fuse_reply_entry(req, e) == -ENOENT)
Miklos Szeredib67f2162006-02-20 10:55:33 +0000852 forget_node(f, e->ino, 1);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000853 } else
854 reply_err(req, err);
855}
856
Miklos Szeredi065f2222006-01-20 15:15:21 +0000857static void fuse_data_init(void *data, struct fuse_conn_info *conn)
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000858{
859 struct fuse *f = (struct fuse *) data;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000860 struct fuse_context_i *c = fuse_get_context_internal();
Miklos Szeredi4f5df5e2005-10-07 12:39:58 +0000861
862 memset(c, 0, sizeof(*c));
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000863 c->ctx.fuse = f;
864 c->ctx.private_data = f->user_data;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000865
866 if (f->op.init)
Miklos Szeredi065f2222006-01-20 15:15:21 +0000867 f->user_data = f->op.init(conn);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000868}
869
870static void fuse_data_destroy(void *data)
871{
872 struct fuse *f = (struct fuse *) data;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000873 struct fuse_context_i *c = fuse_get_context_internal();
Miklos Szeredi4f5df5e2005-10-07 12:39:58 +0000874
875 memset(c, 0, sizeof(*c));
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000876 c->ctx.fuse = f;
877 c->ctx.private_data = f->user_data;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000878
879 if (f->op.destroy)
880 f->op.destroy(f->user_data);
881}
882
883static void fuse_lookup(fuse_req_t req, fuse_ino_t parent, const char *name)
884{
885 struct fuse *f = req_fuse_prepare(req);
886 struct fuse_entry_param e;
887 char *path;
888 int err;
889
890 err = -ENOENT;
Miklos Szeredic2a33ee2005-05-09 13:29:17 +0000891 pthread_rwlock_rdlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000892 path = get_path_name(f, parent, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000893 if (path != NULL) {
Miklos Szeredi659743b2005-12-09 17:41:42 +0000894 if (f->conf.debug) {
Miklos Szeredi6ebe2342002-01-06 21:44:16 +0000895 printf("LOOKUP %s\n", path);
896 fflush(stdout);
897 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000898 err = -ENOSYS;
Miklos Szeredi2b478112005-11-28 13:27:10 +0000899 if (f->op.getattr) {
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000900 err = lookup_path(f, req, parent, name, path, &e, NULL);
Miklos Szeredi659743b2005-12-09 17:41:42 +0000901 if (err == -ENOENT && f->conf.negative_timeout != 0.0) {
Miklos Szeredi2b478112005-11-28 13:27:10 +0000902 e.ino = 0;
Miklos Szeredi659743b2005-12-09 17:41:42 +0000903 e.entry_timeout = f->conf.negative_timeout;
Miklos Szeredi2b478112005-11-28 13:27:10 +0000904 err = 0;
905 }
906 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000907 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000908 }
Miklos Szeredic2a33ee2005-05-09 13:29:17 +0000909 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000910 reply_entry(req, &e, err);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000911}
912
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000913static void fuse_forget(fuse_req_t req, fuse_ino_t ino, unsigned long nlookup)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000914{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000915 struct fuse *f = req_fuse(req);
Miklos Szeredi659743b2005-12-09 17:41:42 +0000916 if (f->conf.debug) {
Miklos Szeredi3a770472005-11-11 21:32:42 +0000917 printf("FORGET %llu/%lu\n", (unsigned long long) ino, nlookup);
Miklos Szeredi43696432001-11-18 19:15:05 +0000918 fflush(stdout);
919 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000920 forget_node(f, ino, nlookup);
921 fuse_reply_none(req);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000922}
923
Miklos Szerediecce1bf2005-08-25 15:19:06 +0000924static void fuse_getattr(fuse_req_t req, fuse_ino_t ino,
925 struct fuse_file_info *fi)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000926{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000927 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000928 struct stat buf;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000929 char *path;
930 int err;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000931
Miklos Szerediecce1bf2005-08-25 15:19:06 +0000932 (void) fi;
Miklos Szeredi16dbf942006-09-02 13:20:40 +0000933 memset(&buf, 0, sizeof(buf));
Miklos Szerediecce1bf2005-08-25 15:19:06 +0000934
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000935 err = -ENOENT;
Miklos Szeredic2a33ee2005-05-09 13:29:17 +0000936 pthread_rwlock_rdlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000937 path = get_path(f, ino);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000938 if (path != NULL) {
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000939 err = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000940 if (f->op.getattr)
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000941 err = fuse_do_getattr(f, req, path, &buf);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000942 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000943 }
Miklos Szeredic2a33ee2005-05-09 13:29:17 +0000944 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000945 if (!err) {
Miklos Szeredi08dab162006-02-01 13:39:15 +0000946 if (f->conf.auto_cache) {
947 pthread_mutex_lock(&f->lock);
948 update_stat(get_node(f, ino), &buf);
949 pthread_mutex_unlock(&f->lock);
950 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000951 set_stat(f, ino, &buf);
Miklos Szeredi659743b2005-12-09 17:41:42 +0000952 fuse_reply_attr(req, &buf, f->conf.attr_timeout);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000953 } else
954 reply_err(req, err);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000955}
956
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000957static int do_chmod(struct fuse *f, fuse_req_t req, const char *path,
958 struct stat *attr)
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000959{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000960 int err;
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000961
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000962 err = -ENOSYS;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000963 if (f->op.chmod) {
964 struct fuse_intr_data d;
965 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000966 err = f->op.chmod(path, attr->st_mode);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000967 fuse_finish_interrupt(f, req, &d);
968 }
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000969
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000970 return err;
Miklos Szeredie5183742005-02-02 11:14:04 +0000971}
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000972
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000973static int do_chown(struct fuse *f, fuse_req_t req, const char *path,
974 struct stat *attr, int valid)
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000975{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000976 int err;
977 uid_t uid = (valid & FUSE_SET_ATTR_UID) ? attr->st_uid : (uid_t) -1;
978 gid_t gid = (valid & FUSE_SET_ATTR_GID) ? attr->st_gid : (gid_t) -1;
Miklos Szeredie5183742005-02-02 11:14:04 +0000979
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000980 err = -ENOSYS;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000981 if (f->op.chown) {
982 struct fuse_intr_data d;
983 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000984 err = f->op.chown(path, uid, gid);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000985 fuse_finish_interrupt(f, req, &d);
986 }
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000987
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000988 return err;
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000989}
990
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000991static int do_truncate(struct fuse *f, fuse_req_t req, const char *path,
992 struct stat *attr, struct fuse_file_info *fi)
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000993{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000994 int err;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000995 struct fuse_intr_data d;
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000996
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000997 err = -ENOSYS;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000998 if (fi && f->op.ftruncate) {
999 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredi11509ce2005-10-26 16:04:04 +00001000 err = f->op.ftruncate(path, attr->st_size, fi);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001001 fuse_finish_interrupt(f, req, &d);
1002 } else if (f->op.truncate) {
1003 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001004 err = f->op.truncate(path, attr->st_size);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001005 fuse_finish_interrupt(f, req, &d);
1006 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001007 return err;
Miklos Szeredif3ea83b2001-11-07 14:55:16 +00001008}
1009
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001010static int do_utimes(struct fuse *f, fuse_req_t req, const char *path,
1011 struct stat *attr)
Miklos Szeredif3ea83b2001-11-07 14:55:16 +00001012{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001013 int err;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001014 struct fuse_intr_data d;
Miklos Szeredifa440772006-09-02 09:51:08 +00001015
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001016 err = -ENOSYS;
Miklos Szeredifa440772006-09-02 09:51:08 +00001017 if (f->op.utimes) {
1018 struct timespec tv[2];
1019 tv[0] = attr->st_atim;
1020 tv[1] = attr->st_mtim;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001021 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredifa440772006-09-02 09:51:08 +00001022 err = f->op.utimes(path, tv);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001023 fuse_finish_interrupt(f, req, &d);
Miklos Szeredifa440772006-09-02 09:51:08 +00001024 } else if (f->op.utime) {
1025 struct utimbuf buf;
1026 buf.actime = attr->st_atime;
1027 buf.modtime = attr->st_mtime;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001028 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001029 err = f->op.utime(path, &buf);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001030 fuse_finish_interrupt(f, req, &d);
Miklos Szeredifa440772006-09-02 09:51:08 +00001031 }
Miklos Szeredif3ea83b2001-11-07 14:55:16 +00001032
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001033 return err;
Miklos Szeredif3ea83b2001-11-07 14:55:16 +00001034}
1035
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001036static void fuse_setattr(fuse_req_t req, fuse_ino_t ino, struct stat *attr,
Miklos Szerediecce1bf2005-08-25 15:19:06 +00001037 int valid, struct fuse_file_info *fi)
Miklos Szeredi5e183482001-10-31 14:52:35 +00001038{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001039 struct fuse *f = req_fuse_prepare(req);
1040 struct stat buf;
Miklos Szeredi5e183482001-10-31 14:52:35 +00001041 char *path;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001042 int err;
Miklos Szeredi5e183482001-10-31 14:52:35 +00001043
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001044 err = -ENOENT;
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001045 pthread_rwlock_rdlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001046 path = get_path(f, ino);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001047 if (path != NULL) {
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001048 err = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001049 if (f->op.getattr) {
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001050 err = 0;
1051 if (!err && (valid & FUSE_SET_ATTR_MODE))
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001052 err = do_chmod(f, req, path, attr);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001053 if (!err && (valid & (FUSE_SET_ATTR_UID | FUSE_SET_ATTR_GID)))
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001054 err = do_chown(f, req, path, attr, valid);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001055 if (!err && (valid & FUSE_SET_ATTR_SIZE))
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001056 err = do_truncate(f, req, path, attr, fi);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001057 if (!err && (valid & (FUSE_SET_ATTR_ATIME | FUSE_SET_ATTR_MTIME)) == (FUSE_SET_ATTR_ATIME | FUSE_SET_ATTR_MTIME))
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001058 err = do_utimes(f, req, path, attr);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001059 if (!err)
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001060 err = fuse_do_getattr(f, req, path, &buf);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001061 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001062 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001063 }
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001064 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001065 if (!err) {
Miklos Szeredi08dab162006-02-01 13:39:15 +00001066 if (f->conf.auto_cache) {
1067 pthread_mutex_lock(&f->lock);
1068 update_stat(get_node(f, ino), &buf);
1069 pthread_mutex_unlock(&f->lock);
1070 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001071 set_stat(f, ino, &buf);
Miklos Szeredi659743b2005-12-09 17:41:42 +00001072 fuse_reply_attr(req, &buf, f->conf.attr_timeout);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001073 } else
1074 reply_err(req, err);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001075}
1076
Miklos Szeredib0b13d12005-10-26 12:53:25 +00001077static void fuse_access(fuse_req_t req, fuse_ino_t ino, int mask)
1078{
1079 struct fuse *f = req_fuse_prepare(req);
1080 char *path;
1081 int err;
1082
1083 err = -ENOENT;
1084 pthread_rwlock_rdlock(&f->tree_lock);
1085 path = get_path(f, ino);
1086 if (path != NULL) {
Miklos Szeredi659743b2005-12-09 17:41:42 +00001087 if (f->conf.debug) {
Miklos Szeredib0b13d12005-10-26 12:53:25 +00001088 printf("ACCESS %s 0%o\n", path, mask);
1089 fflush(stdout);
1090 }
1091 err = -ENOSYS;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001092 if (f->op.access) {
1093 struct fuse_intr_data d;
1094 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredib0b13d12005-10-26 12:53:25 +00001095 err = f->op.access(path, mask);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001096 fuse_finish_interrupt(f, req, &d);
1097 }
Miklos Szeredib0b13d12005-10-26 12:53:25 +00001098 free(path);
1099 }
1100 pthread_rwlock_unlock(&f->tree_lock);
1101 reply_err(req, err);
1102}
1103
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001104static void fuse_readlink(fuse_req_t req, fuse_ino_t ino)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001105{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001106 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredif6e0ec62005-08-03 09:11:06 +00001107 char linkname[PATH_MAX + 1];
Miklos Szeredib483c932001-10-29 14:57:57 +00001108 char *path;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001109 int err;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001110
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001111 err = -ENOENT;
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001112 pthread_rwlock_rdlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001113 path = get_path(f, ino);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001114 if (path != NULL) {
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001115 err = -ENOSYS;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001116 if (f->op.readlink) {
1117 struct fuse_intr_data d;
1118 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredif6e0ec62005-08-03 09:11:06 +00001119 err = f->op.readlink(path, linkname, sizeof(linkname));
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001120 fuse_finish_interrupt(f, req, &d);
1121 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001122 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001123 }
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001124 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001125 if (!err) {
Miklos Szeredif6e0ec62005-08-03 09:11:06 +00001126 linkname[PATH_MAX] = '\0';
1127 fuse_reply_readlink(req, linkname);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001128 } else
1129 reply_err(req, err);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001130}
1131
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001132static void fuse_mknod(fuse_req_t req, fuse_ino_t parent, const char *name,
1133 mode_t mode, dev_t rdev)
Miklos Szeredib483c932001-10-29 14:57:57 +00001134{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001135 struct fuse *f = req_fuse_prepare(req);
1136 struct fuse_entry_param e;
Miklos Szeredib483c932001-10-29 14:57:57 +00001137 char *path;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001138 int err;
Miklos Szeredib483c932001-10-29 14:57:57 +00001139
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001140 err = -ENOENT;
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001141 pthread_rwlock_rdlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001142 path = get_path_name(f, parent, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001143 if (path != NULL) {
Miklos Szeredi659743b2005-12-09 17:41:42 +00001144 if (f->conf.debug) {
Miklos Szeredi76f65782004-02-19 16:55:40 +00001145 printf("MKNOD %s\n", path);
1146 fflush(stdout);
1147 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001148 err = -ENOSYS;
Miklos Szeredib3f99722005-11-16 13:00:24 +00001149 if (S_ISREG(mode) && f->op.create && f->op.getattr) {
1150 struct fuse_file_info fi;
1151
1152 memset(&fi, 0, sizeof(fi));
1153 fi.flags = O_CREAT | O_EXCL | O_WRONLY;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001154 err = fuse_do_create(f, req, path, mode, &fi);
Miklos Szeredib3f99722005-11-16 13:00:24 +00001155 if (!err) {
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001156 err = lookup_path(f, req, parent, name, path, &e, &fi);
Miklos Szeredib3f99722005-11-16 13:00:24 +00001157 if (f->op.release)
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001158 fuse_do_release(f, req, path, &fi);
Miklos Szeredib3f99722005-11-16 13:00:24 +00001159 }
1160 } else if (f->op.mknod && f->op.getattr) {
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001161 struct fuse_intr_data d;
1162 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001163 err = f->op.mknod(path, mode, rdev);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001164 fuse_finish_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001165 if (!err)
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001166 err = lookup_path(f, req, parent, name, path, &e, NULL);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001167 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001168 free(path);
Miklos Szeredib483c932001-10-29 14:57:57 +00001169 }
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001170 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001171 reply_entry(req, &e, err);
Miklos Szeredib483c932001-10-29 14:57:57 +00001172}
1173
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001174static void fuse_mkdir(fuse_req_t req, fuse_ino_t parent, const char *name,
1175 mode_t mode)
Miklos Szeredib483c932001-10-29 14:57:57 +00001176{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001177 struct fuse *f = req_fuse_prepare(req);
1178 struct fuse_entry_param e;
Miklos Szeredib483c932001-10-29 14:57:57 +00001179 char *path;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001180 int err;
Miklos Szeredib483c932001-10-29 14:57:57 +00001181
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001182 err = -ENOENT;
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001183 pthread_rwlock_rdlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001184 path = get_path_name(f, parent, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001185 if (path != NULL) {
Miklos Szeredi659743b2005-12-09 17:41:42 +00001186 if (f->conf.debug) {
Miklos Szeredi76f65782004-02-19 16:55:40 +00001187 printf("MKDIR %s\n", path);
1188 fflush(stdout);
1189 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001190 err = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001191 if (f->op.mkdir && f->op.getattr) {
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001192 struct fuse_intr_data d;
1193 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001194 err = f->op.mkdir(path, mode);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001195 fuse_finish_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001196 if (!err)
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001197 err = lookup_path(f, req, parent, name, path, &e, NULL);
Miklos Szeredi76f65782004-02-19 16:55:40 +00001198 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001199 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001200 }
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001201 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001202 reply_entry(req, &e, err);
Miklos Szeredib483c932001-10-29 14:57:57 +00001203}
1204
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001205static void fuse_unlink(fuse_req_t req, fuse_ino_t parent, const char *name)
Miklos Szeredib483c932001-10-29 14:57:57 +00001206{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001207 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredib483c932001-10-29 14:57:57 +00001208 char *path;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001209 int err;
Miklos Szeredib483c932001-10-29 14:57:57 +00001210
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001211 err = -ENOENT;
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001212 pthread_rwlock_wrlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001213 path = get_path_name(f, parent, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001214 if (path != NULL) {
Miklos Szeredi659743b2005-12-09 17:41:42 +00001215 if (f->conf.debug) {
Miklos Szeredi209f5d02004-07-24 19:56:16 +00001216 printf("UNLINK %s\n", path);
1217 fflush(stdout);
1218 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001219 err = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001220 if (f->op.unlink) {
Miklos Szeredi659743b2005-12-09 17:41:42 +00001221 if (!f->conf.hard_remove && is_open(f, parent, name))
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001222 err = hide_node(f, req, path, parent, name);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001223 else {
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001224 err = fuse_do_unlink(f, req, path);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001225 if (!err)
1226 remove_node(f, parent, name);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001227 }
Miklos Szeredi5e183482001-10-31 14:52:35 +00001228 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001229 free(path);
Miklos Szeredib483c932001-10-29 14:57:57 +00001230 }
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001231 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001232 reply_err(req, err);
Miklos Szeredib5958612004-02-20 14:10:49 +00001233}
1234
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001235static void fuse_rmdir(fuse_req_t req, fuse_ino_t parent, const char *name)
Miklos Szeredib5958612004-02-20 14:10:49 +00001236{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001237 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredib5958612004-02-20 14:10:49 +00001238 char *path;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001239 int err;
Miklos Szeredib5958612004-02-20 14:10:49 +00001240
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001241 err = -ENOENT;
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001242 pthread_rwlock_wrlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001243 path = get_path_name(f, parent, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001244 if (path != NULL) {
Miklos Szeredi659743b2005-12-09 17:41:42 +00001245 if (f->conf.debug) {
Miklos Szeredi209f5d02004-07-24 19:56:16 +00001246 printf("RMDIR %s\n", path);
1247 fflush(stdout);
1248 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001249 err = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001250 if (f->op.rmdir) {
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001251 struct fuse_intr_data d;
1252 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001253 err = f->op.rmdir(path);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001254 fuse_finish_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001255 if (!err)
1256 remove_node(f, parent, name);
Miklos Szeredib5958612004-02-20 14:10:49 +00001257 }
1258 free(path);
1259 }
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001260 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001261 reply_err(req, err);
Miklos Szeredib483c932001-10-29 14:57:57 +00001262}
1263
Miklos Szeredif6e0ec62005-08-03 09:11:06 +00001264static void fuse_symlink(fuse_req_t req, const char *linkname,
1265 fuse_ino_t parent, const char *name)
Miklos Szeredib483c932001-10-29 14:57:57 +00001266{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001267 struct fuse *f = req_fuse_prepare(req);
1268 struct fuse_entry_param e;
Miklos Szeredib483c932001-10-29 14:57:57 +00001269 char *path;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001270 int err;
Miklos Szeredib483c932001-10-29 14:57:57 +00001271
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001272 err = -ENOENT;
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001273 pthread_rwlock_rdlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001274 path = get_path_name(f, parent, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001275 if (path != NULL) {
Miklos Szeredi659743b2005-12-09 17:41:42 +00001276 if (f->conf.debug) {
Miklos Szeredi76f65782004-02-19 16:55:40 +00001277 printf("SYMLINK %s\n", path);
1278 fflush(stdout);
1279 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001280 err = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001281 if (f->op.symlink && f->op.getattr) {
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001282 struct fuse_intr_data d;
1283 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredif6e0ec62005-08-03 09:11:06 +00001284 err = f->op.symlink(linkname, path);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001285 fuse_finish_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001286 if (!err)
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001287 err = lookup_path(f, req, parent, name, path, &e, NULL);
Miklos Szeredi76f65782004-02-19 16:55:40 +00001288 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001289 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001290 }
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001291 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001292 reply_entry(req, &e, err);
Miklos Szeredib483c932001-10-29 14:57:57 +00001293}
1294
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001295static void fuse_rename(fuse_req_t req, fuse_ino_t olddir, const char *oldname,
1296 fuse_ino_t newdir, const char *newname)
Miklos Szeredi19dff1b2001-10-30 15:06:52 +00001297{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001298 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001299 char *oldpath;
1300 char *newpath;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001301 int err;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +00001302
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001303 err = -ENOENT;
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001304 pthread_rwlock_wrlock(&f->tree_lock);
Miklos Szeredia181e612001-11-06 12:03:23 +00001305 oldpath = get_path_name(f, olddir, oldname);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001306 if (oldpath != NULL) {
Miklos Szeredia181e612001-11-06 12:03:23 +00001307 newpath = get_path_name(f, newdir, newname);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001308 if (newpath != NULL) {
Miklos Szeredi659743b2005-12-09 17:41:42 +00001309 if (f->conf.debug) {
Miklos Szeredi209f5d02004-07-24 19:56:16 +00001310 printf("RENAME %s -> %s\n", oldpath, newpath);
1311 fflush(stdout);
1312 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001313 err = -ENOSYS;
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001314 if (f->op.rename) {
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001315 err = 0;
Miklos Szeredi659743b2005-12-09 17:41:42 +00001316 if (!f->conf.hard_remove &&
Miklos Szeredi2529ca22004-07-13 15:36:52 +00001317 is_open(f, newdir, newname))
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001318 err = hide_node(f, req, newpath, newdir, newname);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001319 if (!err) {
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001320 fuse_do_rename(f, req, oldpath, newpath);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001321 if (!err)
1322 err = rename_node(f, olddir, oldname, newdir, newname, 0);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001323 }
1324 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001325 free(newpath);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001326 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001327 free(oldpath);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001328 }
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001329 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001330 reply_err(req, err);
Miklos Szeredi19dff1b2001-10-30 15:06:52 +00001331}
1332
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001333static void fuse_link(fuse_req_t req, fuse_ino_t ino, fuse_ino_t newparent,
1334 const char *newname)
Miklos Szeredi19dff1b2001-10-30 15:06:52 +00001335{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001336 struct fuse *f = req_fuse_prepare(req);
1337 struct fuse_entry_param e;
Miklos Szeredi5e183482001-10-31 14:52:35 +00001338 char *oldpath;
1339 char *newpath;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001340 int err;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +00001341
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001342 err = -ENOENT;
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001343 pthread_rwlock_rdlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001344 oldpath = get_path(f, ino);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001345 if (oldpath != NULL) {
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001346 newpath = get_path_name(f, newparent, newname);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001347 if (newpath != NULL) {
Miklos Szeredi659743b2005-12-09 17:41:42 +00001348 if (f->conf.debug) {
Miklos Szeredi76f65782004-02-19 16:55:40 +00001349 printf("LINK %s\n", newpath);
1350 fflush(stdout);
1351 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001352 err = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001353 if (f->op.link && f->op.getattr) {
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001354 struct fuse_intr_data d;
1355 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001356 err = f->op.link(oldpath, newpath);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001357 fuse_finish_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001358 if (!err)
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001359 err = lookup_path(f, req, newparent, newname, newpath, &e,
1360 NULL);
Miklos Szeredi76f65782004-02-19 16:55:40 +00001361 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001362 free(newpath);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001363 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001364 free(oldpath);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001365 }
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001366 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001367 reply_entry(req, &e, err);
Miklos Szeredi19dff1b2001-10-30 15:06:52 +00001368}
1369
Miklos Szeredid9079a72005-10-26 15:29:06 +00001370static void fuse_create(fuse_req_t req, fuse_ino_t parent, const char *name,
1371 mode_t mode, struct fuse_file_info *fi)
1372{
1373 struct fuse *f = req_fuse_prepare(req);
1374 struct fuse_entry_param e;
1375 char *path;
1376 int err;
1377
1378 err = -ENOENT;
1379 pthread_rwlock_rdlock(&f->tree_lock);
1380 path = get_path_name(f, parent, name);
1381 if (path != NULL) {
1382 err = -ENOSYS;
1383 if (f->op.create && f->op.getattr) {
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001384 err = fuse_do_create(f, req, path, mode, fi);
Miklos Szeredid9079a72005-10-26 15:29:06 +00001385 if (!err) {
Miklos Szeredi659743b2005-12-09 17:41:42 +00001386 if (f->conf.debug) {
Miklos Szeredi3a770472005-11-11 21:32:42 +00001387 printf("CREATE[%llu] flags: 0x%x %s\n",
1388 (unsigned long long) fi->fh, fi->flags, path);
Miklos Szeredid9079a72005-10-26 15:29:06 +00001389 fflush(stdout);
1390 }
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001391 err = lookup_path(f, req, parent, name, path, &e, fi);
Miklos Szeredid9079a72005-10-26 15:29:06 +00001392 if (err) {
1393 if (f->op.release)
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001394 fuse_do_release(f, req, path, fi);
Miklos Szeredid9079a72005-10-26 15:29:06 +00001395 } else if (!S_ISREG(e.attr.st_mode)) {
1396 err = -EIO;
1397 if (f->op.release)
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001398 fuse_do_release(f, req, path, fi);
Miklos Szeredid9079a72005-10-26 15:29:06 +00001399 forget_node(f, e.ino, 1);
1400 }
1401 }
1402 }
1403 }
1404
1405 if (!err) {
Miklos Szeredi659743b2005-12-09 17:41:42 +00001406 if (f->conf.direct_io)
Miklos Szeredid9079a72005-10-26 15:29:06 +00001407 fi->direct_io = 1;
Miklos Szeredi659743b2005-12-09 17:41:42 +00001408 if (f->conf.kernel_cache)
Miklos Szeredid9079a72005-10-26 15:29:06 +00001409 fi->keep_cache = 1;
1410
1411 pthread_mutex_lock(&f->lock);
1412 if (fuse_reply_create(req, &e, fi) == -ENOENT) {
1413 /* The open syscall was interrupted, so it must be cancelled */
1414 if(f->op.release)
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001415 fuse_do_release(f, req, path, fi);
Miklos Szeredid9079a72005-10-26 15:29:06 +00001416 forget_node(f, e.ino, 1);
1417 } else {
1418 struct node *node = get_node(f, e.ino);
1419 node->open_count ++;
1420 }
1421 pthread_mutex_unlock(&f->lock);
1422 } else
1423 reply_err(req, err);
1424
1425 if (path)
1426 free(path);
1427 pthread_rwlock_unlock(&f->tree_lock);
1428}
1429
Miklos Szeredi320abe42006-01-30 18:14:51 +00001430static double diff_timespec(const struct timespec *t1,
1431 const struct timespec *t2)
1432{
1433 return (t1->tv_sec - t2->tv_sec) +
1434 ((double) t1->tv_nsec - (double) t2->tv_nsec) / 1000000000.0;
1435}
1436
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001437static void open_auto_cache(struct fuse *f, fuse_req_t req, fuse_ino_t ino,
1438 const char *path, struct fuse_file_info *fi)
Miklos Szeredi320abe42006-01-30 18:14:51 +00001439{
1440 struct node *node = get_node(f, ino);
Miklos Szeredi08dab162006-02-01 13:39:15 +00001441 if (node->cache_valid) {
1442 struct timespec now;
Miklos Szeredi320abe42006-01-30 18:14:51 +00001443
Miklos Szeredi08dab162006-02-01 13:39:15 +00001444 curr_time(&now);
Miklos Szeredi6e806e92006-02-16 16:59:39 +00001445 if (diff_timespec(&now, &node->stat_updated) > f->conf.ac_attr_timeout) {
Miklos Szeredi08dab162006-02-01 13:39:15 +00001446 struct stat stbuf;
1447 int err;
Miklos Szeredi320abe42006-01-30 18:14:51 +00001448
Miklos Szeredi08dab162006-02-01 13:39:15 +00001449 if (f->op.fgetattr)
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001450 err = fuse_do_fgetattr(f, req, path, &stbuf, fi);
Miklos Szeredi08dab162006-02-01 13:39:15 +00001451 else
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001452 err = fuse_do_getattr(f, req, path, &stbuf);
Miklos Szeredi08dab162006-02-01 13:39:15 +00001453
1454 if (!err)
1455 update_stat(node, &stbuf);
1456 else
1457 node->cache_valid = 0;
1458 }
Miklos Szeredi320abe42006-01-30 18:14:51 +00001459 }
1460 if (node->cache_valid)
1461 fi->keep_cache = 1;
Miklos Szeredi08dab162006-02-01 13:39:15 +00001462
1463 node->cache_valid = 1;
Miklos Szeredi320abe42006-01-30 18:14:51 +00001464}
1465
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001466static void fuse_open(fuse_req_t req, fuse_ino_t ino,
1467 struct fuse_file_info *fi)
Miklos Szeredi5e183482001-10-31 14:52:35 +00001468{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001469 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredi31066bb2005-08-01 14:49:31 +00001470 char *path = NULL;
1471 int err = 0;
Miklos Szeredi5e183482001-10-31 14:52:35 +00001472
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001473 pthread_rwlock_rdlock(&f->tree_lock);
Miklos Szeredi31066bb2005-08-01 14:49:31 +00001474 if (f->op.open) {
1475 err = -ENOENT;
1476 path = get_path(f, ino);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00001477 if (path != NULL)
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001478 err = fuse_compat_open(f, req, path, fi);
Miklos Szeredi40b9a5a2002-12-10 16:09:02 +00001479 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001480 if (!err) {
Miklos Szeredi659743b2005-12-09 17:41:42 +00001481 if (f->conf.debug) {
Miklos Szeredi3a770472005-11-11 21:32:42 +00001482 printf("OPEN[%llu] flags: 0x%x\n", (unsigned long long) fi->fh,
1483 fi->flags);
Miklos Szeredi209f5d02004-07-24 19:56:16 +00001484 fflush(stdout);
1485 }
Miklos Szeredie5183742005-02-02 11:14:04 +00001486
Miklos Szeredi659743b2005-12-09 17:41:42 +00001487 if (f->conf.direct_io)
Miklos Szeredie77cc072005-08-01 11:58:51 +00001488 fi->direct_io = 1;
Miklos Szeredi659743b2005-12-09 17:41:42 +00001489 if (f->conf.kernel_cache)
Miklos Szeredie77cc072005-08-01 11:58:51 +00001490 fi->keep_cache = 1;
1491
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001492 pthread_mutex_lock(&f->lock);
Miklos Szeredi320abe42006-01-30 18:14:51 +00001493 if (f->conf.auto_cache)
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001494 open_auto_cache(f, req, ino, path, fi);
Miklos Szeredi320abe42006-01-30 18:14:51 +00001495
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001496 if (fuse_reply_open(req, fi) == -ENOENT) {
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001497 /* The open syscall was interrupted, so it must be cancelled */
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00001498 if(f->op.release && path != NULL)
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001499 fuse_compat_release(f, req, path, fi);
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001500 } else {
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001501 struct node *node = get_node(f, ino);
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001502 node->open_count ++;
1503 }
Miklos Szeredi73798f92004-07-12 15:55:11 +00001504 pthread_mutex_unlock(&f->lock);
Miklos Szeredi73798f92004-07-12 15:55:11 +00001505 } else
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001506 reply_err(req, err);
Miklos Szeredi73798f92004-07-12 15:55:11 +00001507
Miklos Szeredi9a31cca2004-06-26 21:11:25 +00001508 if (path)
1509 free(path);
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001510 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001511}
1512
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001513static void fuse_read(fuse_req_t req, fuse_ino_t ino, size_t size, off_t off,
1514 struct fuse_file_info *fi)
Miklos Szeredie2e4ac22004-05-18 08:45:28 +00001515{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001516 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredie2e4ac22004-05-18 08:45:28 +00001517 char *path;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001518 char *buf;
Miklos Szeredie2e4ac22004-05-18 08:45:28 +00001519 int res;
1520
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001521 buf = (char *) malloc(size);
1522 if (buf == NULL) {
1523 reply_err(req, -ENOMEM);
1524 return;
1525 }
1526
Miklos Szeredie2e4ac22004-05-18 08:45:28 +00001527 res = -ENOENT;
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001528 pthread_rwlock_rdlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001529 path = get_path(f, ino);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001530 if (path != NULL) {
Miklos Szeredi659743b2005-12-09 17:41:42 +00001531 if (f->conf.debug) {
Miklos Szeredia039f8f2006-02-24 16:21:58 +00001532 printf("READ[%llu] %lu bytes from %llu\n",
1533 (unsigned long long) fi->fh, (unsigned long) size,
1534 (unsigned long long) off);
Miklos Szeredi209f5d02004-07-24 19:56:16 +00001535 fflush(stdout);
1536 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001537
Miklos Szeredie2e4ac22004-05-18 08:45:28 +00001538 res = -ENOSYS;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001539 if (f->op.read) {
1540 struct fuse_intr_data d;
1541 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001542 res = f->op.read(path, buf, size, off, fi);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001543 fuse_finish_interrupt(f, req, &d);
1544 }
Miklos Szeredie2e4ac22004-05-18 08:45:28 +00001545 free(path);
1546 }
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001547 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001548
1549 if (res >= 0) {
Miklos Szeredi659743b2005-12-09 17:41:42 +00001550 if (f->conf.debug) {
Miklos Szeredi3a770472005-11-11 21:32:42 +00001551 printf(" READ[%llu] %u bytes\n", (unsigned long long) fi->fh,
1552 res);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001553 fflush(stdout);
1554 }
Miklos Szeredif412d072005-10-14 21:24:32 +00001555 if ((size_t) res > size)
1556 fprintf(stderr, "fuse: read too many bytes");
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001557 fuse_reply_buf(req, buf, res);
1558 } else
1559 reply_err(req, res);
1560
1561 free(buf);
Miklos Szeredie2e4ac22004-05-18 08:45:28 +00001562}
1563
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001564static void fuse_write(fuse_req_t req, fuse_ino_t ino, const char *buf,
1565 size_t size, off_t off, struct fuse_file_info *fi)
Miklos Szeredic8ba2372002-12-10 12:26:00 +00001566{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001567 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001568 char *path;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001569 int res;
1570
1571 res = -ENOENT;
1572 pthread_rwlock_rdlock(&f->tree_lock);
1573 path = get_path(f, ino);
1574 if (path != NULL) {
Miklos Szeredi659743b2005-12-09 17:41:42 +00001575 if (f->conf.debug) {
Miklos Szeredia039f8f2006-02-24 16:21:58 +00001576 printf("WRITE%s[%llu] %lu bytes to %llu\n",
Miklos Szeredi3a770472005-11-11 21:32:42 +00001577 fi->writepage ? "PAGE" : "", (unsigned long long) fi->fh,
Miklos Szeredia039f8f2006-02-24 16:21:58 +00001578 (unsigned long) size, (unsigned long long) off);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001579 fflush(stdout);
1580 }
1581
1582 res = -ENOSYS;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001583 if (f->op.write) {
1584 struct fuse_intr_data d;
1585 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001586 res = f->op.write(path, buf, size, off, fi);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001587 fuse_finish_interrupt(f, req, &d);
1588 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001589 free(path);
1590 }
1591 pthread_rwlock_unlock(&f->tree_lock);
1592
Miklos Szeredif412d072005-10-14 21:24:32 +00001593 if (res >= 0) {
Miklos Szeredi659743b2005-12-09 17:41:42 +00001594 if (f->conf.debug) {
Miklos Szeredi3a770472005-11-11 21:32:42 +00001595 printf(" WRITE%s[%llu] %u bytes\n",
1596 fi->writepage ? "PAGE" : "", (unsigned long long) fi->fh,
1597 res);
Miklos Szeredif412d072005-10-14 21:24:32 +00001598 fflush(stdout);
1599 }
1600 if ((size_t) res > size)
1601 fprintf(stderr, "fuse: wrote too many bytes");
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001602 fuse_reply_write(req, res);
Miklos Szeredif412d072005-10-14 21:24:32 +00001603 } else
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001604 reply_err(req, res);
1605}
1606
1607static void fuse_flush(fuse_req_t req, fuse_ino_t ino,
Miklos Szeredib052a1a2006-06-28 14:51:20 +00001608 struct fuse_file_info *fi, uint64_t owner)
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001609{
1610 struct fuse *f = req_fuse_prepare(req);
1611 char *path;
1612 int err;
1613
1614 err = -ENOENT;
1615 pthread_rwlock_rdlock(&f->tree_lock);
1616 path = get_path(f, ino);
1617 if (path != NULL) {
Miklos Szeredi659743b2005-12-09 17:41:42 +00001618 if (f->conf.debug) {
Miklos Szeredi3a770472005-11-11 21:32:42 +00001619 printf("FLUSH[%llu]\n", (unsigned long long) fi->fh);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001620 fflush(stdout);
1621 }
1622 err = -ENOSYS;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001623 if (f->op.flush) {
1624 struct fuse_intr_data d;
1625 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001626 err = f->op.flush(path, fi);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001627 fuse_finish_interrupt(f, req, &d);
1628 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001629 free(path);
1630 }
Miklos Szeredi9a5c11d2006-07-30 17:33:40 +00001631 if (f->op.lock) {
1632 struct flock lock;
1633 memset(&lock, 0, sizeof(lock));
1634 lock.l_type = F_UNLCK;
1635 lock.l_whence = SEEK_SET;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001636 fuse_do_lock(f, req, path, fi, F_SETLK, &lock, owner);
Miklos Szeredi9a5c11d2006-07-30 17:33:40 +00001637 if (err == -ENOSYS)
1638 err = 0;
1639 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001640 pthread_rwlock_unlock(&f->tree_lock);
1641 reply_err(req, err);
1642}
1643
1644static void fuse_release(fuse_req_t req, fuse_ino_t ino,
1645 struct fuse_file_info *fi)
1646{
1647 struct fuse *f = req_fuse_prepare(req);
1648 char *path;
1649 struct node *node;
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001650 int unlink_hidden;
Miklos Szeredifb28c5e2004-11-26 12:15:06 +00001651
Miklos Szerediaa8258e2006-02-25 14:42:03 +00001652 pthread_rwlock_rdlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001653 path = get_path(f, ino);
Miklos Szeredi659743b2005-12-09 17:41:42 +00001654 if (f->conf.debug) {
Miklos Szeredi3a770472005-11-11 21:32:42 +00001655 printf("RELEASE[%llu] flags: 0x%x\n", (unsigned long long) fi->fh,
1656 fi->flags);
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001657 fflush(stdout);
Miklos Szeredic8ba2372002-12-10 12:26:00 +00001658 }
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00001659 if (f->op.release)
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001660 fuse_compat_release(f, req, path, fi);
Miklos Szeredie5183742005-02-02 11:14:04 +00001661
Miklos Szeredi9a5c11d2006-07-30 17:33:40 +00001662 pthread_mutex_lock(&f->lock);
1663 node = get_node(f, ino);
1664 assert(node->open_count > 0);
1665 --node->open_count;
1666 unlink_hidden = (node->is_hidden && !node->open_count);
1667 pthread_mutex_unlock(&f->lock);
1668
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001669 if(unlink_hidden && path)
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001670 fuse_do_unlink(f, req, path);
Miklos Szeredie5183742005-02-02 11:14:04 +00001671
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001672 if (path)
1673 free(path);
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001674 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001675
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001676 reply_err(req, 0);
Miklos Szeredic8ba2372002-12-10 12:26:00 +00001677}
1678
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001679static void fuse_fsync(fuse_req_t req, fuse_ino_t ino, int datasync,
1680 struct fuse_file_info *fi)
Miklos Szeredi5e183482001-10-31 14:52:35 +00001681{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001682 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001683 char *path;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001684 int err;
Miklos Szerediab974562005-04-07 15:40:21 +00001685
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001686 err = -ENOENT;
1687 pthread_rwlock_rdlock(&f->tree_lock);
1688 path = get_path(f, ino);
1689 if (path != NULL) {
Miklos Szeredi659743b2005-12-09 17:41:42 +00001690 if (f->conf.debug) {
Miklos Szeredi3a770472005-11-11 21:32:42 +00001691 printf("FSYNC[%llu]\n", (unsigned long long) fi->fh);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001692 fflush(stdout);
1693 }
1694 err = -ENOSYS;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001695 if (f->op.fsync) {
1696 struct fuse_intr_data d;
1697 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001698 err = f->op.fsync(path, datasync, fi);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001699 fuse_finish_interrupt(f, req, &d);
1700 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001701 free(path);
1702 }
1703 pthread_rwlock_unlock(&f->tree_lock);
1704 reply_err(req, err);
1705}
1706
1707static struct fuse_dirhandle *get_dirhandle(const struct fuse_file_info *llfi,
1708 struct fuse_file_info *fi)
1709{
Miklos Szeredi3a770472005-11-11 21:32:42 +00001710 struct fuse_dirhandle *dh = (struct fuse_dirhandle *) (uintptr_t) llfi->fh;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001711 memset(fi, 0, sizeof(struct fuse_file_info));
1712 fi->fh = dh->fh;
Miklos Szerediead7f102005-11-28 16:02:27 +00001713 fi->fh_old = dh->fh;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001714 return dh;
1715}
1716
1717static void fuse_opendir(fuse_req_t req, fuse_ino_t ino,
1718 struct fuse_file_info *llfi)
1719{
1720 struct fuse *f = req_fuse_prepare(req);
1721 struct fuse_dirhandle *dh;
1722
1723 dh = (struct fuse_dirhandle *) malloc(sizeof(struct fuse_dirhandle));
1724 if (dh == NULL) {
1725 reply_err(req, -ENOMEM);
Miklos Szerediab974562005-04-07 15:40:21 +00001726 return;
Miklos Szeredi5e183482001-10-31 14:52:35 +00001727 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001728 memset(dh, 0, sizeof(struct fuse_dirhandle));
1729 dh->fuse = f;
1730 dh->contents = NULL;
1731 dh->len = 0;
1732 dh->filled = 0;
1733 dh->nodeid = ino;
Miklos Szeredi38f152c2006-09-03 18:28:52 +00001734 fuse_mutex_init(&dh->lock);
Miklos Szerediab974562005-04-07 15:40:21 +00001735
Miklos Szeredi3a770472005-11-11 21:32:42 +00001736 llfi->fh = (uintptr_t) dh;
Miklos Szerediab974562005-04-07 15:40:21 +00001737
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001738 if (f->op.opendir) {
1739 struct fuse_file_info fi;
1740 char *path;
1741 int err;
1742
1743 memset(&fi, 0, sizeof(fi));
1744 fi.flags = llfi->flags;
1745
1746 err = -ENOENT;
1747 pthread_rwlock_rdlock(&f->tree_lock);
1748 path = get_path(f, ino);
1749 if (path != NULL) {
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001750 err = fuse_compat_opendir(f, req, path, &fi);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00001751 dh->fh = fi.fh;
Miklos Szerediab974562005-04-07 15:40:21 +00001752 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001753 if (!err) {
1754 pthread_mutex_lock(&f->lock);
1755 if (fuse_reply_open(req, llfi) == -ENOENT) {
1756 /* The opendir syscall was interrupted, so it must be
1757 cancelled */
1758 if(f->op.releasedir)
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001759 fuse_do_releasedir(f, req, path, &fi);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001760 pthread_mutex_destroy(&dh->lock);
1761 free(dh);
1762 }
1763 pthread_mutex_unlock(&f->lock);
1764 } else {
1765 reply_err(req, err);
1766 free(dh);
1767 }
Miklos Szerediab974562005-04-07 15:40:21 +00001768 free(path);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001769 pthread_rwlock_unlock(&f->tree_lock);
1770 } else
1771 fuse_reply_open(req, llfi);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001772}
Miklos Szeredib483c932001-10-29 14:57:57 +00001773
Miklos Szeredi1bf64f42006-02-17 15:49:25 +00001774static int extend_contents(struct fuse_dirhandle *dh, unsigned minsize)
1775{
1776 if (minsize > dh->size) {
1777 char *newptr;
1778 unsigned newsize = dh->size;
1779 if (!newsize)
1780 newsize = 1024;
1781 while (newsize < minsize)
1782 newsize *= 2;
1783
1784 newptr = (char *) realloc(dh->contents, newsize);
1785 if (!newptr) {
1786 dh->error = -ENOMEM;
1787 return -1;
1788 }
1789 dh->contents = newptr;
1790 dh->size = newsize;
1791 }
1792 return 0;
1793}
1794
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001795static int fill_dir_common(struct fuse_dirhandle *dh, const char *name,
Miklos Szeredif6e0ec62005-08-03 09:11:06 +00001796 const struct stat *statp, off_t off)
Miklos Szeredia181e612001-11-06 12:03:23 +00001797{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001798 struct stat stbuf;
Miklos Szeredi1bf64f42006-02-17 15:49:25 +00001799 size_t newlen;
Miklos Szeredifb28c5e2004-11-26 12:15:06 +00001800
Miklos Szeredif6e0ec62005-08-03 09:11:06 +00001801 if (statp)
1802 stbuf = *statp;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001803 else {
1804 memset(&stbuf, 0, sizeof(stbuf));
Miklos Szeredie248e4b2005-12-14 16:18:32 +00001805 stbuf.st_ino = FUSE_UNKNOWN_INO;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001806 }
Miklos Szeredia181e612001-11-06 12:03:23 +00001807
Miklos Szeredi659743b2005-12-09 17:41:42 +00001808 if (!dh->fuse->conf.use_ino) {
Miklos Szeredie248e4b2005-12-14 16:18:32 +00001809 stbuf.st_ino = FUSE_UNKNOWN_INO;
Miklos Szeredi659743b2005-12-09 17:41:42 +00001810 if (dh->fuse->conf.readdir_ino) {
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001811 struct node *node;
1812 pthread_mutex_lock(&dh->fuse->lock);
1813 node = lookup_node(dh->fuse, dh->nodeid, name);
1814 if (node)
1815 stbuf.st_ino = (ino_t) node->nodeid;
1816 pthread_mutex_unlock(&dh->fuse->lock);
Miklos Szeredi6ebe2342002-01-06 21:44:16 +00001817 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001818 }
Miklos Szeredi6ebe2342002-01-06 21:44:16 +00001819
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001820 if (off) {
Miklos Szeredi1bf64f42006-02-17 15:49:25 +00001821 if (extend_contents(dh, dh->needlen) == -1)
1822 return 1;
1823
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001824 dh->filled = 0;
Miklos Szeredi1bf64f42006-02-17 15:49:25 +00001825 newlen = dh->len + fuse_add_direntry(dh->req, dh->contents + dh->len,
1826 dh->needlen - dh->len, name,
1827 &stbuf, off);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001828 if (newlen > dh->needlen)
1829 return 1;
Miklos Szeredi1bf64f42006-02-17 15:49:25 +00001830 } else {
1831 newlen = dh->len + fuse_add_direntry(dh->req, NULL, 0, name, NULL, 0);
1832 if (extend_contents(dh, newlen) == -1)
Miklos Szeredic4c12ae2005-10-20 14:48:50 +00001833 return 1;
Miklos Szeredi1bf64f42006-02-17 15:49:25 +00001834
1835 fuse_add_direntry(dh->req, dh->contents + dh->len, dh->size - dh->len,
1836 name, &stbuf, newlen);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001837 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001838 dh->len = newlen;
1839 return 0;
1840}
1841
Miklos Szeredif6e0ec62005-08-03 09:11:06 +00001842static int fill_dir(void *buf, const char *name, const struct stat *stbuf,
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001843 off_t off)
1844{
Miklos Szeredif6e0ec62005-08-03 09:11:06 +00001845 return fill_dir_common((struct fuse_dirhandle *) buf, name, stbuf, off);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001846}
1847
1848static int fill_dir_old(struct fuse_dirhandle *dh, const char *name, int type,
1849 ino_t ino)
1850{
1851 struct stat stbuf;
1852
1853 memset(&stbuf, 0, sizeof(stbuf));
1854 stbuf.st_mode = type << 12;
1855 stbuf.st_ino = ino;
1856
1857 fill_dir_common(dh, name, &stbuf, 0);
1858 return dh->error;
1859}
1860
Miklos Szeredi1bf64f42006-02-17 15:49:25 +00001861static int readdir_fill(struct fuse *f, fuse_req_t req, fuse_ino_t ino,
1862 size_t size, off_t off, struct fuse_dirhandle *dh,
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001863 struct fuse_file_info *fi)
1864{
1865 int err = -ENOENT;
1866 char *path;
1867 pthread_rwlock_rdlock(&f->tree_lock);
1868 path = get_path(f, ino);
1869 if (path != NULL) {
1870 dh->len = 0;
1871 dh->error = 0;
1872 dh->needlen = size;
1873 dh->filled = 1;
Miklos Szeredi1bf64f42006-02-17 15:49:25 +00001874 dh->req = req;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001875 err = -ENOSYS;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001876 if (f->op.readdir) {
1877 struct fuse_intr_data d;
1878 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001879 err = f->op.readdir(path, dh, fill_dir, off, fi);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001880 fuse_finish_interrupt(f, req, &d);
1881 } else if (f->op.getdir) {
1882 struct fuse_intr_data d;
1883 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001884 err = f->op.getdir(path, dh, fill_dir_old);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001885 fuse_finish_interrupt(f, req, &d);
1886 }
Miklos Szeredi1bf64f42006-02-17 15:49:25 +00001887 dh->req = NULL;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001888 if (!err)
1889 err = dh->error;
1890 if (err)
1891 dh->filled = 0;
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001892 free(path);
Miklos Szeredia181e612001-11-06 12:03:23 +00001893 }
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001894 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001895 return err;
1896}
Miklos Szeredie5183742005-02-02 11:14:04 +00001897
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001898static void fuse_readdir(fuse_req_t req, fuse_ino_t ino, size_t size,
1899 off_t off, struct fuse_file_info *llfi)
1900{
1901 struct fuse *f = req_fuse_prepare(req);
1902 struct fuse_file_info fi;
1903 struct fuse_dirhandle *dh = get_dirhandle(llfi, &fi);
1904
1905 pthread_mutex_lock(&dh->lock);
Miklos Szeredi77ccf652005-08-19 14:40:27 +00001906 /* According to SUS, directory contents need to be refreshed on
1907 rewinddir() */
1908 if (!off)
1909 dh->filled = 0;
1910
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001911 if (!dh->filled) {
Miklos Szeredi1bf64f42006-02-17 15:49:25 +00001912 int err = readdir_fill(f, req, ino, size, off, dh, &fi);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001913 if (err) {
1914 reply_err(req, err);
1915 goto out;
1916 }
Miklos Szeredia181e612001-11-06 12:03:23 +00001917 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001918 if (dh->filled) {
1919 if (off < dh->len) {
1920 if (off + size > dh->len)
1921 size = dh->len - off;
1922 } else
1923 size = 0;
1924 } else {
1925 size = dh->len;
1926 off = 0;
1927 }
1928 fuse_reply_buf(req, dh->contents + off, size);
1929 out:
1930 pthread_mutex_unlock(&dh->lock);
1931}
Miklos Szeredia181e612001-11-06 12:03:23 +00001932
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001933static void fuse_releasedir(fuse_req_t req, fuse_ino_t ino,
1934 struct fuse_file_info *llfi)
1935{
1936 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredi9b813af2005-07-21 07:59:37 +00001937 struct fuse_file_info fi;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001938 struct fuse_dirhandle *dh = get_dirhandle(llfi, &fi);
1939 if (f->op.releasedir) {
1940 char *path;
1941
1942 pthread_rwlock_rdlock(&f->tree_lock);
1943 path = get_path(f, ino);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001944 fuse_do_releasedir(f, req, path ? path : "-", &fi);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001945 free(path);
1946 pthread_rwlock_unlock(&f->tree_lock);
1947 }
1948 pthread_mutex_lock(&dh->lock);
1949 pthread_mutex_unlock(&dh->lock);
1950 pthread_mutex_destroy(&dh->lock);
1951 free(dh->contents);
1952 free(dh);
1953 reply_err(req, 0);
1954}
1955
1956static void fuse_fsyncdir(fuse_req_t req, fuse_ino_t ino, int datasync,
1957 struct fuse_file_info *llfi)
1958{
1959 struct fuse *f = req_fuse_prepare(req);
1960 struct fuse_file_info fi;
1961 char *path;
1962 int err;
1963
1964 get_dirhandle(llfi, &fi);
1965
1966 err = -ENOENT;
1967 pthread_rwlock_rdlock(&f->tree_lock);
1968 path = get_path(f, ino);
1969 if (path != NULL) {
1970 err = -ENOSYS;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001971 if (f->op.fsyncdir) {
1972 struct fuse_intr_data d;
1973 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001974 err = f->op.fsyncdir(path, datasync, &fi);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001975 fuse_finish_interrupt(f, req, &d);
1976 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001977 free(path);
1978 }
1979 pthread_rwlock_unlock(&f->tree_lock);
1980 reply_err(req, err);
Miklos Szeredia181e612001-11-06 12:03:23 +00001981}
1982
Miklos Szeredi52cb09d2005-11-07 11:59:00 +00001983static int default_statfs(struct statvfs *buf)
Miklos Szeredi77f39942004-03-25 11:17:52 +00001984{
Miklos Szeredi52cb09d2005-11-07 11:59:00 +00001985 buf->f_namemax = 255;
Miklos Szeredi77f39942004-03-25 11:17:52 +00001986 buf->f_bsize = 512;
1987 return 0;
1988}
1989
Miklos Szeredi3ded1a32006-08-18 18:43:50 +00001990static void fuse_statfs(fuse_req_t req, fuse_ino_t ino)
Miklos Szeredi18e75e42004-02-19 14:23:27 +00001991{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001992 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredi52cb09d2005-11-07 11:59:00 +00001993 struct statvfs buf;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001994 int err;
Mark Glinesd84b39a2002-01-07 16:32:02 +00001995
Miklos Szeredi52cb09d2005-11-07 11:59:00 +00001996 memset(&buf, 0, sizeof(buf));
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001997 if (f->op.statfs) {
Miklos Szeredi3ded1a32006-08-18 18:43:50 +00001998 if (ino && (!f->compat || f->compat >= 26)) {
1999 char *path;
2000 pthread_rwlock_rdlock(&f->tree_lock);
2001 err = -ENOENT;
2002 path = get_path(f, ino);
2003 if (path) {
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002004 err = fuse_do_statfs(f, req, path, &buf);
Miklos Szeredi3ded1a32006-08-18 18:43:50 +00002005 free(path);
2006 }
2007 pthread_rwlock_unlock(&f->tree_lock);
2008 } else
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002009 err = fuse_compat_statfs(f, req, &buf);
Miklos Szeredi52cb09d2005-11-07 11:59:00 +00002010 } else
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002011 err = default_statfs(&buf);
Miklos Szeredi77f39942004-03-25 11:17:52 +00002012
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002013 if (!err)
2014 fuse_reply_statfs(req, &buf);
Miklos Szeredi03cebae2004-03-31 10:19:18 +00002015 else
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002016 reply_err(req, err);
Miklos Szeredi03cebae2004-03-31 10:19:18 +00002017}
2018
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002019static void fuse_setxattr(fuse_req_t req, fuse_ino_t ino, const char *name,
2020 const char *value, size_t size, int flags)
Miklos Szeredi3ed84232004-03-30 15:17:26 +00002021{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002022 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredi3ed84232004-03-30 15:17:26 +00002023 char *path;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002024 int err;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00002025
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002026 err = -ENOENT;
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00002027 pthread_rwlock_rdlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002028 path = get_path(f, ino);
Miklos Szeredi3ed84232004-03-30 15:17:26 +00002029 if (path != NULL) {
Miklos Szerediab974562005-04-07 15:40:21 +00002030 err = -ENOSYS;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002031 if (f->op.setxattr) {
2032 struct fuse_intr_data d;
2033 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002034 err = f->op.setxattr(path, name, value, size, flags);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002035 fuse_finish_interrupt(f, req, &d);
2036 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002037 free(path);
2038 }
2039 pthread_rwlock_unlock(&f->tree_lock);
2040 reply_err(req, err);
2041}
2042
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002043static int common_getxattr(struct fuse *f, fuse_req_t req, fuse_ino_t ino,
2044 const char *name, char *value, size_t size)
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002045{
2046 int err;
2047 char *path;
2048
2049 err = -ENOENT;
2050 pthread_rwlock_rdlock(&f->tree_lock);
2051 path = get_path(f, ino);
2052 if (path != NULL) {
2053 err = -ENOSYS;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002054 if (f->op.getxattr) {
2055 struct fuse_intr_data d;
2056 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002057 err = f->op.getxattr(path, name, value, size);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002058 fuse_finish_interrupt(f, req, &d);
2059 }
Miklos Szerediab974562005-04-07 15:40:21 +00002060 free(path);
2061 }
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00002062 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szerediab974562005-04-07 15:40:21 +00002063 return err;
2064}
2065
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002066static void fuse_getxattr(fuse_req_t req, fuse_ino_t ino, const char *name,
2067 size_t size)
Miklos Szeredi3ead28e2005-01-18 21:23:41 +00002068{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002069 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredi4283ee72005-03-21 12:09:04 +00002070 int res;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002071
2072 if (size) {
2073 char *value = (char *) malloc(size);
2074 if (value == NULL) {
2075 reply_err(req, -ENOMEM);
2076 return;
2077 }
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002078 res = common_getxattr(f, req, ino, name, value, size);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002079 if (res > 0)
2080 fuse_reply_buf(req, value, res);
2081 else
2082 reply_err(req, res);
2083 free(value);
2084 } else {
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002085 res = common_getxattr(f, req, ino, name, NULL, 0);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002086 if (res >= 0)
2087 fuse_reply_xattr(req, res);
2088 else
2089 reply_err(req, res);
2090 }
2091}
2092
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002093static int common_listxattr(struct fuse *f, fuse_req_t req, fuse_ino_t ino,
2094 char *list, size_t size)
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002095{
Miklos Szeredi4283ee72005-03-21 12:09:04 +00002096 char *path;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002097 int err;
Miklos Szeredi4283ee72005-03-21 12:09:04 +00002098
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002099 err = -ENOENT;
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00002100 pthread_rwlock_rdlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002101 path = get_path(f, ino);
Miklos Szeredi4283ee72005-03-21 12:09:04 +00002102 if (path != NULL) {
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002103 err = -ENOSYS;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002104 if (f->op.listxattr) {
2105 struct fuse_intr_data d;
2106 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002107 err = f->op.listxattr(path, list, size);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002108 fuse_finish_interrupt(f, req, &d);
2109 }
Miklos Szeredi4283ee72005-03-21 12:09:04 +00002110 free(path);
2111 }
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00002112 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002113 return err;
Miklos Szeredi4283ee72005-03-21 12:09:04 +00002114}
Miklos Szeredi3ead28e2005-01-18 21:23:41 +00002115
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002116static void fuse_listxattr(fuse_req_t req, fuse_ino_t ino, size_t size)
Miklos Szeredi43696432001-11-18 19:15:05 +00002117{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002118 struct fuse *f = req_fuse_prepare(req);
2119 int res;
2120
2121 if (size) {
2122 char *list = (char *) malloc(size);
2123 if (list == NULL) {
2124 reply_err(req, -ENOMEM);
2125 return;
2126 }
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002127 res = common_listxattr(f, req, ino, list, size);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002128 if (res > 0)
2129 fuse_reply_buf(req, list, res);
2130 else
2131 reply_err(req, res);
2132 free(list);
2133 } else {
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002134 res = common_listxattr(f, req, ino, NULL, 0);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002135 if (res >= 0)
2136 fuse_reply_xattr(req, res);
2137 else
2138 reply_err(req, res);
2139 }
Miklos Szeredi43696432001-11-18 19:15:05 +00002140}
2141
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002142static void fuse_removexattr(fuse_req_t req, fuse_ino_t ino, const char *name)
2143{
2144 struct fuse *f = req_fuse_prepare(req);
2145 char *path;
2146 int err;
2147
2148 err = -ENOENT;
2149 pthread_rwlock_rdlock(&f->tree_lock);
2150 path = get_path(f, ino);
2151 if (path != NULL) {
2152 err = -ENOSYS;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002153 if (f->op.removexattr) {
2154 struct fuse_intr_data d;
2155 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002156 err = f->op.removexattr(path, name);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002157 fuse_finish_interrupt(f, req, &d);
2158 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002159 free(path);
2160 }
2161 pthread_rwlock_unlock(&f->tree_lock);
2162 reply_err(req, err);
2163}
2164
Miklos Szeredi9a5c11d2006-07-30 17:33:40 +00002165static int fuse_lock_common(fuse_req_t req, fuse_ino_t ino,
2166 struct fuse_file_info *fi, struct flock *lock,
2167 uint64_t owner, int cmd)
2168{
2169 struct fuse *f = req_fuse_prepare(req);
2170 char *path;
2171 int err;
2172
2173 err = -ENOENT;
2174 pthread_rwlock_rdlock(&f->tree_lock);
2175 path = get_path(f, ino);
2176 if (path != NULL) {
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002177 fuse_do_lock(f, req, path, fi, cmd, lock, owner);
Miklos Szeredi9a5c11d2006-07-30 17:33:40 +00002178 free(path);
2179 }
2180 pthread_rwlock_unlock(&f->tree_lock);
2181 return err;
2182}
2183
2184static void fuse_getlk(fuse_req_t req, fuse_ino_t ino,
2185 struct fuse_file_info *fi, struct flock *lock,
2186 uint64_t owner)
2187{
2188 int err = fuse_lock_common(req, ino, fi, lock, owner, F_GETLK);
2189 if (!err)
2190 fuse_reply_lock(req, lock);
2191 else
2192 reply_err(req, err);
2193}
2194
2195static void fuse_setlk(fuse_req_t req, fuse_ino_t ino,
2196 struct fuse_file_info *fi, struct flock *lock,
2197 uint64_t owner, int sleep)
2198{
2199 reply_err(req, fuse_lock_common(req, ino, fi, lock, owner,
2200 sleep ? F_SETLKW : F_SETLK));
2201}
2202
Miklos Szeredia1482422005-08-14 23:00:27 +00002203static struct fuse_lowlevel_ops fuse_path_ops = {
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002204 .init = fuse_data_init,
2205 .destroy = fuse_data_destroy,
2206 .lookup = fuse_lookup,
2207 .forget = fuse_forget,
2208 .getattr = fuse_getattr,
2209 .setattr = fuse_setattr,
Miklos Szeredib0b13d12005-10-26 12:53:25 +00002210 .access = fuse_access,
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002211 .readlink = fuse_readlink,
2212 .mknod = fuse_mknod,
2213 .mkdir = fuse_mkdir,
2214 .unlink = fuse_unlink,
2215 .rmdir = fuse_rmdir,
2216 .symlink = fuse_symlink,
2217 .rename = fuse_rename,
2218 .link = fuse_link,
Miklos Szeredid9079a72005-10-26 15:29:06 +00002219 .create = fuse_create,
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002220 .open = fuse_open,
2221 .read = fuse_read,
2222 .write = fuse_write,
2223 .flush = fuse_flush,
2224 .release = fuse_release,
2225 .fsync = fuse_fsync,
2226 .opendir = fuse_opendir,
2227 .readdir = fuse_readdir,
2228 .releasedir = fuse_releasedir,
2229 .fsyncdir = fuse_fsyncdir,
2230 .statfs = fuse_statfs,
2231 .setxattr = fuse_setxattr,
2232 .getxattr = fuse_getxattr,
2233 .listxattr = fuse_listxattr,
2234 .removexattr = fuse_removexattr,
Miklos Szeredi9a5c11d2006-07-30 17:33:40 +00002235 .getlk = fuse_getlk,
2236 .setlk = fuse_setlk,
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002237};
2238
Miklos Szeredia1482422005-08-14 23:00:27 +00002239static void free_cmd(struct fuse_cmd *cmd)
2240{
2241 free(cmd->buf);
2242 free(cmd);
2243}
2244
Miklos Szeredif458b8c2004-12-07 16:46:42 +00002245void fuse_process_cmd(struct fuse *f, struct fuse_cmd *cmd)
Miklos Szeredia181e612001-11-06 12:03:23 +00002246{
Miklos Szeredi178451d2005-08-15 13:19:07 +00002247 fuse_session_process(f->se, cmd->buf, cmd->buflen, cmd->ch);
Miklos Szeredifa829b52005-12-02 11:05:41 +00002248 free_cmd(cmd);
Miklos Szeredia181e612001-11-06 12:03:23 +00002249}
2250
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002251int fuse_exited(struct fuse *f)
Miklos Szeredi65cf7c72004-06-30 11:34:56 +00002252{
Miklos Szeredia1482422005-08-14 23:00:27 +00002253 return fuse_session_exited(f->se);
2254}
2255
2256struct fuse_session *fuse_get_session(struct fuse *f)
2257{
2258 return f->se;
2259}
2260
2261static struct fuse_cmd *fuse_alloc_cmd(size_t bufsize)
2262{
2263 struct fuse_cmd *cmd = (struct fuse_cmd *) malloc(sizeof(*cmd));
2264 if (cmd == NULL) {
2265 fprintf(stderr, "fuse: failed to allocate cmd\n");
2266 return NULL;
2267 }
2268 cmd->buf = (char *) malloc(bufsize);
2269 if (cmd->buf == NULL) {
2270 fprintf(stderr, "fuse: failed to allocate read buffer\n");
2271 free(cmd);
2272 return NULL;
2273 }
2274 return cmd;
Miklos Szeredi65cf7c72004-06-30 11:34:56 +00002275}
2276
Miklos Szeredif458b8c2004-12-07 16:46:42 +00002277struct fuse_cmd *fuse_read_cmd(struct fuse *f)
Miklos Szeredi2df1c042001-11-06 15:07:17 +00002278{
Miklos Szeredia1482422005-08-14 23:00:27 +00002279 struct fuse_chan *ch = fuse_session_next_chan(f->se, NULL);
2280 size_t bufsize = fuse_chan_bufsize(ch);
2281 struct fuse_cmd *cmd = fuse_alloc_cmd(bufsize);
2282 if (cmd != NULL) {
Miklos Szeredi8d975f62006-03-17 15:56:05 +00002283 int res = fuse_chan_recv(&ch, cmd->buf, bufsize);
Miklos Szeredia1482422005-08-14 23:00:27 +00002284 if (res <= 0) {
2285 free_cmd(cmd);
Miklos Szeredi5d9ce362006-03-01 12:10:13 +00002286 if (res < 0 && res != -EINTR && res != -EAGAIN)
Miklos Szeredifa829b52005-12-02 11:05:41 +00002287 fuse_exit(f);
Miklos Szeredia1482422005-08-14 23:00:27 +00002288 return NULL;
2289 }
2290 cmd->buflen = res;
Miklos Szeredi178451d2005-08-15 13:19:07 +00002291 cmd->ch = ch;
Miklos Szeredia1482422005-08-14 23:00:27 +00002292 }
2293 return cmd;
Miklos Szeredi2df1c042001-11-06 15:07:17 +00002294}
2295
Miklos Szeredib2cf9562004-09-16 08:42:40 +00002296int fuse_loop(struct fuse *f)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00002297{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002298 if (f)
Miklos Szeredia1482422005-08-14 23:00:27 +00002299 return fuse_session_loop(f->se);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002300 else
Miklos Szeredib2cf9562004-09-16 08:42:40 +00002301 return -1;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00002302}
2303
Miklos Szeredi891b8742004-07-29 09:27:49 +00002304int fuse_invalidate(struct fuse *f, const char *path)
2305{
Miklos Szeredie56818b2004-12-12 11:45:24 +00002306 (void) f;
2307 (void) path;
2308 return -EINVAL;
Miklos Szeredi891b8742004-07-29 09:27:49 +00002309}
2310
Miklos Szeredi0f48a262002-12-05 14:23:01 +00002311void fuse_exit(struct fuse *f)
2312{
Miklos Szeredia1482422005-08-14 23:00:27 +00002313 fuse_session_exit(f->se);
Miklos Szeredi0f48a262002-12-05 14:23:01 +00002314}
2315
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002316struct fuse_context *fuse_get_context(void)
Miklos Szeredi2e50d432001-12-20 12:17:25 +00002317{
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002318 return &fuse_get_context_internal()->ctx;
2319}
2320
2321int fuse_interrupted(void)
2322{
2323 return fuse_req_interrupted(fuse_get_context_internal()->req);
Miklos Szeredid169f312004-09-22 08:48:26 +00002324}
2325
Miklos Szeredif458b8c2004-12-07 16:46:42 +00002326void fuse_set_getcontext_func(struct fuse_context *(*func)(void))
Miklos Szeredid169f312004-09-22 08:48:26 +00002327{
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002328 (void) func;
2329 /* no-op */
Miklos Szeredi2e50d432001-12-20 12:17:25 +00002330}
2331
Miklos Szerediad005972006-01-07 10:14:34 +00002332enum {
2333 KEY_HELP,
Miklos Szerediad005972006-01-07 10:14:34 +00002334};
2335
Miklos Szeredi659743b2005-12-09 17:41:42 +00002336#define FUSE_LIB_OPT(t, p, v) { t, offsetof(struct fuse_config, p), v }
2337
2338static const struct fuse_opt fuse_lib_opts[] = {
Miklos Szerediad005972006-01-07 10:14:34 +00002339 FUSE_OPT_KEY("-h", KEY_HELP),
2340 FUSE_OPT_KEY("--help", KEY_HELP),
Miklos Szeredi065f2222006-01-20 15:15:21 +00002341 FUSE_OPT_KEY("debug", FUSE_OPT_KEY_KEEP),
2342 FUSE_OPT_KEY("-d", FUSE_OPT_KEY_KEEP),
Miklos Szeredi659743b2005-12-09 17:41:42 +00002343 FUSE_LIB_OPT("debug", debug, 1),
Miklos Szeredi95da8602006-01-06 18:29:40 +00002344 FUSE_LIB_OPT("-d", debug, 1),
Miklos Szeredi659743b2005-12-09 17:41:42 +00002345 FUSE_LIB_OPT("hard_remove", hard_remove, 1),
2346 FUSE_LIB_OPT("use_ino", use_ino, 1),
2347 FUSE_LIB_OPT("readdir_ino", readdir_ino, 1),
2348 FUSE_LIB_OPT("direct_io", direct_io, 1),
2349 FUSE_LIB_OPT("kernel_cache", kernel_cache, 1),
Miklos Szeredi320abe42006-01-30 18:14:51 +00002350 FUSE_LIB_OPT("auto_cache", auto_cache, 1),
2351 FUSE_LIB_OPT("noauto_cache", auto_cache, 0),
Miklos Szeredi659743b2005-12-09 17:41:42 +00002352 FUSE_LIB_OPT("umask=", set_mode, 1),
2353 FUSE_LIB_OPT("umask=%o", umask, 0),
2354 FUSE_LIB_OPT("uid=", set_uid, 1),
2355 FUSE_LIB_OPT("uid=%d", uid, 0),
2356 FUSE_LIB_OPT("gid=", set_gid, 1),
2357 FUSE_LIB_OPT("gid=%d", gid, 0),
2358 FUSE_LIB_OPT("entry_timeout=%lf", entry_timeout, 0),
2359 FUSE_LIB_OPT("attr_timeout=%lf", attr_timeout, 0),
Miklos Szeredi6e806e92006-02-16 16:59:39 +00002360 FUSE_LIB_OPT("ac_attr_timeout=%lf", ac_attr_timeout, 0),
2361 FUSE_LIB_OPT("ac_attr_timeout=", ac_attr_timeout_set, 1),
Miklos Szeredi659743b2005-12-09 17:41:42 +00002362 FUSE_LIB_OPT("negative_timeout=%lf", negative_timeout, 0),
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002363 FUSE_LIB_OPT("intr", intr, 1),
2364 FUSE_LIB_OPT("intr_signal=%d", intr_signal, 0),
Miklos Szeredi659743b2005-12-09 17:41:42 +00002365 FUSE_OPT_END
2366};
2367
Miklos Szerediad005972006-01-07 10:14:34 +00002368static void fuse_lib_help(void)
2369{
2370 fprintf(stderr,
Miklos Szeredi06091462006-02-16 16:38:34 +00002371" -o hard_remove immediate removal (don't hide files)\n"
2372" -o use_ino let filesystem set inode numbers\n"
2373" -o readdir_ino try to fill in d_ino in readdir\n"
2374" -o direct_io use direct I/O\n"
2375" -o kernel_cache cache files in kernel\n"
2376" -o [no]auto_cache enable caching based on modification times\n"
2377" -o umask=M set file permissions (octal)\n"
2378" -o uid=N set file owner\n"
2379" -o gid=N set file group\n"
2380" -o entry_timeout=T cache timeout for names (1.0s)\n"
2381" -o negative_timeout=T cache timeout for deleted names (0.0s)\n"
Miklos Szeredi6e806e92006-02-16 16:59:39 +00002382" -o attr_timeout=T cache timeout for attributes (1.0s)\n"
2383" -o ac_attr_timeout=T auto cache timeout for attributes (attr_timeout)\n"
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002384" -o intr allow requests to be interrupted\n"
2385" -o intr_signal=NUM signal to send on interrupt (%i)\n"
2386"\n", FUSE_DEFAULT_INTR_SIGNAL);
Miklos Szerediad005972006-01-07 10:14:34 +00002387}
2388
2389static int fuse_lib_opt_proc(void *data, const char *arg, int key,
2390 struct fuse_args *outargs)
2391{
2392 (void) data; (void) arg; (void) outargs;
2393
2394 if (key == KEY_HELP)
2395 fuse_lib_help();
2396
2397 return 1;
2398}
2399
2400
Miklos Szeredibd7661b2004-07-23 17:16:29 +00002401int fuse_is_lib_option(const char *opt)
2402{
Miklos Szeredi659743b2005-12-09 17:41:42 +00002403 return fuse_lowlevel_is_lib_option(opt) ||
2404 fuse_opt_match(fuse_lib_opts, opt);
Miklos Szeredibd7661b2004-07-23 17:16:29 +00002405}
2406
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002407static int fuse_init_intr_signal(int signum, int *installed)
2408{
2409 struct sigaction old_sa;
2410
2411 if (sigaction(signum, NULL, &old_sa) == -1) {
2412 perror("fuse: cannot get old signal handler");
2413 return -1;
2414 }
2415
2416 if (old_sa.sa_handler == SIG_DFL) {
2417 struct sigaction sa;
2418
2419 memset(&sa, 0, sizeof(struct sigaction));
2420 sa.sa_handler = fuse_intr_sighandler;
2421 sigemptyset(&(sa.sa_mask));
2422 sa.sa_flags = 0;
2423
2424 if (sigaction(signum, &sa, NULL) == -1) {
2425 perror("fuse: cannot set interrupt signal handler");
2426 return -1;
2427 }
2428 *installed = 1;
2429 }
2430 return 0;
2431}
2432
2433static void fuse_restore_intr_signal(int signum, int installed)
2434{
2435 if (installed) {
2436 struct sigaction sa;
2437
2438 memset(&sa, 0, sizeof(struct sigaction));
2439 sa.sa_handler = SIG_DFL;
2440 sigaction(signum, &sa, NULL);
2441 }
2442}
2443
Miklos Szeredi6f385412006-03-17 15:05:40 +00002444struct fuse *fuse_new_common(struct fuse_chan *ch, struct fuse_args *args,
Miklos Szeredi0b6a0ad2004-12-04 00:40:50 +00002445 const struct fuse_operations *op,
Miklos Szeredi6f385412006-03-17 15:05:40 +00002446 size_t op_size, void *user_data, int compat)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00002447{
Miklos Szeredi97c61e92001-11-07 12:09:43 +00002448 struct fuse *f;
2449 struct node *root;
Miklos Szeredi9a5c11d2006-07-30 17:33:40 +00002450 struct fuse_lowlevel_ops llop = fuse_path_ops;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00002451
Miklos Szeredi0f62d722005-01-04 12:45:54 +00002452 if (sizeof(struct fuse_operations) < op_size) {
Miklos Szeredi0b6a0ad2004-12-04 00:40:50 +00002453 fprintf(stderr, "fuse: warning: library too old, some operations may not not work\n");
Miklos Szeredi0f62d722005-01-04 12:45:54 +00002454 op_size = sizeof(struct fuse_operations);
Miklos Szeredi0b6a0ad2004-12-04 00:40:50 +00002455 }
2456
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002457 if (fuse_create_context_key() == -1)
2458 goto out;
2459
Miklos Szeredi97c61e92001-11-07 12:09:43 +00002460 f = (struct fuse *) calloc(1, sizeof(struct fuse));
Miklos Szeredie56818b2004-12-12 11:45:24 +00002461 if (f == NULL) {
2462 fprintf(stderr, "fuse: failed to allocate fuse object\n");
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002463 goto out_delete_context_key;
Miklos Szeredie56818b2004-12-12 11:45:24 +00002464 }
Miklos Szeredi2df1c042001-11-06 15:07:17 +00002465
Miklos Szeredi6f385412006-03-17 15:05:40 +00002466 f->user_data = user_data;
Miklos Szeredi659743b2005-12-09 17:41:42 +00002467 f->conf.entry_timeout = 1.0;
2468 f->conf.attr_timeout = 1.0;
2469 f->conf.negative_timeout = 0.0;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002470 f->conf.intr_signal = FUSE_DEFAULT_INTR_SIGNAL;
Miklos Szeredi6c0209a2005-08-02 13:31:28 +00002471
Miklos Szerediad005972006-01-07 10:14:34 +00002472 if (fuse_opt_parse(args, &f->conf, fuse_lib_opts, fuse_lib_opt_proc) == -1)
Miklos Szeredi659743b2005-12-09 17:41:42 +00002473 goto out_free;
Miklos Szeredib2cf9562004-09-16 08:42:40 +00002474
Miklos Szeredi6e806e92006-02-16 16:59:39 +00002475 if (!f->conf.ac_attr_timeout_set)
2476 f->conf.ac_attr_timeout = f->conf.attr_timeout;
2477
Miklos Szeredi659743b2005-12-09 17:41:42 +00002478#ifdef __FreeBSD__
2479 /*
2480 * In FreeBSD, we always use these settings as inode numbers are needed to
2481 * make getcwd(3) work.
2482 */
Miklos Szeredi76fc3de2005-12-12 09:34:45 +00002483 f->conf.readdir_ino = 1;
Miklos Szeredi659743b2005-12-09 17:41:42 +00002484#endif
2485
Miklos Szeredi065f2222006-01-20 15:15:21 +00002486 if (compat && compat <= 25) {
2487 if (fuse_sync_compat_args(args) == -1)
2488 goto out_free;
2489 }
2490
Miklos Szeredi9a5c11d2006-07-30 17:33:40 +00002491 memcpy(&f->op, op, op_size);
2492 if (!f->op.lock) {
2493 llop.getlk = NULL;
2494 llop.setlk = NULL;
2495 }
2496
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002497 f->se = fuse_lowlevel_new_common(args, &llop, sizeof(llop), f);
Miklos Szeredia1482422005-08-14 23:00:27 +00002498 if (f->se == NULL)
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002499 goto out_free;
Miklos Szeredi2bb750e2005-10-03 14:54:24 +00002500
Miklos Szeredia1482422005-08-14 23:00:27 +00002501 fuse_session_add_chan(f->se, ch);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002502
Miklos Szeredi97c61e92001-11-07 12:09:43 +00002503 f->ctr = 0;
Miklos Szeredi76f65782004-02-19 16:55:40 +00002504 f->generation = 0;
Miklos Szeredifff56ab2001-11-16 10:12:59 +00002505 /* FIXME: Dynamic hash table */
Miklos Szeredi97c61e92001-11-07 12:09:43 +00002506 f->name_table_size = 14057;
2507 f->name_table = (struct node **)
2508 calloc(1, sizeof(struct node *) * f->name_table_size);
Miklos Szeredie56818b2004-12-12 11:45:24 +00002509 if (f->name_table == NULL) {
2510 fprintf(stderr, "fuse: memory allocation failed\n");
Miklos Szeredia1482422005-08-14 23:00:27 +00002511 goto out_free_session;
Miklos Szeredie56818b2004-12-12 11:45:24 +00002512 }
Miklos Szeredib2cf9562004-09-16 08:42:40 +00002513
Miklos Szeredia13d9002004-11-02 17:32:03 +00002514 f->id_table_size = 14057;
2515 f->id_table = (struct node **)
2516 calloc(1, sizeof(struct node *) * f->id_table_size);
Miklos Szeredie56818b2004-12-12 11:45:24 +00002517 if (f->id_table == NULL) {
2518 fprintf(stderr, "fuse: memory allocation failed\n");
Miklos Szeredib2cf9562004-09-16 08:42:40 +00002519 goto out_free_name_table;
Miklos Szeredie56818b2004-12-12 11:45:24 +00002520 }
Miklos Szeredib2cf9562004-09-16 08:42:40 +00002521
Miklos Szeredi38f152c2006-09-03 18:28:52 +00002522 fuse_mutex_init(&f->lock);
Miklos Szeredid0a777a2006-04-05 07:18:00 +00002523 pthread_rwlock_init(&f->tree_lock, NULL);
Miklos Szeredi0b6a0ad2004-12-04 00:40:50 +00002524 f->compat = compat;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00002525
Miklos Szeredi97c61e92001-11-07 12:09:43 +00002526 root = (struct node *) calloc(1, sizeof(struct node));
Miklos Szeredie56818b2004-12-12 11:45:24 +00002527 if (root == NULL) {
2528 fprintf(stderr, "fuse: memory allocation failed\n");
Miklos Szeredia13d9002004-11-02 17:32:03 +00002529 goto out_free_id_table;
Miklos Szeredie56818b2004-12-12 11:45:24 +00002530 }
Miklos Szeredib2cf9562004-09-16 08:42:40 +00002531
Miklos Szeredi97c61e92001-11-07 12:09:43 +00002532 root->name = strdup("/");
Miklos Szeredie56818b2004-12-12 11:45:24 +00002533 if (root->name == NULL) {
2534 fprintf(stderr, "fuse: memory allocation failed\n");
Miklos Szeredib2cf9562004-09-16 08:42:40 +00002535 goto out_free_root;
Miklos Szeredie56818b2004-12-12 11:45:24 +00002536 }
Miklos Szeredib2cf9562004-09-16 08:42:40 +00002537
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002538 if (f->conf.intr &&
2539 fuse_init_intr_signal(f->conf.intr_signal, &f->intr_installed) == -1)
2540 goto out_free_root_name;
2541
Miklos Szeredi97c61e92001-11-07 12:09:43 +00002542 root->parent = 0;
Miklos Szeredia13d9002004-11-02 17:32:03 +00002543 root->nodeid = FUSE_ROOT_ID;
Miklos Szeredi76f65782004-02-19 16:55:40 +00002544 root->generation = 0;
Miklos Szeredi0f62d722005-01-04 12:45:54 +00002545 root->refctr = 1;
Miklos Szeredi38009022005-05-08 19:47:22 +00002546 root->nlookup = 1;
Miklos Szeredia13d9002004-11-02 17:32:03 +00002547 hash_id(f, root);
Miklos Szeredi97c61e92001-11-07 12:09:43 +00002548
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00002549 return f;
Miklos Szeredib2cf9562004-09-16 08:42:40 +00002550
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002551 out_free_root_name:
2552 free(root->name);
Miklos Szeredib2cf9562004-09-16 08:42:40 +00002553 out_free_root:
2554 free(root);
Miklos Szeredia13d9002004-11-02 17:32:03 +00002555 out_free_id_table:
2556 free(f->id_table);
Miklos Szeredib2cf9562004-09-16 08:42:40 +00002557 out_free_name_table:
2558 free(f->name_table);
Miklos Szeredia1482422005-08-14 23:00:27 +00002559 out_free_session:
2560 fuse_session_destroy(f->se);
Miklos Szeredib2cf9562004-09-16 08:42:40 +00002561 out_free:
2562 free(f);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002563 out_delete_context_key:
2564 fuse_delete_context_key();
Miklos Szeredib2cf9562004-09-16 08:42:40 +00002565 out:
Miklos Szeredib2cf9562004-09-16 08:42:40 +00002566 return NULL;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00002567}
2568
Miklos Szeredi6f385412006-03-17 15:05:40 +00002569struct fuse *fuse_new(struct fuse_chan *ch, struct fuse_args *args,
2570 const struct fuse_operations *op, size_t op_size,
2571 void *user_data)
Miklos Szeredi0b6a0ad2004-12-04 00:40:50 +00002572{
Miklos Szeredi6f385412006-03-17 15:05:40 +00002573 return fuse_new_common(ch, args, op, op_size, user_data, 0);
Miklos Szeredi0b6a0ad2004-12-04 00:40:50 +00002574}
2575
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00002576void fuse_destroy(struct fuse *f)
2577{
Miklos Szeredi97c61e92001-11-07 12:09:43 +00002578 size_t i;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002579 struct fuse_context_i *c = fuse_get_context_internal();
2580
2581 if (f->conf.intr && f->intr_installed)
2582 fuse_restore_intr_signal(f->conf.intr_signal);
Miklos Szerediad519562006-07-31 11:07:40 +00002583
2584 memset(c, 0, sizeof(*c));
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002585 c->ctx.fuse = f;
2586 c->ctx.private_data = f->user_data;
Miklos Szerediad519562006-07-31 11:07:40 +00002587
Miklos Szeredia13d9002004-11-02 17:32:03 +00002588 for (i = 0; i < f->id_table_size; i++) {
Miklos Szeredi97c61e92001-11-07 12:09:43 +00002589 struct node *node;
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00002590
Miklos Szeredia13d9002004-11-02 17:32:03 +00002591 for (node = f->id_table[i]; node != NULL; node = node->id_next) {
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00002592 if (node->is_hidden) {
Miklos Szeredia13d9002004-11-02 17:32:03 +00002593 char *path = get_path(f, node->nodeid);
Miklos Szeredi21019c92005-05-09 11:22:41 +00002594 if (path) {
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00002595 f->op.unlink(path);
Miklos Szeredi21019c92005-05-09 11:22:41 +00002596 free(path);
2597 }
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00002598 }
2599 }
2600 }
Miklos Szeredia13d9002004-11-02 17:32:03 +00002601 for (i = 0; i < f->id_table_size; i++) {
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00002602 struct node *node;
Miklos Szeredi97c61e92001-11-07 12:09:43 +00002603 struct node *next;
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00002604
Miklos Szeredia13d9002004-11-02 17:32:03 +00002605 for (node = f->id_table[i]; node != NULL; node = next) {
2606 next = node->id_next;
Miklos Szeredi97c61e92001-11-07 12:09:43 +00002607 free_node(node);
2608 }
2609 }
Miklos Szeredia13d9002004-11-02 17:32:03 +00002610 free(f->id_table);
Miklos Szeredi97c61e92001-11-07 12:09:43 +00002611 free(f->name_table);
Miklos Szeredia181e612001-11-06 12:03:23 +00002612 pthread_mutex_destroy(&f->lock);
Miklos Szeredi55a84102006-06-06 10:16:38 +00002613 pthread_rwlock_destroy(&f->tree_lock);
Miklos Szeredia1482422005-08-14 23:00:27 +00002614 fuse_session_destroy(f->se);
Miklos Szeredi97c61e92001-11-07 12:09:43 +00002615 free(f);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002616 fuse_delete_context_key();
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00002617}
Miklos Szeredi0b6a0ad2004-12-04 00:40:50 +00002618
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002619#include "fuse_compat.h"
2620
Miklos Szeredi6f385412006-03-17 15:05:40 +00002621static struct fuse *fuse_new_common_compat25(int fd, struct fuse_args *args,
2622 const struct fuse_operations *op,
2623 size_t op_size, int compat)
2624{
2625 struct fuse *f = NULL;
2626 struct fuse_chan *ch = fuse_kern_chan_new(fd);
2627
2628 if (ch)
2629 f = fuse_new_common(ch, args, op, op_size, NULL, compat);
2630
2631 return f;
2632}
2633
Miklos Szeredi065f2222006-01-20 15:15:21 +00002634#ifndef __FreeBSD__
2635
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002636static int fuse_compat_open(struct fuse *f, fuse_req_t req, char *path,
2637 struct fuse_file_info *fi)
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002638{
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002639 int err;
2640 struct fuse_intr_data d;
Miklos Szeredi065f2222006-01-20 15:15:21 +00002641 if (!f->compat || f->compat >= 25)
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002642 err = fuse_do_open(f, req, path, fi);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002643 else if (f->compat == 22) {
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002644 struct fuse_file_info_compat22 tmp;
2645 memcpy(&tmp, fi, sizeof(tmp));
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002646 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002647 err = ((struct fuse_operations_compat22 *) &f->op)->open(path, &tmp);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002648 fuse_finish_interrupt(f, req, &d);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002649 memcpy(fi, &tmp, sizeof(tmp));
2650 fi->fh = tmp.fh;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002651 } else {
2652 fuse_prepare_interrupt(f, req, &d);
2653 err =
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002654 ((struct fuse_operations_compat2 *) &f->op)->open(path, fi->flags);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002655 fuse_finish_interrupt(f, req, &d);
2656 }
2657 return err;
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002658}
2659
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002660static void fuse_compat_release(struct fuse *f, fuse_req_t req, char *path,
2661 struct fuse_file_info *fi)
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002662{
2663 if (!f->compat || f->compat >= 22)
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002664 fuse_do_release(f, req, path ? path : "-", fi);
2665 else if (path) {
2666 struct fuse_intr_data d;
2667 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002668 ((struct fuse_operations_compat2 *) &f->op)->release(path, fi->flags);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002669 fuse_finish_interrupt(f, req, &d);
2670 }
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002671}
2672
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002673static int fuse_compat_opendir(struct fuse *f, fuse_req_t req, char *path,
2674 struct fuse_file_info *fi)
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002675{
Miklos Szeredi065f2222006-01-20 15:15:21 +00002676 if (!f->compat || f->compat >= 25) {
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002677 return fuse_do_opendir(f, req, path, fi);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002678 } else {
2679 int err;
2680 struct fuse_file_info_compat22 tmp;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002681 struct fuse_intr_data d;
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002682 memcpy(&tmp, fi, sizeof(tmp));
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002683 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002684 err = ((struct fuse_operations_compat22 *) &f->op)->opendir(path, &tmp);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002685 fuse_finish_interrupt(f, req, &d);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002686 memcpy(fi, &tmp, sizeof(tmp));
2687 fi->fh = tmp.fh;
2688 return err;
2689 }
2690}
2691
2692static void convert_statfs_compat(struct fuse_statfs_compat1 *compatbuf,
2693 struct statvfs *stbuf)
2694{
2695 stbuf->f_bsize = compatbuf->block_size;
2696 stbuf->f_blocks = compatbuf->blocks;
2697 stbuf->f_bfree = compatbuf->blocks_free;
2698 stbuf->f_bavail = compatbuf->blocks_free;
2699 stbuf->f_files = compatbuf->files;
2700 stbuf->f_ffree = compatbuf->files_free;
2701 stbuf->f_namemax = compatbuf->namelen;
2702}
2703
2704static void convert_statfs_old(struct statfs *oldbuf, struct statvfs *stbuf)
2705{
2706 stbuf->f_bsize = oldbuf->f_bsize;
2707 stbuf->f_blocks = oldbuf->f_blocks;
2708 stbuf->f_bfree = oldbuf->f_bfree;
2709 stbuf->f_bavail = oldbuf->f_bavail;
2710 stbuf->f_files = oldbuf->f_files;
2711 stbuf->f_ffree = oldbuf->f_ffree;
2712 stbuf->f_namemax = oldbuf->f_namelen;
2713}
2714
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002715static int fuse_compat_statfs(struct fuse *f, fuse_req_t req,
2716 struct statvfs *buf)
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002717{
2718 int err;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002719 struct fuse_intr_data d;
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002720
Miklos Szeredi065f2222006-01-20 15:15:21 +00002721 if (!f->compat || f->compat >= 25) {
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002722 err = fuse_do_statfs(f, req, "/", buf);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002723 } else if (f->compat > 11) {
2724 struct statfs oldbuf;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002725 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002726 err = ((struct fuse_operations_compat22 *) &f->op)->statfs("/", &oldbuf);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002727 fuse_finish_interrupt(f, req, &d);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002728 if (!err)
2729 convert_statfs_old(&oldbuf, buf);
2730 } else {
2731 struct fuse_statfs_compat1 compatbuf;
2732 memset(&compatbuf, 0, sizeof(struct fuse_statfs_compat1));
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002733 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002734 err = ((struct fuse_operations_compat1 *) &f->op)->statfs(&compatbuf);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002735 fuse_finish_interrupt(f, req, &d);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002736 if (!err)
2737 convert_statfs_compat(&compatbuf, buf);
2738 }
2739 return err;
2740}
2741
Miklos Szeredi95da8602006-01-06 18:29:40 +00002742static struct fuse *fuse_new_common_compat(int fd, const char *opts,
2743 const struct fuse_operations *op,
2744 size_t op_size, int compat)
2745{
2746 struct fuse *f;
2747 struct fuse_args args = FUSE_ARGS_INIT(0, NULL);
2748
2749 if (opts &&
2750 (fuse_opt_add_arg(&args, "") == -1 ||
2751 fuse_opt_add_arg(&args, "-o") == -1 ||
2752 fuse_opt_add_arg(&args, opts) == -1)) {
2753 fuse_opt_free_args(&args);
2754 return NULL;
2755 }
Miklos Szeredi6f385412006-03-17 15:05:40 +00002756 f = fuse_new_common_compat25(fd, &args, op, op_size, compat);
Miklos Szeredi95da8602006-01-06 18:29:40 +00002757 fuse_opt_free_args(&args);
2758
2759 return f;
2760}
2761
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002762struct fuse *fuse_new_compat22(int fd, const char *opts,
2763 const struct fuse_operations_compat22 *op,
2764 size_t op_size)
2765{
Miklos Szeredi95da8602006-01-06 18:29:40 +00002766 return fuse_new_common_compat(fd, opts, (struct fuse_operations *) op,
2767 op_size, 22);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002768}
2769
2770struct fuse *fuse_new_compat2(int fd, const char *opts,
2771 const struct fuse_operations_compat2 *op)
2772{
Miklos Szeredi95da8602006-01-06 18:29:40 +00002773 return fuse_new_common_compat(fd, opts, (struct fuse_operations *) op,
2774 sizeof(struct fuse_operations_compat2), 21);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002775}
2776
2777struct fuse *fuse_new_compat1(int fd, int flags,
2778 const struct fuse_operations_compat1 *op)
2779{
2780 const char *opts = NULL;
2781 if (flags & FUSE_DEBUG_COMPAT1)
2782 opts = "debug";
Miklos Szeredi95da8602006-01-06 18:29:40 +00002783 return fuse_new_common_compat(fd, opts, (struct fuse_operations *) op,
2784 sizeof(struct fuse_operations_compat1), 11);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002785}
2786
Miklos Szeredif458b8c2004-12-07 16:46:42 +00002787__asm__(".symver fuse_exited,__fuse_exited@");
2788__asm__(".symver fuse_process_cmd,__fuse_process_cmd@");
2789__asm__(".symver fuse_read_cmd,__fuse_read_cmd@");
2790__asm__(".symver fuse_set_getcontext_func,__fuse_set_getcontext_func@");
2791__asm__(".symver fuse_new_compat2,fuse_new@");
Miklos Szeredi3a770472005-11-11 21:32:42 +00002792__asm__(".symver fuse_new_compat22,fuse_new@FUSE_2.2");
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002793
2794#else /* __FreeBSD__ */
2795
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002796static int fuse_compat_open(struct fuse *f, fuse_req_t req, char *path,
2797 struct fuse_file_info *fi)
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002798{
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002799 return fuse_do_open(f, req, path, fi);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002800}
2801
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002802static void fuse_compat_release(struct fuse *f, fuse_req_t req, char *path,
2803 struct fuse_file_info *fi)
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002804{
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002805 fuse_do_release(f, req, path ? path : "-", fi);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002806}
2807
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002808static int fuse_compat_opendir(struct fuse *f, fuse_req_t req, char *path,
2809 struct fuse_file_info *fi)
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002810{
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002811 return fuse_do_opendir(f, req, path, fi);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002812}
2813
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002814static int fuse_do_statfs(struct fuse *f, fuse_req_t req, struct statvfs *buf)
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002815{
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002816 return fuse_do_statfs(f, req, "/", buf);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002817}
2818
2819#endif /* __FreeBSD__ */
Miklos Szeredi065f2222006-01-20 15:15:21 +00002820
2821struct fuse *fuse_new_compat25(int fd, struct fuse_args *args,
2822 const struct fuse_operations_compat25 *op,
2823 size_t op_size)
2824{
Miklos Szeredi6f385412006-03-17 15:05:40 +00002825 return fuse_new_common_compat25(fd, args, (struct fuse_operations *) op,
2826 op_size, 25);
Miklos Szeredi065f2222006-01-20 15:15:21 +00002827}
2828
2829__asm__(".symver fuse_new_compat25,fuse_new@FUSE_2.5");