blob: 72fd59a02ac894b591a0d1cd3add4630a3d73e13 [file] [log] [blame]
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001/*
2 FUSE: Filesystem in Userspace
Miklos Szeredi149f6072005-01-10 12:29:28 +00003 Copyright (C) 2001-2005 Miklos Szeredi <miklos@szeredi.hu>
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00004
Miklos Szeredi8b39a9f2002-10-25 12:41:16 +00005 This program can be distributed under the terms of the GNU LGPL.
6 See the file COPYING.LIB
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00007*/
8
Miklos Szeredicb264512004-06-23 18:52:50 +00009#include <config.h>
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000010#include "fuse_i.h"
Miklos Szeredi0f62d722005-01-04 12:45:54 +000011#include "fuse_compat.h"
Miklos Szeredib9b94cd2004-12-01 18:56:39 +000012#include "fuse_kernel.h"
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000013
Miklos Szeredi0f62d722005-01-04 12:45:54 +000014#include <stdio.h>
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000015#include <string.h>
Miklos Szeredi97c61e92001-11-07 12:09:43 +000016#include <stdlib.h>
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000017#include <unistd.h>
Miklos Szeredi97c61e92001-11-07 12:09:43 +000018#include <limits.h>
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000019#include <errno.h>
Miklos Szeredi0f62d722005-01-04 12:45:54 +000020#include <assert.h>
21#include <stdint.h>
Miklos Szeredi019b4e92001-12-26 18:08:09 +000022#include <sys/param.h>
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000023
Miklos Szeredi0f62d722005-01-04 12:45:54 +000024/* FUSE flags: */
25
26/** Enable debuging output */
27#define FUSE_DEBUG (1 << 1)
28
29/** If a file is removed but it's still open, don't hide the file but
30 remove it immediately */
31#define FUSE_HARD_REMOVE (1 << 2)
32
33/** Use st_ino field in getattr instead of generating inode numbers */
34#define FUSE_USE_INO (1 << 3)
35
Miklos Szeredi0b6a0ad2004-12-04 00:40:50 +000036#define FUSE_KERNEL_MINOR_VERSION_NEED 1
Miklos Szeredia25d4c22004-11-23 22:32:16 +000037#define FUSE_VERSION_FILE_OLD "/proc/fs/fuse/version"
Miklos Szeredi162bcbb2004-11-29 23:43:44 +000038#define FUSE_VERSION_FILE_NEW "/sys/fs/fuse/version"
Miklos Szeredia25d4c22004-11-23 22:32:16 +000039#define FUSE_DEV_OLD "/proc/fs/fuse/dev"
40
Miklos Szeredi97c61e92001-11-07 12:09:43 +000041#define FUSE_MAX_PATH 4096
Miklos Szeredi6bf8b682002-10-28 08:49:39 +000042#define PARAM(inarg) (((char *)(inarg)) + sizeof(*inarg))
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000043
Miklos Szeredi254d5ed2004-03-02 11:11:24 +000044#define ENTRY_REVALIDATE_TIME 1 /* sec */
45#define ATTR_REVALIDATE_TIME 1 /* sec */
46
Miklos Szeredi0f62d722005-01-04 12:45:54 +000047
48struct node {
49 struct node *name_next;
50 struct node *id_next;
51 nodeid_t nodeid;
52 unsigned int generation;
53 int refctr;
54 nodeid_t parent;
55 char *name;
56 uint64_t version;
57 int open_count;
58 int is_hidden;
59};
60
61struct fuse_dirhandle {
62 struct fuse *fuse;
Miklos Szeredib92d9782005-02-07 16:10:49 +000063 unsigned char *contents;
64 unsigned len;
Miklos Szeredi3ead28e2005-01-18 21:23:41 +000065 int filled;
Miklos Szeredi0f62d722005-01-04 12:45:54 +000066};
67
68struct fuse_cmd {
69 char *buf;
70 size_t buflen;
71};
72
73
Miklos Szeredid169f312004-09-22 08:48:26 +000074static struct fuse_context *(*fuse_getcontext)(void) = NULL;
75
Miklos Szeredi3ead28e2005-01-18 21:23:41 +000076/* Compatibility with kernel ABI version 5.1 */
77struct fuse_getdir_out {
78 __u32 fd;
79};
80
Miklos Szeredie5183742005-02-02 11:14:04 +000081#define FUSE_GETDIR 7
Miklos Szeredi3ead28e2005-01-18 21:23:41 +000082
Miklos Szeredic8ba2372002-12-10 12:26:00 +000083static const char *opname(enum fuse_opcode opcode)
84{
Miklos Szeredie5183742005-02-02 11:14:04 +000085 switch (opcode) {
Miklos Szeredi3ed84232004-03-30 15:17:26 +000086 case FUSE_LOOKUP: return "LOOKUP";
87 case FUSE_FORGET: return "FORGET";
88 case FUSE_GETATTR: return "GETATTR";
89 case FUSE_SETATTR: return "SETATTR";
90 case FUSE_READLINK: return "READLINK";
91 case FUSE_SYMLINK: return "SYMLINK";
92 case FUSE_GETDIR: return "GETDIR";
93 case FUSE_MKNOD: return "MKNOD";
94 case FUSE_MKDIR: return "MKDIR";
95 case FUSE_UNLINK: return "UNLINK";
96 case FUSE_RMDIR: return "RMDIR";
97 case FUSE_RENAME: return "RENAME";
98 case FUSE_LINK: return "LINK";
99 case FUSE_OPEN: return "OPEN";
100 case FUSE_READ: return "READ";
101 case FUSE_WRITE: return "WRITE";
102 case FUSE_STATFS: return "STATFS";
Miklos Szeredi99f20742004-05-19 08:01:10 +0000103 case FUSE_FLUSH: return "FLUSH";
Miklos Szeredi3ed84232004-03-30 15:17:26 +0000104 case FUSE_RELEASE: return "RELEASE";
105 case FUSE_FSYNC: return "FSYNC";
106 case FUSE_SETXATTR: return "SETXATTR";
107 case FUSE_GETXATTR: return "GETXATTR";
108 case FUSE_LISTXATTR: return "LISTXATTR";
109 case FUSE_REMOVEXATTR: return "REMOVEXATTR";
Miklos Szeredi3f0005f2005-01-04 19:24:31 +0000110 case FUSE_INIT: return "INIT";
Miklos Szeredi3ead28e2005-01-18 21:23:41 +0000111 case FUSE_OPENDIR: return "OPENDIR";
112 case FUSE_READDIR: return "READDIR";
113 case FUSE_RELEASEDIR: return "RELEASEDIR";
Miklos Szeredi99f20742004-05-19 08:01:10 +0000114 default: return "???";
Miklos Szeredic8ba2372002-12-10 12:26:00 +0000115 }
116}
117
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000118static inline void fuse_dec_avail(struct fuse *f)
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +0000119{
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000120 pthread_mutex_lock(&f->worker_lock);
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +0000121 f->numavail --;
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000122 pthread_mutex_unlock(&f->worker_lock);
123}
124
125static inline void fuse_inc_avail(struct fuse *f)
126{
127 pthread_mutex_lock(&f->worker_lock);
128 f->numavail ++;
129 pthread_mutex_unlock(&f->worker_lock);
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +0000130}
131
Miklos Szeredif458b8c2004-12-07 16:46:42 +0000132static struct node *get_node_nocheck(struct fuse *f, nodeid_t nodeid)
Miklos Szeredia181e612001-11-06 12:03:23 +0000133{
Miklos Szeredia13d9002004-11-02 17:32:03 +0000134 size_t hash = nodeid % f->id_table_size;
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000135 struct node *node;
136
Miklos Szeredia13d9002004-11-02 17:32:03 +0000137 for (node = f->id_table[hash]; node != NULL; node = node->id_next)
138 if (node->nodeid == nodeid)
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000139 return node;
Miklos Szeredie5183742005-02-02 11:14:04 +0000140
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000141 return NULL;
Miklos Szeredia181e612001-11-06 12:03:23 +0000142}
143
Miklos Szeredia13d9002004-11-02 17:32:03 +0000144static struct node *get_node(struct fuse *f, nodeid_t nodeid)
Miklos Szeredia181e612001-11-06 12:03:23 +0000145{
Miklos Szeredif458b8c2004-12-07 16:46:42 +0000146 struct node *node = get_node_nocheck(f, nodeid);
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000147 if (!node) {
148 fprintf(stderr, "fuse internal error: node %lu not found\n",
149 nodeid);
150 abort();
151 }
152 return node;
Miklos Szeredia181e612001-11-06 12:03:23 +0000153}
154
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000155static void free_node(struct node *node)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000156{
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000157 free(node->name);
158 free(node);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000159}
160
Miklos Szeredia13d9002004-11-02 17:32:03 +0000161static void unhash_id(struct fuse *f, struct node *node)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000162{
Miklos Szeredia13d9002004-11-02 17:32:03 +0000163 size_t hash = node->nodeid % f->id_table_size;
164 struct node **nodep = &f->id_table[hash];
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000165
Miklos Szeredie5183742005-02-02 11:14:04 +0000166 for (; *nodep != NULL; nodep = &(*nodep)->id_next)
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000167 if (*nodep == node) {
Miklos Szeredia13d9002004-11-02 17:32:03 +0000168 *nodep = node->id_next;
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000169 return;
170 }
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000171}
172
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000173static void hash_id(struct fuse *f, struct node *node)
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000174{
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000175 size_t hash = node->nodeid % f->id_table_size;
176 node->id_next = f->id_table[hash];
Miklos Szeredie5183742005-02-02 11:14:04 +0000177 f->id_table[hash] = node;
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000178}
179
Miklos Szeredia13d9002004-11-02 17:32:03 +0000180static unsigned int name_hash(struct fuse *f, nodeid_t parent, const char *name)
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000181{
182 unsigned int hash = *name;
183
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000184 if (hash)
185 for (name += 1; *name != '\0'; name++)
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000186 hash = (hash << 5) - hash + *name;
187
188 return (hash + parent) % f->name_table_size;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000189}
190
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000191static void unref_node(struct fuse *f, struct node *node);
192
193static void unhash_name(struct fuse *f, struct node *node)
194{
195 if (node->name) {
196 size_t hash = name_hash(f, node->parent, node->name);
197 struct node **nodep = &f->name_table[hash];
Miklos Szeredie5183742005-02-02 11:14:04 +0000198
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000199 for (; *nodep != NULL; nodep = &(*nodep)->name_next)
200 if (*nodep == node) {
201 *nodep = node->name_next;
202 node->name_next = NULL;
203 unref_node(f, get_node(f, node->parent));
204 free(node->name);
205 node->name = NULL;
206 node->parent = 0;
207 return;
208 }
209 fprintf(stderr, "fuse internal error: unable to unhash node: %lu\n",
210 node->nodeid);
211 abort();
212 }
213}
214
215static int hash_name(struct fuse *f, struct node *node, nodeid_t parent,
216 const char *name)
217{
218 size_t hash = name_hash(f, parent, name);
219 node->name = strdup(name);
220 if (node->name == NULL)
221 return -1;
222
223 get_node(f, parent)->refctr ++;
224 node->parent = parent;
225 node->name_next = f->name_table[hash];
226 f->name_table[hash] = node;
227 return 0;
228}
229
230static void delete_node(struct fuse *f, struct node *node)
231{
232 assert(!node->name);
233 unhash_id(f, node);
234 free_node(node);
235}
236
237static void unref_node(struct fuse *f, struct node *node)
238{
239 assert(node->refctr > 0);
240 node->refctr --;
241 if (!node->refctr)
242 delete_node(f, node);
243}
244
245static nodeid_t next_id(struct fuse *f)
246{
247 do {
248 f->ctr++;
249 if (!f->ctr)
250 f->generation ++;
251 } while (f->ctr == 0 || get_node_nocheck(f, f->ctr) != NULL);
252 return f->ctr;
253}
254
Miklos Szeredif458b8c2004-12-07 16:46:42 +0000255static struct node *lookup_node(struct fuse *f, nodeid_t parent,
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000256 const char *name)
257{
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000258 size_t hash = name_hash(f, parent, name);
259 struct node *node;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000260
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000261 for (node = f->name_table[hash]; node != NULL; node = node->name_next)
262 if (node->parent == parent && strcmp(node->name, name) == 0)
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000263 return node;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000264
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000265 return NULL;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000266}
267
Miklos Szeredia13d9002004-11-02 17:32:03 +0000268static struct node *find_node(struct fuse *f, nodeid_t parent, char *name,
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000269 struct fuse_attr *attr, uint64_t version)
Miklos Szeredi5e183482001-10-31 14:52:35 +0000270{
271 struct node *node;
Miklos Szeredia181e612001-11-06 12:03:23 +0000272 int mode = attr->mode & S_IFMT;
273 int rdev = 0;
Miklos Szeredie5183742005-02-02 11:14:04 +0000274
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000275 if (S_ISCHR(mode) || S_ISBLK(mode))
Miklos Szeredia181e612001-11-06 12:03:23 +0000276 rdev = attr->rdev;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000277
Miklos Szeredia181e612001-11-06 12:03:23 +0000278 pthread_mutex_lock(&f->lock);
Miklos Szeredif458b8c2004-12-07 16:46:42 +0000279 node = lookup_node(f, parent, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000280 if (node != NULL) {
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000281 if (!(f->flags & FUSE_USE_INO))
Miklos Szeredie5183742005-02-02 11:14:04 +0000282 attr->ino = node->nodeid;
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000283 } else {
284 node = (struct node *) calloc(1, sizeof(struct node));
285 if (node == NULL)
286 goto out_err;
Miklos Szeredie5183742005-02-02 11:14:04 +0000287
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000288 node->refctr = 1;
289 node->nodeid = next_id(f);
290 if (!(f->flags & FUSE_USE_INO))
291 attr->ino = node->nodeid;
292 node->open_count = 0;
293 node->is_hidden = 0;
294 node->generation = f->generation;
295 if (hash_name(f, node, parent, name) == -1) {
296 free(node);
297 node = NULL;
298 goto out_err;
299 }
300 hash_id(f, node);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000301 }
Miklos Szeredia181e612001-11-06 12:03:23 +0000302 node->version = version;
Miklos Szeredic2309912004-09-21 13:40:38 +0000303 out_err:
Miklos Szeredia181e612001-11-06 12:03:23 +0000304 pthread_mutex_unlock(&f->lock);
Miklos Szeredi76f65782004-02-19 16:55:40 +0000305 return node;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000306}
307
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000308static char *add_name(char *buf, char *s, const char *name)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000309{
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000310 size_t len = strlen(name);
311 s -= len;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000312 if (s <= buf) {
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000313 fprintf(stderr, "fuse: path too long: ...%s\n", s + len);
314 return NULL;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000315 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000316 strncpy(s, name, len);
317 s--;
318 *s = '/';
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000319
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000320 return s;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000321}
322
Miklos Szeredia13d9002004-11-02 17:32:03 +0000323static char *get_path_name(struct fuse *f, nodeid_t nodeid, const char *name)
Miklos Szeredib483c932001-10-29 14:57:57 +0000324{
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000325 char buf[FUSE_MAX_PATH];
326 char *s = buf + FUSE_MAX_PATH - 1;
327 struct node *node;
Miklos Szeredie5183742005-02-02 11:14:04 +0000328
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000329 *s = '\0';
Miklos Szeredia181e612001-11-06 12:03:23 +0000330
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000331 if (name != NULL) {
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000332 s = add_name(buf, s, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000333 if (s == NULL)
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000334 return NULL;
335 }
336
337 pthread_mutex_lock(&f->lock);
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000338 for (node = get_node(f, nodeid); node && node->nodeid != FUSE_ROOT_ID;
339 node = get_node(f, node->parent)) {
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000340 if (node->name == NULL) {
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000341 s = NULL;
342 break;
343 }
Miklos Szeredie5183742005-02-02 11:14:04 +0000344
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000345 s = add_name(buf, s, node->name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000346 if (s == NULL)
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000347 break;
348 }
349 pthread_mutex_unlock(&f->lock);
350
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000351 if (node == NULL || s == NULL)
Miklos Szeredi5e183482001-10-31 14:52:35 +0000352 return NULL;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000353 else if (*s == '\0')
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000354 return strdup("/");
355 else
356 return strdup(s);
357}
Miklos Szeredia181e612001-11-06 12:03:23 +0000358
Miklos Szeredia13d9002004-11-02 17:32:03 +0000359static char *get_path(struct fuse *f, nodeid_t nodeid)
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000360{
Miklos Szeredia13d9002004-11-02 17:32:03 +0000361 return get_path_name(f, nodeid, NULL);
Miklos Szeredib483c932001-10-29 14:57:57 +0000362}
363
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000364static void forget_node(struct fuse *f, nodeid_t nodeid, uint64_t version)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000365{
Miklos Szeredia181e612001-11-06 12:03:23 +0000366 struct node *node;
367
368 pthread_mutex_lock(&f->lock);
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000369 node = get_node(f, nodeid);
370 if (node->version == version && nodeid != FUSE_ROOT_ID) {
371 node->version = 0;
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000372 unhash_name(f, node);
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000373 unref_node(f, node);
Miklos Szeredia181e612001-11-06 12:03:23 +0000374 }
375 pthread_mutex_unlock(&f->lock);
376
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000377}
378
Miklos Szeredia13d9002004-11-02 17:32:03 +0000379static void remove_node(struct fuse *f, nodeid_t dir, const char *name)
Miklos Szeredi5e183482001-10-31 14:52:35 +0000380{
Miklos Szeredia181e612001-11-06 12:03:23 +0000381 struct node *node;
382
383 pthread_mutex_lock(&f->lock);
Miklos Szeredif458b8c2004-12-07 16:46:42 +0000384 node = lookup_node(f, dir, name);
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000385 if (node != NULL)
386 unhash_name(f, node);
Miklos Szeredia181e612001-11-06 12:03:23 +0000387 pthread_mutex_unlock(&f->lock);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000388}
389
Miklos Szeredia13d9002004-11-02 17:32:03 +0000390static int rename_node(struct fuse *f, nodeid_t olddir, const char *oldname,
391 nodeid_t newdir, const char *newname, int hide)
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000392{
Miklos Szeredia181e612001-11-06 12:03:23 +0000393 struct node *node;
394 struct node *newnode;
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000395 int err = 0;
Miklos Szeredie5183742005-02-02 11:14:04 +0000396
Miklos Szeredia181e612001-11-06 12:03:23 +0000397 pthread_mutex_lock(&f->lock);
Miklos Szeredif458b8c2004-12-07 16:46:42 +0000398 node = lookup_node(f, olddir, oldname);
399 newnode = lookup_node(f, newdir, newname);
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000400 if (node == NULL)
401 goto out;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000402
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000403 if (newnode != NULL) {
404 if (hide) {
405 fprintf(stderr, "fuse: hidden file got created during hiding\n");
Miklos Szeredib2cf9562004-09-16 08:42:40 +0000406 err = -EBUSY;
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000407 goto out;
408 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000409 unhash_name(f, newnode);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000410 }
Miklos Szeredie5183742005-02-02 11:14:04 +0000411
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000412 unhash_name(f, node);
Miklos Szeredib2cf9562004-09-16 08:42:40 +0000413 if (hash_name(f, node, newdir, newname) == -1) {
414 err = -ENOMEM;
415 goto out;
416 }
Miklos Szeredie5183742005-02-02 11:14:04 +0000417
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000418 if (hide)
419 node->is_hidden = 1;
420
421 out:
Miklos Szeredia181e612001-11-06 12:03:23 +0000422 pthread_mutex_unlock(&f->lock);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000423 return err;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000424}
425
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000426static void convert_stat(struct stat *stbuf, struct fuse_attr *attr)
427{
Miklos Szeredia13d9002004-11-02 17:32:03 +0000428 attr->ino = stbuf->st_ino;
Miklos Szeredib5958612004-02-20 14:10:49 +0000429 attr->mode = stbuf->st_mode;
430 attr->nlink = stbuf->st_nlink;
431 attr->uid = stbuf->st_uid;
432 attr->gid = stbuf->st_gid;
433 attr->rdev = stbuf->st_rdev;
434 attr->size = stbuf->st_size;
435 attr->blocks = stbuf->st_blocks;
436 attr->atime = stbuf->st_atime;
Miklos Szeredib5958612004-02-20 14:10:49 +0000437 attr->mtime = stbuf->st_mtime;
Miklos Szeredib5958612004-02-20 14:10:49 +0000438 attr->ctime = stbuf->st_ctime;
Miklos Szeredicb264512004-06-23 18:52:50 +0000439#ifdef HAVE_STRUCT_STAT_ST_ATIM
440 attr->atimensec = stbuf->st_atim.tv_nsec;
441 attr->mtimensec = stbuf->st_mtim.tv_nsec;
Miklos Szeredib5958612004-02-20 14:10:49 +0000442 attr->ctimensec = stbuf->st_ctim.tv_nsec;
Miklos Szeredicb264512004-06-23 18:52:50 +0000443#endif
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000444}
445
Miklos Szeredi8fb48fe2004-11-08 14:48:52 +0000446static int fill_dir(struct fuse_dirhandle *dh, const char *name, int type,
447 ino_t ino)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000448{
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000449 size_t namelen = strlen(name);
Miklos Szeredib92d9782005-02-07 16:10:49 +0000450 size_t entsize = sizeof(struct fuse_dirhandle) + namelen + 8;
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000451 struct fuse_dirent *dirent;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000452
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000453 if (namelen > FUSE_NAME_MAX)
454 namelen = FUSE_NAME_MAX;
455
Miklos Szeredib92d9782005-02-07 16:10:49 +0000456 dh->contents = realloc(dh->contents, dh->len + entsize);
457 if (dh->contents == NULL)
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000458 return -ENOMEM;
459
Miklos Szeredib92d9782005-02-07 16:10:49 +0000460 dirent = (struct fuse_dirent *) (dh->contents + dh->len);
461 memset(dirent, 0, entsize);
Miklos Szeredi8fb48fe2004-11-08 14:48:52 +0000462 if ((dh->fuse->flags & FUSE_USE_INO))
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000463 dirent->ino = ino;
Miklos Szeredi8fb48fe2004-11-08 14:48:52 +0000464 else
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000465 dirent->ino = (unsigned long) -1;
466 dirent->namelen = namelen;
467 strncpy(dirent->name, name, namelen);
468 dirent->type = type;
Miklos Szeredib92d9782005-02-07 16:10:49 +0000469 dh->len += FUSE_DIRENT_SIZE(dirent);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000470 return 0;
471}
472
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000473static int send_reply_raw(struct fuse *f, char *outbuf, size_t outsize)
Miklos Szeredi43696432001-11-18 19:15:05 +0000474{
475 int res;
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000476 struct fuse_out_header *out = (struct fuse_out_header *) outbuf;
477 out->len = outsize;
Miklos Szeredi43696432001-11-18 19:15:05 +0000478
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000479 if ((f->flags & FUSE_DEBUG)) {
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000480 printf(" unique: %llu, error: %i (%s), outsize: %i\n",
481 out->unique, out->error, strerror(-out->error), outsize);
Miklos Szeredi43696432001-11-18 19:15:05 +0000482 fflush(stdout);
483 }
Miklos Szeredie5183742005-02-02 11:14:04 +0000484
Miklos Szeredi4e71c9f2004-02-09 12:05:14 +0000485 /* This needs to be done before the reply, otherwise the scheduler
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000486 could play tricks with us, and only let the counter be
487 increased long after the operation is done */
488 fuse_inc_avail(f);
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +0000489
Miklos Szeredi43696432001-11-18 19:15:05 +0000490 res = write(f->fd, outbuf, outsize);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000491 if (res == -1) {
Miklos Szeredi43696432001-11-18 19:15:05 +0000492 /* ENOENT means the operation was interrupted */
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000493 if (!f->exited && errno != ENOENT)
Miklos Szeredi96249982001-11-21 12:21:19 +0000494 perror("fuse: writing device");
Miklos Szeredi40b9a5a2002-12-10 16:09:02 +0000495 return -errno;
Miklos Szeredi43696432001-11-18 19:15:05 +0000496 }
Miklos Szeredi40b9a5a2002-12-10 16:09:02 +0000497 return 0;
Miklos Szeredi43696432001-11-18 19:15:05 +0000498}
499
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000500static int send_reply(struct fuse *f, struct fuse_in_header *in, int error,
501 void *arg, size_t argsize)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000502{
Miklos Szeredi40b9a5a2002-12-10 16:09:02 +0000503 int res;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000504 char *outbuf;
505 size_t outsize;
506 struct fuse_out_header *out;
507
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000508 if (error <= -1000 || error > 0) {
Miklos Szeredi0f48a262002-12-05 14:23:01 +0000509 fprintf(stderr, "fuse: bad error value: %i\n", error);
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000510 error = -ERANGE;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000511 }
512
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000513 if (error)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000514 argsize = 0;
515
516 outsize = sizeof(struct fuse_out_header) + argsize;
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000517 outbuf = (char *) malloc(outsize);
Miklos Szeredib2cf9562004-09-16 08:42:40 +0000518 if (outbuf == NULL) {
519 fprintf(stderr, "fuse: failed to allocate reply buffer\n");
520 res = -ENOMEM;
521 } else {
522 out = (struct fuse_out_header *) outbuf;
523 memset(out, 0, sizeof(struct fuse_out_header));
524 out->unique = in->unique;
525 out->error = error;
526 if (argsize != 0)
527 memcpy(outbuf + sizeof(struct fuse_out_header), arg, argsize);
Miklos Szeredie5183742005-02-02 11:14:04 +0000528
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000529 res = send_reply_raw(f, outbuf, outsize);
Miklos Szeredib2cf9562004-09-16 08:42:40 +0000530 free(outbuf);
531 }
Miklos Szeredi40b9a5a2002-12-10 16:09:02 +0000532
533 return res;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000534}
535
Miklos Szeredia13d9002004-11-02 17:32:03 +0000536static int is_open(struct fuse *f, nodeid_t dir, const char *name)
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000537{
538 struct node *node;
539 int isopen = 0;
540 pthread_mutex_lock(&f->lock);
Miklos Szeredif458b8c2004-12-07 16:46:42 +0000541 node = lookup_node(f, dir, name);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000542 if (node && node->open_count > 0)
543 isopen = 1;
544 pthread_mutex_unlock(&f->lock);
545 return isopen;
546}
547
Miklos Szeredia13d9002004-11-02 17:32:03 +0000548static char *hidden_name(struct fuse *f, nodeid_t dir, const char *oldname,
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000549 char *newname, size_t bufsize)
550{
551 struct stat buf;
552 struct node *node;
553 struct node *newnode;
554 char *newpath;
555 int res;
556 int failctr = 10;
557
558 if (!f->op.getattr)
559 return NULL;
560
561 do {
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000562 pthread_mutex_lock(&f->lock);
Miklos Szeredif458b8c2004-12-07 16:46:42 +0000563 node = lookup_node(f, dir, oldname);
564 if (node == NULL) {
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000565 pthread_mutex_unlock(&f->lock);
566 return NULL;
Miklos Szeredif458b8c2004-12-07 16:46:42 +0000567 }
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000568 do {
569 f->hidectr ++;
570 snprintf(newname, bufsize, ".fuse_hidden%08x%08x",
Miklos Szeredia13d9002004-11-02 17:32:03 +0000571 (unsigned int) node->nodeid, f->hidectr);
Miklos Szeredif458b8c2004-12-07 16:46:42 +0000572 newnode = lookup_node(f, dir, newname);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000573 } while(newnode);
574 pthread_mutex_unlock(&f->lock);
Miklos Szeredie5183742005-02-02 11:14:04 +0000575
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000576 newpath = get_path_name(f, dir, newname);
577 if (!newpath)
578 break;
Miklos Szeredie5183742005-02-02 11:14:04 +0000579
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000580 res = f->op.getattr(newpath, &buf);
581 if (res != 0)
582 break;
583 free(newpath);
584 newpath = NULL;
585 } while(--failctr);
586
587 return newpath;
588}
589
Miklos Szeredia13d9002004-11-02 17:32:03 +0000590static int hide_node(struct fuse *f, const char *oldpath, nodeid_t dir,
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000591 const char *oldname)
592{
593 char newname[64];
594 char *newpath;
Miklos Szeredib2cf9562004-09-16 08:42:40 +0000595 int err = -EBUSY;
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000596
Miklos Szeredib2cf9562004-09-16 08:42:40 +0000597 if (f->op.rename && f->op.unlink) {
598 newpath = hidden_name(f, dir, oldname, newname, sizeof(newname));
599 if (newpath) {
600 int res = f->op.rename(oldpath, newpath);
601 if (res == 0)
602 err = rename_node(f, dir, oldname, dir, newname, 1);
603 free(newpath);
604 }
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000605 }
Miklos Szeredib2cf9562004-09-16 08:42:40 +0000606 return err;
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000607}
608
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000609static int lookup_path(struct fuse *f, nodeid_t nodeid, uint64_t version,
610 char *name, const char *path,
611 struct fuse_entry_out *arg)
Miklos Szeredi76f65782004-02-19 16:55:40 +0000612{
613 int res;
614 struct stat buf;
615
616 res = f->op.getattr(path, &buf);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000617 if (res == 0) {
Miklos Szeredi76f65782004-02-19 16:55:40 +0000618 struct node *node;
619
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000620 memset(arg, 0, sizeof(struct fuse_entry_out));
Miklos Szeredi76f65782004-02-19 16:55:40 +0000621 convert_stat(&buf, &arg->attr);
Miklos Szeredia13d9002004-11-02 17:32:03 +0000622 node = find_node(f, nodeid, name, &arg->attr, version);
Miklos Szeredib2cf9562004-09-16 08:42:40 +0000623 if (node == NULL)
624 res = -ENOMEM;
625 else {
Miklos Szeredia13d9002004-11-02 17:32:03 +0000626 arg->nodeid = node->nodeid;
Miklos Szeredib2cf9562004-09-16 08:42:40 +0000627 arg->generation = node->generation;
628 arg->entry_valid = ENTRY_REVALIDATE_TIME;
629 arg->entry_valid_nsec = 0;
630 arg->attr_valid = ATTR_REVALIDATE_TIME;
631 arg->attr_valid_nsec = 0;
632 if (f->flags & FUSE_DEBUG) {
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000633 printf(" NODEID: %lu\n", (unsigned long) arg->nodeid);
Miklos Szeredib2cf9562004-09-16 08:42:40 +0000634 fflush(stdout);
635 }
Miklos Szeredi76f65782004-02-19 16:55:40 +0000636 }
637 }
638 return res;
639}
640
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000641static void do_lookup(struct fuse *f, struct fuse_in_header *in, char *name)
642{
643 int res;
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000644 int res2;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000645 char *path;
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000646 struct fuse_entry_out arg;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000647
Miklos Szeredi5e183482001-10-31 14:52:35 +0000648 res = -ENOENT;
Miklos Szeredia13d9002004-11-02 17:32:03 +0000649 path = get_path_name(f, in->nodeid, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000650 if (path != NULL) {
651 if (f->flags & FUSE_DEBUG) {
Miklos Szeredi6ebe2342002-01-06 21:44:16 +0000652 printf("LOOKUP %s\n", path);
653 fflush(stdout);
654 }
Miklos Szeredi5e183482001-10-31 14:52:35 +0000655 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000656 if (f->op.getattr)
Miklos Szeredia13d9002004-11-02 17:32:03 +0000657 res = lookup_path(f, in->nodeid, in->unique, name, path, &arg);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000658 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000659 }
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000660 res2 = send_reply(f, in, res, &arg, sizeof(arg));
661 if (res == 0 && res2 == -ENOENT)
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000662 forget_node(f, arg.nodeid, in->unique);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000663}
664
Miklos Szeredia181e612001-11-06 12:03:23 +0000665static void do_forget(struct fuse *f, struct fuse_in_header *in,
666 struct fuse_forget_in *arg)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000667{
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000668 if (f->flags & FUSE_DEBUG) {
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000669 printf("FORGET %lu/%llu\n", (unsigned long) in->nodeid,
670 arg->version);
Miklos Szeredi43696432001-11-18 19:15:05 +0000671 fflush(stdout);
672 }
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000673 forget_node(f, in->nodeid, arg->version);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000674}
675
676static void do_getattr(struct fuse *f, struct fuse_in_header *in)
677{
678 int res;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000679 char *path;
680 struct stat buf;
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000681 struct fuse_attr_out arg;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000682
Miklos Szeredi5e183482001-10-31 14:52:35 +0000683 res = -ENOENT;
Miklos Szeredia13d9002004-11-02 17:32:03 +0000684 path = get_path(f, in->nodeid);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000685 if (path != NULL) {
Miklos Szeredi5e183482001-10-31 14:52:35 +0000686 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000687 if (f->op.getattr)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000688 res = f->op.getattr(path, &buf);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000689 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000690 }
Miklos Szeredi0f48a262002-12-05 14:23:01 +0000691
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000692 if (res == 0) {
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000693 memset(&arg, 0, sizeof(struct fuse_attr_out));
694 arg.attr_valid = ATTR_REVALIDATE_TIME;
695 arg.attr_valid_nsec = 0;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000696 convert_stat(&buf, &arg.attr);
Miklos Szeredia13d9002004-11-02 17:32:03 +0000697 if (!(f->flags & FUSE_USE_INO))
698 arg.attr.ino = in->nodeid;
Miklos Szeredi0f48a262002-12-05 14:23:01 +0000699 }
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000700
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000701 send_reply(f, in, res, &arg, sizeof(arg));
702}
703
Miklos Szeredi680a69a2001-11-16 13:31:14 +0000704static int do_chmod(struct fuse *f, const char *path, struct fuse_attr *attr)
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000705{
706 int res;
707
708 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000709 if (f->op.chmod)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000710 res = f->op.chmod(path, attr->mode);
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000711
712 return res;
Miklos Szeredie5183742005-02-02 11:14:04 +0000713}
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000714
Miklos Szeredi680a69a2001-11-16 13:31:14 +0000715static int do_chown(struct fuse *f, const char *path, struct fuse_attr *attr,
Miklos Szeredi2e50d432001-12-20 12:17:25 +0000716 int valid)
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000717{
718 int res;
719 uid_t uid = (valid & FATTR_UID) ? attr->uid : (uid_t) -1;
720 gid_t gid = (valid & FATTR_GID) ? attr->gid : (gid_t) -1;
Miklos Szeredie5183742005-02-02 11:14:04 +0000721
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000722 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000723 if (f->op.chown)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000724 res = f->op.chown(path, uid, gid);
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000725
726 return res;
727}
728
Miklos Szeredi680a69a2001-11-16 13:31:14 +0000729static int do_truncate(struct fuse *f, const char *path,
730 struct fuse_attr *attr)
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000731{
732 int res;
733
734 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000735 if (f->op.truncate)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000736 res = f->op.truncate(path, attr->size);
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000737
738 return res;
739}
740
Miklos Szeredi680a69a2001-11-16 13:31:14 +0000741static int do_utime(struct fuse *f, const char *path, struct fuse_attr *attr)
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000742{
743 int res;
744 struct utimbuf buf;
745 buf.actime = attr->atime;
746 buf.modtime = attr->mtime;
747 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000748 if (f->op.utime)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000749 res = f->op.utime(path, &buf);
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000750
751 return res;
752}
753
Miklos Szeredi5e183482001-10-31 14:52:35 +0000754static void do_setattr(struct fuse *f, struct fuse_in_header *in,
755 struct fuse_setattr_in *arg)
756{
757 int res;
758 char *path;
759 int valid = arg->valid;
760 struct fuse_attr *attr = &arg->attr;
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000761 struct fuse_attr_out outarg;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000762
763 res = -ENOENT;
Miklos Szeredia13d9002004-11-02 17:32:03 +0000764 path = get_path(f, in->nodeid);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000765 if (path != NULL) {
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000766 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000767 if (f->op.getattr) {
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000768 res = 0;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000769 if (!res && (valid & FATTR_MODE))
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000770 res = do_chmod(f, path, attr);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000771 if (!res && (valid & (FATTR_UID | FATTR_GID)))
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000772 res = do_chown(f, path, attr, valid);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000773 if (!res && (valid & FATTR_SIZE))
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000774 res = do_truncate(f, path, attr);
Miklos Szeredie5183742005-02-02 11:14:04 +0000775 if (!res && (valid & (FATTR_ATIME | FATTR_MTIME)) ==
Miklos Szeredib5958612004-02-20 14:10:49 +0000776 (FATTR_ATIME | FATTR_MTIME))
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000777 res = do_utime(f, path, attr);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000778 if (!res) {
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000779 struct stat buf;
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000780 res = f->op.getattr(path, &buf);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000781 if (!res) {
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000782 memset(&outarg, 0, sizeof(struct fuse_attr_out));
783 outarg.attr_valid = ATTR_REVALIDATE_TIME;
784 outarg.attr_valid_nsec = 0;
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000785 convert_stat(&buf, &outarg.attr);
Miklos Szeredia13d9002004-11-02 17:32:03 +0000786 if (!(f->flags & FUSE_USE_INO))
787 outarg.attr.ino = in->nodeid;
Miklos Szeredi0f48a262002-12-05 14:23:01 +0000788 }
Miklos Szeredia181e612001-11-06 12:03:23 +0000789 }
Miklos Szeredi5e183482001-10-31 14:52:35 +0000790 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000791 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000792 }
Miklos Szeredia181e612001-11-06 12:03:23 +0000793 send_reply(f, in, res, &outarg, sizeof(outarg));
Miklos Szeredi5e183482001-10-31 14:52:35 +0000794}
795
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000796static void do_readlink(struct fuse *f, struct fuse_in_header *in)
797{
798 int res;
799 char link[PATH_MAX + 1];
Miklos Szeredib483c932001-10-29 14:57:57 +0000800 char *path;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000801
Miklos Szeredi5e183482001-10-31 14:52:35 +0000802 res = -ENOENT;
Miklos Szeredia13d9002004-11-02 17:32:03 +0000803 path = get_path(f, in->nodeid);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000804 if (path != NULL) {
Miklos Szeredi5e183482001-10-31 14:52:35 +0000805 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000806 if (f->op.readlink)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000807 res = f->op.readlink(path, link, sizeof(link));
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000808 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000809 }
Miklos Szeredi2df1c042001-11-06 15:07:17 +0000810 link[PATH_MAX] = '\0';
Miklos Szeredi4b2bef42002-01-09 12:23:27 +0000811 send_reply(f, in, res, link, res == 0 ? strlen(link) : 0);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000812}
813
Miklos Szeredi3ead28e2005-01-18 21:23:41 +0000814static int common_getdir(struct fuse *f, struct fuse_in_header *in,
815 struct fuse_dirhandle *dh)
816{
817 int res;
818 char *path;
819
820 res = -ENOENT;
821 path = get_path(f, in->nodeid);
822 if (path != NULL) {
823 res = -ENOSYS;
824 if (f->op.getdir)
825 res = f->op.getdir(path, dh, fill_dir);
826 free(path);
827 }
828 return res;
829}
830
Miklos Szeredib483c932001-10-29 14:57:57 +0000831static void do_mknod(struct fuse *f, struct fuse_in_header *in,
832 struct fuse_mknod_in *inarg)
833{
834 int res;
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000835 int res2;
Miklos Szeredib483c932001-10-29 14:57:57 +0000836 char *path;
Miklos Szeredi76f65782004-02-19 16:55:40 +0000837 char *name = PARAM(inarg);
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000838 struct fuse_entry_out outarg;
Miklos Szeredib483c932001-10-29 14:57:57 +0000839
Miklos Szeredi5e183482001-10-31 14:52:35 +0000840 res = -ENOENT;
Miklos Szeredia13d9002004-11-02 17:32:03 +0000841 path = get_path_name(f, in->nodeid, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000842 if (path != NULL) {
843 if (f->flags & FUSE_DEBUG) {
Miklos Szeredi76f65782004-02-19 16:55:40 +0000844 printf("MKNOD %s\n", path);
845 fflush(stdout);
846 }
Miklos Szeredi5e183482001-10-31 14:52:35 +0000847 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000848 if (f->op.mknod && f->op.getattr) {
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000849 res = f->op.mknod(path, inarg->mode, inarg->rdev);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000850 if (res == 0)
Miklos Szeredia13d9002004-11-02 17:32:03 +0000851 res = lookup_path(f, in->nodeid, in->unique, name, path, &outarg);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000852 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000853 free(path);
Miklos Szeredib483c932001-10-29 14:57:57 +0000854 }
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000855 res2 = send_reply(f, in, res, &outarg, sizeof(outarg));
856 if (res == 0 && res2 == -ENOENT)
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000857 forget_node(f, outarg.nodeid, in->unique);
Miklos Szeredib483c932001-10-29 14:57:57 +0000858}
859
860static void do_mkdir(struct fuse *f, struct fuse_in_header *in,
861 struct fuse_mkdir_in *inarg)
862{
863 int res;
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000864 int res2;
Miklos Szeredib483c932001-10-29 14:57:57 +0000865 char *path;
Miklos Szeredi76f65782004-02-19 16:55:40 +0000866 char *name = PARAM(inarg);
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000867 struct fuse_entry_out outarg;
Miklos Szeredib483c932001-10-29 14:57:57 +0000868
Miklos Szeredi5e183482001-10-31 14:52:35 +0000869 res = -ENOENT;
Miklos Szeredia13d9002004-11-02 17:32:03 +0000870 path = get_path_name(f, in->nodeid, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000871 if (path != NULL) {
872 if (f->flags & FUSE_DEBUG) {
Miklos Szeredi76f65782004-02-19 16:55:40 +0000873 printf("MKDIR %s\n", path);
874 fflush(stdout);
875 }
Miklos Szeredi5e183482001-10-31 14:52:35 +0000876 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000877 if (f->op.mkdir && f->op.getattr) {
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000878 res = f->op.mkdir(path, inarg->mode);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000879 if (res == 0)
Miklos Szeredia13d9002004-11-02 17:32:03 +0000880 res = lookup_path(f, in->nodeid, in->unique, name, path, &outarg);
Miklos Szeredi76f65782004-02-19 16:55:40 +0000881 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000882 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000883 }
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000884 res2 = send_reply(f, in, res, &outarg, sizeof(outarg));
885 if (res == 0 && res2 == -ENOENT)
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000886 forget_node(f, outarg.nodeid, in->unique);
Miklos Szeredib483c932001-10-29 14:57:57 +0000887}
888
Miklos Szeredib5958612004-02-20 14:10:49 +0000889static void do_unlink(struct fuse *f, struct fuse_in_header *in, char *name)
Miklos Szeredib483c932001-10-29 14:57:57 +0000890{
891 int res;
892 char *path;
893
Miklos Szeredi5e183482001-10-31 14:52:35 +0000894 res = -ENOENT;
Miklos Szeredia13d9002004-11-02 17:32:03 +0000895 path = get_path_name(f, in->nodeid, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000896 if (path != NULL) {
Miklos Szeredi209f5d02004-07-24 19:56:16 +0000897 if (f->flags & FUSE_DEBUG) {
898 printf("UNLINK %s\n", path);
899 fflush(stdout);
900 }
Miklos Szeredi5e183482001-10-31 14:52:35 +0000901 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000902 if (f->op.unlink) {
Miklos Szeredia13d9002004-11-02 17:32:03 +0000903 if (!(f->flags & FUSE_HARD_REMOVE) && is_open(f, in->nodeid, name))
904 res = hide_node(f, path, in->nodeid, name);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000905 else {
906 res = f->op.unlink(path);
907 if (res == 0)
Miklos Szeredia13d9002004-11-02 17:32:03 +0000908 remove_node(f, in->nodeid, name);
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000909
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000910 }
Miklos Szeredi5e183482001-10-31 14:52:35 +0000911 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000912 free(path);
Miklos Szeredib483c932001-10-29 14:57:57 +0000913 }
Miklos Szeredib5958612004-02-20 14:10:49 +0000914 send_reply(f, in, res, NULL, 0);
915}
916
917static void do_rmdir(struct fuse *f, struct fuse_in_header *in, char *name)
918{
919 int res;
920 char *path;
921
922 res = -ENOENT;
Miklos Szeredia13d9002004-11-02 17:32:03 +0000923 path = get_path_name(f, in->nodeid, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000924 if (path != NULL) {
Miklos Szeredi209f5d02004-07-24 19:56:16 +0000925 if (f->flags & FUSE_DEBUG) {
926 printf("RMDIR %s\n", path);
927 fflush(stdout);
928 }
Miklos Szeredib5958612004-02-20 14:10:49 +0000929 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000930 if (f->op.rmdir) {
Miklos Szeredib5958612004-02-20 14:10:49 +0000931 res = f->op.rmdir(path);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000932 if (res == 0)
Miklos Szeredia13d9002004-11-02 17:32:03 +0000933 remove_node(f, in->nodeid, name);
Miklos Szeredib5958612004-02-20 14:10:49 +0000934 }
935 free(path);
936 }
Miklos Szeredib483c932001-10-29 14:57:57 +0000937 send_reply(f, in, res, NULL, 0);
938}
939
940static void do_symlink(struct fuse *f, struct fuse_in_header *in, char *name,
941 char *link)
942{
943 int res;
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000944 int res2;
Miklos Szeredib483c932001-10-29 14:57:57 +0000945 char *path;
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000946 struct fuse_entry_out outarg;
Miklos Szeredib483c932001-10-29 14:57:57 +0000947
Miklos Szeredi5e183482001-10-31 14:52:35 +0000948 res = -ENOENT;
Miklos Szeredia13d9002004-11-02 17:32:03 +0000949 path = get_path_name(f, in->nodeid, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000950 if (path != NULL) {
951 if (f->flags & FUSE_DEBUG) {
Miklos Szeredi76f65782004-02-19 16:55:40 +0000952 printf("SYMLINK %s\n", path);
953 fflush(stdout);
954 }
Miklos Szeredi5e183482001-10-31 14:52:35 +0000955 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000956 if (f->op.symlink && f->op.getattr) {
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000957 res = f->op.symlink(link, path);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000958 if (res == 0)
Miklos Szeredia13d9002004-11-02 17:32:03 +0000959 res = lookup_path(f, in->nodeid, in->unique, name, path, &outarg);
Miklos Szeredi76f65782004-02-19 16:55:40 +0000960 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000961 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000962 }
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000963 res2 = send_reply(f, in, res, &outarg, sizeof(outarg));
964 if (res == 0 && res2 == -ENOENT)
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000965 forget_node(f, outarg.nodeid, in->unique);
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000966
Miklos Szeredib483c932001-10-29 14:57:57 +0000967}
968
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000969static void do_rename(struct fuse *f, struct fuse_in_header *in,
970 struct fuse_rename_in *inarg)
971{
972 int res;
Miklos Szeredia13d9002004-11-02 17:32:03 +0000973 nodeid_t olddir = in->nodeid;
974 nodeid_t newdir = inarg->newdir;
Miklos Szeredi6bf8b682002-10-28 08:49:39 +0000975 char *oldname = PARAM(inarg);
976 char *newname = oldname + strlen(oldname) + 1;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000977 char *oldpath;
978 char *newpath;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000979
Miklos Szeredi5e183482001-10-31 14:52:35 +0000980 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000981 oldpath = get_path_name(f, olddir, oldname);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000982 if (oldpath != NULL) {
Miklos Szeredia181e612001-11-06 12:03:23 +0000983 newpath = get_path_name(f, newdir, newname);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000984 if (newpath != NULL) {
Miklos Szeredi209f5d02004-07-24 19:56:16 +0000985 if (f->flags & FUSE_DEBUG) {
986 printf("RENAME %s -> %s\n", oldpath, newpath);
987 fflush(stdout);
988 }
Miklos Szeredi5e183482001-10-31 14:52:35 +0000989 res = -ENOSYS;
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000990 if (f->op.rename) {
991 res = 0;
Miklos Szeredie5183742005-02-02 11:14:04 +0000992 if (!(f->flags & FUSE_HARD_REMOVE) &&
Miklos Szeredi2529ca22004-07-13 15:36:52 +0000993 is_open(f, newdir, newname))
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000994 res = hide_node(f, newpath, newdir, newname);
995 if (res == 0) {
996 res = f->op.rename(oldpath, newpath);
997 if (res == 0)
Miklos Szeredib2cf9562004-09-16 08:42:40 +0000998 res = rename_node(f, olddir, oldname, newdir, newname, 0);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000999 }
1000 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001001 free(newpath);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001002 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001003 free(oldpath);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001004 }
Miklos Szeredie5183742005-02-02 11:14:04 +00001005 send_reply(f, in, res, NULL, 0);
Miklos Szeredi19dff1b2001-10-30 15:06:52 +00001006}
1007
1008static void do_link(struct fuse *f, struct fuse_in_header *in,
Miklos Szeredi5e183482001-10-31 14:52:35 +00001009 struct fuse_link_in *arg)
Miklos Szeredi19dff1b2001-10-30 15:06:52 +00001010{
1011 int res;
Miklos Szeredi2778f6c2004-06-21 09:45:30 +00001012 int res2;
Miklos Szeredi5e183482001-10-31 14:52:35 +00001013 char *oldpath;
1014 char *newpath;
Miklos Szeredi76f65782004-02-19 16:55:40 +00001015 char *name = PARAM(arg);
Miklos Szeredi254d5ed2004-03-02 11:11:24 +00001016 struct fuse_entry_out outarg;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +00001017
Miklos Szeredi5e183482001-10-31 14:52:35 +00001018 res = -ENOENT;
Miklos Szeredied6b5dd2005-01-26 17:07:59 +00001019 oldpath = get_path(f, arg->oldnodeid);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001020 if (oldpath != NULL) {
Miklos Szeredied6b5dd2005-01-26 17:07:59 +00001021 newpath = get_path_name(f, in->nodeid, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001022 if (newpath != NULL) {
1023 if (f->flags & FUSE_DEBUG) {
Miklos Szeredi76f65782004-02-19 16:55:40 +00001024 printf("LINK %s\n", newpath);
1025 fflush(stdout);
1026 }
Miklos Szeredi5e183482001-10-31 14:52:35 +00001027 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001028 if (f->op.link && f->op.getattr) {
Miklos Szeredi0a7077f2001-11-11 18:20:17 +00001029 res = f->op.link(oldpath, newpath);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001030 if (res == 0)
Miklos Szeredied6b5dd2005-01-26 17:07:59 +00001031 res = lookup_path(f, in->nodeid, in->unique, name,
Miklos Szeredi76f65782004-02-19 16:55:40 +00001032 newpath, &outarg);
1033 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001034 free(newpath);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001035 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001036 free(oldpath);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001037 }
Miklos Szeredi2778f6c2004-06-21 09:45:30 +00001038 res2 = send_reply(f, in, res, &outarg, sizeof(outarg));
1039 if (res == 0 && res2 == -ENOENT)
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001040 forget_node(f, outarg.nodeid, in->unique);
Miklos Szeredi19dff1b2001-10-30 15:06:52 +00001041}
1042
Miklos Szeredi5e183482001-10-31 14:52:35 +00001043static void do_open(struct fuse *f, struct fuse_in_header *in,
1044 struct fuse_open_in *arg)
1045{
1046 int res;
1047 char *path;
Miklos Szeredi209f5d02004-07-24 19:56:16 +00001048 struct fuse_open_out outarg;
Miklos Szeredifb28c5e2004-11-26 12:15:06 +00001049 struct fuse_file_info fi;
Miklos Szeredi5e183482001-10-31 14:52:35 +00001050
Miklos Szeredied3c97c2005-02-15 17:04:50 +00001051 memset(&outarg, 0, sizeof(outarg));
Miklos Szeredifb28c5e2004-11-26 12:15:06 +00001052 memset(&fi, 0, sizeof(fi));
1053 fi.flags = arg->flags;
Miklos Szeredi5e183482001-10-31 14:52:35 +00001054 res = -ENOENT;
Miklos Szeredia13d9002004-11-02 17:32:03 +00001055 path = get_path(f, in->nodeid);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001056 if (path != NULL) {
Miklos Szeredi5e183482001-10-31 14:52:35 +00001057 res = -ENOSYS;
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001058 if (f->op.open) {
Miklos Szeredi0b6a0ad2004-12-04 00:40:50 +00001059 if (!f->compat)
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001060 res = f->op.open(path, &fi);
Miklos Szeredi0b6a0ad2004-12-04 00:40:50 +00001061 else
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001062 res = ((struct fuse_operations_compat2 *) &f->op)->open(path, fi.flags);
Miklos Szeredi0b6a0ad2004-12-04 00:40:50 +00001063 }
Miklos Szeredi40b9a5a2002-12-10 16:09:02 +00001064 }
Miklos Szeredi73798f92004-07-12 15:55:11 +00001065 if (res == 0) {
1066 int res2;
Miklos Szeredifb28c5e2004-11-26 12:15:06 +00001067 outarg.fh = fi.fh;
Miklos Szeredi209f5d02004-07-24 19:56:16 +00001068 if (f->flags & FUSE_DEBUG) {
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001069 printf("OPEN[%lu] flags: 0x%x\n", fi.fh, arg->flags);
Miklos Szeredi209f5d02004-07-24 19:56:16 +00001070 fflush(stdout);
1071 }
Miklos Szeredie5183742005-02-02 11:14:04 +00001072
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001073 pthread_mutex_lock(&f->lock);
1074 res2 = send_reply(f, in, res, &outarg, sizeof(outarg));
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001075 if(res2 == -ENOENT) {
1076 /* The open syscall was interrupted, so it must be cancelled */
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001077 if(f->op.release) {
Miklos Szeredi0b6a0ad2004-12-04 00:40:50 +00001078 if (!f->compat)
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001079 f->op.release(path, &fi);
Miklos Szeredi0b6a0ad2004-12-04 00:40:50 +00001080 else
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001081 ((struct fuse_operations_compat2 *) &f->op)->release(path, fi.flags);
Miklos Szeredi0b6a0ad2004-12-04 00:40:50 +00001082 }
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001083 } else {
1084 struct node *node = get_node(f, in->nodeid);
1085 node->open_count ++;
1086 }
Miklos Szeredi73798f92004-07-12 15:55:11 +00001087 pthread_mutex_unlock(&f->lock);
Miklos Szeredi73798f92004-07-12 15:55:11 +00001088 } else
1089 send_reply(f, in, res, NULL, 0);
1090
Miklos Szeredi9a31cca2004-06-26 21:11:25 +00001091 if (path)
1092 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001093}
1094
Miklos Szeredi209f5d02004-07-24 19:56:16 +00001095static void do_flush(struct fuse *f, struct fuse_in_header *in,
1096 struct fuse_flush_in *arg)
Miklos Szeredie2e4ac22004-05-18 08:45:28 +00001097{
1098 char *path;
1099 int res;
Miklos Szeredifb28c5e2004-11-26 12:15:06 +00001100 struct fuse_file_info fi;
Miklos Szeredie2e4ac22004-05-18 08:45:28 +00001101
Miklos Szeredifb28c5e2004-11-26 12:15:06 +00001102 memset(&fi, 0, sizeof(fi));
1103 fi.fh = arg->fh;
Miklos Szeredie2e4ac22004-05-18 08:45:28 +00001104 res = -ENOENT;
Miklos Szeredia13d9002004-11-02 17:32:03 +00001105 path = get_path(f, in->nodeid);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001106 if (path != NULL) {
Miklos Szeredi209f5d02004-07-24 19:56:16 +00001107 if (f->flags & FUSE_DEBUG) {
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001108 printf("FLUSH[%lu]\n", (unsigned long) arg->fh);
Miklos Szeredi209f5d02004-07-24 19:56:16 +00001109 fflush(stdout);
1110 }
Miklos Szeredie2e4ac22004-05-18 08:45:28 +00001111 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001112 if (f->op.flush)
Miklos Szeredifb28c5e2004-11-26 12:15:06 +00001113 res = f->op.flush(path, &fi);
Miklos Szeredie2e4ac22004-05-18 08:45:28 +00001114 free(path);
1115 }
1116 send_reply(f, in, res, NULL, 0);
1117}
1118
Miklos Szeredi9478e862002-12-11 09:50:26 +00001119static void do_release(struct fuse *f, struct fuse_in_header *in,
Miklos Szeredi209f5d02004-07-24 19:56:16 +00001120 struct fuse_release_in *arg)
Miklos Szeredic8ba2372002-12-10 12:26:00 +00001121{
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001122 struct node *node;
1123 char *path;
Miklos Szeredifb28c5e2004-11-26 12:15:06 +00001124 struct fuse_file_info fi;
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001125 int unlink_hidden;
Miklos Szeredifb28c5e2004-11-26 12:15:06 +00001126
1127 memset(&fi, 0, sizeof(fi));
1128 fi.flags = arg->flags;
1129 fi.fh = arg->fh;
Miklos Szeredic8ba2372002-12-10 12:26:00 +00001130
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001131 pthread_mutex_lock(&f->lock);
Miklos Szeredia13d9002004-11-02 17:32:03 +00001132 node = get_node(f, in->nodeid);
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001133 assert(node->open_count > 0);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001134 --node->open_count;
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001135 unlink_hidden = (node->is_hidden && !node->open_count);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001136 pthread_mutex_unlock(&f->lock);
1137
Miklos Szeredia13d9002004-11-02 17:32:03 +00001138 path = get_path(f, in->nodeid);
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001139 if (f->flags & FUSE_DEBUG) {
1140 printf("RELEASE[%lu] flags: 0x%x\n", fi.fh, fi.flags);
1141 fflush(stdout);
Miklos Szeredic8ba2372002-12-10 12:26:00 +00001142 }
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001143 if (f->op.release) {
1144 if (!f->compat)
1145 f->op.release(path ? path : "-", &fi);
1146 else if (path)
1147 ((struct fuse_operations_compat2 *) &f->op)->release(path, fi.flags);
1148 }
Miklos Szeredie5183742005-02-02 11:14:04 +00001149
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001150 if(unlink_hidden && path)
1151 f->op.unlink(path);
Miklos Szeredie5183742005-02-02 11:14:04 +00001152
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001153 if (path)
1154 free(path);
1155
Miklos Szeredi556d03d2004-06-30 11:13:41 +00001156 send_reply(f, in, 0, NULL, 0);
Miklos Szeredic8ba2372002-12-10 12:26:00 +00001157}
1158
Miklos Szeredi5e183482001-10-31 14:52:35 +00001159static void do_read(struct fuse *f, struct fuse_in_header *in,
1160 struct fuse_read_in *arg)
1161{
1162 int res;
1163 char *path;
Miklos Szeredi43696432001-11-18 19:15:05 +00001164 char *outbuf = (char *) malloc(sizeof(struct fuse_out_header) + arg->size);
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001165 if (outbuf == NULL)
1166 send_reply(f, in, -ENOMEM, NULL, 0);
1167 else {
1168 struct fuse_out_header *out = (struct fuse_out_header *) outbuf;
1169 char *buf = outbuf + sizeof(struct fuse_out_header);
1170 size_t size;
1171 size_t outsize;
Miklos Szeredifb28c5e2004-11-26 12:15:06 +00001172 struct fuse_file_info fi;
Miklos Szeredie5183742005-02-02 11:14:04 +00001173
Miklos Szeredifb28c5e2004-11-26 12:15:06 +00001174 memset(&fi, 0, sizeof(fi));
1175 fi.fh = arg->fh;
1176
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001177 res = -ENOENT;
Miklos Szeredia13d9002004-11-02 17:32:03 +00001178 path = get_path(f, in->nodeid);
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001179 if (path != NULL) {
1180 if (f->flags & FUSE_DEBUG) {
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001181 printf("READ[%lu] %u bytes from %llu\n",
1182 (unsigned long) arg->fh, arg->size, arg->offset);
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001183 fflush(stdout);
1184 }
Miklos Szeredie5183742005-02-02 11:14:04 +00001185
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001186 res = -ENOSYS;
1187 if (f->op.read)
Miklos Szeredifb28c5e2004-11-26 12:15:06 +00001188 res = f->op.read(path, buf, arg->size, arg->offset, &fi);
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001189 free(path);
Miklos Szeredi6ebe2342002-01-06 21:44:16 +00001190 }
Miklos Szeredie5183742005-02-02 11:14:04 +00001191
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001192 size = 0;
1193 if (res >= 0) {
1194 size = res;
1195 res = 0;
1196 if (f->flags & FUSE_DEBUG) {
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001197 printf(" READ[%lu] %u bytes\n", (unsigned long) arg->fh,
1198 size);
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001199 fflush(stdout);
1200 }
Miklos Szeredi6ebe2342002-01-06 21:44:16 +00001201 }
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001202 memset(out, 0, sizeof(struct fuse_out_header));
1203 out->unique = in->unique;
1204 out->error = res;
1205 outsize = sizeof(struct fuse_out_header) + size;
Miklos Szeredie5183742005-02-02 11:14:04 +00001206
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001207 send_reply_raw(f, outbuf, outsize);
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001208 free(outbuf);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001209 }
Miklos Szeredi5e183482001-10-31 14:52:35 +00001210}
Miklos Szeredib483c932001-10-29 14:57:57 +00001211
Miklos Szeredia181e612001-11-06 12:03:23 +00001212static void do_write(struct fuse *f, struct fuse_in_header *in,
1213 struct fuse_write_in *arg)
1214{
1215 int res;
1216 char *path;
Miklos Szerediad051c32004-07-02 09:22:50 +00001217 struct fuse_write_out outarg;
Miklos Szeredifb28c5e2004-11-26 12:15:06 +00001218 struct fuse_file_info fi;
1219
1220 memset(&fi, 0, sizeof(fi));
1221 fi.fh = arg->fh;
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001222 fi.writepage = arg->write_flags & 1;
Miklos Szeredia181e612001-11-06 12:03:23 +00001223
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001224 res = -ENOENT;
Miklos Szeredia13d9002004-11-02 17:32:03 +00001225 path = get_path(f, in->nodeid);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001226 if (path != NULL) {
1227 if (f->flags & FUSE_DEBUG) {
Miklos Szeredi1eea0322004-09-27 18:50:11 +00001228 printf("WRITE%s[%lu] %u bytes to %llu\n",
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001229 (arg->write_flags & 1) ? "PAGE" : "",
1230 (unsigned long) arg->fh, arg->size, arg->offset);
Miklos Szeredi6ebe2342002-01-06 21:44:16 +00001231 fflush(stdout);
1232 }
1233
Miklos Szeredia181e612001-11-06 12:03:23 +00001234 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001235 if (f->op.write)
Miklos Szeredifb28c5e2004-11-26 12:15:06 +00001236 res = f->op.write(path, PARAM(arg), arg->size, arg->offset, &fi);
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001237 free(path);
Miklos Szeredia181e612001-11-06 12:03:23 +00001238 }
Miklos Szeredie5183742005-02-02 11:14:04 +00001239
1240 if (res >= 0) {
Miklos Szerediad051c32004-07-02 09:22:50 +00001241 outarg.size = res;
1242 res = 0;
Miklos Szeredia181e612001-11-06 12:03:23 +00001243 }
1244
Miklos Szerediad051c32004-07-02 09:22:50 +00001245 send_reply(f, in, res, &outarg, sizeof(outarg));
Miklos Szeredia181e612001-11-06 12:03:23 +00001246}
1247
Miklos Szeredi77f39942004-03-25 11:17:52 +00001248static int default_statfs(struct statfs *buf)
1249{
1250 buf->f_namelen = 255;
1251 buf->f_bsize = 512;
1252 return 0;
1253}
1254
Miklos Szeredif458b8c2004-12-07 16:46:42 +00001255static void convert_statfs_compat(struct fuse_statfs_compat1 *compatbuf,
Miklos Szeredi0b6a0ad2004-12-04 00:40:50 +00001256 struct statfs *statfs)
1257{
1258 statfs->f_bsize = compatbuf->block_size;
1259 statfs->f_blocks = compatbuf->blocks;
1260 statfs->f_bfree = compatbuf->blocks_free;
1261 statfs->f_bavail = compatbuf->blocks_free;
1262 statfs->f_files = compatbuf->files;
1263 statfs->f_ffree = compatbuf->files_free;
1264 statfs->f_namelen = compatbuf->namelen;
1265}
1266
Miklos Szeredi18e75e42004-02-19 14:23:27 +00001267static void convert_statfs(struct statfs *statfs, struct fuse_kstatfs *kstatfs)
1268{
1269 kstatfs->bsize = statfs->f_bsize;
1270 kstatfs->blocks = statfs->f_blocks;
1271 kstatfs->bfree = statfs->f_bfree;
1272 kstatfs->bavail = statfs->f_bavail;
1273 kstatfs->files = statfs->f_files;
1274 kstatfs->ffree = statfs->f_ffree;
1275 kstatfs->namelen = statfs->f_namelen;
1276}
1277
Mark Glinesd84b39a2002-01-07 16:32:02 +00001278static void do_statfs(struct fuse *f, struct fuse_in_header *in)
1279{
1280 int res;
Mark Glinesd84b39a2002-01-07 16:32:02 +00001281 struct fuse_statfs_out arg;
Miklos Szeredi18e75e42004-02-19 14:23:27 +00001282 struct statfs buf;
Mark Glinesd84b39a2002-01-07 16:32:02 +00001283
Miklos Szeredi77f39942004-03-25 11:17:52 +00001284 memset(&buf, 0, sizeof(struct statfs));
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001285 if (f->op.statfs) {
Miklos Szeredi0b6a0ad2004-12-04 00:40:50 +00001286 if (!f->compat || f->compat > 11)
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001287 res = f->op.statfs("/", &buf);
Miklos Szeredi0b6a0ad2004-12-04 00:40:50 +00001288 else {
Miklos Szeredif458b8c2004-12-07 16:46:42 +00001289 struct fuse_statfs_compat1 compatbuf;
1290 memset(&compatbuf, 0, sizeof(struct fuse_statfs_compat1));
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001291 res = ((struct fuse_operations_compat1 *) &f->op)->statfs(&compatbuf);
Miklos Szeredi0b6a0ad2004-12-04 00:40:50 +00001292 if (res == 0)
1293 convert_statfs_compat(&compatbuf, &buf);
1294 }
1295 }
Miklos Szeredi77f39942004-03-25 11:17:52 +00001296 else
1297 res = default_statfs(&buf);
1298
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001299 if (res == 0)
Miklos Szeredi77f39942004-03-25 11:17:52 +00001300 convert_statfs(&buf, &arg.st);
Miklos Szeredi4b2bef42002-01-09 12:23:27 +00001301
Mark Glinesd84b39a2002-01-07 16:32:02 +00001302 send_reply(f, in, res, &arg, sizeof(arg));
1303}
1304
Miklos Szeredi5e43f2c2003-12-12 14:06:41 +00001305static void do_fsync(struct fuse *f, struct fuse_in_header *in,
1306 struct fuse_fsync_in *inarg)
1307{
1308 int res;
1309 char *path;
Miklos Szeredifb28c5e2004-11-26 12:15:06 +00001310 struct fuse_file_info fi;
1311
1312 memset(&fi, 0, sizeof(fi));
1313 fi.fh = inarg->fh;
Miklos Szeredi5e43f2c2003-12-12 14:06:41 +00001314
1315 res = -ENOENT;
Miklos Szeredia13d9002004-11-02 17:32:03 +00001316 path = get_path(f, in->nodeid);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001317 if (path != NULL) {
Miklos Szeredi209f5d02004-07-24 19:56:16 +00001318 if (f->flags & FUSE_DEBUG) {
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001319 printf("FSYNC[%lu]\n", (unsigned long) inarg->fh);
Miklos Szeredi209f5d02004-07-24 19:56:16 +00001320 fflush(stdout);
1321 }
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001322 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001323 if (f->op.fsync)
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001324 res = f->op.fsync(path, inarg->fsync_flags & 1, &fi);
Miklos Szeredi5e43f2c2003-12-12 14:06:41 +00001325 free(path);
1326 }
1327 send_reply(f, in, res, NULL, 0);
1328}
1329
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001330static void do_setxattr(struct fuse *f, struct fuse_in_header *in,
1331 struct fuse_setxattr_in *arg)
1332{
1333 int res;
1334 char *path;
1335 char *name = PARAM(arg);
1336 unsigned char *value = name + strlen(name) + 1;
1337
1338 res = -ENOENT;
Miklos Szeredia13d9002004-11-02 17:32:03 +00001339 path = get_path(f, in->nodeid);
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001340 if (path != NULL) {
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001341 res = -ENOSYS;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001342 if (f->op.setxattr)
1343 res = f->op.setxattr(path, name, value, arg->size, arg->flags);
1344 free(path);
Miklos Szeredie5183742005-02-02 11:14:04 +00001345 }
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001346 send_reply(f, in, res, NULL, 0);
1347}
1348
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001349static int common_getxattr(struct fuse *f, struct fuse_in_header *in,
1350 const char *name, char *value, size_t size)
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001351{
1352 int res;
1353 char *path;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001354
1355 res = -ENOENT;
Miklos Szeredia13d9002004-11-02 17:32:03 +00001356 path = get_path(f, in->nodeid);
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001357 if (path != NULL) {
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001358 res = -ENOSYS;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001359 if (f->op.getxattr)
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001360 res = f->op.getxattr(path, name, value, size);
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001361 free(path);
Miklos Szeredie5183742005-02-02 11:14:04 +00001362 }
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001363 return res;
1364}
1365
1366static void do_getxattr_read(struct fuse *f, struct fuse_in_header *in,
1367 const char *name, size_t size)
1368{
1369 int res;
1370 char *outbuf = (char *) malloc(sizeof(struct fuse_out_header) + size);
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001371 if (outbuf == NULL)
1372 send_reply(f, in, -ENOMEM, NULL, 0);
1373 else {
1374 struct fuse_out_header *out = (struct fuse_out_header *) outbuf;
1375 char *value = outbuf + sizeof(struct fuse_out_header);
Miklos Szeredie5183742005-02-02 11:14:04 +00001376
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001377 res = common_getxattr(f, in, name, value, size);
1378 size = 0;
1379 if (res > 0) {
1380 size = res;
1381 res = 0;
1382 }
1383 memset(out, 0, sizeof(struct fuse_out_header));
1384 out->unique = in->unique;
1385 out->error = res;
Miklos Szeredie5183742005-02-02 11:14:04 +00001386
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001387 send_reply_raw(f, outbuf, sizeof(struct fuse_out_header) + size);
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001388 free(outbuf);
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001389 }
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001390}
1391
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001392static void do_getxattr_size(struct fuse *f, struct fuse_in_header *in,
1393 const char *name)
1394{
1395 int res;
1396 struct fuse_getxattr_out arg;
1397
1398 res = common_getxattr(f, in, name, NULL, 0);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001399 if (res >= 0) {
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001400 arg.size = res;
1401 res = 0;
1402 }
1403 send_reply(f, in, res, &arg, sizeof(arg));
1404}
1405
1406static void do_getxattr(struct fuse *f, struct fuse_in_header *in,
1407 struct fuse_getxattr_in *arg)
1408{
1409 char *name = PARAM(arg);
Miklos Szeredie5183742005-02-02 11:14:04 +00001410
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001411 if (arg->size)
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001412 do_getxattr_read(f, in, name, arg->size);
1413 else
1414 do_getxattr_size(f, in, name);
1415}
1416
1417static int common_listxattr(struct fuse *f, struct fuse_in_header *in,
1418 char *list, size_t size)
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001419{
1420 int res;
1421 char *path;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001422
1423 res = -ENOENT;
Miklos Szeredia13d9002004-11-02 17:32:03 +00001424 path = get_path(f, in->nodeid);
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001425 if (path != NULL) {
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001426 res = -ENOSYS;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001427 if (f->op.listxattr)
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001428 res = f->op.listxattr(path, list, size);
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001429 free(path);
Miklos Szeredie5183742005-02-02 11:14:04 +00001430 }
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001431 return res;
1432}
1433
1434static void do_listxattr_read(struct fuse *f, struct fuse_in_header *in,
1435 size_t size)
1436{
1437 int res;
1438 char *outbuf = (char *) malloc(sizeof(struct fuse_out_header) + size);
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001439 if (outbuf == NULL)
1440 send_reply(f, in, -ENOMEM, NULL, 0);
1441 else {
1442 struct fuse_out_header *out = (struct fuse_out_header *) outbuf;
1443 char *list = outbuf + sizeof(struct fuse_out_header);
Miklos Szeredie5183742005-02-02 11:14:04 +00001444
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001445 res = common_listxattr(f, in, list, size);
1446 size = 0;
1447 if (res > 0) {
1448 size = res;
1449 res = 0;
1450 }
1451 memset(out, 0, sizeof(struct fuse_out_header));
1452 out->unique = in->unique;
1453 out->error = res;
Miklos Szeredie5183742005-02-02 11:14:04 +00001454
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001455 send_reply_raw(f, outbuf, sizeof(struct fuse_out_header) + size);
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001456 free(outbuf);
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001457 }
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001458}
1459
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001460static void do_listxattr_size(struct fuse *f, struct fuse_in_header *in)
1461{
1462 int res;
1463 struct fuse_getxattr_out arg;
1464
1465 res = common_listxattr(f, in, NULL, 0);
1466 if (res >= 0) {
1467 arg.size = res;
1468 res = 0;
1469 }
1470 send_reply(f, in, res, &arg, sizeof(arg));
1471}
1472
1473static void do_listxattr(struct fuse *f, struct fuse_in_header *in,
1474 struct fuse_getxattr_in *arg)
1475{
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001476 if (arg->size)
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001477 do_listxattr_read(f, in, arg->size);
1478 else
1479 do_listxattr_size(f, in);
1480}
1481
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001482static void do_removexattr(struct fuse *f, struct fuse_in_header *in,
1483 char *name)
1484{
1485 int res;
1486 char *path;
1487
1488 res = -ENOENT;
Miklos Szeredia13d9002004-11-02 17:32:03 +00001489 path = get_path(f, in->nodeid);
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001490 if (path != NULL) {
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001491 res = -ENOSYS;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001492 if (f->op.removexattr)
1493 res = f->op.removexattr(path, name);
1494 free(path);
Miklos Szeredie5183742005-02-02 11:14:04 +00001495 }
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001496 send_reply(f, in, res, NULL, 0);
1497}
1498
Miklos Szeredi3f0005f2005-01-04 19:24:31 +00001499static void do_init(struct fuse *f, struct fuse_in_header *in,
1500 struct fuse_init_in_out *arg)
1501{
1502 struct fuse_init_in_out outarg;
1503 if (f->flags & FUSE_DEBUG) {
1504 printf(" INIT: %u.%u\n", arg->major, arg->minor);
1505 fflush(stdout);
1506 }
1507 f->got_init = 1;
1508 memset(&outarg, 0, sizeof(outarg));
1509 outarg.major = FUSE_KERNEL_VERSION;
1510 outarg.minor = FUSE_KERNEL_MINOR_VERSION;
1511 send_reply(f, in, 0, &outarg, sizeof(outarg));
1512}
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001513
Miklos Szeredi3ead28e2005-01-18 21:23:41 +00001514static struct fuse_dirhandle *get_dirhandle(unsigned long fh)
1515{
1516 return (struct fuse_dirhandle *) fh;
1517}
1518
1519static void do_opendir(struct fuse *f, struct fuse_in_header *in,
1520 struct fuse_open_in *arg)
1521{
1522 int res;
1523 struct fuse_open_out outarg;
1524 struct fuse_dirhandle *dh;
1525
1526 (void) arg;
Miklos Szeredied3c97c2005-02-15 17:04:50 +00001527 memset(&outarg, 0, sizeof(outarg));
Miklos Szeredi3ead28e2005-01-18 21:23:41 +00001528 res = -ENOMEM;
1529 dh = (struct fuse_dirhandle *) malloc(sizeof(struct fuse_dirhandle));
1530 if (dh != NULL) {
Miklos Szeredied3c97c2005-02-15 17:04:50 +00001531 memset(dh, 0, sizeof(struct fuse_dirhandle));
Miklos Szeredi3ead28e2005-01-18 21:23:41 +00001532 dh->fuse = f;
Miklos Szeredib92d9782005-02-07 16:10:49 +00001533 dh->contents = NULL;
1534 dh->len = 0;
Miklos Szeredi3ead28e2005-01-18 21:23:41 +00001535 dh->filled = 0;
Miklos Szeredib92d9782005-02-07 16:10:49 +00001536 outarg.fh = (unsigned long) dh;
1537 res = 0;
Miklos Szeredi3ead28e2005-01-18 21:23:41 +00001538 }
1539 send_reply(f, in, res, &outarg, sizeof(outarg));
1540}
1541
1542static void do_readdir(struct fuse *f, struct fuse_in_header *in,
1543 struct fuse_read_in *arg)
1544{
Miklos Szeredi3ead28e2005-01-18 21:23:41 +00001545 char *outbuf;
1546 struct fuse_dirhandle *dh = get_dirhandle(arg->fh);
1547
1548 if (!dh->filled) {
Miklos Szeredib92d9782005-02-07 16:10:49 +00001549 int res = common_getdir(f, in, dh);
Miklos Szeredi01fd89c2005-01-21 11:18:35 +00001550 if (res) {
Miklos Szeredi3ead28e2005-01-18 21:23:41 +00001551 send_reply(f, in, res, NULL, 0);
Miklos Szeredi01fd89c2005-01-21 11:18:35 +00001552 return;
1553 }
Miklos Szeredi3ead28e2005-01-18 21:23:41 +00001554 dh->filled = 1;
1555 }
1556 outbuf = (char *) malloc(sizeof(struct fuse_out_header) + arg->size);
1557 if (outbuf == NULL)
1558 send_reply(f, in, -ENOMEM, NULL, 0);
1559 else {
1560 struct fuse_out_header *out = (struct fuse_out_header *) outbuf;
1561 char *buf = outbuf + sizeof(struct fuse_out_header);
1562 size_t size = 0;
1563 size_t outsize;
Miklos Szeredib92d9782005-02-07 16:10:49 +00001564 if (arg->offset < dh->len) {
1565 size = arg->size;
1566 if (arg->offset + size > dh->len)
1567 size = dh->len - arg->offset;
1568
1569 memcpy(buf, dh->contents + arg->offset, size);
Miklos Szeredi3ead28e2005-01-18 21:23:41 +00001570 }
1571 memset(out, 0, sizeof(struct fuse_out_header));
1572 out->unique = in->unique;
Miklos Szeredib92d9782005-02-07 16:10:49 +00001573 out->error = 0;
Miklos Szeredi3ead28e2005-01-18 21:23:41 +00001574 outsize = sizeof(struct fuse_out_header) + size;
Miklos Szeredie5183742005-02-02 11:14:04 +00001575
Miklos Szeredi3ead28e2005-01-18 21:23:41 +00001576 send_reply_raw(f, outbuf, outsize);
1577 free(outbuf);
1578 }
1579}
1580
1581static void do_releasedir(struct fuse *f, struct fuse_in_header *in,
1582 struct fuse_release_in *arg)
1583{
1584 struct fuse_dirhandle *dh = get_dirhandle(arg->fh);
Miklos Szeredib92d9782005-02-07 16:10:49 +00001585 free(dh->contents);
Miklos Szeredi3ead28e2005-01-18 21:23:41 +00001586 free(dh);
1587 send_reply(f, in, 0, NULL, 0);
1588}
1589
1590
Miklos Szeredi43696432001-11-18 19:15:05 +00001591static void free_cmd(struct fuse_cmd *cmd)
1592{
1593 free(cmd->buf);
1594 free(cmd);
1595}
1596
Miklos Szeredif458b8c2004-12-07 16:46:42 +00001597void fuse_process_cmd(struct fuse *f, struct fuse_cmd *cmd)
Miklos Szeredia181e612001-11-06 12:03:23 +00001598{
Miklos Szeredia181e612001-11-06 12:03:23 +00001599 struct fuse_in_header *in = (struct fuse_in_header *) cmd->buf;
1600 void *inarg = cmd->buf + sizeof(struct fuse_in_header);
1601 size_t argsize;
Miklos Szeredid169f312004-09-22 08:48:26 +00001602 struct fuse_context *ctx = fuse_get_context();
Miklos Szeredia181e612001-11-06 12:03:23 +00001603
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001604 fuse_dec_avail(f);
Miklos Szeredi33232032001-11-19 17:55:51 +00001605
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001606 if ((f->flags & FUSE_DEBUG)) {
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001607 printf("unique: %llu, opcode: %s (%i), nodeid: %lu, insize: %i\n",
1608 in->unique, opname(in->opcode), in->opcode,
1609 (unsigned long) in->nodeid, cmd->buflen);
Miklos Szeredic0938ea2001-11-07 12:35:06 +00001610 fflush(stdout);
1611 }
Miklos Szeredife25def2001-12-20 15:38:05 +00001612
Miklos Szeredi3f0005f2005-01-04 19:24:31 +00001613 if (!f->got_init && in->opcode != FUSE_INIT) {
1614 /* Old kernel version probably */
1615 send_reply(f, in, -EPROTO, NULL, 0);
1616 goto out;
1617 }
1618
Miklos Szeredid169f312004-09-22 08:48:26 +00001619 ctx->fuse = f;
Miklos Szeredife25def2001-12-20 15:38:05 +00001620 ctx->uid = in->uid;
1621 ctx->gid = in->gid;
Miklos Szeredi1f18db52004-09-27 06:54:49 +00001622 ctx->pid = in->pid;
Miklos Szeredie5183742005-02-02 11:14:04 +00001623
Miklos Szeredia181e612001-11-06 12:03:23 +00001624 argsize = cmd->buflen - sizeof(struct fuse_in_header);
Miklos Szeredie5183742005-02-02 11:14:04 +00001625
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001626 switch (in->opcode) {
Miklos Szeredia181e612001-11-06 12:03:23 +00001627 case FUSE_LOOKUP:
1628 do_lookup(f, in, (char *) inarg);
1629 break;
1630
Miklos Szeredia181e612001-11-06 12:03:23 +00001631 case FUSE_GETATTR:
1632 do_getattr(f, in);
1633 break;
1634
1635 case FUSE_SETATTR:
1636 do_setattr(f, in, (struct fuse_setattr_in *) inarg);
1637 break;
1638
1639 case FUSE_READLINK:
1640 do_readlink(f, in);
1641 break;
1642
Miklos Szeredia181e612001-11-06 12:03:23 +00001643 case FUSE_MKNOD:
1644 do_mknod(f, in, (struct fuse_mknod_in *) inarg);
1645 break;
Miklos Szeredie5183742005-02-02 11:14:04 +00001646
Miklos Szeredia181e612001-11-06 12:03:23 +00001647 case FUSE_MKDIR:
1648 do_mkdir(f, in, (struct fuse_mkdir_in *) inarg);
1649 break;
Miklos Szeredie5183742005-02-02 11:14:04 +00001650
Miklos Szeredia181e612001-11-06 12:03:23 +00001651 case FUSE_UNLINK:
Miklos Szeredib5958612004-02-20 14:10:49 +00001652 do_unlink(f, in, (char *) inarg);
1653 break;
1654
Miklos Szeredia181e612001-11-06 12:03:23 +00001655 case FUSE_RMDIR:
Miklos Szeredib5958612004-02-20 14:10:49 +00001656 do_rmdir(f, in, (char *) inarg);
Miklos Szeredia181e612001-11-06 12:03:23 +00001657 break;
1658
1659 case FUSE_SYMLINK:
Miklos Szeredie5183742005-02-02 11:14:04 +00001660 do_symlink(f, in, (char *) inarg,
Miklos Szeredia181e612001-11-06 12:03:23 +00001661 ((char *) inarg) + strlen((char *) inarg) + 1);
1662 break;
1663
1664 case FUSE_RENAME:
1665 do_rename(f, in, (struct fuse_rename_in *) inarg);
1666 break;
Miklos Szeredie5183742005-02-02 11:14:04 +00001667
Miklos Szeredia181e612001-11-06 12:03:23 +00001668 case FUSE_LINK:
1669 do_link(f, in, (struct fuse_link_in *) inarg);
1670 break;
1671
1672 case FUSE_OPEN:
1673 do_open(f, in, (struct fuse_open_in *) inarg);
1674 break;
1675
Miklos Szeredie2e4ac22004-05-18 08:45:28 +00001676 case FUSE_FLUSH:
Miklos Szeredi209f5d02004-07-24 19:56:16 +00001677 do_flush(f, in, (struct fuse_flush_in *) inarg);
Miklos Szeredie2e4ac22004-05-18 08:45:28 +00001678 break;
1679
Miklos Szeredi9478e862002-12-11 09:50:26 +00001680 case FUSE_RELEASE:
Miklos Szeredi209f5d02004-07-24 19:56:16 +00001681 do_release(f, in, (struct fuse_release_in *) inarg);
Miklos Szeredi9478e862002-12-11 09:50:26 +00001682 break;
1683
Miklos Szeredia181e612001-11-06 12:03:23 +00001684 case FUSE_READ:
1685 do_read(f, in, (struct fuse_read_in *) inarg);
1686 break;
1687
1688 case FUSE_WRITE:
1689 do_write(f, in, (struct fuse_write_in *) inarg);
1690 break;
1691
Mark Glinesd84b39a2002-01-07 16:32:02 +00001692 case FUSE_STATFS:
1693 do_statfs(f, in);
1694 break;
1695
Miklos Szeredi5e43f2c2003-12-12 14:06:41 +00001696 case FUSE_FSYNC:
1697 do_fsync(f, in, (struct fuse_fsync_in *) inarg);
1698 break;
1699
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001700 case FUSE_SETXATTR:
1701 do_setxattr(f, in, (struct fuse_setxattr_in *) inarg);
1702 break;
1703
1704 case FUSE_GETXATTR:
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001705 do_getxattr(f, in, (struct fuse_getxattr_in *) inarg);
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001706 break;
1707
1708 case FUSE_LISTXATTR:
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001709 do_listxattr(f, in, (struct fuse_getxattr_in *) inarg);
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001710 break;
1711
1712 case FUSE_REMOVEXATTR:
1713 do_removexattr(f, in, (char *) inarg);
1714 break;
1715
Miklos Szeredi3f0005f2005-01-04 19:24:31 +00001716 case FUSE_INIT:
1717 do_init(f, in, (struct fuse_init_in_out *) inarg);
1718 break;
1719
Miklos Szeredi3ead28e2005-01-18 21:23:41 +00001720 case FUSE_OPENDIR:
1721 do_opendir(f, in, (struct fuse_open_in *) inarg);
1722 break;
1723
1724 case FUSE_READDIR:
1725 do_readdir(f, in, (struct fuse_read_in *) inarg);
1726 break;
1727
1728 case FUSE_RELEASEDIR:
1729 do_releasedir(f, in, (struct fuse_release_in *) inarg);
1730 break;
1731
Miklos Szeredia181e612001-11-06 12:03:23 +00001732 default:
Miklos Szeredi43696432001-11-18 19:15:05 +00001733 send_reply(f, in, -ENOSYS, NULL, 0);
Miklos Szeredia181e612001-11-06 12:03:23 +00001734 }
Miklos Szeredi43696432001-11-18 19:15:05 +00001735
Miklos Szeredi3f0005f2005-01-04 19:24:31 +00001736 out:
Miklos Szeredi43696432001-11-18 19:15:05 +00001737 free_cmd(cmd);
Miklos Szeredia181e612001-11-06 12:03:23 +00001738}
1739
Miklos Szeredif458b8c2004-12-07 16:46:42 +00001740int fuse_exited(struct fuse* f)
Miklos Szeredi65cf7c72004-06-30 11:34:56 +00001741{
1742 return f->exited;
1743}
1744
Miklos Szeredif458b8c2004-12-07 16:46:42 +00001745struct fuse_cmd *fuse_read_cmd(struct fuse *f)
Miklos Szeredi2df1c042001-11-06 15:07:17 +00001746{
Miklos Szeredifff56ab2001-11-16 10:12:59 +00001747 ssize_t res;
Miklos Szeredifff56ab2001-11-16 10:12:59 +00001748 struct fuse_cmd *cmd;
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +00001749 struct fuse_in_header *in;
1750 void *inarg;
Miklos Szeredifff56ab2001-11-16 10:12:59 +00001751
Miklos Szeredi43696432001-11-18 19:15:05 +00001752 cmd = (struct fuse_cmd *) malloc(sizeof(struct fuse_cmd));
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001753 if (cmd == NULL) {
1754 fprintf(stderr, "fuse: failed to allocate cmd in read\n");
1755 return NULL;
1756 }
Miklos Szeredi43696432001-11-18 19:15:05 +00001757 cmd->buf = (char *) malloc(FUSE_MAX_IN);
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001758 if (cmd->buf == NULL) {
1759 fprintf(stderr, "fuse: failed to allocate read buffer\n");
1760 free(cmd);
1761 return NULL;
1762 }
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +00001763 in = (struct fuse_in_header *) cmd->buf;
1764 inarg = cmd->buf + sizeof(struct fuse_in_header);
Miklos Szeredi43696432001-11-18 19:15:05 +00001765
Miklos Szeredi65cf7c72004-06-30 11:34:56 +00001766 res = read(f->fd, cmd->buf, FUSE_MAX_IN);
1767 if (res == -1) {
1768 free_cmd(cmd);
Miklos Szeredie56818b2004-12-12 11:45:24 +00001769 if (fuse_exited(f) || errno == EINTR || errno == ENOENT)
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +00001770 return NULL;
Miklos Szeredie5183742005-02-02 11:14:04 +00001771
Miklos Szeredi65cf7c72004-06-30 11:34:56 +00001772 /* ENODEV means we got unmounted, so we silenty return failure */
1773 if (errno != ENODEV) {
1774 /* BAD... This will happen again */
1775 perror("fuse: reading device");
1776 }
Miklos Szeredie5183742005-02-02 11:14:04 +00001777
Miklos Szeredi65cf7c72004-06-30 11:34:56 +00001778 fuse_exit(f);
1779 return NULL;
1780 }
1781 if ((size_t) res < sizeof(struct fuse_in_header)) {
1782 free_cmd(cmd);
1783 /* Cannot happen */
1784 fprintf(stderr, "short read on fuse device\n");
1785 fuse_exit(f);
1786 return NULL;
1787 }
1788 cmd->buflen = res;
Miklos Szeredie5183742005-02-02 11:14:04 +00001789
Miklos Szeredi65cf7c72004-06-30 11:34:56 +00001790 /* Forget is special, it can be done without messing with threads. */
1791 if (in->opcode == FUSE_FORGET) {
1792 do_forget(f, in, (struct fuse_forget_in *) inarg);
1793 free_cmd(cmd);
1794 return NULL;
1795 }
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +00001796
Miklos Szeredifff56ab2001-11-16 10:12:59 +00001797 return cmd;
Miklos Szeredi2df1c042001-11-06 15:07:17 +00001798}
1799
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001800int fuse_loop(struct fuse *f)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001801{
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001802 if (f == NULL)
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001803 return -1;
Miklos Szeredic40748a2004-02-20 16:38:45 +00001804
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001805 while (1) {
Miklos Szeredi0f48a262002-12-05 14:23:01 +00001806 struct fuse_cmd *cmd;
1807
Miklos Szeredif458b8c2004-12-07 16:46:42 +00001808 if (fuse_exited(f))
Miklos Szeredi874e3c12004-11-01 23:15:20 +00001809 break;
Miklos Szeredi0f48a262002-12-05 14:23:01 +00001810
Miklos Szeredif458b8c2004-12-07 16:46:42 +00001811 cmd = fuse_read_cmd(f);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001812 if (cmd == NULL)
Miklos Szeredi0f48a262002-12-05 14:23:01 +00001813 continue;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001814
Miklos Szeredif458b8c2004-12-07 16:46:42 +00001815 fuse_process_cmd(f, cmd);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001816 }
Miklos Szeredi874e3c12004-11-01 23:15:20 +00001817 f->exited = 0;
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001818 return 0;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001819}
1820
Miklos Szeredi891b8742004-07-29 09:27:49 +00001821int fuse_invalidate(struct fuse *f, const char *path)
1822{
Miklos Szeredie56818b2004-12-12 11:45:24 +00001823 (void) f;
1824 (void) path;
1825 return -EINVAL;
Miklos Szeredi891b8742004-07-29 09:27:49 +00001826}
1827
Miklos Szeredi0f48a262002-12-05 14:23:01 +00001828void fuse_exit(struct fuse *f)
1829{
1830 f->exited = 1;
1831}
1832
Miklos Szeredid169f312004-09-22 08:48:26 +00001833struct fuse_context *fuse_get_context()
Miklos Szeredi2e50d432001-12-20 12:17:25 +00001834{
Miklos Szeredid169f312004-09-22 08:48:26 +00001835 static struct fuse_context context;
1836 if (fuse_getcontext)
1837 return fuse_getcontext();
Miklos Szeredi2e50d432001-12-20 12:17:25 +00001838 else
Miklos Szeredid169f312004-09-22 08:48:26 +00001839 return &context;
1840}
1841
Miklos Szeredif458b8c2004-12-07 16:46:42 +00001842void fuse_set_getcontext_func(struct fuse_context *(*func)(void))
Miklos Szeredid169f312004-09-22 08:48:26 +00001843{
1844 fuse_getcontext = func;
Miklos Szeredi2e50d432001-12-20 12:17:25 +00001845}
1846
Miklos Szeredibd7661b2004-07-23 17:16:29 +00001847int fuse_is_lib_option(const char *opt)
1848{
1849 if (strcmp(opt, "debug") == 0 ||
Miklos Szeredia13d9002004-11-02 17:32:03 +00001850 strcmp(opt, "hard_remove") == 0 ||
1851 strcmp(opt, "use_ino") == 0)
Miklos Szeredibd7661b2004-07-23 17:16:29 +00001852 return 1;
1853 else
1854 return 0;
1855}
1856
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001857static int parse_lib_opts(struct fuse *f, const char *opts)
Miklos Szeredibd7661b2004-07-23 17:16:29 +00001858{
1859 if (opts) {
1860 char *xopts = strdup(opts);
1861 char *s = xopts;
1862 char *opt;
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001863
Miklos Szeredie56818b2004-12-12 11:45:24 +00001864 if (xopts == NULL) {
1865 fprintf(stderr, "fuse: memory allocation failed\n");
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001866 return -1;
Miklos Szeredie56818b2004-12-12 11:45:24 +00001867 }
Miklos Szeredie5183742005-02-02 11:14:04 +00001868
Miklos Szeredibd7661b2004-07-23 17:16:29 +00001869 while((opt = strsep(&s, ","))) {
1870 if (strcmp(opt, "debug") == 0)
1871 f->flags |= FUSE_DEBUG;
1872 else if (strcmp(opt, "hard_remove") == 0)
1873 f->flags |= FUSE_HARD_REMOVE;
Miklos Szeredia13d9002004-11-02 17:32:03 +00001874 else if (strcmp(opt, "use_ino") == 0)
1875 f->flags |= FUSE_USE_INO;
Miklos Szeredie5183742005-02-02 11:14:04 +00001876 else
Miklos Szeredibd7661b2004-07-23 17:16:29 +00001877 fprintf(stderr, "fuse: warning: unknown option `%s'\n", opt);
1878 }
1879 free(xopts);
1880 }
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001881 return 0;
Miklos Szeredibd7661b2004-07-23 17:16:29 +00001882}
1883
Miklos Szeredi0b6a0ad2004-12-04 00:40:50 +00001884struct fuse *fuse_new_common(int fd, const char *opts,
1885 const struct fuse_operations *op,
1886 size_t op_size, int compat)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001887{
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001888 struct fuse *f;
1889 struct node *root;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001890
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001891 if (sizeof(struct fuse_operations) < op_size) {
Miklos Szeredi0b6a0ad2004-12-04 00:40:50 +00001892 fprintf(stderr, "fuse: warning: library too old, some operations may not not work\n");
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001893 op_size = sizeof(struct fuse_operations);
Miklos Szeredi0b6a0ad2004-12-04 00:40:50 +00001894 }
1895
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001896 f = (struct fuse *) calloc(1, sizeof(struct fuse));
Miklos Szeredie56818b2004-12-12 11:45:24 +00001897 if (f == NULL) {
1898 fprintf(stderr, "fuse: failed to allocate fuse object\n");
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001899 goto out;
Miklos Szeredie56818b2004-12-12 11:45:24 +00001900 }
Miklos Szeredi2df1c042001-11-06 15:07:17 +00001901
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001902 if (parse_lib_opts(f, opts) == -1)
1903 goto out_free;
1904
Miklos Szeredi8cffdb92001-11-09 14:49:18 +00001905 f->fd = fd;
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001906 f->ctr = 0;
Miklos Szeredi76f65782004-02-19 16:55:40 +00001907 f->generation = 0;
Miklos Szeredifff56ab2001-11-16 10:12:59 +00001908 /* FIXME: Dynamic hash table */
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001909 f->name_table_size = 14057;
1910 f->name_table = (struct node **)
1911 calloc(1, sizeof(struct node *) * f->name_table_size);
Miklos Szeredie56818b2004-12-12 11:45:24 +00001912 if (f->name_table == NULL) {
1913 fprintf(stderr, "fuse: memory allocation failed\n");
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001914 goto out_free;
Miklos Szeredie56818b2004-12-12 11:45:24 +00001915 }
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001916
Miklos Szeredia13d9002004-11-02 17:32:03 +00001917 f->id_table_size = 14057;
1918 f->id_table = (struct node **)
1919 calloc(1, sizeof(struct node *) * f->id_table_size);
Miklos Szeredie56818b2004-12-12 11:45:24 +00001920 if (f->id_table == NULL) {
1921 fprintf(stderr, "fuse: memory allocation failed\n");
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001922 goto out_free_name_table;
Miklos Szeredie56818b2004-12-12 11:45:24 +00001923 }
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001924
Miklos Szeredia25d4c22004-11-23 22:32:16 +00001925#ifndef USE_UCLIBC
1926 pthread_mutex_init(&f->lock, NULL);
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001927 pthread_mutex_init(&f->worker_lock, NULL);
Miklos Szeredia25d4c22004-11-23 22:32:16 +00001928#else
1929 {
1930 pthread_mutexattr_t attr;
1931 pthread_mutexattr_init(&attr);
1932 pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ADAPTIVE_NP);
1933 pthread_mutex_init(&f->lock, &attr);
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001934 pthread_mutex_init(&f->worker_lock, &attr);
Miklos Szeredia25d4c22004-11-23 22:32:16 +00001935 pthread_mutexattr_destroy(&attr);
1936 }
1937#endif
Miklos Szeredi33232032001-11-19 17:55:51 +00001938 f->numworker = 0;
1939 f->numavail = 0;
Miklos Szeredi0b6a0ad2004-12-04 00:40:50 +00001940 memcpy(&f->op, op, op_size);
1941 f->compat = compat;
Miklos Szeredi0f48a262002-12-05 14:23:01 +00001942 f->exited = 0;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001943
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001944 root = (struct node *) calloc(1, sizeof(struct node));
Miklos Szeredie56818b2004-12-12 11:45:24 +00001945 if (root == NULL) {
1946 fprintf(stderr, "fuse: memory allocation failed\n");
Miklos Szeredia13d9002004-11-02 17:32:03 +00001947 goto out_free_id_table;
Miklos Szeredie56818b2004-12-12 11:45:24 +00001948 }
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001949
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001950 root->name = strdup("/");
Miklos Szeredie56818b2004-12-12 11:45:24 +00001951 if (root->name == NULL) {
1952 fprintf(stderr, "fuse: memory allocation failed\n");
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001953 goto out_free_root;
Miklos Szeredie56818b2004-12-12 11:45:24 +00001954 }
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001955
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001956 root->parent = 0;
Miklos Szeredia13d9002004-11-02 17:32:03 +00001957 root->nodeid = FUSE_ROOT_ID;
Miklos Szeredi76f65782004-02-19 16:55:40 +00001958 root->generation = 0;
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001959 root->refctr = 1;
Miklos Szeredia13d9002004-11-02 17:32:03 +00001960 hash_id(f, root);
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001961
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001962 return f;
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001963
1964 out_free_root:
1965 free(root);
Miklos Szeredia13d9002004-11-02 17:32:03 +00001966 out_free_id_table:
1967 free(f->id_table);
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001968 out_free_name_table:
1969 free(f->name_table);
1970 out_free:
1971 free(f);
1972 out:
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001973 return NULL;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001974}
1975
Miklos Szeredi0b6a0ad2004-12-04 00:40:50 +00001976struct fuse *fuse_new(int fd, const char *opts,
1977 const struct fuse_operations *op, size_t op_size)
1978{
1979 return fuse_new_common(fd, opts, op, op_size, 0);
1980}
1981
Miklos Szeredif458b8c2004-12-07 16:46:42 +00001982struct fuse *fuse_new_compat2(int fd, const char *opts,
1983 const struct fuse_operations_compat2 *op)
Miklos Szeredi0b6a0ad2004-12-04 00:40:50 +00001984{
1985 return fuse_new_common(fd, opts, (struct fuse_operations *) op,
Miklos Szeredif458b8c2004-12-07 16:46:42 +00001986 sizeof(struct fuse_operations_compat2), 21);
Miklos Szeredi0b6a0ad2004-12-04 00:40:50 +00001987}
1988
Miklos Szeredif458b8c2004-12-07 16:46:42 +00001989struct fuse *fuse_new_compat1(int fd, int flags,
1990 const struct fuse_operations_compat1 *op)
Miklos Szeredi0b6a0ad2004-12-04 00:40:50 +00001991{
1992 char *opts = NULL;
Miklos Szeredif458b8c2004-12-07 16:46:42 +00001993 if (flags & FUSE_DEBUG_COMPAT1)
Miklos Szeredi0b6a0ad2004-12-04 00:40:50 +00001994 opts = "debug";
1995 return fuse_new_common(fd, opts, (struct fuse_operations *) op,
Miklos Szeredif458b8c2004-12-07 16:46:42 +00001996 sizeof(struct fuse_operations_compat1), 11);
Miklos Szeredi0b6a0ad2004-12-04 00:40:50 +00001997}
1998
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001999void fuse_destroy(struct fuse *f)
2000{
Miklos Szeredi97c61e92001-11-07 12:09:43 +00002001 size_t i;
Miklos Szeredia13d9002004-11-02 17:32:03 +00002002 for (i = 0; i < f->id_table_size; i++) {
Miklos Szeredi97c61e92001-11-07 12:09:43 +00002003 struct node *node;
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00002004
Miklos Szeredia13d9002004-11-02 17:32:03 +00002005 for (node = f->id_table[i]; node != NULL; node = node->id_next) {
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00002006 if (node->is_hidden) {
Miklos Szeredia13d9002004-11-02 17:32:03 +00002007 char *path = get_path(f, node->nodeid);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00002008 if (path)
2009 f->op.unlink(path);
2010 }
2011 }
2012 }
Miklos Szeredia13d9002004-11-02 17:32:03 +00002013 for (i = 0; i < f->id_table_size; i++) {
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00002014 struct node *node;
Miklos Szeredi97c61e92001-11-07 12:09:43 +00002015 struct node *next;
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00002016
Miklos Szeredia13d9002004-11-02 17:32:03 +00002017 for (node = f->id_table[i]; node != NULL; node = next) {
2018 next = node->id_next;
Miklos Szeredi97c61e92001-11-07 12:09:43 +00002019 free_node(node);
2020 }
2021 }
Miklos Szeredia13d9002004-11-02 17:32:03 +00002022 free(f->id_table);
Miklos Szeredi97c61e92001-11-07 12:09:43 +00002023 free(f->name_table);
Miklos Szeredia181e612001-11-06 12:03:23 +00002024 pthread_mutex_destroy(&f->lock);
Miklos Szeredi0f62d722005-01-04 12:45:54 +00002025 pthread_mutex_destroy(&f->worker_lock);
Miklos Szeredi97c61e92001-11-07 12:09:43 +00002026 free(f);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00002027}
Miklos Szeredi0b6a0ad2004-12-04 00:40:50 +00002028
Miklos Szeredif458b8c2004-12-07 16:46:42 +00002029__asm__(".symver fuse_exited,__fuse_exited@");
2030__asm__(".symver fuse_process_cmd,__fuse_process_cmd@");
2031__asm__(".symver fuse_read_cmd,__fuse_read_cmd@");
2032__asm__(".symver fuse_set_getcontext_func,__fuse_set_getcontext_func@");
2033__asm__(".symver fuse_new_compat2,fuse_new@");