blob: 104d6544ac53be549221ce8a2f7a5b4229519b1c [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 Szeredifb28c5e2004-11-26 12:15:06 +00001051 memset(&fi, 0, sizeof(fi));
1052 fi.flags = arg->flags;
Miklos Szeredi5e183482001-10-31 14:52:35 +00001053 res = -ENOENT;
Miklos Szeredia13d9002004-11-02 17:32:03 +00001054 path = get_path(f, in->nodeid);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001055 if (path != NULL) {
Miklos Szeredi5e183482001-10-31 14:52:35 +00001056 res = -ENOSYS;
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001057 if (f->op.open) {
Miklos Szeredi0b6a0ad2004-12-04 00:40:50 +00001058 if (!f->compat)
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001059 res = f->op.open(path, &fi);
Miklos Szeredi0b6a0ad2004-12-04 00:40:50 +00001060 else
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001061 res = ((struct fuse_operations_compat2 *) &f->op)->open(path, fi.flags);
Miklos Szeredi0b6a0ad2004-12-04 00:40:50 +00001062 }
Miklos Szeredi40b9a5a2002-12-10 16:09:02 +00001063 }
Miklos Szeredi73798f92004-07-12 15:55:11 +00001064 if (res == 0) {
1065 int res2;
Miklos Szeredifb28c5e2004-11-26 12:15:06 +00001066 outarg.fh = fi.fh;
Miklos Szeredi209f5d02004-07-24 19:56:16 +00001067 if (f->flags & FUSE_DEBUG) {
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001068 printf("OPEN[%lu] flags: 0x%x\n", fi.fh, arg->flags);
Miklos Szeredi209f5d02004-07-24 19:56:16 +00001069 fflush(stdout);
1070 }
Miklos Szeredie5183742005-02-02 11:14:04 +00001071
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001072 pthread_mutex_lock(&f->lock);
1073 res2 = send_reply(f, in, res, &outarg, sizeof(outarg));
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001074 if(res2 == -ENOENT) {
1075 /* The open syscall was interrupted, so it must be cancelled */
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001076 if(f->op.release) {
Miklos Szeredi0b6a0ad2004-12-04 00:40:50 +00001077 if (!f->compat)
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001078 f->op.release(path, &fi);
Miklos Szeredi0b6a0ad2004-12-04 00:40:50 +00001079 else
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001080 ((struct fuse_operations_compat2 *) &f->op)->release(path, fi.flags);
Miklos Szeredi0b6a0ad2004-12-04 00:40:50 +00001081 }
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001082 } else {
1083 struct node *node = get_node(f, in->nodeid);
1084 node->open_count ++;
1085 }
Miklos Szeredi73798f92004-07-12 15:55:11 +00001086 pthread_mutex_unlock(&f->lock);
Miklos Szeredi73798f92004-07-12 15:55:11 +00001087 } else
1088 send_reply(f, in, res, NULL, 0);
1089
Miklos Szeredi9a31cca2004-06-26 21:11:25 +00001090 if (path)
1091 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001092}
1093
Miklos Szeredi209f5d02004-07-24 19:56:16 +00001094static void do_flush(struct fuse *f, struct fuse_in_header *in,
1095 struct fuse_flush_in *arg)
Miklos Szeredie2e4ac22004-05-18 08:45:28 +00001096{
1097 char *path;
1098 int res;
Miklos Szeredifb28c5e2004-11-26 12:15:06 +00001099 struct fuse_file_info fi;
Miklos Szeredie2e4ac22004-05-18 08:45:28 +00001100
Miklos Szeredifb28c5e2004-11-26 12:15:06 +00001101 memset(&fi, 0, sizeof(fi));
1102 fi.fh = arg->fh;
Miklos Szeredie2e4ac22004-05-18 08:45:28 +00001103 res = -ENOENT;
Miklos Szeredia13d9002004-11-02 17:32:03 +00001104 path = get_path(f, in->nodeid);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001105 if (path != NULL) {
Miklos Szeredi209f5d02004-07-24 19:56:16 +00001106 if (f->flags & FUSE_DEBUG) {
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001107 printf("FLUSH[%lu]\n", (unsigned long) arg->fh);
Miklos Szeredi209f5d02004-07-24 19:56:16 +00001108 fflush(stdout);
1109 }
Miklos Szeredie2e4ac22004-05-18 08:45:28 +00001110 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001111 if (f->op.flush)
Miklos Szeredifb28c5e2004-11-26 12:15:06 +00001112 res = f->op.flush(path, &fi);
Miklos Szeredie2e4ac22004-05-18 08:45:28 +00001113 free(path);
1114 }
1115 send_reply(f, in, res, NULL, 0);
1116}
1117
Miklos Szeredi9478e862002-12-11 09:50:26 +00001118static void do_release(struct fuse *f, struct fuse_in_header *in,
Miklos Szeredi209f5d02004-07-24 19:56:16 +00001119 struct fuse_release_in *arg)
Miklos Szeredic8ba2372002-12-10 12:26:00 +00001120{
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001121 struct node *node;
1122 char *path;
Miklos Szeredifb28c5e2004-11-26 12:15:06 +00001123 struct fuse_file_info fi;
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001124 int unlink_hidden;
Miklos Szeredifb28c5e2004-11-26 12:15:06 +00001125
1126 memset(&fi, 0, sizeof(fi));
1127 fi.flags = arg->flags;
1128 fi.fh = arg->fh;
Miklos Szeredic8ba2372002-12-10 12:26:00 +00001129
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001130 pthread_mutex_lock(&f->lock);
Miklos Szeredia13d9002004-11-02 17:32:03 +00001131 node = get_node(f, in->nodeid);
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001132 assert(node->open_count > 0);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001133 --node->open_count;
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001134 unlink_hidden = (node->is_hidden && !node->open_count);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001135 pthread_mutex_unlock(&f->lock);
1136
Miklos Szeredia13d9002004-11-02 17:32:03 +00001137 path = get_path(f, in->nodeid);
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001138 if (f->flags & FUSE_DEBUG) {
1139 printf("RELEASE[%lu] flags: 0x%x\n", fi.fh, fi.flags);
1140 fflush(stdout);
Miklos Szeredic8ba2372002-12-10 12:26:00 +00001141 }
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001142 if (f->op.release) {
1143 if (!f->compat)
1144 f->op.release(path ? path : "-", &fi);
1145 else if (path)
1146 ((struct fuse_operations_compat2 *) &f->op)->release(path, fi.flags);
1147 }
Miklos Szeredie5183742005-02-02 11:14:04 +00001148
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001149 if(unlink_hidden && path)
1150 f->op.unlink(path);
Miklos Szeredie5183742005-02-02 11:14:04 +00001151
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001152 if (path)
1153 free(path);
1154
Miklos Szeredi556d03d2004-06-30 11:13:41 +00001155 send_reply(f, in, 0, NULL, 0);
Miklos Szeredic8ba2372002-12-10 12:26:00 +00001156}
1157
Miklos Szeredi5e183482001-10-31 14:52:35 +00001158static void do_read(struct fuse *f, struct fuse_in_header *in,
1159 struct fuse_read_in *arg)
1160{
1161 int res;
1162 char *path;
Miklos Szeredi43696432001-11-18 19:15:05 +00001163 char *outbuf = (char *) malloc(sizeof(struct fuse_out_header) + arg->size);
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001164 if (outbuf == NULL)
1165 send_reply(f, in, -ENOMEM, NULL, 0);
1166 else {
1167 struct fuse_out_header *out = (struct fuse_out_header *) outbuf;
1168 char *buf = outbuf + sizeof(struct fuse_out_header);
1169 size_t size;
1170 size_t outsize;
Miklos Szeredifb28c5e2004-11-26 12:15:06 +00001171 struct fuse_file_info fi;
Miklos Szeredie5183742005-02-02 11:14:04 +00001172
Miklos Szeredifb28c5e2004-11-26 12:15:06 +00001173 memset(&fi, 0, sizeof(fi));
1174 fi.fh = arg->fh;
1175
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001176 res = -ENOENT;
Miklos Szeredia13d9002004-11-02 17:32:03 +00001177 path = get_path(f, in->nodeid);
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001178 if (path != NULL) {
1179 if (f->flags & FUSE_DEBUG) {
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001180 printf("READ[%lu] %u bytes from %llu\n",
1181 (unsigned long) arg->fh, arg->size, arg->offset);
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001182 fflush(stdout);
1183 }
Miklos Szeredie5183742005-02-02 11:14:04 +00001184
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001185 res = -ENOSYS;
1186 if (f->op.read)
Miklos Szeredifb28c5e2004-11-26 12:15:06 +00001187 res = f->op.read(path, buf, arg->size, arg->offset, &fi);
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001188 free(path);
Miklos Szeredi6ebe2342002-01-06 21:44:16 +00001189 }
Miklos Szeredie5183742005-02-02 11:14:04 +00001190
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001191 size = 0;
1192 if (res >= 0) {
1193 size = res;
1194 res = 0;
1195 if (f->flags & FUSE_DEBUG) {
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001196 printf(" READ[%lu] %u bytes\n", (unsigned long) arg->fh,
1197 size);
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001198 fflush(stdout);
1199 }
Miklos Szeredi6ebe2342002-01-06 21:44:16 +00001200 }
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001201 memset(out, 0, sizeof(struct fuse_out_header));
1202 out->unique = in->unique;
1203 out->error = res;
1204 outsize = sizeof(struct fuse_out_header) + size;
Miklos Szeredie5183742005-02-02 11:14:04 +00001205
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001206 send_reply_raw(f, outbuf, outsize);
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001207 free(outbuf);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001208 }
Miklos Szeredi5e183482001-10-31 14:52:35 +00001209}
Miklos Szeredib483c932001-10-29 14:57:57 +00001210
Miklos Szeredia181e612001-11-06 12:03:23 +00001211static void do_write(struct fuse *f, struct fuse_in_header *in,
1212 struct fuse_write_in *arg)
1213{
1214 int res;
1215 char *path;
Miklos Szerediad051c32004-07-02 09:22:50 +00001216 struct fuse_write_out outarg;
Miklos Szeredifb28c5e2004-11-26 12:15:06 +00001217 struct fuse_file_info fi;
1218
1219 memset(&fi, 0, sizeof(fi));
1220 fi.fh = arg->fh;
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001221 fi.writepage = arg->write_flags & 1;
Miklos Szeredia181e612001-11-06 12:03:23 +00001222
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001223 res = -ENOENT;
Miklos Szeredia13d9002004-11-02 17:32:03 +00001224 path = get_path(f, in->nodeid);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001225 if (path != NULL) {
1226 if (f->flags & FUSE_DEBUG) {
Miklos Szeredi1eea0322004-09-27 18:50:11 +00001227 printf("WRITE%s[%lu] %u bytes to %llu\n",
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001228 (arg->write_flags & 1) ? "PAGE" : "",
1229 (unsigned long) arg->fh, arg->size, arg->offset);
Miklos Szeredi6ebe2342002-01-06 21:44:16 +00001230 fflush(stdout);
1231 }
1232
Miklos Szeredia181e612001-11-06 12:03:23 +00001233 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001234 if (f->op.write)
Miklos Szeredifb28c5e2004-11-26 12:15:06 +00001235 res = f->op.write(path, PARAM(arg), arg->size, arg->offset, &fi);
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001236 free(path);
Miklos Szeredia181e612001-11-06 12:03:23 +00001237 }
Miklos Szeredie5183742005-02-02 11:14:04 +00001238
1239 if (res >= 0) {
Miklos Szerediad051c32004-07-02 09:22:50 +00001240 outarg.size = res;
1241 res = 0;
Miklos Szeredia181e612001-11-06 12:03:23 +00001242 }
1243
Miklos Szerediad051c32004-07-02 09:22:50 +00001244 send_reply(f, in, res, &outarg, sizeof(outarg));
Miklos Szeredia181e612001-11-06 12:03:23 +00001245}
1246
Miklos Szeredi77f39942004-03-25 11:17:52 +00001247static int default_statfs(struct statfs *buf)
1248{
1249 buf->f_namelen = 255;
1250 buf->f_bsize = 512;
1251 return 0;
1252}
1253
Miklos Szeredif458b8c2004-12-07 16:46:42 +00001254static void convert_statfs_compat(struct fuse_statfs_compat1 *compatbuf,
Miklos Szeredi0b6a0ad2004-12-04 00:40:50 +00001255 struct statfs *statfs)
1256{
1257 statfs->f_bsize = compatbuf->block_size;
1258 statfs->f_blocks = compatbuf->blocks;
1259 statfs->f_bfree = compatbuf->blocks_free;
1260 statfs->f_bavail = compatbuf->blocks_free;
1261 statfs->f_files = compatbuf->files;
1262 statfs->f_ffree = compatbuf->files_free;
1263 statfs->f_namelen = compatbuf->namelen;
1264}
1265
Miklos Szeredi18e75e42004-02-19 14:23:27 +00001266static void convert_statfs(struct statfs *statfs, struct fuse_kstatfs *kstatfs)
1267{
1268 kstatfs->bsize = statfs->f_bsize;
1269 kstatfs->blocks = statfs->f_blocks;
1270 kstatfs->bfree = statfs->f_bfree;
1271 kstatfs->bavail = statfs->f_bavail;
1272 kstatfs->files = statfs->f_files;
1273 kstatfs->ffree = statfs->f_ffree;
1274 kstatfs->namelen = statfs->f_namelen;
1275}
1276
Mark Glinesd84b39a2002-01-07 16:32:02 +00001277static void do_statfs(struct fuse *f, struct fuse_in_header *in)
1278{
1279 int res;
Mark Glinesd84b39a2002-01-07 16:32:02 +00001280 struct fuse_statfs_out arg;
Miklos Szeredi18e75e42004-02-19 14:23:27 +00001281 struct statfs buf;
Mark Glinesd84b39a2002-01-07 16:32:02 +00001282
Miklos Szeredi77f39942004-03-25 11:17:52 +00001283 memset(&buf, 0, sizeof(struct statfs));
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001284 if (f->op.statfs) {
Miklos Szeredi0b6a0ad2004-12-04 00:40:50 +00001285 if (!f->compat || f->compat > 11)
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001286 res = f->op.statfs("/", &buf);
Miklos Szeredi0b6a0ad2004-12-04 00:40:50 +00001287 else {
Miklos Szeredif458b8c2004-12-07 16:46:42 +00001288 struct fuse_statfs_compat1 compatbuf;
1289 memset(&compatbuf, 0, sizeof(struct fuse_statfs_compat1));
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001290 res = ((struct fuse_operations_compat1 *) &f->op)->statfs(&compatbuf);
Miklos Szeredi0b6a0ad2004-12-04 00:40:50 +00001291 if (res == 0)
1292 convert_statfs_compat(&compatbuf, &buf);
1293 }
1294 }
Miklos Szeredi77f39942004-03-25 11:17:52 +00001295 else
1296 res = default_statfs(&buf);
1297
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001298 if (res == 0)
Miklos Szeredi77f39942004-03-25 11:17:52 +00001299 convert_statfs(&buf, &arg.st);
Miklos Szeredi4b2bef42002-01-09 12:23:27 +00001300
Mark Glinesd84b39a2002-01-07 16:32:02 +00001301 send_reply(f, in, res, &arg, sizeof(arg));
1302}
1303
Miklos Szeredi5e43f2c2003-12-12 14:06:41 +00001304static void do_fsync(struct fuse *f, struct fuse_in_header *in,
1305 struct fuse_fsync_in *inarg)
1306{
1307 int res;
1308 char *path;
Miklos Szeredifb28c5e2004-11-26 12:15:06 +00001309 struct fuse_file_info fi;
1310
1311 memset(&fi, 0, sizeof(fi));
1312 fi.fh = inarg->fh;
Miklos Szeredi5e43f2c2003-12-12 14:06:41 +00001313
1314 res = -ENOENT;
Miklos Szeredia13d9002004-11-02 17:32:03 +00001315 path = get_path(f, in->nodeid);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001316 if (path != NULL) {
Miklos Szeredi209f5d02004-07-24 19:56:16 +00001317 if (f->flags & FUSE_DEBUG) {
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001318 printf("FSYNC[%lu]\n", (unsigned long) inarg->fh);
Miklos Szeredi209f5d02004-07-24 19:56:16 +00001319 fflush(stdout);
1320 }
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001321 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001322 if (f->op.fsync)
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001323 res = f->op.fsync(path, inarg->fsync_flags & 1, &fi);
Miklos Szeredi5e43f2c2003-12-12 14:06:41 +00001324 free(path);
1325 }
1326 send_reply(f, in, res, NULL, 0);
1327}
1328
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001329static void do_setxattr(struct fuse *f, struct fuse_in_header *in,
1330 struct fuse_setxattr_in *arg)
1331{
1332 int res;
1333 char *path;
1334 char *name = PARAM(arg);
1335 unsigned char *value = name + strlen(name) + 1;
1336
1337 res = -ENOENT;
Miklos Szeredia13d9002004-11-02 17:32:03 +00001338 path = get_path(f, in->nodeid);
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001339 if (path != NULL) {
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001340 res = -ENOSYS;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001341 if (f->op.setxattr)
1342 res = f->op.setxattr(path, name, value, arg->size, arg->flags);
1343 free(path);
Miklos Szeredie5183742005-02-02 11:14:04 +00001344 }
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001345 send_reply(f, in, res, NULL, 0);
1346}
1347
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001348static int common_getxattr(struct fuse *f, struct fuse_in_header *in,
1349 const char *name, char *value, size_t size)
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001350{
1351 int res;
1352 char *path;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001353
1354 res = -ENOENT;
Miklos Szeredia13d9002004-11-02 17:32:03 +00001355 path = get_path(f, in->nodeid);
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001356 if (path != NULL) {
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001357 res = -ENOSYS;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001358 if (f->op.getxattr)
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001359 res = f->op.getxattr(path, name, value, size);
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001360 free(path);
Miklos Szeredie5183742005-02-02 11:14:04 +00001361 }
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001362 return res;
1363}
1364
1365static void do_getxattr_read(struct fuse *f, struct fuse_in_header *in,
1366 const char *name, size_t size)
1367{
1368 int res;
1369 char *outbuf = (char *) malloc(sizeof(struct fuse_out_header) + size);
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001370 if (outbuf == NULL)
1371 send_reply(f, in, -ENOMEM, NULL, 0);
1372 else {
1373 struct fuse_out_header *out = (struct fuse_out_header *) outbuf;
1374 char *value = outbuf + sizeof(struct fuse_out_header);
Miklos Szeredie5183742005-02-02 11:14:04 +00001375
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001376 res = common_getxattr(f, in, name, value, size);
1377 size = 0;
1378 if (res > 0) {
1379 size = res;
1380 res = 0;
1381 }
1382 memset(out, 0, sizeof(struct fuse_out_header));
1383 out->unique = in->unique;
1384 out->error = res;
Miklos Szeredie5183742005-02-02 11:14:04 +00001385
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001386 send_reply_raw(f, outbuf, sizeof(struct fuse_out_header) + size);
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001387 free(outbuf);
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001388 }
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001389}
1390
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001391static void do_getxattr_size(struct fuse *f, struct fuse_in_header *in,
1392 const char *name)
1393{
1394 int res;
1395 struct fuse_getxattr_out arg;
1396
1397 res = common_getxattr(f, in, name, NULL, 0);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001398 if (res >= 0) {
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001399 arg.size = res;
1400 res = 0;
1401 }
1402 send_reply(f, in, res, &arg, sizeof(arg));
1403}
1404
1405static void do_getxattr(struct fuse *f, struct fuse_in_header *in,
1406 struct fuse_getxattr_in *arg)
1407{
1408 char *name = PARAM(arg);
Miklos Szeredie5183742005-02-02 11:14:04 +00001409
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001410 if (arg->size)
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001411 do_getxattr_read(f, in, name, arg->size);
1412 else
1413 do_getxattr_size(f, in, name);
1414}
1415
1416static int common_listxattr(struct fuse *f, struct fuse_in_header *in,
1417 char *list, size_t size)
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001418{
1419 int res;
1420 char *path;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001421
1422 res = -ENOENT;
Miklos Szeredia13d9002004-11-02 17:32:03 +00001423 path = get_path(f, in->nodeid);
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001424 if (path != NULL) {
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001425 res = -ENOSYS;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001426 if (f->op.listxattr)
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001427 res = f->op.listxattr(path, list, size);
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001428 free(path);
Miklos Szeredie5183742005-02-02 11:14:04 +00001429 }
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001430 return res;
1431}
1432
1433static void do_listxattr_read(struct fuse *f, struct fuse_in_header *in,
1434 size_t size)
1435{
1436 int res;
1437 char *outbuf = (char *) malloc(sizeof(struct fuse_out_header) + size);
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001438 if (outbuf == NULL)
1439 send_reply(f, in, -ENOMEM, NULL, 0);
1440 else {
1441 struct fuse_out_header *out = (struct fuse_out_header *) outbuf;
1442 char *list = outbuf + sizeof(struct fuse_out_header);
Miklos Szeredie5183742005-02-02 11:14:04 +00001443
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001444 res = common_listxattr(f, in, list, size);
1445 size = 0;
1446 if (res > 0) {
1447 size = res;
1448 res = 0;
1449 }
1450 memset(out, 0, sizeof(struct fuse_out_header));
1451 out->unique = in->unique;
1452 out->error = res;
Miklos Szeredie5183742005-02-02 11:14:04 +00001453
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001454 send_reply_raw(f, outbuf, sizeof(struct fuse_out_header) + size);
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001455 free(outbuf);
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001456 }
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001457}
1458
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001459static void do_listxattr_size(struct fuse *f, struct fuse_in_header *in)
1460{
1461 int res;
1462 struct fuse_getxattr_out arg;
1463
1464 res = common_listxattr(f, in, NULL, 0);
1465 if (res >= 0) {
1466 arg.size = res;
1467 res = 0;
1468 }
1469 send_reply(f, in, res, &arg, sizeof(arg));
1470}
1471
1472static void do_listxattr(struct fuse *f, struct fuse_in_header *in,
1473 struct fuse_getxattr_in *arg)
1474{
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001475 if (arg->size)
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001476 do_listxattr_read(f, in, arg->size);
1477 else
1478 do_listxattr_size(f, in);
1479}
1480
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001481static void do_removexattr(struct fuse *f, struct fuse_in_header *in,
1482 char *name)
1483{
1484 int res;
1485 char *path;
1486
1487 res = -ENOENT;
Miklos Szeredia13d9002004-11-02 17:32:03 +00001488 path = get_path(f, in->nodeid);
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001489 if (path != NULL) {
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001490 res = -ENOSYS;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001491 if (f->op.removexattr)
1492 res = f->op.removexattr(path, name);
1493 free(path);
Miklos Szeredie5183742005-02-02 11:14:04 +00001494 }
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001495 send_reply(f, in, res, NULL, 0);
1496}
1497
Miklos Szeredi3f0005f2005-01-04 19:24:31 +00001498static void do_init(struct fuse *f, struct fuse_in_header *in,
1499 struct fuse_init_in_out *arg)
1500{
1501 struct fuse_init_in_out outarg;
1502 if (f->flags & FUSE_DEBUG) {
1503 printf(" INIT: %u.%u\n", arg->major, arg->minor);
1504 fflush(stdout);
1505 }
1506 f->got_init = 1;
1507 memset(&outarg, 0, sizeof(outarg));
1508 outarg.major = FUSE_KERNEL_VERSION;
1509 outarg.minor = FUSE_KERNEL_MINOR_VERSION;
1510 send_reply(f, in, 0, &outarg, sizeof(outarg));
1511}
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001512
Miklos Szeredi3ead28e2005-01-18 21:23:41 +00001513static struct fuse_dirhandle *get_dirhandle(unsigned long fh)
1514{
1515 return (struct fuse_dirhandle *) fh;
1516}
1517
1518static void do_opendir(struct fuse *f, struct fuse_in_header *in,
1519 struct fuse_open_in *arg)
1520{
1521 int res;
1522 struct fuse_open_out outarg;
1523 struct fuse_dirhandle *dh;
1524
1525 (void) arg;
1526
1527 res = -ENOMEM;
1528 dh = (struct fuse_dirhandle *) malloc(sizeof(struct fuse_dirhandle));
1529 if (dh != NULL) {
1530 dh->fuse = f;
Miklos Szeredib92d9782005-02-07 16:10:49 +00001531 dh->contents = NULL;
1532 dh->len = 0;
Miklos Szeredi3ead28e2005-01-18 21:23:41 +00001533 dh->filled = 0;
Miklos Szeredib92d9782005-02-07 16:10:49 +00001534 outarg.fh = (unsigned long) dh;
1535 res = 0;
Miklos Szeredi3ead28e2005-01-18 21:23:41 +00001536 }
1537 send_reply(f, in, res, &outarg, sizeof(outarg));
1538}
1539
1540static void do_readdir(struct fuse *f, struct fuse_in_header *in,
1541 struct fuse_read_in *arg)
1542{
Miklos Szeredi3ead28e2005-01-18 21:23:41 +00001543 char *outbuf;
1544 struct fuse_dirhandle *dh = get_dirhandle(arg->fh);
1545
1546 if (!dh->filled) {
Miklos Szeredib92d9782005-02-07 16:10:49 +00001547 int res = common_getdir(f, in, dh);
Miklos Szeredi01fd89c2005-01-21 11:18:35 +00001548 if (res) {
Miklos Szeredi3ead28e2005-01-18 21:23:41 +00001549 send_reply(f, in, res, NULL, 0);
Miklos Szeredi01fd89c2005-01-21 11:18:35 +00001550 return;
1551 }
Miklos Szeredi3ead28e2005-01-18 21:23:41 +00001552 dh->filled = 1;
1553 }
1554 outbuf = (char *) malloc(sizeof(struct fuse_out_header) + arg->size);
1555 if (outbuf == NULL)
1556 send_reply(f, in, -ENOMEM, NULL, 0);
1557 else {
1558 struct fuse_out_header *out = (struct fuse_out_header *) outbuf;
1559 char *buf = outbuf + sizeof(struct fuse_out_header);
1560 size_t size = 0;
1561 size_t outsize;
Miklos Szeredib92d9782005-02-07 16:10:49 +00001562 if (arg->offset < dh->len) {
1563 size = arg->size;
1564 if (arg->offset + size > dh->len)
1565 size = dh->len - arg->offset;
1566
1567 memcpy(buf, dh->contents + arg->offset, size);
Miklos Szeredi3ead28e2005-01-18 21:23:41 +00001568 }
1569 memset(out, 0, sizeof(struct fuse_out_header));
1570 out->unique = in->unique;
Miklos Szeredib92d9782005-02-07 16:10:49 +00001571 out->error = 0;
Miklos Szeredi3ead28e2005-01-18 21:23:41 +00001572 outsize = sizeof(struct fuse_out_header) + size;
Miklos Szeredie5183742005-02-02 11:14:04 +00001573
Miklos Szeredi3ead28e2005-01-18 21:23:41 +00001574 send_reply_raw(f, outbuf, outsize);
1575 free(outbuf);
1576 }
1577}
1578
1579static void do_releasedir(struct fuse *f, struct fuse_in_header *in,
1580 struct fuse_release_in *arg)
1581{
1582 struct fuse_dirhandle *dh = get_dirhandle(arg->fh);
Miklos Szeredib92d9782005-02-07 16:10:49 +00001583 free(dh->contents);
Miklos Szeredi3ead28e2005-01-18 21:23:41 +00001584 free(dh);
1585 send_reply(f, in, 0, NULL, 0);
1586}
1587
1588
Miklos Szeredi43696432001-11-18 19:15:05 +00001589static void free_cmd(struct fuse_cmd *cmd)
1590{
1591 free(cmd->buf);
1592 free(cmd);
1593}
1594
Miklos Szeredif458b8c2004-12-07 16:46:42 +00001595void fuse_process_cmd(struct fuse *f, struct fuse_cmd *cmd)
Miklos Szeredia181e612001-11-06 12:03:23 +00001596{
Miklos Szeredia181e612001-11-06 12:03:23 +00001597 struct fuse_in_header *in = (struct fuse_in_header *) cmd->buf;
1598 void *inarg = cmd->buf + sizeof(struct fuse_in_header);
1599 size_t argsize;
Miklos Szeredid169f312004-09-22 08:48:26 +00001600 struct fuse_context *ctx = fuse_get_context();
Miklos Szeredia181e612001-11-06 12:03:23 +00001601
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001602 fuse_dec_avail(f);
Miklos Szeredi33232032001-11-19 17:55:51 +00001603
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001604 if ((f->flags & FUSE_DEBUG)) {
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001605 printf("unique: %llu, opcode: %s (%i), nodeid: %lu, insize: %i\n",
1606 in->unique, opname(in->opcode), in->opcode,
1607 (unsigned long) in->nodeid, cmd->buflen);
Miklos Szeredic0938ea2001-11-07 12:35:06 +00001608 fflush(stdout);
1609 }
Miklos Szeredife25def2001-12-20 15:38:05 +00001610
Miklos Szeredi3f0005f2005-01-04 19:24:31 +00001611 if (!f->got_init && in->opcode != FUSE_INIT) {
1612 /* Old kernel version probably */
1613 send_reply(f, in, -EPROTO, NULL, 0);
1614 goto out;
1615 }
1616
Miklos Szeredid169f312004-09-22 08:48:26 +00001617 ctx->fuse = f;
Miklos Szeredife25def2001-12-20 15:38:05 +00001618 ctx->uid = in->uid;
1619 ctx->gid = in->gid;
Miklos Szeredi1f18db52004-09-27 06:54:49 +00001620 ctx->pid = in->pid;
Miklos Szeredie5183742005-02-02 11:14:04 +00001621
Miklos Szeredia181e612001-11-06 12:03:23 +00001622 argsize = cmd->buflen - sizeof(struct fuse_in_header);
Miklos Szeredie5183742005-02-02 11:14:04 +00001623
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001624 switch (in->opcode) {
Miklos Szeredia181e612001-11-06 12:03:23 +00001625 case FUSE_LOOKUP:
1626 do_lookup(f, in, (char *) inarg);
1627 break;
1628
Miklos Szeredia181e612001-11-06 12:03:23 +00001629 case FUSE_GETATTR:
1630 do_getattr(f, in);
1631 break;
1632
1633 case FUSE_SETATTR:
1634 do_setattr(f, in, (struct fuse_setattr_in *) inarg);
1635 break;
1636
1637 case FUSE_READLINK:
1638 do_readlink(f, in);
1639 break;
1640
Miklos Szeredia181e612001-11-06 12:03:23 +00001641 case FUSE_MKNOD:
1642 do_mknod(f, in, (struct fuse_mknod_in *) inarg);
1643 break;
Miklos Szeredie5183742005-02-02 11:14:04 +00001644
Miklos Szeredia181e612001-11-06 12:03:23 +00001645 case FUSE_MKDIR:
1646 do_mkdir(f, in, (struct fuse_mkdir_in *) inarg);
1647 break;
Miklos Szeredie5183742005-02-02 11:14:04 +00001648
Miklos Szeredia181e612001-11-06 12:03:23 +00001649 case FUSE_UNLINK:
Miklos Szeredib5958612004-02-20 14:10:49 +00001650 do_unlink(f, in, (char *) inarg);
1651 break;
1652
Miklos Szeredia181e612001-11-06 12:03:23 +00001653 case FUSE_RMDIR:
Miklos Szeredib5958612004-02-20 14:10:49 +00001654 do_rmdir(f, in, (char *) inarg);
Miklos Szeredia181e612001-11-06 12:03:23 +00001655 break;
1656
1657 case FUSE_SYMLINK:
Miklos Szeredie5183742005-02-02 11:14:04 +00001658 do_symlink(f, in, (char *) inarg,
Miklos Szeredia181e612001-11-06 12:03:23 +00001659 ((char *) inarg) + strlen((char *) inarg) + 1);
1660 break;
1661
1662 case FUSE_RENAME:
1663 do_rename(f, in, (struct fuse_rename_in *) inarg);
1664 break;
Miklos Szeredie5183742005-02-02 11:14:04 +00001665
Miklos Szeredia181e612001-11-06 12:03:23 +00001666 case FUSE_LINK:
1667 do_link(f, in, (struct fuse_link_in *) inarg);
1668 break;
1669
1670 case FUSE_OPEN:
1671 do_open(f, in, (struct fuse_open_in *) inarg);
1672 break;
1673
Miklos Szeredie2e4ac22004-05-18 08:45:28 +00001674 case FUSE_FLUSH:
Miklos Szeredi209f5d02004-07-24 19:56:16 +00001675 do_flush(f, in, (struct fuse_flush_in *) inarg);
Miklos Szeredie2e4ac22004-05-18 08:45:28 +00001676 break;
1677
Miklos Szeredi9478e862002-12-11 09:50:26 +00001678 case FUSE_RELEASE:
Miklos Szeredi209f5d02004-07-24 19:56:16 +00001679 do_release(f, in, (struct fuse_release_in *) inarg);
Miklos Szeredi9478e862002-12-11 09:50:26 +00001680 break;
1681
Miklos Szeredia181e612001-11-06 12:03:23 +00001682 case FUSE_READ:
1683 do_read(f, in, (struct fuse_read_in *) inarg);
1684 break;
1685
1686 case FUSE_WRITE:
1687 do_write(f, in, (struct fuse_write_in *) inarg);
1688 break;
1689
Mark Glinesd84b39a2002-01-07 16:32:02 +00001690 case FUSE_STATFS:
1691 do_statfs(f, in);
1692 break;
1693
Miklos Szeredi5e43f2c2003-12-12 14:06:41 +00001694 case FUSE_FSYNC:
1695 do_fsync(f, in, (struct fuse_fsync_in *) inarg);
1696 break;
1697
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001698 case FUSE_SETXATTR:
1699 do_setxattr(f, in, (struct fuse_setxattr_in *) inarg);
1700 break;
1701
1702 case FUSE_GETXATTR:
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001703 do_getxattr(f, in, (struct fuse_getxattr_in *) inarg);
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001704 break;
1705
1706 case FUSE_LISTXATTR:
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001707 do_listxattr(f, in, (struct fuse_getxattr_in *) inarg);
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001708 break;
1709
1710 case FUSE_REMOVEXATTR:
1711 do_removexattr(f, in, (char *) inarg);
1712 break;
1713
Miklos Szeredi3f0005f2005-01-04 19:24:31 +00001714 case FUSE_INIT:
1715 do_init(f, in, (struct fuse_init_in_out *) inarg);
1716 break;
1717
Miklos Szeredi3ead28e2005-01-18 21:23:41 +00001718 case FUSE_OPENDIR:
1719 do_opendir(f, in, (struct fuse_open_in *) inarg);
1720 break;
1721
1722 case FUSE_READDIR:
1723 do_readdir(f, in, (struct fuse_read_in *) inarg);
1724 break;
1725
1726 case FUSE_RELEASEDIR:
1727 do_releasedir(f, in, (struct fuse_release_in *) inarg);
1728 break;
1729
Miklos Szeredia181e612001-11-06 12:03:23 +00001730 default:
Miklos Szeredi43696432001-11-18 19:15:05 +00001731 send_reply(f, in, -ENOSYS, NULL, 0);
Miklos Szeredia181e612001-11-06 12:03:23 +00001732 }
Miklos Szeredi43696432001-11-18 19:15:05 +00001733
Miklos Szeredi3f0005f2005-01-04 19:24:31 +00001734 out:
Miklos Szeredi43696432001-11-18 19:15:05 +00001735 free_cmd(cmd);
Miklos Szeredia181e612001-11-06 12:03:23 +00001736}
1737
Miklos Szeredif458b8c2004-12-07 16:46:42 +00001738int fuse_exited(struct fuse* f)
Miklos Szeredi65cf7c72004-06-30 11:34:56 +00001739{
1740 return f->exited;
1741}
1742
Miklos Szeredif458b8c2004-12-07 16:46:42 +00001743struct fuse_cmd *fuse_read_cmd(struct fuse *f)
Miklos Szeredi2df1c042001-11-06 15:07:17 +00001744{
Miklos Szeredifff56ab2001-11-16 10:12:59 +00001745 ssize_t res;
Miklos Szeredifff56ab2001-11-16 10:12:59 +00001746 struct fuse_cmd *cmd;
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +00001747 struct fuse_in_header *in;
1748 void *inarg;
Miklos Szeredifff56ab2001-11-16 10:12:59 +00001749
Miklos Szeredi43696432001-11-18 19:15:05 +00001750 cmd = (struct fuse_cmd *) malloc(sizeof(struct fuse_cmd));
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001751 if (cmd == NULL) {
1752 fprintf(stderr, "fuse: failed to allocate cmd in read\n");
1753 return NULL;
1754 }
Miklos Szeredi43696432001-11-18 19:15:05 +00001755 cmd->buf = (char *) malloc(FUSE_MAX_IN);
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001756 if (cmd->buf == NULL) {
1757 fprintf(stderr, "fuse: failed to allocate read buffer\n");
1758 free(cmd);
1759 return NULL;
1760 }
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +00001761 in = (struct fuse_in_header *) cmd->buf;
1762 inarg = cmd->buf + sizeof(struct fuse_in_header);
Miklos Szeredi43696432001-11-18 19:15:05 +00001763
Miklos Szeredi65cf7c72004-06-30 11:34:56 +00001764 res = read(f->fd, cmd->buf, FUSE_MAX_IN);
1765 if (res == -1) {
1766 free_cmd(cmd);
Miklos Szeredie56818b2004-12-12 11:45:24 +00001767 if (fuse_exited(f) || errno == EINTR || errno == ENOENT)
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +00001768 return NULL;
Miklos Szeredie5183742005-02-02 11:14:04 +00001769
Miklos Szeredi65cf7c72004-06-30 11:34:56 +00001770 /* ENODEV means we got unmounted, so we silenty return failure */
1771 if (errno != ENODEV) {
1772 /* BAD... This will happen again */
1773 perror("fuse: reading device");
1774 }
Miklos Szeredie5183742005-02-02 11:14:04 +00001775
Miklos Szeredi65cf7c72004-06-30 11:34:56 +00001776 fuse_exit(f);
1777 return NULL;
1778 }
1779 if ((size_t) res < sizeof(struct fuse_in_header)) {
1780 free_cmd(cmd);
1781 /* Cannot happen */
1782 fprintf(stderr, "short read on fuse device\n");
1783 fuse_exit(f);
1784 return NULL;
1785 }
1786 cmd->buflen = res;
Miklos Szeredie5183742005-02-02 11:14:04 +00001787
Miklos Szeredi65cf7c72004-06-30 11:34:56 +00001788 /* Forget is special, it can be done without messing with threads. */
1789 if (in->opcode == FUSE_FORGET) {
1790 do_forget(f, in, (struct fuse_forget_in *) inarg);
1791 free_cmd(cmd);
1792 return NULL;
1793 }
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +00001794
Miklos Szeredifff56ab2001-11-16 10:12:59 +00001795 return cmd;
Miklos Szeredi2df1c042001-11-06 15:07:17 +00001796}
1797
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001798int fuse_loop(struct fuse *f)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001799{
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001800 if (f == NULL)
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001801 return -1;
Miklos Szeredic40748a2004-02-20 16:38:45 +00001802
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001803 while (1) {
Miklos Szeredi0f48a262002-12-05 14:23:01 +00001804 struct fuse_cmd *cmd;
1805
Miklos Szeredif458b8c2004-12-07 16:46:42 +00001806 if (fuse_exited(f))
Miklos Szeredi874e3c12004-11-01 23:15:20 +00001807 break;
Miklos Szeredi0f48a262002-12-05 14:23:01 +00001808
Miklos Szeredif458b8c2004-12-07 16:46:42 +00001809 cmd = fuse_read_cmd(f);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001810 if (cmd == NULL)
Miklos Szeredi0f48a262002-12-05 14:23:01 +00001811 continue;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001812
Miklos Szeredif458b8c2004-12-07 16:46:42 +00001813 fuse_process_cmd(f, cmd);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001814 }
Miklos Szeredi874e3c12004-11-01 23:15:20 +00001815 f->exited = 0;
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001816 return 0;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001817}
1818
Miklos Szeredi891b8742004-07-29 09:27:49 +00001819int fuse_invalidate(struct fuse *f, const char *path)
1820{
Miklos Szeredie56818b2004-12-12 11:45:24 +00001821 (void) f;
1822 (void) path;
1823 return -EINVAL;
Miklos Szeredi891b8742004-07-29 09:27:49 +00001824}
1825
Miklos Szeredi0f48a262002-12-05 14:23:01 +00001826void fuse_exit(struct fuse *f)
1827{
1828 f->exited = 1;
1829}
1830
Miklos Szeredid169f312004-09-22 08:48:26 +00001831struct fuse_context *fuse_get_context()
Miklos Szeredi2e50d432001-12-20 12:17:25 +00001832{
Miklos Szeredid169f312004-09-22 08:48:26 +00001833 static struct fuse_context context;
1834 if (fuse_getcontext)
1835 return fuse_getcontext();
Miklos Szeredi2e50d432001-12-20 12:17:25 +00001836 else
Miklos Szeredid169f312004-09-22 08:48:26 +00001837 return &context;
1838}
1839
Miklos Szeredif458b8c2004-12-07 16:46:42 +00001840void fuse_set_getcontext_func(struct fuse_context *(*func)(void))
Miklos Szeredid169f312004-09-22 08:48:26 +00001841{
1842 fuse_getcontext = func;
Miklos Szeredi2e50d432001-12-20 12:17:25 +00001843}
1844
Miklos Szeredibd7661b2004-07-23 17:16:29 +00001845int fuse_is_lib_option(const char *opt)
1846{
1847 if (strcmp(opt, "debug") == 0 ||
Miklos Szeredia13d9002004-11-02 17:32:03 +00001848 strcmp(opt, "hard_remove") == 0 ||
1849 strcmp(opt, "use_ino") == 0)
Miklos Szeredibd7661b2004-07-23 17:16:29 +00001850 return 1;
1851 else
1852 return 0;
1853}
1854
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001855static int parse_lib_opts(struct fuse *f, const char *opts)
Miklos Szeredibd7661b2004-07-23 17:16:29 +00001856{
1857 if (opts) {
1858 char *xopts = strdup(opts);
1859 char *s = xopts;
1860 char *opt;
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001861
Miklos Szeredie56818b2004-12-12 11:45:24 +00001862 if (xopts == NULL) {
1863 fprintf(stderr, "fuse: memory allocation failed\n");
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001864 return -1;
Miklos Szeredie56818b2004-12-12 11:45:24 +00001865 }
Miklos Szeredie5183742005-02-02 11:14:04 +00001866
Miklos Szeredibd7661b2004-07-23 17:16:29 +00001867 while((opt = strsep(&s, ","))) {
1868 if (strcmp(opt, "debug") == 0)
1869 f->flags |= FUSE_DEBUG;
1870 else if (strcmp(opt, "hard_remove") == 0)
1871 f->flags |= FUSE_HARD_REMOVE;
Miklos Szeredia13d9002004-11-02 17:32:03 +00001872 else if (strcmp(opt, "use_ino") == 0)
1873 f->flags |= FUSE_USE_INO;
Miklos Szeredie5183742005-02-02 11:14:04 +00001874 else
Miklos Szeredibd7661b2004-07-23 17:16:29 +00001875 fprintf(stderr, "fuse: warning: unknown option `%s'\n", opt);
1876 }
1877 free(xopts);
1878 }
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001879 return 0;
Miklos Szeredibd7661b2004-07-23 17:16:29 +00001880}
1881
Miklos Szeredi0b6a0ad2004-12-04 00:40:50 +00001882struct fuse *fuse_new_common(int fd, const char *opts,
1883 const struct fuse_operations *op,
1884 size_t op_size, int compat)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001885{
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001886 struct fuse *f;
1887 struct node *root;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001888
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001889 if (sizeof(struct fuse_operations) < op_size) {
Miklos Szeredi0b6a0ad2004-12-04 00:40:50 +00001890 fprintf(stderr, "fuse: warning: library too old, some operations may not not work\n");
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001891 op_size = sizeof(struct fuse_operations);
Miklos Szeredi0b6a0ad2004-12-04 00:40:50 +00001892 }
1893
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001894 f = (struct fuse *) calloc(1, sizeof(struct fuse));
Miklos Szeredie56818b2004-12-12 11:45:24 +00001895 if (f == NULL) {
1896 fprintf(stderr, "fuse: failed to allocate fuse object\n");
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001897 goto out;
Miklos Szeredie56818b2004-12-12 11:45:24 +00001898 }
Miklos Szeredi2df1c042001-11-06 15:07:17 +00001899
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001900 if (parse_lib_opts(f, opts) == -1)
1901 goto out_free;
1902
Miklos Szeredi8cffdb92001-11-09 14:49:18 +00001903 f->fd = fd;
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001904 f->ctr = 0;
Miklos Szeredi76f65782004-02-19 16:55:40 +00001905 f->generation = 0;
Miklos Szeredifff56ab2001-11-16 10:12:59 +00001906 /* FIXME: Dynamic hash table */
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001907 f->name_table_size = 14057;
1908 f->name_table = (struct node **)
1909 calloc(1, sizeof(struct node *) * f->name_table_size);
Miklos Szeredie56818b2004-12-12 11:45:24 +00001910 if (f->name_table == NULL) {
1911 fprintf(stderr, "fuse: memory allocation failed\n");
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001912 goto out_free;
Miklos Szeredie56818b2004-12-12 11:45:24 +00001913 }
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001914
Miklos Szeredia13d9002004-11-02 17:32:03 +00001915 f->id_table_size = 14057;
1916 f->id_table = (struct node **)
1917 calloc(1, sizeof(struct node *) * f->id_table_size);
Miklos Szeredie56818b2004-12-12 11:45:24 +00001918 if (f->id_table == NULL) {
1919 fprintf(stderr, "fuse: memory allocation failed\n");
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001920 goto out_free_name_table;
Miklos Szeredie56818b2004-12-12 11:45:24 +00001921 }
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001922
Miklos Szeredia25d4c22004-11-23 22:32:16 +00001923#ifndef USE_UCLIBC
1924 pthread_mutex_init(&f->lock, NULL);
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001925 pthread_mutex_init(&f->worker_lock, NULL);
Miklos Szeredia25d4c22004-11-23 22:32:16 +00001926#else
1927 {
1928 pthread_mutexattr_t attr;
1929 pthread_mutexattr_init(&attr);
1930 pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ADAPTIVE_NP);
1931 pthread_mutex_init(&f->lock, &attr);
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001932 pthread_mutex_init(&f->worker_lock, &attr);
Miklos Szeredia25d4c22004-11-23 22:32:16 +00001933 pthread_mutexattr_destroy(&attr);
1934 }
1935#endif
Miklos Szeredi33232032001-11-19 17:55:51 +00001936 f->numworker = 0;
1937 f->numavail = 0;
Miklos Szeredi0b6a0ad2004-12-04 00:40:50 +00001938 memcpy(&f->op, op, op_size);
1939 f->compat = compat;
Miklos Szeredi0f48a262002-12-05 14:23:01 +00001940 f->exited = 0;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001941
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001942 root = (struct node *) calloc(1, sizeof(struct node));
Miklos Szeredie56818b2004-12-12 11:45:24 +00001943 if (root == NULL) {
1944 fprintf(stderr, "fuse: memory allocation failed\n");
Miklos Szeredia13d9002004-11-02 17:32:03 +00001945 goto out_free_id_table;
Miklos Szeredie56818b2004-12-12 11:45:24 +00001946 }
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001947
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001948 root->name = strdup("/");
Miklos Szeredie56818b2004-12-12 11:45:24 +00001949 if (root->name == NULL) {
1950 fprintf(stderr, "fuse: memory allocation failed\n");
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001951 goto out_free_root;
Miklos Szeredie56818b2004-12-12 11:45:24 +00001952 }
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001953
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001954 root->parent = 0;
Miklos Szeredia13d9002004-11-02 17:32:03 +00001955 root->nodeid = FUSE_ROOT_ID;
Miklos Szeredi76f65782004-02-19 16:55:40 +00001956 root->generation = 0;
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001957 root->refctr = 1;
Miklos Szeredia13d9002004-11-02 17:32:03 +00001958 hash_id(f, root);
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001959
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001960 return f;
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001961
1962 out_free_root:
1963 free(root);
Miklos Szeredia13d9002004-11-02 17:32:03 +00001964 out_free_id_table:
1965 free(f->id_table);
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001966 out_free_name_table:
1967 free(f->name_table);
1968 out_free:
1969 free(f);
1970 out:
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001971 return NULL;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001972}
1973
Miklos Szeredi0b6a0ad2004-12-04 00:40:50 +00001974struct fuse *fuse_new(int fd, const char *opts,
1975 const struct fuse_operations *op, size_t op_size)
1976{
1977 return fuse_new_common(fd, opts, op, op_size, 0);
1978}
1979
Miklos Szeredif458b8c2004-12-07 16:46:42 +00001980struct fuse *fuse_new_compat2(int fd, const char *opts,
1981 const struct fuse_operations_compat2 *op)
Miklos Szeredi0b6a0ad2004-12-04 00:40:50 +00001982{
1983 return fuse_new_common(fd, opts, (struct fuse_operations *) op,
Miklos Szeredif458b8c2004-12-07 16:46:42 +00001984 sizeof(struct fuse_operations_compat2), 21);
Miklos Szeredi0b6a0ad2004-12-04 00:40:50 +00001985}
1986
Miklos Szeredif458b8c2004-12-07 16:46:42 +00001987struct fuse *fuse_new_compat1(int fd, int flags,
1988 const struct fuse_operations_compat1 *op)
Miklos Szeredi0b6a0ad2004-12-04 00:40:50 +00001989{
1990 char *opts = NULL;
Miklos Szeredif458b8c2004-12-07 16:46:42 +00001991 if (flags & FUSE_DEBUG_COMPAT1)
Miklos Szeredi0b6a0ad2004-12-04 00:40:50 +00001992 opts = "debug";
1993 return fuse_new_common(fd, opts, (struct fuse_operations *) op,
Miklos Szeredif458b8c2004-12-07 16:46:42 +00001994 sizeof(struct fuse_operations_compat1), 11);
Miklos Szeredi0b6a0ad2004-12-04 00:40:50 +00001995}
1996
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001997void fuse_destroy(struct fuse *f)
1998{
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001999 size_t i;
Miklos Szeredia13d9002004-11-02 17:32:03 +00002000 for (i = 0; i < f->id_table_size; i++) {
Miklos Szeredi97c61e92001-11-07 12:09:43 +00002001 struct node *node;
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00002002
Miklos Szeredia13d9002004-11-02 17:32:03 +00002003 for (node = f->id_table[i]; node != NULL; node = node->id_next) {
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00002004 if (node->is_hidden) {
Miklos Szeredia13d9002004-11-02 17:32:03 +00002005 char *path = get_path(f, node->nodeid);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00002006 if (path)
2007 f->op.unlink(path);
2008 }
2009 }
2010 }
Miklos Szeredia13d9002004-11-02 17:32:03 +00002011 for (i = 0; i < f->id_table_size; i++) {
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00002012 struct node *node;
Miklos Szeredi97c61e92001-11-07 12:09:43 +00002013 struct node *next;
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00002014
Miklos Szeredia13d9002004-11-02 17:32:03 +00002015 for (node = f->id_table[i]; node != NULL; node = next) {
2016 next = node->id_next;
Miklos Szeredi97c61e92001-11-07 12:09:43 +00002017 free_node(node);
2018 }
2019 }
Miklos Szeredia13d9002004-11-02 17:32:03 +00002020 free(f->id_table);
Miklos Szeredi97c61e92001-11-07 12:09:43 +00002021 free(f->name_table);
Miklos Szeredia181e612001-11-06 12:03:23 +00002022 pthread_mutex_destroy(&f->lock);
Miklos Szeredi0f62d722005-01-04 12:45:54 +00002023 pthread_mutex_destroy(&f->worker_lock);
Miklos Szeredi97c61e92001-11-07 12:09:43 +00002024 free(f);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00002025}
Miklos Szeredi0b6a0ad2004-12-04 00:40:50 +00002026
Miklos Szeredif458b8c2004-12-07 16:46:42 +00002027__asm__(".symver fuse_exited,__fuse_exited@");
2028__asm__(".symver fuse_process_cmd,__fuse_process_cmd@");
2029__asm__(".symver fuse_read_cmd,__fuse_read_cmd@");
2030__asm__(".symver fuse_set_getcontext_func,__fuse_set_getcontext_func@");
2031__asm__(".symver fuse_new_compat2,fuse_new@");