blob: 8fc1bac1ae04e6cba0def4664369a55da0bd0039 [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 Szeredi288ed4e2006-09-07 06:02:44 +0000704 int res = fuse_do_rename(f, req, oldpath, newpath);
Miklos Szeredib2cf9562004-09-16 08:42:40 +0000705 if (res == 0)
706 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 Szeredi288ed4e2006-09-07 06:02:44 +00001349 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 Szeredid9079a72005-10-26 15:29:06 +00001445 forget_node(f, e.ino, 1);
1446 } else {
1447 struct node *node = get_node(f, e.ino);
1448 node->open_count ++;
1449 }
1450 pthread_mutex_unlock(&f->lock);
1451 } else
1452 reply_err(req, err);
1453
1454 if (path)
1455 free(path);
1456 pthread_rwlock_unlock(&f->tree_lock);
1457}
1458
Miklos Szeredi320abe42006-01-30 18:14:51 +00001459static double diff_timespec(const struct timespec *t1,
1460 const struct timespec *t2)
1461{
1462 return (t1->tv_sec - t2->tv_sec) +
1463 ((double) t1->tv_nsec - (double) t2->tv_nsec) / 1000000000.0;
1464}
1465
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001466static void open_auto_cache(struct fuse *f, fuse_req_t req, fuse_ino_t ino,
1467 const char *path, struct fuse_file_info *fi)
Miklos Szeredi320abe42006-01-30 18:14:51 +00001468{
1469 struct node *node = get_node(f, ino);
Miklos Szeredi08dab162006-02-01 13:39:15 +00001470 if (node->cache_valid) {
1471 struct timespec now;
Miklos Szeredi320abe42006-01-30 18:14:51 +00001472
Miklos Szeredi08dab162006-02-01 13:39:15 +00001473 curr_time(&now);
Miklos Szeredi6e806e92006-02-16 16:59:39 +00001474 if (diff_timespec(&now, &node->stat_updated) > f->conf.ac_attr_timeout) {
Miklos Szeredi08dab162006-02-01 13:39:15 +00001475 struct stat stbuf;
1476 int err;
Miklos Szeredi320abe42006-01-30 18:14:51 +00001477
Miklos Szeredi08dab162006-02-01 13:39:15 +00001478 if (f->op.fgetattr)
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001479 err = fuse_do_fgetattr(f, req, path, &stbuf, fi);
Miklos Szeredi08dab162006-02-01 13:39:15 +00001480 else
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001481 err = fuse_do_getattr(f, req, path, &stbuf);
Miklos Szeredi08dab162006-02-01 13:39:15 +00001482
1483 if (!err)
1484 update_stat(node, &stbuf);
1485 else
1486 node->cache_valid = 0;
1487 }
Miklos Szeredi320abe42006-01-30 18:14:51 +00001488 }
1489 if (node->cache_valid)
1490 fi->keep_cache = 1;
Miklos Szeredi08dab162006-02-01 13:39:15 +00001491
1492 node->cache_valid = 1;
Miklos Szeredi320abe42006-01-30 18:14:51 +00001493}
1494
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001495static void fuse_open(fuse_req_t req, fuse_ino_t ino,
1496 struct fuse_file_info *fi)
Miklos Szeredi5e183482001-10-31 14:52:35 +00001497{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001498 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredi31066bb2005-08-01 14:49:31 +00001499 char *path = NULL;
1500 int err = 0;
Miklos Szeredi5e183482001-10-31 14:52:35 +00001501
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001502 pthread_rwlock_rdlock(&f->tree_lock);
Miklos Szeredi31066bb2005-08-01 14:49:31 +00001503 if (f->op.open) {
1504 err = -ENOENT;
1505 path = get_path(f, ino);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00001506 if (path != NULL)
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001507 err = fuse_compat_open(f, req, path, fi);
Miklos Szeredi40b9a5a2002-12-10 16:09:02 +00001508 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001509 if (!err) {
Miklos Szeredi659743b2005-12-09 17:41:42 +00001510 if (f->conf.debug) {
Miklos Szeredi3a770472005-11-11 21:32:42 +00001511 printf("OPEN[%llu] flags: 0x%x\n", (unsigned long long) fi->fh,
1512 fi->flags);
Miklos Szeredi209f5d02004-07-24 19:56:16 +00001513 fflush(stdout);
1514 }
Miklos Szeredie5183742005-02-02 11:14:04 +00001515
Miklos Szeredi659743b2005-12-09 17:41:42 +00001516 if (f->conf.direct_io)
Miklos Szeredie77cc072005-08-01 11:58:51 +00001517 fi->direct_io = 1;
Miklos Szeredi659743b2005-12-09 17:41:42 +00001518 if (f->conf.kernel_cache)
Miklos Szeredie77cc072005-08-01 11:58:51 +00001519 fi->keep_cache = 1;
1520
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001521 pthread_mutex_lock(&f->lock);
Miklos Szeredi320abe42006-01-30 18:14:51 +00001522 if (f->conf.auto_cache)
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001523 open_auto_cache(f, req, ino, path, fi);
Miklos Szeredi320abe42006-01-30 18:14:51 +00001524
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001525 if (fuse_reply_open(req, fi) == -ENOENT) {
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001526 /* The open syscall was interrupted, so it must be cancelled */
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00001527 if(f->op.release && path != NULL)
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001528 fuse_compat_release(f, req, path, fi);
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001529 } else {
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001530 struct node *node = get_node(f, ino);
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001531 node->open_count ++;
1532 }
Miklos Szeredi73798f92004-07-12 15:55:11 +00001533 pthread_mutex_unlock(&f->lock);
Miklos Szeredi73798f92004-07-12 15:55:11 +00001534 } else
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001535 reply_err(req, err);
Miklos Szeredi73798f92004-07-12 15:55:11 +00001536
Miklos Szeredi9a31cca2004-06-26 21:11:25 +00001537 if (path)
1538 free(path);
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001539 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001540}
1541
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001542static void fuse_read(fuse_req_t req, fuse_ino_t ino, size_t size, off_t off,
1543 struct fuse_file_info *fi)
Miklos Szeredie2e4ac22004-05-18 08:45:28 +00001544{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001545 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredie2e4ac22004-05-18 08:45:28 +00001546 char *path;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001547 char *buf;
Miklos Szeredie2e4ac22004-05-18 08:45:28 +00001548 int res;
1549
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001550 buf = (char *) malloc(size);
1551 if (buf == NULL) {
1552 reply_err(req, -ENOMEM);
1553 return;
1554 }
1555
Miklos Szeredie2e4ac22004-05-18 08:45:28 +00001556 res = -ENOENT;
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001557 pthread_rwlock_rdlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001558 path = get_path(f, ino);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001559 if (path != NULL) {
Miklos Szeredi659743b2005-12-09 17:41:42 +00001560 if (f->conf.debug) {
Miklos Szeredia039f8f2006-02-24 16:21:58 +00001561 printf("READ[%llu] %lu bytes from %llu\n",
1562 (unsigned long long) fi->fh, (unsigned long) size,
1563 (unsigned long long) off);
Miklos Szeredi209f5d02004-07-24 19:56:16 +00001564 fflush(stdout);
1565 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001566
Miklos Szeredie2e4ac22004-05-18 08:45:28 +00001567 res = -ENOSYS;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001568 if (f->op.read) {
1569 struct fuse_intr_data d;
1570 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001571 res = f->op.read(path, buf, size, off, fi);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001572 fuse_finish_interrupt(f, req, &d);
1573 }
Miklos Szeredie2e4ac22004-05-18 08:45:28 +00001574 free(path);
1575 }
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001576 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001577
1578 if (res >= 0) {
Miklos Szeredi659743b2005-12-09 17:41:42 +00001579 if (f->conf.debug) {
Miklos Szeredi3a770472005-11-11 21:32:42 +00001580 printf(" READ[%llu] %u bytes\n", (unsigned long long) fi->fh,
1581 res);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001582 fflush(stdout);
1583 }
Miklos Szeredif412d072005-10-14 21:24:32 +00001584 if ((size_t) res > size)
1585 fprintf(stderr, "fuse: read too many bytes");
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001586 fuse_reply_buf(req, buf, res);
1587 } else
1588 reply_err(req, res);
1589
1590 free(buf);
Miklos Szeredie2e4ac22004-05-18 08:45:28 +00001591}
1592
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001593static void fuse_write(fuse_req_t req, fuse_ino_t ino, const char *buf,
1594 size_t size, off_t off, struct fuse_file_info *fi)
Miklos Szeredic8ba2372002-12-10 12:26:00 +00001595{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001596 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001597 char *path;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001598 int res;
1599
1600 res = -ENOENT;
1601 pthread_rwlock_rdlock(&f->tree_lock);
1602 path = get_path(f, ino);
1603 if (path != NULL) {
Miklos Szeredi659743b2005-12-09 17:41:42 +00001604 if (f->conf.debug) {
Miklos Szeredia039f8f2006-02-24 16:21:58 +00001605 printf("WRITE%s[%llu] %lu bytes to %llu\n",
Miklos Szeredi3a770472005-11-11 21:32:42 +00001606 fi->writepage ? "PAGE" : "", (unsigned long long) fi->fh,
Miklos Szeredia039f8f2006-02-24 16:21:58 +00001607 (unsigned long) size, (unsigned long long) off);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001608 fflush(stdout);
1609 }
1610
1611 res = -ENOSYS;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001612 if (f->op.write) {
1613 struct fuse_intr_data d;
1614 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001615 res = f->op.write(path, buf, size, off, fi);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001616 fuse_finish_interrupt(f, req, &d);
1617 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001618 free(path);
1619 }
1620 pthread_rwlock_unlock(&f->tree_lock);
1621
Miklos Szeredif412d072005-10-14 21:24:32 +00001622 if (res >= 0) {
Miklos Szeredi659743b2005-12-09 17:41:42 +00001623 if (f->conf.debug) {
Miklos Szeredi3a770472005-11-11 21:32:42 +00001624 printf(" WRITE%s[%llu] %u bytes\n",
1625 fi->writepage ? "PAGE" : "", (unsigned long long) fi->fh,
1626 res);
Miklos Szeredif412d072005-10-14 21:24:32 +00001627 fflush(stdout);
1628 }
1629 if ((size_t) res > size)
1630 fprintf(stderr, "fuse: wrote too many bytes");
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001631 fuse_reply_write(req, res);
Miklos Szeredif412d072005-10-14 21:24:32 +00001632 } else
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001633 reply_err(req, res);
1634}
1635
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001636static void fuse_release(fuse_req_t req, fuse_ino_t ino,
1637 struct fuse_file_info *fi)
1638{
1639 struct fuse *f = req_fuse_prepare(req);
1640 char *path;
1641 struct node *node;
Miklos Szeredic3b76812006-09-16 08:52:09 +00001642 int unlink_hidden = 0;
Miklos Szeredi4fca4322006-10-01 14:41:04 +00001643 int err = 0;
Miklos Szeredifb28c5e2004-11-26 12:15:06 +00001644
Miklos Szerediaa8258e2006-02-25 14:42:03 +00001645 pthread_rwlock_rdlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001646 path = get_path(f, ino);
Miklos Szeredi659743b2005-12-09 17:41:42 +00001647 if (f->conf.debug) {
Miklos Szeredi4fca4322006-10-01 14:41:04 +00001648 printf("RELEASE%s[%llu] flags: 0x%x\n", fi->flush ? "+FLUSH" : "",
1649 (unsigned long long) fi->fh, fi->flags);
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001650 fflush(stdout);
Miklos Szeredic8ba2372002-12-10 12:26:00 +00001651 }
Miklos Szeredi4fca4322006-10-01 14:41:04 +00001652 if (fi->flush && path && f->op.flush)
1653 err = fuse_do_flush(f, req, path, fi);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00001654 if (f->op.release)
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001655 fuse_compat_release(f, req, path, fi);
Miklos Szeredie5183742005-02-02 11:14:04 +00001656
Miklos Szeredi9a5c11d2006-07-30 17:33:40 +00001657 pthread_mutex_lock(&f->lock);
1658 node = get_node(f, ino);
1659 assert(node->open_count > 0);
1660 --node->open_count;
Miklos Szeredic3b76812006-09-16 08:52:09 +00001661 if (node->is_hidden && !node->open_count) {
1662 unlink_hidden = 1;
1663 node->is_hidden = 0;
1664 }
Miklos Szeredi9a5c11d2006-07-30 17:33:40 +00001665 pthread_mutex_unlock(&f->lock);
1666
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001667 if(unlink_hidden && path)
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001668 fuse_do_unlink(f, req, path);
Miklos Szeredie5183742005-02-02 11:14:04 +00001669
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001670 if (path)
1671 free(path);
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001672 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001673
Miklos Szeredi4fca4322006-10-01 14:41:04 +00001674 reply_err(req, err);
Miklos Szeredic8ba2372002-12-10 12:26:00 +00001675}
1676
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001677static void fuse_fsync(fuse_req_t req, fuse_ino_t ino, int datasync,
1678 struct fuse_file_info *fi)
Miklos Szeredi5e183482001-10-31 14:52:35 +00001679{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001680 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001681 char *path;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001682 int err;
Miklos Szerediab974562005-04-07 15:40:21 +00001683
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001684 err = -ENOENT;
1685 pthread_rwlock_rdlock(&f->tree_lock);
1686 path = get_path(f, ino);
1687 if (path != NULL) {
Miklos Szeredi659743b2005-12-09 17:41:42 +00001688 if (f->conf.debug) {
Miklos Szeredi3a770472005-11-11 21:32:42 +00001689 printf("FSYNC[%llu]\n", (unsigned long long) fi->fh);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001690 fflush(stdout);
1691 }
1692 err = -ENOSYS;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001693 if (f->op.fsync) {
1694 struct fuse_intr_data d;
1695 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001696 err = f->op.fsync(path, datasync, fi);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001697 fuse_finish_interrupt(f, req, &d);
1698 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001699 free(path);
1700 }
1701 pthread_rwlock_unlock(&f->tree_lock);
1702 reply_err(req, err);
1703}
1704
1705static struct fuse_dirhandle *get_dirhandle(const struct fuse_file_info *llfi,
1706 struct fuse_file_info *fi)
1707{
Miklos Szeredi3a770472005-11-11 21:32:42 +00001708 struct fuse_dirhandle *dh = (struct fuse_dirhandle *) (uintptr_t) llfi->fh;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001709 memset(fi, 0, sizeof(struct fuse_file_info));
1710 fi->fh = dh->fh;
Miklos Szerediead7f102005-11-28 16:02:27 +00001711 fi->fh_old = dh->fh;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001712 return dh;
1713}
1714
1715static void fuse_opendir(fuse_req_t req, fuse_ino_t ino,
1716 struct fuse_file_info *llfi)
1717{
1718 struct fuse *f = req_fuse_prepare(req);
1719 struct fuse_dirhandle *dh;
1720
1721 dh = (struct fuse_dirhandle *) malloc(sizeof(struct fuse_dirhandle));
1722 if (dh == NULL) {
1723 reply_err(req, -ENOMEM);
Miklos Szerediab974562005-04-07 15:40:21 +00001724 return;
Miklos Szeredi5e183482001-10-31 14:52:35 +00001725 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001726 memset(dh, 0, sizeof(struct fuse_dirhandle));
1727 dh->fuse = f;
1728 dh->contents = NULL;
1729 dh->len = 0;
1730 dh->filled = 0;
1731 dh->nodeid = ino;
Miklos Szeredi38f152c2006-09-03 18:28:52 +00001732 fuse_mutex_init(&dh->lock);
Miklos Szerediab974562005-04-07 15:40:21 +00001733
Miklos Szeredi3a770472005-11-11 21:32:42 +00001734 llfi->fh = (uintptr_t) dh;
Miklos Szerediab974562005-04-07 15:40:21 +00001735
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001736 if (f->op.opendir) {
1737 struct fuse_file_info fi;
1738 char *path;
1739 int err;
1740
1741 memset(&fi, 0, sizeof(fi));
1742 fi.flags = llfi->flags;
1743
1744 err = -ENOENT;
1745 pthread_rwlock_rdlock(&f->tree_lock);
1746 path = get_path(f, ino);
1747 if (path != NULL) {
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001748 err = fuse_compat_opendir(f, req, path, &fi);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00001749 dh->fh = fi.fh;
Miklos Szerediab974562005-04-07 15:40:21 +00001750 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001751 if (!err) {
1752 pthread_mutex_lock(&f->lock);
1753 if (fuse_reply_open(req, llfi) == -ENOENT) {
1754 /* The opendir syscall was interrupted, so it must be
1755 cancelled */
1756 if(f->op.releasedir)
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001757 fuse_do_releasedir(f, req, path, &fi);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001758 pthread_mutex_destroy(&dh->lock);
1759 free(dh);
1760 }
1761 pthread_mutex_unlock(&f->lock);
1762 } else {
1763 reply_err(req, err);
1764 free(dh);
1765 }
Miklos Szerediab974562005-04-07 15:40:21 +00001766 free(path);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001767 pthread_rwlock_unlock(&f->tree_lock);
1768 } else
1769 fuse_reply_open(req, llfi);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001770}
Miklos Szeredib483c932001-10-29 14:57:57 +00001771
Miklos Szeredi1bf64f42006-02-17 15:49:25 +00001772static int extend_contents(struct fuse_dirhandle *dh, unsigned minsize)
1773{
1774 if (minsize > dh->size) {
1775 char *newptr;
1776 unsigned newsize = dh->size;
1777 if (!newsize)
1778 newsize = 1024;
1779 while (newsize < minsize)
1780 newsize *= 2;
1781
1782 newptr = (char *) realloc(dh->contents, newsize);
1783 if (!newptr) {
1784 dh->error = -ENOMEM;
1785 return -1;
1786 }
1787 dh->contents = newptr;
1788 dh->size = newsize;
1789 }
1790 return 0;
1791}
1792
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001793static int fill_dir_common(struct fuse_dirhandle *dh, const char *name,
Miklos Szeredif6e0ec62005-08-03 09:11:06 +00001794 const struct stat *statp, off_t off)
Miklos Szeredia181e612001-11-06 12:03:23 +00001795{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001796 struct stat stbuf;
Miklos Szeredi1bf64f42006-02-17 15:49:25 +00001797 size_t newlen;
Miklos Szeredifb28c5e2004-11-26 12:15:06 +00001798
Miklos Szeredif6e0ec62005-08-03 09:11:06 +00001799 if (statp)
1800 stbuf = *statp;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001801 else {
1802 memset(&stbuf, 0, sizeof(stbuf));
Miklos Szeredie248e4b2005-12-14 16:18:32 +00001803 stbuf.st_ino = FUSE_UNKNOWN_INO;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001804 }
Miklos Szeredia181e612001-11-06 12:03:23 +00001805
Miklos Szeredi659743b2005-12-09 17:41:42 +00001806 if (!dh->fuse->conf.use_ino) {
Miklos Szeredie248e4b2005-12-14 16:18:32 +00001807 stbuf.st_ino = FUSE_UNKNOWN_INO;
Miklos Szeredi659743b2005-12-09 17:41:42 +00001808 if (dh->fuse->conf.readdir_ino) {
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001809 struct node *node;
1810 pthread_mutex_lock(&dh->fuse->lock);
1811 node = lookup_node(dh->fuse, dh->nodeid, name);
1812 if (node)
1813 stbuf.st_ino = (ino_t) node->nodeid;
1814 pthread_mutex_unlock(&dh->fuse->lock);
Miklos Szeredi6ebe2342002-01-06 21:44:16 +00001815 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001816 }
Miklos Szeredi6ebe2342002-01-06 21:44:16 +00001817
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001818 if (off) {
Miklos Szeredi1bf64f42006-02-17 15:49:25 +00001819 if (extend_contents(dh, dh->needlen) == -1)
1820 return 1;
1821
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001822 dh->filled = 0;
Miklos Szeredi1bf64f42006-02-17 15:49:25 +00001823 newlen = dh->len + fuse_add_direntry(dh->req, dh->contents + dh->len,
1824 dh->needlen - dh->len, name,
1825 &stbuf, off);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001826 if (newlen > dh->needlen)
1827 return 1;
Miklos Szeredi1bf64f42006-02-17 15:49:25 +00001828 } else {
1829 newlen = dh->len + fuse_add_direntry(dh->req, NULL, 0, name, NULL, 0);
1830 if (extend_contents(dh, newlen) == -1)
Miklos Szeredic4c12ae2005-10-20 14:48:50 +00001831 return 1;
Miklos Szeredi1bf64f42006-02-17 15:49:25 +00001832
1833 fuse_add_direntry(dh->req, dh->contents + dh->len, dh->size - dh->len,
1834 name, &stbuf, newlen);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001835 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001836 dh->len = newlen;
1837 return 0;
1838}
1839
Miklos Szeredif6e0ec62005-08-03 09:11:06 +00001840static int fill_dir(void *buf, const char *name, const struct stat *stbuf,
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001841 off_t off)
1842{
Miklos Szeredif6e0ec62005-08-03 09:11:06 +00001843 return fill_dir_common((struct fuse_dirhandle *) buf, name, stbuf, off);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001844}
1845
1846static int fill_dir_old(struct fuse_dirhandle *dh, const char *name, int type,
1847 ino_t ino)
1848{
1849 struct stat stbuf;
1850
1851 memset(&stbuf, 0, sizeof(stbuf));
1852 stbuf.st_mode = type << 12;
1853 stbuf.st_ino = ino;
1854
1855 fill_dir_common(dh, name, &stbuf, 0);
1856 return dh->error;
1857}
1858
Miklos Szeredi1bf64f42006-02-17 15:49:25 +00001859static int readdir_fill(struct fuse *f, fuse_req_t req, fuse_ino_t ino,
1860 size_t size, off_t off, struct fuse_dirhandle *dh,
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001861 struct fuse_file_info *fi)
1862{
1863 int err = -ENOENT;
1864 char *path;
1865 pthread_rwlock_rdlock(&f->tree_lock);
1866 path = get_path(f, ino);
1867 if (path != NULL) {
1868 dh->len = 0;
1869 dh->error = 0;
1870 dh->needlen = size;
1871 dh->filled = 1;
Miklos Szeredi1bf64f42006-02-17 15:49:25 +00001872 dh->req = req;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001873 err = -ENOSYS;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001874 if (f->op.readdir) {
1875 struct fuse_intr_data d;
1876 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001877 err = f->op.readdir(path, dh, fill_dir, off, fi);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001878 fuse_finish_interrupt(f, req, &d);
1879 } else if (f->op.getdir) {
1880 struct fuse_intr_data d;
1881 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001882 err = f->op.getdir(path, dh, fill_dir_old);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001883 fuse_finish_interrupt(f, req, &d);
1884 }
Miklos Szeredi1bf64f42006-02-17 15:49:25 +00001885 dh->req = NULL;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001886 if (!err)
1887 err = dh->error;
1888 if (err)
1889 dh->filled = 0;
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001890 free(path);
Miklos Szeredia181e612001-11-06 12:03:23 +00001891 }
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001892 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001893 return err;
1894}
Miklos Szeredie5183742005-02-02 11:14:04 +00001895
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001896static void fuse_readdir(fuse_req_t req, fuse_ino_t ino, size_t size,
1897 off_t off, struct fuse_file_info *llfi)
1898{
1899 struct fuse *f = req_fuse_prepare(req);
1900 struct fuse_file_info fi;
1901 struct fuse_dirhandle *dh = get_dirhandle(llfi, &fi);
1902
1903 pthread_mutex_lock(&dh->lock);
Miklos Szeredi77ccf652005-08-19 14:40:27 +00001904 /* According to SUS, directory contents need to be refreshed on
1905 rewinddir() */
1906 if (!off)
1907 dh->filled = 0;
1908
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001909 if (!dh->filled) {
Miklos Szeredi1bf64f42006-02-17 15:49:25 +00001910 int err = readdir_fill(f, req, ino, size, off, dh, &fi);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001911 if (err) {
1912 reply_err(req, err);
1913 goto out;
1914 }
Miklos Szeredia181e612001-11-06 12:03:23 +00001915 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001916 if (dh->filled) {
1917 if (off < dh->len) {
1918 if (off + size > dh->len)
1919 size = dh->len - off;
1920 } else
1921 size = 0;
1922 } else {
1923 size = dh->len;
1924 off = 0;
1925 }
1926 fuse_reply_buf(req, dh->contents + off, size);
1927 out:
1928 pthread_mutex_unlock(&dh->lock);
1929}
Miklos Szeredia181e612001-11-06 12:03:23 +00001930
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001931static void fuse_releasedir(fuse_req_t req, fuse_ino_t ino,
1932 struct fuse_file_info *llfi)
1933{
1934 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredi9b813af2005-07-21 07:59:37 +00001935 struct fuse_file_info fi;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001936 struct fuse_dirhandle *dh = get_dirhandle(llfi, &fi);
1937 if (f->op.releasedir) {
1938 char *path;
1939
1940 pthread_rwlock_rdlock(&f->tree_lock);
1941 path = get_path(f, ino);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001942 fuse_do_releasedir(f, req, path ? path : "-", &fi);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001943 free(path);
1944 pthread_rwlock_unlock(&f->tree_lock);
1945 }
1946 pthread_mutex_lock(&dh->lock);
1947 pthread_mutex_unlock(&dh->lock);
1948 pthread_mutex_destroy(&dh->lock);
1949 free(dh->contents);
1950 free(dh);
1951 reply_err(req, 0);
1952}
1953
1954static void fuse_fsyncdir(fuse_req_t req, fuse_ino_t ino, int datasync,
1955 struct fuse_file_info *llfi)
1956{
1957 struct fuse *f = req_fuse_prepare(req);
1958 struct fuse_file_info fi;
1959 char *path;
1960 int err;
1961
1962 get_dirhandle(llfi, &fi);
1963
1964 err = -ENOENT;
1965 pthread_rwlock_rdlock(&f->tree_lock);
1966 path = get_path(f, ino);
1967 if (path != NULL) {
1968 err = -ENOSYS;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001969 if (f->op.fsyncdir) {
1970 struct fuse_intr_data d;
1971 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001972 err = f->op.fsyncdir(path, datasync, &fi);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001973 fuse_finish_interrupt(f, req, &d);
1974 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001975 free(path);
1976 }
1977 pthread_rwlock_unlock(&f->tree_lock);
1978 reply_err(req, err);
Miklos Szeredia181e612001-11-06 12:03:23 +00001979}
1980
Miklos Szeredi52cb09d2005-11-07 11:59:00 +00001981static int default_statfs(struct statvfs *buf)
Miklos Szeredi77f39942004-03-25 11:17:52 +00001982{
Miklos Szeredi52cb09d2005-11-07 11:59:00 +00001983 buf->f_namemax = 255;
Miklos Szeredi77f39942004-03-25 11:17:52 +00001984 buf->f_bsize = 512;
1985 return 0;
1986}
1987
Miklos Szeredi3ded1a32006-08-18 18:43:50 +00001988static void fuse_statfs(fuse_req_t req, fuse_ino_t ino)
Miklos Szeredi18e75e42004-02-19 14:23:27 +00001989{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001990 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredi52cb09d2005-11-07 11:59:00 +00001991 struct statvfs buf;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001992 int err;
Mark Glinesd84b39a2002-01-07 16:32:02 +00001993
Miklos Szeredi52cb09d2005-11-07 11:59:00 +00001994 memset(&buf, 0, sizeof(buf));
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001995 if (f->op.statfs) {
Miklos Szeredi3ded1a32006-08-18 18:43:50 +00001996 if (ino && (!f->compat || f->compat >= 26)) {
1997 char *path;
1998 pthread_rwlock_rdlock(&f->tree_lock);
1999 err = -ENOENT;
2000 path = get_path(f, ino);
2001 if (path) {
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002002 err = fuse_do_statfs(f, req, path, &buf);
Miklos Szeredi3ded1a32006-08-18 18:43:50 +00002003 free(path);
2004 }
2005 pthread_rwlock_unlock(&f->tree_lock);
2006 } else
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002007 err = fuse_compat_statfs(f, req, &buf);
Miklos Szeredi52cb09d2005-11-07 11:59:00 +00002008 } else
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002009 err = default_statfs(&buf);
Miklos Szeredi77f39942004-03-25 11:17:52 +00002010
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002011 if (!err)
2012 fuse_reply_statfs(req, &buf);
Miklos Szeredi03cebae2004-03-31 10:19:18 +00002013 else
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002014 reply_err(req, err);
Miklos Szeredi03cebae2004-03-31 10:19:18 +00002015}
2016
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002017static void fuse_setxattr(fuse_req_t req, fuse_ino_t ino, const char *name,
2018 const char *value, size_t size, int flags)
Miklos Szeredi3ed84232004-03-30 15:17:26 +00002019{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002020 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredi3ed84232004-03-30 15:17:26 +00002021 char *path;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002022 int err;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00002023
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002024 err = -ENOENT;
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00002025 pthread_rwlock_rdlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002026 path = get_path(f, ino);
Miklos Szeredi3ed84232004-03-30 15:17:26 +00002027 if (path != NULL) {
Miklos Szerediab974562005-04-07 15:40:21 +00002028 err = -ENOSYS;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002029 if (f->op.setxattr) {
2030 struct fuse_intr_data d;
2031 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002032 err = f->op.setxattr(path, name, value, size, flags);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002033 fuse_finish_interrupt(f, req, &d);
2034 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002035 free(path);
2036 }
2037 pthread_rwlock_unlock(&f->tree_lock);
2038 reply_err(req, err);
2039}
2040
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002041static int common_getxattr(struct fuse *f, fuse_req_t req, fuse_ino_t ino,
2042 const char *name, char *value, size_t size)
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002043{
2044 int err;
2045 char *path;
2046
2047 err = -ENOENT;
2048 pthread_rwlock_rdlock(&f->tree_lock);
2049 path = get_path(f, ino);
2050 if (path != NULL) {
2051 err = -ENOSYS;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002052 if (f->op.getxattr) {
2053 struct fuse_intr_data d;
2054 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002055 err = f->op.getxattr(path, name, value, size);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002056 fuse_finish_interrupt(f, req, &d);
2057 }
Miklos Szerediab974562005-04-07 15:40:21 +00002058 free(path);
2059 }
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00002060 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szerediab974562005-04-07 15:40:21 +00002061 return err;
2062}
2063
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002064static void fuse_getxattr(fuse_req_t req, fuse_ino_t ino, const char *name,
2065 size_t size)
Miklos Szeredi3ead28e2005-01-18 21:23:41 +00002066{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002067 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredi4283ee72005-03-21 12:09:04 +00002068 int res;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002069
2070 if (size) {
2071 char *value = (char *) malloc(size);
2072 if (value == NULL) {
2073 reply_err(req, -ENOMEM);
2074 return;
2075 }
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002076 res = common_getxattr(f, req, ino, name, value, size);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002077 if (res > 0)
2078 fuse_reply_buf(req, value, res);
2079 else
2080 reply_err(req, res);
2081 free(value);
2082 } else {
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002083 res = common_getxattr(f, req, ino, name, NULL, 0);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002084 if (res >= 0)
2085 fuse_reply_xattr(req, res);
2086 else
2087 reply_err(req, res);
2088 }
2089}
2090
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002091static int common_listxattr(struct fuse *f, fuse_req_t req, fuse_ino_t ino,
2092 char *list, size_t size)
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002093{
Miklos Szeredi4283ee72005-03-21 12:09:04 +00002094 char *path;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002095 int err;
Miklos Szeredi4283ee72005-03-21 12:09:04 +00002096
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002097 err = -ENOENT;
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00002098 pthread_rwlock_rdlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002099 path = get_path(f, ino);
Miklos Szeredi4283ee72005-03-21 12:09:04 +00002100 if (path != NULL) {
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002101 err = -ENOSYS;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002102 if (f->op.listxattr) {
2103 struct fuse_intr_data d;
2104 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002105 err = f->op.listxattr(path, list, size);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002106 fuse_finish_interrupt(f, req, &d);
2107 }
Miklos Szeredi4283ee72005-03-21 12:09:04 +00002108 free(path);
2109 }
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00002110 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002111 return err;
Miklos Szeredi4283ee72005-03-21 12:09:04 +00002112}
Miklos Szeredi3ead28e2005-01-18 21:23:41 +00002113
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002114static void fuse_listxattr(fuse_req_t req, fuse_ino_t ino, size_t size)
Miklos Szeredi43696432001-11-18 19:15:05 +00002115{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002116 struct fuse *f = req_fuse_prepare(req);
2117 int res;
2118
2119 if (size) {
2120 char *list = (char *) malloc(size);
2121 if (list == NULL) {
2122 reply_err(req, -ENOMEM);
2123 return;
2124 }
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002125 res = common_listxattr(f, req, ino, list, size);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002126 if (res > 0)
2127 fuse_reply_buf(req, list, res);
2128 else
2129 reply_err(req, res);
2130 free(list);
2131 } else {
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002132 res = common_listxattr(f, req, ino, NULL, 0);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002133 if (res >= 0)
2134 fuse_reply_xattr(req, res);
2135 else
2136 reply_err(req, res);
2137 }
Miklos Szeredi43696432001-11-18 19:15:05 +00002138}
2139
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002140static void fuse_removexattr(fuse_req_t req, fuse_ino_t ino, const char *name)
2141{
2142 struct fuse *f = req_fuse_prepare(req);
2143 char *path;
2144 int err;
2145
2146 err = -ENOENT;
2147 pthread_rwlock_rdlock(&f->tree_lock);
2148 path = get_path(f, ino);
2149 if (path != NULL) {
2150 err = -ENOSYS;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002151 if (f->op.removexattr) {
2152 struct fuse_intr_data d;
2153 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002154 err = f->op.removexattr(path, name);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002155 fuse_finish_interrupt(f, req, &d);
2156 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002157 free(path);
2158 }
2159 pthread_rwlock_unlock(&f->tree_lock);
2160 reply_err(req, err);
2161}
2162
Miklos Szeredi0c59ebf2006-09-10 20:53:36 +00002163static struct lock *locks_conflict(struct node *node, const struct lock *lock)
2164{
2165 struct lock *l;
2166
2167 for (l = node->locks; l; l = l->next)
2168 if (l->owner != lock->owner &&
2169 lock->start <= l->end && l->start <= lock->end &&
2170 (l->type == F_WRLCK || lock->type == F_WRLCK))
2171 break;
2172
2173 return l;
2174}
2175
2176static void delete_lock(struct lock **lockp)
2177{
2178 struct lock *l = *lockp;
2179 *lockp = l->next;
2180 free(l);
2181}
2182
2183static void insert_lock(struct lock **pos, struct lock *lock)
2184{
2185 lock->next = *pos;
2186 *pos = lock;
2187}
2188
2189static int locks_insert(struct node *node, struct lock *lock)
2190{
2191 struct lock **lp;
2192 struct lock *newl1 = NULL;
2193 struct lock *newl2 = NULL;
2194
2195 if (lock->type != F_UNLCK || lock->start != 0 || lock->end != OFFSET_MAX) {
2196 newl1 = malloc(sizeof(struct lock));
2197 newl2 = malloc(sizeof(struct lock));
2198
2199 if (!newl1 || !newl2) {
2200 free(newl1);
2201 free(newl2);
2202 return -ENOLCK;
2203 }
2204 }
2205
2206 for (lp = &node->locks; *lp;) {
2207 struct lock *l = *lp;
2208 if (l->owner != lock->owner)
2209 goto skip;
2210
2211 if (lock->type == l->type) {
2212 if (l->end < lock->start - 1)
2213 goto skip;
2214 if (lock->end < l->start - 1)
2215 break;
2216 if (l->start <= lock->start && lock->end <= l->end)
2217 goto out;
2218 if (l->start < lock->start)
2219 lock->start = l->start;
2220 if (lock->end < l->end)
2221 lock->end = l->end;
2222 goto delete;
2223 } else {
2224 if (l->end < lock->start)
2225 goto skip;
2226 if (lock->end < l->start)
2227 break;
2228 if (lock->start <= l->start && l->end <= lock->end)
2229 goto delete;
2230 if (l->end <= lock->end) {
2231 l->end = lock->start - 1;
2232 goto skip;
2233 }
2234 if (lock->start <= l->start) {
2235 l->start = lock->end + 1;
2236 break;
2237 }
2238 *newl2 = *l;
2239 newl2->start = lock->end + 1;
2240 l->end = lock->start - 1;
2241 insert_lock(&l->next, newl2);
2242 newl2 = NULL;
2243 }
2244 skip:
2245 lp = &l->next;
2246 continue;
2247
2248 delete:
2249 delete_lock(lp);
2250 }
2251 if (lock->type != F_UNLCK) {
2252 *newl1 = *lock;
2253 insert_lock(lp, newl1);
2254 newl1 = NULL;
2255 }
2256out:
2257 free(newl1);
2258 free(newl2);
2259 return 0;
2260}
2261
2262static void flock_to_lock(struct flock *flock, struct lock *lock)
2263{
2264 memset(lock, 0, sizeof(struct lock));
2265 lock->type = flock->l_type;
2266 lock->start = flock->l_start;
2267 lock->end = flock->l_len ? flock->l_start + flock->l_len - 1 : OFFSET_MAX;
2268 lock->pid = flock->l_pid;
2269}
2270
2271static void lock_to_flock(struct lock *lock, struct flock *flock)
2272{
2273 flock->l_type = lock->type;
2274 flock->l_start = lock->start;
2275 flock->l_len = (lock->end == OFFSET_MAX) ? 0 : lock->end - lock->start + 1;
2276 flock->l_pid = lock->pid;
2277}
2278
2279static void fuse_flush(fuse_req_t req, fuse_ino_t ino,
Miklos Szeredi07407852006-09-30 20:03:52 +00002280 struct fuse_file_info *fi)
Miklos Szeredi0c59ebf2006-09-10 20:53:36 +00002281{
2282 struct fuse *f = req_fuse_prepare(req);
2283 char *path;
2284 int err;
2285
2286 err = -ENOENT;
2287 pthread_rwlock_rdlock(&f->tree_lock);
2288 path = get_path(f, ino);
2289 if (path != NULL) {
2290 if (f->conf.debug) {
2291 printf("FLUSH[%llu]\n", (unsigned long long) fi->fh);
2292 fflush(stdout);
2293 }
2294 err = -ENOSYS;
Miklos Szeredi4fca4322006-10-01 14:41:04 +00002295 if (f->op.flush)
2296 err = fuse_do_flush(f, req, path, fi);
Miklos Szeredi0c59ebf2006-09-10 20:53:36 +00002297 free(path);
2298 }
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 }
2316 pthread_rwlock_unlock(&f->tree_lock);
2317 reply_err(req, err);
2318}
2319
Miklos Szeredi9a5c11d2006-07-30 17:33:40 +00002320static int fuse_lock_common(fuse_req_t req, fuse_ino_t ino,
2321 struct fuse_file_info *fi, struct flock *lock,
Miklos Szeredi07407852006-09-30 20:03:52 +00002322 int cmd)
Miklos Szeredi9a5c11d2006-07-30 17:33:40 +00002323{
2324 struct fuse *f = req_fuse_prepare(req);
2325 char *path;
2326 int err;
2327
2328 err = -ENOENT;
2329 pthread_rwlock_rdlock(&f->tree_lock);
2330 path = get_path(f, ino);
2331 if (path != NULL) {
Miklos Szeredi07407852006-09-30 20:03:52 +00002332 err = fuse_do_lock(f, req, path, fi, cmd, lock);
Miklos Szeredi9a5c11d2006-07-30 17:33:40 +00002333 free(path);
2334 }
2335 pthread_rwlock_unlock(&f->tree_lock);
2336 return err;
2337}
2338
2339static void fuse_getlk(fuse_req_t req, fuse_ino_t ino,
Miklos Szeredi07407852006-09-30 20:03:52 +00002340 struct fuse_file_info *fi, struct flock *lock)
Miklos Szeredi9a5c11d2006-07-30 17:33:40 +00002341{
Miklos Szeredi0c59ebf2006-09-10 20:53:36 +00002342 int err;
2343 struct lock l;
2344 struct lock *conflict;
2345 struct fuse *f = req_fuse(req);
2346
2347 flock_to_lock(lock, &l);
Miklos Szeredi07407852006-09-30 20:03:52 +00002348 l.owner = fi->lock_owner;
Miklos Szeredi0c59ebf2006-09-10 20:53:36 +00002349 pthread_mutex_lock(&f->lock);
2350 conflict = locks_conflict(get_node(f, ino), &l);
2351 if (conflict)
2352 lock_to_flock(conflict, lock);
2353 pthread_mutex_unlock(&f->lock);
2354 if (!conflict)
Miklos Szeredi07407852006-09-30 20:03:52 +00002355 err = fuse_lock_common(req, ino, fi, lock, F_GETLK);
Miklos Szeredi0c59ebf2006-09-10 20:53:36 +00002356 else
2357 err = 0;
2358
Miklos Szeredi9a5c11d2006-07-30 17:33:40 +00002359 if (!err)
2360 fuse_reply_lock(req, lock);
2361 else
2362 reply_err(req, err);
2363}
2364
2365static void fuse_setlk(fuse_req_t req, fuse_ino_t ino,
2366 struct fuse_file_info *fi, struct flock *lock,
Miklos Szeredi07407852006-09-30 20:03:52 +00002367 int sleep)
Miklos Szeredi9a5c11d2006-07-30 17:33:40 +00002368{
Miklos Szeredi07407852006-09-30 20:03:52 +00002369 int err = fuse_lock_common(req, ino, fi, lock, sleep ? F_SETLKW : F_SETLK);
Miklos Szeredi0c59ebf2006-09-10 20:53:36 +00002370 if (!err) {
2371 struct fuse *f = req_fuse(req);
2372 struct lock l;
2373 flock_to_lock(lock, &l);
Miklos Szeredi07407852006-09-30 20:03:52 +00002374 l.owner = fi->lock_owner;
Miklos Szeredi0c59ebf2006-09-10 20:53:36 +00002375 pthread_mutex_lock(&f->lock);
2376 locks_insert(get_node(f, ino), &l);
2377 pthread_mutex_unlock(&f->lock);
2378 }
2379 reply_err(req, err);
Miklos Szeredi9a5c11d2006-07-30 17:33:40 +00002380}
2381
Miklos Szeredi708b4812006-09-30 16:02:25 +00002382static void fuse_bmap(fuse_req_t req, fuse_ino_t ino, size_t blocksize,
2383 uint64_t idx)
2384{
2385 struct fuse *f = req_fuse_prepare(req);
2386 char *path;
2387 int err;
2388
2389 err = -ENOENT;
2390 pthread_rwlock_rdlock(&f->tree_lock);
2391 path = get_path(f, ino);
2392 if (path != NULL) {
2393 err = -ENOSYS;
2394 if (f->op.bmap)
2395 err = f->op.bmap(path, blocksize, &idx);
2396 free(path);
2397 }
2398 pthread_rwlock_unlock(&f->tree_lock);
2399 if (!err)
2400 fuse_reply_bmap(req, idx);
2401 else
2402 reply_err(req, err);
2403}
2404
Miklos Szeredia1482422005-08-14 23:00:27 +00002405static struct fuse_lowlevel_ops fuse_path_ops = {
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002406 .init = fuse_data_init,
2407 .destroy = fuse_data_destroy,
2408 .lookup = fuse_lookup,
2409 .forget = fuse_forget,
2410 .getattr = fuse_getattr,
2411 .setattr = fuse_setattr,
Miklos Szeredib0b13d12005-10-26 12:53:25 +00002412 .access = fuse_access,
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002413 .readlink = fuse_readlink,
2414 .mknod = fuse_mknod,
2415 .mkdir = fuse_mkdir,
2416 .unlink = fuse_unlink,
2417 .rmdir = fuse_rmdir,
2418 .symlink = fuse_symlink,
2419 .rename = fuse_rename,
2420 .link = fuse_link,
Miklos Szeredid9079a72005-10-26 15:29:06 +00002421 .create = fuse_create,
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002422 .open = fuse_open,
2423 .read = fuse_read,
2424 .write = fuse_write,
2425 .flush = fuse_flush,
2426 .release = fuse_release,
2427 .fsync = fuse_fsync,
2428 .opendir = fuse_opendir,
2429 .readdir = fuse_readdir,
2430 .releasedir = fuse_releasedir,
2431 .fsyncdir = fuse_fsyncdir,
2432 .statfs = fuse_statfs,
2433 .setxattr = fuse_setxattr,
2434 .getxattr = fuse_getxattr,
2435 .listxattr = fuse_listxattr,
2436 .removexattr = fuse_removexattr,
Miklos Szeredi9a5c11d2006-07-30 17:33:40 +00002437 .getlk = fuse_getlk,
2438 .setlk = fuse_setlk,
Miklos Szeredi708b4812006-09-30 16:02:25 +00002439 .bmap = fuse_bmap,
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002440};
2441
Miklos Szeredia1482422005-08-14 23:00:27 +00002442static void free_cmd(struct fuse_cmd *cmd)
2443{
2444 free(cmd->buf);
2445 free(cmd);
2446}
2447
Miklos Szeredif458b8c2004-12-07 16:46:42 +00002448void fuse_process_cmd(struct fuse *f, struct fuse_cmd *cmd)
Miklos Szeredia181e612001-11-06 12:03:23 +00002449{
Miklos Szeredi178451d2005-08-15 13:19:07 +00002450 fuse_session_process(f->se, cmd->buf, cmd->buflen, cmd->ch);
Miklos Szeredifa829b52005-12-02 11:05:41 +00002451 free_cmd(cmd);
Miklos Szeredia181e612001-11-06 12:03:23 +00002452}
2453
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002454int fuse_exited(struct fuse *f)
Miklos Szeredi65cf7c72004-06-30 11:34:56 +00002455{
Miklos Szeredia1482422005-08-14 23:00:27 +00002456 return fuse_session_exited(f->se);
2457}
2458
2459struct fuse_session *fuse_get_session(struct fuse *f)
2460{
2461 return f->se;
2462}
2463
2464static struct fuse_cmd *fuse_alloc_cmd(size_t bufsize)
2465{
2466 struct fuse_cmd *cmd = (struct fuse_cmd *) malloc(sizeof(*cmd));
2467 if (cmd == NULL) {
2468 fprintf(stderr, "fuse: failed to allocate cmd\n");
2469 return NULL;
2470 }
2471 cmd->buf = (char *) malloc(bufsize);
2472 if (cmd->buf == NULL) {
2473 fprintf(stderr, "fuse: failed to allocate read buffer\n");
2474 free(cmd);
2475 return NULL;
2476 }
2477 return cmd;
Miklos Szeredi65cf7c72004-06-30 11:34:56 +00002478}
2479
Miklos Szeredif458b8c2004-12-07 16:46:42 +00002480struct fuse_cmd *fuse_read_cmd(struct fuse *f)
Miklos Szeredi2df1c042001-11-06 15:07:17 +00002481{
Miklos Szeredia1482422005-08-14 23:00:27 +00002482 struct fuse_chan *ch = fuse_session_next_chan(f->se, NULL);
2483 size_t bufsize = fuse_chan_bufsize(ch);
2484 struct fuse_cmd *cmd = fuse_alloc_cmd(bufsize);
2485 if (cmd != NULL) {
Miklos Szeredi8d975f62006-03-17 15:56:05 +00002486 int res = fuse_chan_recv(&ch, cmd->buf, bufsize);
Miklos Szeredia1482422005-08-14 23:00:27 +00002487 if (res <= 0) {
2488 free_cmd(cmd);
Miklos Szeredi5d9ce362006-03-01 12:10:13 +00002489 if (res < 0 && res != -EINTR && res != -EAGAIN)
Miklos Szeredifa829b52005-12-02 11:05:41 +00002490 fuse_exit(f);
Miklos Szeredia1482422005-08-14 23:00:27 +00002491 return NULL;
2492 }
2493 cmd->buflen = res;
Miklos Szeredi178451d2005-08-15 13:19:07 +00002494 cmd->ch = ch;
Miklos Szeredia1482422005-08-14 23:00:27 +00002495 }
2496 return cmd;
Miklos Szeredi2df1c042001-11-06 15:07:17 +00002497}
2498
Miklos Szeredib2cf9562004-09-16 08:42:40 +00002499int fuse_loop(struct fuse *f)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00002500{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002501 if (f)
Miklos Szeredia1482422005-08-14 23:00:27 +00002502 return fuse_session_loop(f->se);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002503 else
Miklos Szeredib2cf9562004-09-16 08:42:40 +00002504 return -1;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00002505}
2506
Miklos Szeredi891b8742004-07-29 09:27:49 +00002507int fuse_invalidate(struct fuse *f, const char *path)
2508{
Miklos Szeredie56818b2004-12-12 11:45:24 +00002509 (void) f;
2510 (void) path;
2511 return -EINVAL;
Miklos Szeredi891b8742004-07-29 09:27:49 +00002512}
2513
Miklos Szeredi0f48a262002-12-05 14:23:01 +00002514void fuse_exit(struct fuse *f)
2515{
Miklos Szeredia1482422005-08-14 23:00:27 +00002516 fuse_session_exit(f->se);
Miklos Szeredi0f48a262002-12-05 14:23:01 +00002517}
2518
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002519struct fuse_context *fuse_get_context(void)
Miklos Szeredi2e50d432001-12-20 12:17:25 +00002520{
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002521 return &fuse_get_context_internal()->ctx;
2522}
2523
2524int fuse_interrupted(void)
2525{
2526 return fuse_req_interrupted(fuse_get_context_internal()->req);
Miklos Szeredid169f312004-09-22 08:48:26 +00002527}
2528
Miklos Szeredif458b8c2004-12-07 16:46:42 +00002529void fuse_set_getcontext_func(struct fuse_context *(*func)(void))
Miklos Szeredid169f312004-09-22 08:48:26 +00002530{
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002531 (void) func;
2532 /* no-op */
Miklos Szeredi2e50d432001-12-20 12:17:25 +00002533}
2534
Miklos Szerediad005972006-01-07 10:14:34 +00002535enum {
2536 KEY_HELP,
Miklos Szerediad005972006-01-07 10:14:34 +00002537};
2538
Miklos Szeredi659743b2005-12-09 17:41:42 +00002539#define FUSE_LIB_OPT(t, p, v) { t, offsetof(struct fuse_config, p), v }
2540
2541static const struct fuse_opt fuse_lib_opts[] = {
Miklos Szerediad005972006-01-07 10:14:34 +00002542 FUSE_OPT_KEY("-h", KEY_HELP),
2543 FUSE_OPT_KEY("--help", KEY_HELP),
Miklos Szeredi065f2222006-01-20 15:15:21 +00002544 FUSE_OPT_KEY("debug", FUSE_OPT_KEY_KEEP),
2545 FUSE_OPT_KEY("-d", FUSE_OPT_KEY_KEEP),
Miklos Szeredi659743b2005-12-09 17:41:42 +00002546 FUSE_LIB_OPT("debug", debug, 1),
Miklos Szeredi95da8602006-01-06 18:29:40 +00002547 FUSE_LIB_OPT("-d", debug, 1),
Miklos Szeredi659743b2005-12-09 17:41:42 +00002548 FUSE_LIB_OPT("hard_remove", hard_remove, 1),
2549 FUSE_LIB_OPT("use_ino", use_ino, 1),
2550 FUSE_LIB_OPT("readdir_ino", readdir_ino, 1),
2551 FUSE_LIB_OPT("direct_io", direct_io, 1),
2552 FUSE_LIB_OPT("kernel_cache", kernel_cache, 1),
Miklos Szeredi320abe42006-01-30 18:14:51 +00002553 FUSE_LIB_OPT("auto_cache", auto_cache, 1),
2554 FUSE_LIB_OPT("noauto_cache", auto_cache, 0),
Miklos Szeredi659743b2005-12-09 17:41:42 +00002555 FUSE_LIB_OPT("umask=", set_mode, 1),
2556 FUSE_LIB_OPT("umask=%o", umask, 0),
2557 FUSE_LIB_OPT("uid=", set_uid, 1),
2558 FUSE_LIB_OPT("uid=%d", uid, 0),
2559 FUSE_LIB_OPT("gid=", set_gid, 1),
2560 FUSE_LIB_OPT("gid=%d", gid, 0),
2561 FUSE_LIB_OPT("entry_timeout=%lf", entry_timeout, 0),
2562 FUSE_LIB_OPT("attr_timeout=%lf", attr_timeout, 0),
Miklos Szeredi6e806e92006-02-16 16:59:39 +00002563 FUSE_LIB_OPT("ac_attr_timeout=%lf", ac_attr_timeout, 0),
2564 FUSE_LIB_OPT("ac_attr_timeout=", ac_attr_timeout_set, 1),
Miklos Szeredi659743b2005-12-09 17:41:42 +00002565 FUSE_LIB_OPT("negative_timeout=%lf", negative_timeout, 0),
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002566 FUSE_LIB_OPT("intr", intr, 1),
2567 FUSE_LIB_OPT("intr_signal=%d", intr_signal, 0),
Miklos Szeredi659743b2005-12-09 17:41:42 +00002568 FUSE_OPT_END
2569};
2570
Miklos Szerediad005972006-01-07 10:14:34 +00002571static void fuse_lib_help(void)
2572{
2573 fprintf(stderr,
Miklos Szeredi06091462006-02-16 16:38:34 +00002574" -o hard_remove immediate removal (don't hide files)\n"
2575" -o use_ino let filesystem set inode numbers\n"
2576" -o readdir_ino try to fill in d_ino in readdir\n"
2577" -o direct_io use direct I/O\n"
2578" -o kernel_cache cache files in kernel\n"
2579" -o [no]auto_cache enable caching based on modification times\n"
2580" -o umask=M set file permissions (octal)\n"
2581" -o uid=N set file owner\n"
2582" -o gid=N set file group\n"
2583" -o entry_timeout=T cache timeout for names (1.0s)\n"
2584" -o negative_timeout=T cache timeout for deleted names (0.0s)\n"
Miklos Szeredi6e806e92006-02-16 16:59:39 +00002585" -o attr_timeout=T cache timeout for attributes (1.0s)\n"
2586" -o ac_attr_timeout=T auto cache timeout for attributes (attr_timeout)\n"
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002587" -o intr allow requests to be interrupted\n"
2588" -o intr_signal=NUM signal to send on interrupt (%i)\n"
2589"\n", FUSE_DEFAULT_INTR_SIGNAL);
Miklos Szerediad005972006-01-07 10:14:34 +00002590}
2591
2592static int fuse_lib_opt_proc(void *data, const char *arg, int key,
2593 struct fuse_args *outargs)
2594{
2595 (void) data; (void) arg; (void) outargs;
2596
2597 if (key == KEY_HELP)
2598 fuse_lib_help();
2599
2600 return 1;
2601}
2602
2603
Miklos Szeredibd7661b2004-07-23 17:16:29 +00002604int fuse_is_lib_option(const char *opt)
2605{
Miklos Szeredi659743b2005-12-09 17:41:42 +00002606 return fuse_lowlevel_is_lib_option(opt) ||
2607 fuse_opt_match(fuse_lib_opts, opt);
Miklos Szeredibd7661b2004-07-23 17:16:29 +00002608}
2609
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002610static int fuse_init_intr_signal(int signum, int *installed)
2611{
2612 struct sigaction old_sa;
2613
2614 if (sigaction(signum, NULL, &old_sa) == -1) {
2615 perror("fuse: cannot get old signal handler");
2616 return -1;
2617 }
2618
2619 if (old_sa.sa_handler == SIG_DFL) {
2620 struct sigaction sa;
2621
2622 memset(&sa, 0, sizeof(struct sigaction));
2623 sa.sa_handler = fuse_intr_sighandler;
Miklos Szeredi0c59ebf2006-09-10 20:53:36 +00002624 sigemptyset(&sa.sa_mask);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002625
2626 if (sigaction(signum, &sa, NULL) == -1) {
2627 perror("fuse: cannot set interrupt signal handler");
2628 return -1;
2629 }
2630 *installed = 1;
2631 }
2632 return 0;
2633}
2634
Miklos Szeredi349bdda2006-09-07 11:48:16 +00002635static void fuse_restore_intr_signal(int signum)
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002636{
Miklos Szeredi349bdda2006-09-07 11:48:16 +00002637 struct sigaction sa;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002638
Miklos Szeredi349bdda2006-09-07 11:48:16 +00002639 memset(&sa, 0, sizeof(struct sigaction));
2640 sa.sa_handler = SIG_DFL;
2641 sigaction(signum, &sa, NULL);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002642}
2643
Miklos Szeredi6f385412006-03-17 15:05:40 +00002644struct fuse *fuse_new_common(struct fuse_chan *ch, struct fuse_args *args,
Miklos Szeredi0b6a0ad2004-12-04 00:40:50 +00002645 const struct fuse_operations *op,
Miklos Szeredi6f385412006-03-17 15:05:40 +00002646 size_t op_size, void *user_data, int compat)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00002647{
Miklos Szeredi97c61e92001-11-07 12:09:43 +00002648 struct fuse *f;
2649 struct node *root;
Miklos Szeredi9a5c11d2006-07-30 17:33:40 +00002650 struct fuse_lowlevel_ops llop = fuse_path_ops;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00002651
Miklos Szeredi0f62d722005-01-04 12:45:54 +00002652 if (sizeof(struct fuse_operations) < op_size) {
Miklos Szeredi0b6a0ad2004-12-04 00:40:50 +00002653 fprintf(stderr, "fuse: warning: library too old, some operations may not not work\n");
Miklos Szeredi0f62d722005-01-04 12:45:54 +00002654 op_size = sizeof(struct fuse_operations);
Miklos Szeredi0b6a0ad2004-12-04 00:40:50 +00002655 }
2656
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002657 if (fuse_create_context_key() == -1)
2658 goto out;
2659
Miklos Szeredi97c61e92001-11-07 12:09:43 +00002660 f = (struct fuse *) calloc(1, sizeof(struct fuse));
Miklos Szeredie56818b2004-12-12 11:45:24 +00002661 if (f == NULL) {
2662 fprintf(stderr, "fuse: failed to allocate fuse object\n");
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002663 goto out_delete_context_key;
Miklos Szeredie56818b2004-12-12 11:45:24 +00002664 }
Miklos Szeredi2df1c042001-11-06 15:07:17 +00002665
Miklos Szeredi6f385412006-03-17 15:05:40 +00002666 f->user_data = user_data;
Miklos Szeredi659743b2005-12-09 17:41:42 +00002667 f->conf.entry_timeout = 1.0;
2668 f->conf.attr_timeout = 1.0;
2669 f->conf.negative_timeout = 0.0;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002670 f->conf.intr_signal = FUSE_DEFAULT_INTR_SIGNAL;
Miklos Szeredi6c0209a2005-08-02 13:31:28 +00002671
Miklos Szerediad005972006-01-07 10:14:34 +00002672 if (fuse_opt_parse(args, &f->conf, fuse_lib_opts, fuse_lib_opt_proc) == -1)
Miklos Szeredi659743b2005-12-09 17:41:42 +00002673 goto out_free;
Miklos Szeredib2cf9562004-09-16 08:42:40 +00002674
Miklos Szeredi6e806e92006-02-16 16:59:39 +00002675 if (!f->conf.ac_attr_timeout_set)
2676 f->conf.ac_attr_timeout = f->conf.attr_timeout;
2677
Miklos Szeredi659743b2005-12-09 17:41:42 +00002678#ifdef __FreeBSD__
2679 /*
2680 * In FreeBSD, we always use these settings as inode numbers are needed to
2681 * make getcwd(3) work.
2682 */
Miklos Szeredi76fc3de2005-12-12 09:34:45 +00002683 f->conf.readdir_ino = 1;
Miklos Szeredi659743b2005-12-09 17:41:42 +00002684#endif
2685
Miklos Szeredi065f2222006-01-20 15:15:21 +00002686 if (compat && compat <= 25) {
2687 if (fuse_sync_compat_args(args) == -1)
2688 goto out_free;
2689 }
2690
Miklos Szeredi9a5c11d2006-07-30 17:33:40 +00002691 memcpy(&f->op, op, op_size);
2692 if (!f->op.lock) {
2693 llop.getlk = NULL;
2694 llop.setlk = NULL;
2695 }
2696
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002697 f->se = fuse_lowlevel_new_common(args, &llop, sizeof(llop), f);
Miklos Szeredia1482422005-08-14 23:00:27 +00002698 if (f->se == NULL)
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002699 goto out_free;
Miklos Szeredi2bb750e2005-10-03 14:54:24 +00002700
Miklos Szeredia1482422005-08-14 23:00:27 +00002701 fuse_session_add_chan(f->se, ch);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002702
Miklos Szeredi97c61e92001-11-07 12:09:43 +00002703 f->ctr = 0;
Miklos Szeredi76f65782004-02-19 16:55:40 +00002704 f->generation = 0;
Miklos Szeredifff56ab2001-11-16 10:12:59 +00002705 /* FIXME: Dynamic hash table */
Miklos Szeredi97c61e92001-11-07 12:09:43 +00002706 f->name_table_size = 14057;
2707 f->name_table = (struct node **)
2708 calloc(1, sizeof(struct node *) * f->name_table_size);
Miklos Szeredie56818b2004-12-12 11:45:24 +00002709 if (f->name_table == NULL) {
2710 fprintf(stderr, "fuse: memory allocation failed\n");
Miklos Szeredia1482422005-08-14 23:00:27 +00002711 goto out_free_session;
Miklos Szeredie56818b2004-12-12 11:45:24 +00002712 }
Miklos Szeredib2cf9562004-09-16 08:42:40 +00002713
Miklos Szeredia13d9002004-11-02 17:32:03 +00002714 f->id_table_size = 14057;
2715 f->id_table = (struct node **)
2716 calloc(1, sizeof(struct node *) * f->id_table_size);
Miklos Szeredie56818b2004-12-12 11:45:24 +00002717 if (f->id_table == NULL) {
2718 fprintf(stderr, "fuse: memory allocation failed\n");
Miklos Szeredib2cf9562004-09-16 08:42:40 +00002719 goto out_free_name_table;
Miklos Szeredie56818b2004-12-12 11:45:24 +00002720 }
Miklos Szeredib2cf9562004-09-16 08:42:40 +00002721
Miklos Szeredi38f152c2006-09-03 18:28:52 +00002722 fuse_mutex_init(&f->lock);
Miklos Szeredid0a777a2006-04-05 07:18:00 +00002723 pthread_rwlock_init(&f->tree_lock, NULL);
Miklos Szeredi0b6a0ad2004-12-04 00:40:50 +00002724 f->compat = compat;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00002725
Miklos Szeredi97c61e92001-11-07 12:09:43 +00002726 root = (struct node *) calloc(1, sizeof(struct node));
Miklos Szeredie56818b2004-12-12 11:45:24 +00002727 if (root == NULL) {
2728 fprintf(stderr, "fuse: memory allocation failed\n");
Miklos Szeredia13d9002004-11-02 17:32:03 +00002729 goto out_free_id_table;
Miklos Szeredie56818b2004-12-12 11:45:24 +00002730 }
Miklos Szeredib2cf9562004-09-16 08:42:40 +00002731
Miklos Szeredi97c61e92001-11-07 12:09:43 +00002732 root->name = strdup("/");
Miklos Szeredie56818b2004-12-12 11:45:24 +00002733 if (root->name == NULL) {
2734 fprintf(stderr, "fuse: memory allocation failed\n");
Miklos Szeredib2cf9562004-09-16 08:42:40 +00002735 goto out_free_root;
Miklos Szeredie56818b2004-12-12 11:45:24 +00002736 }
Miklos Szeredib2cf9562004-09-16 08:42:40 +00002737
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002738 if (f->conf.intr &&
2739 fuse_init_intr_signal(f->conf.intr_signal, &f->intr_installed) == -1)
2740 goto out_free_root_name;
2741
Miklos Szeredi97c61e92001-11-07 12:09:43 +00002742 root->parent = 0;
Miklos Szeredia13d9002004-11-02 17:32:03 +00002743 root->nodeid = FUSE_ROOT_ID;
Miklos Szeredi76f65782004-02-19 16:55:40 +00002744 root->generation = 0;
Miklos Szeredi0f62d722005-01-04 12:45:54 +00002745 root->refctr = 1;
Miklos Szeredi38009022005-05-08 19:47:22 +00002746 root->nlookup = 1;
Miklos Szeredia13d9002004-11-02 17:32:03 +00002747 hash_id(f, root);
Miklos Szeredi97c61e92001-11-07 12:09:43 +00002748
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00002749 return f;
Miklos Szeredib2cf9562004-09-16 08:42:40 +00002750
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002751 out_free_root_name:
2752 free(root->name);
Miklos Szeredib2cf9562004-09-16 08:42:40 +00002753 out_free_root:
2754 free(root);
Miklos Szeredia13d9002004-11-02 17:32:03 +00002755 out_free_id_table:
2756 free(f->id_table);
Miklos Szeredib2cf9562004-09-16 08:42:40 +00002757 out_free_name_table:
2758 free(f->name_table);
Miklos Szeredia1482422005-08-14 23:00:27 +00002759 out_free_session:
2760 fuse_session_destroy(f->se);
Miklos Szeredib2cf9562004-09-16 08:42:40 +00002761 out_free:
2762 free(f);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002763 out_delete_context_key:
2764 fuse_delete_context_key();
Miklos Szeredib2cf9562004-09-16 08:42:40 +00002765 out:
Miklos Szeredib2cf9562004-09-16 08:42:40 +00002766 return NULL;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00002767}
2768
Miklos Szeredi6f385412006-03-17 15:05:40 +00002769struct fuse *fuse_new(struct fuse_chan *ch, struct fuse_args *args,
2770 const struct fuse_operations *op, size_t op_size,
2771 void *user_data)
Miklos Szeredi0b6a0ad2004-12-04 00:40:50 +00002772{
Miklos Szeredi6f385412006-03-17 15:05:40 +00002773 return fuse_new_common(ch, args, op, op_size, user_data, 0);
Miklos Szeredi0b6a0ad2004-12-04 00:40:50 +00002774}
2775
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00002776void fuse_destroy(struct fuse *f)
2777{
Miklos Szeredi97c61e92001-11-07 12:09:43 +00002778 size_t i;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002779 struct fuse_context_i *c = fuse_get_context_internal();
2780
2781 if (f->conf.intr && f->intr_installed)
2782 fuse_restore_intr_signal(f->conf.intr_signal);
Miklos Szerediad519562006-07-31 11:07:40 +00002783
2784 memset(c, 0, sizeof(*c));
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002785 c->ctx.fuse = f;
2786 c->ctx.private_data = f->user_data;
Miklos Szerediad519562006-07-31 11:07:40 +00002787
Miklos Szeredia13d9002004-11-02 17:32:03 +00002788 for (i = 0; i < f->id_table_size; i++) {
Miklos Szeredi97c61e92001-11-07 12:09:43 +00002789 struct node *node;
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00002790
Miklos Szeredia13d9002004-11-02 17:32:03 +00002791 for (node = f->id_table[i]; node != NULL; node = node->id_next) {
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00002792 if (node->is_hidden) {
Miklos Szeredia13d9002004-11-02 17:32:03 +00002793 char *path = get_path(f, node->nodeid);
Miklos Szeredi21019c92005-05-09 11:22:41 +00002794 if (path) {
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00002795 f->op.unlink(path);
Miklos Szeredi21019c92005-05-09 11:22:41 +00002796 free(path);
2797 }
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00002798 }
2799 }
2800 }
Miklos Szeredia13d9002004-11-02 17:32:03 +00002801 for (i = 0; i < f->id_table_size; i++) {
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00002802 struct node *node;
Miklos Szeredi97c61e92001-11-07 12:09:43 +00002803 struct node *next;
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00002804
Miklos Szeredia13d9002004-11-02 17:32:03 +00002805 for (node = f->id_table[i]; node != NULL; node = next) {
2806 next = node->id_next;
Miklos Szeredi97c61e92001-11-07 12:09:43 +00002807 free_node(node);
2808 }
2809 }
Miklos Szeredia13d9002004-11-02 17:32:03 +00002810 free(f->id_table);
Miklos Szeredi97c61e92001-11-07 12:09:43 +00002811 free(f->name_table);
Miklos Szeredia181e612001-11-06 12:03:23 +00002812 pthread_mutex_destroy(&f->lock);
Miklos Szeredi55a84102006-06-06 10:16:38 +00002813 pthread_rwlock_destroy(&f->tree_lock);
Miklos Szeredia1482422005-08-14 23:00:27 +00002814 fuse_session_destroy(f->se);
Miklos Szeredi97c61e92001-11-07 12:09:43 +00002815 free(f);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002816 fuse_delete_context_key();
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00002817}
Miklos Szeredi0b6a0ad2004-12-04 00:40:50 +00002818
Miklos Szeredieafdf422006-09-22 19:30:17 +00002819#include "fuse_common_compat.h"
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002820#include "fuse_compat.h"
2821
Miklos Szeredi6f385412006-03-17 15:05:40 +00002822static struct fuse *fuse_new_common_compat25(int fd, struct fuse_args *args,
2823 const struct fuse_operations *op,
2824 size_t op_size, int compat)
2825{
2826 struct fuse *f = NULL;
2827 struct fuse_chan *ch = fuse_kern_chan_new(fd);
2828
2829 if (ch)
2830 f = fuse_new_common(ch, args, op, op_size, NULL, compat);
2831
2832 return f;
2833}
2834
Miklos Szeredi065f2222006-01-20 15:15:21 +00002835#ifndef __FreeBSD__
2836
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002837static int fuse_compat_open(struct fuse *f, fuse_req_t req, char *path,
2838 struct fuse_file_info *fi)
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002839{
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002840 int err;
2841 struct fuse_intr_data d;
Miklos Szeredi065f2222006-01-20 15:15:21 +00002842 if (!f->compat || f->compat >= 25)
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002843 err = fuse_do_open(f, req, path, fi);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002844 else if (f->compat == 22) {
Miklos Szeredieafdf422006-09-22 19:30:17 +00002845 struct fuse_file_info_compat tmp;
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002846 memcpy(&tmp, fi, sizeof(tmp));
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002847 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002848 err = ((struct fuse_operations_compat22 *) &f->op)->open(path, &tmp);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002849 fuse_finish_interrupt(f, req, &d);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002850 memcpy(fi, &tmp, sizeof(tmp));
2851 fi->fh = tmp.fh;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002852 } else {
2853 fuse_prepare_interrupt(f, req, &d);
2854 err =
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002855 ((struct fuse_operations_compat2 *) &f->op)->open(path, fi->flags);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002856 fuse_finish_interrupt(f, req, &d);
2857 }
2858 return err;
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002859}
2860
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002861static void fuse_compat_release(struct fuse *f, fuse_req_t req, char *path,
2862 struct fuse_file_info *fi)
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002863{
2864 if (!f->compat || f->compat >= 22)
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002865 fuse_do_release(f, req, path ? path : "-", fi);
2866 else if (path) {
2867 struct fuse_intr_data d;
2868 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002869 ((struct fuse_operations_compat2 *) &f->op)->release(path, fi->flags);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002870 fuse_finish_interrupt(f, req, &d);
2871 }
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002872}
2873
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002874static int fuse_compat_opendir(struct fuse *f, fuse_req_t req, char *path,
2875 struct fuse_file_info *fi)
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002876{
Miklos Szeredi065f2222006-01-20 15:15:21 +00002877 if (!f->compat || f->compat >= 25) {
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002878 return fuse_do_opendir(f, req, path, fi);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002879 } else {
2880 int err;
Miklos Szeredieafdf422006-09-22 19:30:17 +00002881 struct fuse_file_info_compat tmp;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002882 struct fuse_intr_data d;
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002883 memcpy(&tmp, fi, sizeof(tmp));
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002884 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002885 err = ((struct fuse_operations_compat22 *) &f->op)->opendir(path, &tmp);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002886 fuse_finish_interrupt(f, req, &d);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002887 memcpy(fi, &tmp, sizeof(tmp));
2888 fi->fh = tmp.fh;
2889 return err;
2890 }
2891}
2892
2893static void convert_statfs_compat(struct fuse_statfs_compat1 *compatbuf,
2894 struct statvfs *stbuf)
2895{
2896 stbuf->f_bsize = compatbuf->block_size;
2897 stbuf->f_blocks = compatbuf->blocks;
2898 stbuf->f_bfree = compatbuf->blocks_free;
2899 stbuf->f_bavail = compatbuf->blocks_free;
2900 stbuf->f_files = compatbuf->files;
2901 stbuf->f_ffree = compatbuf->files_free;
2902 stbuf->f_namemax = compatbuf->namelen;
2903}
2904
2905static void convert_statfs_old(struct statfs *oldbuf, struct statvfs *stbuf)
2906{
2907 stbuf->f_bsize = oldbuf->f_bsize;
2908 stbuf->f_blocks = oldbuf->f_blocks;
2909 stbuf->f_bfree = oldbuf->f_bfree;
2910 stbuf->f_bavail = oldbuf->f_bavail;
2911 stbuf->f_files = oldbuf->f_files;
2912 stbuf->f_ffree = oldbuf->f_ffree;
2913 stbuf->f_namemax = oldbuf->f_namelen;
2914}
2915
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002916static int fuse_compat_statfs(struct fuse *f, fuse_req_t req,
2917 struct statvfs *buf)
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002918{
2919 int err;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002920 struct fuse_intr_data d;
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002921
Miklos Szeredi065f2222006-01-20 15:15:21 +00002922 if (!f->compat || f->compat >= 25) {
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002923 err = fuse_do_statfs(f, req, "/", buf);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002924 } else if (f->compat > 11) {
2925 struct statfs oldbuf;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002926 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002927 err = ((struct fuse_operations_compat22 *) &f->op)->statfs("/", &oldbuf);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002928 fuse_finish_interrupt(f, req, &d);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002929 if (!err)
2930 convert_statfs_old(&oldbuf, buf);
2931 } else {
2932 struct fuse_statfs_compat1 compatbuf;
2933 memset(&compatbuf, 0, sizeof(struct fuse_statfs_compat1));
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002934 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002935 err = ((struct fuse_operations_compat1 *) &f->op)->statfs(&compatbuf);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002936 fuse_finish_interrupt(f, req, &d);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002937 if (!err)
2938 convert_statfs_compat(&compatbuf, buf);
2939 }
2940 return err;
2941}
2942
Miklos Szeredi95da8602006-01-06 18:29:40 +00002943static struct fuse *fuse_new_common_compat(int fd, const char *opts,
2944 const struct fuse_operations *op,
2945 size_t op_size, int compat)
2946{
2947 struct fuse *f;
2948 struct fuse_args args = FUSE_ARGS_INIT(0, NULL);
2949
2950 if (opts &&
2951 (fuse_opt_add_arg(&args, "") == -1 ||
2952 fuse_opt_add_arg(&args, "-o") == -1 ||
2953 fuse_opt_add_arg(&args, opts) == -1)) {
2954 fuse_opt_free_args(&args);
2955 return NULL;
2956 }
Miklos Szeredi6f385412006-03-17 15:05:40 +00002957 f = fuse_new_common_compat25(fd, &args, op, op_size, compat);
Miklos Szeredi95da8602006-01-06 18:29:40 +00002958 fuse_opt_free_args(&args);
2959
2960 return f;
2961}
2962
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002963struct fuse *fuse_new_compat22(int fd, const char *opts,
2964 const struct fuse_operations_compat22 *op,
2965 size_t op_size)
2966{
Miklos Szeredi95da8602006-01-06 18:29:40 +00002967 return fuse_new_common_compat(fd, opts, (struct fuse_operations *) op,
2968 op_size, 22);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002969}
2970
2971struct fuse *fuse_new_compat2(int fd, const char *opts,
2972 const struct fuse_operations_compat2 *op)
2973{
Miklos Szeredi95da8602006-01-06 18:29:40 +00002974 return fuse_new_common_compat(fd, opts, (struct fuse_operations *) op,
2975 sizeof(struct fuse_operations_compat2), 21);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002976}
2977
2978struct fuse *fuse_new_compat1(int fd, int flags,
2979 const struct fuse_operations_compat1 *op)
2980{
2981 const char *opts = NULL;
2982 if (flags & FUSE_DEBUG_COMPAT1)
2983 opts = "debug";
Miklos Szeredi95da8602006-01-06 18:29:40 +00002984 return fuse_new_common_compat(fd, opts, (struct fuse_operations *) op,
2985 sizeof(struct fuse_operations_compat1), 11);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002986}
2987
Miklos Szeredif458b8c2004-12-07 16:46:42 +00002988__asm__(".symver fuse_exited,__fuse_exited@");
2989__asm__(".symver fuse_process_cmd,__fuse_process_cmd@");
2990__asm__(".symver fuse_read_cmd,__fuse_read_cmd@");
2991__asm__(".symver fuse_set_getcontext_func,__fuse_set_getcontext_func@");
2992__asm__(".symver fuse_new_compat2,fuse_new@");
Miklos Szeredi3a770472005-11-11 21:32:42 +00002993__asm__(".symver fuse_new_compat22,fuse_new@FUSE_2.2");
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002994
2995#else /* __FreeBSD__ */
2996
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002997static int fuse_compat_open(struct fuse *f, fuse_req_t req, char *path,
2998 struct fuse_file_info *fi)
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002999{
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00003000 return fuse_do_open(f, req, path, fi);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00003001}
3002
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00003003static void fuse_compat_release(struct fuse *f, fuse_req_t req, char *path,
3004 struct fuse_file_info *fi)
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00003005{
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00003006 fuse_do_release(f, req, path ? path : "-", fi);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00003007}
3008
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00003009static int fuse_compat_opendir(struct fuse *f, fuse_req_t req, char *path,
3010 struct fuse_file_info *fi)
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00003011{
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00003012 return fuse_do_opendir(f, req, path, fi);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00003013}
3014
Csaba Henk3e3a1252006-09-24 14:53:29 +00003015static int fuse_compat_statfs(struct fuse *f, fuse_req_t req, struct statvfs *buf)
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00003016{
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00003017 return fuse_do_statfs(f, req, "/", buf);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00003018}
3019
3020#endif /* __FreeBSD__ */
Miklos Szeredi065f2222006-01-20 15:15:21 +00003021
3022struct fuse *fuse_new_compat25(int fd, struct fuse_args *args,
3023 const struct fuse_operations_compat25 *op,
3024 size_t op_size)
3025{
Miklos Szeredi6f385412006-03-17 15:05:40 +00003026 return fuse_new_common_compat25(fd, args, (struct fuse_operations *) op,
3027 op_size, 25);
Miklos Szeredi065f2222006-01-20 15:15:21 +00003028}
3029
3030__asm__(".symver fuse_new_compat25,fuse_new@FUSE_2.5");