blob: d97f5255f336e488446f9c8db495eb44485389db [file] [log] [blame]
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001/*
2 FUSE: Filesystem in Userspace
Miklos Szeredi149f6072005-01-10 12:29:28 +00003 Copyright (C) 2001-2005 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 Szeredi85c74fc2001-10-28 19:44:14 +000016
Miklos Szeredi0f62d722005-01-04 12:45:54 +000017#include <stdio.h>
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000018#include <string.h>
Miklos Szeredi97c61e92001-11-07 12:09:43 +000019#include <stdlib.h>
Miklos Szeredi659743b2005-12-09 17:41:42 +000020#include <stddef.h>
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000021#include <unistd.h>
Miklos Szeredib3f99722005-11-16 13:00:24 +000022#include <fcntl.h>
Miklos Szeredi97c61e92001-11-07 12:09:43 +000023#include <limits.h>
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000024#include <errno.h>
Miklos Szeredi0f62d722005-01-04 12:45:54 +000025#include <assert.h>
Miklos Szeredie2aa2e22005-07-15 13:31:36 +000026#include <pthread.h>
Miklos Szeredi019b4e92001-12-26 18:08:09 +000027#include <sys/param.h>
Miklos Szerediab974562005-04-07 15:40:21 +000028#include <sys/uio.h>
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000029
Miklos Szeredi97c61e92001-11-07 12:09:43 +000030#define FUSE_MAX_PATH 4096
Miklos Szeredi30e093a2005-04-03 17:44:54 +000031
Miklos Szeredie248e4b2005-12-14 16:18:32 +000032#define FUSE_UNKNOWN_INO 0xffffffff
33
Miklos Szeredi659743b2005-12-09 17:41:42 +000034struct fuse_config {
35 char *llopts;
36 unsigned int uid;
37 unsigned int gid;
38 unsigned int umask;
39 double entry_timeout;
40 double negative_timeout;
41 double attr_timeout;
42 int debug;
43 int hard_remove;
44 int use_ino;
45 int readdir_ino;
46 int set_mode;
47 int set_uid;
48 int set_gid;
49 int direct_io;
50 int kernel_cache;
51};
52
Miklos Szeredie2aa2e22005-07-15 13:31:36 +000053struct fuse {
Miklos Szeredia1482422005-08-14 23:00:27 +000054 struct fuse_session *se;
Miklos Szeredie2aa2e22005-07-15 13:31:36 +000055 struct fuse_operations op;
56 int compat;
57 struct node **name_table;
58 size_t name_table_size;
59 struct node **id_table;
60 size_t id_table_size;
61 fuse_ino_t ctr;
62 unsigned int generation;
63 unsigned int hidectr;
64 pthread_mutex_t lock;
65 pthread_rwlock_t tree_lock;
66 void *user_data;
Miklos Szeredi659743b2005-12-09 17:41:42 +000067 struct fuse_config conf;
Miklos Szeredie2aa2e22005-07-15 13:31:36 +000068};
69
Miklos Szeredi0f62d722005-01-04 12:45:54 +000070struct node {
71 struct node *name_next;
72 struct node *id_next;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +000073 fuse_ino_t nodeid;
Miklos Szeredi0f62d722005-01-04 12:45:54 +000074 unsigned int generation;
75 int refctr;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +000076 fuse_ino_t parent;
Miklos Szeredi0f62d722005-01-04 12:45:54 +000077 char *name;
Miklos Szeredi38009022005-05-08 19:47:22 +000078 uint64_t nlookup;
Miklos Szeredi0f62d722005-01-04 12:45:54 +000079 int open_count;
80 int is_hidden;
81};
82
83struct fuse_dirhandle {
Miklos Szerediab974562005-04-07 15:40:21 +000084 pthread_mutex_t lock;
Miklos Szeredi0f62d722005-01-04 12:45:54 +000085 struct fuse *fuse;
Miklos Szeredi1b188022005-07-28 11:07:29 +000086 char *contents;
Miklos Szerediab974562005-04-07 15:40:21 +000087 int allocated;
Miklos Szeredib92d9782005-02-07 16:10:49 +000088 unsigned len;
Miklos Szeredic4c12ae2005-10-20 14:48:50 +000089 unsigned size;
Miklos Szerediab974562005-04-07 15:40:21 +000090 unsigned needlen;
Miklos Szeredi3ead28e2005-01-18 21:23:41 +000091 int filled;
Miklos Szeredi3a770472005-11-11 21:32:42 +000092 uint64_t fh;
Miklos Szerediab974562005-04-07 15:40:21 +000093 int error;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +000094 fuse_ino_t nodeid;
Miklos Szeredi0f62d722005-01-04 12:45:54 +000095};
96
Miklos Szeredid169f312004-09-22 08:48:26 +000097static struct fuse_context *(*fuse_getcontext)(void) = NULL;
98
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +000099static int fuse_do_open(struct fuse *, char *, struct fuse_file_info *);
100static void fuse_do_release(struct fuse *, char *, struct fuse_file_info *);
101static int fuse_do_opendir(struct fuse *, char *, struct fuse_file_info *);
102static int fuse_do_statfs(struct fuse *, char *, struct statvfs *);
103
Miklos Szerediab974562005-04-07 15:40:21 +0000104#ifndef USE_UCLIBC
105#define mutex_init(mut) pthread_mutex_init(mut, NULL)
106#else
Miklos Szeredi129ef8f2005-06-20 13:48:42 +0000107static void mutex_init(pthread_mutex_t *mut)
Miklos Szerediab974562005-04-07 15:40:21 +0000108{
109 pthread_mutexattr_t attr;
110 pthread_mutexattr_init(&attr);
111 pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ADAPTIVE_NP);
112 pthread_mutex_init(mut, &attr);
113 pthread_mutexattr_destroy(&attr);
114}
115#endif
116
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000117static struct node *get_node_nocheck(struct fuse *f, fuse_ino_t nodeid)
Miklos Szeredia181e612001-11-06 12:03:23 +0000118{
Miklos Szeredia13d9002004-11-02 17:32:03 +0000119 size_t hash = nodeid % f->id_table_size;
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000120 struct node *node;
121
Miklos Szeredia13d9002004-11-02 17:32:03 +0000122 for (node = f->id_table[hash]; node != NULL; node = node->id_next)
123 if (node->nodeid == nodeid)
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000124 return node;
Miklos Szeredie5183742005-02-02 11:14:04 +0000125
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000126 return NULL;
Miklos Szeredia181e612001-11-06 12:03:23 +0000127}
128
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000129static struct node *get_node(struct fuse *f, fuse_ino_t nodeid)
Miklos Szeredia181e612001-11-06 12:03:23 +0000130{
Miklos Szeredif458b8c2004-12-07 16:46:42 +0000131 struct node *node = get_node_nocheck(f, nodeid);
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000132 if (!node) {
Miklos Szeredi3a770472005-11-11 21:32:42 +0000133 fprintf(stderr, "fuse internal error: node %llu not found\n",
134 (unsigned long long) nodeid);
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000135 abort();
136 }
137 return node;
Miklos Szeredia181e612001-11-06 12:03:23 +0000138}
139
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000140static void free_node(struct node *node)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000141{
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000142 free(node->name);
143 free(node);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000144}
145
Miklos Szeredia13d9002004-11-02 17:32:03 +0000146static void unhash_id(struct fuse *f, struct node *node)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000147{
Miklos Szeredia13d9002004-11-02 17:32:03 +0000148 size_t hash = node->nodeid % f->id_table_size;
149 struct node **nodep = &f->id_table[hash];
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000150
Miklos Szeredie5183742005-02-02 11:14:04 +0000151 for (; *nodep != NULL; nodep = &(*nodep)->id_next)
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000152 if (*nodep == node) {
Miklos Szeredia13d9002004-11-02 17:32:03 +0000153 *nodep = node->id_next;
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000154 return;
155 }
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000156}
157
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000158static void hash_id(struct fuse *f, struct node *node)
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000159{
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000160 size_t hash = node->nodeid % f->id_table_size;
161 node->id_next = f->id_table[hash];
Miklos Szeredie5183742005-02-02 11:14:04 +0000162 f->id_table[hash] = node;
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000163}
164
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000165static unsigned int name_hash(struct fuse *f, fuse_ino_t parent, const char *name)
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000166{
167 unsigned int hash = *name;
168
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000169 if (hash)
170 for (name += 1; *name != '\0'; name++)
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000171 hash = (hash << 5) - hash + *name;
172
173 return (hash + parent) % f->name_table_size;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000174}
175
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000176static void unref_node(struct fuse *f, struct node *node);
177
178static void unhash_name(struct fuse *f, struct node *node)
179{
180 if (node->name) {
181 size_t hash = name_hash(f, node->parent, node->name);
182 struct node **nodep = &f->name_table[hash];
Miklos Szeredie5183742005-02-02 11:14:04 +0000183
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000184 for (; *nodep != NULL; nodep = &(*nodep)->name_next)
185 if (*nodep == node) {
186 *nodep = node->name_next;
187 node->name_next = NULL;
188 unref_node(f, get_node(f, node->parent));
189 free(node->name);
190 node->name = NULL;
191 node->parent = 0;
192 return;
193 }
Miklos Szeredi3a770472005-11-11 21:32:42 +0000194 fprintf(stderr, "fuse internal error: unable to unhash node: %llu\n",
195 (unsigned long long) node->nodeid);
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000196 abort();
197 }
198}
199
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000200static int hash_name(struct fuse *f, struct node *node, fuse_ino_t parent,
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000201 const char *name)
202{
203 size_t hash = name_hash(f, parent, name);
204 node->name = strdup(name);
205 if (node->name == NULL)
206 return -1;
207
208 get_node(f, parent)->refctr ++;
209 node->parent = parent;
210 node->name_next = f->name_table[hash];
211 f->name_table[hash] = node;
212 return 0;
213}
214
215static void delete_node(struct fuse *f, struct node *node)
216{
Miklos Szeredi659743b2005-12-09 17:41:42 +0000217 if (f->conf.debug) {
Miklos Szeredi3a770472005-11-11 21:32:42 +0000218 printf("delete: %llu\n", (unsigned long long) node->nodeid);
Miklos Szeredi38009022005-05-08 19:47:22 +0000219 fflush(stdout);
220 }
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000221 assert(!node->name);
222 unhash_id(f, node);
223 free_node(node);
224}
225
226static void unref_node(struct fuse *f, struct node *node)
227{
228 assert(node->refctr > 0);
229 node->refctr --;
230 if (!node->refctr)
231 delete_node(f, node);
232}
233
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000234static fuse_ino_t next_id(struct fuse *f)
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000235{
236 do {
237 f->ctr++;
238 if (!f->ctr)
239 f->generation ++;
240 } while (f->ctr == 0 || get_node_nocheck(f, f->ctr) != NULL);
241 return f->ctr;
242}
243
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000244static struct node *lookup_node(struct fuse *f, fuse_ino_t parent,
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000245 const char *name)
246{
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000247 size_t hash = name_hash(f, parent, name);
248 struct node *node;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000249
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000250 for (node = f->name_table[hash]; node != NULL; node = node->name_next)
251 if (node->parent == parent && strcmp(node->name, name) == 0)
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000252 return node;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000253
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000254 return NULL;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000255}
256
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000257static struct node *find_node(struct fuse *f, fuse_ino_t parent,
258 const char *name)
Miklos Szeredi5e183482001-10-31 14:52:35 +0000259{
260 struct node *node;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000261
Miklos Szeredia181e612001-11-06 12:03:23 +0000262 pthread_mutex_lock(&f->lock);
Miklos Szeredif458b8c2004-12-07 16:46:42 +0000263 node = lookup_node(f, parent, name);
Miklos Szeredie331c4b2005-07-06 13:34:02 +0000264 if (node == NULL) {
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000265 node = (struct node *) calloc(1, sizeof(struct node));
266 if (node == NULL)
267 goto out_err;
Miklos Szeredie5183742005-02-02 11:14:04 +0000268
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000269 node->refctr = 1;
270 node->nodeid = next_id(f);
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000271 node->open_count = 0;
272 node->is_hidden = 0;
273 node->generation = f->generation;
274 if (hash_name(f, node, parent, name) == -1) {
275 free(node);
276 node = NULL;
277 goto out_err;
278 }
279 hash_id(f, node);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000280 }
Miklos Szeredi38009022005-05-08 19:47:22 +0000281 node->nlookup ++;
Miklos Szeredic2309912004-09-21 13:40:38 +0000282 out_err:
Miklos Szeredia181e612001-11-06 12:03:23 +0000283 pthread_mutex_unlock(&f->lock);
Miklos Szeredi76f65782004-02-19 16:55:40 +0000284 return node;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000285}
286
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000287static char *add_name(char *buf, char *s, const char *name)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000288{
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000289 size_t len = strlen(name);
290 s -= len;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000291 if (s <= buf) {
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000292 fprintf(stderr, "fuse: path too long: ...%s\n", s + len);
293 return NULL;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000294 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000295 strncpy(s, name, len);
296 s--;
297 *s = '/';
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000298
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000299 return s;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000300}
301
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000302static char *get_path_name(struct fuse *f, fuse_ino_t nodeid, const char *name)
Miklos Szeredib483c932001-10-29 14:57:57 +0000303{
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000304 char buf[FUSE_MAX_PATH];
305 char *s = buf + FUSE_MAX_PATH - 1;
306 struct node *node;
Miklos Szeredie5183742005-02-02 11:14:04 +0000307
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000308 *s = '\0';
Miklos Szeredia181e612001-11-06 12:03:23 +0000309
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000310 if (name != NULL) {
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000311 s = add_name(buf, s, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000312 if (s == NULL)
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000313 return NULL;
314 }
315
316 pthread_mutex_lock(&f->lock);
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000317 for (node = get_node(f, nodeid); node && node->nodeid != FUSE_ROOT_ID;
318 node = get_node(f, node->parent)) {
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000319 if (node->name == NULL) {
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000320 s = NULL;
321 break;
322 }
Miklos Szeredie5183742005-02-02 11:14:04 +0000323
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000324 s = add_name(buf, s, node->name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000325 if (s == NULL)
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000326 break;
327 }
328 pthread_mutex_unlock(&f->lock);
329
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000330 if (node == NULL || s == NULL)
Miklos Szeredi5e183482001-10-31 14:52:35 +0000331 return NULL;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000332 else if (*s == '\0')
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000333 return strdup("/");
334 else
335 return strdup(s);
336}
Miklos Szeredia181e612001-11-06 12:03:23 +0000337
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000338static char *get_path(struct fuse *f, fuse_ino_t nodeid)
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000339{
Miklos Szeredia13d9002004-11-02 17:32:03 +0000340 return get_path_name(f, nodeid, NULL);
Miklos Szeredib483c932001-10-29 14:57:57 +0000341}
342
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000343static void forget_node(struct fuse *f, fuse_ino_t nodeid, uint64_t nlookup)
Miklos Szeredi38009022005-05-08 19:47:22 +0000344{
345 struct node *node;
346 if (nodeid == FUSE_ROOT_ID)
347 return;
348 pthread_mutex_lock(&f->lock);
349 node = get_node(f, nodeid);
350 assert(node->nlookup >= nlookup);
351 node->nlookup -= nlookup;
352 if (!node->nlookup) {
353 unhash_name(f, node);
354 unref_node(f, node);
355 }
356 pthread_mutex_unlock(&f->lock);
357}
358
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000359static void remove_node(struct fuse *f, fuse_ino_t dir, const char *name)
Miklos Szeredi5e183482001-10-31 14:52:35 +0000360{
Miklos Szeredia181e612001-11-06 12:03:23 +0000361 struct node *node;
362
363 pthread_mutex_lock(&f->lock);
Miklos Szeredif458b8c2004-12-07 16:46:42 +0000364 node = lookup_node(f, dir, name);
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000365 if (node != NULL)
366 unhash_name(f, node);
Miklos Szeredia181e612001-11-06 12:03:23 +0000367 pthread_mutex_unlock(&f->lock);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000368}
369
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000370static int rename_node(struct fuse *f, fuse_ino_t olddir, const char *oldname,
371 fuse_ino_t newdir, const char *newname, int hide)
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000372{
Miklos Szeredia181e612001-11-06 12:03:23 +0000373 struct node *node;
374 struct node *newnode;
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000375 int err = 0;
Miklos Szeredie5183742005-02-02 11:14:04 +0000376
Miklos Szeredia181e612001-11-06 12:03:23 +0000377 pthread_mutex_lock(&f->lock);
Miklos Szeredif458b8c2004-12-07 16:46:42 +0000378 node = lookup_node(f, olddir, oldname);
379 newnode = lookup_node(f, newdir, newname);
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000380 if (node == NULL)
381 goto out;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000382
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000383 if (newnode != NULL) {
384 if (hide) {
385 fprintf(stderr, "fuse: hidden file got created during hiding\n");
Miklos Szeredib2cf9562004-09-16 08:42:40 +0000386 err = -EBUSY;
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000387 goto out;
388 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000389 unhash_name(f, newnode);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000390 }
Miklos Szeredie5183742005-02-02 11:14:04 +0000391
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000392 unhash_name(f, node);
Miklos Szeredib2cf9562004-09-16 08:42:40 +0000393 if (hash_name(f, node, newdir, newname) == -1) {
394 err = -ENOMEM;
395 goto out;
396 }
Miklos Szeredie5183742005-02-02 11:14:04 +0000397
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000398 if (hide)
399 node->is_hidden = 1;
400
401 out:
Miklos Szeredia181e612001-11-06 12:03:23 +0000402 pthread_mutex_unlock(&f->lock);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000403 return err;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000404}
405
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000406static void set_stat(struct fuse *f, fuse_ino_t nodeid, struct stat *stbuf)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000407{
Miklos Szeredi659743b2005-12-09 17:41:42 +0000408 if (!f->conf.use_ino)
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000409 stbuf->st_ino = nodeid;
Miklos Szeredi659743b2005-12-09 17:41:42 +0000410 if (f->conf.set_mode)
411 stbuf->st_mode = (stbuf->st_mode & S_IFMT) | (0777 & ~f->conf.umask);
412 if (f->conf.set_uid)
413 stbuf->st_uid = f->conf.uid;
414 if (f->conf.set_gid)
415 stbuf->st_gid = f->conf.gid;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000416}
417
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000418static int is_open(struct fuse *f, fuse_ino_t dir, const char *name)
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000419{
420 struct node *node;
421 int isopen = 0;
422 pthread_mutex_lock(&f->lock);
Miklos Szeredif458b8c2004-12-07 16:46:42 +0000423 node = lookup_node(f, dir, name);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000424 if (node && node->open_count > 0)
425 isopen = 1;
426 pthread_mutex_unlock(&f->lock);
427 return isopen;
428}
429
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000430static char *hidden_name(struct fuse *f, fuse_ino_t dir, const char *oldname,
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000431 char *newname, size_t bufsize)
432{
433 struct stat buf;
434 struct node *node;
435 struct node *newnode;
436 char *newpath;
437 int res;
438 int failctr = 10;
439
440 if (!f->op.getattr)
441 return NULL;
442
443 do {
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000444 pthread_mutex_lock(&f->lock);
Miklos Szeredif458b8c2004-12-07 16:46:42 +0000445 node = lookup_node(f, dir, oldname);
446 if (node == NULL) {
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000447 pthread_mutex_unlock(&f->lock);
448 return NULL;
Miklos Szeredif458b8c2004-12-07 16:46:42 +0000449 }
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000450 do {
451 f->hidectr ++;
452 snprintf(newname, bufsize, ".fuse_hidden%08x%08x",
Miklos Szeredia13d9002004-11-02 17:32:03 +0000453 (unsigned int) node->nodeid, f->hidectr);
Miklos Szeredif458b8c2004-12-07 16:46:42 +0000454 newnode = lookup_node(f, dir, newname);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000455 } while(newnode);
456 pthread_mutex_unlock(&f->lock);
Miklos Szeredie5183742005-02-02 11:14:04 +0000457
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000458 newpath = get_path_name(f, dir, newname);
459 if (!newpath)
460 break;
Miklos Szeredie5183742005-02-02 11:14:04 +0000461
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000462 res = f->op.getattr(newpath, &buf);
463 if (res != 0)
464 break;
465 free(newpath);
466 newpath = NULL;
467 } while(--failctr);
468
469 return newpath;
470}
471
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000472static int hide_node(struct fuse *f, const char *oldpath, fuse_ino_t dir,
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000473 const char *oldname)
474{
475 char newname[64];
476 char *newpath;
Miklos Szeredib2cf9562004-09-16 08:42:40 +0000477 int err = -EBUSY;
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000478
Miklos Szeredib2cf9562004-09-16 08:42:40 +0000479 if (f->op.rename && f->op.unlink) {
480 newpath = hidden_name(f, dir, oldname, newname, sizeof(newname));
481 if (newpath) {
482 int res = f->op.rename(oldpath, newpath);
483 if (res == 0)
484 err = rename_node(f, dir, oldname, dir, newname, 1);
485 free(newpath);
486 }
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000487 }
Miklos Szeredib2cf9562004-09-16 08:42:40 +0000488 return err;
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000489}
490
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000491static int lookup_path(struct fuse *f, fuse_ino_t nodeid, const char *name,
Miklos Szeredif7eec032005-10-28 13:09:50 +0000492 const char *path, struct fuse_entry_param *e,
493 struct fuse_file_info *fi)
Miklos Szeredi76f65782004-02-19 16:55:40 +0000494{
495 int res;
Miklos Szeredi76f65782004-02-19 16:55:40 +0000496
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000497 memset(e, 0, sizeof(struct fuse_entry_param));
Miklos Szeredif7eec032005-10-28 13:09:50 +0000498 if (fi && f->op.fgetattr)
499 res = f->op.fgetattr(path, &e->attr, fi);
500 else
501 res = f->op.getattr(path, &e->attr);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000502 if (res == 0) {
Miklos Szeredi76f65782004-02-19 16:55:40 +0000503 struct node *node;
504
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000505 node = find_node(f, nodeid, name);
Miklos Szeredib2cf9562004-09-16 08:42:40 +0000506 if (node == NULL)
507 res = -ENOMEM;
508 else {
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000509 e->ino = node->nodeid;
510 e->generation = node->generation;
Miklos Szeredi659743b2005-12-09 17:41:42 +0000511 e->entry_timeout = f->conf.entry_timeout;
512 e->attr_timeout = f->conf.attr_timeout;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000513 set_stat(f, e->ino, &e->attr);
Miklos Szeredi659743b2005-12-09 17:41:42 +0000514 if (f->conf.debug) {
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000515 printf(" NODEID: %lu\n", (unsigned long) e->ino);
Miklos Szeredib2cf9562004-09-16 08:42:40 +0000516 fflush(stdout);
517 }
Miklos Szeredi76f65782004-02-19 16:55:40 +0000518 }
519 }
520 return res;
521}
522
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000523static struct fuse *req_fuse(fuse_req_t req)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000524{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000525 return (struct fuse *) fuse_req_userdata(req);
526}
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000527
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000528static struct fuse *req_fuse_prepare(fuse_req_t req)
529{
530 struct fuse_context *c = fuse_get_context();
531 const struct fuse_ctx *ctx = fuse_req_ctx(req);
532 c->fuse = req_fuse(req);
533 c->uid = ctx->uid;
534 c->gid = ctx->gid;
535 c->pid = ctx->pid;
536 c->private_data = c->fuse->user_data;
537
538 return c->fuse;
539}
540
541static inline void reply_err(fuse_req_t req, int err)
542{
543 /* fuse_reply_err() uses non-negated errno values */
544 fuse_reply_err(req, -err);
545}
546
547static void reply_entry(fuse_req_t req, const struct fuse_entry_param *e,
548 int err)
549{
550 if (!err) {
Miklos Szeredi9b813af2005-07-21 07:59:37 +0000551 if (fuse_reply_entry(req, e) == -ENOENT)
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000552 forget_node(req_fuse(req), e->ino, 1);
553 } else
554 reply_err(req, err);
555}
556
Miklos Szeredia1482422005-08-14 23:00:27 +0000557static void fuse_data_init(void *data)
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000558{
559 struct fuse *f = (struct fuse *) data;
Miklos Szeredi4f5df5e2005-10-07 12:39:58 +0000560 struct fuse_context *c = fuse_get_context();
561
562 memset(c, 0, sizeof(*c));
563 c->fuse = f;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000564
565 if (f->op.init)
566 f->user_data = f->op.init();
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000567}
568
569static void fuse_data_destroy(void *data)
570{
571 struct fuse *f = (struct fuse *) data;
Miklos Szeredi4f5df5e2005-10-07 12:39:58 +0000572 struct fuse_context *c = fuse_get_context();
573
574 memset(c, 0, sizeof(*c));
575 c->fuse = f;
576 c->private_data = f->user_data;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000577
578 if (f->op.destroy)
579 f->op.destroy(f->user_data);
580}
581
582static void fuse_lookup(fuse_req_t req, fuse_ino_t parent, const char *name)
583{
584 struct fuse *f = req_fuse_prepare(req);
585 struct fuse_entry_param e;
586 char *path;
587 int err;
588
589 err = -ENOENT;
Miklos Szeredic2a33ee2005-05-09 13:29:17 +0000590 pthread_rwlock_rdlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000591 path = get_path_name(f, parent, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000592 if (path != NULL) {
Miklos Szeredi659743b2005-12-09 17:41:42 +0000593 if (f->conf.debug) {
Miklos Szeredi6ebe2342002-01-06 21:44:16 +0000594 printf("LOOKUP %s\n", path);
595 fflush(stdout);
596 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000597 err = -ENOSYS;
Miklos Szeredi2b478112005-11-28 13:27:10 +0000598 if (f->op.getattr) {
Miklos Szeredif7eec032005-10-28 13:09:50 +0000599 err = lookup_path(f, parent, name, path, &e, NULL);
Miklos Szeredi659743b2005-12-09 17:41:42 +0000600 if (err == -ENOENT && f->conf.negative_timeout != 0.0) {
Miklos Szeredi2b478112005-11-28 13:27:10 +0000601 e.ino = 0;
Miklos Szeredi659743b2005-12-09 17:41:42 +0000602 e.entry_timeout = f->conf.negative_timeout;
Miklos Szeredi2b478112005-11-28 13:27:10 +0000603 err = 0;
604 }
605 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000606 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000607 }
Miklos Szeredic2a33ee2005-05-09 13:29:17 +0000608 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000609 reply_entry(req, &e, err);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000610}
611
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000612static void fuse_forget(fuse_req_t req, fuse_ino_t ino, unsigned long nlookup)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000613{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000614 struct fuse *f = req_fuse(req);
Miklos Szeredi659743b2005-12-09 17:41:42 +0000615 if (f->conf.debug) {
Miklos Szeredi3a770472005-11-11 21:32:42 +0000616 printf("FORGET %llu/%lu\n", (unsigned long long) ino, nlookup);
Miklos Szeredi43696432001-11-18 19:15:05 +0000617 fflush(stdout);
618 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000619 forget_node(f, ino, nlookup);
620 fuse_reply_none(req);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000621}
622
Miklos Szerediecce1bf2005-08-25 15:19:06 +0000623static void fuse_getattr(fuse_req_t req, fuse_ino_t ino,
624 struct fuse_file_info *fi)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000625{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000626 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000627 struct stat buf;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000628 char *path;
629 int err;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000630
Miklos Szerediecce1bf2005-08-25 15:19:06 +0000631 (void) fi;
632
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000633 err = -ENOENT;
Miklos Szeredic2a33ee2005-05-09 13:29:17 +0000634 pthread_rwlock_rdlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000635 path = get_path(f, ino);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000636 if (path != NULL) {
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000637 err = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000638 if (f->op.getattr)
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000639 err = f->op.getattr(path, &buf);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000640 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000641 }
Miklos Szeredic2a33ee2005-05-09 13:29:17 +0000642 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000643 if (!err) {
644 set_stat(f, ino, &buf);
Miklos Szeredi659743b2005-12-09 17:41:42 +0000645 fuse_reply_attr(req, &buf, f->conf.attr_timeout);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000646 } else
647 reply_err(req, err);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000648}
649
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000650static int do_chmod(struct fuse *f, const char *path, struct stat *attr)
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000651{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000652 int err;
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000653
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000654 err = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000655 if (f->op.chmod)
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000656 err = f->op.chmod(path, attr->st_mode);
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000657
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000658 return err;
Miklos Szeredie5183742005-02-02 11:14:04 +0000659}
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000660
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000661static int do_chown(struct fuse *f, const char *path, struct stat *attr,
Miklos Szeredi2e50d432001-12-20 12:17:25 +0000662 int valid)
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000663{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000664 int err;
665 uid_t uid = (valid & FUSE_SET_ATTR_UID) ? attr->st_uid : (uid_t) -1;
666 gid_t gid = (valid & FUSE_SET_ATTR_GID) ? attr->st_gid : (gid_t) -1;
Miklos Szeredie5183742005-02-02 11:14:04 +0000667
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000668 err = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000669 if (f->op.chown)
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000670 err = f->op.chown(path, uid, gid);
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000671
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000672 return err;
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000673}
674
Miklos Szeredi11509ce2005-10-26 16:04:04 +0000675static int do_truncate(struct fuse *f, const char *path, struct stat *attr,
676 struct fuse_file_info *fi)
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000677{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000678 int err;
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000679
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000680 err = -ENOSYS;
Miklos Szeredi11509ce2005-10-26 16:04:04 +0000681 if (fi && f->op.ftruncate)
682 err = f->op.ftruncate(path, attr->st_size, fi);
683 else if (f->op.truncate)
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000684 err = f->op.truncate(path, attr->st_size);
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000685
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000686 return err;
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000687}
688
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000689static int do_utime(struct fuse *f, const char *path, struct stat *attr)
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000690{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000691 int err;
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000692 struct utimbuf buf;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000693 buf.actime = attr->st_atime;
694 buf.modtime = attr->st_mtime;
695 err = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000696 if (f->op.utime)
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000697 err = f->op.utime(path, &buf);
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000698
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000699 return err;
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000700}
701
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000702static void fuse_setattr(fuse_req_t req, fuse_ino_t ino, struct stat *attr,
Miklos Szerediecce1bf2005-08-25 15:19:06 +0000703 int valid, struct fuse_file_info *fi)
Miklos Szeredi5e183482001-10-31 14:52:35 +0000704{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000705 struct fuse *f = req_fuse_prepare(req);
706 struct stat buf;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000707 char *path;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000708 int err;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000709
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000710 err = -ENOENT;
Miklos Szeredic2a33ee2005-05-09 13:29:17 +0000711 pthread_rwlock_rdlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000712 path = get_path(f, ino);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000713 if (path != NULL) {
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000714 err = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000715 if (f->op.getattr) {
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000716 err = 0;
717 if (!err && (valid & FUSE_SET_ATTR_MODE))
718 err = do_chmod(f, path, attr);
719 if (!err && (valid & (FUSE_SET_ATTR_UID | FUSE_SET_ATTR_GID)))
720 err = do_chown(f, path, attr, valid);
721 if (!err && (valid & FUSE_SET_ATTR_SIZE))
Miklos Szeredi11509ce2005-10-26 16:04:04 +0000722 err = do_truncate(f, path, attr, fi);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000723 if (!err && (valid & (FUSE_SET_ATTR_ATIME | FUSE_SET_ATTR_MTIME)) == (FUSE_SET_ATTR_ATIME | FUSE_SET_ATTR_MTIME))
724 err = do_utime(f, path, attr);
725 if (!err)
726 err = f->op.getattr(path, &buf);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000727 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000728 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000729 }
Miklos Szeredic2a33ee2005-05-09 13:29:17 +0000730 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000731 if (!err) {
732 set_stat(f, ino, &buf);
Miklos Szeredi659743b2005-12-09 17:41:42 +0000733 fuse_reply_attr(req, &buf, f->conf.attr_timeout);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000734 } else
735 reply_err(req, err);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000736}
737
Miklos Szeredib0b13d12005-10-26 12:53:25 +0000738static void fuse_access(fuse_req_t req, fuse_ino_t ino, int mask)
739{
740 struct fuse *f = req_fuse_prepare(req);
741 char *path;
742 int err;
743
744 err = -ENOENT;
745 pthread_rwlock_rdlock(&f->tree_lock);
746 path = get_path(f, ino);
747 if (path != NULL) {
Miklos Szeredi659743b2005-12-09 17:41:42 +0000748 if (f->conf.debug) {
Miklos Szeredib0b13d12005-10-26 12:53:25 +0000749 printf("ACCESS %s 0%o\n", path, mask);
750 fflush(stdout);
751 }
752 err = -ENOSYS;
753 if (f->op.access)
754 err = f->op.access(path, mask);
755 free(path);
756 }
757 pthread_rwlock_unlock(&f->tree_lock);
758 reply_err(req, err);
759}
760
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000761static void fuse_readlink(fuse_req_t req, fuse_ino_t ino)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000762{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000763 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredif6e0ec62005-08-03 09:11:06 +0000764 char linkname[PATH_MAX + 1];
Miklos Szeredib483c932001-10-29 14:57:57 +0000765 char *path;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000766 int err;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000767
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000768 err = -ENOENT;
Miklos Szeredic2a33ee2005-05-09 13:29:17 +0000769 pthread_rwlock_rdlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000770 path = get_path(f, ino);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000771 if (path != NULL) {
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000772 err = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000773 if (f->op.readlink)
Miklos Szeredif6e0ec62005-08-03 09:11:06 +0000774 err = f->op.readlink(path, linkname, sizeof(linkname));
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000775 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000776 }
Miklos Szeredic2a33ee2005-05-09 13:29:17 +0000777 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000778 if (!err) {
Miklos Szeredif6e0ec62005-08-03 09:11:06 +0000779 linkname[PATH_MAX] = '\0';
780 fuse_reply_readlink(req, linkname);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000781 } else
782 reply_err(req, err);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000783}
784
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000785static void fuse_mknod(fuse_req_t req, fuse_ino_t parent, const char *name,
786 mode_t mode, dev_t rdev)
Miklos Szeredib483c932001-10-29 14:57:57 +0000787{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000788 struct fuse *f = req_fuse_prepare(req);
789 struct fuse_entry_param e;
Miklos Szeredib483c932001-10-29 14:57:57 +0000790 char *path;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000791 int err;
Miklos Szeredib483c932001-10-29 14:57:57 +0000792
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000793 err = -ENOENT;
Miklos Szeredic2a33ee2005-05-09 13:29:17 +0000794 pthread_rwlock_rdlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000795 path = get_path_name(f, parent, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000796 if (path != NULL) {
Miklos Szeredi659743b2005-12-09 17:41:42 +0000797 if (f->conf.debug) {
Miklos Szeredi76f65782004-02-19 16:55:40 +0000798 printf("MKNOD %s\n", path);
799 fflush(stdout);
800 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000801 err = -ENOSYS;
Miklos Szeredib3f99722005-11-16 13:00:24 +0000802 if (S_ISREG(mode) && f->op.create && f->op.getattr) {
803 struct fuse_file_info fi;
804
805 memset(&fi, 0, sizeof(fi));
806 fi.flags = O_CREAT | O_EXCL | O_WRONLY;
807 err = f->op.create(path, mode, &fi);
808 if (!err) {
809 err = lookup_path(f, parent, name, path, &e, &fi);
810 if (f->op.release)
811 f->op.release(path, &fi);
812 }
813 } else if (f->op.mknod && f->op.getattr) {
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000814 err = f->op.mknod(path, mode, rdev);
815 if (!err)
Miklos Szeredif7eec032005-10-28 13:09:50 +0000816 err = lookup_path(f, parent, name, path, &e, NULL);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000817 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000818 free(path);
Miklos Szeredib483c932001-10-29 14:57:57 +0000819 }
Miklos Szeredic2a33ee2005-05-09 13:29:17 +0000820 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000821 reply_entry(req, &e, err);
Miklos Szeredib483c932001-10-29 14:57:57 +0000822}
823
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000824static void fuse_mkdir(fuse_req_t req, fuse_ino_t parent, const char *name,
825 mode_t mode)
Miklos Szeredib483c932001-10-29 14:57:57 +0000826{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000827 struct fuse *f = req_fuse_prepare(req);
828 struct fuse_entry_param e;
Miklos Szeredib483c932001-10-29 14:57:57 +0000829 char *path;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000830 int err;
Miklos Szeredib483c932001-10-29 14:57:57 +0000831
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000832 err = -ENOENT;
Miklos Szeredic2a33ee2005-05-09 13:29:17 +0000833 pthread_rwlock_rdlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000834 path = get_path_name(f, parent, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000835 if (path != NULL) {
Miklos Szeredi659743b2005-12-09 17:41:42 +0000836 if (f->conf.debug) {
Miklos Szeredi76f65782004-02-19 16:55:40 +0000837 printf("MKDIR %s\n", path);
838 fflush(stdout);
839 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000840 err = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000841 if (f->op.mkdir && f->op.getattr) {
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000842 err = f->op.mkdir(path, mode);
843 if (!err)
Miklos Szeredif7eec032005-10-28 13:09:50 +0000844 err = lookup_path(f, parent, name, path, &e, NULL);
Miklos Szeredi76f65782004-02-19 16:55:40 +0000845 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000846 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000847 }
Miklos Szeredic2a33ee2005-05-09 13:29:17 +0000848 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000849 reply_entry(req, &e, err);
Miklos Szeredib483c932001-10-29 14:57:57 +0000850}
851
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000852static void fuse_unlink(fuse_req_t req, fuse_ino_t parent, const char *name)
Miklos Szeredib483c932001-10-29 14:57:57 +0000853{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000854 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredib483c932001-10-29 14:57:57 +0000855 char *path;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000856 int err;
Miklos Szeredib483c932001-10-29 14:57:57 +0000857
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000858 err = -ENOENT;
Miklos Szeredic2a33ee2005-05-09 13:29:17 +0000859 pthread_rwlock_wrlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000860 path = get_path_name(f, parent, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000861 if (path != NULL) {
Miklos Szeredi659743b2005-12-09 17:41:42 +0000862 if (f->conf.debug) {
Miklos Szeredi209f5d02004-07-24 19:56:16 +0000863 printf("UNLINK %s\n", path);
864 fflush(stdout);
865 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000866 err = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000867 if (f->op.unlink) {
Miklos Szeredi659743b2005-12-09 17:41:42 +0000868 if (!f->conf.hard_remove && is_open(f, parent, name))
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000869 err = hide_node(f, path, parent, name);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000870 else {
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000871 err = f->op.unlink(path);
872 if (!err)
873 remove_node(f, parent, name);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000874 }
Miklos Szeredi5e183482001-10-31 14:52:35 +0000875 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000876 free(path);
Miklos Szeredib483c932001-10-29 14:57:57 +0000877 }
Miklos Szeredic2a33ee2005-05-09 13:29:17 +0000878 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000879 reply_err(req, err);
Miklos Szeredib5958612004-02-20 14:10:49 +0000880}
881
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000882static void fuse_rmdir(fuse_req_t req, fuse_ino_t parent, const char *name)
Miklos Szeredib5958612004-02-20 14:10:49 +0000883{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000884 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredib5958612004-02-20 14:10:49 +0000885 char *path;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000886 int err;
Miklos Szeredib5958612004-02-20 14:10:49 +0000887
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000888 err = -ENOENT;
Miklos Szeredic2a33ee2005-05-09 13:29:17 +0000889 pthread_rwlock_wrlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000890 path = get_path_name(f, parent, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000891 if (path != NULL) {
Miklos Szeredi659743b2005-12-09 17:41:42 +0000892 if (f->conf.debug) {
Miklos Szeredi209f5d02004-07-24 19:56:16 +0000893 printf("RMDIR %s\n", path);
894 fflush(stdout);
895 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000896 err = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000897 if (f->op.rmdir) {
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000898 err = f->op.rmdir(path);
899 if (!err)
900 remove_node(f, parent, name);
Miklos Szeredib5958612004-02-20 14:10:49 +0000901 }
902 free(path);
903 }
Miklos Szeredic2a33ee2005-05-09 13:29:17 +0000904 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000905 reply_err(req, err);
Miklos Szeredib483c932001-10-29 14:57:57 +0000906}
907
Miklos Szeredif6e0ec62005-08-03 09:11:06 +0000908static void fuse_symlink(fuse_req_t req, const char *linkname,
909 fuse_ino_t parent, const char *name)
Miklos Szeredib483c932001-10-29 14:57:57 +0000910{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000911 struct fuse *f = req_fuse_prepare(req);
912 struct fuse_entry_param e;
Miklos Szeredib483c932001-10-29 14:57:57 +0000913 char *path;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000914 int err;
Miklos Szeredib483c932001-10-29 14:57:57 +0000915
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000916 err = -ENOENT;
Miklos Szeredic2a33ee2005-05-09 13:29:17 +0000917 pthread_rwlock_rdlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000918 path = get_path_name(f, parent, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000919 if (path != NULL) {
Miklos Szeredi659743b2005-12-09 17:41:42 +0000920 if (f->conf.debug) {
Miklos Szeredi76f65782004-02-19 16:55:40 +0000921 printf("SYMLINK %s\n", path);
922 fflush(stdout);
923 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000924 err = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000925 if (f->op.symlink && f->op.getattr) {
Miklos Szeredif6e0ec62005-08-03 09:11:06 +0000926 err = f->op.symlink(linkname, path);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000927 if (!err)
Miklos Szeredif7eec032005-10-28 13:09:50 +0000928 err = lookup_path(f, parent, name, path, &e, NULL);
Miklos Szeredi76f65782004-02-19 16:55:40 +0000929 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000930 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000931 }
Miklos Szeredic2a33ee2005-05-09 13:29:17 +0000932 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000933 reply_entry(req, &e, err);
Miklos Szeredib483c932001-10-29 14:57:57 +0000934}
935
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000936static void fuse_rename(fuse_req_t req, fuse_ino_t olddir, const char *oldname,
937 fuse_ino_t newdir, const char *newname)
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000938{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000939 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000940 char *oldpath;
941 char *newpath;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000942 int err;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000943
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000944 err = -ENOENT;
Miklos Szeredic2a33ee2005-05-09 13:29:17 +0000945 pthread_rwlock_wrlock(&f->tree_lock);
Miklos Szeredia181e612001-11-06 12:03:23 +0000946 oldpath = get_path_name(f, olddir, oldname);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000947 if (oldpath != NULL) {
Miklos Szeredia181e612001-11-06 12:03:23 +0000948 newpath = get_path_name(f, newdir, newname);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000949 if (newpath != NULL) {
Miklos Szeredi659743b2005-12-09 17:41:42 +0000950 if (f->conf.debug) {
Miklos Szeredi209f5d02004-07-24 19:56:16 +0000951 printf("RENAME %s -> %s\n", oldpath, newpath);
952 fflush(stdout);
953 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000954 err = -ENOSYS;
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000955 if (f->op.rename) {
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000956 err = 0;
Miklos Szeredi659743b2005-12-09 17:41:42 +0000957 if (!f->conf.hard_remove &&
Miklos Szeredi2529ca22004-07-13 15:36:52 +0000958 is_open(f, newdir, newname))
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000959 err = hide_node(f, newpath, newdir, newname);
960 if (!err) {
961 err = f->op.rename(oldpath, newpath);
962 if (!err)
963 err = rename_node(f, olddir, oldname, newdir, newname, 0);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000964 }
965 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000966 free(newpath);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000967 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000968 free(oldpath);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000969 }
Miklos Szeredic2a33ee2005-05-09 13:29:17 +0000970 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000971 reply_err(req, err);
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000972}
973
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000974static void fuse_link(fuse_req_t req, fuse_ino_t ino, fuse_ino_t newparent,
975 const char *newname)
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000976{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000977 struct fuse *f = req_fuse_prepare(req);
978 struct fuse_entry_param e;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000979 char *oldpath;
980 char *newpath;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000981 int err;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000982
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000983 err = -ENOENT;
Miklos Szeredic2a33ee2005-05-09 13:29:17 +0000984 pthread_rwlock_rdlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000985 oldpath = get_path(f, ino);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000986 if (oldpath != NULL) {
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000987 newpath = get_path_name(f, newparent, newname);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000988 if (newpath != NULL) {
Miklos Szeredi659743b2005-12-09 17:41:42 +0000989 if (f->conf.debug) {
Miklos Szeredi76f65782004-02-19 16:55:40 +0000990 printf("LINK %s\n", newpath);
991 fflush(stdout);
992 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000993 err = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000994 if (f->op.link && f->op.getattr) {
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000995 err = f->op.link(oldpath, newpath);
996 if (!err)
Miklos Szeredif7eec032005-10-28 13:09:50 +0000997 err = lookup_path(f, newparent, newname, newpath, &e, NULL);
Miklos Szeredi76f65782004-02-19 16:55:40 +0000998 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000999 free(newpath);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001000 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001001 free(oldpath);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001002 }
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001003 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001004 reply_entry(req, &e, err);
Miklos Szeredi19dff1b2001-10-30 15:06:52 +00001005}
1006
Miklos Szeredid9079a72005-10-26 15:29:06 +00001007static void fuse_create(fuse_req_t req, fuse_ino_t parent, const char *name,
1008 mode_t mode, struct fuse_file_info *fi)
1009{
1010 struct fuse *f = req_fuse_prepare(req);
1011 struct fuse_entry_param e;
1012 char *path;
1013 int err;
1014
1015 err = -ENOENT;
1016 pthread_rwlock_rdlock(&f->tree_lock);
1017 path = get_path_name(f, parent, name);
1018 if (path != NULL) {
1019 err = -ENOSYS;
1020 if (f->op.create && f->op.getattr) {
1021 err = f->op.create(path, mode, fi);
1022 if (!err) {
Miklos Szeredi659743b2005-12-09 17:41:42 +00001023 if (f->conf.debug) {
Miklos Szeredi3a770472005-11-11 21:32:42 +00001024 printf("CREATE[%llu] flags: 0x%x %s\n",
1025 (unsigned long long) fi->fh, fi->flags, path);
Miklos Szeredid9079a72005-10-26 15:29:06 +00001026 fflush(stdout);
1027 }
Miklos Szeredif7eec032005-10-28 13:09:50 +00001028 err = lookup_path(f, parent, name, path, &e, fi);
Miklos Szeredid9079a72005-10-26 15:29:06 +00001029 if (err) {
1030 if (f->op.release)
1031 f->op.release(path, fi);
1032 } else if (!S_ISREG(e.attr.st_mode)) {
1033 err = -EIO;
1034 if (f->op.release)
1035 f->op.release(path, fi);
1036 forget_node(f, e.ino, 1);
1037 }
1038 }
1039 }
1040 }
1041
1042 if (!err) {
Miklos Szeredi659743b2005-12-09 17:41:42 +00001043 if (f->conf.direct_io)
Miklos Szeredid9079a72005-10-26 15:29:06 +00001044 fi->direct_io = 1;
Miklos Szeredi659743b2005-12-09 17:41:42 +00001045 if (f->conf.kernel_cache)
Miklos Szeredid9079a72005-10-26 15:29:06 +00001046 fi->keep_cache = 1;
1047
1048 pthread_mutex_lock(&f->lock);
1049 if (fuse_reply_create(req, &e, fi) == -ENOENT) {
1050 /* The open syscall was interrupted, so it must be cancelled */
1051 if(f->op.release)
1052 f->op.release(path, fi);
1053 forget_node(f, e.ino, 1);
1054 } else {
1055 struct node *node = get_node(f, e.ino);
1056 node->open_count ++;
1057 }
1058 pthread_mutex_unlock(&f->lock);
1059 } else
1060 reply_err(req, err);
1061
1062 if (path)
1063 free(path);
1064 pthread_rwlock_unlock(&f->tree_lock);
1065}
1066
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001067static void fuse_open(fuse_req_t req, fuse_ino_t ino,
1068 struct fuse_file_info *fi)
Miklos Szeredi5e183482001-10-31 14:52:35 +00001069{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001070 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredi31066bb2005-08-01 14:49:31 +00001071 char *path = NULL;
1072 int err = 0;
Miklos Szeredi5e183482001-10-31 14:52:35 +00001073
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001074 pthread_rwlock_rdlock(&f->tree_lock);
Miklos Szeredi31066bb2005-08-01 14:49:31 +00001075 if (f->op.open) {
1076 err = -ENOENT;
1077 path = get_path(f, ino);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00001078 if (path != NULL)
1079 err = fuse_do_open(f, path, fi);
Miklos Szeredi40b9a5a2002-12-10 16:09:02 +00001080 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001081 if (!err) {
Miklos Szeredi659743b2005-12-09 17:41:42 +00001082 if (f->conf.debug) {
Miklos Szeredi3a770472005-11-11 21:32:42 +00001083 printf("OPEN[%llu] flags: 0x%x\n", (unsigned long long) fi->fh,
1084 fi->flags);
Miklos Szeredi209f5d02004-07-24 19:56:16 +00001085 fflush(stdout);
1086 }
Miklos Szeredie5183742005-02-02 11:14:04 +00001087
Miklos Szeredi659743b2005-12-09 17:41:42 +00001088 if (f->conf.direct_io)
Miklos Szeredie77cc072005-08-01 11:58:51 +00001089 fi->direct_io = 1;
Miklos Szeredi659743b2005-12-09 17:41:42 +00001090 if (f->conf.kernel_cache)
Miklos Szeredie77cc072005-08-01 11:58:51 +00001091 fi->keep_cache = 1;
1092
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001093 pthread_mutex_lock(&f->lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001094 if (fuse_reply_open(req, fi) == -ENOENT) {
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001095 /* The open syscall was interrupted, so it must be cancelled */
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00001096 if(f->op.release && path != NULL)
1097 fuse_do_release(f, path, fi);
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001098 } else {
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001099 struct node *node = get_node(f, ino);
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001100 node->open_count ++;
1101 }
Miklos Szeredi73798f92004-07-12 15:55:11 +00001102 pthread_mutex_unlock(&f->lock);
Miklos Szeredi73798f92004-07-12 15:55:11 +00001103 } else
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001104 reply_err(req, err);
Miklos Szeredi73798f92004-07-12 15:55:11 +00001105
Miklos Szeredi9a31cca2004-06-26 21:11:25 +00001106 if (path)
1107 free(path);
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001108 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001109}
1110
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001111static void fuse_read(fuse_req_t req, fuse_ino_t ino, size_t size, off_t off,
1112 struct fuse_file_info *fi)
Miklos Szeredie2e4ac22004-05-18 08:45:28 +00001113{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001114 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredie2e4ac22004-05-18 08:45:28 +00001115 char *path;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001116 char *buf;
Miklos Szeredie2e4ac22004-05-18 08:45:28 +00001117 int res;
1118
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001119 buf = (char *) malloc(size);
1120 if (buf == NULL) {
1121 reply_err(req, -ENOMEM);
1122 return;
1123 }
1124
Miklos Szeredie2e4ac22004-05-18 08:45:28 +00001125 res = -ENOENT;
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001126 pthread_rwlock_rdlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001127 path = get_path(f, ino);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001128 if (path != NULL) {
Miklos Szeredi659743b2005-12-09 17:41:42 +00001129 if (f->conf.debug) {
Miklos Szeredi3a770472005-11-11 21:32:42 +00001130 printf("READ[%llu] %u bytes from %llu\n",
1131 (unsigned long long) fi->fh, size, off);
Miklos Szeredi209f5d02004-07-24 19:56:16 +00001132 fflush(stdout);
1133 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001134
Miklos Szeredie2e4ac22004-05-18 08:45:28 +00001135 res = -ENOSYS;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001136 if (f->op.read)
1137 res = f->op.read(path, buf, size, off, fi);
Miklos Szeredie2e4ac22004-05-18 08:45:28 +00001138 free(path);
1139 }
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001140 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001141
1142 if (res >= 0) {
Miklos Szeredi659743b2005-12-09 17:41:42 +00001143 if (f->conf.debug) {
Miklos Szeredi3a770472005-11-11 21:32:42 +00001144 printf(" READ[%llu] %u bytes\n", (unsigned long long) fi->fh,
1145 res);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001146 fflush(stdout);
1147 }
Miklos Szeredif412d072005-10-14 21:24:32 +00001148 if ((size_t) res > size)
1149 fprintf(stderr, "fuse: read too many bytes");
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001150 fuse_reply_buf(req, buf, res);
1151 } else
1152 reply_err(req, res);
1153
1154 free(buf);
Miklos Szeredie2e4ac22004-05-18 08:45:28 +00001155}
1156
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001157static void fuse_write(fuse_req_t req, fuse_ino_t ino, const char *buf,
1158 size_t size, off_t off, struct fuse_file_info *fi)
Miklos Szeredic8ba2372002-12-10 12:26:00 +00001159{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001160 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001161 char *path;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001162 int res;
1163
1164 res = -ENOENT;
1165 pthread_rwlock_rdlock(&f->tree_lock);
1166 path = get_path(f, ino);
1167 if (path != NULL) {
Miklos Szeredi659743b2005-12-09 17:41:42 +00001168 if (f->conf.debug) {
Miklos Szeredi3a770472005-11-11 21:32:42 +00001169 printf("WRITE%s[%llu] %u bytes to %llu\n",
1170 fi->writepage ? "PAGE" : "", (unsigned long long) fi->fh,
1171 size, off);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001172 fflush(stdout);
1173 }
1174
1175 res = -ENOSYS;
1176 if (f->op.write)
1177 res = f->op.write(path, buf, size, off, fi);
1178 free(path);
1179 }
1180 pthread_rwlock_unlock(&f->tree_lock);
1181
Miklos Szeredif412d072005-10-14 21:24:32 +00001182 if (res >= 0) {
Miklos Szeredi659743b2005-12-09 17:41:42 +00001183 if (f->conf.debug) {
Miklos Szeredi3a770472005-11-11 21:32:42 +00001184 printf(" WRITE%s[%llu] %u bytes\n",
1185 fi->writepage ? "PAGE" : "", (unsigned long long) fi->fh,
1186 res);
Miklos Szeredif412d072005-10-14 21:24:32 +00001187 fflush(stdout);
1188 }
1189 if ((size_t) res > size)
1190 fprintf(stderr, "fuse: wrote too many bytes");
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001191 fuse_reply_write(req, res);
Miklos Szeredif412d072005-10-14 21:24:32 +00001192 } else
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001193 reply_err(req, res);
1194}
1195
1196static void fuse_flush(fuse_req_t req, fuse_ino_t ino,
1197 struct fuse_file_info *fi)
1198{
1199 struct fuse *f = req_fuse_prepare(req);
1200 char *path;
1201 int err;
1202
1203 err = -ENOENT;
1204 pthread_rwlock_rdlock(&f->tree_lock);
1205 path = get_path(f, ino);
1206 if (path != NULL) {
Miklos Szeredi659743b2005-12-09 17:41:42 +00001207 if (f->conf.debug) {
Miklos Szeredi3a770472005-11-11 21:32:42 +00001208 printf("FLUSH[%llu]\n", (unsigned long long) fi->fh);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001209 fflush(stdout);
1210 }
1211 err = -ENOSYS;
1212 if (f->op.flush)
1213 err = f->op.flush(path, fi);
1214 free(path);
1215 }
1216 pthread_rwlock_unlock(&f->tree_lock);
1217 reply_err(req, err);
1218}
1219
1220static void fuse_release(fuse_req_t req, fuse_ino_t ino,
1221 struct fuse_file_info *fi)
1222{
1223 struct fuse *f = req_fuse_prepare(req);
1224 char *path;
1225 struct node *node;
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001226 int unlink_hidden;
Miklos Szeredifb28c5e2004-11-26 12:15:06 +00001227
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001228 pthread_mutex_lock(&f->lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001229 node = get_node(f, ino);
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001230 assert(node->open_count > 0);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001231 --node->open_count;
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001232 unlink_hidden = (node->is_hidden && !node->open_count);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001233 pthread_mutex_unlock(&f->lock);
1234
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001235 pthread_rwlock_rdlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001236 path = get_path(f, ino);
Miklos Szeredi659743b2005-12-09 17:41:42 +00001237 if (f->conf.debug) {
Miklos Szeredi3a770472005-11-11 21:32:42 +00001238 printf("RELEASE[%llu] flags: 0x%x\n", (unsigned long long) fi->fh,
1239 fi->flags);
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001240 fflush(stdout);
Miklos Szeredic8ba2372002-12-10 12:26:00 +00001241 }
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00001242 if (f->op.release)
1243 fuse_do_release(f, path, fi);
Miklos Szeredie5183742005-02-02 11:14:04 +00001244
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001245 if(unlink_hidden && path)
1246 f->op.unlink(path);
Miklos Szeredie5183742005-02-02 11:14:04 +00001247
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001248 if (path)
1249 free(path);
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001250 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001251
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001252 reply_err(req, 0);
Miklos Szeredic8ba2372002-12-10 12:26:00 +00001253}
1254
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001255static void fuse_fsync(fuse_req_t req, fuse_ino_t ino, int datasync,
1256 struct fuse_file_info *fi)
Miklos Szeredi5e183482001-10-31 14:52:35 +00001257{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001258 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001259 char *path;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001260 int err;
Miklos Szerediab974562005-04-07 15:40:21 +00001261
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001262 err = -ENOENT;
1263 pthread_rwlock_rdlock(&f->tree_lock);
1264 path = get_path(f, ino);
1265 if (path != NULL) {
Miklos Szeredi659743b2005-12-09 17:41:42 +00001266 if (f->conf.debug) {
Miklos Szeredi3a770472005-11-11 21:32:42 +00001267 printf("FSYNC[%llu]\n", (unsigned long long) fi->fh);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001268 fflush(stdout);
1269 }
1270 err = -ENOSYS;
1271 if (f->op.fsync)
1272 err = f->op.fsync(path, datasync, fi);
1273 free(path);
1274 }
1275 pthread_rwlock_unlock(&f->tree_lock);
1276 reply_err(req, err);
1277}
1278
1279static struct fuse_dirhandle *get_dirhandle(const struct fuse_file_info *llfi,
1280 struct fuse_file_info *fi)
1281{
Miklos Szeredi3a770472005-11-11 21:32:42 +00001282 struct fuse_dirhandle *dh = (struct fuse_dirhandle *) (uintptr_t) llfi->fh;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001283 memset(fi, 0, sizeof(struct fuse_file_info));
1284 fi->fh = dh->fh;
Miklos Szerediead7f102005-11-28 16:02:27 +00001285 fi->fh_old = dh->fh;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001286 return dh;
1287}
1288
1289static void fuse_opendir(fuse_req_t req, fuse_ino_t ino,
1290 struct fuse_file_info *llfi)
1291{
1292 struct fuse *f = req_fuse_prepare(req);
1293 struct fuse_dirhandle *dh;
1294
1295 dh = (struct fuse_dirhandle *) malloc(sizeof(struct fuse_dirhandle));
1296 if (dh == NULL) {
1297 reply_err(req, -ENOMEM);
Miklos Szerediab974562005-04-07 15:40:21 +00001298 return;
Miklos Szeredi5e183482001-10-31 14:52:35 +00001299 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001300 memset(dh, 0, sizeof(struct fuse_dirhandle));
1301 dh->fuse = f;
1302 dh->contents = NULL;
1303 dh->len = 0;
1304 dh->filled = 0;
1305 dh->nodeid = ino;
1306 mutex_init(&dh->lock);
Miklos Szerediab974562005-04-07 15:40:21 +00001307
Miklos Szeredi3a770472005-11-11 21:32:42 +00001308 llfi->fh = (uintptr_t) dh;
Miklos Szerediab974562005-04-07 15:40:21 +00001309
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001310 if (f->op.opendir) {
1311 struct fuse_file_info fi;
1312 char *path;
1313 int err;
1314
1315 memset(&fi, 0, sizeof(fi));
1316 fi.flags = llfi->flags;
1317
1318 err = -ENOENT;
1319 pthread_rwlock_rdlock(&f->tree_lock);
1320 path = get_path(f, ino);
1321 if (path != NULL) {
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00001322 err = fuse_do_opendir(f, path, &fi);
1323 dh->fh = fi.fh;
Miklos Szerediab974562005-04-07 15:40:21 +00001324 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001325 if (!err) {
1326 pthread_mutex_lock(&f->lock);
1327 if (fuse_reply_open(req, llfi) == -ENOENT) {
1328 /* The opendir syscall was interrupted, so it must be
1329 cancelled */
1330 if(f->op.releasedir)
1331 f->op.releasedir(path, &fi);
1332 pthread_mutex_destroy(&dh->lock);
1333 free(dh);
1334 }
1335 pthread_mutex_unlock(&f->lock);
1336 } else {
1337 reply_err(req, err);
1338 free(dh);
1339 }
Miklos Szerediab974562005-04-07 15:40:21 +00001340 free(path);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001341 pthread_rwlock_unlock(&f->tree_lock);
1342 } else
1343 fuse_reply_open(req, llfi);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001344}
Miklos Szeredib483c932001-10-29 14:57:57 +00001345
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001346static int fill_dir_common(struct fuse_dirhandle *dh, const char *name,
Miklos Szeredif6e0ec62005-08-03 09:11:06 +00001347 const struct stat *statp, off_t off)
Miklos Szeredia181e612001-11-06 12:03:23 +00001348{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001349 struct stat stbuf;
1350 unsigned namelen = strlen(name);
1351 unsigned entsize;
1352 unsigned newlen;
Miklos Szeredifb28c5e2004-11-26 12:15:06 +00001353
Miklos Szeredif6e0ec62005-08-03 09:11:06 +00001354 if (statp)
1355 stbuf = *statp;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001356 else {
1357 memset(&stbuf, 0, sizeof(stbuf));
Miklos Szeredie248e4b2005-12-14 16:18:32 +00001358 stbuf.st_ino = FUSE_UNKNOWN_INO;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001359 }
Miklos Szeredia181e612001-11-06 12:03:23 +00001360
Miklos Szeredi659743b2005-12-09 17:41:42 +00001361 if (!dh->fuse->conf.use_ino) {
Miklos Szeredie248e4b2005-12-14 16:18:32 +00001362 stbuf.st_ino = FUSE_UNKNOWN_INO;
Miklos Szeredi659743b2005-12-09 17:41:42 +00001363 if (dh->fuse->conf.readdir_ino) {
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001364 struct node *node;
1365 pthread_mutex_lock(&dh->fuse->lock);
1366 node = lookup_node(dh->fuse, dh->nodeid, name);
1367 if (node)
1368 stbuf.st_ino = (ino_t) node->nodeid;
1369 pthread_mutex_unlock(&dh->fuse->lock);
Miklos Szeredi6ebe2342002-01-06 21:44:16 +00001370 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001371 }
Miklos Szeredi6ebe2342002-01-06 21:44:16 +00001372
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001373 entsize = fuse_dirent_size(namelen);
1374 newlen = dh->len + entsize;
1375
1376 if (off) {
1377 dh->filled = 0;
1378 if (newlen > dh->needlen)
1379 return 1;
1380 }
1381
Miklos Szeredic4c12ae2005-10-20 14:48:50 +00001382 if (newlen > dh->size) {
1383 char *newptr;
1384
1385 if (!dh->size)
1386 dh->size = 1024;
1387 while (newlen > dh->size)
1388 dh->size *= 2;
1389
1390 newptr = (char *) realloc(dh->contents, dh->size);
1391 if (!newptr) {
1392 dh->error = -ENOMEM;
1393 return 1;
1394 }
1395 dh->contents = newptr;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001396 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001397 fuse_add_dirent(dh->contents + dh->len, name, &stbuf, off ? off : newlen);
1398 dh->len = newlen;
1399 return 0;
1400}
1401
Miklos Szeredif6e0ec62005-08-03 09:11:06 +00001402static int fill_dir(void *buf, const char *name, const struct stat *stbuf,
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001403 off_t off)
1404{
Miklos Szeredif6e0ec62005-08-03 09:11:06 +00001405 return fill_dir_common((struct fuse_dirhandle *) buf, name, stbuf, off);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001406}
1407
1408static int fill_dir_old(struct fuse_dirhandle *dh, const char *name, int type,
1409 ino_t ino)
1410{
1411 struct stat stbuf;
1412
1413 memset(&stbuf, 0, sizeof(stbuf));
1414 stbuf.st_mode = type << 12;
1415 stbuf.st_ino = ino;
1416
1417 fill_dir_common(dh, name, &stbuf, 0);
1418 return dh->error;
1419}
1420
1421static int readdir_fill(struct fuse *f, fuse_ino_t ino, size_t size,
1422 off_t off, struct fuse_dirhandle *dh,
1423 struct fuse_file_info *fi)
1424{
1425 int err = -ENOENT;
1426 char *path;
1427 pthread_rwlock_rdlock(&f->tree_lock);
1428 path = get_path(f, ino);
1429 if (path != NULL) {
1430 dh->len = 0;
1431 dh->error = 0;
1432 dh->needlen = size;
1433 dh->filled = 1;
1434 err = -ENOSYS;
1435 if (f->op.readdir)
1436 err = f->op.readdir(path, dh, fill_dir, off, fi);
1437 else if (f->op.getdir)
1438 err = f->op.getdir(path, dh, fill_dir_old);
1439 if (!err)
1440 err = dh->error;
1441 if (err)
1442 dh->filled = 0;
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001443 free(path);
Miklos Szeredia181e612001-11-06 12:03:23 +00001444 }
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001445 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001446 return err;
1447}
Miklos Szeredie5183742005-02-02 11:14:04 +00001448
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001449static void fuse_readdir(fuse_req_t req, fuse_ino_t ino, size_t size,
1450 off_t off, struct fuse_file_info *llfi)
1451{
1452 struct fuse *f = req_fuse_prepare(req);
1453 struct fuse_file_info fi;
1454 struct fuse_dirhandle *dh = get_dirhandle(llfi, &fi);
1455
1456 pthread_mutex_lock(&dh->lock);
Miklos Szeredi77ccf652005-08-19 14:40:27 +00001457 /* According to SUS, directory contents need to be refreshed on
1458 rewinddir() */
1459 if (!off)
1460 dh->filled = 0;
1461
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001462 if (!dh->filled) {
1463 int err = readdir_fill(f, ino, size, off, dh, &fi);
1464 if (err) {
1465 reply_err(req, err);
1466 goto out;
1467 }
Miklos Szeredia181e612001-11-06 12:03:23 +00001468 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001469 if (dh->filled) {
1470 if (off < dh->len) {
1471 if (off + size > dh->len)
1472 size = dh->len - off;
1473 } else
1474 size = 0;
1475 } else {
1476 size = dh->len;
1477 off = 0;
1478 }
1479 fuse_reply_buf(req, dh->contents + off, size);
1480 out:
1481 pthread_mutex_unlock(&dh->lock);
1482}
Miklos Szeredia181e612001-11-06 12:03:23 +00001483
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001484static void fuse_releasedir(fuse_req_t req, fuse_ino_t ino,
1485 struct fuse_file_info *llfi)
1486{
1487 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredi9b813af2005-07-21 07:59:37 +00001488 struct fuse_file_info fi;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001489 struct fuse_dirhandle *dh = get_dirhandle(llfi, &fi);
1490 if (f->op.releasedir) {
1491 char *path;
1492
1493 pthread_rwlock_rdlock(&f->tree_lock);
1494 path = get_path(f, ino);
1495 f->op.releasedir(path ? path : "-", &fi);
1496 free(path);
1497 pthread_rwlock_unlock(&f->tree_lock);
1498 }
1499 pthread_mutex_lock(&dh->lock);
1500 pthread_mutex_unlock(&dh->lock);
1501 pthread_mutex_destroy(&dh->lock);
1502 free(dh->contents);
1503 free(dh);
1504 reply_err(req, 0);
1505}
1506
1507static void fuse_fsyncdir(fuse_req_t req, fuse_ino_t ino, int datasync,
1508 struct fuse_file_info *llfi)
1509{
1510 struct fuse *f = req_fuse_prepare(req);
1511 struct fuse_file_info fi;
1512 char *path;
1513 int err;
1514
1515 get_dirhandle(llfi, &fi);
1516
1517 err = -ENOENT;
1518 pthread_rwlock_rdlock(&f->tree_lock);
1519 path = get_path(f, ino);
1520 if (path != NULL) {
1521 err = -ENOSYS;
1522 if (f->op.fsyncdir)
1523 err = f->op.fsyncdir(path, datasync, &fi);
1524 free(path);
1525 }
1526 pthread_rwlock_unlock(&f->tree_lock);
1527 reply_err(req, err);
Miklos Szeredia181e612001-11-06 12:03:23 +00001528}
1529
Miklos Szeredi52cb09d2005-11-07 11:59:00 +00001530static int default_statfs(struct statvfs *buf)
Miklos Szeredi77f39942004-03-25 11:17:52 +00001531{
Miklos Szeredi52cb09d2005-11-07 11:59:00 +00001532 buf->f_namemax = 255;
Miklos Szeredi77f39942004-03-25 11:17:52 +00001533 buf->f_bsize = 512;
1534 return 0;
1535}
1536
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001537static void fuse_statfs(fuse_req_t req)
Miklos Szeredi18e75e42004-02-19 14:23:27 +00001538{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001539 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredi52cb09d2005-11-07 11:59:00 +00001540 struct statvfs buf;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001541 int err;
Mark Glinesd84b39a2002-01-07 16:32:02 +00001542
Miklos Szeredi52cb09d2005-11-07 11:59:00 +00001543 memset(&buf, 0, sizeof(buf));
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001544 if (f->op.statfs) {
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00001545 err = fuse_do_statfs(f, "/", &buf);
Miklos Szeredi52cb09d2005-11-07 11:59:00 +00001546 } else
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001547 err = default_statfs(&buf);
Miklos Szeredi77f39942004-03-25 11:17:52 +00001548
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001549 if (!err)
1550 fuse_reply_statfs(req, &buf);
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001551 else
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001552 reply_err(req, err);
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001553}
1554
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001555static void fuse_setxattr(fuse_req_t req, fuse_ino_t ino, const char *name,
1556 const char *value, size_t size, int flags)
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001557{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001558 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001559 char *path;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001560 int err;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001561
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001562 err = -ENOENT;
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001563 pthread_rwlock_rdlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001564 path = get_path(f, ino);
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001565 if (path != NULL) {
Miklos Szerediab974562005-04-07 15:40:21 +00001566 err = -ENOSYS;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001567 if (f->op.setxattr)
1568 err = f->op.setxattr(path, name, value, size, flags);
1569 free(path);
1570 }
1571 pthread_rwlock_unlock(&f->tree_lock);
1572 reply_err(req, err);
1573}
1574
1575static int common_getxattr(struct fuse *f, fuse_ino_t ino, const char *name,
1576 char *value, size_t size)
1577{
1578 int err;
1579 char *path;
1580
1581 err = -ENOENT;
1582 pthread_rwlock_rdlock(&f->tree_lock);
1583 path = get_path(f, ino);
1584 if (path != NULL) {
1585 err = -ENOSYS;
1586 if (f->op.getxattr)
1587 err = f->op.getxattr(path, name, value, size);
Miklos Szerediab974562005-04-07 15:40:21 +00001588 free(path);
1589 }
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001590 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szerediab974562005-04-07 15:40:21 +00001591 return err;
1592}
1593
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001594static void fuse_getxattr(fuse_req_t req, fuse_ino_t ino, const char *name,
1595 size_t size)
Miklos Szeredi3ead28e2005-01-18 21:23:41 +00001596{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001597 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredi4283ee72005-03-21 12:09:04 +00001598 int res;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001599
1600 if (size) {
1601 char *value = (char *) malloc(size);
1602 if (value == NULL) {
1603 reply_err(req, -ENOMEM);
1604 return;
1605 }
1606 res = common_getxattr(f, ino, name, value, size);
1607 if (res > 0)
1608 fuse_reply_buf(req, value, res);
1609 else
1610 reply_err(req, res);
1611 free(value);
1612 } else {
1613 res = common_getxattr(f, ino, name, NULL, 0);
1614 if (res >= 0)
1615 fuse_reply_xattr(req, res);
1616 else
1617 reply_err(req, res);
1618 }
1619}
1620
1621static int common_listxattr(struct fuse *f, fuse_ino_t ino, char *list,
1622 size_t size)
1623{
Miklos Szeredi4283ee72005-03-21 12:09:04 +00001624 char *path;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001625 int err;
Miklos Szeredi4283ee72005-03-21 12:09:04 +00001626
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001627 err = -ENOENT;
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001628 pthread_rwlock_rdlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001629 path = get_path(f, ino);
Miklos Szeredi4283ee72005-03-21 12:09:04 +00001630 if (path != NULL) {
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001631 err = -ENOSYS;
1632 if (f->op.listxattr)
1633 err = f->op.listxattr(path, list, size);
Miklos Szeredi4283ee72005-03-21 12:09:04 +00001634 free(path);
1635 }
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001636 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001637 return err;
Miklos Szeredi4283ee72005-03-21 12:09:04 +00001638}
Miklos Szeredi3ead28e2005-01-18 21:23:41 +00001639
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001640static void fuse_listxattr(fuse_req_t req, fuse_ino_t ino, size_t size)
Miklos Szeredi43696432001-11-18 19:15:05 +00001641{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001642 struct fuse *f = req_fuse_prepare(req);
1643 int res;
1644
1645 if (size) {
1646 char *list = (char *) malloc(size);
1647 if (list == NULL) {
1648 reply_err(req, -ENOMEM);
1649 return;
1650 }
1651 res = common_listxattr(f, ino, list, size);
1652 if (res > 0)
1653 fuse_reply_buf(req, list, res);
1654 else
1655 reply_err(req, res);
1656 free(list);
1657 } else {
1658 res = common_listxattr(f, ino, NULL, 0);
1659 if (res >= 0)
1660 fuse_reply_xattr(req, res);
1661 else
1662 reply_err(req, res);
1663 }
Miklos Szeredi43696432001-11-18 19:15:05 +00001664}
1665
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001666static void fuse_removexattr(fuse_req_t req, fuse_ino_t ino, const char *name)
1667{
1668 struct fuse *f = req_fuse_prepare(req);
1669 char *path;
1670 int err;
1671
1672 err = -ENOENT;
1673 pthread_rwlock_rdlock(&f->tree_lock);
1674 path = get_path(f, ino);
1675 if (path != NULL) {
1676 err = -ENOSYS;
1677 if (f->op.removexattr)
1678 err = f->op.removexattr(path, name);
1679 free(path);
1680 }
1681 pthread_rwlock_unlock(&f->tree_lock);
1682 reply_err(req, err);
1683}
1684
Miklos Szeredia1482422005-08-14 23:00:27 +00001685static struct fuse_lowlevel_ops fuse_path_ops = {
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001686 .init = fuse_data_init,
1687 .destroy = fuse_data_destroy,
1688 .lookup = fuse_lookup,
1689 .forget = fuse_forget,
1690 .getattr = fuse_getattr,
1691 .setattr = fuse_setattr,
Miklos Szeredib0b13d12005-10-26 12:53:25 +00001692 .access = fuse_access,
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001693 .readlink = fuse_readlink,
1694 .mknod = fuse_mknod,
1695 .mkdir = fuse_mkdir,
1696 .unlink = fuse_unlink,
1697 .rmdir = fuse_rmdir,
1698 .symlink = fuse_symlink,
1699 .rename = fuse_rename,
1700 .link = fuse_link,
Miklos Szeredid9079a72005-10-26 15:29:06 +00001701 .create = fuse_create,
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001702 .open = fuse_open,
1703 .read = fuse_read,
1704 .write = fuse_write,
1705 .flush = fuse_flush,
1706 .release = fuse_release,
1707 .fsync = fuse_fsync,
1708 .opendir = fuse_opendir,
1709 .readdir = fuse_readdir,
1710 .releasedir = fuse_releasedir,
1711 .fsyncdir = fuse_fsyncdir,
1712 .statfs = fuse_statfs,
1713 .setxattr = fuse_setxattr,
1714 .getxattr = fuse_getxattr,
1715 .listxattr = fuse_listxattr,
1716 .removexattr = fuse_removexattr,
1717};
1718
Miklos Szeredia1482422005-08-14 23:00:27 +00001719static void free_cmd(struct fuse_cmd *cmd)
1720{
1721 free(cmd->buf);
1722 free(cmd);
1723}
1724
Miklos Szeredif458b8c2004-12-07 16:46:42 +00001725void fuse_process_cmd(struct fuse *f, struct fuse_cmd *cmd)
Miklos Szeredia181e612001-11-06 12:03:23 +00001726{
Miklos Szeredi178451d2005-08-15 13:19:07 +00001727 fuse_session_process(f->se, cmd->buf, cmd->buflen, cmd->ch);
Miklos Szeredifa829b52005-12-02 11:05:41 +00001728 free_cmd(cmd);
Miklos Szeredia181e612001-11-06 12:03:23 +00001729}
1730
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001731int fuse_exited(struct fuse *f)
Miklos Szeredi65cf7c72004-06-30 11:34:56 +00001732{
Miklos Szeredia1482422005-08-14 23:00:27 +00001733 return fuse_session_exited(f->se);
1734}
1735
1736struct fuse_session *fuse_get_session(struct fuse *f)
1737{
1738 return f->se;
1739}
1740
1741static struct fuse_cmd *fuse_alloc_cmd(size_t bufsize)
1742{
1743 struct fuse_cmd *cmd = (struct fuse_cmd *) malloc(sizeof(*cmd));
1744 if (cmd == NULL) {
1745 fprintf(stderr, "fuse: failed to allocate cmd\n");
1746 return NULL;
1747 }
1748 cmd->buf = (char *) malloc(bufsize);
1749 if (cmd->buf == NULL) {
1750 fprintf(stderr, "fuse: failed to allocate read buffer\n");
1751 free(cmd);
1752 return NULL;
1753 }
1754 return cmd;
Miklos Szeredi65cf7c72004-06-30 11:34:56 +00001755}
1756
Miklos Szeredif458b8c2004-12-07 16:46:42 +00001757struct fuse_cmd *fuse_read_cmd(struct fuse *f)
Miklos Szeredi2df1c042001-11-06 15:07:17 +00001758{
Miklos Szeredia1482422005-08-14 23:00:27 +00001759 struct fuse_chan *ch = fuse_session_next_chan(f->se, NULL);
1760 size_t bufsize = fuse_chan_bufsize(ch);
1761 struct fuse_cmd *cmd = fuse_alloc_cmd(bufsize);
1762 if (cmd != NULL) {
1763 int res = fuse_chan_receive(ch, cmd->buf, bufsize);
1764 if (res <= 0) {
1765 free_cmd(cmd);
Miklos Szeredifa829b52005-12-02 11:05:41 +00001766 if (res == -1)
1767 fuse_exit(f);
Miklos Szeredia1482422005-08-14 23:00:27 +00001768 return NULL;
1769 }
1770 cmd->buflen = res;
Miklos Szeredi178451d2005-08-15 13:19:07 +00001771 cmd->ch = ch;
Miklos Szeredia1482422005-08-14 23:00:27 +00001772 }
1773 return cmd;
Miklos Szeredi2df1c042001-11-06 15:07:17 +00001774}
1775
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001776int fuse_loop(struct fuse *f)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001777{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001778 if (f)
Miklos Szeredia1482422005-08-14 23:00:27 +00001779 return fuse_session_loop(f->se);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001780 else
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001781 return -1;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001782}
1783
Miklos Szeredi891b8742004-07-29 09:27:49 +00001784int fuse_invalidate(struct fuse *f, const char *path)
1785{
Miklos Szeredie56818b2004-12-12 11:45:24 +00001786 (void) f;
1787 (void) path;
1788 return -EINVAL;
Miklos Szeredi891b8742004-07-29 09:27:49 +00001789}
1790
Miklos Szeredi0f48a262002-12-05 14:23:01 +00001791void fuse_exit(struct fuse *f)
1792{
Miklos Szeredia1482422005-08-14 23:00:27 +00001793 fuse_session_exit(f->se);
Miklos Szeredi0f48a262002-12-05 14:23:01 +00001794}
1795
Miklos Szeredid169f312004-09-22 08:48:26 +00001796struct fuse_context *fuse_get_context()
Miklos Szeredi2e50d432001-12-20 12:17:25 +00001797{
Miklos Szeredid169f312004-09-22 08:48:26 +00001798 static struct fuse_context context;
1799 if (fuse_getcontext)
1800 return fuse_getcontext();
Miklos Szeredi2e50d432001-12-20 12:17:25 +00001801 else
Miklos Szeredid169f312004-09-22 08:48:26 +00001802 return &context;
1803}
1804
Miklos Szeredif458b8c2004-12-07 16:46:42 +00001805void fuse_set_getcontext_func(struct fuse_context *(*func)(void))
Miklos Szeredid169f312004-09-22 08:48:26 +00001806{
1807 fuse_getcontext = func;
Miklos Szeredi2e50d432001-12-20 12:17:25 +00001808}
1809
Miklos Szeredi659743b2005-12-09 17:41:42 +00001810static int fuse_lib_opt_proc(void *data, const char *arg, int key)
Miklos Szeredie331c4b2005-07-06 13:34:02 +00001811{
Miklos Szeredi659743b2005-12-09 17:41:42 +00001812 struct fuse_config *conf = data;
1813 (void) key;
1814 return fuse_opt_add_opt(&conf->llopts, arg);
Miklos Szeredie331c4b2005-07-06 13:34:02 +00001815}
1816
Miklos Szeredi659743b2005-12-09 17:41:42 +00001817#define FUSE_LIB_OPT(t, p, v) { t, offsetof(struct fuse_config, p), v }
1818
1819static const struct fuse_opt fuse_lib_opts[] = {
1820 { "debug", FUSE_OPT_OFFSET_KEY, 0 },
1821 FUSE_LIB_OPT("debug", debug, 1),
1822 FUSE_LIB_OPT("hard_remove", hard_remove, 1),
1823 FUSE_LIB_OPT("use_ino", use_ino, 1),
1824 FUSE_LIB_OPT("readdir_ino", readdir_ino, 1),
1825 FUSE_LIB_OPT("direct_io", direct_io, 1),
1826 FUSE_LIB_OPT("kernel_cache", kernel_cache, 1),
1827 FUSE_LIB_OPT("umask=", set_mode, 1),
1828 FUSE_LIB_OPT("umask=%o", umask, 0),
1829 FUSE_LIB_OPT("uid=", set_uid, 1),
1830 FUSE_LIB_OPT("uid=%d", uid, 0),
1831 FUSE_LIB_OPT("gid=", set_gid, 1),
1832 FUSE_LIB_OPT("gid=%d", gid, 0),
1833 FUSE_LIB_OPT("entry_timeout=%lf", entry_timeout, 0),
1834 FUSE_LIB_OPT("attr_timeout=%lf", attr_timeout, 0),
1835 FUSE_LIB_OPT("negative_timeout=%lf", negative_timeout, 0),
1836 FUSE_OPT_END
1837};
1838
Miklos Szeredibd7661b2004-07-23 17:16:29 +00001839int fuse_is_lib_option(const char *opt)
1840{
Miklos Szeredi659743b2005-12-09 17:41:42 +00001841 return fuse_lowlevel_is_lib_option(opt) ||
1842 fuse_opt_match(fuse_lib_opts, opt);
Miklos Szeredibd7661b2004-07-23 17:16:29 +00001843}
1844
Miklos Szeredi0b6a0ad2004-12-04 00:40:50 +00001845struct fuse *fuse_new_common(int fd, const char *opts,
1846 const struct fuse_operations *op,
1847 size_t op_size, int compat)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001848{
Miklos Szeredia1482422005-08-14 23:00:27 +00001849 struct fuse_chan *ch;
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001850 struct fuse *f;
1851 struct node *root;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001852
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001853 if (sizeof(struct fuse_operations) < op_size) {
Miklos Szeredi0b6a0ad2004-12-04 00:40:50 +00001854 fprintf(stderr, "fuse: warning: library too old, some operations may not not work\n");
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001855 op_size = sizeof(struct fuse_operations);
Miklos Szeredi0b6a0ad2004-12-04 00:40:50 +00001856 }
1857
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001858 f = (struct fuse *) calloc(1, sizeof(struct fuse));
Miklos Szeredie56818b2004-12-12 11:45:24 +00001859 if (f == NULL) {
1860 fprintf(stderr, "fuse: failed to allocate fuse object\n");
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001861 goto out;
Miklos Szeredie56818b2004-12-12 11:45:24 +00001862 }
Miklos Szeredi2df1c042001-11-06 15:07:17 +00001863
Miklos Szeredi659743b2005-12-09 17:41:42 +00001864 f->conf.entry_timeout = 1.0;
1865 f->conf.attr_timeout = 1.0;
1866 f->conf.negative_timeout = 0.0;
Miklos Szeredi6c0209a2005-08-02 13:31:28 +00001867
Miklos Szeredi659743b2005-12-09 17:41:42 +00001868 if (opts) {
1869 const char *argv[] = { "", "-o", opts, NULL };
1870 if (fuse_opt_parse(3, (char **) argv, &f->conf,
1871 fuse_lib_opts, fuse_lib_opt_proc, NULL, NULL) == -1)
1872 goto out_free;
1873 }
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001874
Miklos Szeredi659743b2005-12-09 17:41:42 +00001875#ifdef __FreeBSD__
1876 /*
1877 * In FreeBSD, we always use these settings as inode numbers are needed to
1878 * make getcwd(3) work.
1879 */
Miklos Szeredi76fc3de2005-12-12 09:34:45 +00001880 f->conf.readdir_ino = 1;
Miklos Szeredi659743b2005-12-09 17:41:42 +00001881#endif
1882
1883 f->se = fuse_lowlevel_new(f->conf.llopts, &fuse_path_ops,
1884 sizeof(fuse_path_ops), f);
1885 free(f->conf.llopts);
Miklos Szeredia1482422005-08-14 23:00:27 +00001886 if (f->se == NULL)
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001887 goto out_free;
Miklos Szeredi2bb750e2005-10-03 14:54:24 +00001888
Miklos Szeredia1482422005-08-14 23:00:27 +00001889 ch = fuse_kern_chan_new(fd);
1890 if (ch == NULL)
1891 goto out_free_session;
Miklos Szeredi2bb750e2005-10-03 14:54:24 +00001892
Miklos Szeredia1482422005-08-14 23:00:27 +00001893 fuse_session_add_chan(f->se, ch);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001894
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001895 f->ctr = 0;
Miklos Szeredi76f65782004-02-19 16:55:40 +00001896 f->generation = 0;
Miklos Szeredifff56ab2001-11-16 10:12:59 +00001897 /* FIXME: Dynamic hash table */
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001898 f->name_table_size = 14057;
1899 f->name_table = (struct node **)
1900 calloc(1, sizeof(struct node *) * f->name_table_size);
Miklos Szeredie56818b2004-12-12 11:45:24 +00001901 if (f->name_table == NULL) {
1902 fprintf(stderr, "fuse: memory allocation failed\n");
Miklos Szeredia1482422005-08-14 23:00:27 +00001903 goto out_free_session;
Miklos Szeredie56818b2004-12-12 11:45:24 +00001904 }
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001905
Miklos Szeredia13d9002004-11-02 17:32:03 +00001906 f->id_table_size = 14057;
1907 f->id_table = (struct node **)
1908 calloc(1, sizeof(struct node *) * f->id_table_size);
Miklos Szeredie56818b2004-12-12 11:45:24 +00001909 if (f->id_table == NULL) {
1910 fprintf(stderr, "fuse: memory allocation failed\n");
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001911 goto out_free_name_table;
Miklos Szeredie56818b2004-12-12 11:45:24 +00001912 }
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001913
Miklos Szerediab974562005-04-07 15:40:21 +00001914 mutex_init(&f->lock);
Miklos Szeredi0b6a0ad2004-12-04 00:40:50 +00001915 memcpy(&f->op, op, op_size);
1916 f->compat = compat;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001917
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001918 root = (struct node *) calloc(1, sizeof(struct node));
Miklos Szeredie56818b2004-12-12 11:45:24 +00001919 if (root == NULL) {
1920 fprintf(stderr, "fuse: memory allocation failed\n");
Miklos Szeredia13d9002004-11-02 17:32:03 +00001921 goto out_free_id_table;
Miklos Szeredie56818b2004-12-12 11:45:24 +00001922 }
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001923
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001924 root->name = strdup("/");
Miklos Szeredie56818b2004-12-12 11:45:24 +00001925 if (root->name == NULL) {
1926 fprintf(stderr, "fuse: memory allocation failed\n");
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001927 goto out_free_root;
Miklos Szeredie56818b2004-12-12 11:45:24 +00001928 }
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001929
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001930 root->parent = 0;
Miklos Szeredia13d9002004-11-02 17:32:03 +00001931 root->nodeid = FUSE_ROOT_ID;
Miklos Szeredi76f65782004-02-19 16:55:40 +00001932 root->generation = 0;
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001933 root->refctr = 1;
Miklos Szeredi38009022005-05-08 19:47:22 +00001934 root->nlookup = 1;
Miklos Szeredia13d9002004-11-02 17:32:03 +00001935 hash_id(f, root);
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001936
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001937 return f;
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001938
1939 out_free_root:
1940 free(root);
Miklos Szeredia13d9002004-11-02 17:32:03 +00001941 out_free_id_table:
1942 free(f->id_table);
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001943 out_free_name_table:
1944 free(f->name_table);
Miklos Szeredia1482422005-08-14 23:00:27 +00001945 out_free_session:
1946 fuse_session_destroy(f->se);
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001947 out_free:
1948 free(f);
1949 out:
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001950 return NULL;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001951}
1952
Miklos Szeredi0b6a0ad2004-12-04 00:40:50 +00001953struct fuse *fuse_new(int fd, const char *opts,
1954 const struct fuse_operations *op, size_t op_size)
1955{
1956 return fuse_new_common(fd, opts, op, op_size, 0);
1957}
1958
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001959void fuse_destroy(struct fuse *f)
1960{
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001961 size_t i;
Miklos Szeredia13d9002004-11-02 17:32:03 +00001962 for (i = 0; i < f->id_table_size; i++) {
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001963 struct node *node;
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001964
Miklos Szeredia13d9002004-11-02 17:32:03 +00001965 for (node = f->id_table[i]; node != NULL; node = node->id_next) {
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001966 if (node->is_hidden) {
Miklos Szeredia13d9002004-11-02 17:32:03 +00001967 char *path = get_path(f, node->nodeid);
Miklos Szeredi21019c92005-05-09 11:22:41 +00001968 if (path) {
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001969 f->op.unlink(path);
Miklos Szeredi21019c92005-05-09 11:22:41 +00001970 free(path);
1971 }
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001972 }
1973 }
1974 }
Miklos Szeredia13d9002004-11-02 17:32:03 +00001975 for (i = 0; i < f->id_table_size; i++) {
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001976 struct node *node;
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001977 struct node *next;
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001978
Miklos Szeredia13d9002004-11-02 17:32:03 +00001979 for (node = f->id_table[i]; node != NULL; node = next) {
1980 next = node->id_next;
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001981 free_node(node);
1982 }
1983 }
Miklos Szeredia13d9002004-11-02 17:32:03 +00001984 free(f->id_table);
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001985 free(f->name_table);
Miklos Szeredia181e612001-11-06 12:03:23 +00001986 pthread_mutex_destroy(&f->lock);
Miklos Szeredia1482422005-08-14 23:00:27 +00001987 fuse_session_destroy(f->se);
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001988 free(f);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001989}
Miklos Szeredi0b6a0ad2004-12-04 00:40:50 +00001990
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00001991#ifndef __FreeBSD__
1992
1993#include "fuse_compat.h"
1994
1995static int fuse_do_open(struct fuse *f, char *path, struct fuse_file_info *fi)
1996{
1997 if (!f->compat)
1998 return f->op.open(path, fi);
1999 else if (f->compat == 22) {
2000 int err;
2001 struct fuse_file_info_compat22 tmp;
2002 memcpy(&tmp, fi, sizeof(tmp));
2003 err = ((struct fuse_operations_compat22 *) &f->op)->open(path, &tmp);
2004 memcpy(fi, &tmp, sizeof(tmp));
2005 fi->fh = tmp.fh;
2006 return err;
2007 } else
Miklos Szerediead7f102005-11-28 16:02:27 +00002008 return
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002009 ((struct fuse_operations_compat2 *) &f->op)->open(path, fi->flags);
2010}
2011
2012static void fuse_do_release(struct fuse *f, char *path,
2013 struct fuse_file_info *fi)
2014{
2015 if (!f->compat || f->compat >= 22)
2016 f->op.release(path ? path : "-", fi);
2017 else if (path)
2018 ((struct fuse_operations_compat2 *) &f->op)->release(path, fi->flags);
2019}
2020
2021static int fuse_do_opendir(struct fuse *f, char *path,
2022 struct fuse_file_info *fi)
2023{
2024 if (!f->compat) {
2025 return f->op.opendir(path, fi);
2026 } else {
2027 int err;
2028 struct fuse_file_info_compat22 tmp;
2029 memcpy(&tmp, fi, sizeof(tmp));
2030 err = ((struct fuse_operations_compat22 *) &f->op)->opendir(path, &tmp);
2031 memcpy(fi, &tmp, sizeof(tmp));
2032 fi->fh = tmp.fh;
2033 return err;
2034 }
2035}
2036
2037static void convert_statfs_compat(struct fuse_statfs_compat1 *compatbuf,
2038 struct statvfs *stbuf)
2039{
2040 stbuf->f_bsize = compatbuf->block_size;
2041 stbuf->f_blocks = compatbuf->blocks;
2042 stbuf->f_bfree = compatbuf->blocks_free;
2043 stbuf->f_bavail = compatbuf->blocks_free;
2044 stbuf->f_files = compatbuf->files;
2045 stbuf->f_ffree = compatbuf->files_free;
2046 stbuf->f_namemax = compatbuf->namelen;
2047}
2048
2049static void convert_statfs_old(struct statfs *oldbuf, struct statvfs *stbuf)
2050{
2051 stbuf->f_bsize = oldbuf->f_bsize;
2052 stbuf->f_blocks = oldbuf->f_blocks;
2053 stbuf->f_bfree = oldbuf->f_bfree;
2054 stbuf->f_bavail = oldbuf->f_bavail;
2055 stbuf->f_files = oldbuf->f_files;
2056 stbuf->f_ffree = oldbuf->f_ffree;
2057 stbuf->f_namemax = oldbuf->f_namelen;
2058}
2059
2060static int fuse_do_statfs(struct fuse *f, char *path, struct statvfs *buf)
2061{
2062 int err;
2063
2064 if (!f->compat) {
2065 err = f->op.statfs(path, buf);
2066 } else if (f->compat > 11) {
2067 struct statfs oldbuf;
2068 err = ((struct fuse_operations_compat22 *) &f->op)->statfs("/", &oldbuf);
2069 if (!err)
2070 convert_statfs_old(&oldbuf, buf);
2071 } else {
2072 struct fuse_statfs_compat1 compatbuf;
2073 memset(&compatbuf, 0, sizeof(struct fuse_statfs_compat1));
2074 err = ((struct fuse_operations_compat1 *) &f->op)->statfs(&compatbuf);
2075 if (!err)
2076 convert_statfs_compat(&compatbuf, buf);
2077 }
2078 return err;
2079}
2080
2081struct fuse *fuse_new_compat22(int fd, const char *opts,
2082 const struct fuse_operations_compat22 *op,
2083 size_t op_size)
2084{
2085 return fuse_new_common(fd, opts, (struct fuse_operations *) op,
2086 op_size, 22);
2087}
2088
2089struct fuse *fuse_new_compat2(int fd, const char *opts,
2090 const struct fuse_operations_compat2 *op)
2091{
2092 return fuse_new_common(fd, opts, (struct fuse_operations *) op,
2093 sizeof(struct fuse_operations_compat2), 21);
2094}
2095
2096struct fuse *fuse_new_compat1(int fd, int flags,
2097 const struct fuse_operations_compat1 *op)
2098{
2099 const char *opts = NULL;
2100 if (flags & FUSE_DEBUG_COMPAT1)
2101 opts = "debug";
2102 return fuse_new_common(fd, opts, (struct fuse_operations *) op,
2103 sizeof(struct fuse_operations_compat1), 11);
2104}
2105
Miklos Szeredif458b8c2004-12-07 16:46:42 +00002106__asm__(".symver fuse_exited,__fuse_exited@");
2107__asm__(".symver fuse_process_cmd,__fuse_process_cmd@");
2108__asm__(".symver fuse_read_cmd,__fuse_read_cmd@");
2109__asm__(".symver fuse_set_getcontext_func,__fuse_set_getcontext_func@");
2110__asm__(".symver fuse_new_compat2,fuse_new@");
Miklos Szeredi3a770472005-11-11 21:32:42 +00002111__asm__(".symver fuse_new_compat22,fuse_new@FUSE_2.2");
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002112
2113#else /* __FreeBSD__ */
2114
2115static int fuse_do_open(struct fuse *f, char *path, struct fuse_file_info *fi)
2116{
Miklos Szerediead7f102005-11-28 16:02:27 +00002117 return f->op.open(path, fi);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002118}
2119
2120static void fuse_do_release(struct fuse *f, char *path,
2121 struct fuse_file_info *fi)
2122{
2123 f->op.release(path ? path : "-", fi);
2124}
2125
2126static int fuse_do_opendir(struct fuse *f, char *path,
2127 struct fuse_file_info *fi)
2128{
Miklos Szerediead7f102005-11-28 16:02:27 +00002129 return f->op.opendir(path, fi);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002130}
2131
2132static int fuse_do_statfs(struct fuse *f, char *path, struct statvfs *buf)
2133{
2134 return f->op.statfs(path, buf);
2135}
2136
2137#endif /* __FreeBSD__ */