blob: 994a31f773dc341f4693f5e23b1f6e8a8fccfb05 [file] [log] [blame]
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001/*
2 FUSE: Filesystem in Userspace
Miklos Szeredi95da8602006-01-06 18:29:40 +00003 Copyright (C) 2001-2006 Miklos Szeredi <miklos@szeredi.hu>
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00004
Miklos Szeredi8b39a9f2002-10-25 12:41:16 +00005 This program can be distributed under the terms of the GNU LGPL.
6 See the file COPYING.LIB
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00007*/
8
Miklos Szeredie2aa2e22005-07-15 13:31:36 +00009
10/* For pthread_rwlock_t */
11#define _GNU_SOURCE
12
Miklos Szeredi178451d2005-08-15 13:19:07 +000013#include "fuse_i.h"
Miklos Szeredie2aa2e22005-07-15 13:31:36 +000014#include "fuse_lowlevel.h"
Miklos Szeredi659743b2005-12-09 17:41:42 +000015#include "fuse_opt.h"
Miklos Szeredi38f152c2006-09-03 18:28:52 +000016#include "fuse_misc.h"
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000017
Miklos Szeredi0f62d722005-01-04 12:45:54 +000018#include <stdio.h>
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000019#include <string.h>
Miklos Szeredi97c61e92001-11-07 12:09:43 +000020#include <stdlib.h>
Miklos Szeredi659743b2005-12-09 17:41:42 +000021#include <stddef.h>
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000022#include <unistd.h>
Miklos Szeredi320abe42006-01-30 18:14:51 +000023#include <time.h>
Miklos Szeredib3f99722005-11-16 13:00:24 +000024#include <fcntl.h>
Miklos Szeredi97c61e92001-11-07 12:09:43 +000025#include <limits.h>
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000026#include <errno.h>
Miklos Szeredi288ed4e2006-09-07 06:02:44 +000027#include <signal.h>
Miklos Szeredi0f62d722005-01-04 12:45:54 +000028#include <assert.h>
Miklos Szeredi019b4e92001-12-26 18:08:09 +000029#include <sys/param.h>
Miklos Szerediab974562005-04-07 15:40:21 +000030#include <sys/uio.h>
Miklos Szeredi288ed4e2006-09-07 06:02:44 +000031#include <sys/time.h>
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000032
Miklos Szeredi97c61e92001-11-07 12:09:43 +000033#define FUSE_MAX_PATH 4096
Miklos Szeredi288ed4e2006-09-07 06:02:44 +000034#define FUSE_DEFAULT_INTR_SIGNAL SIGUSR1
Miklos Szeredi30e093a2005-04-03 17:44:54 +000035
Miklos Szeredie248e4b2005-12-14 16:18:32 +000036#define FUSE_UNKNOWN_INO 0xffffffff
Miklos Szeredi0c59ebf2006-09-10 20:53:36 +000037#define OFFSET_MAX 0x7fffffffffffffffLL
Miklos Szeredie248e4b2005-12-14 16:18:32 +000038
Miklos Szeredi659743b2005-12-09 17:41:42 +000039struct fuse_config {
Miklos Szeredi659743b2005-12-09 17:41:42 +000040 unsigned int uid;
41 unsigned int gid;
42 unsigned int umask;
43 double entry_timeout;
44 double negative_timeout;
45 double attr_timeout;
Miklos Szeredi6e806e92006-02-16 16:59:39 +000046 double ac_attr_timeout;
47 int ac_attr_timeout_set;
Miklos Szeredi659743b2005-12-09 17:41:42 +000048 int debug;
49 int hard_remove;
50 int use_ino;
51 int readdir_ino;
52 int set_mode;
53 int set_uid;
54 int set_gid;
55 int direct_io;
56 int kernel_cache;
Miklos Szeredi320abe42006-01-30 18:14:51 +000057 int auto_cache;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +000058 int intr;
59 int intr_signal;
Miklos Szeredi659743b2005-12-09 17:41:42 +000060};
61
Miklos Szeredie2aa2e22005-07-15 13:31:36 +000062struct fuse {
Miklos Szeredia1482422005-08-14 23:00:27 +000063 struct fuse_session *se;
Miklos Szeredie2aa2e22005-07-15 13:31:36 +000064 struct fuse_operations op;
65 int compat;
66 struct node **name_table;
67 size_t name_table_size;
68 struct node **id_table;
69 size_t id_table_size;
70 fuse_ino_t ctr;
71 unsigned int generation;
72 unsigned int hidectr;
73 pthread_mutex_t lock;
74 pthread_rwlock_t tree_lock;
75 void *user_data;
Miklos Szeredi659743b2005-12-09 17:41:42 +000076 struct fuse_config conf;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +000077 int intr_installed;
Miklos Szeredie2aa2e22005-07-15 13:31:36 +000078};
79
Miklos Szeredi0c59ebf2006-09-10 20:53:36 +000080struct lock {
81 int type;
82 off_t start;
83 off_t end;
84 pid_t pid;
85 uint64_t owner;
86 struct lock *next;
87};
88
Miklos Szeredi0f62d722005-01-04 12:45:54 +000089struct node {
90 struct node *name_next;
91 struct node *id_next;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +000092 fuse_ino_t nodeid;
Miklos Szeredi0f62d722005-01-04 12:45:54 +000093 unsigned int generation;
94 int refctr;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +000095 fuse_ino_t parent;
Miklos Szeredi0f62d722005-01-04 12:45:54 +000096 char *name;
Miklos Szeredi38009022005-05-08 19:47:22 +000097 uint64_t nlookup;
Miklos Szeredi0f62d722005-01-04 12:45:54 +000098 int open_count;
99 int is_hidden;
Miklos Szeredi320abe42006-01-30 18:14:51 +0000100 struct timespec stat_updated;
101 struct timespec mtime;
102 off_t size;
103 int cache_valid;
Miklos Szeredi0c59ebf2006-09-10 20:53:36 +0000104 struct lock *locks;
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000105};
106
107struct fuse_dirhandle {
Miklos Szerediab974562005-04-07 15:40:21 +0000108 pthread_mutex_t lock;
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000109 struct fuse *fuse;
Miklos Szeredi1bf64f42006-02-17 15:49:25 +0000110 fuse_req_t req;
Miklos Szeredi1b188022005-07-28 11:07:29 +0000111 char *contents;
Miklos Szerediab974562005-04-07 15:40:21 +0000112 int allocated;
Miklos Szeredib92d9782005-02-07 16:10:49 +0000113 unsigned len;
Miklos Szeredic4c12ae2005-10-20 14:48:50 +0000114 unsigned size;
Miklos Szerediab974562005-04-07 15:40:21 +0000115 unsigned needlen;
Miklos Szeredi3ead28e2005-01-18 21:23:41 +0000116 int filled;
Miklos Szeredi3a770472005-11-11 21:32:42 +0000117 uint64_t fh;
Miklos Szerediab974562005-04-07 15:40:21 +0000118 int error;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000119 fuse_ino_t nodeid;
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000120};
121
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000122struct fuse_context_i {
123 struct fuse_context ctx;
124 fuse_req_t req;
125};
Miklos Szeredid169f312004-09-22 08:48:26 +0000126
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000127static pthread_key_t fuse_context_key;
128static pthread_mutex_t fuse_context_lock = PTHREAD_MUTEX_INITIALIZER;
129static int fuse_context_ref;
130
131static int fuse_compat_open(struct fuse *, fuse_req_t, char *,
132 struct fuse_file_info *);
133static void fuse_compat_release(struct fuse *, fuse_req_t, char *,
134 struct fuse_file_info *);
135static int fuse_compat_opendir(struct fuse *, fuse_req_t, char *,
136 struct fuse_file_info *);
137static int fuse_compat_statfs(struct fuse *, fuse_req_t, struct statvfs *);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +0000138
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000139static struct node *get_node_nocheck(struct fuse *f, fuse_ino_t nodeid)
Miklos Szeredia181e612001-11-06 12:03:23 +0000140{
Miklos Szeredia13d9002004-11-02 17:32:03 +0000141 size_t hash = nodeid % f->id_table_size;
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000142 struct node *node;
143
Miklos Szeredia13d9002004-11-02 17:32:03 +0000144 for (node = f->id_table[hash]; node != NULL; node = node->id_next)
145 if (node->nodeid == nodeid)
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000146 return node;
Miklos Szeredie5183742005-02-02 11:14:04 +0000147
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000148 return NULL;
Miklos Szeredia181e612001-11-06 12:03:23 +0000149}
150
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000151static struct node *get_node(struct fuse *f, fuse_ino_t nodeid)
Miklos Szeredia181e612001-11-06 12:03:23 +0000152{
Miklos Szeredif458b8c2004-12-07 16:46:42 +0000153 struct node *node = get_node_nocheck(f, nodeid);
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000154 if (!node) {
Miklos Szeredi3a770472005-11-11 21:32:42 +0000155 fprintf(stderr, "fuse internal error: node %llu not found\n",
156 (unsigned long long) nodeid);
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000157 abort();
158 }
159 return node;
Miklos Szeredia181e612001-11-06 12:03:23 +0000160}
161
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000162static void free_node(struct node *node)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000163{
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000164 free(node->name);
165 free(node);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000166}
167
Miklos Szeredia13d9002004-11-02 17:32:03 +0000168static void unhash_id(struct fuse *f, struct node *node)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000169{
Miklos Szeredia13d9002004-11-02 17:32:03 +0000170 size_t hash = node->nodeid % f->id_table_size;
171 struct node **nodep = &f->id_table[hash];
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000172
Miklos Szeredie5183742005-02-02 11:14:04 +0000173 for (; *nodep != NULL; nodep = &(*nodep)->id_next)
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000174 if (*nodep == node) {
Miklos Szeredia13d9002004-11-02 17:32:03 +0000175 *nodep = node->id_next;
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000176 return;
177 }
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000178}
179
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000180static void hash_id(struct fuse *f, struct node *node)
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000181{
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000182 size_t hash = node->nodeid % f->id_table_size;
183 node->id_next = f->id_table[hash];
Miklos Szeredie5183742005-02-02 11:14:04 +0000184 f->id_table[hash] = node;
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000185}
186
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000187static unsigned int name_hash(struct fuse *f, fuse_ino_t parent, const char *name)
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000188{
189 unsigned int hash = *name;
190
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000191 if (hash)
192 for (name += 1; *name != '\0'; name++)
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000193 hash = (hash << 5) - hash + *name;
194
195 return (hash + parent) % f->name_table_size;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000196}
197
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000198static void unref_node(struct fuse *f, struct node *node);
199
200static void unhash_name(struct fuse *f, struct node *node)
201{
202 if (node->name) {
203 size_t hash = name_hash(f, node->parent, node->name);
204 struct node **nodep = &f->name_table[hash];
Miklos Szeredie5183742005-02-02 11:14:04 +0000205
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000206 for (; *nodep != NULL; nodep = &(*nodep)->name_next)
207 if (*nodep == node) {
208 *nodep = node->name_next;
209 node->name_next = NULL;
210 unref_node(f, get_node(f, node->parent));
211 free(node->name);
212 node->name = NULL;
213 node->parent = 0;
214 return;
215 }
Miklos Szeredi3a770472005-11-11 21:32:42 +0000216 fprintf(stderr, "fuse internal error: unable to unhash node: %llu\n",
217 (unsigned long long) node->nodeid);
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000218 abort();
219 }
220}
221
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000222static int hash_name(struct fuse *f, struct node *node, fuse_ino_t parent,
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000223 const char *name)
224{
225 size_t hash = name_hash(f, parent, name);
226 node->name = strdup(name);
227 if (node->name == NULL)
228 return -1;
229
230 get_node(f, parent)->refctr ++;
231 node->parent = parent;
232 node->name_next = f->name_table[hash];
233 f->name_table[hash] = node;
234 return 0;
235}
236
237static void delete_node(struct fuse *f, struct node *node)
238{
Miklos Szeredi659743b2005-12-09 17:41:42 +0000239 if (f->conf.debug) {
Miklos Szeredi3a770472005-11-11 21:32:42 +0000240 printf("delete: %llu\n", (unsigned long long) node->nodeid);
Miklos Szeredi38009022005-05-08 19:47:22 +0000241 fflush(stdout);
242 }
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000243 assert(!node->name);
244 unhash_id(f, node);
245 free_node(node);
246}
247
248static void unref_node(struct fuse *f, struct node *node)
249{
250 assert(node->refctr > 0);
251 node->refctr --;
252 if (!node->refctr)
253 delete_node(f, node);
254}
255
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000256static fuse_ino_t next_id(struct fuse *f)
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000257{
258 do {
Miklos Szeredi7e7fa1f2006-10-08 15:41:20 +0000259 f->ctr = (f->ctr + 1) & 0xffffffff;
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000260 if (!f->ctr)
261 f->generation ++;
Miklos Szeredi7e7fa1f2006-10-08 15:41:20 +0000262 } while (f->ctr == 0 || f->ctr == FUSE_UNKNOWN_INO ||
263 get_node_nocheck(f, f->ctr) != NULL);
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000264 return f->ctr;
265}
266
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000267static struct node *lookup_node(struct fuse *f, fuse_ino_t parent,
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000268 const char *name)
269{
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000270 size_t hash = name_hash(f, parent, name);
271 struct node *node;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000272
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000273 for (node = f->name_table[hash]; node != NULL; node = node->name_next)
274 if (node->parent == parent && strcmp(node->name, name) == 0)
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000275 return node;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000276
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000277 return NULL;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000278}
279
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000280static struct node *find_node(struct fuse *f, fuse_ino_t parent,
281 const char *name)
Miklos Szeredi5e183482001-10-31 14:52:35 +0000282{
283 struct node *node;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000284
Miklos Szeredia181e612001-11-06 12:03:23 +0000285 pthread_mutex_lock(&f->lock);
Miklos Szeredif458b8c2004-12-07 16:46:42 +0000286 node = lookup_node(f, parent, name);
Miklos Szeredie331c4b2005-07-06 13:34:02 +0000287 if (node == NULL) {
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000288 node = (struct node *) calloc(1, sizeof(struct node));
289 if (node == NULL)
290 goto out_err;
Miklos Szeredie5183742005-02-02 11:14:04 +0000291
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000292 node->refctr = 1;
293 node->nodeid = next_id(f);
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000294 node->open_count = 0;
295 node->is_hidden = 0;
296 node->generation = f->generation;
297 if (hash_name(f, node, parent, name) == -1) {
298 free(node);
299 node = NULL;
300 goto out_err;
301 }
302 hash_id(f, node);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000303 }
Miklos Szeredi38009022005-05-08 19:47:22 +0000304 node->nlookup ++;
Miklos Szeredic2309912004-09-21 13:40:38 +0000305 out_err:
Miklos Szeredia181e612001-11-06 12:03:23 +0000306 pthread_mutex_unlock(&f->lock);
Miklos Szeredi76f65782004-02-19 16:55:40 +0000307 return node;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000308}
309
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000310static char *add_name(char *buf, char *s, const char *name)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000311{
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000312 size_t len = strlen(name);
313 s -= len;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000314 if (s <= buf) {
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000315 fprintf(stderr, "fuse: path too long: ...%s\n", s + len);
316 return NULL;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000317 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000318 strncpy(s, name, len);
319 s--;
320 *s = '/';
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000321
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000322 return s;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000323}
324
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000325static char *get_path_name(struct fuse *f, fuse_ino_t nodeid, const char *name)
Miklos Szeredib483c932001-10-29 14:57:57 +0000326{
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000327 char buf[FUSE_MAX_PATH];
328 char *s = buf + FUSE_MAX_PATH - 1;
329 struct node *node;
Miklos Szeredie5183742005-02-02 11:14:04 +0000330
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000331 *s = '\0';
Miklos Szeredia181e612001-11-06 12:03:23 +0000332
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000333 if (name != NULL) {
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000334 s = add_name(buf, s, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000335 if (s == NULL)
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000336 return NULL;
337 }
338
339 pthread_mutex_lock(&f->lock);
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000340 for (node = get_node(f, nodeid); node && node->nodeid != FUSE_ROOT_ID;
341 node = get_node(f, node->parent)) {
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000342 if (node->name == NULL) {
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000343 s = NULL;
344 break;
345 }
Miklos Szeredie5183742005-02-02 11:14:04 +0000346
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000347 s = add_name(buf, s, node->name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000348 if (s == NULL)
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000349 break;
350 }
351 pthread_mutex_unlock(&f->lock);
352
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000353 if (node == NULL || s == NULL)
Miklos Szeredi5e183482001-10-31 14:52:35 +0000354 return NULL;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000355 else if (*s == '\0')
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000356 return strdup("/");
357 else
358 return strdup(s);
359}
Miklos Szeredia181e612001-11-06 12:03:23 +0000360
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000361static char *get_path(struct fuse *f, fuse_ino_t nodeid)
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000362{
Miklos Szeredia13d9002004-11-02 17:32:03 +0000363 return get_path_name(f, nodeid, NULL);
Miklos Szeredib483c932001-10-29 14:57:57 +0000364}
365
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000366static void forget_node(struct fuse *f, fuse_ino_t nodeid, uint64_t nlookup)
Miklos Szeredi38009022005-05-08 19:47:22 +0000367{
368 struct node *node;
369 if (nodeid == FUSE_ROOT_ID)
370 return;
371 pthread_mutex_lock(&f->lock);
372 node = get_node(f, nodeid);
373 assert(node->nlookup >= nlookup);
374 node->nlookup -= nlookup;
375 if (!node->nlookup) {
376 unhash_name(f, node);
377 unref_node(f, node);
378 }
379 pthread_mutex_unlock(&f->lock);
380}
381
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000382static void remove_node(struct fuse *f, fuse_ino_t dir, const char *name)
Miklos Szeredi5e183482001-10-31 14:52:35 +0000383{
Miklos Szeredia181e612001-11-06 12:03:23 +0000384 struct node *node;
385
386 pthread_mutex_lock(&f->lock);
Miklos Szeredif458b8c2004-12-07 16:46:42 +0000387 node = lookup_node(f, dir, name);
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000388 if (node != NULL)
389 unhash_name(f, node);
Miklos Szeredia181e612001-11-06 12:03:23 +0000390 pthread_mutex_unlock(&f->lock);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000391}
392
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000393static int rename_node(struct fuse *f, fuse_ino_t olddir, const char *oldname,
394 fuse_ino_t newdir, const char *newname, int hide)
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000395{
Miklos Szeredia181e612001-11-06 12:03:23 +0000396 struct node *node;
397 struct node *newnode;
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000398 int err = 0;
Miklos Szeredie5183742005-02-02 11:14:04 +0000399
Miklos Szeredia181e612001-11-06 12:03:23 +0000400 pthread_mutex_lock(&f->lock);
Miklos Szeredif458b8c2004-12-07 16:46:42 +0000401 node = lookup_node(f, olddir, oldname);
402 newnode = lookup_node(f, newdir, newname);
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000403 if (node == NULL)
404 goto out;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000405
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000406 if (newnode != NULL) {
407 if (hide) {
408 fprintf(stderr, "fuse: hidden file got created during hiding\n");
Miklos Szeredib2cf9562004-09-16 08:42:40 +0000409 err = -EBUSY;
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000410 goto out;
411 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000412 unhash_name(f, newnode);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000413 }
Miklos Szeredie5183742005-02-02 11:14:04 +0000414
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000415 unhash_name(f, node);
Miklos Szeredib2cf9562004-09-16 08:42:40 +0000416 if (hash_name(f, node, newdir, newname) == -1) {
417 err = -ENOMEM;
418 goto out;
419 }
Miklos Szeredie5183742005-02-02 11:14:04 +0000420
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000421 if (hide)
422 node->is_hidden = 1;
423
424 out:
Miklos Szeredia181e612001-11-06 12:03:23 +0000425 pthread_mutex_unlock(&f->lock);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000426 return err;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000427}
428
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000429static void set_stat(struct fuse *f, fuse_ino_t nodeid, struct stat *stbuf)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000430{
Miklos Szeredi659743b2005-12-09 17:41:42 +0000431 if (!f->conf.use_ino)
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000432 stbuf->st_ino = nodeid;
Miklos Szeredi659743b2005-12-09 17:41:42 +0000433 if (f->conf.set_mode)
434 stbuf->st_mode = (stbuf->st_mode & S_IFMT) | (0777 & ~f->conf.umask);
435 if (f->conf.set_uid)
436 stbuf->st_uid = f->conf.uid;
437 if (f->conf.set_gid)
438 stbuf->st_gid = f->conf.gid;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000439}
440
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000441static struct fuse *req_fuse(fuse_req_t req)
442{
443 return (struct fuse *) fuse_req_userdata(req);
444}
445
446static void fuse_intr_sighandler(int sig)
447{
448 (void) sig;
449 /* Nothing to do */
450}
451
452struct fuse_intr_data {
453 pthread_t id;
454 pthread_cond_t cond;
455 int finished;
456};
457
458static void fuse_interrupt(fuse_req_t req, void *d_)
459{
460 struct fuse_intr_data *d = d_;
461 struct fuse *f = req_fuse(req);
462
463 if (d->id == pthread_self())
464 return;
465
466 pthread_mutex_lock(&f->lock);
467 while (!d->finished) {
468 struct timeval now;
469 struct timespec timeout;
470
471 pthread_kill(d->id, f->conf.intr_signal);
472 gettimeofday(&now, NULL);
473 timeout.tv_sec = now.tv_sec + 1;
474 timeout.tv_nsec = now.tv_usec * 1000;
475 pthread_cond_timedwait(&d->cond, &f->lock, &timeout);
476 }
477 pthread_mutex_unlock(&f->lock);
478}
479
480static void fuse_do_finish_interrupt(struct fuse *f, fuse_req_t req,
481 struct fuse_intr_data *d)
482{
483 pthread_mutex_lock(&f->lock);
484 d->finished = 1;
485 pthread_cond_broadcast(&d->cond);
486 pthread_mutex_unlock(&f->lock);
487 fuse_req_interrupt_func(req, NULL, NULL);
488 pthread_cond_destroy(&d->cond);
489}
490
491static void fuse_do_prepare_interrupt(fuse_req_t req, struct fuse_intr_data *d)
492{
493 d->id = pthread_self();
494 pthread_cond_init(&d->cond, NULL);
495 d->finished = 0;
496 fuse_req_interrupt_func(req, fuse_interrupt, d);
497}
498
499static inline void fuse_finish_interrupt(struct fuse *f, fuse_req_t req,
500 struct fuse_intr_data *d)
501{
502 if (f->conf.intr)
503 fuse_do_finish_interrupt(f, req, d);
504}
505
506static inline void fuse_prepare_interrupt(struct fuse *f, fuse_req_t req,
507 struct fuse_intr_data *d)
508{
509 if (f->conf.intr)
510 fuse_do_prepare_interrupt(req, d);
511}
512
513static int fuse_do_getattr(struct fuse *f, fuse_req_t req, const char *path,
514 struct stat *buf)
515{
516 int res;
517 struct fuse_intr_data d;
518 fuse_prepare_interrupt(f, req, &d);
519 res = f->op.getattr(path, buf);
520 fuse_finish_interrupt(f, req, &d);
521 return res;
522}
523
524static int fuse_do_fgetattr(struct fuse *f, fuse_req_t req, const char *path,
525 struct stat *buf, struct fuse_file_info *fi)
526{
527 int res;
528 struct fuse_intr_data d;
529 fuse_prepare_interrupt(f, req, &d);
530 res = f->op.fgetattr(path, buf, fi);
531 fuse_finish_interrupt(f, req, &d);
532 return res;
533}
534
535static int fuse_do_rename(struct fuse *f, fuse_req_t req, const char *oldpath,
536 const char *newpath)
537{
538 int res;
539 struct fuse_intr_data d;
540 fuse_prepare_interrupt(f, req, &d);
541 res = f->op.rename(oldpath, newpath);
542 fuse_finish_interrupt(f, req, &d);
543 return res;
544}
545
546static int fuse_do_unlink(struct fuse *f, fuse_req_t req, const char *path)
547{
548 int res;
549 struct fuse_intr_data d;
550 fuse_prepare_interrupt(f, req, &d);
551 res = f->op.unlink(path);
552 fuse_finish_interrupt(f, req, &d);
553 return res;
554}
555
556static void fuse_do_release(struct fuse *f, fuse_req_t req, const char *path,
557 struct fuse_file_info *fi)
558{
559 struct fuse_intr_data d;
560 fuse_prepare_interrupt(f, req, &d);
561 f->op.release(path, fi);
562 fuse_finish_interrupt(f, req, &d);
563}
564
565static int fuse_do_opendir(struct fuse *f, fuse_req_t req, char *path,
566 struct fuse_file_info *fi)
567{
568 int res;
569 struct fuse_intr_data d;
570 fuse_prepare_interrupt(f, req, &d);
571 res = f->op.opendir(path, fi);
572 fuse_finish_interrupt(f, req, &d);
573 return res;
574}
575
576static int fuse_do_open(struct fuse *f, fuse_req_t req, char *path,
577 struct fuse_file_info *fi)
578{
579 int res;
580 struct fuse_intr_data d;
581 fuse_prepare_interrupt(f, req, &d);
582 res = f->op.open(path, fi);
583 fuse_finish_interrupt(f, req, &d);
584 return res;
585}
586
Miklos Szeredi4fca4322006-10-01 14:41:04 +0000587static int fuse_do_flush(struct fuse *f, fuse_req_t req, const char *path,
588 struct fuse_file_info *fi)
589{
590 int res;
591 struct fuse_intr_data d;
592 fuse_prepare_interrupt(f, req, &d);
593 res = f->op.flush(path, fi);
594 fuse_finish_interrupt(f, req, &d);
595 return res;
596}
597
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000598static int fuse_do_statfs(struct fuse *f, fuse_req_t req, const char *path,
599 struct statvfs *buf)
600{
601 int res;
602 struct fuse_intr_data d;
603 fuse_prepare_interrupt(f, req, &d);
604 res = f->op.statfs(path, buf);
605 fuse_finish_interrupt(f, req, &d);
606 return res;
607}
608
609static void fuse_do_releasedir(struct fuse *f, fuse_req_t req,
610 const char *path, struct fuse_file_info *fi)
611{
612 struct fuse_intr_data d;
613 fuse_prepare_interrupt(f, req, &d);
614 f->op.releasedir(path, fi);
615 fuse_finish_interrupt(f, req, &d);
616}
617
618static int fuse_do_create(struct fuse *f, fuse_req_t req, const char *path,
619 mode_t mode, struct fuse_file_info *fi)
620{
621 int res;
622 struct fuse_intr_data d;
623 fuse_prepare_interrupt(f, req, &d);
624 res = f->op.create(path, mode, fi);
625 fuse_finish_interrupt(f, req, &d);
626 return res;
627}
628
629static int fuse_do_lock(struct fuse *f, fuse_req_t req, const char *path,
Miklos Szeredi07407852006-09-30 20:03:52 +0000630 struct fuse_file_info *fi, int cmd, struct flock *lock)
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000631{
632 int res;
633 struct fuse_intr_data d;
634 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredi07407852006-09-30 20:03:52 +0000635 res = f->op.lock(path, fi, cmd, lock);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000636 fuse_finish_interrupt(f, req, &d);
637 return res;
638}
639
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000640static int is_open(struct fuse *f, fuse_ino_t dir, const char *name)
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000641{
642 struct node *node;
643 int isopen = 0;
644 pthread_mutex_lock(&f->lock);
Miklos Szeredif458b8c2004-12-07 16:46:42 +0000645 node = lookup_node(f, dir, name);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000646 if (node && node->open_count > 0)
647 isopen = 1;
648 pthread_mutex_unlock(&f->lock);
649 return isopen;
650}
651
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000652static char *hidden_name(struct fuse *f, fuse_req_t req, fuse_ino_t dir,
653 const char *oldname, char *newname, size_t bufsize)
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000654{
655 struct stat buf;
656 struct node *node;
657 struct node *newnode;
658 char *newpath;
659 int res;
660 int failctr = 10;
661
662 if (!f->op.getattr)
663 return NULL;
664
665 do {
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000666 pthread_mutex_lock(&f->lock);
Miklos Szeredif458b8c2004-12-07 16:46:42 +0000667 node = lookup_node(f, dir, oldname);
668 if (node == NULL) {
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000669 pthread_mutex_unlock(&f->lock);
670 return NULL;
Miklos Szeredif458b8c2004-12-07 16:46:42 +0000671 }
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000672 do {
673 f->hidectr ++;
674 snprintf(newname, bufsize, ".fuse_hidden%08x%08x",
Miklos Szeredia13d9002004-11-02 17:32:03 +0000675 (unsigned int) node->nodeid, f->hidectr);
Miklos Szeredif458b8c2004-12-07 16:46:42 +0000676 newnode = lookup_node(f, dir, newname);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000677 } while(newnode);
678 pthread_mutex_unlock(&f->lock);
Miklos Szeredie5183742005-02-02 11:14:04 +0000679
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000680 newpath = get_path_name(f, dir, newname);
681 if (!newpath)
682 break;
Miklos Szeredie5183742005-02-02 11:14:04 +0000683
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000684 res = fuse_do_getattr(f, req, newpath, &buf);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000685 if (res != 0)
686 break;
687 free(newpath);
688 newpath = NULL;
689 } while(--failctr);
690
691 return newpath;
692}
693
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000694static int hide_node(struct fuse *f, fuse_req_t req, const char *oldpath,
695 fuse_ino_t dir, const char *oldname)
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000696{
697 char newname[64];
698 char *newpath;
Miklos Szeredib2cf9562004-09-16 08:42:40 +0000699 int err = -EBUSY;
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000700
Miklos Szeredib2cf9562004-09-16 08:42:40 +0000701 if (f->op.rename && f->op.unlink) {
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000702 newpath = hidden_name(f, req, dir, oldname, newname, sizeof(newname));
Miklos Szeredib2cf9562004-09-16 08:42:40 +0000703 if (newpath) {
Miklos Szeredibcfa4162006-10-13 19:48:19 +0000704 err = fuse_do_rename(f, req, oldpath, newpath);
705 if (!err)
Miklos Szeredib2cf9562004-09-16 08:42:40 +0000706 err = rename_node(f, dir, oldname, dir, newname, 1);
707 free(newpath);
708 }
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000709 }
Miklos Szeredib2cf9562004-09-16 08:42:40 +0000710 return err;
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000711}
712
Miklos Szeredi320abe42006-01-30 18:14:51 +0000713static int mtime_eq(const struct stat *stbuf, const struct timespec *ts)
714{
715 return stbuf->st_mtime == ts->tv_sec
Csaba Henk3e3a1252006-09-24 14:53:29 +0000716#ifdef FUSE_STAT_HAS_NANOSEC
717 && ST_MTIM(stbuf).tv_nsec == ts->tv_nsec
Miklos Szeredi320abe42006-01-30 18:14:51 +0000718#endif
719 ;
720}
721
722static void mtime_set(const struct stat *stbuf, struct timespec *ts)
723{
Csaba Henk3e3a1252006-09-24 14:53:29 +0000724#ifdef FUSE_STAT_HAS_NANOSEC
725 *ts = ST_MTIM(stbuf);
Miklos Szeredi320abe42006-01-30 18:14:51 +0000726#else
727 ts->tv_sec = stbuf->st_mtime;
728#endif
729}
730
Miklos Szeredi2512aaa2006-05-03 14:54:59 +0000731#ifndef CLOCK_MONOTONIC
732#define CLOCK_MONOTONIC CLOCK_REALTIME
733#endif
734
Miklos Szeredi320abe42006-01-30 18:14:51 +0000735static void curr_time(struct timespec *now)
736{
737 static clockid_t clockid = CLOCK_MONOTONIC;
738 int res = clock_gettime(clockid, now);
739 if (res == -1 && errno == EINVAL) {
740 clockid = CLOCK_REALTIME;
741 res = clock_gettime(clockid, now);
742 }
743 if (res == -1) {
744 perror("fuse: clock_gettime");
745 abort();
746 }
747}
748
749static void update_stat(struct node *node, const struct stat *stbuf)
750{
751 if (node->cache_valid && (!mtime_eq(stbuf, &node->mtime) ||
752 stbuf->st_size != node->size))
753 node->cache_valid = 0;
754 mtime_set(stbuf, &node->mtime);
755 node->size = stbuf->st_size;
756 curr_time(&node->stat_updated);
757}
758
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000759static int lookup_path(struct fuse *f, fuse_req_t req, fuse_ino_t nodeid,
760 const char *name, const char *path,
761 struct fuse_entry_param *e, struct fuse_file_info *fi)
Miklos Szeredi76f65782004-02-19 16:55:40 +0000762{
763 int res;
Miklos Szeredi76f65782004-02-19 16:55:40 +0000764
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000765 memset(e, 0, sizeof(struct fuse_entry_param));
Miklos Szeredif7eec032005-10-28 13:09:50 +0000766 if (fi && f->op.fgetattr)
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000767 res = fuse_do_fgetattr(f, req, path, &e->attr, fi);
Miklos Szeredif7eec032005-10-28 13:09:50 +0000768 else
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000769 res = fuse_do_getattr(f, req, path, &e->attr);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000770 if (res == 0) {
Miklos Szeredi76f65782004-02-19 16:55:40 +0000771 struct node *node;
772
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000773 node = find_node(f, nodeid, name);
Miklos Szeredib2cf9562004-09-16 08:42:40 +0000774 if (node == NULL)
775 res = -ENOMEM;
776 else {
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000777 e->ino = node->nodeid;
778 e->generation = node->generation;
Miklos Szeredi659743b2005-12-09 17:41:42 +0000779 e->entry_timeout = f->conf.entry_timeout;
780 e->attr_timeout = f->conf.attr_timeout;
Miklos Szeredi320abe42006-01-30 18:14:51 +0000781 if (f->conf.auto_cache) {
782 pthread_mutex_lock(&f->lock);
783 update_stat(node, &e->attr);
784 pthread_mutex_unlock(&f->lock);
785 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000786 set_stat(f, e->ino, &e->attr);
Miklos Szeredi659743b2005-12-09 17:41:42 +0000787 if (f->conf.debug) {
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000788 printf(" NODEID: %lu\n", (unsigned long) e->ino);
Miklos Szeredib2cf9562004-09-16 08:42:40 +0000789 fflush(stdout);
790 }
Miklos Szeredi76f65782004-02-19 16:55:40 +0000791 }
792 }
793 return res;
794}
795
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000796static struct fuse_context_i *fuse_get_context_internal(void)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000797{
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000798 struct fuse_context_i *c;
799
800 c = (struct fuse_context_i *) pthread_getspecific(fuse_context_key);
801 if (c == NULL) {
802 c = (struct fuse_context_i *) malloc(sizeof(struct fuse_context_i));
803 if (c == NULL) {
804 /* This is hard to deal with properly, so just abort. If
805 memory is so low that the context cannot be allocated,
806 there's not much hope for the filesystem anyway */
807 fprintf(stderr, "fuse: failed to allocate thread specific data\n");
808 abort();
809 }
810 pthread_setspecific(fuse_context_key, c);
811 }
812 return c;
813}
814
815static void fuse_freecontext(void *data)
816{
817 free(data);
818}
819
820static int fuse_create_context_key(void)
821{
822 int err = 0;
823 pthread_mutex_lock(&fuse_context_lock);
824 if (!fuse_context_ref) {
825 err = pthread_key_create(&fuse_context_key, fuse_freecontext);
826 if (err) {
827 fprintf(stderr, "fuse: failed to create thread specific key: %s\n",
828 strerror(err));
829 pthread_mutex_unlock(&fuse_context_lock);
830 return -1;
831 }
832 }
833 fuse_context_ref++;
834 pthread_mutex_unlock(&fuse_context_lock);
835 return 0;
836}
837
838static void fuse_delete_context_key(void)
839{
840 pthread_mutex_lock(&fuse_context_lock);
841 fuse_context_ref--;
842 if (!fuse_context_ref) {
843 free(pthread_getspecific(fuse_context_key));
844 pthread_key_delete(fuse_context_key);
845 }
846 pthread_mutex_unlock(&fuse_context_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000847}
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000848
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000849static struct fuse *req_fuse_prepare(fuse_req_t req)
850{
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000851 struct fuse_context_i *c = fuse_get_context_internal();
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000852 const struct fuse_ctx *ctx = fuse_req_ctx(req);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000853 c->req = req;
854 c->ctx.fuse = req_fuse(req);
855 c->ctx.uid = ctx->uid;
856 c->ctx.gid = ctx->gid;
857 c->ctx.pid = ctx->pid;
858 c->ctx.private_data = c->ctx.fuse->user_data;
859 return c->ctx.fuse;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000860}
861
862static inline void reply_err(fuse_req_t req, int err)
863{
864 /* fuse_reply_err() uses non-negated errno values */
865 fuse_reply_err(req, -err);
866}
867
868static void reply_entry(fuse_req_t req, const struct fuse_entry_param *e,
869 int err)
870{
871 if (!err) {
Miklos Szeredib67f2162006-02-20 10:55:33 +0000872 struct fuse *f = req_fuse(req);
Miklos Szeredi9b813af2005-07-21 07:59:37 +0000873 if (fuse_reply_entry(req, e) == -ENOENT)
Miklos Szeredib67f2162006-02-20 10:55:33 +0000874 forget_node(f, e->ino, 1);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000875 } else
876 reply_err(req, err);
877}
878
Miklos Szeredi065f2222006-01-20 15:15:21 +0000879static void fuse_data_init(void *data, struct fuse_conn_info *conn)
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000880{
881 struct fuse *f = (struct fuse *) data;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000882 struct fuse_context_i *c = fuse_get_context_internal();
Miklos Szeredi4f5df5e2005-10-07 12:39:58 +0000883
884 memset(c, 0, sizeof(*c));
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000885 c->ctx.fuse = f;
886 c->ctx.private_data = f->user_data;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000887
888 if (f->op.init)
Miklos Szeredi065f2222006-01-20 15:15:21 +0000889 f->user_data = f->op.init(conn);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000890}
891
892static void fuse_data_destroy(void *data)
893{
894 struct fuse *f = (struct fuse *) data;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000895 struct fuse_context_i *c = fuse_get_context_internal();
Miklos Szeredi4f5df5e2005-10-07 12:39:58 +0000896
897 memset(c, 0, sizeof(*c));
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000898 c->ctx.fuse = f;
899 c->ctx.private_data = f->user_data;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000900
901 if (f->op.destroy)
902 f->op.destroy(f->user_data);
903}
904
905static void fuse_lookup(fuse_req_t req, fuse_ino_t parent, const char *name)
906{
907 struct fuse *f = req_fuse_prepare(req);
908 struct fuse_entry_param e;
909 char *path;
910 int err;
911
912 err = -ENOENT;
Miklos Szeredic2a33ee2005-05-09 13:29:17 +0000913 pthread_rwlock_rdlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000914 path = get_path_name(f, parent, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000915 if (path != NULL) {
Miklos Szeredi659743b2005-12-09 17:41:42 +0000916 if (f->conf.debug) {
Miklos Szeredi6ebe2342002-01-06 21:44:16 +0000917 printf("LOOKUP %s\n", path);
918 fflush(stdout);
919 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000920 err = -ENOSYS;
Miklos Szeredi2b478112005-11-28 13:27:10 +0000921 if (f->op.getattr) {
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000922 err = lookup_path(f, req, parent, name, path, &e, NULL);
Miklos Szeredi659743b2005-12-09 17:41:42 +0000923 if (err == -ENOENT && f->conf.negative_timeout != 0.0) {
Miklos Szeredi2b478112005-11-28 13:27:10 +0000924 e.ino = 0;
Miklos Szeredi659743b2005-12-09 17:41:42 +0000925 e.entry_timeout = f->conf.negative_timeout;
Miklos Szeredi2b478112005-11-28 13:27:10 +0000926 err = 0;
927 }
928 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000929 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000930 }
Miklos Szeredic2a33ee2005-05-09 13:29:17 +0000931 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000932 reply_entry(req, &e, err);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000933}
934
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000935static void fuse_forget(fuse_req_t req, fuse_ino_t ino, unsigned long nlookup)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000936{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000937 struct fuse *f = req_fuse(req);
Miklos Szeredi659743b2005-12-09 17:41:42 +0000938 if (f->conf.debug) {
Miklos Szeredi3a770472005-11-11 21:32:42 +0000939 printf("FORGET %llu/%lu\n", (unsigned long long) ino, nlookup);
Miklos Szeredi43696432001-11-18 19:15:05 +0000940 fflush(stdout);
941 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000942 forget_node(f, ino, nlookup);
943 fuse_reply_none(req);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000944}
945
Miklos Szerediecce1bf2005-08-25 15:19:06 +0000946static void fuse_getattr(fuse_req_t req, fuse_ino_t ino,
947 struct fuse_file_info *fi)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000948{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000949 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000950 struct stat buf;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000951 char *path;
952 int err;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000953
Miklos Szerediecce1bf2005-08-25 15:19:06 +0000954 (void) fi;
Miklos Szeredi16dbf942006-09-02 13:20:40 +0000955 memset(&buf, 0, sizeof(buf));
Miklos Szerediecce1bf2005-08-25 15:19:06 +0000956
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000957 err = -ENOENT;
Miklos Szeredic2a33ee2005-05-09 13:29:17 +0000958 pthread_rwlock_rdlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000959 path = get_path(f, ino);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000960 if (path != NULL) {
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000961 err = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000962 if (f->op.getattr)
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000963 err = fuse_do_getattr(f, req, path, &buf);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000964 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000965 }
Miklos Szeredic2a33ee2005-05-09 13:29:17 +0000966 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000967 if (!err) {
Miklos Szeredi08dab162006-02-01 13:39:15 +0000968 if (f->conf.auto_cache) {
969 pthread_mutex_lock(&f->lock);
970 update_stat(get_node(f, ino), &buf);
971 pthread_mutex_unlock(&f->lock);
972 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000973 set_stat(f, ino, &buf);
Miklos Szeredi659743b2005-12-09 17:41:42 +0000974 fuse_reply_attr(req, &buf, f->conf.attr_timeout);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000975 } else
976 reply_err(req, err);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000977}
978
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000979static int do_chmod(struct fuse *f, fuse_req_t req, const char *path,
980 struct stat *attr)
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000981{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000982 int err;
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000983
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000984 err = -ENOSYS;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000985 if (f->op.chmod) {
986 struct fuse_intr_data d;
987 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000988 err = f->op.chmod(path, attr->st_mode);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000989 fuse_finish_interrupt(f, req, &d);
990 }
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000991
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000992 return err;
Miklos Szeredie5183742005-02-02 11:14:04 +0000993}
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000994
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000995static int do_chown(struct fuse *f, fuse_req_t req, const char *path,
996 struct stat *attr, int valid)
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000997{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000998 int err;
999 uid_t uid = (valid & FUSE_SET_ATTR_UID) ? attr->st_uid : (uid_t) -1;
1000 gid_t gid = (valid & FUSE_SET_ATTR_GID) ? attr->st_gid : (gid_t) -1;
Miklos Szeredie5183742005-02-02 11:14:04 +00001001
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001002 err = -ENOSYS;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001003 if (f->op.chown) {
1004 struct fuse_intr_data d;
1005 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001006 err = f->op.chown(path, uid, gid);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001007 fuse_finish_interrupt(f, req, &d);
1008 }
Miklos Szeredif3ea83b2001-11-07 14:55:16 +00001009
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001010 return err;
Miklos Szeredif3ea83b2001-11-07 14:55:16 +00001011}
1012
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001013static int do_truncate(struct fuse *f, fuse_req_t req, const char *path,
1014 struct stat *attr, struct fuse_file_info *fi)
Miklos Szeredif3ea83b2001-11-07 14:55:16 +00001015{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001016 int err;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001017 struct fuse_intr_data d;
Miklos Szeredif3ea83b2001-11-07 14:55:16 +00001018
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001019 err = -ENOSYS;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001020 if (fi && f->op.ftruncate) {
1021 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredi11509ce2005-10-26 16:04:04 +00001022 err = f->op.ftruncate(path, attr->st_size, fi);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001023 fuse_finish_interrupt(f, req, &d);
1024 } else if (f->op.truncate) {
1025 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001026 err = f->op.truncate(path, attr->st_size);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001027 fuse_finish_interrupt(f, req, &d);
1028 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001029 return err;
Miklos Szeredif3ea83b2001-11-07 14:55:16 +00001030}
1031
Miklos Szeredic3b76812006-09-16 08:52:09 +00001032static int do_utimens(struct fuse *f, fuse_req_t req, const char *path,
1033 struct stat *attr)
Miklos Szeredif3ea83b2001-11-07 14:55:16 +00001034{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001035 int err;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001036 struct fuse_intr_data d;
Miklos Szeredifa440772006-09-02 09:51:08 +00001037
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001038 err = -ENOSYS;
Miklos Szeredic3b76812006-09-16 08:52:09 +00001039 if (f->op.utimens) {
Miklos Szeredifa440772006-09-02 09:51:08 +00001040 struct timespec tv[2];
Csaba Henk3e3a1252006-09-24 14:53:29 +00001041#ifdef FUSE_STAT_HAS_NANOSEC
1042 tv[0] = ST_ATIM(attr);
1043 tv[1] = ST_MTIM(attr);
1044#else
1045 tv[0].tv_sec = attr->st_atime;
1046 tv[0].tv_nsec = 0;
1047 tv[1].tv_sec = attr->st_mtime;
1048 tv[1].tv_nsec = 0;
1049#endif
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001050 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredic3b76812006-09-16 08:52:09 +00001051 err = f->op.utimens(path, tv);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001052 fuse_finish_interrupt(f, req, &d);
Miklos Szeredifa440772006-09-02 09:51:08 +00001053 } else if (f->op.utime) {
1054 struct utimbuf buf;
1055 buf.actime = attr->st_atime;
1056 buf.modtime = attr->st_mtime;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001057 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001058 err = f->op.utime(path, &buf);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001059 fuse_finish_interrupt(f, req, &d);
Miklos Szeredifa440772006-09-02 09:51:08 +00001060 }
Miklos Szeredif3ea83b2001-11-07 14:55:16 +00001061
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001062 return err;
Miklos Szeredif3ea83b2001-11-07 14:55:16 +00001063}
1064
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001065static void fuse_setattr(fuse_req_t req, fuse_ino_t ino, struct stat *attr,
Miklos Szerediecce1bf2005-08-25 15:19:06 +00001066 int valid, struct fuse_file_info *fi)
Miklos Szeredi5e183482001-10-31 14:52:35 +00001067{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001068 struct fuse *f = req_fuse_prepare(req);
1069 struct stat buf;
Miklos Szeredi5e183482001-10-31 14:52:35 +00001070 char *path;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001071 int err;
Miklos Szeredi5e183482001-10-31 14:52:35 +00001072
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001073 err = -ENOENT;
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001074 pthread_rwlock_rdlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001075 path = get_path(f, ino);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001076 if (path != NULL) {
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001077 err = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001078 if (f->op.getattr) {
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001079 err = 0;
1080 if (!err && (valid & FUSE_SET_ATTR_MODE))
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001081 err = do_chmod(f, req, path, attr);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001082 if (!err && (valid & (FUSE_SET_ATTR_UID | FUSE_SET_ATTR_GID)))
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001083 err = do_chown(f, req, path, attr, valid);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001084 if (!err && (valid & FUSE_SET_ATTR_SIZE))
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001085 err = do_truncate(f, req, path, attr, fi);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001086 if (!err && (valid & (FUSE_SET_ATTR_ATIME | FUSE_SET_ATTR_MTIME)) == (FUSE_SET_ATTR_ATIME | FUSE_SET_ATTR_MTIME))
Miklos Szeredic3b76812006-09-16 08:52:09 +00001087 err = do_utimens(f, req, path, attr);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001088 if (!err)
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001089 err = fuse_do_getattr(f, req, path, &buf);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001090 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001091 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001092 }
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001093 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001094 if (!err) {
Miklos Szeredi08dab162006-02-01 13:39:15 +00001095 if (f->conf.auto_cache) {
1096 pthread_mutex_lock(&f->lock);
1097 update_stat(get_node(f, ino), &buf);
1098 pthread_mutex_unlock(&f->lock);
1099 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001100 set_stat(f, ino, &buf);
Miklos Szeredi659743b2005-12-09 17:41:42 +00001101 fuse_reply_attr(req, &buf, f->conf.attr_timeout);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001102 } else
1103 reply_err(req, err);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001104}
1105
Miklos Szeredib0b13d12005-10-26 12:53:25 +00001106static void fuse_access(fuse_req_t req, fuse_ino_t ino, int mask)
1107{
1108 struct fuse *f = req_fuse_prepare(req);
1109 char *path;
1110 int err;
1111
1112 err = -ENOENT;
1113 pthread_rwlock_rdlock(&f->tree_lock);
1114 path = get_path(f, ino);
1115 if (path != NULL) {
Miklos Szeredi659743b2005-12-09 17:41:42 +00001116 if (f->conf.debug) {
Miklos Szeredib0b13d12005-10-26 12:53:25 +00001117 printf("ACCESS %s 0%o\n", path, mask);
1118 fflush(stdout);
1119 }
1120 err = -ENOSYS;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001121 if (f->op.access) {
1122 struct fuse_intr_data d;
1123 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredib0b13d12005-10-26 12:53:25 +00001124 err = f->op.access(path, mask);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001125 fuse_finish_interrupt(f, req, &d);
1126 }
Miklos Szeredib0b13d12005-10-26 12:53:25 +00001127 free(path);
1128 }
1129 pthread_rwlock_unlock(&f->tree_lock);
1130 reply_err(req, err);
1131}
1132
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001133static void fuse_readlink(fuse_req_t req, fuse_ino_t ino)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001134{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001135 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredif6e0ec62005-08-03 09:11:06 +00001136 char linkname[PATH_MAX + 1];
Miklos Szeredib483c932001-10-29 14:57:57 +00001137 char *path;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001138 int err;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001139
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001140 err = -ENOENT;
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001141 pthread_rwlock_rdlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001142 path = get_path(f, ino);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001143 if (path != NULL) {
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001144 err = -ENOSYS;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001145 if (f->op.readlink) {
1146 struct fuse_intr_data d;
1147 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredif6e0ec62005-08-03 09:11:06 +00001148 err = f->op.readlink(path, linkname, sizeof(linkname));
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001149 fuse_finish_interrupt(f, req, &d);
1150 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001151 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001152 }
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001153 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001154 if (!err) {
Miklos Szeredif6e0ec62005-08-03 09:11:06 +00001155 linkname[PATH_MAX] = '\0';
1156 fuse_reply_readlink(req, linkname);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001157 } else
1158 reply_err(req, err);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001159}
1160
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001161static void fuse_mknod(fuse_req_t req, fuse_ino_t parent, const char *name,
1162 mode_t mode, dev_t rdev)
Miklos Szeredib483c932001-10-29 14:57:57 +00001163{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001164 struct fuse *f = req_fuse_prepare(req);
1165 struct fuse_entry_param e;
Miklos Szeredib483c932001-10-29 14:57:57 +00001166 char *path;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001167 int err;
Miklos Szeredib483c932001-10-29 14:57:57 +00001168
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001169 err = -ENOENT;
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001170 pthread_rwlock_rdlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001171 path = get_path_name(f, parent, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001172 if (path != NULL) {
Miklos Szeredi659743b2005-12-09 17:41:42 +00001173 if (f->conf.debug) {
Miklos Szeredi76f65782004-02-19 16:55:40 +00001174 printf("MKNOD %s\n", path);
1175 fflush(stdout);
1176 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001177 err = -ENOSYS;
Miklos Szeredib3f99722005-11-16 13:00:24 +00001178 if (S_ISREG(mode) && f->op.create && f->op.getattr) {
1179 struct fuse_file_info fi;
1180
1181 memset(&fi, 0, sizeof(fi));
1182 fi.flags = O_CREAT | O_EXCL | O_WRONLY;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001183 err = fuse_do_create(f, req, path, mode, &fi);
Miklos Szeredib3f99722005-11-16 13:00:24 +00001184 if (!err) {
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001185 err = lookup_path(f, req, parent, name, path, &e, &fi);
Miklos Szeredib3f99722005-11-16 13:00:24 +00001186 if (f->op.release)
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001187 fuse_do_release(f, req, path, &fi);
Miklos Szeredib3f99722005-11-16 13:00:24 +00001188 }
1189 } else if (f->op.mknod && f->op.getattr) {
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001190 struct fuse_intr_data d;
1191 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001192 err = f->op.mknod(path, mode, rdev);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001193 fuse_finish_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001194 if (!err)
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001195 err = lookup_path(f, req, parent, name, path, &e, NULL);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001196 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001197 free(path);
Miklos Szeredib483c932001-10-29 14:57:57 +00001198 }
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001199 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001200 reply_entry(req, &e, err);
Miklos Szeredib483c932001-10-29 14:57:57 +00001201}
1202
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001203static void fuse_mkdir(fuse_req_t req, fuse_ino_t parent, const char *name,
1204 mode_t mode)
Miklos Szeredib483c932001-10-29 14:57:57 +00001205{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001206 struct fuse *f = req_fuse_prepare(req);
1207 struct fuse_entry_param e;
Miklos Szeredib483c932001-10-29 14:57:57 +00001208 char *path;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001209 int err;
Miklos Szeredib483c932001-10-29 14:57:57 +00001210
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001211 err = -ENOENT;
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001212 pthread_rwlock_rdlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001213 path = get_path_name(f, parent, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001214 if (path != NULL) {
Miklos Szeredi659743b2005-12-09 17:41:42 +00001215 if (f->conf.debug) {
Miklos Szeredi76f65782004-02-19 16:55:40 +00001216 printf("MKDIR %s\n", path);
1217 fflush(stdout);
1218 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001219 err = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001220 if (f->op.mkdir && f->op.getattr) {
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001221 struct fuse_intr_data d;
1222 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001223 err = f->op.mkdir(path, mode);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001224 fuse_finish_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001225 if (!err)
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001226 err = lookup_path(f, req, parent, name, path, &e, NULL);
Miklos Szeredi76f65782004-02-19 16:55:40 +00001227 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001228 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001229 }
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001230 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001231 reply_entry(req, &e, err);
Miklos Szeredib483c932001-10-29 14:57:57 +00001232}
1233
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001234static void fuse_unlink(fuse_req_t req, fuse_ino_t parent, const char *name)
Miklos Szeredib483c932001-10-29 14:57:57 +00001235{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001236 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredib483c932001-10-29 14:57:57 +00001237 char *path;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001238 int err;
Miklos Szeredib483c932001-10-29 14:57:57 +00001239
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001240 err = -ENOENT;
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001241 pthread_rwlock_wrlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001242 path = get_path_name(f, parent, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001243 if (path != NULL) {
Miklos Szeredi659743b2005-12-09 17:41:42 +00001244 if (f->conf.debug) {
Miklos Szeredi209f5d02004-07-24 19:56:16 +00001245 printf("UNLINK %s\n", path);
1246 fflush(stdout);
1247 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001248 err = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001249 if (f->op.unlink) {
Miklos Szeredi659743b2005-12-09 17:41:42 +00001250 if (!f->conf.hard_remove && is_open(f, parent, name))
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001251 err = hide_node(f, req, path, parent, name);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001252 else {
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001253 err = fuse_do_unlink(f, req, path);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001254 if (!err)
1255 remove_node(f, parent, name);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001256 }
Miklos Szeredi5e183482001-10-31 14:52:35 +00001257 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001258 free(path);
Miklos Szeredib483c932001-10-29 14:57:57 +00001259 }
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001260 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001261 reply_err(req, err);
Miklos Szeredib5958612004-02-20 14:10:49 +00001262}
1263
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001264static void fuse_rmdir(fuse_req_t req, fuse_ino_t parent, const char *name)
Miklos Szeredib5958612004-02-20 14:10:49 +00001265{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001266 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredib5958612004-02-20 14:10:49 +00001267 char *path;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001268 int err;
Miklos Szeredib5958612004-02-20 14:10:49 +00001269
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001270 err = -ENOENT;
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001271 pthread_rwlock_wrlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001272 path = get_path_name(f, parent, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001273 if (path != NULL) {
Miklos Szeredi659743b2005-12-09 17:41:42 +00001274 if (f->conf.debug) {
Miklos Szeredi209f5d02004-07-24 19:56:16 +00001275 printf("RMDIR %s\n", path);
1276 fflush(stdout);
1277 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001278 err = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001279 if (f->op.rmdir) {
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001280 struct fuse_intr_data d;
1281 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001282 err = f->op.rmdir(path);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001283 fuse_finish_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001284 if (!err)
1285 remove_node(f, parent, name);
Miklos Szeredib5958612004-02-20 14:10:49 +00001286 }
1287 free(path);
1288 }
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001289 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001290 reply_err(req, err);
Miklos Szeredib483c932001-10-29 14:57:57 +00001291}
1292
Miklos Szeredif6e0ec62005-08-03 09:11:06 +00001293static void fuse_symlink(fuse_req_t req, const char *linkname,
1294 fuse_ino_t parent, const char *name)
Miklos Szeredib483c932001-10-29 14:57:57 +00001295{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001296 struct fuse *f = req_fuse_prepare(req);
1297 struct fuse_entry_param e;
Miklos Szeredib483c932001-10-29 14:57:57 +00001298 char *path;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001299 int err;
Miklos Szeredib483c932001-10-29 14:57:57 +00001300
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001301 err = -ENOENT;
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001302 pthread_rwlock_rdlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001303 path = get_path_name(f, parent, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001304 if (path != NULL) {
Miklos Szeredi659743b2005-12-09 17:41:42 +00001305 if (f->conf.debug) {
Miklos Szeredi76f65782004-02-19 16:55:40 +00001306 printf("SYMLINK %s\n", path);
1307 fflush(stdout);
1308 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001309 err = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001310 if (f->op.symlink && f->op.getattr) {
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001311 struct fuse_intr_data d;
1312 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredif6e0ec62005-08-03 09:11:06 +00001313 err = f->op.symlink(linkname, path);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001314 fuse_finish_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001315 if (!err)
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001316 err = lookup_path(f, req, parent, name, path, &e, NULL);
Miklos Szeredi76f65782004-02-19 16:55:40 +00001317 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001318 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001319 }
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001320 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001321 reply_entry(req, &e, err);
Miklos Szeredib483c932001-10-29 14:57:57 +00001322}
1323
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001324static void fuse_rename(fuse_req_t req, fuse_ino_t olddir, const char *oldname,
1325 fuse_ino_t newdir, const char *newname)
Miklos Szeredi19dff1b2001-10-30 15:06:52 +00001326{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001327 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001328 char *oldpath;
1329 char *newpath;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001330 int err;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +00001331
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001332 err = -ENOENT;
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001333 pthread_rwlock_wrlock(&f->tree_lock);
Miklos Szeredia181e612001-11-06 12:03:23 +00001334 oldpath = get_path_name(f, olddir, oldname);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001335 if (oldpath != NULL) {
Miklos Szeredia181e612001-11-06 12:03:23 +00001336 newpath = get_path_name(f, newdir, newname);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001337 if (newpath != NULL) {
Miklos Szeredi659743b2005-12-09 17:41:42 +00001338 if (f->conf.debug) {
Miklos Szeredi209f5d02004-07-24 19:56:16 +00001339 printf("RENAME %s -> %s\n", oldpath, newpath);
1340 fflush(stdout);
1341 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001342 err = -ENOSYS;
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001343 if (f->op.rename) {
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001344 err = 0;
Miklos Szeredi659743b2005-12-09 17:41:42 +00001345 if (!f->conf.hard_remove &&
Miklos Szeredi2529ca22004-07-13 15:36:52 +00001346 is_open(f, newdir, newname))
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001347 err = hide_node(f, req, newpath, newdir, newname);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001348 if (!err) {
Miklos Szeredibcfa4162006-10-13 19:48:19 +00001349 err = fuse_do_rename(f, req, oldpath, newpath);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001350 if (!err)
1351 err = rename_node(f, olddir, oldname, newdir, newname, 0);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001352 }
1353 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001354 free(newpath);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001355 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001356 free(oldpath);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001357 }
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001358 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001359 reply_err(req, err);
Miklos Szeredi19dff1b2001-10-30 15:06:52 +00001360}
1361
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001362static void fuse_link(fuse_req_t req, fuse_ino_t ino, fuse_ino_t newparent,
1363 const char *newname)
Miklos Szeredi19dff1b2001-10-30 15:06:52 +00001364{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001365 struct fuse *f = req_fuse_prepare(req);
1366 struct fuse_entry_param e;
Miklos Szeredi5e183482001-10-31 14:52:35 +00001367 char *oldpath;
1368 char *newpath;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001369 int err;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +00001370
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001371 err = -ENOENT;
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001372 pthread_rwlock_rdlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001373 oldpath = get_path(f, ino);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001374 if (oldpath != NULL) {
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001375 newpath = get_path_name(f, newparent, newname);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001376 if (newpath != NULL) {
Miklos Szeredi659743b2005-12-09 17:41:42 +00001377 if (f->conf.debug) {
Miklos Szeredi76f65782004-02-19 16:55:40 +00001378 printf("LINK %s\n", newpath);
1379 fflush(stdout);
1380 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001381 err = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001382 if (f->op.link && f->op.getattr) {
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001383 struct fuse_intr_data d;
1384 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001385 err = f->op.link(oldpath, newpath);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001386 fuse_finish_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001387 if (!err)
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001388 err = lookup_path(f, req, newparent, newname, newpath, &e,
1389 NULL);
Miklos Szeredi76f65782004-02-19 16:55:40 +00001390 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001391 free(newpath);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001392 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001393 free(oldpath);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001394 }
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001395 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001396 reply_entry(req, &e, err);
Miklos Szeredi19dff1b2001-10-30 15:06:52 +00001397}
1398
Miklos Szeredid9079a72005-10-26 15:29:06 +00001399static void fuse_create(fuse_req_t req, fuse_ino_t parent, const char *name,
1400 mode_t mode, struct fuse_file_info *fi)
1401{
1402 struct fuse *f = req_fuse_prepare(req);
1403 struct fuse_entry_param e;
1404 char *path;
1405 int err;
1406
1407 err = -ENOENT;
1408 pthread_rwlock_rdlock(&f->tree_lock);
1409 path = get_path_name(f, parent, name);
1410 if (path != NULL) {
1411 err = -ENOSYS;
1412 if (f->op.create && f->op.getattr) {
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001413 err = fuse_do_create(f, req, path, mode, fi);
Miklos Szeredid9079a72005-10-26 15:29:06 +00001414 if (!err) {
Miklos Szeredi659743b2005-12-09 17:41:42 +00001415 if (f->conf.debug) {
Miklos Szeredi3a770472005-11-11 21:32:42 +00001416 printf("CREATE[%llu] flags: 0x%x %s\n",
1417 (unsigned long long) fi->fh, fi->flags, path);
Miklos Szeredid9079a72005-10-26 15:29:06 +00001418 fflush(stdout);
1419 }
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001420 err = lookup_path(f, req, parent, name, path, &e, fi);
Miklos Szeredid9079a72005-10-26 15:29:06 +00001421 if (err) {
1422 if (f->op.release)
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001423 fuse_do_release(f, req, path, fi);
Miklos Szeredid9079a72005-10-26 15:29:06 +00001424 } else if (!S_ISREG(e.attr.st_mode)) {
1425 err = -EIO;
1426 if (f->op.release)
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001427 fuse_do_release(f, req, path, fi);
Miklos Szeredid9079a72005-10-26 15:29:06 +00001428 forget_node(f, e.ino, 1);
1429 }
1430 }
1431 }
1432 }
1433
1434 if (!err) {
Miklos Szeredi659743b2005-12-09 17:41:42 +00001435 if (f->conf.direct_io)
Miklos Szeredid9079a72005-10-26 15:29:06 +00001436 fi->direct_io = 1;
Miklos Szeredi659743b2005-12-09 17:41:42 +00001437 if (f->conf.kernel_cache)
Miklos Szeredid9079a72005-10-26 15:29:06 +00001438 fi->keep_cache = 1;
1439
1440 pthread_mutex_lock(&f->lock);
1441 if (fuse_reply_create(req, &e, fi) == -ENOENT) {
1442 /* The open syscall was interrupted, so it must be cancelled */
1443 if(f->op.release)
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001444 fuse_do_release(f, req, path, fi);
Miklos Szeredifc5309c2006-11-11 09:55:55 +00001445 pthread_mutex_unlock(&f->lock);
Miklos Szeredid9079a72005-10-26 15:29:06 +00001446 forget_node(f, e.ino, 1);
1447 } else {
1448 struct node *node = get_node(f, e.ino);
1449 node->open_count ++;
Miklos Szeredifc5309c2006-11-11 09:55:55 +00001450 pthread_mutex_unlock(&f->lock);
Miklos Szeredid9079a72005-10-26 15:29:06 +00001451 }
Miklos Szeredid9079a72005-10-26 15:29:06 +00001452 } else
1453 reply_err(req, err);
1454
1455 if (path)
1456 free(path);
1457 pthread_rwlock_unlock(&f->tree_lock);
1458}
1459
Miklos Szeredi320abe42006-01-30 18:14:51 +00001460static double diff_timespec(const struct timespec *t1,
1461 const struct timespec *t2)
1462{
1463 return (t1->tv_sec - t2->tv_sec) +
1464 ((double) t1->tv_nsec - (double) t2->tv_nsec) / 1000000000.0;
1465}
1466
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001467static void open_auto_cache(struct fuse *f, fuse_req_t req, fuse_ino_t ino,
1468 const char *path, struct fuse_file_info *fi)
Miklos Szeredi320abe42006-01-30 18:14:51 +00001469{
1470 struct node *node = get_node(f, ino);
Miklos Szeredi08dab162006-02-01 13:39:15 +00001471 if (node->cache_valid) {
1472 struct timespec now;
Miklos Szeredi320abe42006-01-30 18:14:51 +00001473
Miklos Szeredi08dab162006-02-01 13:39:15 +00001474 curr_time(&now);
Miklos Szeredi6e806e92006-02-16 16:59:39 +00001475 if (diff_timespec(&now, &node->stat_updated) > f->conf.ac_attr_timeout) {
Miklos Szeredi08dab162006-02-01 13:39:15 +00001476 struct stat stbuf;
1477 int err;
Miklos Szeredi320abe42006-01-30 18:14:51 +00001478
Miklos Szeredi08dab162006-02-01 13:39:15 +00001479 if (f->op.fgetattr)
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001480 err = fuse_do_fgetattr(f, req, path, &stbuf, fi);
Miklos Szeredi08dab162006-02-01 13:39:15 +00001481 else
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001482 err = fuse_do_getattr(f, req, path, &stbuf);
Miklos Szeredi08dab162006-02-01 13:39:15 +00001483
1484 if (!err)
1485 update_stat(node, &stbuf);
1486 else
1487 node->cache_valid = 0;
1488 }
Miklos Szeredi320abe42006-01-30 18:14:51 +00001489 }
1490 if (node->cache_valid)
1491 fi->keep_cache = 1;
Miklos Szeredi08dab162006-02-01 13:39:15 +00001492
1493 node->cache_valid = 1;
Miklos Szeredi320abe42006-01-30 18:14:51 +00001494}
1495
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001496static void fuse_open(fuse_req_t req, fuse_ino_t ino,
1497 struct fuse_file_info *fi)
Miklos Szeredi5e183482001-10-31 14:52:35 +00001498{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001499 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredi31066bb2005-08-01 14:49:31 +00001500 char *path = NULL;
1501 int err = 0;
Miklos Szeredi5e183482001-10-31 14:52:35 +00001502
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001503 pthread_rwlock_rdlock(&f->tree_lock);
Miklos Szeredi31066bb2005-08-01 14:49:31 +00001504 if (f->op.open) {
1505 err = -ENOENT;
1506 path = get_path(f, ino);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00001507 if (path != NULL)
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001508 err = fuse_compat_open(f, req, path, fi);
Miklos Szeredi40b9a5a2002-12-10 16:09:02 +00001509 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001510 if (!err) {
Miklos Szeredi659743b2005-12-09 17:41:42 +00001511 if (f->conf.debug) {
Miklos Szeredi3a770472005-11-11 21:32:42 +00001512 printf("OPEN[%llu] flags: 0x%x\n", (unsigned long long) fi->fh,
1513 fi->flags);
Miklos Szeredi209f5d02004-07-24 19:56:16 +00001514 fflush(stdout);
1515 }
Miklos Szeredie5183742005-02-02 11:14:04 +00001516
Miklos Szeredi659743b2005-12-09 17:41:42 +00001517 if (f->conf.direct_io)
Miklos Szeredie77cc072005-08-01 11:58:51 +00001518 fi->direct_io = 1;
Miklos Szeredi659743b2005-12-09 17:41:42 +00001519 if (f->conf.kernel_cache)
Miklos Szeredie77cc072005-08-01 11:58:51 +00001520 fi->keep_cache = 1;
1521
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001522 pthread_mutex_lock(&f->lock);
Miklos Szeredi320abe42006-01-30 18:14:51 +00001523 if (f->conf.auto_cache)
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001524 open_auto_cache(f, req, ino, path, fi);
Miklos Szeredi320abe42006-01-30 18:14:51 +00001525
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001526 if (fuse_reply_open(req, fi) == -ENOENT) {
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001527 /* The open syscall was interrupted, so it must be cancelled */
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00001528 if(f->op.release && path != NULL)
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001529 fuse_compat_release(f, req, path, fi);
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001530 } else {
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001531 struct node *node = get_node(f, ino);
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001532 node->open_count ++;
1533 }
Miklos Szeredi73798f92004-07-12 15:55:11 +00001534 pthread_mutex_unlock(&f->lock);
Miklos Szeredi73798f92004-07-12 15:55:11 +00001535 } else
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001536 reply_err(req, err);
Miklos Szeredi73798f92004-07-12 15:55:11 +00001537
Miklos Szeredi9a31cca2004-06-26 21:11:25 +00001538 if (path)
1539 free(path);
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001540 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001541}
1542
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001543static void fuse_read(fuse_req_t req, fuse_ino_t ino, size_t size, off_t off,
1544 struct fuse_file_info *fi)
Miklos Szeredie2e4ac22004-05-18 08:45:28 +00001545{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001546 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredie2e4ac22004-05-18 08:45:28 +00001547 char *path;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001548 char *buf;
Miklos Szeredie2e4ac22004-05-18 08:45:28 +00001549 int res;
1550
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001551 buf = (char *) malloc(size);
1552 if (buf == NULL) {
1553 reply_err(req, -ENOMEM);
1554 return;
1555 }
1556
Miklos Szeredie2e4ac22004-05-18 08:45:28 +00001557 res = -ENOENT;
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001558 pthread_rwlock_rdlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001559 path = get_path(f, ino);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001560 if (path != NULL) {
Miklos Szeredi659743b2005-12-09 17:41:42 +00001561 if (f->conf.debug) {
Miklos Szeredia039f8f2006-02-24 16:21:58 +00001562 printf("READ[%llu] %lu bytes from %llu\n",
1563 (unsigned long long) fi->fh, (unsigned long) size,
1564 (unsigned long long) off);
Miklos Szeredi209f5d02004-07-24 19:56:16 +00001565 fflush(stdout);
1566 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001567
Miklos Szeredie2e4ac22004-05-18 08:45:28 +00001568 res = -ENOSYS;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001569 if (f->op.read) {
1570 struct fuse_intr_data d;
1571 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001572 res = f->op.read(path, buf, size, off, fi);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001573 fuse_finish_interrupt(f, req, &d);
1574 }
Miklos Szeredie2e4ac22004-05-18 08:45:28 +00001575 free(path);
1576 }
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001577 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001578
1579 if (res >= 0) {
Miklos Szeredi659743b2005-12-09 17:41:42 +00001580 if (f->conf.debug) {
Miklos Szeredi3a770472005-11-11 21:32:42 +00001581 printf(" READ[%llu] %u bytes\n", (unsigned long long) fi->fh,
1582 res);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001583 fflush(stdout);
1584 }
Miklos Szeredif412d072005-10-14 21:24:32 +00001585 if ((size_t) res > size)
1586 fprintf(stderr, "fuse: read too many bytes");
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001587 fuse_reply_buf(req, buf, res);
1588 } else
1589 reply_err(req, res);
1590
1591 free(buf);
Miklos Szeredie2e4ac22004-05-18 08:45:28 +00001592}
1593
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001594static void fuse_write(fuse_req_t req, fuse_ino_t ino, const char *buf,
1595 size_t size, off_t off, struct fuse_file_info *fi)
Miklos Szeredic8ba2372002-12-10 12:26:00 +00001596{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001597 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001598 char *path;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001599 int res;
1600
1601 res = -ENOENT;
1602 pthread_rwlock_rdlock(&f->tree_lock);
1603 path = get_path(f, ino);
1604 if (path != NULL) {
Miklos Szeredi659743b2005-12-09 17:41:42 +00001605 if (f->conf.debug) {
Miklos Szeredia039f8f2006-02-24 16:21:58 +00001606 printf("WRITE%s[%llu] %lu bytes to %llu\n",
Miklos Szeredi3a770472005-11-11 21:32:42 +00001607 fi->writepage ? "PAGE" : "", (unsigned long long) fi->fh,
Miklos Szeredia039f8f2006-02-24 16:21:58 +00001608 (unsigned long) size, (unsigned long long) off);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001609 fflush(stdout);
1610 }
1611
1612 res = -ENOSYS;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001613 if (f->op.write) {
1614 struct fuse_intr_data d;
1615 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001616 res = f->op.write(path, buf, size, off, fi);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001617 fuse_finish_interrupt(f, req, &d);
1618 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001619 free(path);
1620 }
1621 pthread_rwlock_unlock(&f->tree_lock);
1622
Miklos Szeredif412d072005-10-14 21:24:32 +00001623 if (res >= 0) {
Miklos Szeredi659743b2005-12-09 17:41:42 +00001624 if (f->conf.debug) {
Miklos Szeredi3a770472005-11-11 21:32:42 +00001625 printf(" WRITE%s[%llu] %u bytes\n",
1626 fi->writepage ? "PAGE" : "", (unsigned long long) fi->fh,
1627 res);
Miklos Szeredif412d072005-10-14 21:24:32 +00001628 fflush(stdout);
1629 }
1630 if ((size_t) res > size)
1631 fprintf(stderr, "fuse: wrote too many bytes");
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001632 fuse_reply_write(req, res);
Miklos Szeredif412d072005-10-14 21:24:32 +00001633 } else
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001634 reply_err(req, res);
1635}
1636
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001637static void fuse_release(fuse_req_t req, fuse_ino_t ino,
1638 struct fuse_file_info *fi)
1639{
1640 struct fuse *f = req_fuse_prepare(req);
1641 char *path;
1642 struct node *node;
Miklos Szeredic3b76812006-09-16 08:52:09 +00001643 int unlink_hidden = 0;
Miklos Szeredi4fca4322006-10-01 14:41:04 +00001644 int err = 0;
Miklos Szeredifb28c5e2004-11-26 12:15:06 +00001645
Miklos Szerediaa8258e2006-02-25 14:42:03 +00001646 pthread_rwlock_rdlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001647 path = get_path(f, ino);
Miklos Szeredi659743b2005-12-09 17:41:42 +00001648 if (f->conf.debug) {
Miklos Szeredi4fca4322006-10-01 14:41:04 +00001649 printf("RELEASE%s[%llu] flags: 0x%x\n", fi->flush ? "+FLUSH" : "",
1650 (unsigned long long) fi->fh, fi->flags);
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001651 fflush(stdout);
Miklos Szeredic8ba2372002-12-10 12:26:00 +00001652 }
Miklos Szeredi4fca4322006-10-01 14:41:04 +00001653 if (fi->flush && path && f->op.flush)
1654 err = fuse_do_flush(f, req, path, fi);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00001655 if (f->op.release)
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001656 fuse_compat_release(f, req, path, fi);
Miklos Szeredie5183742005-02-02 11:14:04 +00001657
Miklos Szeredi9a5c11d2006-07-30 17:33:40 +00001658 pthread_mutex_lock(&f->lock);
1659 node = get_node(f, ino);
1660 assert(node->open_count > 0);
1661 --node->open_count;
Miklos Szeredic3b76812006-09-16 08:52:09 +00001662 if (node->is_hidden && !node->open_count) {
1663 unlink_hidden = 1;
1664 node->is_hidden = 0;
1665 }
Miklos Szeredi9a5c11d2006-07-30 17:33:40 +00001666 pthread_mutex_unlock(&f->lock);
1667
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001668 if(unlink_hidden && path)
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001669 fuse_do_unlink(f, req, path);
Miklos Szeredie5183742005-02-02 11:14:04 +00001670
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001671 if (path)
1672 free(path);
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001673 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001674
Miklos Szeredi4fca4322006-10-01 14:41:04 +00001675 reply_err(req, err);
Miklos Szeredic8ba2372002-12-10 12:26:00 +00001676}
1677
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001678static void fuse_fsync(fuse_req_t req, fuse_ino_t ino, int datasync,
1679 struct fuse_file_info *fi)
Miklos Szeredi5e183482001-10-31 14:52:35 +00001680{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001681 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001682 char *path;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001683 int err;
Miklos Szerediab974562005-04-07 15:40:21 +00001684
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001685 err = -ENOENT;
1686 pthread_rwlock_rdlock(&f->tree_lock);
1687 path = get_path(f, ino);
1688 if (path != NULL) {
Miklos Szeredi659743b2005-12-09 17:41:42 +00001689 if (f->conf.debug) {
Miklos Szeredi3a770472005-11-11 21:32:42 +00001690 printf("FSYNC[%llu]\n", (unsigned long long) fi->fh);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001691 fflush(stdout);
1692 }
1693 err = -ENOSYS;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001694 if (f->op.fsync) {
1695 struct fuse_intr_data d;
1696 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001697 err = f->op.fsync(path, datasync, fi);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001698 fuse_finish_interrupt(f, req, &d);
1699 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001700 free(path);
1701 }
1702 pthread_rwlock_unlock(&f->tree_lock);
1703 reply_err(req, err);
1704}
1705
1706static struct fuse_dirhandle *get_dirhandle(const struct fuse_file_info *llfi,
1707 struct fuse_file_info *fi)
1708{
Miklos Szeredi3a770472005-11-11 21:32:42 +00001709 struct fuse_dirhandle *dh = (struct fuse_dirhandle *) (uintptr_t) llfi->fh;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001710 memset(fi, 0, sizeof(struct fuse_file_info));
1711 fi->fh = dh->fh;
Miklos Szerediead7f102005-11-28 16:02:27 +00001712 fi->fh_old = dh->fh;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001713 return dh;
1714}
1715
1716static void fuse_opendir(fuse_req_t req, fuse_ino_t ino,
1717 struct fuse_file_info *llfi)
1718{
1719 struct fuse *f = req_fuse_prepare(req);
1720 struct fuse_dirhandle *dh;
1721
1722 dh = (struct fuse_dirhandle *) malloc(sizeof(struct fuse_dirhandle));
1723 if (dh == NULL) {
1724 reply_err(req, -ENOMEM);
Miklos Szerediab974562005-04-07 15:40:21 +00001725 return;
Miklos Szeredi5e183482001-10-31 14:52:35 +00001726 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001727 memset(dh, 0, sizeof(struct fuse_dirhandle));
1728 dh->fuse = f;
1729 dh->contents = NULL;
1730 dh->len = 0;
1731 dh->filled = 0;
1732 dh->nodeid = ino;
Miklos Szeredi38f152c2006-09-03 18:28:52 +00001733 fuse_mutex_init(&dh->lock);
Miklos Szerediab974562005-04-07 15:40:21 +00001734
Miklos Szeredi3a770472005-11-11 21:32:42 +00001735 llfi->fh = (uintptr_t) dh;
Miklos Szerediab974562005-04-07 15:40:21 +00001736
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001737 if (f->op.opendir) {
1738 struct fuse_file_info fi;
1739 char *path;
1740 int err;
1741
1742 memset(&fi, 0, sizeof(fi));
1743 fi.flags = llfi->flags;
1744
1745 err = -ENOENT;
1746 pthread_rwlock_rdlock(&f->tree_lock);
1747 path = get_path(f, ino);
1748 if (path != NULL) {
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001749 err = fuse_compat_opendir(f, req, path, &fi);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00001750 dh->fh = fi.fh;
Miklos Szerediab974562005-04-07 15:40:21 +00001751 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001752 if (!err) {
1753 pthread_mutex_lock(&f->lock);
1754 if (fuse_reply_open(req, llfi) == -ENOENT) {
1755 /* The opendir syscall was interrupted, so it must be
1756 cancelled */
1757 if(f->op.releasedir)
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001758 fuse_do_releasedir(f, req, path, &fi);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001759 pthread_mutex_destroy(&dh->lock);
1760 free(dh);
1761 }
1762 pthread_mutex_unlock(&f->lock);
1763 } else {
1764 reply_err(req, err);
1765 free(dh);
1766 }
Miklos Szerediab974562005-04-07 15:40:21 +00001767 free(path);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001768 pthread_rwlock_unlock(&f->tree_lock);
1769 } else
1770 fuse_reply_open(req, llfi);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001771}
Miklos Szeredib483c932001-10-29 14:57:57 +00001772
Miklos Szeredi1bf64f42006-02-17 15:49:25 +00001773static int extend_contents(struct fuse_dirhandle *dh, unsigned minsize)
1774{
1775 if (minsize > dh->size) {
1776 char *newptr;
1777 unsigned newsize = dh->size;
1778 if (!newsize)
1779 newsize = 1024;
1780 while (newsize < minsize)
1781 newsize *= 2;
1782
1783 newptr = (char *) realloc(dh->contents, newsize);
1784 if (!newptr) {
1785 dh->error = -ENOMEM;
1786 return -1;
1787 }
1788 dh->contents = newptr;
1789 dh->size = newsize;
1790 }
1791 return 0;
1792}
1793
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001794static int fill_dir_common(struct fuse_dirhandle *dh, const char *name,
Miklos Szeredif6e0ec62005-08-03 09:11:06 +00001795 const struct stat *statp, off_t off)
Miklos Szeredia181e612001-11-06 12:03:23 +00001796{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001797 struct stat stbuf;
Miklos Szeredi1bf64f42006-02-17 15:49:25 +00001798 size_t newlen;
Miklos Szeredifb28c5e2004-11-26 12:15:06 +00001799
Miklos Szeredif6e0ec62005-08-03 09:11:06 +00001800 if (statp)
1801 stbuf = *statp;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001802 else {
1803 memset(&stbuf, 0, sizeof(stbuf));
Miklos Szeredie248e4b2005-12-14 16:18:32 +00001804 stbuf.st_ino = FUSE_UNKNOWN_INO;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001805 }
Miklos Szeredia181e612001-11-06 12:03:23 +00001806
Miklos Szeredi659743b2005-12-09 17:41:42 +00001807 if (!dh->fuse->conf.use_ino) {
Miklos Szeredie248e4b2005-12-14 16:18:32 +00001808 stbuf.st_ino = FUSE_UNKNOWN_INO;
Miklos Szeredi659743b2005-12-09 17:41:42 +00001809 if (dh->fuse->conf.readdir_ino) {
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001810 struct node *node;
1811 pthread_mutex_lock(&dh->fuse->lock);
1812 node = lookup_node(dh->fuse, dh->nodeid, name);
1813 if (node)
1814 stbuf.st_ino = (ino_t) node->nodeid;
1815 pthread_mutex_unlock(&dh->fuse->lock);
Miklos Szeredi6ebe2342002-01-06 21:44:16 +00001816 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001817 }
Miklos Szeredi6ebe2342002-01-06 21:44:16 +00001818
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001819 if (off) {
Miklos Szeredi1bf64f42006-02-17 15:49:25 +00001820 if (extend_contents(dh, dh->needlen) == -1)
1821 return 1;
1822
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001823 dh->filled = 0;
Miklos Szeredi1bf64f42006-02-17 15:49:25 +00001824 newlen = dh->len + fuse_add_direntry(dh->req, dh->contents + dh->len,
1825 dh->needlen - dh->len, name,
1826 &stbuf, off);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001827 if (newlen > dh->needlen)
1828 return 1;
Miklos Szeredi1bf64f42006-02-17 15:49:25 +00001829 } else {
1830 newlen = dh->len + fuse_add_direntry(dh->req, NULL, 0, name, NULL, 0);
1831 if (extend_contents(dh, newlen) == -1)
Miklos Szeredic4c12ae2005-10-20 14:48:50 +00001832 return 1;
Miklos Szeredi1bf64f42006-02-17 15:49:25 +00001833
1834 fuse_add_direntry(dh->req, dh->contents + dh->len, dh->size - dh->len,
1835 name, &stbuf, newlen);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001836 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001837 dh->len = newlen;
1838 return 0;
1839}
1840
Miklos Szeredif6e0ec62005-08-03 09:11:06 +00001841static int fill_dir(void *buf, const char *name, const struct stat *stbuf,
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001842 off_t off)
1843{
Miklos Szeredif6e0ec62005-08-03 09:11:06 +00001844 return fill_dir_common((struct fuse_dirhandle *) buf, name, stbuf, off);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001845}
1846
1847static int fill_dir_old(struct fuse_dirhandle *dh, const char *name, int type,
1848 ino_t ino)
1849{
1850 struct stat stbuf;
1851
1852 memset(&stbuf, 0, sizeof(stbuf));
1853 stbuf.st_mode = type << 12;
1854 stbuf.st_ino = ino;
1855
1856 fill_dir_common(dh, name, &stbuf, 0);
1857 return dh->error;
1858}
1859
Miklos Szeredi1bf64f42006-02-17 15:49:25 +00001860static int readdir_fill(struct fuse *f, fuse_req_t req, fuse_ino_t ino,
1861 size_t size, off_t off, struct fuse_dirhandle *dh,
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001862 struct fuse_file_info *fi)
1863{
1864 int err = -ENOENT;
1865 char *path;
1866 pthread_rwlock_rdlock(&f->tree_lock);
1867 path = get_path(f, ino);
1868 if (path != NULL) {
1869 dh->len = 0;
1870 dh->error = 0;
1871 dh->needlen = size;
1872 dh->filled = 1;
Miklos Szeredi1bf64f42006-02-17 15:49:25 +00001873 dh->req = req;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001874 err = -ENOSYS;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001875 if (f->op.readdir) {
1876 struct fuse_intr_data d;
1877 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001878 err = f->op.readdir(path, dh, fill_dir, off, fi);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001879 fuse_finish_interrupt(f, req, &d);
1880 } else if (f->op.getdir) {
1881 struct fuse_intr_data d;
1882 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001883 err = f->op.getdir(path, dh, fill_dir_old);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001884 fuse_finish_interrupt(f, req, &d);
1885 }
Miklos Szeredi1bf64f42006-02-17 15:49:25 +00001886 dh->req = NULL;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001887 if (!err)
1888 err = dh->error;
1889 if (err)
1890 dh->filled = 0;
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001891 free(path);
Miklos Szeredia181e612001-11-06 12:03:23 +00001892 }
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001893 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001894 return err;
1895}
Miklos Szeredie5183742005-02-02 11:14:04 +00001896
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001897static void fuse_readdir(fuse_req_t req, fuse_ino_t ino, size_t size,
1898 off_t off, struct fuse_file_info *llfi)
1899{
1900 struct fuse *f = req_fuse_prepare(req);
1901 struct fuse_file_info fi;
1902 struct fuse_dirhandle *dh = get_dirhandle(llfi, &fi);
1903
1904 pthread_mutex_lock(&dh->lock);
Miklos Szeredi77ccf652005-08-19 14:40:27 +00001905 /* According to SUS, directory contents need to be refreshed on
1906 rewinddir() */
1907 if (!off)
1908 dh->filled = 0;
1909
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001910 if (!dh->filled) {
Miklos Szeredi1bf64f42006-02-17 15:49:25 +00001911 int err = readdir_fill(f, req, ino, size, off, dh, &fi);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001912 if (err) {
1913 reply_err(req, err);
1914 goto out;
1915 }
Miklos Szeredia181e612001-11-06 12:03:23 +00001916 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001917 if (dh->filled) {
1918 if (off < dh->len) {
1919 if (off + size > dh->len)
1920 size = dh->len - off;
1921 } else
1922 size = 0;
1923 } else {
1924 size = dh->len;
1925 off = 0;
1926 }
1927 fuse_reply_buf(req, dh->contents + off, size);
1928 out:
1929 pthread_mutex_unlock(&dh->lock);
1930}
Miklos Szeredia181e612001-11-06 12:03:23 +00001931
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001932static void fuse_releasedir(fuse_req_t req, fuse_ino_t ino,
1933 struct fuse_file_info *llfi)
1934{
1935 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredi9b813af2005-07-21 07:59:37 +00001936 struct fuse_file_info fi;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001937 struct fuse_dirhandle *dh = get_dirhandle(llfi, &fi);
1938 if (f->op.releasedir) {
1939 char *path;
1940
1941 pthread_rwlock_rdlock(&f->tree_lock);
1942 path = get_path(f, ino);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001943 fuse_do_releasedir(f, req, path ? path : "-", &fi);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001944 free(path);
1945 pthread_rwlock_unlock(&f->tree_lock);
1946 }
1947 pthread_mutex_lock(&dh->lock);
1948 pthread_mutex_unlock(&dh->lock);
1949 pthread_mutex_destroy(&dh->lock);
1950 free(dh->contents);
1951 free(dh);
1952 reply_err(req, 0);
1953}
1954
1955static void fuse_fsyncdir(fuse_req_t req, fuse_ino_t ino, int datasync,
1956 struct fuse_file_info *llfi)
1957{
1958 struct fuse *f = req_fuse_prepare(req);
1959 struct fuse_file_info fi;
1960 char *path;
1961 int err;
1962
1963 get_dirhandle(llfi, &fi);
1964
1965 err = -ENOENT;
1966 pthread_rwlock_rdlock(&f->tree_lock);
1967 path = get_path(f, ino);
1968 if (path != NULL) {
1969 err = -ENOSYS;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001970 if (f->op.fsyncdir) {
1971 struct fuse_intr_data d;
1972 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001973 err = f->op.fsyncdir(path, datasync, &fi);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001974 fuse_finish_interrupt(f, req, &d);
1975 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001976 free(path);
1977 }
1978 pthread_rwlock_unlock(&f->tree_lock);
1979 reply_err(req, err);
Miklos Szeredia181e612001-11-06 12:03:23 +00001980}
1981
Miklos Szeredi52cb09d2005-11-07 11:59:00 +00001982static int default_statfs(struct statvfs *buf)
Miklos Szeredi77f39942004-03-25 11:17:52 +00001983{
Miklos Szeredi52cb09d2005-11-07 11:59:00 +00001984 buf->f_namemax = 255;
Miklos Szeredi77f39942004-03-25 11:17:52 +00001985 buf->f_bsize = 512;
1986 return 0;
1987}
1988
Miklos Szeredi3ded1a32006-08-18 18:43:50 +00001989static void fuse_statfs(fuse_req_t req, fuse_ino_t ino)
Miklos Szeredi18e75e42004-02-19 14:23:27 +00001990{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001991 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredi52cb09d2005-11-07 11:59:00 +00001992 struct statvfs buf;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001993 int err;
Mark Glinesd84b39a2002-01-07 16:32:02 +00001994
Miklos Szeredi52cb09d2005-11-07 11:59:00 +00001995 memset(&buf, 0, sizeof(buf));
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001996 if (f->op.statfs) {
Miklos Szeredi3ded1a32006-08-18 18:43:50 +00001997 if (ino && (!f->compat || f->compat >= 26)) {
1998 char *path;
1999 pthread_rwlock_rdlock(&f->tree_lock);
2000 err = -ENOENT;
2001 path = get_path(f, ino);
2002 if (path) {
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002003 err = fuse_do_statfs(f, req, path, &buf);
Miklos Szeredi3ded1a32006-08-18 18:43:50 +00002004 free(path);
2005 }
2006 pthread_rwlock_unlock(&f->tree_lock);
2007 } else
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002008 err = fuse_compat_statfs(f, req, &buf);
Miklos Szeredi52cb09d2005-11-07 11:59:00 +00002009 } else
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002010 err = default_statfs(&buf);
Miklos Szeredi77f39942004-03-25 11:17:52 +00002011
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002012 if (!err)
2013 fuse_reply_statfs(req, &buf);
Miklos Szeredi03cebae2004-03-31 10:19:18 +00002014 else
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002015 reply_err(req, err);
Miklos Szeredi03cebae2004-03-31 10:19:18 +00002016}
2017
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002018static void fuse_setxattr(fuse_req_t req, fuse_ino_t ino, const char *name,
2019 const char *value, size_t size, int flags)
Miklos Szeredi3ed84232004-03-30 15:17:26 +00002020{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002021 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredi3ed84232004-03-30 15:17:26 +00002022 char *path;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002023 int err;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00002024
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002025 err = -ENOENT;
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00002026 pthread_rwlock_rdlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002027 path = get_path(f, ino);
Miklos Szeredi3ed84232004-03-30 15:17:26 +00002028 if (path != NULL) {
Miklos Szerediab974562005-04-07 15:40:21 +00002029 err = -ENOSYS;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002030 if (f->op.setxattr) {
2031 struct fuse_intr_data d;
2032 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002033 err = f->op.setxattr(path, name, value, size, flags);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002034 fuse_finish_interrupt(f, req, &d);
2035 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002036 free(path);
2037 }
2038 pthread_rwlock_unlock(&f->tree_lock);
2039 reply_err(req, err);
2040}
2041
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002042static int common_getxattr(struct fuse *f, fuse_req_t req, fuse_ino_t ino,
2043 const char *name, char *value, size_t size)
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002044{
2045 int err;
2046 char *path;
2047
2048 err = -ENOENT;
2049 pthread_rwlock_rdlock(&f->tree_lock);
2050 path = get_path(f, ino);
2051 if (path != NULL) {
2052 err = -ENOSYS;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002053 if (f->op.getxattr) {
2054 struct fuse_intr_data d;
2055 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002056 err = f->op.getxattr(path, name, value, size);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002057 fuse_finish_interrupt(f, req, &d);
2058 }
Miklos Szerediab974562005-04-07 15:40:21 +00002059 free(path);
2060 }
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00002061 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szerediab974562005-04-07 15:40:21 +00002062 return err;
2063}
2064
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002065static void fuse_getxattr(fuse_req_t req, fuse_ino_t ino, const char *name,
2066 size_t size)
Miklos Szeredi3ead28e2005-01-18 21:23:41 +00002067{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002068 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredi4283ee72005-03-21 12:09:04 +00002069 int res;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002070
2071 if (size) {
2072 char *value = (char *) malloc(size);
2073 if (value == NULL) {
2074 reply_err(req, -ENOMEM);
2075 return;
2076 }
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002077 res = common_getxattr(f, req, ino, name, value, size);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002078 if (res > 0)
2079 fuse_reply_buf(req, value, res);
2080 else
2081 reply_err(req, res);
2082 free(value);
2083 } else {
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002084 res = common_getxattr(f, req, ino, name, NULL, 0);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002085 if (res >= 0)
2086 fuse_reply_xattr(req, res);
2087 else
2088 reply_err(req, res);
2089 }
2090}
2091
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002092static int common_listxattr(struct fuse *f, fuse_req_t req, fuse_ino_t ino,
2093 char *list, size_t size)
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002094{
Miklos Szeredi4283ee72005-03-21 12:09:04 +00002095 char *path;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002096 int err;
Miklos Szeredi4283ee72005-03-21 12:09:04 +00002097
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002098 err = -ENOENT;
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00002099 pthread_rwlock_rdlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002100 path = get_path(f, ino);
Miklos Szeredi4283ee72005-03-21 12:09:04 +00002101 if (path != NULL) {
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002102 err = -ENOSYS;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002103 if (f->op.listxattr) {
2104 struct fuse_intr_data d;
2105 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002106 err = f->op.listxattr(path, list, size);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002107 fuse_finish_interrupt(f, req, &d);
2108 }
Miklos Szeredi4283ee72005-03-21 12:09:04 +00002109 free(path);
2110 }
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00002111 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002112 return err;
Miklos Szeredi4283ee72005-03-21 12:09:04 +00002113}
Miklos Szeredi3ead28e2005-01-18 21:23:41 +00002114
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002115static void fuse_listxattr(fuse_req_t req, fuse_ino_t ino, size_t size)
Miklos Szeredi43696432001-11-18 19:15:05 +00002116{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002117 struct fuse *f = req_fuse_prepare(req);
2118 int res;
2119
2120 if (size) {
2121 char *list = (char *) malloc(size);
2122 if (list == NULL) {
2123 reply_err(req, -ENOMEM);
2124 return;
2125 }
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002126 res = common_listxattr(f, req, ino, list, size);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002127 if (res > 0)
2128 fuse_reply_buf(req, list, res);
2129 else
2130 reply_err(req, res);
2131 free(list);
2132 } else {
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002133 res = common_listxattr(f, req, ino, NULL, 0);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002134 if (res >= 0)
2135 fuse_reply_xattr(req, res);
2136 else
2137 reply_err(req, res);
2138 }
Miklos Szeredi43696432001-11-18 19:15:05 +00002139}
2140
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002141static void fuse_removexattr(fuse_req_t req, fuse_ino_t ino, const char *name)
2142{
2143 struct fuse *f = req_fuse_prepare(req);
2144 char *path;
2145 int err;
2146
2147 err = -ENOENT;
2148 pthread_rwlock_rdlock(&f->tree_lock);
2149 path = get_path(f, ino);
2150 if (path != NULL) {
2151 err = -ENOSYS;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002152 if (f->op.removexattr) {
2153 struct fuse_intr_data d;
2154 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002155 err = f->op.removexattr(path, name);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002156 fuse_finish_interrupt(f, req, &d);
2157 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002158 free(path);
2159 }
2160 pthread_rwlock_unlock(&f->tree_lock);
2161 reply_err(req, err);
2162}
2163
Miklos Szeredi0c59ebf2006-09-10 20:53:36 +00002164static struct lock *locks_conflict(struct node *node, const struct lock *lock)
2165{
2166 struct lock *l;
2167
2168 for (l = node->locks; l; l = l->next)
2169 if (l->owner != lock->owner &&
2170 lock->start <= l->end && l->start <= lock->end &&
2171 (l->type == F_WRLCK || lock->type == F_WRLCK))
2172 break;
2173
2174 return l;
2175}
2176
2177static void delete_lock(struct lock **lockp)
2178{
2179 struct lock *l = *lockp;
2180 *lockp = l->next;
2181 free(l);
2182}
2183
2184static void insert_lock(struct lock **pos, struct lock *lock)
2185{
2186 lock->next = *pos;
2187 *pos = lock;
2188}
2189
2190static int locks_insert(struct node *node, struct lock *lock)
2191{
2192 struct lock **lp;
2193 struct lock *newl1 = NULL;
2194 struct lock *newl2 = NULL;
2195
2196 if (lock->type != F_UNLCK || lock->start != 0 || lock->end != OFFSET_MAX) {
2197 newl1 = malloc(sizeof(struct lock));
2198 newl2 = malloc(sizeof(struct lock));
2199
2200 if (!newl1 || !newl2) {
2201 free(newl1);
2202 free(newl2);
2203 return -ENOLCK;
2204 }
2205 }
2206
2207 for (lp = &node->locks; *lp;) {
2208 struct lock *l = *lp;
2209 if (l->owner != lock->owner)
2210 goto skip;
2211
2212 if (lock->type == l->type) {
2213 if (l->end < lock->start - 1)
2214 goto skip;
2215 if (lock->end < l->start - 1)
2216 break;
2217 if (l->start <= lock->start && lock->end <= l->end)
2218 goto out;
2219 if (l->start < lock->start)
2220 lock->start = l->start;
2221 if (lock->end < l->end)
2222 lock->end = l->end;
2223 goto delete;
2224 } else {
2225 if (l->end < lock->start)
2226 goto skip;
2227 if (lock->end < l->start)
2228 break;
2229 if (lock->start <= l->start && l->end <= lock->end)
2230 goto delete;
2231 if (l->end <= lock->end) {
2232 l->end = lock->start - 1;
2233 goto skip;
2234 }
2235 if (lock->start <= l->start) {
2236 l->start = lock->end + 1;
2237 break;
2238 }
2239 *newl2 = *l;
2240 newl2->start = lock->end + 1;
2241 l->end = lock->start - 1;
2242 insert_lock(&l->next, newl2);
2243 newl2 = NULL;
2244 }
2245 skip:
2246 lp = &l->next;
2247 continue;
2248
2249 delete:
2250 delete_lock(lp);
2251 }
2252 if (lock->type != F_UNLCK) {
2253 *newl1 = *lock;
2254 insert_lock(lp, newl1);
2255 newl1 = NULL;
2256 }
2257out:
2258 free(newl1);
2259 free(newl2);
2260 return 0;
2261}
2262
2263static void flock_to_lock(struct flock *flock, struct lock *lock)
2264{
2265 memset(lock, 0, sizeof(struct lock));
2266 lock->type = flock->l_type;
2267 lock->start = flock->l_start;
2268 lock->end = flock->l_len ? flock->l_start + flock->l_len - 1 : OFFSET_MAX;
2269 lock->pid = flock->l_pid;
2270}
2271
2272static void lock_to_flock(struct lock *lock, struct flock *flock)
2273{
2274 flock->l_type = lock->type;
2275 flock->l_start = lock->start;
2276 flock->l_len = (lock->end == OFFSET_MAX) ? 0 : lock->end - lock->start + 1;
2277 flock->l_pid = lock->pid;
2278}
2279
2280static void fuse_flush(fuse_req_t req, fuse_ino_t ino,
Miklos Szeredi07407852006-09-30 20:03:52 +00002281 struct fuse_file_info *fi)
Miklos Szeredi0c59ebf2006-09-10 20:53:36 +00002282{
2283 struct fuse *f = req_fuse_prepare(req);
2284 char *path;
2285 int err;
2286
2287 err = -ENOENT;
2288 pthread_rwlock_rdlock(&f->tree_lock);
2289 path = get_path(f, ino);
2290 if (path != NULL) {
2291 if (f->conf.debug) {
2292 printf("FLUSH[%llu]\n", (unsigned long long) fi->fh);
2293 fflush(stdout);
2294 }
2295 err = -ENOSYS;
Miklos Szeredi4fca4322006-10-01 14:41:04 +00002296 if (f->op.flush)
2297 err = fuse_do_flush(f, req, path, fi);
Miklos Szeredi0c59ebf2006-09-10 20:53:36 +00002298 }
2299 if (f->op.lock) {
2300 struct flock lock;
2301 struct lock l;
2302 memset(&lock, 0, sizeof(lock));
2303 lock.l_type = F_UNLCK;
2304 lock.l_whence = SEEK_SET;
Miklos Szeredi07407852006-09-30 20:03:52 +00002305 fuse_do_lock(f, req, path, fi, F_SETLK, &lock);
Miklos Szeredi0c59ebf2006-09-10 20:53:36 +00002306 flock_to_lock(&lock, &l);
Miklos Szeredi07407852006-09-30 20:03:52 +00002307 l.owner = fi->lock_owner;
Miklos Szeredi0c59ebf2006-09-10 20:53:36 +00002308 pthread_mutex_lock(&f->lock);
2309 locks_insert(get_node(f, ino), &l);
2310 pthread_mutex_unlock(&f->lock);
2311
2312 /* if op.lock() is defined FLUSH is needed regardless of op.flush() */
2313 if (err == -ENOSYS)
2314 err = 0;
2315 }
Miklos Szeredi6e7d0182007-01-19 22:11:40 +00002316 free(path);
Miklos Szeredi0c59ebf2006-09-10 20:53:36 +00002317 pthread_rwlock_unlock(&f->tree_lock);
2318 reply_err(req, err);
2319}
2320
Miklos Szeredi9a5c11d2006-07-30 17:33:40 +00002321static int fuse_lock_common(fuse_req_t req, fuse_ino_t ino,
2322 struct fuse_file_info *fi, struct flock *lock,
Miklos Szeredi07407852006-09-30 20:03:52 +00002323 int cmd)
Miklos Szeredi9a5c11d2006-07-30 17:33:40 +00002324{
2325 struct fuse *f = req_fuse_prepare(req);
2326 char *path;
2327 int err;
2328
2329 err = -ENOENT;
2330 pthread_rwlock_rdlock(&f->tree_lock);
2331 path = get_path(f, ino);
2332 if (path != NULL) {
Miklos Szeredi07407852006-09-30 20:03:52 +00002333 err = fuse_do_lock(f, req, path, fi, cmd, lock);
Miklos Szeredi9a5c11d2006-07-30 17:33:40 +00002334 free(path);
2335 }
2336 pthread_rwlock_unlock(&f->tree_lock);
2337 return err;
2338}
2339
2340static void fuse_getlk(fuse_req_t req, fuse_ino_t ino,
Miklos Szeredi07407852006-09-30 20:03:52 +00002341 struct fuse_file_info *fi, struct flock *lock)
Miklos Szeredi9a5c11d2006-07-30 17:33:40 +00002342{
Miklos Szeredi0c59ebf2006-09-10 20:53:36 +00002343 int err;
2344 struct lock l;
2345 struct lock *conflict;
2346 struct fuse *f = req_fuse(req);
2347
2348 flock_to_lock(lock, &l);
Miklos Szeredi07407852006-09-30 20:03:52 +00002349 l.owner = fi->lock_owner;
Miklos Szeredi0c59ebf2006-09-10 20:53:36 +00002350 pthread_mutex_lock(&f->lock);
2351 conflict = locks_conflict(get_node(f, ino), &l);
2352 if (conflict)
2353 lock_to_flock(conflict, lock);
2354 pthread_mutex_unlock(&f->lock);
2355 if (!conflict)
Miklos Szeredi07407852006-09-30 20:03:52 +00002356 err = fuse_lock_common(req, ino, fi, lock, F_GETLK);
Miklos Szeredi0c59ebf2006-09-10 20:53:36 +00002357 else
2358 err = 0;
2359
Miklos Szeredi9a5c11d2006-07-30 17:33:40 +00002360 if (!err)
2361 fuse_reply_lock(req, lock);
2362 else
2363 reply_err(req, err);
2364}
2365
2366static void fuse_setlk(fuse_req_t req, fuse_ino_t ino,
2367 struct fuse_file_info *fi, struct flock *lock,
Miklos Szeredi07407852006-09-30 20:03:52 +00002368 int sleep)
Miklos Szeredi9a5c11d2006-07-30 17:33:40 +00002369{
Miklos Szeredi07407852006-09-30 20:03:52 +00002370 int err = fuse_lock_common(req, ino, fi, lock, sleep ? F_SETLKW : F_SETLK);
Miklos Szeredi0c59ebf2006-09-10 20:53:36 +00002371 if (!err) {
2372 struct fuse *f = req_fuse(req);
2373 struct lock l;
2374 flock_to_lock(lock, &l);
Miklos Szeredi07407852006-09-30 20:03:52 +00002375 l.owner = fi->lock_owner;
Miklos Szeredi0c59ebf2006-09-10 20:53:36 +00002376 pthread_mutex_lock(&f->lock);
2377 locks_insert(get_node(f, ino), &l);
2378 pthread_mutex_unlock(&f->lock);
2379 }
2380 reply_err(req, err);
Miklos Szeredi9a5c11d2006-07-30 17:33:40 +00002381}
2382
Miklos Szeredi708b4812006-09-30 16:02:25 +00002383static void fuse_bmap(fuse_req_t req, fuse_ino_t ino, size_t blocksize,
2384 uint64_t idx)
2385{
2386 struct fuse *f = req_fuse_prepare(req);
2387 char *path;
2388 int err;
2389
2390 err = -ENOENT;
2391 pthread_rwlock_rdlock(&f->tree_lock);
2392 path = get_path(f, ino);
2393 if (path != NULL) {
2394 err = -ENOSYS;
2395 if (f->op.bmap)
2396 err = f->op.bmap(path, blocksize, &idx);
2397 free(path);
2398 }
2399 pthread_rwlock_unlock(&f->tree_lock);
2400 if (!err)
2401 fuse_reply_bmap(req, idx);
2402 else
2403 reply_err(req, err);
2404}
2405
Miklos Szeredia1482422005-08-14 23:00:27 +00002406static struct fuse_lowlevel_ops fuse_path_ops = {
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002407 .init = fuse_data_init,
2408 .destroy = fuse_data_destroy,
2409 .lookup = fuse_lookup,
2410 .forget = fuse_forget,
2411 .getattr = fuse_getattr,
2412 .setattr = fuse_setattr,
Miklos Szeredib0b13d12005-10-26 12:53:25 +00002413 .access = fuse_access,
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002414 .readlink = fuse_readlink,
2415 .mknod = fuse_mknod,
2416 .mkdir = fuse_mkdir,
2417 .unlink = fuse_unlink,
2418 .rmdir = fuse_rmdir,
2419 .symlink = fuse_symlink,
2420 .rename = fuse_rename,
2421 .link = fuse_link,
Miklos Szeredid9079a72005-10-26 15:29:06 +00002422 .create = fuse_create,
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002423 .open = fuse_open,
2424 .read = fuse_read,
2425 .write = fuse_write,
2426 .flush = fuse_flush,
2427 .release = fuse_release,
2428 .fsync = fuse_fsync,
2429 .opendir = fuse_opendir,
2430 .readdir = fuse_readdir,
2431 .releasedir = fuse_releasedir,
2432 .fsyncdir = fuse_fsyncdir,
2433 .statfs = fuse_statfs,
2434 .setxattr = fuse_setxattr,
2435 .getxattr = fuse_getxattr,
2436 .listxattr = fuse_listxattr,
2437 .removexattr = fuse_removexattr,
Miklos Szeredi9a5c11d2006-07-30 17:33:40 +00002438 .getlk = fuse_getlk,
2439 .setlk = fuse_setlk,
Miklos Szeredi708b4812006-09-30 16:02:25 +00002440 .bmap = fuse_bmap,
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002441};
2442
Miklos Szeredia1482422005-08-14 23:00:27 +00002443static void free_cmd(struct fuse_cmd *cmd)
2444{
2445 free(cmd->buf);
2446 free(cmd);
2447}
2448
Miklos Szeredif458b8c2004-12-07 16:46:42 +00002449void fuse_process_cmd(struct fuse *f, struct fuse_cmd *cmd)
Miklos Szeredia181e612001-11-06 12:03:23 +00002450{
Miklos Szeredi178451d2005-08-15 13:19:07 +00002451 fuse_session_process(f->se, cmd->buf, cmd->buflen, cmd->ch);
Miklos Szeredifa829b52005-12-02 11:05:41 +00002452 free_cmd(cmd);
Miklos Szeredia181e612001-11-06 12:03:23 +00002453}
2454
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002455int fuse_exited(struct fuse *f)
Miklos Szeredi65cf7c72004-06-30 11:34:56 +00002456{
Miklos Szeredia1482422005-08-14 23:00:27 +00002457 return fuse_session_exited(f->se);
2458}
2459
2460struct fuse_session *fuse_get_session(struct fuse *f)
2461{
2462 return f->se;
2463}
2464
2465static struct fuse_cmd *fuse_alloc_cmd(size_t bufsize)
2466{
2467 struct fuse_cmd *cmd = (struct fuse_cmd *) malloc(sizeof(*cmd));
2468 if (cmd == NULL) {
2469 fprintf(stderr, "fuse: failed to allocate cmd\n");
2470 return NULL;
2471 }
2472 cmd->buf = (char *) malloc(bufsize);
2473 if (cmd->buf == NULL) {
2474 fprintf(stderr, "fuse: failed to allocate read buffer\n");
2475 free(cmd);
2476 return NULL;
2477 }
2478 return cmd;
Miklos Szeredi65cf7c72004-06-30 11:34:56 +00002479}
2480
Miklos Szeredif458b8c2004-12-07 16:46:42 +00002481struct fuse_cmd *fuse_read_cmd(struct fuse *f)
Miklos Szeredi2df1c042001-11-06 15:07:17 +00002482{
Miklos Szeredia1482422005-08-14 23:00:27 +00002483 struct fuse_chan *ch = fuse_session_next_chan(f->se, NULL);
2484 size_t bufsize = fuse_chan_bufsize(ch);
2485 struct fuse_cmd *cmd = fuse_alloc_cmd(bufsize);
2486 if (cmd != NULL) {
Miklos Szeredi8d975f62006-03-17 15:56:05 +00002487 int res = fuse_chan_recv(&ch, cmd->buf, bufsize);
Miklos Szeredia1482422005-08-14 23:00:27 +00002488 if (res <= 0) {
2489 free_cmd(cmd);
Miklos Szeredi5d9ce362006-03-01 12:10:13 +00002490 if (res < 0 && res != -EINTR && res != -EAGAIN)
Miklos Szeredifa829b52005-12-02 11:05:41 +00002491 fuse_exit(f);
Miklos Szeredia1482422005-08-14 23:00:27 +00002492 return NULL;
2493 }
2494 cmd->buflen = res;
Miklos Szeredi178451d2005-08-15 13:19:07 +00002495 cmd->ch = ch;
Miklos Szeredia1482422005-08-14 23:00:27 +00002496 }
2497 return cmd;
Miklos Szeredi2df1c042001-11-06 15:07:17 +00002498}
2499
Miklos Szeredib2cf9562004-09-16 08:42:40 +00002500int fuse_loop(struct fuse *f)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00002501{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002502 if (f)
Miklos Szeredia1482422005-08-14 23:00:27 +00002503 return fuse_session_loop(f->se);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002504 else
Miklos Szeredib2cf9562004-09-16 08:42:40 +00002505 return -1;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00002506}
2507
Miklos Szeredi891b8742004-07-29 09:27:49 +00002508int fuse_invalidate(struct fuse *f, const char *path)
2509{
Miklos Szeredie56818b2004-12-12 11:45:24 +00002510 (void) f;
2511 (void) path;
2512 return -EINVAL;
Miklos Szeredi891b8742004-07-29 09:27:49 +00002513}
2514
Miklos Szeredi0f48a262002-12-05 14:23:01 +00002515void fuse_exit(struct fuse *f)
2516{
Miklos Szeredia1482422005-08-14 23:00:27 +00002517 fuse_session_exit(f->se);
Miklos Szeredi0f48a262002-12-05 14:23:01 +00002518}
2519
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002520struct fuse_context *fuse_get_context(void)
Miklos Szeredi2e50d432001-12-20 12:17:25 +00002521{
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002522 return &fuse_get_context_internal()->ctx;
2523}
2524
2525int fuse_interrupted(void)
2526{
2527 return fuse_req_interrupted(fuse_get_context_internal()->req);
Miklos Szeredid169f312004-09-22 08:48:26 +00002528}
2529
Miklos Szeredif458b8c2004-12-07 16:46:42 +00002530void fuse_set_getcontext_func(struct fuse_context *(*func)(void))
Miklos Szeredid169f312004-09-22 08:48:26 +00002531{
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002532 (void) func;
2533 /* no-op */
Miklos Szeredi2e50d432001-12-20 12:17:25 +00002534}
2535
Miklos Szerediad005972006-01-07 10:14:34 +00002536enum {
2537 KEY_HELP,
Miklos Szerediad005972006-01-07 10:14:34 +00002538};
2539
Miklos Szeredi659743b2005-12-09 17:41:42 +00002540#define FUSE_LIB_OPT(t, p, v) { t, offsetof(struct fuse_config, p), v }
2541
2542static const struct fuse_opt fuse_lib_opts[] = {
Miklos Szerediad005972006-01-07 10:14:34 +00002543 FUSE_OPT_KEY("-h", KEY_HELP),
2544 FUSE_OPT_KEY("--help", KEY_HELP),
Miklos Szeredi065f2222006-01-20 15:15:21 +00002545 FUSE_OPT_KEY("debug", FUSE_OPT_KEY_KEEP),
2546 FUSE_OPT_KEY("-d", FUSE_OPT_KEY_KEEP),
Miklos Szeredi659743b2005-12-09 17:41:42 +00002547 FUSE_LIB_OPT("debug", debug, 1),
Miklos Szeredi95da8602006-01-06 18:29:40 +00002548 FUSE_LIB_OPT("-d", debug, 1),
Miklos Szeredi659743b2005-12-09 17:41:42 +00002549 FUSE_LIB_OPT("hard_remove", hard_remove, 1),
2550 FUSE_LIB_OPT("use_ino", use_ino, 1),
2551 FUSE_LIB_OPT("readdir_ino", readdir_ino, 1),
2552 FUSE_LIB_OPT("direct_io", direct_io, 1),
2553 FUSE_LIB_OPT("kernel_cache", kernel_cache, 1),
Miklos Szeredi320abe42006-01-30 18:14:51 +00002554 FUSE_LIB_OPT("auto_cache", auto_cache, 1),
2555 FUSE_LIB_OPT("noauto_cache", auto_cache, 0),
Miklos Szeredi659743b2005-12-09 17:41:42 +00002556 FUSE_LIB_OPT("umask=", set_mode, 1),
2557 FUSE_LIB_OPT("umask=%o", umask, 0),
2558 FUSE_LIB_OPT("uid=", set_uid, 1),
2559 FUSE_LIB_OPT("uid=%d", uid, 0),
2560 FUSE_LIB_OPT("gid=", set_gid, 1),
2561 FUSE_LIB_OPT("gid=%d", gid, 0),
2562 FUSE_LIB_OPT("entry_timeout=%lf", entry_timeout, 0),
2563 FUSE_LIB_OPT("attr_timeout=%lf", attr_timeout, 0),
Miklos Szeredi6e806e92006-02-16 16:59:39 +00002564 FUSE_LIB_OPT("ac_attr_timeout=%lf", ac_attr_timeout, 0),
2565 FUSE_LIB_OPT("ac_attr_timeout=", ac_attr_timeout_set, 1),
Miklos Szeredi659743b2005-12-09 17:41:42 +00002566 FUSE_LIB_OPT("negative_timeout=%lf", negative_timeout, 0),
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002567 FUSE_LIB_OPT("intr", intr, 1),
2568 FUSE_LIB_OPT("intr_signal=%d", intr_signal, 0),
Miklos Szeredi659743b2005-12-09 17:41:42 +00002569 FUSE_OPT_END
2570};
2571
Miklos Szerediad005972006-01-07 10:14:34 +00002572static void fuse_lib_help(void)
2573{
2574 fprintf(stderr,
Miklos Szeredi06091462006-02-16 16:38:34 +00002575" -o hard_remove immediate removal (don't hide files)\n"
2576" -o use_ino let filesystem set inode numbers\n"
2577" -o readdir_ino try to fill in d_ino in readdir\n"
2578" -o direct_io use direct I/O\n"
2579" -o kernel_cache cache files in kernel\n"
2580" -o [no]auto_cache enable caching based on modification times\n"
2581" -o umask=M set file permissions (octal)\n"
2582" -o uid=N set file owner\n"
2583" -o gid=N set file group\n"
2584" -o entry_timeout=T cache timeout for names (1.0s)\n"
2585" -o negative_timeout=T cache timeout for deleted names (0.0s)\n"
Miklos Szeredi6e806e92006-02-16 16:59:39 +00002586" -o attr_timeout=T cache timeout for attributes (1.0s)\n"
2587" -o ac_attr_timeout=T auto cache timeout for attributes (attr_timeout)\n"
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002588" -o intr allow requests to be interrupted\n"
2589" -o intr_signal=NUM signal to send on interrupt (%i)\n"
2590"\n", FUSE_DEFAULT_INTR_SIGNAL);
Miklos Szerediad005972006-01-07 10:14:34 +00002591}
2592
2593static int fuse_lib_opt_proc(void *data, const char *arg, int key,
2594 struct fuse_args *outargs)
2595{
2596 (void) data; (void) arg; (void) outargs;
2597
2598 if (key == KEY_HELP)
2599 fuse_lib_help();
2600
2601 return 1;
2602}
2603
2604
Miklos Szeredibd7661b2004-07-23 17:16:29 +00002605int fuse_is_lib_option(const char *opt)
2606{
Miklos Szeredi659743b2005-12-09 17:41:42 +00002607 return fuse_lowlevel_is_lib_option(opt) ||
2608 fuse_opt_match(fuse_lib_opts, opt);
Miklos Szeredibd7661b2004-07-23 17:16:29 +00002609}
2610
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002611static int fuse_init_intr_signal(int signum, int *installed)
2612{
2613 struct sigaction old_sa;
2614
2615 if (sigaction(signum, NULL, &old_sa) == -1) {
2616 perror("fuse: cannot get old signal handler");
2617 return -1;
2618 }
2619
2620 if (old_sa.sa_handler == SIG_DFL) {
2621 struct sigaction sa;
2622
2623 memset(&sa, 0, sizeof(struct sigaction));
2624 sa.sa_handler = fuse_intr_sighandler;
Miklos Szeredi0c59ebf2006-09-10 20:53:36 +00002625 sigemptyset(&sa.sa_mask);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002626
2627 if (sigaction(signum, &sa, NULL) == -1) {
2628 perror("fuse: cannot set interrupt signal handler");
2629 return -1;
2630 }
2631 *installed = 1;
2632 }
2633 return 0;
2634}
2635
Miklos Szeredi349bdda2006-09-07 11:48:16 +00002636static void fuse_restore_intr_signal(int signum)
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002637{
Miklos Szeredi349bdda2006-09-07 11:48:16 +00002638 struct sigaction sa;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002639
Miklos Szeredi349bdda2006-09-07 11:48:16 +00002640 memset(&sa, 0, sizeof(struct sigaction));
2641 sa.sa_handler = SIG_DFL;
2642 sigaction(signum, &sa, NULL);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002643}
2644
Miklos Szeredi6f385412006-03-17 15:05:40 +00002645struct fuse *fuse_new_common(struct fuse_chan *ch, struct fuse_args *args,
Miklos Szeredi0b6a0ad2004-12-04 00:40:50 +00002646 const struct fuse_operations *op,
Miklos Szeredi6f385412006-03-17 15:05:40 +00002647 size_t op_size, void *user_data, int compat)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00002648{
Miklos Szeredi97c61e92001-11-07 12:09:43 +00002649 struct fuse *f;
2650 struct node *root;
Miklos Szeredi9a5c11d2006-07-30 17:33:40 +00002651 struct fuse_lowlevel_ops llop = fuse_path_ops;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00002652
Miklos Szeredi0f62d722005-01-04 12:45:54 +00002653 if (sizeof(struct fuse_operations) < op_size) {
Miklos Szeredi0b6a0ad2004-12-04 00:40:50 +00002654 fprintf(stderr, "fuse: warning: library too old, some operations may not not work\n");
Miklos Szeredi0f62d722005-01-04 12:45:54 +00002655 op_size = sizeof(struct fuse_operations);
Miklos Szeredi0b6a0ad2004-12-04 00:40:50 +00002656 }
2657
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002658 if (fuse_create_context_key() == -1)
2659 goto out;
2660
Miklos Szeredi97c61e92001-11-07 12:09:43 +00002661 f = (struct fuse *) calloc(1, sizeof(struct fuse));
Miklos Szeredie56818b2004-12-12 11:45:24 +00002662 if (f == NULL) {
2663 fprintf(stderr, "fuse: failed to allocate fuse object\n");
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002664 goto out_delete_context_key;
Miklos Szeredie56818b2004-12-12 11:45:24 +00002665 }
Miklos Szeredi2df1c042001-11-06 15:07:17 +00002666
Miklos Szeredi6f385412006-03-17 15:05:40 +00002667 f->user_data = user_data;
Miklos Szeredi659743b2005-12-09 17:41:42 +00002668 f->conf.entry_timeout = 1.0;
2669 f->conf.attr_timeout = 1.0;
2670 f->conf.negative_timeout = 0.0;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002671 f->conf.intr_signal = FUSE_DEFAULT_INTR_SIGNAL;
Miklos Szeredi6c0209a2005-08-02 13:31:28 +00002672
Miklos Szerediad005972006-01-07 10:14:34 +00002673 if (fuse_opt_parse(args, &f->conf, fuse_lib_opts, fuse_lib_opt_proc) == -1)
Miklos Szeredi659743b2005-12-09 17:41:42 +00002674 goto out_free;
Miklos Szeredib2cf9562004-09-16 08:42:40 +00002675
Miklos Szeredi6e806e92006-02-16 16:59:39 +00002676 if (!f->conf.ac_attr_timeout_set)
2677 f->conf.ac_attr_timeout = f->conf.attr_timeout;
2678
Miklos Szeredi659743b2005-12-09 17:41:42 +00002679#ifdef __FreeBSD__
2680 /*
2681 * In FreeBSD, we always use these settings as inode numbers are needed to
2682 * make getcwd(3) work.
2683 */
Miklos Szeredi76fc3de2005-12-12 09:34:45 +00002684 f->conf.readdir_ino = 1;
Miklos Szeredi659743b2005-12-09 17:41:42 +00002685#endif
2686
Miklos Szeredi065f2222006-01-20 15:15:21 +00002687 if (compat && compat <= 25) {
2688 if (fuse_sync_compat_args(args) == -1)
2689 goto out_free;
2690 }
2691
Miklos Szeredi9a5c11d2006-07-30 17:33:40 +00002692 memcpy(&f->op, op, op_size);
2693 if (!f->op.lock) {
2694 llop.getlk = NULL;
2695 llop.setlk = NULL;
2696 }
2697
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002698 f->se = fuse_lowlevel_new_common(args, &llop, sizeof(llop), f);
Miklos Szeredia1482422005-08-14 23:00:27 +00002699 if (f->se == NULL)
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002700 goto out_free;
Miklos Szeredi2bb750e2005-10-03 14:54:24 +00002701
Miklos Szeredia1482422005-08-14 23:00:27 +00002702 fuse_session_add_chan(f->se, ch);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002703
Miklos Szeredi97c61e92001-11-07 12:09:43 +00002704 f->ctr = 0;
Miklos Szeredi76f65782004-02-19 16:55:40 +00002705 f->generation = 0;
Miklos Szeredifff56ab2001-11-16 10:12:59 +00002706 /* FIXME: Dynamic hash table */
Miklos Szeredi97c61e92001-11-07 12:09:43 +00002707 f->name_table_size = 14057;
2708 f->name_table = (struct node **)
2709 calloc(1, sizeof(struct node *) * f->name_table_size);
Miklos Szeredie56818b2004-12-12 11:45:24 +00002710 if (f->name_table == NULL) {
2711 fprintf(stderr, "fuse: memory allocation failed\n");
Miklos Szeredia1482422005-08-14 23:00:27 +00002712 goto out_free_session;
Miklos Szeredie56818b2004-12-12 11:45:24 +00002713 }
Miklos Szeredib2cf9562004-09-16 08:42:40 +00002714
Miklos Szeredia13d9002004-11-02 17:32:03 +00002715 f->id_table_size = 14057;
2716 f->id_table = (struct node **)
2717 calloc(1, sizeof(struct node *) * f->id_table_size);
Miklos Szeredie56818b2004-12-12 11:45:24 +00002718 if (f->id_table == NULL) {
2719 fprintf(stderr, "fuse: memory allocation failed\n");
Miklos Szeredib2cf9562004-09-16 08:42:40 +00002720 goto out_free_name_table;
Miklos Szeredie56818b2004-12-12 11:45:24 +00002721 }
Miklos Szeredib2cf9562004-09-16 08:42:40 +00002722
Miklos Szeredi38f152c2006-09-03 18:28:52 +00002723 fuse_mutex_init(&f->lock);
Miklos Szeredid0a777a2006-04-05 07:18:00 +00002724 pthread_rwlock_init(&f->tree_lock, NULL);
Miklos Szeredi0b6a0ad2004-12-04 00:40:50 +00002725 f->compat = compat;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00002726
Miklos Szeredi97c61e92001-11-07 12:09:43 +00002727 root = (struct node *) calloc(1, sizeof(struct node));
Miklos Szeredie56818b2004-12-12 11:45:24 +00002728 if (root == NULL) {
2729 fprintf(stderr, "fuse: memory allocation failed\n");
Miklos Szeredia13d9002004-11-02 17:32:03 +00002730 goto out_free_id_table;
Miklos Szeredie56818b2004-12-12 11:45:24 +00002731 }
Miklos Szeredib2cf9562004-09-16 08:42:40 +00002732
Miklos Szeredi97c61e92001-11-07 12:09:43 +00002733 root->name = strdup("/");
Miklos Szeredie56818b2004-12-12 11:45:24 +00002734 if (root->name == NULL) {
2735 fprintf(stderr, "fuse: memory allocation failed\n");
Miklos Szeredib2cf9562004-09-16 08:42:40 +00002736 goto out_free_root;
Miklos Szeredie56818b2004-12-12 11:45:24 +00002737 }
Miklos Szeredib2cf9562004-09-16 08:42:40 +00002738
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002739 if (f->conf.intr &&
2740 fuse_init_intr_signal(f->conf.intr_signal, &f->intr_installed) == -1)
2741 goto out_free_root_name;
2742
Miklos Szeredi97c61e92001-11-07 12:09:43 +00002743 root->parent = 0;
Miklos Szeredia13d9002004-11-02 17:32:03 +00002744 root->nodeid = FUSE_ROOT_ID;
Miklos Szeredi76f65782004-02-19 16:55:40 +00002745 root->generation = 0;
Miklos Szeredi0f62d722005-01-04 12:45:54 +00002746 root->refctr = 1;
Miklos Szeredi38009022005-05-08 19:47:22 +00002747 root->nlookup = 1;
Miklos Szeredia13d9002004-11-02 17:32:03 +00002748 hash_id(f, root);
Miklos Szeredi97c61e92001-11-07 12:09:43 +00002749
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00002750 return f;
Miklos Szeredib2cf9562004-09-16 08:42:40 +00002751
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002752 out_free_root_name:
2753 free(root->name);
Miklos Szeredib2cf9562004-09-16 08:42:40 +00002754 out_free_root:
2755 free(root);
Miklos Szeredia13d9002004-11-02 17:32:03 +00002756 out_free_id_table:
2757 free(f->id_table);
Miklos Szeredib2cf9562004-09-16 08:42:40 +00002758 out_free_name_table:
2759 free(f->name_table);
Miklos Szeredia1482422005-08-14 23:00:27 +00002760 out_free_session:
2761 fuse_session_destroy(f->se);
Miklos Szeredib2cf9562004-09-16 08:42:40 +00002762 out_free:
2763 free(f);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002764 out_delete_context_key:
2765 fuse_delete_context_key();
Miklos Szeredib2cf9562004-09-16 08:42:40 +00002766 out:
Miklos Szeredib2cf9562004-09-16 08:42:40 +00002767 return NULL;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00002768}
2769
Miklos Szeredi6f385412006-03-17 15:05:40 +00002770struct fuse *fuse_new(struct fuse_chan *ch, struct fuse_args *args,
2771 const struct fuse_operations *op, size_t op_size,
2772 void *user_data)
Miklos Szeredi0b6a0ad2004-12-04 00:40:50 +00002773{
Miklos Szeredi6f385412006-03-17 15:05:40 +00002774 return fuse_new_common(ch, args, op, op_size, user_data, 0);
Miklos Szeredi0b6a0ad2004-12-04 00:40:50 +00002775}
2776
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00002777void fuse_destroy(struct fuse *f)
2778{
Miklos Szeredi97c61e92001-11-07 12:09:43 +00002779 size_t i;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002780 struct fuse_context_i *c = fuse_get_context_internal();
2781
2782 if (f->conf.intr && f->intr_installed)
2783 fuse_restore_intr_signal(f->conf.intr_signal);
Miklos Szerediad519562006-07-31 11:07:40 +00002784
2785 memset(c, 0, sizeof(*c));
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002786 c->ctx.fuse = f;
2787 c->ctx.private_data = f->user_data;
Miklos Szerediad519562006-07-31 11:07:40 +00002788
Miklos Szeredia13d9002004-11-02 17:32:03 +00002789 for (i = 0; i < f->id_table_size; i++) {
Miklos Szeredi97c61e92001-11-07 12:09:43 +00002790 struct node *node;
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00002791
Miklos Szeredia13d9002004-11-02 17:32:03 +00002792 for (node = f->id_table[i]; node != NULL; node = node->id_next) {
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00002793 if (node->is_hidden) {
Miklos Szeredia13d9002004-11-02 17:32:03 +00002794 char *path = get_path(f, node->nodeid);
Miklos Szeredi21019c92005-05-09 11:22:41 +00002795 if (path) {
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00002796 f->op.unlink(path);
Miklos Szeredi21019c92005-05-09 11:22:41 +00002797 free(path);
2798 }
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00002799 }
2800 }
2801 }
Miklos Szeredia13d9002004-11-02 17:32:03 +00002802 for (i = 0; i < f->id_table_size; i++) {
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00002803 struct node *node;
Miklos Szeredi97c61e92001-11-07 12:09:43 +00002804 struct node *next;
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00002805
Miklos Szeredia13d9002004-11-02 17:32:03 +00002806 for (node = f->id_table[i]; node != NULL; node = next) {
2807 next = node->id_next;
Miklos Szeredi97c61e92001-11-07 12:09:43 +00002808 free_node(node);
2809 }
2810 }
Miklos Szeredia13d9002004-11-02 17:32:03 +00002811 free(f->id_table);
Miklos Szeredi97c61e92001-11-07 12:09:43 +00002812 free(f->name_table);
Miklos Szeredia181e612001-11-06 12:03:23 +00002813 pthread_mutex_destroy(&f->lock);
Miklos Szeredi55a84102006-06-06 10:16:38 +00002814 pthread_rwlock_destroy(&f->tree_lock);
Miklos Szeredia1482422005-08-14 23:00:27 +00002815 fuse_session_destroy(f->se);
Miklos Szeredi97c61e92001-11-07 12:09:43 +00002816 free(f);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002817 fuse_delete_context_key();
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00002818}
Miklos Szeredi0b6a0ad2004-12-04 00:40:50 +00002819
Miklos Szeredieafdf422006-09-22 19:30:17 +00002820#include "fuse_common_compat.h"
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002821#include "fuse_compat.h"
2822
Miklos Szeredi6f385412006-03-17 15:05:40 +00002823static struct fuse *fuse_new_common_compat25(int fd, struct fuse_args *args,
2824 const struct fuse_operations *op,
2825 size_t op_size, int compat)
2826{
2827 struct fuse *f = NULL;
2828 struct fuse_chan *ch = fuse_kern_chan_new(fd);
2829
2830 if (ch)
2831 f = fuse_new_common(ch, args, op, op_size, NULL, compat);
2832
2833 return f;
2834}
2835
Miklos Szeredi065f2222006-01-20 15:15:21 +00002836#ifndef __FreeBSD__
2837
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002838static int fuse_compat_open(struct fuse *f, fuse_req_t req, char *path,
2839 struct fuse_file_info *fi)
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002840{
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002841 int err;
2842 struct fuse_intr_data d;
Miklos Szeredi065f2222006-01-20 15:15:21 +00002843 if (!f->compat || f->compat >= 25)
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002844 err = fuse_do_open(f, req, path, fi);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002845 else if (f->compat == 22) {
Miklos Szeredieafdf422006-09-22 19:30:17 +00002846 struct fuse_file_info_compat tmp;
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002847 memcpy(&tmp, fi, sizeof(tmp));
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002848 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002849 err = ((struct fuse_operations_compat22 *) &f->op)->open(path, &tmp);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002850 fuse_finish_interrupt(f, req, &d);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002851 memcpy(fi, &tmp, sizeof(tmp));
2852 fi->fh = tmp.fh;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002853 } else {
2854 fuse_prepare_interrupt(f, req, &d);
2855 err =
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002856 ((struct fuse_operations_compat2 *) &f->op)->open(path, fi->flags);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002857 fuse_finish_interrupt(f, req, &d);
2858 }
2859 return err;
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002860}
2861
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002862static void fuse_compat_release(struct fuse *f, fuse_req_t req, char *path,
2863 struct fuse_file_info *fi)
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002864{
2865 if (!f->compat || f->compat >= 22)
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002866 fuse_do_release(f, req, path ? path : "-", fi);
2867 else if (path) {
2868 struct fuse_intr_data d;
2869 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002870 ((struct fuse_operations_compat2 *) &f->op)->release(path, fi->flags);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002871 fuse_finish_interrupt(f, req, &d);
2872 }
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002873}
2874
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002875static int fuse_compat_opendir(struct fuse *f, fuse_req_t req, char *path,
2876 struct fuse_file_info *fi)
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002877{
Miklos Szeredi065f2222006-01-20 15:15:21 +00002878 if (!f->compat || f->compat >= 25) {
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002879 return fuse_do_opendir(f, req, path, fi);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002880 } else {
2881 int err;
Miklos Szeredieafdf422006-09-22 19:30:17 +00002882 struct fuse_file_info_compat tmp;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002883 struct fuse_intr_data d;
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002884 memcpy(&tmp, fi, sizeof(tmp));
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002885 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002886 err = ((struct fuse_operations_compat22 *) &f->op)->opendir(path, &tmp);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002887 fuse_finish_interrupt(f, req, &d);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002888 memcpy(fi, &tmp, sizeof(tmp));
2889 fi->fh = tmp.fh;
2890 return err;
2891 }
2892}
2893
2894static void convert_statfs_compat(struct fuse_statfs_compat1 *compatbuf,
2895 struct statvfs *stbuf)
2896{
2897 stbuf->f_bsize = compatbuf->block_size;
2898 stbuf->f_blocks = compatbuf->blocks;
2899 stbuf->f_bfree = compatbuf->blocks_free;
2900 stbuf->f_bavail = compatbuf->blocks_free;
2901 stbuf->f_files = compatbuf->files;
2902 stbuf->f_ffree = compatbuf->files_free;
2903 stbuf->f_namemax = compatbuf->namelen;
2904}
2905
2906static void convert_statfs_old(struct statfs *oldbuf, struct statvfs *stbuf)
2907{
2908 stbuf->f_bsize = oldbuf->f_bsize;
2909 stbuf->f_blocks = oldbuf->f_blocks;
2910 stbuf->f_bfree = oldbuf->f_bfree;
2911 stbuf->f_bavail = oldbuf->f_bavail;
2912 stbuf->f_files = oldbuf->f_files;
2913 stbuf->f_ffree = oldbuf->f_ffree;
2914 stbuf->f_namemax = oldbuf->f_namelen;
2915}
2916
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002917static int fuse_compat_statfs(struct fuse *f, fuse_req_t req,
2918 struct statvfs *buf)
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002919{
2920 int err;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002921 struct fuse_intr_data d;
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002922
Miklos Szeredi065f2222006-01-20 15:15:21 +00002923 if (!f->compat || f->compat >= 25) {
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002924 err = fuse_do_statfs(f, req, "/", buf);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002925 } else if (f->compat > 11) {
2926 struct statfs oldbuf;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002927 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002928 err = ((struct fuse_operations_compat22 *) &f->op)->statfs("/", &oldbuf);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002929 fuse_finish_interrupt(f, req, &d);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002930 if (!err)
2931 convert_statfs_old(&oldbuf, buf);
2932 } else {
2933 struct fuse_statfs_compat1 compatbuf;
2934 memset(&compatbuf, 0, sizeof(struct fuse_statfs_compat1));
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002935 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002936 err = ((struct fuse_operations_compat1 *) &f->op)->statfs(&compatbuf);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002937 fuse_finish_interrupt(f, req, &d);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002938 if (!err)
2939 convert_statfs_compat(&compatbuf, buf);
2940 }
2941 return err;
2942}
2943
Miklos Szeredi95da8602006-01-06 18:29:40 +00002944static struct fuse *fuse_new_common_compat(int fd, const char *opts,
2945 const struct fuse_operations *op,
2946 size_t op_size, int compat)
2947{
2948 struct fuse *f;
2949 struct fuse_args args = FUSE_ARGS_INIT(0, NULL);
2950
Miklos Szeredi6e7d0182007-01-19 22:11:40 +00002951 if (fuse_opt_add_arg(&args, "") == -1)
2952 return NULL;
Miklos Szeredi95da8602006-01-06 18:29:40 +00002953 if (opts &&
Miklos Szeredi6e7d0182007-01-19 22:11:40 +00002954 (fuse_opt_add_arg(&args, "-o") == -1 ||
Miklos Szeredi95da8602006-01-06 18:29:40 +00002955 fuse_opt_add_arg(&args, opts) == -1)) {
2956 fuse_opt_free_args(&args);
2957 return NULL;
2958 }
Miklos Szeredi6f385412006-03-17 15:05:40 +00002959 f = fuse_new_common_compat25(fd, &args, op, op_size, compat);
Miklos Szeredi95da8602006-01-06 18:29:40 +00002960 fuse_opt_free_args(&args);
2961
2962 return f;
2963}
2964
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002965struct fuse *fuse_new_compat22(int fd, const char *opts,
2966 const struct fuse_operations_compat22 *op,
2967 size_t op_size)
2968{
Miklos Szeredi95da8602006-01-06 18:29:40 +00002969 return fuse_new_common_compat(fd, opts, (struct fuse_operations *) op,
2970 op_size, 22);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002971}
2972
2973struct fuse *fuse_new_compat2(int fd, const char *opts,
2974 const struct fuse_operations_compat2 *op)
2975{
Miklos Szeredi95da8602006-01-06 18:29:40 +00002976 return fuse_new_common_compat(fd, opts, (struct fuse_operations *) op,
2977 sizeof(struct fuse_operations_compat2), 21);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002978}
2979
2980struct fuse *fuse_new_compat1(int fd, int flags,
2981 const struct fuse_operations_compat1 *op)
2982{
2983 const char *opts = NULL;
2984 if (flags & FUSE_DEBUG_COMPAT1)
2985 opts = "debug";
Miklos Szeredi95da8602006-01-06 18:29:40 +00002986 return fuse_new_common_compat(fd, opts, (struct fuse_operations *) op,
2987 sizeof(struct fuse_operations_compat1), 11);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002988}
2989
Miklos Szeredif458b8c2004-12-07 16:46:42 +00002990__asm__(".symver fuse_exited,__fuse_exited@");
2991__asm__(".symver fuse_process_cmd,__fuse_process_cmd@");
2992__asm__(".symver fuse_read_cmd,__fuse_read_cmd@");
2993__asm__(".symver fuse_set_getcontext_func,__fuse_set_getcontext_func@");
2994__asm__(".symver fuse_new_compat2,fuse_new@");
Miklos Szeredi3a770472005-11-11 21:32:42 +00002995__asm__(".symver fuse_new_compat22,fuse_new@FUSE_2.2");
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002996
2997#else /* __FreeBSD__ */
2998
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002999static int fuse_compat_open(struct fuse *f, fuse_req_t req, char *path,
3000 struct fuse_file_info *fi)
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00003001{
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00003002 return fuse_do_open(f, req, path, fi);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00003003}
3004
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00003005static void fuse_compat_release(struct fuse *f, fuse_req_t req, char *path,
3006 struct fuse_file_info *fi)
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00003007{
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00003008 fuse_do_release(f, req, path ? path : "-", fi);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00003009}
3010
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00003011static int fuse_compat_opendir(struct fuse *f, fuse_req_t req, char *path,
3012 struct fuse_file_info *fi)
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00003013{
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00003014 return fuse_do_opendir(f, req, path, fi);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00003015}
3016
Csaba Henk3e3a1252006-09-24 14:53:29 +00003017static int fuse_compat_statfs(struct fuse *f, fuse_req_t req, struct statvfs *buf)
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00003018{
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00003019 return fuse_do_statfs(f, req, "/", buf);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00003020}
3021
3022#endif /* __FreeBSD__ */
Miklos Szeredi065f2222006-01-20 15:15:21 +00003023
3024struct fuse *fuse_new_compat25(int fd, struct fuse_args *args,
3025 const struct fuse_operations_compat25 *op,
3026 size_t op_size)
3027{
Miklos Szeredi6f385412006-03-17 15:05:40 +00003028 return fuse_new_common_compat25(fd, args, (struct fuse_operations *) op,
3029 op_size, 25);
Miklos Szeredi065f2222006-01-20 15:15:21 +00003030}
3031
3032__asm__(".symver fuse_new_compat25,fuse_new@FUSE_2.5");