blob: 0e3e1d14c6442f6fcf7f4f527c5ec58214650a12 [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 {
259 f->ctr++;
260 if (!f->ctr)
261 f->generation ++;
262 } while (f->ctr == 0 || get_node_nocheck(f, f->ctr) != NULL);
263 return f->ctr;
264}
265
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000266static struct node *lookup_node(struct fuse *f, fuse_ino_t parent,
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000267 const char *name)
268{
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000269 size_t hash = name_hash(f, parent, name);
270 struct node *node;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000271
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000272 for (node = f->name_table[hash]; node != NULL; node = node->name_next)
273 if (node->parent == parent && strcmp(node->name, name) == 0)
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000274 return node;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000275
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000276 return NULL;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000277}
278
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000279static struct node *find_node(struct fuse *f, fuse_ino_t parent,
280 const char *name)
Miklos Szeredi5e183482001-10-31 14:52:35 +0000281{
282 struct node *node;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000283
Miklos Szeredia181e612001-11-06 12:03:23 +0000284 pthread_mutex_lock(&f->lock);
Miklos Szeredif458b8c2004-12-07 16:46:42 +0000285 node = lookup_node(f, parent, name);
Miklos Szeredie331c4b2005-07-06 13:34:02 +0000286 if (node == NULL) {
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000287 node = (struct node *) calloc(1, sizeof(struct node));
288 if (node == NULL)
289 goto out_err;
Miklos Szeredie5183742005-02-02 11:14:04 +0000290
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000291 node->refctr = 1;
292 node->nodeid = next_id(f);
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000293 node->open_count = 0;
294 node->is_hidden = 0;
295 node->generation = f->generation;
296 if (hash_name(f, node, parent, name) == -1) {
297 free(node);
298 node = NULL;
299 goto out_err;
300 }
301 hash_id(f, node);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000302 }
Miklos Szeredi38009022005-05-08 19:47:22 +0000303 node->nlookup ++;
Miklos Szeredic2309912004-09-21 13:40:38 +0000304 out_err:
Miklos Szeredia181e612001-11-06 12:03:23 +0000305 pthread_mutex_unlock(&f->lock);
Miklos Szeredi76f65782004-02-19 16:55:40 +0000306 return node;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000307}
308
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000309static char *add_name(char *buf, char *s, const char *name)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000310{
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000311 size_t len = strlen(name);
312 s -= len;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000313 if (s <= buf) {
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000314 fprintf(stderr, "fuse: path too long: ...%s\n", s + len);
315 return NULL;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000316 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000317 strncpy(s, name, len);
318 s--;
319 *s = '/';
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000320
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000321 return s;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000322}
323
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000324static char *get_path_name(struct fuse *f, fuse_ino_t nodeid, const char *name)
Miklos Szeredib483c932001-10-29 14:57:57 +0000325{
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000326 char buf[FUSE_MAX_PATH];
327 char *s = buf + FUSE_MAX_PATH - 1;
328 struct node *node;
Miklos Szeredie5183742005-02-02 11:14:04 +0000329
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000330 *s = '\0';
Miklos Szeredia181e612001-11-06 12:03:23 +0000331
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000332 if (name != NULL) {
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000333 s = add_name(buf, s, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000334 if (s == NULL)
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000335 return NULL;
336 }
337
338 pthread_mutex_lock(&f->lock);
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000339 for (node = get_node(f, nodeid); node && node->nodeid != FUSE_ROOT_ID;
340 node = get_node(f, node->parent)) {
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000341 if (node->name == NULL) {
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000342 s = NULL;
343 break;
344 }
Miklos Szeredie5183742005-02-02 11:14:04 +0000345
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000346 s = add_name(buf, s, node->name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000347 if (s == NULL)
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000348 break;
349 }
350 pthread_mutex_unlock(&f->lock);
351
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000352 if (node == NULL || s == NULL)
Miklos Szeredi5e183482001-10-31 14:52:35 +0000353 return NULL;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000354 else if (*s == '\0')
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000355 return strdup("/");
356 else
357 return strdup(s);
358}
Miklos Szeredia181e612001-11-06 12:03:23 +0000359
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000360static char *get_path(struct fuse *f, fuse_ino_t nodeid)
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000361{
Miklos Szeredia13d9002004-11-02 17:32:03 +0000362 return get_path_name(f, nodeid, NULL);
Miklos Szeredib483c932001-10-29 14:57:57 +0000363}
364
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000365static void forget_node(struct fuse *f, fuse_ino_t nodeid, uint64_t nlookup)
Miklos Szeredi38009022005-05-08 19:47:22 +0000366{
367 struct node *node;
368 if (nodeid == FUSE_ROOT_ID)
369 return;
370 pthread_mutex_lock(&f->lock);
371 node = get_node(f, nodeid);
372 assert(node->nlookup >= nlookup);
373 node->nlookup -= nlookup;
374 if (!node->nlookup) {
375 unhash_name(f, node);
376 unref_node(f, node);
377 }
378 pthread_mutex_unlock(&f->lock);
379}
380
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000381static void remove_node(struct fuse *f, fuse_ino_t dir, const char *name)
Miklos Szeredi5e183482001-10-31 14:52:35 +0000382{
Miklos Szeredia181e612001-11-06 12:03:23 +0000383 struct node *node;
384
385 pthread_mutex_lock(&f->lock);
Miklos Szeredif458b8c2004-12-07 16:46:42 +0000386 node = lookup_node(f, dir, name);
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000387 if (node != NULL)
388 unhash_name(f, node);
Miklos Szeredia181e612001-11-06 12:03:23 +0000389 pthread_mutex_unlock(&f->lock);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000390}
391
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000392static int rename_node(struct fuse *f, fuse_ino_t olddir, const char *oldname,
393 fuse_ino_t newdir, const char *newname, int hide)
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000394{
Miklos Szeredia181e612001-11-06 12:03:23 +0000395 struct node *node;
396 struct node *newnode;
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000397 int err = 0;
Miklos Szeredie5183742005-02-02 11:14:04 +0000398
Miklos Szeredia181e612001-11-06 12:03:23 +0000399 pthread_mutex_lock(&f->lock);
Miklos Szeredif458b8c2004-12-07 16:46:42 +0000400 node = lookup_node(f, olddir, oldname);
401 newnode = lookup_node(f, newdir, newname);
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000402 if (node == NULL)
403 goto out;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000404
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000405 if (newnode != NULL) {
406 if (hide) {
407 fprintf(stderr, "fuse: hidden file got created during hiding\n");
Miklos Szeredib2cf9562004-09-16 08:42:40 +0000408 err = -EBUSY;
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000409 goto out;
410 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000411 unhash_name(f, newnode);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000412 }
Miklos Szeredie5183742005-02-02 11:14:04 +0000413
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000414 unhash_name(f, node);
Miklos Szeredib2cf9562004-09-16 08:42:40 +0000415 if (hash_name(f, node, newdir, newname) == -1) {
416 err = -ENOMEM;
417 goto out;
418 }
Miklos Szeredie5183742005-02-02 11:14:04 +0000419
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000420 if (hide)
421 node->is_hidden = 1;
422
423 out:
Miklos Szeredia181e612001-11-06 12:03:23 +0000424 pthread_mutex_unlock(&f->lock);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000425 return err;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000426}
427
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000428static void set_stat(struct fuse *f, fuse_ino_t nodeid, struct stat *stbuf)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000429{
Miklos Szeredi659743b2005-12-09 17:41:42 +0000430 if (!f->conf.use_ino)
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000431 stbuf->st_ino = nodeid;
Miklos Szeredi659743b2005-12-09 17:41:42 +0000432 if (f->conf.set_mode)
433 stbuf->st_mode = (stbuf->st_mode & S_IFMT) | (0777 & ~f->conf.umask);
434 if (f->conf.set_uid)
435 stbuf->st_uid = f->conf.uid;
436 if (f->conf.set_gid)
437 stbuf->st_gid = f->conf.gid;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000438}
439
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000440static struct fuse *req_fuse(fuse_req_t req)
441{
442 return (struct fuse *) fuse_req_userdata(req);
443}
444
445static void fuse_intr_sighandler(int sig)
446{
447 (void) sig;
448 /* Nothing to do */
449}
450
451struct fuse_intr_data {
452 pthread_t id;
453 pthread_cond_t cond;
454 int finished;
455};
456
457static void fuse_interrupt(fuse_req_t req, void *d_)
458{
459 struct fuse_intr_data *d = d_;
460 struct fuse *f = req_fuse(req);
461
462 if (d->id == pthread_self())
463 return;
464
465 pthread_mutex_lock(&f->lock);
466 while (!d->finished) {
467 struct timeval now;
468 struct timespec timeout;
469
470 pthread_kill(d->id, f->conf.intr_signal);
471 gettimeofday(&now, NULL);
472 timeout.tv_sec = now.tv_sec + 1;
473 timeout.tv_nsec = now.tv_usec * 1000;
474 pthread_cond_timedwait(&d->cond, &f->lock, &timeout);
475 }
476 pthread_mutex_unlock(&f->lock);
477}
478
479static void fuse_do_finish_interrupt(struct fuse *f, fuse_req_t req,
480 struct fuse_intr_data *d)
481{
482 pthread_mutex_lock(&f->lock);
483 d->finished = 1;
484 pthread_cond_broadcast(&d->cond);
485 pthread_mutex_unlock(&f->lock);
486 fuse_req_interrupt_func(req, NULL, NULL);
487 pthread_cond_destroy(&d->cond);
488}
489
490static void fuse_do_prepare_interrupt(fuse_req_t req, struct fuse_intr_data *d)
491{
492 d->id = pthread_self();
493 pthread_cond_init(&d->cond, NULL);
494 d->finished = 0;
495 fuse_req_interrupt_func(req, fuse_interrupt, d);
496}
497
498static inline void fuse_finish_interrupt(struct fuse *f, fuse_req_t req,
499 struct fuse_intr_data *d)
500{
501 if (f->conf.intr)
502 fuse_do_finish_interrupt(f, req, d);
503}
504
505static inline void fuse_prepare_interrupt(struct fuse *f, fuse_req_t req,
506 struct fuse_intr_data *d)
507{
508 if (f->conf.intr)
509 fuse_do_prepare_interrupt(req, d);
510}
511
512static int fuse_do_getattr(struct fuse *f, fuse_req_t req, const char *path,
513 struct stat *buf)
514{
515 int res;
516 struct fuse_intr_data d;
517 fuse_prepare_interrupt(f, req, &d);
518 res = f->op.getattr(path, buf);
519 fuse_finish_interrupt(f, req, &d);
520 return res;
521}
522
523static int fuse_do_fgetattr(struct fuse *f, fuse_req_t req, const char *path,
524 struct stat *buf, struct fuse_file_info *fi)
525{
526 int res;
527 struct fuse_intr_data d;
528 fuse_prepare_interrupt(f, req, &d);
529 res = f->op.fgetattr(path, buf, fi);
530 fuse_finish_interrupt(f, req, &d);
531 return res;
532}
533
534static int fuse_do_rename(struct fuse *f, fuse_req_t req, const char *oldpath,
535 const char *newpath)
536{
537 int res;
538 struct fuse_intr_data d;
539 fuse_prepare_interrupt(f, req, &d);
540 res = f->op.rename(oldpath, newpath);
541 fuse_finish_interrupt(f, req, &d);
542 return res;
543}
544
545static int fuse_do_unlink(struct fuse *f, fuse_req_t req, const char *path)
546{
547 int res;
548 struct fuse_intr_data d;
549 fuse_prepare_interrupt(f, req, &d);
550 res = f->op.unlink(path);
551 fuse_finish_interrupt(f, req, &d);
552 return res;
553}
554
555static void fuse_do_release(struct fuse *f, fuse_req_t req, const char *path,
556 struct fuse_file_info *fi)
557{
558 struct fuse_intr_data d;
559 fuse_prepare_interrupt(f, req, &d);
560 f->op.release(path, fi);
561 fuse_finish_interrupt(f, req, &d);
562}
563
564static int fuse_do_opendir(struct fuse *f, fuse_req_t req, char *path,
565 struct fuse_file_info *fi)
566{
567 int res;
568 struct fuse_intr_data d;
569 fuse_prepare_interrupt(f, req, &d);
570 res = f->op.opendir(path, fi);
571 fuse_finish_interrupt(f, req, &d);
572 return res;
573}
574
575static int fuse_do_open(struct fuse *f, fuse_req_t req, char *path,
576 struct fuse_file_info *fi)
577{
578 int res;
579 struct fuse_intr_data d;
580 fuse_prepare_interrupt(f, req, &d);
581 res = f->op.open(path, fi);
582 fuse_finish_interrupt(f, req, &d);
583 return res;
584}
585
586static int fuse_do_statfs(struct fuse *f, fuse_req_t req, const char *path,
587 struct statvfs *buf)
588{
589 int res;
590 struct fuse_intr_data d;
591 fuse_prepare_interrupt(f, req, &d);
592 res = f->op.statfs(path, buf);
593 fuse_finish_interrupt(f, req, &d);
594 return res;
595}
596
597static void fuse_do_releasedir(struct fuse *f, fuse_req_t req,
598 const char *path, struct fuse_file_info *fi)
599{
600 struct fuse_intr_data d;
601 fuse_prepare_interrupt(f, req, &d);
602 f->op.releasedir(path, fi);
603 fuse_finish_interrupt(f, req, &d);
604}
605
606static int fuse_do_create(struct fuse *f, fuse_req_t req, const char *path,
607 mode_t mode, struct fuse_file_info *fi)
608{
609 int res;
610 struct fuse_intr_data d;
611 fuse_prepare_interrupt(f, req, &d);
612 res = f->op.create(path, mode, fi);
613 fuse_finish_interrupt(f, req, &d);
614 return res;
615}
616
617static int fuse_do_lock(struct fuse *f, fuse_req_t req, const char *path,
618 struct fuse_file_info *fi, int cmd, struct flock *lock,
619 uint64_t owner)
620{
621 int res;
622 struct fuse_intr_data d;
623 fuse_prepare_interrupt(f, req, &d);
624 res = f->op.lock(path, fi, cmd, lock, owner);
625 fuse_finish_interrupt(f, req, &d);
626 return res;
627}
628
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000629static int is_open(struct fuse *f, fuse_ino_t dir, const char *name)
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000630{
631 struct node *node;
632 int isopen = 0;
633 pthread_mutex_lock(&f->lock);
Miklos Szeredif458b8c2004-12-07 16:46:42 +0000634 node = lookup_node(f, dir, name);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000635 if (node && node->open_count > 0)
636 isopen = 1;
637 pthread_mutex_unlock(&f->lock);
638 return isopen;
639}
640
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000641static char *hidden_name(struct fuse *f, fuse_req_t req, fuse_ino_t dir,
642 const char *oldname, char *newname, size_t bufsize)
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000643{
644 struct stat buf;
645 struct node *node;
646 struct node *newnode;
647 char *newpath;
648 int res;
649 int failctr = 10;
650
651 if (!f->op.getattr)
652 return NULL;
653
654 do {
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000655 pthread_mutex_lock(&f->lock);
Miklos Szeredif458b8c2004-12-07 16:46:42 +0000656 node = lookup_node(f, dir, oldname);
657 if (node == NULL) {
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000658 pthread_mutex_unlock(&f->lock);
659 return NULL;
Miklos Szeredif458b8c2004-12-07 16:46:42 +0000660 }
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000661 do {
662 f->hidectr ++;
663 snprintf(newname, bufsize, ".fuse_hidden%08x%08x",
Miklos Szeredia13d9002004-11-02 17:32:03 +0000664 (unsigned int) node->nodeid, f->hidectr);
Miklos Szeredif458b8c2004-12-07 16:46:42 +0000665 newnode = lookup_node(f, dir, newname);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000666 } while(newnode);
667 pthread_mutex_unlock(&f->lock);
Miklos Szeredie5183742005-02-02 11:14:04 +0000668
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000669 newpath = get_path_name(f, dir, newname);
670 if (!newpath)
671 break;
Miklos Szeredie5183742005-02-02 11:14:04 +0000672
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000673 res = fuse_do_getattr(f, req, newpath, &buf);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000674 if (res != 0)
675 break;
676 free(newpath);
677 newpath = NULL;
678 } while(--failctr);
679
680 return newpath;
681}
682
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000683static int hide_node(struct fuse *f, fuse_req_t req, const char *oldpath,
684 fuse_ino_t dir, const char *oldname)
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000685{
686 char newname[64];
687 char *newpath;
Miklos Szeredib2cf9562004-09-16 08:42:40 +0000688 int err = -EBUSY;
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000689
Miklos Szeredib2cf9562004-09-16 08:42:40 +0000690 if (f->op.rename && f->op.unlink) {
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000691 newpath = hidden_name(f, req, dir, oldname, newname, sizeof(newname));
Miklos Szeredib2cf9562004-09-16 08:42:40 +0000692 if (newpath) {
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000693 int res = fuse_do_rename(f, req, oldpath, newpath);
Miklos Szeredib2cf9562004-09-16 08:42:40 +0000694 if (res == 0)
695 err = rename_node(f, dir, oldname, dir, newname, 1);
696 free(newpath);
697 }
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000698 }
Miklos Szeredib2cf9562004-09-16 08:42:40 +0000699 return err;
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000700}
701
Miklos Szeredi320abe42006-01-30 18:14:51 +0000702static int mtime_eq(const struct stat *stbuf, const struct timespec *ts)
703{
704 return stbuf->st_mtime == ts->tv_sec
Csaba Henk3e3a1252006-09-24 14:53:29 +0000705#ifdef FUSE_STAT_HAS_NANOSEC
706 && ST_MTIM(stbuf).tv_nsec == ts->tv_nsec
Miklos Szeredi320abe42006-01-30 18:14:51 +0000707#endif
708 ;
709}
710
711static void mtime_set(const struct stat *stbuf, struct timespec *ts)
712{
Csaba Henk3e3a1252006-09-24 14:53:29 +0000713#ifdef FUSE_STAT_HAS_NANOSEC
714 *ts = ST_MTIM(stbuf);
Miklos Szeredi320abe42006-01-30 18:14:51 +0000715#else
716 ts->tv_sec = stbuf->st_mtime;
717#endif
718}
719
Miklos Szeredi2512aaa2006-05-03 14:54:59 +0000720#ifndef CLOCK_MONOTONIC
721#define CLOCK_MONOTONIC CLOCK_REALTIME
722#endif
723
Miklos Szeredi320abe42006-01-30 18:14:51 +0000724static void curr_time(struct timespec *now)
725{
726 static clockid_t clockid = CLOCK_MONOTONIC;
727 int res = clock_gettime(clockid, now);
728 if (res == -1 && errno == EINVAL) {
729 clockid = CLOCK_REALTIME;
730 res = clock_gettime(clockid, now);
731 }
732 if (res == -1) {
733 perror("fuse: clock_gettime");
734 abort();
735 }
736}
737
738static void update_stat(struct node *node, const struct stat *stbuf)
739{
740 if (node->cache_valid && (!mtime_eq(stbuf, &node->mtime) ||
741 stbuf->st_size != node->size))
742 node->cache_valid = 0;
743 mtime_set(stbuf, &node->mtime);
744 node->size = stbuf->st_size;
745 curr_time(&node->stat_updated);
746}
747
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000748static int lookup_path(struct fuse *f, fuse_req_t req, fuse_ino_t nodeid,
749 const char *name, const char *path,
750 struct fuse_entry_param *e, struct fuse_file_info *fi)
Miklos Szeredi76f65782004-02-19 16:55:40 +0000751{
752 int res;
Miklos Szeredi76f65782004-02-19 16:55:40 +0000753
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000754 memset(e, 0, sizeof(struct fuse_entry_param));
Miklos Szeredif7eec032005-10-28 13:09:50 +0000755 if (fi && f->op.fgetattr)
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000756 res = fuse_do_fgetattr(f, req, path, &e->attr, fi);
Miklos Szeredif7eec032005-10-28 13:09:50 +0000757 else
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000758 res = fuse_do_getattr(f, req, path, &e->attr);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000759 if (res == 0) {
Miklos Szeredi76f65782004-02-19 16:55:40 +0000760 struct node *node;
761
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000762 node = find_node(f, nodeid, name);
Miklos Szeredib2cf9562004-09-16 08:42:40 +0000763 if (node == NULL)
764 res = -ENOMEM;
765 else {
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000766 e->ino = node->nodeid;
767 e->generation = node->generation;
Miklos Szeredi659743b2005-12-09 17:41:42 +0000768 e->entry_timeout = f->conf.entry_timeout;
769 e->attr_timeout = f->conf.attr_timeout;
Miklos Szeredi320abe42006-01-30 18:14:51 +0000770 if (f->conf.auto_cache) {
771 pthread_mutex_lock(&f->lock);
772 update_stat(node, &e->attr);
773 pthread_mutex_unlock(&f->lock);
774 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000775 set_stat(f, e->ino, &e->attr);
Miklos Szeredi659743b2005-12-09 17:41:42 +0000776 if (f->conf.debug) {
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000777 printf(" NODEID: %lu\n", (unsigned long) e->ino);
Miklos Szeredib2cf9562004-09-16 08:42:40 +0000778 fflush(stdout);
779 }
Miklos Szeredi76f65782004-02-19 16:55:40 +0000780 }
781 }
782 return res;
783}
784
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000785static struct fuse_context_i *fuse_get_context_internal(void)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000786{
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000787 struct fuse_context_i *c;
788
789 c = (struct fuse_context_i *) pthread_getspecific(fuse_context_key);
790 if (c == NULL) {
791 c = (struct fuse_context_i *) malloc(sizeof(struct fuse_context_i));
792 if (c == NULL) {
793 /* This is hard to deal with properly, so just abort. If
794 memory is so low that the context cannot be allocated,
795 there's not much hope for the filesystem anyway */
796 fprintf(stderr, "fuse: failed to allocate thread specific data\n");
797 abort();
798 }
799 pthread_setspecific(fuse_context_key, c);
800 }
801 return c;
802}
803
804static void fuse_freecontext(void *data)
805{
806 free(data);
807}
808
809static int fuse_create_context_key(void)
810{
811 int err = 0;
812 pthread_mutex_lock(&fuse_context_lock);
813 if (!fuse_context_ref) {
814 err = pthread_key_create(&fuse_context_key, fuse_freecontext);
815 if (err) {
816 fprintf(stderr, "fuse: failed to create thread specific key: %s\n",
817 strerror(err));
818 pthread_mutex_unlock(&fuse_context_lock);
819 return -1;
820 }
821 }
822 fuse_context_ref++;
823 pthread_mutex_unlock(&fuse_context_lock);
824 return 0;
825}
826
827static void fuse_delete_context_key(void)
828{
829 pthread_mutex_lock(&fuse_context_lock);
830 fuse_context_ref--;
831 if (!fuse_context_ref) {
832 free(pthread_getspecific(fuse_context_key));
833 pthread_key_delete(fuse_context_key);
834 }
835 pthread_mutex_unlock(&fuse_context_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000836}
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000837
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000838static struct fuse *req_fuse_prepare(fuse_req_t req)
839{
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000840 struct fuse_context_i *c = fuse_get_context_internal();
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000841 const struct fuse_ctx *ctx = fuse_req_ctx(req);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000842 c->req = req;
843 c->ctx.fuse = req_fuse(req);
844 c->ctx.uid = ctx->uid;
845 c->ctx.gid = ctx->gid;
846 c->ctx.pid = ctx->pid;
847 c->ctx.private_data = c->ctx.fuse->user_data;
848 return c->ctx.fuse;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000849}
850
851static inline void reply_err(fuse_req_t req, int err)
852{
853 /* fuse_reply_err() uses non-negated errno values */
854 fuse_reply_err(req, -err);
855}
856
857static void reply_entry(fuse_req_t req, const struct fuse_entry_param *e,
858 int err)
859{
860 if (!err) {
Miklos Szeredib67f2162006-02-20 10:55:33 +0000861 struct fuse *f = req_fuse(req);
Miklos Szeredi9b813af2005-07-21 07:59:37 +0000862 if (fuse_reply_entry(req, e) == -ENOENT)
Miklos Szeredib67f2162006-02-20 10:55:33 +0000863 forget_node(f, e->ino, 1);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000864 } else
865 reply_err(req, err);
866}
867
Miklos Szeredi065f2222006-01-20 15:15:21 +0000868static void fuse_data_init(void *data, struct fuse_conn_info *conn)
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000869{
870 struct fuse *f = (struct fuse *) data;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000871 struct fuse_context_i *c = fuse_get_context_internal();
Miklos Szeredi4f5df5e2005-10-07 12:39:58 +0000872
873 memset(c, 0, sizeof(*c));
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000874 c->ctx.fuse = f;
875 c->ctx.private_data = f->user_data;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000876
877 if (f->op.init)
Miklos Szeredi065f2222006-01-20 15:15:21 +0000878 f->user_data = f->op.init(conn);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000879}
880
881static void fuse_data_destroy(void *data)
882{
883 struct fuse *f = (struct fuse *) data;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000884 struct fuse_context_i *c = fuse_get_context_internal();
Miklos Szeredi4f5df5e2005-10-07 12:39:58 +0000885
886 memset(c, 0, sizeof(*c));
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000887 c->ctx.fuse = f;
888 c->ctx.private_data = f->user_data;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000889
890 if (f->op.destroy)
891 f->op.destroy(f->user_data);
892}
893
894static void fuse_lookup(fuse_req_t req, fuse_ino_t parent, const char *name)
895{
896 struct fuse *f = req_fuse_prepare(req);
897 struct fuse_entry_param e;
898 char *path;
899 int err;
900
901 err = -ENOENT;
Miklos Szeredic2a33ee2005-05-09 13:29:17 +0000902 pthread_rwlock_rdlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000903 path = get_path_name(f, parent, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000904 if (path != NULL) {
Miklos Szeredi659743b2005-12-09 17:41:42 +0000905 if (f->conf.debug) {
Miklos Szeredi6ebe2342002-01-06 21:44:16 +0000906 printf("LOOKUP %s\n", path);
907 fflush(stdout);
908 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000909 err = -ENOSYS;
Miklos Szeredi2b478112005-11-28 13:27:10 +0000910 if (f->op.getattr) {
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000911 err = lookup_path(f, req, parent, name, path, &e, NULL);
Miklos Szeredi659743b2005-12-09 17:41:42 +0000912 if (err == -ENOENT && f->conf.negative_timeout != 0.0) {
Miklos Szeredi2b478112005-11-28 13:27:10 +0000913 e.ino = 0;
Miklos Szeredi659743b2005-12-09 17:41:42 +0000914 e.entry_timeout = f->conf.negative_timeout;
Miklos Szeredi2b478112005-11-28 13:27:10 +0000915 err = 0;
916 }
917 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000918 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000919 }
Miklos Szeredic2a33ee2005-05-09 13:29:17 +0000920 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000921 reply_entry(req, &e, err);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000922}
923
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000924static void fuse_forget(fuse_req_t req, fuse_ino_t ino, unsigned long nlookup)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000925{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000926 struct fuse *f = req_fuse(req);
Miklos Szeredi659743b2005-12-09 17:41:42 +0000927 if (f->conf.debug) {
Miklos Szeredi3a770472005-11-11 21:32:42 +0000928 printf("FORGET %llu/%lu\n", (unsigned long long) ino, nlookup);
Miklos Szeredi43696432001-11-18 19:15:05 +0000929 fflush(stdout);
930 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000931 forget_node(f, ino, nlookup);
932 fuse_reply_none(req);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000933}
934
Miklos Szerediecce1bf2005-08-25 15:19:06 +0000935static void fuse_getattr(fuse_req_t req, fuse_ino_t ino,
936 struct fuse_file_info *fi)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000937{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000938 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000939 struct stat buf;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000940 char *path;
941 int err;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000942
Miklos Szerediecce1bf2005-08-25 15:19:06 +0000943 (void) fi;
Miklos Szeredi16dbf942006-09-02 13:20:40 +0000944 memset(&buf, 0, sizeof(buf));
Miklos Szerediecce1bf2005-08-25 15:19:06 +0000945
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000946 err = -ENOENT;
Miklos Szeredic2a33ee2005-05-09 13:29:17 +0000947 pthread_rwlock_rdlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000948 path = get_path(f, ino);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000949 if (path != NULL) {
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000950 err = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000951 if (f->op.getattr)
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000952 err = fuse_do_getattr(f, req, path, &buf);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000953 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000954 }
Miklos Szeredic2a33ee2005-05-09 13:29:17 +0000955 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000956 if (!err) {
Miklos Szeredi08dab162006-02-01 13:39:15 +0000957 if (f->conf.auto_cache) {
958 pthread_mutex_lock(&f->lock);
959 update_stat(get_node(f, ino), &buf);
960 pthread_mutex_unlock(&f->lock);
961 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000962 set_stat(f, ino, &buf);
Miklos Szeredi659743b2005-12-09 17:41:42 +0000963 fuse_reply_attr(req, &buf, f->conf.attr_timeout);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000964 } else
965 reply_err(req, err);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000966}
967
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000968static int do_chmod(struct fuse *f, fuse_req_t req, const char *path,
969 struct stat *attr)
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000970{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000971 int err;
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000972
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000973 err = -ENOSYS;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000974 if (f->op.chmod) {
975 struct fuse_intr_data d;
976 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000977 err = f->op.chmod(path, attr->st_mode);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000978 fuse_finish_interrupt(f, req, &d);
979 }
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000980
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000981 return err;
Miklos Szeredie5183742005-02-02 11:14:04 +0000982}
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000983
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000984static int do_chown(struct fuse *f, fuse_req_t req, const char *path,
985 struct stat *attr, int valid)
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000986{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000987 int err;
988 uid_t uid = (valid & FUSE_SET_ATTR_UID) ? attr->st_uid : (uid_t) -1;
989 gid_t gid = (valid & FUSE_SET_ATTR_GID) ? attr->st_gid : (gid_t) -1;
Miklos Szeredie5183742005-02-02 11:14:04 +0000990
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000991 err = -ENOSYS;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000992 if (f->op.chown) {
993 struct fuse_intr_data d;
994 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000995 err = f->op.chown(path, uid, gid);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000996 fuse_finish_interrupt(f, req, &d);
997 }
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000998
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000999 return err;
Miklos Szeredif3ea83b2001-11-07 14:55:16 +00001000}
1001
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001002static int do_truncate(struct fuse *f, fuse_req_t req, const char *path,
1003 struct stat *attr, struct fuse_file_info *fi)
Miklos Szeredif3ea83b2001-11-07 14:55:16 +00001004{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001005 int err;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001006 struct fuse_intr_data d;
Miklos Szeredif3ea83b2001-11-07 14:55:16 +00001007
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001008 err = -ENOSYS;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001009 if (fi && f->op.ftruncate) {
1010 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredi11509ce2005-10-26 16:04:04 +00001011 err = f->op.ftruncate(path, attr->st_size, fi);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001012 fuse_finish_interrupt(f, req, &d);
1013 } else if (f->op.truncate) {
1014 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001015 err = f->op.truncate(path, attr->st_size);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001016 fuse_finish_interrupt(f, req, &d);
1017 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001018 return err;
Miklos Szeredif3ea83b2001-11-07 14:55:16 +00001019}
1020
Miklos Szeredic3b76812006-09-16 08:52:09 +00001021static int do_utimens(struct fuse *f, fuse_req_t req, const char *path,
1022 struct stat *attr)
Miklos Szeredif3ea83b2001-11-07 14:55:16 +00001023{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001024 int err;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001025 struct fuse_intr_data d;
Miklos Szeredifa440772006-09-02 09:51:08 +00001026
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001027 err = -ENOSYS;
Miklos Szeredic3b76812006-09-16 08:52:09 +00001028 if (f->op.utimens) {
Miklos Szeredifa440772006-09-02 09:51:08 +00001029 struct timespec tv[2];
Csaba Henk3e3a1252006-09-24 14:53:29 +00001030#ifdef FUSE_STAT_HAS_NANOSEC
1031 tv[0] = ST_ATIM(attr);
1032 tv[1] = ST_MTIM(attr);
1033#else
1034 tv[0].tv_sec = attr->st_atime;
1035 tv[0].tv_nsec = 0;
1036 tv[1].tv_sec = attr->st_mtime;
1037 tv[1].tv_nsec = 0;
1038#endif
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001039 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredic3b76812006-09-16 08:52:09 +00001040 err = f->op.utimens(path, tv);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001041 fuse_finish_interrupt(f, req, &d);
Miklos Szeredifa440772006-09-02 09:51:08 +00001042 } else if (f->op.utime) {
1043 struct utimbuf buf;
1044 buf.actime = attr->st_atime;
1045 buf.modtime = attr->st_mtime;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001046 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001047 err = f->op.utime(path, &buf);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001048 fuse_finish_interrupt(f, req, &d);
Miklos Szeredifa440772006-09-02 09:51:08 +00001049 }
Miklos Szeredif3ea83b2001-11-07 14:55:16 +00001050
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001051 return err;
Miklos Szeredif3ea83b2001-11-07 14:55:16 +00001052}
1053
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001054static void fuse_setattr(fuse_req_t req, fuse_ino_t ino, struct stat *attr,
Miklos Szerediecce1bf2005-08-25 15:19:06 +00001055 int valid, struct fuse_file_info *fi)
Miklos Szeredi5e183482001-10-31 14:52:35 +00001056{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001057 struct fuse *f = req_fuse_prepare(req);
1058 struct stat buf;
Miklos Szeredi5e183482001-10-31 14:52:35 +00001059 char *path;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001060 int err;
Miklos Szeredi5e183482001-10-31 14:52:35 +00001061
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001062 err = -ENOENT;
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001063 pthread_rwlock_rdlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001064 path = get_path(f, ino);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001065 if (path != NULL) {
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001066 err = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001067 if (f->op.getattr) {
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001068 err = 0;
1069 if (!err && (valid & FUSE_SET_ATTR_MODE))
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001070 err = do_chmod(f, req, path, attr);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001071 if (!err && (valid & (FUSE_SET_ATTR_UID | FUSE_SET_ATTR_GID)))
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001072 err = do_chown(f, req, path, attr, valid);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001073 if (!err && (valid & FUSE_SET_ATTR_SIZE))
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001074 err = do_truncate(f, req, path, attr, fi);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001075 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 +00001076 err = do_utimens(f, req, path, attr);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001077 if (!err)
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001078 err = fuse_do_getattr(f, req, path, &buf);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001079 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001080 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001081 }
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001082 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001083 if (!err) {
Miklos Szeredi08dab162006-02-01 13:39:15 +00001084 if (f->conf.auto_cache) {
1085 pthread_mutex_lock(&f->lock);
1086 update_stat(get_node(f, ino), &buf);
1087 pthread_mutex_unlock(&f->lock);
1088 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001089 set_stat(f, ino, &buf);
Miklos Szeredi659743b2005-12-09 17:41:42 +00001090 fuse_reply_attr(req, &buf, f->conf.attr_timeout);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001091 } else
1092 reply_err(req, err);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001093}
1094
Miklos Szeredib0b13d12005-10-26 12:53:25 +00001095static void fuse_access(fuse_req_t req, fuse_ino_t ino, int mask)
1096{
1097 struct fuse *f = req_fuse_prepare(req);
1098 char *path;
1099 int err;
1100
1101 err = -ENOENT;
1102 pthread_rwlock_rdlock(&f->tree_lock);
1103 path = get_path(f, ino);
1104 if (path != NULL) {
Miklos Szeredi659743b2005-12-09 17:41:42 +00001105 if (f->conf.debug) {
Miklos Szeredib0b13d12005-10-26 12:53:25 +00001106 printf("ACCESS %s 0%o\n", path, mask);
1107 fflush(stdout);
1108 }
1109 err = -ENOSYS;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001110 if (f->op.access) {
1111 struct fuse_intr_data d;
1112 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredib0b13d12005-10-26 12:53:25 +00001113 err = f->op.access(path, mask);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001114 fuse_finish_interrupt(f, req, &d);
1115 }
Miklos Szeredib0b13d12005-10-26 12:53:25 +00001116 free(path);
1117 }
1118 pthread_rwlock_unlock(&f->tree_lock);
1119 reply_err(req, err);
1120}
1121
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001122static void fuse_readlink(fuse_req_t req, fuse_ino_t ino)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001123{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001124 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredif6e0ec62005-08-03 09:11:06 +00001125 char linkname[PATH_MAX + 1];
Miklos Szeredib483c932001-10-29 14:57:57 +00001126 char *path;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001127 int err;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001128
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001129 err = -ENOENT;
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001130 pthread_rwlock_rdlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001131 path = get_path(f, ino);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001132 if (path != NULL) {
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001133 err = -ENOSYS;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001134 if (f->op.readlink) {
1135 struct fuse_intr_data d;
1136 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredif6e0ec62005-08-03 09:11:06 +00001137 err = f->op.readlink(path, linkname, sizeof(linkname));
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001138 fuse_finish_interrupt(f, req, &d);
1139 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001140 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001141 }
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001142 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001143 if (!err) {
Miklos Szeredif6e0ec62005-08-03 09:11:06 +00001144 linkname[PATH_MAX] = '\0';
1145 fuse_reply_readlink(req, linkname);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001146 } else
1147 reply_err(req, err);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001148}
1149
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001150static void fuse_mknod(fuse_req_t req, fuse_ino_t parent, const char *name,
1151 mode_t mode, dev_t rdev)
Miklos Szeredib483c932001-10-29 14:57:57 +00001152{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001153 struct fuse *f = req_fuse_prepare(req);
1154 struct fuse_entry_param e;
Miklos Szeredib483c932001-10-29 14:57:57 +00001155 char *path;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001156 int err;
Miklos Szeredib483c932001-10-29 14:57:57 +00001157
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001158 err = -ENOENT;
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001159 pthread_rwlock_rdlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001160 path = get_path_name(f, parent, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001161 if (path != NULL) {
Miklos Szeredi659743b2005-12-09 17:41:42 +00001162 if (f->conf.debug) {
Miklos Szeredi76f65782004-02-19 16:55:40 +00001163 printf("MKNOD %s\n", path);
1164 fflush(stdout);
1165 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001166 err = -ENOSYS;
Miklos Szeredib3f99722005-11-16 13:00:24 +00001167 if (S_ISREG(mode) && f->op.create && f->op.getattr) {
1168 struct fuse_file_info fi;
1169
1170 memset(&fi, 0, sizeof(fi));
1171 fi.flags = O_CREAT | O_EXCL | O_WRONLY;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001172 err = fuse_do_create(f, req, path, mode, &fi);
Miklos Szeredib3f99722005-11-16 13:00:24 +00001173 if (!err) {
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001174 err = lookup_path(f, req, parent, name, path, &e, &fi);
Miklos Szeredib3f99722005-11-16 13:00:24 +00001175 if (f->op.release)
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001176 fuse_do_release(f, req, path, &fi);
Miklos Szeredib3f99722005-11-16 13:00:24 +00001177 }
1178 } else if (f->op.mknod && f->op.getattr) {
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001179 struct fuse_intr_data d;
1180 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001181 err = f->op.mknod(path, mode, rdev);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001182 fuse_finish_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001183 if (!err)
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001184 err = lookup_path(f, req, parent, name, path, &e, NULL);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001185 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001186 free(path);
Miklos Szeredib483c932001-10-29 14:57:57 +00001187 }
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001188 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001189 reply_entry(req, &e, err);
Miklos Szeredib483c932001-10-29 14:57:57 +00001190}
1191
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001192static void fuse_mkdir(fuse_req_t req, fuse_ino_t parent, const char *name,
1193 mode_t mode)
Miklos Szeredib483c932001-10-29 14:57:57 +00001194{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001195 struct fuse *f = req_fuse_prepare(req);
1196 struct fuse_entry_param e;
Miklos Szeredib483c932001-10-29 14:57:57 +00001197 char *path;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001198 int err;
Miklos Szeredib483c932001-10-29 14:57:57 +00001199
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001200 err = -ENOENT;
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001201 pthread_rwlock_rdlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001202 path = get_path_name(f, parent, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001203 if (path != NULL) {
Miklos Szeredi659743b2005-12-09 17:41:42 +00001204 if (f->conf.debug) {
Miklos Szeredi76f65782004-02-19 16:55:40 +00001205 printf("MKDIR %s\n", path);
1206 fflush(stdout);
1207 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001208 err = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001209 if (f->op.mkdir && f->op.getattr) {
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001210 struct fuse_intr_data d;
1211 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001212 err = f->op.mkdir(path, mode);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001213 fuse_finish_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001214 if (!err)
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001215 err = lookup_path(f, req, parent, name, path, &e, NULL);
Miklos Szeredi76f65782004-02-19 16:55:40 +00001216 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001217 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001218 }
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001219 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001220 reply_entry(req, &e, err);
Miklos Szeredib483c932001-10-29 14:57:57 +00001221}
1222
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001223static void fuse_unlink(fuse_req_t req, fuse_ino_t parent, const char *name)
Miklos Szeredib483c932001-10-29 14:57:57 +00001224{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001225 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredib483c932001-10-29 14:57:57 +00001226 char *path;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001227 int err;
Miklos Szeredib483c932001-10-29 14:57:57 +00001228
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001229 err = -ENOENT;
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001230 pthread_rwlock_wrlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001231 path = get_path_name(f, parent, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001232 if (path != NULL) {
Miklos Szeredi659743b2005-12-09 17:41:42 +00001233 if (f->conf.debug) {
Miklos Szeredi209f5d02004-07-24 19:56:16 +00001234 printf("UNLINK %s\n", path);
1235 fflush(stdout);
1236 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001237 err = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001238 if (f->op.unlink) {
Miklos Szeredi659743b2005-12-09 17:41:42 +00001239 if (!f->conf.hard_remove && is_open(f, parent, name))
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001240 err = hide_node(f, req, path, parent, name);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001241 else {
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001242 err = fuse_do_unlink(f, req, path);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001243 if (!err)
1244 remove_node(f, parent, name);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001245 }
Miklos Szeredi5e183482001-10-31 14:52:35 +00001246 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001247 free(path);
Miklos Szeredib483c932001-10-29 14:57:57 +00001248 }
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001249 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001250 reply_err(req, err);
Miklos Szeredib5958612004-02-20 14:10:49 +00001251}
1252
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001253static void fuse_rmdir(fuse_req_t req, fuse_ino_t parent, const char *name)
Miklos Szeredib5958612004-02-20 14:10:49 +00001254{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001255 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredib5958612004-02-20 14:10:49 +00001256 char *path;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001257 int err;
Miklos Szeredib5958612004-02-20 14:10:49 +00001258
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001259 err = -ENOENT;
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001260 pthread_rwlock_wrlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001261 path = get_path_name(f, parent, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001262 if (path != NULL) {
Miklos Szeredi659743b2005-12-09 17:41:42 +00001263 if (f->conf.debug) {
Miklos Szeredi209f5d02004-07-24 19:56:16 +00001264 printf("RMDIR %s\n", path);
1265 fflush(stdout);
1266 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001267 err = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001268 if (f->op.rmdir) {
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001269 struct fuse_intr_data d;
1270 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001271 err = f->op.rmdir(path);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001272 fuse_finish_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001273 if (!err)
1274 remove_node(f, parent, name);
Miklos Szeredib5958612004-02-20 14:10:49 +00001275 }
1276 free(path);
1277 }
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001278 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001279 reply_err(req, err);
Miklos Szeredib483c932001-10-29 14:57:57 +00001280}
1281
Miklos Szeredif6e0ec62005-08-03 09:11:06 +00001282static void fuse_symlink(fuse_req_t req, const char *linkname,
1283 fuse_ino_t parent, const char *name)
Miklos Szeredib483c932001-10-29 14:57:57 +00001284{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001285 struct fuse *f = req_fuse_prepare(req);
1286 struct fuse_entry_param e;
Miklos Szeredib483c932001-10-29 14:57:57 +00001287 char *path;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001288 int err;
Miklos Szeredib483c932001-10-29 14:57:57 +00001289
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001290 err = -ENOENT;
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001291 pthread_rwlock_rdlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001292 path = get_path_name(f, parent, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001293 if (path != NULL) {
Miklos Szeredi659743b2005-12-09 17:41:42 +00001294 if (f->conf.debug) {
Miklos Szeredi76f65782004-02-19 16:55:40 +00001295 printf("SYMLINK %s\n", path);
1296 fflush(stdout);
1297 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001298 err = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001299 if (f->op.symlink && f->op.getattr) {
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001300 struct fuse_intr_data d;
1301 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredif6e0ec62005-08-03 09:11:06 +00001302 err = f->op.symlink(linkname, path);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001303 fuse_finish_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001304 if (!err)
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001305 err = lookup_path(f, req, parent, name, path, &e, NULL);
Miklos Szeredi76f65782004-02-19 16:55:40 +00001306 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001307 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001308 }
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001309 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001310 reply_entry(req, &e, err);
Miklos Szeredib483c932001-10-29 14:57:57 +00001311}
1312
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001313static void fuse_rename(fuse_req_t req, fuse_ino_t olddir, const char *oldname,
1314 fuse_ino_t newdir, const char *newname)
Miklos Szeredi19dff1b2001-10-30 15:06:52 +00001315{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001316 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001317 char *oldpath;
1318 char *newpath;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001319 int err;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +00001320
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001321 err = -ENOENT;
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001322 pthread_rwlock_wrlock(&f->tree_lock);
Miklos Szeredia181e612001-11-06 12:03:23 +00001323 oldpath = get_path_name(f, olddir, oldname);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001324 if (oldpath != NULL) {
Miklos Szeredia181e612001-11-06 12:03:23 +00001325 newpath = get_path_name(f, newdir, newname);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001326 if (newpath != NULL) {
Miklos Szeredi659743b2005-12-09 17:41:42 +00001327 if (f->conf.debug) {
Miklos Szeredi209f5d02004-07-24 19:56:16 +00001328 printf("RENAME %s -> %s\n", oldpath, newpath);
1329 fflush(stdout);
1330 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001331 err = -ENOSYS;
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001332 if (f->op.rename) {
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001333 err = 0;
Miklos Szeredi659743b2005-12-09 17:41:42 +00001334 if (!f->conf.hard_remove &&
Miklos Szeredi2529ca22004-07-13 15:36:52 +00001335 is_open(f, newdir, newname))
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001336 err = hide_node(f, req, newpath, newdir, newname);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001337 if (!err) {
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001338 fuse_do_rename(f, req, oldpath, newpath);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001339 if (!err)
1340 err = rename_node(f, olddir, oldname, newdir, newname, 0);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001341 }
1342 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001343 free(newpath);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001344 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001345 free(oldpath);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001346 }
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001347 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001348 reply_err(req, err);
Miklos Szeredi19dff1b2001-10-30 15:06:52 +00001349}
1350
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001351static void fuse_link(fuse_req_t req, fuse_ino_t ino, fuse_ino_t newparent,
1352 const char *newname)
Miklos Szeredi19dff1b2001-10-30 15:06:52 +00001353{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001354 struct fuse *f = req_fuse_prepare(req);
1355 struct fuse_entry_param e;
Miklos Szeredi5e183482001-10-31 14:52:35 +00001356 char *oldpath;
1357 char *newpath;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001358 int err;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +00001359
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001360 err = -ENOENT;
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001361 pthread_rwlock_rdlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001362 oldpath = get_path(f, ino);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001363 if (oldpath != NULL) {
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001364 newpath = get_path_name(f, newparent, newname);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001365 if (newpath != NULL) {
Miklos Szeredi659743b2005-12-09 17:41:42 +00001366 if (f->conf.debug) {
Miklos Szeredi76f65782004-02-19 16:55:40 +00001367 printf("LINK %s\n", newpath);
1368 fflush(stdout);
1369 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001370 err = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001371 if (f->op.link && f->op.getattr) {
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001372 struct fuse_intr_data d;
1373 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001374 err = f->op.link(oldpath, newpath);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001375 fuse_finish_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001376 if (!err)
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001377 err = lookup_path(f, req, newparent, newname, newpath, &e,
1378 NULL);
Miklos Szeredi76f65782004-02-19 16:55:40 +00001379 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001380 free(newpath);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001381 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001382 free(oldpath);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001383 }
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001384 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001385 reply_entry(req, &e, err);
Miklos Szeredi19dff1b2001-10-30 15:06:52 +00001386}
1387
Miklos Szeredid9079a72005-10-26 15:29:06 +00001388static void fuse_create(fuse_req_t req, fuse_ino_t parent, const char *name,
1389 mode_t mode, struct fuse_file_info *fi)
1390{
1391 struct fuse *f = req_fuse_prepare(req);
1392 struct fuse_entry_param e;
1393 char *path;
1394 int err;
1395
1396 err = -ENOENT;
1397 pthread_rwlock_rdlock(&f->tree_lock);
1398 path = get_path_name(f, parent, name);
1399 if (path != NULL) {
1400 err = -ENOSYS;
1401 if (f->op.create && f->op.getattr) {
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001402 err = fuse_do_create(f, req, path, mode, fi);
Miklos Szeredid9079a72005-10-26 15:29:06 +00001403 if (!err) {
Miklos Szeredi659743b2005-12-09 17:41:42 +00001404 if (f->conf.debug) {
Miklos Szeredi3a770472005-11-11 21:32:42 +00001405 printf("CREATE[%llu] flags: 0x%x %s\n",
1406 (unsigned long long) fi->fh, fi->flags, path);
Miklos Szeredid9079a72005-10-26 15:29:06 +00001407 fflush(stdout);
1408 }
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001409 err = lookup_path(f, req, parent, name, path, &e, fi);
Miklos Szeredid9079a72005-10-26 15:29:06 +00001410 if (err) {
1411 if (f->op.release)
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001412 fuse_do_release(f, req, path, fi);
Miklos Szeredid9079a72005-10-26 15:29:06 +00001413 } else if (!S_ISREG(e.attr.st_mode)) {
1414 err = -EIO;
1415 if (f->op.release)
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001416 fuse_do_release(f, req, path, fi);
Miklos Szeredid9079a72005-10-26 15:29:06 +00001417 forget_node(f, e.ino, 1);
1418 }
1419 }
1420 }
1421 }
1422
1423 if (!err) {
Miklos Szeredi659743b2005-12-09 17:41:42 +00001424 if (f->conf.direct_io)
Miklos Szeredid9079a72005-10-26 15:29:06 +00001425 fi->direct_io = 1;
Miklos Szeredi659743b2005-12-09 17:41:42 +00001426 if (f->conf.kernel_cache)
Miklos Szeredid9079a72005-10-26 15:29:06 +00001427 fi->keep_cache = 1;
1428
1429 pthread_mutex_lock(&f->lock);
1430 if (fuse_reply_create(req, &e, fi) == -ENOENT) {
1431 /* The open syscall was interrupted, so it must be cancelled */
1432 if(f->op.release)
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001433 fuse_do_release(f, req, path, fi);
Miklos Szeredid9079a72005-10-26 15:29:06 +00001434 forget_node(f, e.ino, 1);
1435 } else {
1436 struct node *node = get_node(f, e.ino);
1437 node->open_count ++;
1438 }
1439 pthread_mutex_unlock(&f->lock);
1440 } else
1441 reply_err(req, err);
1442
1443 if (path)
1444 free(path);
1445 pthread_rwlock_unlock(&f->tree_lock);
1446}
1447
Miklos Szeredi320abe42006-01-30 18:14:51 +00001448static double diff_timespec(const struct timespec *t1,
1449 const struct timespec *t2)
1450{
1451 return (t1->tv_sec - t2->tv_sec) +
1452 ((double) t1->tv_nsec - (double) t2->tv_nsec) / 1000000000.0;
1453}
1454
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001455static void open_auto_cache(struct fuse *f, fuse_req_t req, fuse_ino_t ino,
1456 const char *path, struct fuse_file_info *fi)
Miklos Szeredi320abe42006-01-30 18:14:51 +00001457{
1458 struct node *node = get_node(f, ino);
Miklos Szeredi08dab162006-02-01 13:39:15 +00001459 if (node->cache_valid) {
1460 struct timespec now;
Miklos Szeredi320abe42006-01-30 18:14:51 +00001461
Miklos Szeredi08dab162006-02-01 13:39:15 +00001462 curr_time(&now);
Miklos Szeredi6e806e92006-02-16 16:59:39 +00001463 if (diff_timespec(&now, &node->stat_updated) > f->conf.ac_attr_timeout) {
Miklos Szeredi08dab162006-02-01 13:39:15 +00001464 struct stat stbuf;
1465 int err;
Miklos Szeredi320abe42006-01-30 18:14:51 +00001466
Miklos Szeredi08dab162006-02-01 13:39:15 +00001467 if (f->op.fgetattr)
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001468 err = fuse_do_fgetattr(f, req, path, &stbuf, fi);
Miklos Szeredi08dab162006-02-01 13:39:15 +00001469 else
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001470 err = fuse_do_getattr(f, req, path, &stbuf);
Miklos Szeredi08dab162006-02-01 13:39:15 +00001471
1472 if (!err)
1473 update_stat(node, &stbuf);
1474 else
1475 node->cache_valid = 0;
1476 }
Miklos Szeredi320abe42006-01-30 18:14:51 +00001477 }
1478 if (node->cache_valid)
1479 fi->keep_cache = 1;
Miklos Szeredi08dab162006-02-01 13:39:15 +00001480
1481 node->cache_valid = 1;
Miklos Szeredi320abe42006-01-30 18:14:51 +00001482}
1483
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001484static void fuse_open(fuse_req_t req, fuse_ino_t ino,
1485 struct fuse_file_info *fi)
Miklos Szeredi5e183482001-10-31 14:52:35 +00001486{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001487 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredi31066bb2005-08-01 14:49:31 +00001488 char *path = NULL;
1489 int err = 0;
Miklos Szeredi5e183482001-10-31 14:52:35 +00001490
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001491 pthread_rwlock_rdlock(&f->tree_lock);
Miklos Szeredi31066bb2005-08-01 14:49:31 +00001492 if (f->op.open) {
1493 err = -ENOENT;
1494 path = get_path(f, ino);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00001495 if (path != NULL)
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001496 err = fuse_compat_open(f, req, path, fi);
Miklos Szeredi40b9a5a2002-12-10 16:09:02 +00001497 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001498 if (!err) {
Miklos Szeredi659743b2005-12-09 17:41:42 +00001499 if (f->conf.debug) {
Miklos Szeredi3a770472005-11-11 21:32:42 +00001500 printf("OPEN[%llu] flags: 0x%x\n", (unsigned long long) fi->fh,
1501 fi->flags);
Miklos Szeredi209f5d02004-07-24 19:56:16 +00001502 fflush(stdout);
1503 }
Miklos Szeredie5183742005-02-02 11:14:04 +00001504
Miklos Szeredi659743b2005-12-09 17:41:42 +00001505 if (f->conf.direct_io)
Miklos Szeredie77cc072005-08-01 11:58:51 +00001506 fi->direct_io = 1;
Miklos Szeredi659743b2005-12-09 17:41:42 +00001507 if (f->conf.kernel_cache)
Miklos Szeredie77cc072005-08-01 11:58:51 +00001508 fi->keep_cache = 1;
1509
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001510 pthread_mutex_lock(&f->lock);
Miklos Szeredi320abe42006-01-30 18:14:51 +00001511 if (f->conf.auto_cache)
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001512 open_auto_cache(f, req, ino, path, fi);
Miklos Szeredi320abe42006-01-30 18:14:51 +00001513
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001514 if (fuse_reply_open(req, fi) == -ENOENT) {
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001515 /* The open syscall was interrupted, so it must be cancelled */
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00001516 if(f->op.release && path != NULL)
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001517 fuse_compat_release(f, req, path, fi);
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001518 } else {
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001519 struct node *node = get_node(f, ino);
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001520 node->open_count ++;
1521 }
Miklos Szeredi73798f92004-07-12 15:55:11 +00001522 pthread_mutex_unlock(&f->lock);
Miklos Szeredi73798f92004-07-12 15:55:11 +00001523 } else
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001524 reply_err(req, err);
Miklos Szeredi73798f92004-07-12 15:55:11 +00001525
Miklos Szeredi9a31cca2004-06-26 21:11:25 +00001526 if (path)
1527 free(path);
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001528 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001529}
1530
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001531static void fuse_read(fuse_req_t req, fuse_ino_t ino, size_t size, off_t off,
1532 struct fuse_file_info *fi)
Miklos Szeredie2e4ac22004-05-18 08:45:28 +00001533{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001534 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredie2e4ac22004-05-18 08:45:28 +00001535 char *path;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001536 char *buf;
Miklos Szeredie2e4ac22004-05-18 08:45:28 +00001537 int res;
1538
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001539 buf = (char *) malloc(size);
1540 if (buf == NULL) {
1541 reply_err(req, -ENOMEM);
1542 return;
1543 }
1544
Miklos Szeredie2e4ac22004-05-18 08:45:28 +00001545 res = -ENOENT;
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001546 pthread_rwlock_rdlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001547 path = get_path(f, ino);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001548 if (path != NULL) {
Miklos Szeredi659743b2005-12-09 17:41:42 +00001549 if (f->conf.debug) {
Miklos Szeredia039f8f2006-02-24 16:21:58 +00001550 printf("READ[%llu] %lu bytes from %llu\n",
1551 (unsigned long long) fi->fh, (unsigned long) size,
1552 (unsigned long long) off);
Miklos Szeredi209f5d02004-07-24 19:56:16 +00001553 fflush(stdout);
1554 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001555
Miklos Szeredie2e4ac22004-05-18 08:45:28 +00001556 res = -ENOSYS;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001557 if (f->op.read) {
1558 struct fuse_intr_data d;
1559 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001560 res = f->op.read(path, buf, size, off, fi);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001561 fuse_finish_interrupt(f, req, &d);
1562 }
Miklos Szeredie2e4ac22004-05-18 08:45:28 +00001563 free(path);
1564 }
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001565 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001566
1567 if (res >= 0) {
Miklos Szeredi659743b2005-12-09 17:41:42 +00001568 if (f->conf.debug) {
Miklos Szeredi3a770472005-11-11 21:32:42 +00001569 printf(" READ[%llu] %u bytes\n", (unsigned long long) fi->fh,
1570 res);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001571 fflush(stdout);
1572 }
Miklos Szeredif412d072005-10-14 21:24:32 +00001573 if ((size_t) res > size)
1574 fprintf(stderr, "fuse: read too many bytes");
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001575 fuse_reply_buf(req, buf, res);
1576 } else
1577 reply_err(req, res);
1578
1579 free(buf);
Miklos Szeredie2e4ac22004-05-18 08:45:28 +00001580}
1581
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001582static void fuse_write(fuse_req_t req, fuse_ino_t ino, const char *buf,
1583 size_t size, off_t off, struct fuse_file_info *fi)
Miklos Szeredic8ba2372002-12-10 12:26:00 +00001584{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001585 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001586 char *path;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001587 int res;
1588
1589 res = -ENOENT;
1590 pthread_rwlock_rdlock(&f->tree_lock);
1591 path = get_path(f, ino);
1592 if (path != NULL) {
Miklos Szeredi659743b2005-12-09 17:41:42 +00001593 if (f->conf.debug) {
Miklos Szeredia039f8f2006-02-24 16:21:58 +00001594 printf("WRITE%s[%llu] %lu bytes to %llu\n",
Miklos Szeredi3a770472005-11-11 21:32:42 +00001595 fi->writepage ? "PAGE" : "", (unsigned long long) fi->fh,
Miklos Szeredia039f8f2006-02-24 16:21:58 +00001596 (unsigned long) size, (unsigned long long) off);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001597 fflush(stdout);
1598 }
1599
1600 res = -ENOSYS;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001601 if (f->op.write) {
1602 struct fuse_intr_data d;
1603 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001604 res = f->op.write(path, buf, size, off, fi);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001605 fuse_finish_interrupt(f, req, &d);
1606 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001607 free(path);
1608 }
1609 pthread_rwlock_unlock(&f->tree_lock);
1610
Miklos Szeredif412d072005-10-14 21:24:32 +00001611 if (res >= 0) {
Miklos Szeredi659743b2005-12-09 17:41:42 +00001612 if (f->conf.debug) {
Miklos Szeredi3a770472005-11-11 21:32:42 +00001613 printf(" WRITE%s[%llu] %u bytes\n",
1614 fi->writepage ? "PAGE" : "", (unsigned long long) fi->fh,
1615 res);
Miklos Szeredif412d072005-10-14 21:24:32 +00001616 fflush(stdout);
1617 }
1618 if ((size_t) res > size)
1619 fprintf(stderr, "fuse: wrote too many bytes");
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001620 fuse_reply_write(req, res);
Miklos Szeredif412d072005-10-14 21:24:32 +00001621 } else
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001622 reply_err(req, res);
1623}
1624
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001625static void fuse_release(fuse_req_t req, fuse_ino_t ino,
1626 struct fuse_file_info *fi)
1627{
1628 struct fuse *f = req_fuse_prepare(req);
1629 char *path;
1630 struct node *node;
Miklos Szeredic3b76812006-09-16 08:52:09 +00001631 int unlink_hidden = 0;
Miklos Szeredifb28c5e2004-11-26 12:15:06 +00001632
Miklos Szerediaa8258e2006-02-25 14:42:03 +00001633 pthread_rwlock_rdlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001634 path = get_path(f, ino);
Miklos Szeredi659743b2005-12-09 17:41:42 +00001635 if (f->conf.debug) {
Miklos Szeredi3a770472005-11-11 21:32:42 +00001636 printf("RELEASE[%llu] flags: 0x%x\n", (unsigned long long) fi->fh,
1637 fi->flags);
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001638 fflush(stdout);
Miklos Szeredic8ba2372002-12-10 12:26:00 +00001639 }
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00001640 if (f->op.release)
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001641 fuse_compat_release(f, req, path, fi);
Miklos Szeredie5183742005-02-02 11:14:04 +00001642
Miklos Szeredi9a5c11d2006-07-30 17:33:40 +00001643 pthread_mutex_lock(&f->lock);
1644 node = get_node(f, ino);
1645 assert(node->open_count > 0);
1646 --node->open_count;
Miklos Szeredic3b76812006-09-16 08:52:09 +00001647 if (node->is_hidden && !node->open_count) {
1648 unlink_hidden = 1;
1649 node->is_hidden = 0;
1650 }
Miklos Szeredi9a5c11d2006-07-30 17:33:40 +00001651 pthread_mutex_unlock(&f->lock);
1652
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001653 if(unlink_hidden && path)
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001654 fuse_do_unlink(f, req, path);
Miklos Szeredie5183742005-02-02 11:14:04 +00001655
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001656 if (path)
1657 free(path);
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001658 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001659
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001660 reply_err(req, 0);
Miklos Szeredic8ba2372002-12-10 12:26:00 +00001661}
1662
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001663static void fuse_fsync(fuse_req_t req, fuse_ino_t ino, int datasync,
1664 struct fuse_file_info *fi)
Miklos Szeredi5e183482001-10-31 14:52:35 +00001665{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001666 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001667 char *path;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001668 int err;
Miklos Szerediab974562005-04-07 15:40:21 +00001669
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001670 err = -ENOENT;
1671 pthread_rwlock_rdlock(&f->tree_lock);
1672 path = get_path(f, ino);
1673 if (path != NULL) {
Miklos Szeredi659743b2005-12-09 17:41:42 +00001674 if (f->conf.debug) {
Miklos Szeredi3a770472005-11-11 21:32:42 +00001675 printf("FSYNC[%llu]\n", (unsigned long long) fi->fh);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001676 fflush(stdout);
1677 }
1678 err = -ENOSYS;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001679 if (f->op.fsync) {
1680 struct fuse_intr_data d;
1681 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001682 err = f->op.fsync(path, datasync, fi);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001683 fuse_finish_interrupt(f, req, &d);
1684 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001685 free(path);
1686 }
1687 pthread_rwlock_unlock(&f->tree_lock);
1688 reply_err(req, err);
1689}
1690
1691static struct fuse_dirhandle *get_dirhandle(const struct fuse_file_info *llfi,
1692 struct fuse_file_info *fi)
1693{
Miklos Szeredi3a770472005-11-11 21:32:42 +00001694 struct fuse_dirhandle *dh = (struct fuse_dirhandle *) (uintptr_t) llfi->fh;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001695 memset(fi, 0, sizeof(struct fuse_file_info));
1696 fi->fh = dh->fh;
Miklos Szerediead7f102005-11-28 16:02:27 +00001697 fi->fh_old = dh->fh;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001698 return dh;
1699}
1700
1701static void fuse_opendir(fuse_req_t req, fuse_ino_t ino,
1702 struct fuse_file_info *llfi)
1703{
1704 struct fuse *f = req_fuse_prepare(req);
1705 struct fuse_dirhandle *dh;
1706
1707 dh = (struct fuse_dirhandle *) malloc(sizeof(struct fuse_dirhandle));
1708 if (dh == NULL) {
1709 reply_err(req, -ENOMEM);
Miklos Szerediab974562005-04-07 15:40:21 +00001710 return;
Miklos Szeredi5e183482001-10-31 14:52:35 +00001711 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001712 memset(dh, 0, sizeof(struct fuse_dirhandle));
1713 dh->fuse = f;
1714 dh->contents = NULL;
1715 dh->len = 0;
1716 dh->filled = 0;
1717 dh->nodeid = ino;
Miklos Szeredi38f152c2006-09-03 18:28:52 +00001718 fuse_mutex_init(&dh->lock);
Miklos Szerediab974562005-04-07 15:40:21 +00001719
Miklos Szeredi3a770472005-11-11 21:32:42 +00001720 llfi->fh = (uintptr_t) dh;
Miklos Szerediab974562005-04-07 15:40:21 +00001721
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001722 if (f->op.opendir) {
1723 struct fuse_file_info fi;
1724 char *path;
1725 int err;
1726
1727 memset(&fi, 0, sizeof(fi));
1728 fi.flags = llfi->flags;
1729
1730 err = -ENOENT;
1731 pthread_rwlock_rdlock(&f->tree_lock);
1732 path = get_path(f, ino);
1733 if (path != NULL) {
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001734 err = fuse_compat_opendir(f, req, path, &fi);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00001735 dh->fh = fi.fh;
Miklos Szerediab974562005-04-07 15:40:21 +00001736 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001737 if (!err) {
1738 pthread_mutex_lock(&f->lock);
1739 if (fuse_reply_open(req, llfi) == -ENOENT) {
1740 /* The opendir syscall was interrupted, so it must be
1741 cancelled */
1742 if(f->op.releasedir)
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001743 fuse_do_releasedir(f, req, path, &fi);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001744 pthread_mutex_destroy(&dh->lock);
1745 free(dh);
1746 }
1747 pthread_mutex_unlock(&f->lock);
1748 } else {
1749 reply_err(req, err);
1750 free(dh);
1751 }
Miklos Szerediab974562005-04-07 15:40:21 +00001752 free(path);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001753 pthread_rwlock_unlock(&f->tree_lock);
1754 } else
1755 fuse_reply_open(req, llfi);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001756}
Miklos Szeredib483c932001-10-29 14:57:57 +00001757
Miklos Szeredi1bf64f42006-02-17 15:49:25 +00001758static int extend_contents(struct fuse_dirhandle *dh, unsigned minsize)
1759{
1760 if (minsize > dh->size) {
1761 char *newptr;
1762 unsigned newsize = dh->size;
1763 if (!newsize)
1764 newsize = 1024;
1765 while (newsize < minsize)
1766 newsize *= 2;
1767
1768 newptr = (char *) realloc(dh->contents, newsize);
1769 if (!newptr) {
1770 dh->error = -ENOMEM;
1771 return -1;
1772 }
1773 dh->contents = newptr;
1774 dh->size = newsize;
1775 }
1776 return 0;
1777}
1778
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001779static int fill_dir_common(struct fuse_dirhandle *dh, const char *name,
Miklos Szeredif6e0ec62005-08-03 09:11:06 +00001780 const struct stat *statp, off_t off)
Miklos Szeredia181e612001-11-06 12:03:23 +00001781{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001782 struct stat stbuf;
Miklos Szeredi1bf64f42006-02-17 15:49:25 +00001783 size_t newlen;
Miklos Szeredifb28c5e2004-11-26 12:15:06 +00001784
Miklos Szeredif6e0ec62005-08-03 09:11:06 +00001785 if (statp)
1786 stbuf = *statp;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001787 else {
1788 memset(&stbuf, 0, sizeof(stbuf));
Miklos Szeredie248e4b2005-12-14 16:18:32 +00001789 stbuf.st_ino = FUSE_UNKNOWN_INO;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001790 }
Miklos Szeredia181e612001-11-06 12:03:23 +00001791
Miklos Szeredi659743b2005-12-09 17:41:42 +00001792 if (!dh->fuse->conf.use_ino) {
Miklos Szeredie248e4b2005-12-14 16:18:32 +00001793 stbuf.st_ino = FUSE_UNKNOWN_INO;
Miklos Szeredi659743b2005-12-09 17:41:42 +00001794 if (dh->fuse->conf.readdir_ino) {
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001795 struct node *node;
1796 pthread_mutex_lock(&dh->fuse->lock);
1797 node = lookup_node(dh->fuse, dh->nodeid, name);
1798 if (node)
1799 stbuf.st_ino = (ino_t) node->nodeid;
1800 pthread_mutex_unlock(&dh->fuse->lock);
Miklos Szeredi6ebe2342002-01-06 21:44:16 +00001801 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001802 }
Miklos Szeredi6ebe2342002-01-06 21:44:16 +00001803
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001804 if (off) {
Miklos Szeredi1bf64f42006-02-17 15:49:25 +00001805 if (extend_contents(dh, dh->needlen) == -1)
1806 return 1;
1807
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001808 dh->filled = 0;
Miklos Szeredi1bf64f42006-02-17 15:49:25 +00001809 newlen = dh->len + fuse_add_direntry(dh->req, dh->contents + dh->len,
1810 dh->needlen - dh->len, name,
1811 &stbuf, off);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001812 if (newlen > dh->needlen)
1813 return 1;
Miklos Szeredi1bf64f42006-02-17 15:49:25 +00001814 } else {
1815 newlen = dh->len + fuse_add_direntry(dh->req, NULL, 0, name, NULL, 0);
1816 if (extend_contents(dh, newlen) == -1)
Miklos Szeredic4c12ae2005-10-20 14:48:50 +00001817 return 1;
Miklos Szeredi1bf64f42006-02-17 15:49:25 +00001818
1819 fuse_add_direntry(dh->req, dh->contents + dh->len, dh->size - dh->len,
1820 name, &stbuf, newlen);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001821 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001822 dh->len = newlen;
1823 return 0;
1824}
1825
Miklos Szeredif6e0ec62005-08-03 09:11:06 +00001826static int fill_dir(void *buf, const char *name, const struct stat *stbuf,
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001827 off_t off)
1828{
Miklos Szeredif6e0ec62005-08-03 09:11:06 +00001829 return fill_dir_common((struct fuse_dirhandle *) buf, name, stbuf, off);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001830}
1831
1832static int fill_dir_old(struct fuse_dirhandle *dh, const char *name, int type,
1833 ino_t ino)
1834{
1835 struct stat stbuf;
1836
1837 memset(&stbuf, 0, sizeof(stbuf));
1838 stbuf.st_mode = type << 12;
1839 stbuf.st_ino = ino;
1840
1841 fill_dir_common(dh, name, &stbuf, 0);
1842 return dh->error;
1843}
1844
Miklos Szeredi1bf64f42006-02-17 15:49:25 +00001845static int readdir_fill(struct fuse *f, fuse_req_t req, fuse_ino_t ino,
1846 size_t size, off_t off, struct fuse_dirhandle *dh,
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001847 struct fuse_file_info *fi)
1848{
1849 int err = -ENOENT;
1850 char *path;
1851 pthread_rwlock_rdlock(&f->tree_lock);
1852 path = get_path(f, ino);
1853 if (path != NULL) {
1854 dh->len = 0;
1855 dh->error = 0;
1856 dh->needlen = size;
1857 dh->filled = 1;
Miklos Szeredi1bf64f42006-02-17 15:49:25 +00001858 dh->req = req;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001859 err = -ENOSYS;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001860 if (f->op.readdir) {
1861 struct fuse_intr_data d;
1862 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001863 err = f->op.readdir(path, dh, fill_dir, off, fi);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001864 fuse_finish_interrupt(f, req, &d);
1865 } else if (f->op.getdir) {
1866 struct fuse_intr_data d;
1867 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001868 err = f->op.getdir(path, dh, fill_dir_old);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001869 fuse_finish_interrupt(f, req, &d);
1870 }
Miklos Szeredi1bf64f42006-02-17 15:49:25 +00001871 dh->req = NULL;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001872 if (!err)
1873 err = dh->error;
1874 if (err)
1875 dh->filled = 0;
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001876 free(path);
Miklos Szeredia181e612001-11-06 12:03:23 +00001877 }
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001878 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001879 return err;
1880}
Miklos Szeredie5183742005-02-02 11:14:04 +00001881
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001882static void fuse_readdir(fuse_req_t req, fuse_ino_t ino, size_t size,
1883 off_t off, struct fuse_file_info *llfi)
1884{
1885 struct fuse *f = req_fuse_prepare(req);
1886 struct fuse_file_info fi;
1887 struct fuse_dirhandle *dh = get_dirhandle(llfi, &fi);
1888
1889 pthread_mutex_lock(&dh->lock);
Miklos Szeredi77ccf652005-08-19 14:40:27 +00001890 /* According to SUS, directory contents need to be refreshed on
1891 rewinddir() */
1892 if (!off)
1893 dh->filled = 0;
1894
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001895 if (!dh->filled) {
Miklos Szeredi1bf64f42006-02-17 15:49:25 +00001896 int err = readdir_fill(f, req, ino, size, off, dh, &fi);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001897 if (err) {
1898 reply_err(req, err);
1899 goto out;
1900 }
Miklos Szeredia181e612001-11-06 12:03:23 +00001901 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001902 if (dh->filled) {
1903 if (off < dh->len) {
1904 if (off + size > dh->len)
1905 size = dh->len - off;
1906 } else
1907 size = 0;
1908 } else {
1909 size = dh->len;
1910 off = 0;
1911 }
1912 fuse_reply_buf(req, dh->contents + off, size);
1913 out:
1914 pthread_mutex_unlock(&dh->lock);
1915}
Miklos Szeredia181e612001-11-06 12:03:23 +00001916
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001917static void fuse_releasedir(fuse_req_t req, fuse_ino_t ino,
1918 struct fuse_file_info *llfi)
1919{
1920 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredi9b813af2005-07-21 07:59:37 +00001921 struct fuse_file_info fi;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001922 struct fuse_dirhandle *dh = get_dirhandle(llfi, &fi);
1923 if (f->op.releasedir) {
1924 char *path;
1925
1926 pthread_rwlock_rdlock(&f->tree_lock);
1927 path = get_path(f, ino);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001928 fuse_do_releasedir(f, req, path ? path : "-", &fi);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001929 free(path);
1930 pthread_rwlock_unlock(&f->tree_lock);
1931 }
1932 pthread_mutex_lock(&dh->lock);
1933 pthread_mutex_unlock(&dh->lock);
1934 pthread_mutex_destroy(&dh->lock);
1935 free(dh->contents);
1936 free(dh);
1937 reply_err(req, 0);
1938}
1939
1940static void fuse_fsyncdir(fuse_req_t req, fuse_ino_t ino, int datasync,
1941 struct fuse_file_info *llfi)
1942{
1943 struct fuse *f = req_fuse_prepare(req);
1944 struct fuse_file_info fi;
1945 char *path;
1946 int err;
1947
1948 get_dirhandle(llfi, &fi);
1949
1950 err = -ENOENT;
1951 pthread_rwlock_rdlock(&f->tree_lock);
1952 path = get_path(f, ino);
1953 if (path != NULL) {
1954 err = -ENOSYS;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001955 if (f->op.fsyncdir) {
1956 struct fuse_intr_data d;
1957 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001958 err = f->op.fsyncdir(path, datasync, &fi);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001959 fuse_finish_interrupt(f, req, &d);
1960 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001961 free(path);
1962 }
1963 pthread_rwlock_unlock(&f->tree_lock);
1964 reply_err(req, err);
Miklos Szeredia181e612001-11-06 12:03:23 +00001965}
1966
Miklos Szeredi52cb09d2005-11-07 11:59:00 +00001967static int default_statfs(struct statvfs *buf)
Miklos Szeredi77f39942004-03-25 11:17:52 +00001968{
Miklos Szeredi52cb09d2005-11-07 11:59:00 +00001969 buf->f_namemax = 255;
Miklos Szeredi77f39942004-03-25 11:17:52 +00001970 buf->f_bsize = 512;
1971 return 0;
1972}
1973
Miklos Szeredi3ded1a32006-08-18 18:43:50 +00001974static void fuse_statfs(fuse_req_t req, fuse_ino_t ino)
Miklos Szeredi18e75e42004-02-19 14:23:27 +00001975{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001976 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredi52cb09d2005-11-07 11:59:00 +00001977 struct statvfs buf;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001978 int err;
Mark Glinesd84b39a2002-01-07 16:32:02 +00001979
Miklos Szeredi52cb09d2005-11-07 11:59:00 +00001980 memset(&buf, 0, sizeof(buf));
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001981 if (f->op.statfs) {
Miklos Szeredi3ded1a32006-08-18 18:43:50 +00001982 if (ino && (!f->compat || f->compat >= 26)) {
1983 char *path;
1984 pthread_rwlock_rdlock(&f->tree_lock);
1985 err = -ENOENT;
1986 path = get_path(f, ino);
1987 if (path) {
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001988 err = fuse_do_statfs(f, req, path, &buf);
Miklos Szeredi3ded1a32006-08-18 18:43:50 +00001989 free(path);
1990 }
1991 pthread_rwlock_unlock(&f->tree_lock);
1992 } else
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001993 err = fuse_compat_statfs(f, req, &buf);
Miklos Szeredi52cb09d2005-11-07 11:59:00 +00001994 } else
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001995 err = default_statfs(&buf);
Miklos Szeredi77f39942004-03-25 11:17:52 +00001996
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001997 if (!err)
1998 fuse_reply_statfs(req, &buf);
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001999 else
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002000 reply_err(req, err);
Miklos Szeredi03cebae2004-03-31 10:19:18 +00002001}
2002
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002003static void fuse_setxattr(fuse_req_t req, fuse_ino_t ino, const char *name,
2004 const char *value, size_t size, int flags)
Miklos Szeredi3ed84232004-03-30 15:17:26 +00002005{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002006 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredi3ed84232004-03-30 15:17:26 +00002007 char *path;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002008 int err;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00002009
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002010 err = -ENOENT;
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00002011 pthread_rwlock_rdlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002012 path = get_path(f, ino);
Miklos Szeredi3ed84232004-03-30 15:17:26 +00002013 if (path != NULL) {
Miklos Szerediab974562005-04-07 15:40:21 +00002014 err = -ENOSYS;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002015 if (f->op.setxattr) {
2016 struct fuse_intr_data d;
2017 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002018 err = f->op.setxattr(path, name, value, size, flags);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002019 fuse_finish_interrupt(f, req, &d);
2020 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002021 free(path);
2022 }
2023 pthread_rwlock_unlock(&f->tree_lock);
2024 reply_err(req, err);
2025}
2026
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002027static int common_getxattr(struct fuse *f, fuse_req_t req, fuse_ino_t ino,
2028 const char *name, char *value, size_t size)
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002029{
2030 int err;
2031 char *path;
2032
2033 err = -ENOENT;
2034 pthread_rwlock_rdlock(&f->tree_lock);
2035 path = get_path(f, ino);
2036 if (path != NULL) {
2037 err = -ENOSYS;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002038 if (f->op.getxattr) {
2039 struct fuse_intr_data d;
2040 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002041 err = f->op.getxattr(path, name, value, size);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002042 fuse_finish_interrupt(f, req, &d);
2043 }
Miklos Szerediab974562005-04-07 15:40:21 +00002044 free(path);
2045 }
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00002046 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szerediab974562005-04-07 15:40:21 +00002047 return err;
2048}
2049
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002050static void fuse_getxattr(fuse_req_t req, fuse_ino_t ino, const char *name,
2051 size_t size)
Miklos Szeredi3ead28e2005-01-18 21:23:41 +00002052{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002053 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredi4283ee72005-03-21 12:09:04 +00002054 int res;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002055
2056 if (size) {
2057 char *value = (char *) malloc(size);
2058 if (value == NULL) {
2059 reply_err(req, -ENOMEM);
2060 return;
2061 }
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002062 res = common_getxattr(f, req, ino, name, value, size);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002063 if (res > 0)
2064 fuse_reply_buf(req, value, res);
2065 else
2066 reply_err(req, res);
2067 free(value);
2068 } else {
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002069 res = common_getxattr(f, req, ino, name, NULL, 0);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002070 if (res >= 0)
2071 fuse_reply_xattr(req, res);
2072 else
2073 reply_err(req, res);
2074 }
2075}
2076
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002077static int common_listxattr(struct fuse *f, fuse_req_t req, fuse_ino_t ino,
2078 char *list, size_t size)
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002079{
Miklos Szeredi4283ee72005-03-21 12:09:04 +00002080 char *path;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002081 int err;
Miklos Szeredi4283ee72005-03-21 12:09:04 +00002082
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002083 err = -ENOENT;
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00002084 pthread_rwlock_rdlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002085 path = get_path(f, ino);
Miklos Szeredi4283ee72005-03-21 12:09:04 +00002086 if (path != NULL) {
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002087 err = -ENOSYS;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002088 if (f->op.listxattr) {
2089 struct fuse_intr_data d;
2090 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002091 err = f->op.listxattr(path, list, size);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002092 fuse_finish_interrupt(f, req, &d);
2093 }
Miklos Szeredi4283ee72005-03-21 12:09:04 +00002094 free(path);
2095 }
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00002096 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002097 return err;
Miklos Szeredi4283ee72005-03-21 12:09:04 +00002098}
Miklos Szeredi3ead28e2005-01-18 21:23:41 +00002099
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002100static void fuse_listxattr(fuse_req_t req, fuse_ino_t ino, size_t size)
Miklos Szeredi43696432001-11-18 19:15:05 +00002101{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002102 struct fuse *f = req_fuse_prepare(req);
2103 int res;
2104
2105 if (size) {
2106 char *list = (char *) malloc(size);
2107 if (list == NULL) {
2108 reply_err(req, -ENOMEM);
2109 return;
2110 }
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002111 res = common_listxattr(f, req, ino, list, size);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002112 if (res > 0)
2113 fuse_reply_buf(req, list, res);
2114 else
2115 reply_err(req, res);
2116 free(list);
2117 } else {
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002118 res = common_listxattr(f, req, ino, NULL, 0);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002119 if (res >= 0)
2120 fuse_reply_xattr(req, res);
2121 else
2122 reply_err(req, res);
2123 }
Miklos Szeredi43696432001-11-18 19:15:05 +00002124}
2125
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002126static void fuse_removexattr(fuse_req_t req, fuse_ino_t ino, const char *name)
2127{
2128 struct fuse *f = req_fuse_prepare(req);
2129 char *path;
2130 int err;
2131
2132 err = -ENOENT;
2133 pthread_rwlock_rdlock(&f->tree_lock);
2134 path = get_path(f, ino);
2135 if (path != NULL) {
2136 err = -ENOSYS;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002137 if (f->op.removexattr) {
2138 struct fuse_intr_data d;
2139 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002140 err = f->op.removexattr(path, name);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002141 fuse_finish_interrupt(f, req, &d);
2142 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002143 free(path);
2144 }
2145 pthread_rwlock_unlock(&f->tree_lock);
2146 reply_err(req, err);
2147}
2148
Miklos Szeredi0c59ebf2006-09-10 20:53:36 +00002149static struct lock *locks_conflict(struct node *node, const struct lock *lock)
2150{
2151 struct lock *l;
2152
2153 for (l = node->locks; l; l = l->next)
2154 if (l->owner != lock->owner &&
2155 lock->start <= l->end && l->start <= lock->end &&
2156 (l->type == F_WRLCK || lock->type == F_WRLCK))
2157 break;
2158
2159 return l;
2160}
2161
2162static void delete_lock(struct lock **lockp)
2163{
2164 struct lock *l = *lockp;
2165 *lockp = l->next;
2166 free(l);
2167}
2168
2169static void insert_lock(struct lock **pos, struct lock *lock)
2170{
2171 lock->next = *pos;
2172 *pos = lock;
2173}
2174
2175static int locks_insert(struct node *node, struct lock *lock)
2176{
2177 struct lock **lp;
2178 struct lock *newl1 = NULL;
2179 struct lock *newl2 = NULL;
2180
2181 if (lock->type != F_UNLCK || lock->start != 0 || lock->end != OFFSET_MAX) {
2182 newl1 = malloc(sizeof(struct lock));
2183 newl2 = malloc(sizeof(struct lock));
2184
2185 if (!newl1 || !newl2) {
2186 free(newl1);
2187 free(newl2);
2188 return -ENOLCK;
2189 }
2190 }
2191
2192 for (lp = &node->locks; *lp;) {
2193 struct lock *l = *lp;
2194 if (l->owner != lock->owner)
2195 goto skip;
2196
2197 if (lock->type == l->type) {
2198 if (l->end < lock->start - 1)
2199 goto skip;
2200 if (lock->end < l->start - 1)
2201 break;
2202 if (l->start <= lock->start && lock->end <= l->end)
2203 goto out;
2204 if (l->start < lock->start)
2205 lock->start = l->start;
2206 if (lock->end < l->end)
2207 lock->end = l->end;
2208 goto delete;
2209 } else {
2210 if (l->end < lock->start)
2211 goto skip;
2212 if (lock->end < l->start)
2213 break;
2214 if (lock->start <= l->start && l->end <= lock->end)
2215 goto delete;
2216 if (l->end <= lock->end) {
2217 l->end = lock->start - 1;
2218 goto skip;
2219 }
2220 if (lock->start <= l->start) {
2221 l->start = lock->end + 1;
2222 break;
2223 }
2224 *newl2 = *l;
2225 newl2->start = lock->end + 1;
2226 l->end = lock->start - 1;
2227 insert_lock(&l->next, newl2);
2228 newl2 = NULL;
2229 }
2230 skip:
2231 lp = &l->next;
2232 continue;
2233
2234 delete:
2235 delete_lock(lp);
2236 }
2237 if (lock->type != F_UNLCK) {
2238 *newl1 = *lock;
2239 insert_lock(lp, newl1);
2240 newl1 = NULL;
2241 }
2242out:
2243 free(newl1);
2244 free(newl2);
2245 return 0;
2246}
2247
2248static void flock_to_lock(struct flock *flock, struct lock *lock)
2249{
2250 memset(lock, 0, sizeof(struct lock));
2251 lock->type = flock->l_type;
2252 lock->start = flock->l_start;
2253 lock->end = flock->l_len ? flock->l_start + flock->l_len - 1 : OFFSET_MAX;
2254 lock->pid = flock->l_pid;
2255}
2256
2257static void lock_to_flock(struct lock *lock, struct flock *flock)
2258{
2259 flock->l_type = lock->type;
2260 flock->l_start = lock->start;
2261 flock->l_len = (lock->end == OFFSET_MAX) ? 0 : lock->end - lock->start + 1;
2262 flock->l_pid = lock->pid;
2263}
2264
2265static void fuse_flush(fuse_req_t req, fuse_ino_t ino,
2266 struct fuse_file_info *fi, uint64_t owner)
2267{
2268 struct fuse *f = req_fuse_prepare(req);
2269 char *path;
2270 int err;
2271
2272 err = -ENOENT;
2273 pthread_rwlock_rdlock(&f->tree_lock);
2274 path = get_path(f, ino);
2275 if (path != NULL) {
2276 if (f->conf.debug) {
2277 printf("FLUSH[%llu]\n", (unsigned long long) fi->fh);
2278 fflush(stdout);
2279 }
2280 err = -ENOSYS;
2281 if (f->op.flush) {
2282 struct fuse_intr_data d;
2283 fuse_prepare_interrupt(f, req, &d);
2284 err = f->op.flush(path, fi);
2285 fuse_finish_interrupt(f, req, &d);
2286 }
2287 free(path);
2288 }
2289 if (f->op.lock) {
2290 struct flock lock;
2291 struct lock l;
2292 memset(&lock, 0, sizeof(lock));
2293 lock.l_type = F_UNLCK;
2294 lock.l_whence = SEEK_SET;
2295 fuse_do_lock(f, req, path, fi, F_SETLK, &lock, owner);
2296 flock_to_lock(&lock, &l);
2297 l.owner = owner;
2298 pthread_mutex_lock(&f->lock);
2299 locks_insert(get_node(f, ino), &l);
2300 pthread_mutex_unlock(&f->lock);
2301
2302 /* if op.lock() is defined FLUSH is needed regardless of op.flush() */
2303 if (err == -ENOSYS)
2304 err = 0;
2305 }
2306 pthread_rwlock_unlock(&f->tree_lock);
2307 reply_err(req, err);
2308}
2309
Miklos Szeredi9a5c11d2006-07-30 17:33:40 +00002310static int fuse_lock_common(fuse_req_t req, fuse_ino_t ino,
2311 struct fuse_file_info *fi, struct flock *lock,
2312 uint64_t owner, int cmd)
2313{
2314 struct fuse *f = req_fuse_prepare(req);
2315 char *path;
2316 int err;
2317
2318 err = -ENOENT;
2319 pthread_rwlock_rdlock(&f->tree_lock);
2320 path = get_path(f, ino);
2321 if (path != NULL) {
Miklos Szeredi0c59ebf2006-09-10 20:53:36 +00002322 err = fuse_do_lock(f, req, path, fi, cmd, lock, owner);
Miklos Szeredi9a5c11d2006-07-30 17:33:40 +00002323 free(path);
2324 }
2325 pthread_rwlock_unlock(&f->tree_lock);
2326 return err;
2327}
2328
2329static void fuse_getlk(fuse_req_t req, fuse_ino_t ino,
2330 struct fuse_file_info *fi, struct flock *lock,
2331 uint64_t owner)
2332{
Miklos Szeredi0c59ebf2006-09-10 20:53:36 +00002333 int err;
2334 struct lock l;
2335 struct lock *conflict;
2336 struct fuse *f = req_fuse(req);
2337
2338 flock_to_lock(lock, &l);
2339 l.owner = owner;
2340 pthread_mutex_lock(&f->lock);
2341 conflict = locks_conflict(get_node(f, ino), &l);
2342 if (conflict)
2343 lock_to_flock(conflict, lock);
2344 pthread_mutex_unlock(&f->lock);
2345 if (!conflict)
2346 err = fuse_lock_common(req, ino, fi, lock, owner, F_GETLK);
2347 else
2348 err = 0;
2349
Miklos Szeredi9a5c11d2006-07-30 17:33:40 +00002350 if (!err)
2351 fuse_reply_lock(req, lock);
2352 else
2353 reply_err(req, err);
2354}
2355
2356static void fuse_setlk(fuse_req_t req, fuse_ino_t ino,
2357 struct fuse_file_info *fi, struct flock *lock,
2358 uint64_t owner, int sleep)
2359{
Miklos Szeredi0c59ebf2006-09-10 20:53:36 +00002360 int err = fuse_lock_common(req, ino, fi, lock, owner,
2361 sleep ? F_SETLKW : F_SETLK);
2362 if (!err) {
2363 struct fuse *f = req_fuse(req);
2364 struct lock l;
2365 flock_to_lock(lock, &l);
2366 l.owner = owner;
2367 pthread_mutex_lock(&f->lock);
2368 locks_insert(get_node(f, ino), &l);
2369 pthread_mutex_unlock(&f->lock);
2370 }
2371 reply_err(req, err);
Miklos Szeredi9a5c11d2006-07-30 17:33:40 +00002372}
2373
Miklos Szeredi708b4812006-09-30 16:02:25 +00002374static void fuse_bmap(fuse_req_t req, fuse_ino_t ino, size_t blocksize,
2375 uint64_t idx)
2376{
2377 struct fuse *f = req_fuse_prepare(req);
2378 char *path;
2379 int err;
2380
2381 err = -ENOENT;
2382 pthread_rwlock_rdlock(&f->tree_lock);
2383 path = get_path(f, ino);
2384 if (path != NULL) {
2385 err = -ENOSYS;
2386 if (f->op.bmap)
2387 err = f->op.bmap(path, blocksize, &idx);
2388 free(path);
2389 }
2390 pthread_rwlock_unlock(&f->tree_lock);
2391 if (!err)
2392 fuse_reply_bmap(req, idx);
2393 else
2394 reply_err(req, err);
2395}
2396
Miklos Szeredia1482422005-08-14 23:00:27 +00002397static struct fuse_lowlevel_ops fuse_path_ops = {
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002398 .init = fuse_data_init,
2399 .destroy = fuse_data_destroy,
2400 .lookup = fuse_lookup,
2401 .forget = fuse_forget,
2402 .getattr = fuse_getattr,
2403 .setattr = fuse_setattr,
Miklos Szeredib0b13d12005-10-26 12:53:25 +00002404 .access = fuse_access,
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002405 .readlink = fuse_readlink,
2406 .mknod = fuse_mknod,
2407 .mkdir = fuse_mkdir,
2408 .unlink = fuse_unlink,
2409 .rmdir = fuse_rmdir,
2410 .symlink = fuse_symlink,
2411 .rename = fuse_rename,
2412 .link = fuse_link,
Miklos Szeredid9079a72005-10-26 15:29:06 +00002413 .create = fuse_create,
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002414 .open = fuse_open,
2415 .read = fuse_read,
2416 .write = fuse_write,
2417 .flush = fuse_flush,
2418 .release = fuse_release,
2419 .fsync = fuse_fsync,
2420 .opendir = fuse_opendir,
2421 .readdir = fuse_readdir,
2422 .releasedir = fuse_releasedir,
2423 .fsyncdir = fuse_fsyncdir,
2424 .statfs = fuse_statfs,
2425 .setxattr = fuse_setxattr,
2426 .getxattr = fuse_getxattr,
2427 .listxattr = fuse_listxattr,
2428 .removexattr = fuse_removexattr,
Miklos Szeredi9a5c11d2006-07-30 17:33:40 +00002429 .getlk = fuse_getlk,
2430 .setlk = fuse_setlk,
Miklos Szeredi708b4812006-09-30 16:02:25 +00002431 .bmap = fuse_bmap,
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002432};
2433
Miklos Szeredia1482422005-08-14 23:00:27 +00002434static void free_cmd(struct fuse_cmd *cmd)
2435{
2436 free(cmd->buf);
2437 free(cmd);
2438}
2439
Miklos Szeredif458b8c2004-12-07 16:46:42 +00002440void fuse_process_cmd(struct fuse *f, struct fuse_cmd *cmd)
Miklos Szeredia181e612001-11-06 12:03:23 +00002441{
Miklos Szeredi178451d2005-08-15 13:19:07 +00002442 fuse_session_process(f->se, cmd->buf, cmd->buflen, cmd->ch);
Miklos Szeredifa829b52005-12-02 11:05:41 +00002443 free_cmd(cmd);
Miklos Szeredia181e612001-11-06 12:03:23 +00002444}
2445
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002446int fuse_exited(struct fuse *f)
Miklos Szeredi65cf7c72004-06-30 11:34:56 +00002447{
Miklos Szeredia1482422005-08-14 23:00:27 +00002448 return fuse_session_exited(f->se);
2449}
2450
2451struct fuse_session *fuse_get_session(struct fuse *f)
2452{
2453 return f->se;
2454}
2455
2456static struct fuse_cmd *fuse_alloc_cmd(size_t bufsize)
2457{
2458 struct fuse_cmd *cmd = (struct fuse_cmd *) malloc(sizeof(*cmd));
2459 if (cmd == NULL) {
2460 fprintf(stderr, "fuse: failed to allocate cmd\n");
2461 return NULL;
2462 }
2463 cmd->buf = (char *) malloc(bufsize);
2464 if (cmd->buf == NULL) {
2465 fprintf(stderr, "fuse: failed to allocate read buffer\n");
2466 free(cmd);
2467 return NULL;
2468 }
2469 return cmd;
Miklos Szeredi65cf7c72004-06-30 11:34:56 +00002470}
2471
Miklos Szeredif458b8c2004-12-07 16:46:42 +00002472struct fuse_cmd *fuse_read_cmd(struct fuse *f)
Miklos Szeredi2df1c042001-11-06 15:07:17 +00002473{
Miklos Szeredia1482422005-08-14 23:00:27 +00002474 struct fuse_chan *ch = fuse_session_next_chan(f->se, NULL);
2475 size_t bufsize = fuse_chan_bufsize(ch);
2476 struct fuse_cmd *cmd = fuse_alloc_cmd(bufsize);
2477 if (cmd != NULL) {
Miklos Szeredi8d975f62006-03-17 15:56:05 +00002478 int res = fuse_chan_recv(&ch, cmd->buf, bufsize);
Miklos Szeredia1482422005-08-14 23:00:27 +00002479 if (res <= 0) {
2480 free_cmd(cmd);
Miklos Szeredi5d9ce362006-03-01 12:10:13 +00002481 if (res < 0 && res != -EINTR && res != -EAGAIN)
Miklos Szeredifa829b52005-12-02 11:05:41 +00002482 fuse_exit(f);
Miklos Szeredia1482422005-08-14 23:00:27 +00002483 return NULL;
2484 }
2485 cmd->buflen = res;
Miklos Szeredi178451d2005-08-15 13:19:07 +00002486 cmd->ch = ch;
Miklos Szeredia1482422005-08-14 23:00:27 +00002487 }
2488 return cmd;
Miklos Szeredi2df1c042001-11-06 15:07:17 +00002489}
2490
Miklos Szeredib2cf9562004-09-16 08:42:40 +00002491int fuse_loop(struct fuse *f)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00002492{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002493 if (f)
Miklos Szeredia1482422005-08-14 23:00:27 +00002494 return fuse_session_loop(f->se);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002495 else
Miklos Szeredib2cf9562004-09-16 08:42:40 +00002496 return -1;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00002497}
2498
Miklos Szeredi891b8742004-07-29 09:27:49 +00002499int fuse_invalidate(struct fuse *f, const char *path)
2500{
Miklos Szeredie56818b2004-12-12 11:45:24 +00002501 (void) f;
2502 (void) path;
2503 return -EINVAL;
Miklos Szeredi891b8742004-07-29 09:27:49 +00002504}
2505
Miklos Szeredi0f48a262002-12-05 14:23:01 +00002506void fuse_exit(struct fuse *f)
2507{
Miklos Szeredia1482422005-08-14 23:00:27 +00002508 fuse_session_exit(f->se);
Miklos Szeredi0f48a262002-12-05 14:23:01 +00002509}
2510
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002511struct fuse_context *fuse_get_context(void)
Miklos Szeredi2e50d432001-12-20 12:17:25 +00002512{
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002513 return &fuse_get_context_internal()->ctx;
2514}
2515
2516int fuse_interrupted(void)
2517{
2518 return fuse_req_interrupted(fuse_get_context_internal()->req);
Miklos Szeredid169f312004-09-22 08:48:26 +00002519}
2520
Miklos Szeredif458b8c2004-12-07 16:46:42 +00002521void fuse_set_getcontext_func(struct fuse_context *(*func)(void))
Miklos Szeredid169f312004-09-22 08:48:26 +00002522{
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002523 (void) func;
2524 /* no-op */
Miklos Szeredi2e50d432001-12-20 12:17:25 +00002525}
2526
Miklos Szerediad005972006-01-07 10:14:34 +00002527enum {
2528 KEY_HELP,
Miklos Szerediad005972006-01-07 10:14:34 +00002529};
2530
Miklos Szeredi659743b2005-12-09 17:41:42 +00002531#define FUSE_LIB_OPT(t, p, v) { t, offsetof(struct fuse_config, p), v }
2532
2533static const struct fuse_opt fuse_lib_opts[] = {
Miklos Szerediad005972006-01-07 10:14:34 +00002534 FUSE_OPT_KEY("-h", KEY_HELP),
2535 FUSE_OPT_KEY("--help", KEY_HELP),
Miklos Szeredi065f2222006-01-20 15:15:21 +00002536 FUSE_OPT_KEY("debug", FUSE_OPT_KEY_KEEP),
2537 FUSE_OPT_KEY("-d", FUSE_OPT_KEY_KEEP),
Miklos Szeredi659743b2005-12-09 17:41:42 +00002538 FUSE_LIB_OPT("debug", debug, 1),
Miklos Szeredi95da8602006-01-06 18:29:40 +00002539 FUSE_LIB_OPT("-d", debug, 1),
Miklos Szeredi659743b2005-12-09 17:41:42 +00002540 FUSE_LIB_OPT("hard_remove", hard_remove, 1),
2541 FUSE_LIB_OPT("use_ino", use_ino, 1),
2542 FUSE_LIB_OPT("readdir_ino", readdir_ino, 1),
2543 FUSE_LIB_OPT("direct_io", direct_io, 1),
2544 FUSE_LIB_OPT("kernel_cache", kernel_cache, 1),
Miklos Szeredi320abe42006-01-30 18:14:51 +00002545 FUSE_LIB_OPT("auto_cache", auto_cache, 1),
2546 FUSE_LIB_OPT("noauto_cache", auto_cache, 0),
Miklos Szeredi659743b2005-12-09 17:41:42 +00002547 FUSE_LIB_OPT("umask=", set_mode, 1),
2548 FUSE_LIB_OPT("umask=%o", umask, 0),
2549 FUSE_LIB_OPT("uid=", set_uid, 1),
2550 FUSE_LIB_OPT("uid=%d", uid, 0),
2551 FUSE_LIB_OPT("gid=", set_gid, 1),
2552 FUSE_LIB_OPT("gid=%d", gid, 0),
2553 FUSE_LIB_OPT("entry_timeout=%lf", entry_timeout, 0),
2554 FUSE_LIB_OPT("attr_timeout=%lf", attr_timeout, 0),
Miklos Szeredi6e806e92006-02-16 16:59:39 +00002555 FUSE_LIB_OPT("ac_attr_timeout=%lf", ac_attr_timeout, 0),
2556 FUSE_LIB_OPT("ac_attr_timeout=", ac_attr_timeout_set, 1),
Miklos Szeredi659743b2005-12-09 17:41:42 +00002557 FUSE_LIB_OPT("negative_timeout=%lf", negative_timeout, 0),
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002558 FUSE_LIB_OPT("intr", intr, 1),
2559 FUSE_LIB_OPT("intr_signal=%d", intr_signal, 0),
Miklos Szeredi659743b2005-12-09 17:41:42 +00002560 FUSE_OPT_END
2561};
2562
Miklos Szerediad005972006-01-07 10:14:34 +00002563static void fuse_lib_help(void)
2564{
2565 fprintf(stderr,
Miklos Szeredi06091462006-02-16 16:38:34 +00002566" -o hard_remove immediate removal (don't hide files)\n"
2567" -o use_ino let filesystem set inode numbers\n"
2568" -o readdir_ino try to fill in d_ino in readdir\n"
2569" -o direct_io use direct I/O\n"
2570" -o kernel_cache cache files in kernel\n"
2571" -o [no]auto_cache enable caching based on modification times\n"
2572" -o umask=M set file permissions (octal)\n"
2573" -o uid=N set file owner\n"
2574" -o gid=N set file group\n"
2575" -o entry_timeout=T cache timeout for names (1.0s)\n"
2576" -o negative_timeout=T cache timeout for deleted names (0.0s)\n"
Miklos Szeredi6e806e92006-02-16 16:59:39 +00002577" -o attr_timeout=T cache timeout for attributes (1.0s)\n"
2578" -o ac_attr_timeout=T auto cache timeout for attributes (attr_timeout)\n"
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002579" -o intr allow requests to be interrupted\n"
2580" -o intr_signal=NUM signal to send on interrupt (%i)\n"
2581"\n", FUSE_DEFAULT_INTR_SIGNAL);
Miklos Szerediad005972006-01-07 10:14:34 +00002582}
2583
2584static int fuse_lib_opt_proc(void *data, const char *arg, int key,
2585 struct fuse_args *outargs)
2586{
2587 (void) data; (void) arg; (void) outargs;
2588
2589 if (key == KEY_HELP)
2590 fuse_lib_help();
2591
2592 return 1;
2593}
2594
2595
Miklos Szeredibd7661b2004-07-23 17:16:29 +00002596int fuse_is_lib_option(const char *opt)
2597{
Miklos Szeredi659743b2005-12-09 17:41:42 +00002598 return fuse_lowlevel_is_lib_option(opt) ||
2599 fuse_opt_match(fuse_lib_opts, opt);
Miklos Szeredibd7661b2004-07-23 17:16:29 +00002600}
2601
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002602static int fuse_init_intr_signal(int signum, int *installed)
2603{
2604 struct sigaction old_sa;
2605
2606 if (sigaction(signum, NULL, &old_sa) == -1) {
2607 perror("fuse: cannot get old signal handler");
2608 return -1;
2609 }
2610
2611 if (old_sa.sa_handler == SIG_DFL) {
2612 struct sigaction sa;
2613
2614 memset(&sa, 0, sizeof(struct sigaction));
2615 sa.sa_handler = fuse_intr_sighandler;
Miklos Szeredi0c59ebf2006-09-10 20:53:36 +00002616 sigemptyset(&sa.sa_mask);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002617
2618 if (sigaction(signum, &sa, NULL) == -1) {
2619 perror("fuse: cannot set interrupt signal handler");
2620 return -1;
2621 }
2622 *installed = 1;
2623 }
2624 return 0;
2625}
2626
Miklos Szeredi349bdda2006-09-07 11:48:16 +00002627static void fuse_restore_intr_signal(int signum)
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002628{
Miklos Szeredi349bdda2006-09-07 11:48:16 +00002629 struct sigaction sa;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002630
Miklos Szeredi349bdda2006-09-07 11:48:16 +00002631 memset(&sa, 0, sizeof(struct sigaction));
2632 sa.sa_handler = SIG_DFL;
2633 sigaction(signum, &sa, NULL);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002634}
2635
Miklos Szeredi6f385412006-03-17 15:05:40 +00002636struct fuse *fuse_new_common(struct fuse_chan *ch, struct fuse_args *args,
Miklos Szeredi0b6a0ad2004-12-04 00:40:50 +00002637 const struct fuse_operations *op,
Miklos Szeredi6f385412006-03-17 15:05:40 +00002638 size_t op_size, void *user_data, int compat)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00002639{
Miklos Szeredi97c61e92001-11-07 12:09:43 +00002640 struct fuse *f;
2641 struct node *root;
Miklos Szeredi9a5c11d2006-07-30 17:33:40 +00002642 struct fuse_lowlevel_ops llop = fuse_path_ops;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00002643
Miklos Szeredi0f62d722005-01-04 12:45:54 +00002644 if (sizeof(struct fuse_operations) < op_size) {
Miklos Szeredi0b6a0ad2004-12-04 00:40:50 +00002645 fprintf(stderr, "fuse: warning: library too old, some operations may not not work\n");
Miklos Szeredi0f62d722005-01-04 12:45:54 +00002646 op_size = sizeof(struct fuse_operations);
Miklos Szeredi0b6a0ad2004-12-04 00:40:50 +00002647 }
2648
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002649 if (fuse_create_context_key() == -1)
2650 goto out;
2651
Miklos Szeredi97c61e92001-11-07 12:09:43 +00002652 f = (struct fuse *) calloc(1, sizeof(struct fuse));
Miklos Szeredie56818b2004-12-12 11:45:24 +00002653 if (f == NULL) {
2654 fprintf(stderr, "fuse: failed to allocate fuse object\n");
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002655 goto out_delete_context_key;
Miklos Szeredie56818b2004-12-12 11:45:24 +00002656 }
Miklos Szeredi2df1c042001-11-06 15:07:17 +00002657
Miklos Szeredi6f385412006-03-17 15:05:40 +00002658 f->user_data = user_data;
Miklos Szeredi659743b2005-12-09 17:41:42 +00002659 f->conf.entry_timeout = 1.0;
2660 f->conf.attr_timeout = 1.0;
2661 f->conf.negative_timeout = 0.0;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002662 f->conf.intr_signal = FUSE_DEFAULT_INTR_SIGNAL;
Miklos Szeredi6c0209a2005-08-02 13:31:28 +00002663
Miklos Szerediad005972006-01-07 10:14:34 +00002664 if (fuse_opt_parse(args, &f->conf, fuse_lib_opts, fuse_lib_opt_proc) == -1)
Miklos Szeredi659743b2005-12-09 17:41:42 +00002665 goto out_free;
Miklos Szeredib2cf9562004-09-16 08:42:40 +00002666
Miklos Szeredi6e806e92006-02-16 16:59:39 +00002667 if (!f->conf.ac_attr_timeout_set)
2668 f->conf.ac_attr_timeout = f->conf.attr_timeout;
2669
Miklos Szeredi659743b2005-12-09 17:41:42 +00002670#ifdef __FreeBSD__
2671 /*
2672 * In FreeBSD, we always use these settings as inode numbers are needed to
2673 * make getcwd(3) work.
2674 */
Miklos Szeredi76fc3de2005-12-12 09:34:45 +00002675 f->conf.readdir_ino = 1;
Miklos Szeredi659743b2005-12-09 17:41:42 +00002676#endif
2677
Miklos Szeredi065f2222006-01-20 15:15:21 +00002678 if (compat && compat <= 25) {
2679 if (fuse_sync_compat_args(args) == -1)
2680 goto out_free;
2681 }
2682
Miklos Szeredi9a5c11d2006-07-30 17:33:40 +00002683 memcpy(&f->op, op, op_size);
2684 if (!f->op.lock) {
2685 llop.getlk = NULL;
2686 llop.setlk = NULL;
2687 }
2688
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002689 f->se = fuse_lowlevel_new_common(args, &llop, sizeof(llop), f);
Miklos Szeredia1482422005-08-14 23:00:27 +00002690 if (f->se == NULL)
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002691 goto out_free;
Miklos Szeredi2bb750e2005-10-03 14:54:24 +00002692
Miklos Szeredia1482422005-08-14 23:00:27 +00002693 fuse_session_add_chan(f->se, ch);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002694
Miklos Szeredi97c61e92001-11-07 12:09:43 +00002695 f->ctr = 0;
Miklos Szeredi76f65782004-02-19 16:55:40 +00002696 f->generation = 0;
Miklos Szeredifff56ab2001-11-16 10:12:59 +00002697 /* FIXME: Dynamic hash table */
Miklos Szeredi97c61e92001-11-07 12:09:43 +00002698 f->name_table_size = 14057;
2699 f->name_table = (struct node **)
2700 calloc(1, sizeof(struct node *) * f->name_table_size);
Miklos Szeredie56818b2004-12-12 11:45:24 +00002701 if (f->name_table == NULL) {
2702 fprintf(stderr, "fuse: memory allocation failed\n");
Miklos Szeredia1482422005-08-14 23:00:27 +00002703 goto out_free_session;
Miklos Szeredie56818b2004-12-12 11:45:24 +00002704 }
Miklos Szeredib2cf9562004-09-16 08:42:40 +00002705
Miklos Szeredia13d9002004-11-02 17:32:03 +00002706 f->id_table_size = 14057;
2707 f->id_table = (struct node **)
2708 calloc(1, sizeof(struct node *) * f->id_table_size);
Miklos Szeredie56818b2004-12-12 11:45:24 +00002709 if (f->id_table == NULL) {
2710 fprintf(stderr, "fuse: memory allocation failed\n");
Miklos Szeredib2cf9562004-09-16 08:42:40 +00002711 goto out_free_name_table;
Miklos Szeredie56818b2004-12-12 11:45:24 +00002712 }
Miklos Szeredib2cf9562004-09-16 08:42:40 +00002713
Miklos Szeredi38f152c2006-09-03 18:28:52 +00002714 fuse_mutex_init(&f->lock);
Miklos Szeredid0a777a2006-04-05 07:18:00 +00002715 pthread_rwlock_init(&f->tree_lock, NULL);
Miklos Szeredi0b6a0ad2004-12-04 00:40:50 +00002716 f->compat = compat;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00002717
Miklos Szeredi97c61e92001-11-07 12:09:43 +00002718 root = (struct node *) calloc(1, sizeof(struct node));
Miklos Szeredie56818b2004-12-12 11:45:24 +00002719 if (root == NULL) {
2720 fprintf(stderr, "fuse: memory allocation failed\n");
Miklos Szeredia13d9002004-11-02 17:32:03 +00002721 goto out_free_id_table;
Miklos Szeredie56818b2004-12-12 11:45:24 +00002722 }
Miklos Szeredib2cf9562004-09-16 08:42:40 +00002723
Miklos Szeredi97c61e92001-11-07 12:09:43 +00002724 root->name = strdup("/");
Miklos Szeredie56818b2004-12-12 11:45:24 +00002725 if (root->name == NULL) {
2726 fprintf(stderr, "fuse: memory allocation failed\n");
Miklos Szeredib2cf9562004-09-16 08:42:40 +00002727 goto out_free_root;
Miklos Szeredie56818b2004-12-12 11:45:24 +00002728 }
Miklos Szeredib2cf9562004-09-16 08:42:40 +00002729
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002730 if (f->conf.intr &&
2731 fuse_init_intr_signal(f->conf.intr_signal, &f->intr_installed) == -1)
2732 goto out_free_root_name;
2733
Miklos Szeredi97c61e92001-11-07 12:09:43 +00002734 root->parent = 0;
Miklos Szeredia13d9002004-11-02 17:32:03 +00002735 root->nodeid = FUSE_ROOT_ID;
Miklos Szeredi76f65782004-02-19 16:55:40 +00002736 root->generation = 0;
Miklos Szeredi0f62d722005-01-04 12:45:54 +00002737 root->refctr = 1;
Miklos Szeredi38009022005-05-08 19:47:22 +00002738 root->nlookup = 1;
Miklos Szeredia13d9002004-11-02 17:32:03 +00002739 hash_id(f, root);
Miklos Szeredi97c61e92001-11-07 12:09:43 +00002740
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00002741 return f;
Miklos Szeredib2cf9562004-09-16 08:42:40 +00002742
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002743 out_free_root_name:
2744 free(root->name);
Miklos Szeredib2cf9562004-09-16 08:42:40 +00002745 out_free_root:
2746 free(root);
Miklos Szeredia13d9002004-11-02 17:32:03 +00002747 out_free_id_table:
2748 free(f->id_table);
Miklos Szeredib2cf9562004-09-16 08:42:40 +00002749 out_free_name_table:
2750 free(f->name_table);
Miklos Szeredia1482422005-08-14 23:00:27 +00002751 out_free_session:
2752 fuse_session_destroy(f->se);
Miklos Szeredib2cf9562004-09-16 08:42:40 +00002753 out_free:
2754 free(f);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002755 out_delete_context_key:
2756 fuse_delete_context_key();
Miklos Szeredib2cf9562004-09-16 08:42:40 +00002757 out:
Miklos Szeredib2cf9562004-09-16 08:42:40 +00002758 return NULL;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00002759}
2760
Miklos Szeredi6f385412006-03-17 15:05:40 +00002761struct fuse *fuse_new(struct fuse_chan *ch, struct fuse_args *args,
2762 const struct fuse_operations *op, size_t op_size,
2763 void *user_data)
Miklos Szeredi0b6a0ad2004-12-04 00:40:50 +00002764{
Miklos Szeredi6f385412006-03-17 15:05:40 +00002765 return fuse_new_common(ch, args, op, op_size, user_data, 0);
Miklos Szeredi0b6a0ad2004-12-04 00:40:50 +00002766}
2767
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00002768void fuse_destroy(struct fuse *f)
2769{
Miklos Szeredi97c61e92001-11-07 12:09:43 +00002770 size_t i;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002771 struct fuse_context_i *c = fuse_get_context_internal();
2772
2773 if (f->conf.intr && f->intr_installed)
2774 fuse_restore_intr_signal(f->conf.intr_signal);
Miklos Szerediad519562006-07-31 11:07:40 +00002775
2776 memset(c, 0, sizeof(*c));
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002777 c->ctx.fuse = f;
2778 c->ctx.private_data = f->user_data;
Miklos Szerediad519562006-07-31 11:07:40 +00002779
Miklos Szeredia13d9002004-11-02 17:32:03 +00002780 for (i = 0; i < f->id_table_size; i++) {
Miklos Szeredi97c61e92001-11-07 12:09:43 +00002781 struct node *node;
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00002782
Miklos Szeredia13d9002004-11-02 17:32:03 +00002783 for (node = f->id_table[i]; node != NULL; node = node->id_next) {
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00002784 if (node->is_hidden) {
Miklos Szeredia13d9002004-11-02 17:32:03 +00002785 char *path = get_path(f, node->nodeid);
Miklos Szeredi21019c92005-05-09 11:22:41 +00002786 if (path) {
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00002787 f->op.unlink(path);
Miklos Szeredi21019c92005-05-09 11:22:41 +00002788 free(path);
2789 }
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00002790 }
2791 }
2792 }
Miklos Szeredia13d9002004-11-02 17:32:03 +00002793 for (i = 0; i < f->id_table_size; i++) {
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00002794 struct node *node;
Miklos Szeredi97c61e92001-11-07 12:09:43 +00002795 struct node *next;
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00002796
Miklos Szeredia13d9002004-11-02 17:32:03 +00002797 for (node = f->id_table[i]; node != NULL; node = next) {
2798 next = node->id_next;
Miklos Szeredi97c61e92001-11-07 12:09:43 +00002799 free_node(node);
2800 }
2801 }
Miklos Szeredia13d9002004-11-02 17:32:03 +00002802 free(f->id_table);
Miklos Szeredi97c61e92001-11-07 12:09:43 +00002803 free(f->name_table);
Miklos Szeredia181e612001-11-06 12:03:23 +00002804 pthread_mutex_destroy(&f->lock);
Miklos Szeredi55a84102006-06-06 10:16:38 +00002805 pthread_rwlock_destroy(&f->tree_lock);
Miklos Szeredia1482422005-08-14 23:00:27 +00002806 fuse_session_destroy(f->se);
Miklos Szeredi97c61e92001-11-07 12:09:43 +00002807 free(f);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002808 fuse_delete_context_key();
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00002809}
Miklos Szeredi0b6a0ad2004-12-04 00:40:50 +00002810
Miklos Szeredieafdf422006-09-22 19:30:17 +00002811#include "fuse_common_compat.h"
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002812#include "fuse_compat.h"
2813
Miklos Szeredi6f385412006-03-17 15:05:40 +00002814static struct fuse *fuse_new_common_compat25(int fd, struct fuse_args *args,
2815 const struct fuse_operations *op,
2816 size_t op_size, int compat)
2817{
2818 struct fuse *f = NULL;
2819 struct fuse_chan *ch = fuse_kern_chan_new(fd);
2820
2821 if (ch)
2822 f = fuse_new_common(ch, args, op, op_size, NULL, compat);
2823
2824 return f;
2825}
2826
Miklos Szeredi065f2222006-01-20 15:15:21 +00002827#ifndef __FreeBSD__
2828
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002829static int fuse_compat_open(struct fuse *f, fuse_req_t req, char *path,
2830 struct fuse_file_info *fi)
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002831{
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002832 int err;
2833 struct fuse_intr_data d;
Miklos Szeredi065f2222006-01-20 15:15:21 +00002834 if (!f->compat || f->compat >= 25)
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002835 err = fuse_do_open(f, req, path, fi);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002836 else if (f->compat == 22) {
Miklos Szeredieafdf422006-09-22 19:30:17 +00002837 struct fuse_file_info_compat tmp;
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002838 memcpy(&tmp, fi, sizeof(tmp));
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002839 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002840 err = ((struct fuse_operations_compat22 *) &f->op)->open(path, &tmp);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002841 fuse_finish_interrupt(f, req, &d);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002842 memcpy(fi, &tmp, sizeof(tmp));
2843 fi->fh = tmp.fh;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002844 } else {
2845 fuse_prepare_interrupt(f, req, &d);
2846 err =
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002847 ((struct fuse_operations_compat2 *) &f->op)->open(path, fi->flags);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002848 fuse_finish_interrupt(f, req, &d);
2849 }
2850 return err;
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002851}
2852
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002853static void fuse_compat_release(struct fuse *f, fuse_req_t req, char *path,
2854 struct fuse_file_info *fi)
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002855{
2856 if (!f->compat || f->compat >= 22)
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002857 fuse_do_release(f, req, path ? path : "-", fi);
2858 else if (path) {
2859 struct fuse_intr_data d;
2860 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002861 ((struct fuse_operations_compat2 *) &f->op)->release(path, fi->flags);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002862 fuse_finish_interrupt(f, req, &d);
2863 }
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002864}
2865
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002866static int fuse_compat_opendir(struct fuse *f, fuse_req_t req, char *path,
2867 struct fuse_file_info *fi)
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002868{
Miklos Szeredi065f2222006-01-20 15:15:21 +00002869 if (!f->compat || f->compat >= 25) {
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002870 return fuse_do_opendir(f, req, path, fi);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002871 } else {
2872 int err;
Miklos Szeredieafdf422006-09-22 19:30:17 +00002873 struct fuse_file_info_compat tmp;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002874 struct fuse_intr_data d;
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002875 memcpy(&tmp, fi, sizeof(tmp));
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002876 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002877 err = ((struct fuse_operations_compat22 *) &f->op)->opendir(path, &tmp);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002878 fuse_finish_interrupt(f, req, &d);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002879 memcpy(fi, &tmp, sizeof(tmp));
2880 fi->fh = tmp.fh;
2881 return err;
2882 }
2883}
2884
2885static void convert_statfs_compat(struct fuse_statfs_compat1 *compatbuf,
2886 struct statvfs *stbuf)
2887{
2888 stbuf->f_bsize = compatbuf->block_size;
2889 stbuf->f_blocks = compatbuf->blocks;
2890 stbuf->f_bfree = compatbuf->blocks_free;
2891 stbuf->f_bavail = compatbuf->blocks_free;
2892 stbuf->f_files = compatbuf->files;
2893 stbuf->f_ffree = compatbuf->files_free;
2894 stbuf->f_namemax = compatbuf->namelen;
2895}
2896
2897static void convert_statfs_old(struct statfs *oldbuf, struct statvfs *stbuf)
2898{
2899 stbuf->f_bsize = oldbuf->f_bsize;
2900 stbuf->f_blocks = oldbuf->f_blocks;
2901 stbuf->f_bfree = oldbuf->f_bfree;
2902 stbuf->f_bavail = oldbuf->f_bavail;
2903 stbuf->f_files = oldbuf->f_files;
2904 stbuf->f_ffree = oldbuf->f_ffree;
2905 stbuf->f_namemax = oldbuf->f_namelen;
2906}
2907
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002908static int fuse_compat_statfs(struct fuse *f, fuse_req_t req,
2909 struct statvfs *buf)
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002910{
2911 int err;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002912 struct fuse_intr_data d;
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002913
Miklos Szeredi065f2222006-01-20 15:15:21 +00002914 if (!f->compat || f->compat >= 25) {
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002915 err = fuse_do_statfs(f, req, "/", buf);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002916 } else if (f->compat > 11) {
2917 struct statfs oldbuf;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002918 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002919 err = ((struct fuse_operations_compat22 *) &f->op)->statfs("/", &oldbuf);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002920 fuse_finish_interrupt(f, req, &d);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002921 if (!err)
2922 convert_statfs_old(&oldbuf, buf);
2923 } else {
2924 struct fuse_statfs_compat1 compatbuf;
2925 memset(&compatbuf, 0, sizeof(struct fuse_statfs_compat1));
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_compat1 *) &f->op)->statfs(&compatbuf);
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_compat(&compatbuf, buf);
2931 }
2932 return err;
2933}
2934
Miklos Szeredi95da8602006-01-06 18:29:40 +00002935static struct fuse *fuse_new_common_compat(int fd, const char *opts,
2936 const struct fuse_operations *op,
2937 size_t op_size, int compat)
2938{
2939 struct fuse *f;
2940 struct fuse_args args = FUSE_ARGS_INIT(0, NULL);
2941
2942 if (opts &&
2943 (fuse_opt_add_arg(&args, "") == -1 ||
2944 fuse_opt_add_arg(&args, "-o") == -1 ||
2945 fuse_opt_add_arg(&args, opts) == -1)) {
2946 fuse_opt_free_args(&args);
2947 return NULL;
2948 }
Miklos Szeredi6f385412006-03-17 15:05:40 +00002949 f = fuse_new_common_compat25(fd, &args, op, op_size, compat);
Miklos Szeredi95da8602006-01-06 18:29:40 +00002950 fuse_opt_free_args(&args);
2951
2952 return f;
2953}
2954
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002955struct fuse *fuse_new_compat22(int fd, const char *opts,
2956 const struct fuse_operations_compat22 *op,
2957 size_t op_size)
2958{
Miklos Szeredi95da8602006-01-06 18:29:40 +00002959 return fuse_new_common_compat(fd, opts, (struct fuse_operations *) op,
2960 op_size, 22);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002961}
2962
2963struct fuse *fuse_new_compat2(int fd, const char *opts,
2964 const struct fuse_operations_compat2 *op)
2965{
Miklos Szeredi95da8602006-01-06 18:29:40 +00002966 return fuse_new_common_compat(fd, opts, (struct fuse_operations *) op,
2967 sizeof(struct fuse_operations_compat2), 21);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002968}
2969
2970struct fuse *fuse_new_compat1(int fd, int flags,
2971 const struct fuse_operations_compat1 *op)
2972{
2973 const char *opts = NULL;
2974 if (flags & FUSE_DEBUG_COMPAT1)
2975 opts = "debug";
Miklos Szeredi95da8602006-01-06 18:29:40 +00002976 return fuse_new_common_compat(fd, opts, (struct fuse_operations *) op,
2977 sizeof(struct fuse_operations_compat1), 11);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002978}
2979
Miklos Szeredif458b8c2004-12-07 16:46:42 +00002980__asm__(".symver fuse_exited,__fuse_exited@");
2981__asm__(".symver fuse_process_cmd,__fuse_process_cmd@");
2982__asm__(".symver fuse_read_cmd,__fuse_read_cmd@");
2983__asm__(".symver fuse_set_getcontext_func,__fuse_set_getcontext_func@");
2984__asm__(".symver fuse_new_compat2,fuse_new@");
Miklos Szeredi3a770472005-11-11 21:32:42 +00002985__asm__(".symver fuse_new_compat22,fuse_new@FUSE_2.2");
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002986
2987#else /* __FreeBSD__ */
2988
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002989static int fuse_compat_open(struct fuse *f, fuse_req_t req, char *path,
2990 struct fuse_file_info *fi)
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002991{
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002992 return fuse_do_open(f, req, path, fi);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002993}
2994
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002995static void fuse_compat_release(struct fuse *f, fuse_req_t req, char *path,
2996 struct fuse_file_info *fi)
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002997{
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002998 fuse_do_release(f, req, path ? path : "-", fi);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002999}
3000
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00003001static int fuse_compat_opendir(struct fuse *f, fuse_req_t req, char *path,
3002 struct fuse_file_info *fi)
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00003003{
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00003004 return fuse_do_opendir(f, req, path, fi);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00003005}
3006
Csaba Henk3e3a1252006-09-24 14:53:29 +00003007static int fuse_compat_statfs(struct fuse *f, fuse_req_t req, struct statvfs *buf)
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00003008{
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00003009 return fuse_do_statfs(f, req, "/", buf);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00003010}
3011
3012#endif /* __FreeBSD__ */
Miklos Szeredi065f2222006-01-20 15:15:21 +00003013
3014struct fuse *fuse_new_compat25(int fd, struct fuse_args *args,
3015 const struct fuse_operations_compat25 *op,
3016 size_t op_size)
3017{
Miklos Szeredi6f385412006-03-17 15:05:40 +00003018 return fuse_new_common_compat25(fd, args, (struct fuse_operations *) op,
3019 op_size, 25);
Miklos Szeredi065f2222006-01-20 15:15:21 +00003020}
3021
3022__asm__(".symver fuse_new_compat25,fuse_new@FUSE_2.5");