blob: 59f8b453b26d6b6dd3dc643a4ef161bd57a99a0c [file] [log] [blame]
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001/*
2 FUSE: Filesystem in Userspace
Miklos Szeredi2e6b6f22004-07-07 19:19:53 +00003 Copyright (C) 2001-2004 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"
11#include <linux/fuse.h>
12
13#include <string.h>
Miklos Szeredi97c61e92001-11-07 12:09:43 +000014#include <stdlib.h>
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000015#include <unistd.h>
Miklos Szeredi97c61e92001-11-07 12:09:43 +000016#include <limits.h>
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000017#include <errno.h>
Miklos Szeredi019b4e92001-12-26 18:08:09 +000018#include <sys/param.h>
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000019
Miklos Szeredia25d4c22004-11-23 22:32:16 +000020#define FUSE_VERSION_FILE_OLD "/proc/fs/fuse/version"
21#define FUSE_DEV_OLD "/proc/fs/fuse/dev"
22
Miklos Szeredi97c61e92001-11-07 12:09:43 +000023#define FUSE_MAX_PATH 4096
Miklos Szeredi6bf8b682002-10-28 08:49:39 +000024#define PARAM(inarg) (((char *)(inarg)) + sizeof(*inarg))
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000025
Miklos Szeredi254d5ed2004-03-02 11:11:24 +000026#define ENTRY_REVALIDATE_TIME 1 /* sec */
27#define ATTR_REVALIDATE_TIME 1 /* sec */
28
Miklos Szeredid169f312004-09-22 08:48:26 +000029static struct fuse_context *(*fuse_getcontext)(void) = NULL;
30
Miklos Szeredic8ba2372002-12-10 12:26:00 +000031static const char *opname(enum fuse_opcode opcode)
32{
Miklos Szeredi7eafcce2004-06-19 22:42:38 +000033 switch (opcode) {
Miklos Szeredi3ed84232004-03-30 15:17:26 +000034 case FUSE_LOOKUP: return "LOOKUP";
35 case FUSE_FORGET: return "FORGET";
36 case FUSE_GETATTR: return "GETATTR";
37 case FUSE_SETATTR: return "SETATTR";
38 case FUSE_READLINK: return "READLINK";
39 case FUSE_SYMLINK: return "SYMLINK";
40 case FUSE_GETDIR: return "GETDIR";
41 case FUSE_MKNOD: return "MKNOD";
42 case FUSE_MKDIR: return "MKDIR";
43 case FUSE_UNLINK: return "UNLINK";
44 case FUSE_RMDIR: return "RMDIR";
45 case FUSE_RENAME: return "RENAME";
46 case FUSE_LINK: return "LINK";
47 case FUSE_OPEN: return "OPEN";
48 case FUSE_READ: return "READ";
49 case FUSE_WRITE: return "WRITE";
50 case FUSE_STATFS: return "STATFS";
Miklos Szeredi99f20742004-05-19 08:01:10 +000051 case FUSE_FLUSH: return "FLUSH";
Miklos Szeredi3ed84232004-03-30 15:17:26 +000052 case FUSE_RELEASE: return "RELEASE";
53 case FUSE_FSYNC: return "FSYNC";
54 case FUSE_SETXATTR: return "SETXATTR";
55 case FUSE_GETXATTR: return "GETXATTR";
56 case FUSE_LISTXATTR: return "LISTXATTR";
57 case FUSE_REMOVEXATTR: return "REMOVEXATTR";
Miklos Szeredi99f20742004-05-19 08:01:10 +000058 default: return "???";
Miklos Szeredic8ba2372002-12-10 12:26:00 +000059 }
60}
61
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +000062
63static inline void dec_avail(struct fuse *f)
64{
65 pthread_mutex_lock(&f->lock);
66 f->numavail --;
67 pthread_mutex_unlock(&f->lock);
68}
69
Miklos Szeredia13d9002004-11-02 17:32:03 +000070static struct node *__get_node(struct fuse *f, nodeid_t nodeid)
Miklos Szeredia181e612001-11-06 12:03:23 +000071{
Miklos Szeredia13d9002004-11-02 17:32:03 +000072 size_t hash = nodeid % f->id_table_size;
Miklos Szeredi97c61e92001-11-07 12:09:43 +000073 struct node *node;
74
Miklos Szeredia13d9002004-11-02 17:32:03 +000075 for (node = f->id_table[hash]; node != NULL; node = node->id_next)
76 if (node->nodeid == nodeid)
Miklos Szeredi97c61e92001-11-07 12:09:43 +000077 return node;
78
79 return NULL;
Miklos Szeredia181e612001-11-06 12:03:23 +000080}
81
Miklos Szeredia13d9002004-11-02 17:32:03 +000082static struct node *get_node(struct fuse *f, nodeid_t nodeid)
Miklos Szeredia181e612001-11-06 12:03:23 +000083{
Miklos Szeredia13d9002004-11-02 17:32:03 +000084 struct node *node = __get_node(f, nodeid);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +000085 if (node != NULL)
Miklos Szeredi97c61e92001-11-07 12:09:43 +000086 return node;
87
Miklos Szeredia13d9002004-11-02 17:32:03 +000088 fprintf(stderr, "fuse internal error: inode %lu not found\n", nodeid);
Miklos Szeredi97c61e92001-11-07 12:09:43 +000089 abort();
Miklos Szeredia181e612001-11-06 12:03:23 +000090}
91
Miklos Szeredia13d9002004-11-02 17:32:03 +000092static void hash_id(struct fuse *f, struct node *node)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000093{
Miklos Szeredia13d9002004-11-02 17:32:03 +000094 size_t hash = node->nodeid % f->id_table_size;
95 node->id_next = f->id_table[hash];
96 f->id_table[hash] = node;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000097}
98
Miklos Szeredia13d9002004-11-02 17:32:03 +000099static void unhash_id(struct fuse *f, struct node *node)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000100{
Miklos Szeredia13d9002004-11-02 17:32:03 +0000101 size_t hash = node->nodeid % f->id_table_size;
102 struct node **nodep = &f->id_table[hash];
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000103
Miklos Szeredia13d9002004-11-02 17:32:03 +0000104 for (; *nodep != NULL; nodep = &(*nodep)->id_next)
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000105 if (*nodep == node) {
Miklos Szeredia13d9002004-11-02 17:32:03 +0000106 *nodep = node->id_next;
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000107 return;
108 }
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000109}
110
Miklos Szeredia13d9002004-11-02 17:32:03 +0000111static nodeid_t next_id(struct fuse *f)
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000112{
Miklos Szeredi76f65782004-02-19 16:55:40 +0000113 do {
114 f->ctr++;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000115 if (!f->ctr)
Miklos Szeredi76f65782004-02-19 16:55:40 +0000116 f->generation ++;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000117 } while (f->ctr == 0 || __get_node(f, f->ctr) != NULL);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000118 return f->ctr;
119}
120
121static void free_node(struct node *node)
122{
123 free(node->name);
124 free(node);
125}
126
Miklos Szeredia13d9002004-11-02 17:32:03 +0000127static unsigned int name_hash(struct fuse *f, nodeid_t parent, const char *name)
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000128{
129 unsigned int hash = *name;
130
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000131 if (hash)
132 for (name += 1; *name != '\0'; name++)
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000133 hash = (hash << 5) - hash + *name;
134
135 return (hash + parent) % f->name_table_size;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000136}
137
Miklos Szeredia13d9002004-11-02 17:32:03 +0000138static struct node *__lookup_node(struct fuse *f, nodeid_t parent,
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000139 const char *name)
140{
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000141 size_t hash = name_hash(f, parent, name);
142 struct node *node;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000143
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000144 for (node = f->name_table[hash]; node != NULL; node = node->name_next)
145 if (node->parent == parent && strcmp(node->name, name) == 0)
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000146 return node;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000147
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000148 return NULL;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000149}
150
Miklos Szeredia13d9002004-11-02 17:32:03 +0000151static struct node *lookup_node(struct fuse *f, nodeid_t parent,
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000152 const char *name)
153{
154 struct node *node;
155
156 pthread_mutex_lock(&f->lock);
157 node = __lookup_node(f, parent, name);
158 pthread_mutex_unlock(&f->lock);
159 if (node != NULL)
160 return node;
161
162 fprintf(stderr, "fuse internal error: node %lu/%s not found\n", parent,
163 name);
164 abort();
165}
166
Miklos Szeredia13d9002004-11-02 17:32:03 +0000167static int hash_name(struct fuse *f, struct node *node, nodeid_t parent,
Miklos Szeredib2cf9562004-09-16 08:42:40 +0000168 const char *name)
Miklos Szeredi5e183482001-10-31 14:52:35 +0000169{
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000170 size_t hash = name_hash(f, parent, name);
Miklos Szeredia181e612001-11-06 12:03:23 +0000171 node->parent = parent;
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000172 node->name = strdup(name);
Miklos Szeredib2cf9562004-09-16 08:42:40 +0000173 if (node->name == NULL)
174 return -1;
175
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000176 node->name_next = f->name_table[hash];
Miklos Szeredib2cf9562004-09-16 08:42:40 +0000177 f->name_table[hash] = node;
178 return 0;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000179}
180
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000181static void unhash_name(struct fuse *f, struct node *node)
Miklos Szeredia181e612001-11-06 12:03:23 +0000182{
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000183 if (node->name != NULL) {
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000184 size_t hash = name_hash(f, node->parent, node->name);
185 struct node **nodep = &f->name_table[hash];
186
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000187 for (; *nodep != NULL; nodep = &(*nodep)->name_next)
188 if (*nodep == node) {
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000189 *nodep = node->name_next;
190 node->name_next = NULL;
191 free(node->name);
192 node->name = NULL;
193 node->parent = 0;
194 return;
195 }
196 fprintf(stderr, "fuse internal error: unable to unhash node: %lu\n",
Miklos Szeredia13d9002004-11-02 17:32:03 +0000197 node->nodeid);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000198 abort();
Miklos Szeredia181e612001-11-06 12:03:23 +0000199 }
200}
201
Miklos Szeredia13d9002004-11-02 17:32:03 +0000202static struct node *find_node(struct fuse *f, nodeid_t parent, char *name,
Miklos Szeredi76f65782004-02-19 16:55:40 +0000203 struct fuse_attr *attr, int version)
Miklos Szeredi5e183482001-10-31 14:52:35 +0000204{
205 struct node *node;
Miklos Szeredia181e612001-11-06 12:03:23 +0000206 int mode = attr->mode & S_IFMT;
207 int rdev = 0;
208
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000209 if (S_ISCHR(mode) || S_ISBLK(mode))
Miklos Szeredia181e612001-11-06 12:03:23 +0000210 rdev = attr->rdev;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000211
Miklos Szeredia181e612001-11-06 12:03:23 +0000212 pthread_mutex_lock(&f->lock);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000213 node = __lookup_node(f, parent, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000214 if (node != NULL) {
Miklos Szeredia13d9002004-11-02 17:32:03 +0000215 if (node->mode == mode && node->rdev == rdev &&
216 (!(f->flags & FUSE_USE_INO) || node->ino == attr->ino)) {
217 if (!(f->flags & FUSE_USE_INO))
218 attr->ino = node->nodeid;
219
Miklos Szeredia181e612001-11-06 12:03:23 +0000220 goto out;
Miklos Szeredia13d9002004-11-02 17:32:03 +0000221 }
Miklos Szeredia181e612001-11-06 12:03:23 +0000222
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000223 unhash_name(f, node);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000224 }
225
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000226 node = (struct node *) calloc(1, sizeof(struct node));
Miklos Szeredib2cf9562004-09-16 08:42:40 +0000227 if (node == NULL)
Miklos Szeredic2309912004-09-21 13:40:38 +0000228 goto out_err;
Miklos Szeredib2cf9562004-09-16 08:42:40 +0000229
Miklos Szeredia13d9002004-11-02 17:32:03 +0000230 node->nodeid = next_id(f);
231 if (!(f->flags & FUSE_USE_INO))
232 attr->ino = node->nodeid;
Miklos Szeredia181e612001-11-06 12:03:23 +0000233 node->mode = mode;
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000234 node->rdev = rdev;
Miklos Szeredia13d9002004-11-02 17:32:03 +0000235 node->ino = attr->ino;
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000236 node->open_count = 0;
237 node->is_hidden = 0;
Miklos Szeredi76f65782004-02-19 16:55:40 +0000238 node->generation = f->generation;
Miklos Szeredib2cf9562004-09-16 08:42:40 +0000239 if (hash_name(f, node, parent, name) == -1) {
240 free(node);
Miklos Szeredic2309912004-09-21 13:40:38 +0000241 node = NULL;
242 goto out_err;
Miklos Szeredib2cf9562004-09-16 08:42:40 +0000243 }
Miklos Szeredia13d9002004-11-02 17:32:03 +0000244 hash_id(f, node);
Miklos Szeredia181e612001-11-06 12:03:23 +0000245
Miklos Szeredic2309912004-09-21 13:40:38 +0000246 out:
Miklos Szeredia181e612001-11-06 12:03:23 +0000247 node->version = version;
Miklos Szeredic2309912004-09-21 13:40:38 +0000248 out_err:
Miklos Szeredia181e612001-11-06 12:03:23 +0000249 pthread_mutex_unlock(&f->lock);
Miklos Szeredi76f65782004-02-19 16:55:40 +0000250 return node;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000251}
252
Miklos Szeredia13d9002004-11-02 17:32:03 +0000253static int path_lookup(struct fuse *f, const char *path, nodeid_t *nodeidp,
254 unsigned long *inop)
Miklos Szeredi891b8742004-07-29 09:27:49 +0000255{
Miklos Szeredia13d9002004-11-02 17:32:03 +0000256 nodeid_t nodeid;
257 unsigned long ino;
Miklos Szeredi891b8742004-07-29 09:27:49 +0000258 int err;
259 char *s;
260 char *name;
261 char *tmp = strdup(path);
262 if (!tmp)
263 return -ENOMEM;
264
265 pthread_mutex_lock(&f->lock);
Miklos Szeredia13d9002004-11-02 17:32:03 +0000266 nodeid = FUSE_ROOT_ID;
267 ino = nodeid;
Miklos Szeredi891b8742004-07-29 09:27:49 +0000268 err = 0;
269 for (s = tmp; (name = strsep(&s, "/")) != NULL; ) {
270 if (name[0]) {
Miklos Szeredia13d9002004-11-02 17:32:03 +0000271 struct node *node = __lookup_node(f, nodeid, name);
Miklos Szeredi891b8742004-07-29 09:27:49 +0000272 if (node == NULL) {
273 err = -ENOENT;
274 break;
275 }
Miklos Szeredia13d9002004-11-02 17:32:03 +0000276 nodeid = node->nodeid;
Miklos Szeredi891b8742004-07-29 09:27:49 +0000277 ino = node->ino;
278 }
279 }
280 pthread_mutex_unlock(&f->lock);
281 free(tmp);
Miklos Szeredia13d9002004-11-02 17:32:03 +0000282 if (!err) {
283 *nodeidp = nodeid;
Miklos Szeredi891b8742004-07-29 09:27:49 +0000284 *inop = ino;
Miklos Szeredia13d9002004-11-02 17:32:03 +0000285 }
Miklos Szeredi891b8742004-07-29 09:27:49 +0000286
287 return err;
288}
289
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000290static char *add_name(char *buf, char *s, const char *name)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000291{
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000292 size_t len = strlen(name);
293 s -= len;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000294 if (s <= buf) {
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000295 fprintf(stderr, "fuse: path too long: ...%s\n", s + len);
296 return NULL;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000297 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000298 strncpy(s, name, len);
299 s--;
300 *s = '/';
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000301
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000302 return s;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000303}
304
Miklos Szeredia13d9002004-11-02 17:32:03 +0000305static char *get_path_name(struct fuse *f, nodeid_t nodeid, const char *name)
Miklos Szeredib483c932001-10-29 14:57:57 +0000306{
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000307 char buf[FUSE_MAX_PATH];
308 char *s = buf + FUSE_MAX_PATH - 1;
309 struct node *node;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000310
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000311 *s = '\0';
Miklos Szeredia181e612001-11-06 12:03:23 +0000312
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000313 if (name != NULL) {
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000314 s = add_name(buf, s, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000315 if (s == NULL)
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000316 return NULL;
317 }
318
319 pthread_mutex_lock(&f->lock);
Miklos Szeredia13d9002004-11-02 17:32:03 +0000320 for (node = get_node(f, nodeid); node->nodeid != FUSE_ROOT_ID;
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000321 node = get_node(f, node->parent)) {
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000322 if (node->name == NULL) {
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000323 s = NULL;
324 break;
325 }
326
327 s = add_name(buf, s, node->name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000328 if (s == NULL)
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000329 break;
330 }
331 pthread_mutex_unlock(&f->lock);
332
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000333 if (s == NULL)
Miklos Szeredi5e183482001-10-31 14:52:35 +0000334 return NULL;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000335 else if (*s == '\0')
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000336 return strdup("/");
337 else
338 return strdup(s);
339}
Miklos Szeredia181e612001-11-06 12:03:23 +0000340
Miklos Szeredia13d9002004-11-02 17:32:03 +0000341static char *get_path(struct fuse *f, nodeid_t nodeid)
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000342{
Miklos Szeredia13d9002004-11-02 17:32:03 +0000343 return get_path_name(f, nodeid, NULL);
Miklos Szeredib483c932001-10-29 14:57:57 +0000344}
345
Miklos Szeredia13d9002004-11-02 17:32:03 +0000346static void destroy_node(struct fuse *f, nodeid_t nodeid, int version)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000347{
Miklos Szeredia181e612001-11-06 12:03:23 +0000348 struct node *node;
349
350 pthread_mutex_lock(&f->lock);
Miklos Szeredia13d9002004-11-02 17:32:03 +0000351 node = __get_node(f, nodeid);
352 if (node && node->version == version && nodeid != FUSE_ROOT_ID) {
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000353 unhash_name(f, node);
Miklos Szeredia13d9002004-11-02 17:32:03 +0000354 unhash_id(f, node);
Miklos Szeredia181e612001-11-06 12:03:23 +0000355 free_node(node);
356 }
357 pthread_mutex_unlock(&f->lock);
358
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000359}
360
Miklos Szeredia13d9002004-11-02 17:32:03 +0000361static void remove_node(struct fuse *f, nodeid_t dir, const char *name)
Miklos Szeredi5e183482001-10-31 14:52:35 +0000362{
Miklos Szeredia181e612001-11-06 12:03:23 +0000363 struct node *node;
364
365 pthread_mutex_lock(&f->lock);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000366 node = __lookup_node(f, dir, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000367 if (node == NULL) {
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000368 fprintf(stderr, "fuse internal error: unable to remove node %lu/%s\n",
369 dir, name);
370 abort();
371 }
372 unhash_name(f, node);
Miklos Szeredia181e612001-11-06 12:03:23 +0000373 pthread_mutex_unlock(&f->lock);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000374}
375
Miklos Szeredia13d9002004-11-02 17:32:03 +0000376static int rename_node(struct fuse *f, nodeid_t olddir, const char *oldname,
377 nodeid_t newdir, const char *newname, int hide)
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000378{
Miklos Szeredia181e612001-11-06 12:03:23 +0000379 struct node *node;
380 struct node *newnode;
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000381 int err = 0;
Miklos Szeredia181e612001-11-06 12:03:23 +0000382
383 pthread_mutex_lock(&f->lock);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000384 node = __lookup_node(f, olddir, oldname);
385 newnode = __lookup_node(f, newdir, newname);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000386 if (node == NULL) {
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000387 fprintf(stderr, "fuse internal error: unable to rename node %lu/%s\n",
388 olddir, oldname);
389 abort();
390 }
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000391
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000392 if (newnode != NULL) {
393 if (hide) {
394 fprintf(stderr, "fuse: hidden file got created during hiding\n");
Miklos Szeredib2cf9562004-09-16 08:42:40 +0000395 err = -EBUSY;
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000396 goto out;
397 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000398 unhash_name(f, newnode);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000399 }
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000400
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000401 unhash_name(f, node);
Miklos Szeredib2cf9562004-09-16 08:42:40 +0000402 if (hash_name(f, node, newdir, newname) == -1) {
403 err = -ENOMEM;
404 goto out;
405 }
406
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000407 if (hide)
408 node->is_hidden = 1;
409
410 out:
Miklos Szeredia181e612001-11-06 12:03:23 +0000411 pthread_mutex_unlock(&f->lock);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000412 return err;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000413}
414
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000415static void convert_stat(struct stat *stbuf, struct fuse_attr *attr)
416{
Miklos Szeredia13d9002004-11-02 17:32:03 +0000417 attr->ino = stbuf->st_ino;
Miklos Szeredib5958612004-02-20 14:10:49 +0000418 attr->mode = stbuf->st_mode;
419 attr->nlink = stbuf->st_nlink;
420 attr->uid = stbuf->st_uid;
421 attr->gid = stbuf->st_gid;
422 attr->rdev = stbuf->st_rdev;
423 attr->size = stbuf->st_size;
424 attr->blocks = stbuf->st_blocks;
425 attr->atime = stbuf->st_atime;
Miklos Szeredib5958612004-02-20 14:10:49 +0000426 attr->mtime = stbuf->st_mtime;
Miklos Szeredib5958612004-02-20 14:10:49 +0000427 attr->ctime = stbuf->st_ctime;
Miklos Szeredicb264512004-06-23 18:52:50 +0000428#ifdef HAVE_STRUCT_STAT_ST_ATIM
429 attr->atimensec = stbuf->st_atim.tv_nsec;
430 attr->mtimensec = stbuf->st_mtim.tv_nsec;
Miklos Szeredib5958612004-02-20 14:10:49 +0000431 attr->ctimensec = stbuf->st_ctim.tv_nsec;
Miklos Szeredicb264512004-06-23 18:52:50 +0000432#endif
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000433}
434
Miklos Szeredi8fb48fe2004-11-08 14:48:52 +0000435static int fill_dir(struct fuse_dirhandle *dh, const char *name, int type,
436 ino_t ino)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000437{
438 struct fuse_dirent dirent;
439 size_t reclen;
440 size_t res;
441
Miklos Szeredi8fb48fe2004-11-08 14:48:52 +0000442 if ((dh->fuse->flags & FUSE_USE_INO))
443 dirent.ino = ino;
444 else
445 dirent.ino = (unsigned long) -1;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000446 dirent.namelen = strlen(name);
447 strncpy(dirent.name, name, sizeof(dirent.name));
448 dirent.type = type;
449 reclen = FUSE_DIRENT_SIZE(&dirent);
450 res = fwrite(&dirent, reclen, 1, dh->fp);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000451 if (res == 0) {
Miklos Szeredi96249982001-11-21 12:21:19 +0000452 perror("fuse: writing directory file");
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000453 return -EIO;
454 }
455 return 0;
456}
457
Miklos Szeredi73798f92004-07-12 15:55:11 +0000458static int send_reply_raw(struct fuse *f, char *outbuf, size_t outsize,
459 int locked)
Miklos Szeredi43696432001-11-18 19:15:05 +0000460{
461 int res;
462
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000463 if ((f->flags & FUSE_DEBUG)) {
Miklos Szeredi43696432001-11-18 19:15:05 +0000464 struct fuse_out_header *out = (struct fuse_out_header *) outbuf;
465 printf(" unique: %i, error: %i (%s), outsize: %i\n", out->unique,
466 out->error, strerror(-out->error), outsize);
467 fflush(stdout);
468 }
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +0000469
Miklos Szeredi4e71c9f2004-02-09 12:05:14 +0000470 /* This needs to be done before the reply, otherwise the scheduler
471 could play tricks with us, and only let the counter be increased
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +0000472 long after the operation is done */
Miklos Szeredi73798f92004-07-12 15:55:11 +0000473 if (!locked)
474 pthread_mutex_lock(&f->lock);
475 f->numavail ++;
476 if (!locked)
477 pthread_mutex_unlock(&f->lock);
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +0000478
Miklos Szeredi43696432001-11-18 19:15:05 +0000479 res = write(f->fd, outbuf, outsize);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000480 if (res == -1) {
Miklos Szeredi43696432001-11-18 19:15:05 +0000481 /* ENOENT means the operation was interrupted */
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000482 if (!f->exited && errno != ENOENT)
Miklos Szeredi96249982001-11-21 12:21:19 +0000483 perror("fuse: writing device");
Miklos Szeredi40b9a5a2002-12-10 16:09:02 +0000484 return -errno;
Miklos Szeredi43696432001-11-18 19:15:05 +0000485 }
Miklos Szeredi40b9a5a2002-12-10 16:09:02 +0000486 return 0;
Miklos Szeredi43696432001-11-18 19:15:05 +0000487}
488
Miklos Szeredi73798f92004-07-12 15:55:11 +0000489static int __send_reply(struct fuse *f, struct fuse_in_header *in, int error,
490 void *arg, size_t argsize, int locked)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000491{
Miklos Szeredi40b9a5a2002-12-10 16:09:02 +0000492 int res;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000493 char *outbuf;
494 size_t outsize;
495 struct fuse_out_header *out;
496
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000497 if (error <= -1000 || error > 0) {
Miklos Szeredi0f48a262002-12-05 14:23:01 +0000498 fprintf(stderr, "fuse: bad error value: %i\n", error);
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000499 error = -ERANGE;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000500 }
501
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000502 if (error)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000503 argsize = 0;
504
505 outsize = sizeof(struct fuse_out_header) + argsize;
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000506 outbuf = (char *) malloc(outsize);
Miklos Szeredib2cf9562004-09-16 08:42:40 +0000507 if (outbuf == NULL) {
508 fprintf(stderr, "fuse: failed to allocate reply buffer\n");
509 res = -ENOMEM;
510 } else {
511 out = (struct fuse_out_header *) outbuf;
512 memset(out, 0, sizeof(struct fuse_out_header));
513 out->unique = in->unique;
514 out->error = error;
515 if (argsize != 0)
516 memcpy(outbuf + sizeof(struct fuse_out_header), arg, argsize);
517
518 res = send_reply_raw(f, outbuf, outsize, locked);
519 free(outbuf);
520 }
Miklos Szeredi40b9a5a2002-12-10 16:09:02 +0000521
522 return res;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000523}
524
Miklos Szeredi73798f92004-07-12 15:55:11 +0000525static int send_reply(struct fuse *f, struct fuse_in_header *in, int error,
526 void *arg, size_t argsize)
527{
528 return __send_reply(f, in, error, arg, argsize, 0);
529}
530
Miklos Szeredia13d9002004-11-02 17:32:03 +0000531static int is_open(struct fuse *f, nodeid_t dir, const char *name)
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000532{
533 struct node *node;
534 int isopen = 0;
535 pthread_mutex_lock(&f->lock);
536 node = __lookup_node(f, dir, name);
537 if (node && node->open_count > 0)
538 isopen = 1;
539 pthread_mutex_unlock(&f->lock);
540 return isopen;
541}
542
Miklos Szeredia13d9002004-11-02 17:32:03 +0000543static char *hidden_name(struct fuse *f, nodeid_t dir, const char *oldname,
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000544 char *newname, size_t bufsize)
545{
546 struct stat buf;
547 struct node *node;
548 struct node *newnode;
549 char *newpath;
550 int res;
551 int failctr = 10;
552
553 if (!f->op.getattr)
554 return NULL;
555
556 do {
557 node = lookup_node(f, dir, oldname);
558 pthread_mutex_lock(&f->lock);
559 do {
560 f->hidectr ++;
561 snprintf(newname, bufsize, ".fuse_hidden%08x%08x",
Miklos Szeredia13d9002004-11-02 17:32:03 +0000562 (unsigned int) node->nodeid, f->hidectr);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000563 newnode = __lookup_node(f, dir, newname);
564 } while(newnode);
565 pthread_mutex_unlock(&f->lock);
566
567 newpath = get_path_name(f, dir, newname);
568 if (!newpath)
569 break;
570
571 res = f->op.getattr(newpath, &buf);
572 if (res != 0)
573 break;
574 free(newpath);
575 newpath = NULL;
576 } while(--failctr);
577
578 return newpath;
579}
580
Miklos Szeredia13d9002004-11-02 17:32:03 +0000581static int hide_node(struct fuse *f, const char *oldpath, nodeid_t dir,
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000582 const char *oldname)
583{
584 char newname[64];
585 char *newpath;
Miklos Szeredib2cf9562004-09-16 08:42:40 +0000586 int err = -EBUSY;
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000587
Miklos Szeredib2cf9562004-09-16 08:42:40 +0000588 if (f->op.rename && f->op.unlink) {
589 newpath = hidden_name(f, dir, oldname, newname, sizeof(newname));
590 if (newpath) {
591 int res = f->op.rename(oldpath, newpath);
592 if (res == 0)
593 err = rename_node(f, dir, oldname, dir, newname, 1);
594 free(newpath);
595 }
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000596 }
Miklos Szeredib2cf9562004-09-16 08:42:40 +0000597 return err;
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000598}
599
Miklos Szeredia13d9002004-11-02 17:32:03 +0000600static int lookup_path(struct fuse *f, nodeid_t nodeid, int version, char *name,
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000601 const char *path, struct fuse_entry_out *arg)
Miklos Szeredi76f65782004-02-19 16:55:40 +0000602{
603 int res;
604 struct stat buf;
605
606 res = f->op.getattr(path, &buf);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000607 if (res == 0) {
Miklos Szeredi76f65782004-02-19 16:55:40 +0000608 struct node *node;
609
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000610 memset(arg, 0, sizeof(struct fuse_entry_out));
Miklos Szeredi76f65782004-02-19 16:55:40 +0000611 convert_stat(&buf, &arg->attr);
Miklos Szeredia13d9002004-11-02 17:32:03 +0000612 node = find_node(f, nodeid, name, &arg->attr, version);
Miklos Szeredib2cf9562004-09-16 08:42:40 +0000613 if (node == NULL)
614 res = -ENOMEM;
615 else {
Miklos Szeredia13d9002004-11-02 17:32:03 +0000616 arg->nodeid = node->nodeid;
Miklos Szeredib2cf9562004-09-16 08:42:40 +0000617 arg->generation = node->generation;
618 arg->entry_valid = ENTRY_REVALIDATE_TIME;
619 arg->entry_valid_nsec = 0;
620 arg->attr_valid = ATTR_REVALIDATE_TIME;
621 arg->attr_valid_nsec = 0;
622 if (f->flags & FUSE_DEBUG) {
Miklos Szeredia13d9002004-11-02 17:32:03 +0000623 printf(" NODEID: %li\n", arg->nodeid);
Miklos Szeredib2cf9562004-09-16 08:42:40 +0000624 fflush(stdout);
625 }
Miklos Szeredi76f65782004-02-19 16:55:40 +0000626 }
627 }
628 return res;
629}
630
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000631static void do_lookup(struct fuse *f, struct fuse_in_header *in, char *name)
632{
633 int res;
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000634 int res2;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000635 char *path;
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000636 struct fuse_entry_out arg;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000637
Miklos Szeredi5e183482001-10-31 14:52:35 +0000638 res = -ENOENT;
Miklos Szeredia13d9002004-11-02 17:32:03 +0000639 path = get_path_name(f, in->nodeid, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000640 if (path != NULL) {
641 if (f->flags & FUSE_DEBUG) {
Miklos Szeredi6ebe2342002-01-06 21:44:16 +0000642 printf("LOOKUP %s\n", path);
643 fflush(stdout);
644 }
Miklos Szeredi5e183482001-10-31 14:52:35 +0000645 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000646 if (f->op.getattr)
Miklos Szeredia13d9002004-11-02 17:32:03 +0000647 res = lookup_path(f, in->nodeid, in->unique, name, path, &arg);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000648 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000649 }
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000650 res2 = send_reply(f, in, res, &arg, sizeof(arg));
651 if (res == 0 && res2 == -ENOENT)
Miklos Szeredia13d9002004-11-02 17:32:03 +0000652 destroy_node(f, arg.nodeid, in->unique);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000653}
654
Miklos Szeredia181e612001-11-06 12:03:23 +0000655static void do_forget(struct fuse *f, struct fuse_in_header *in,
656 struct fuse_forget_in *arg)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000657{
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000658 if (f->flags & FUSE_DEBUG) {
Miklos Szeredia13d9002004-11-02 17:32:03 +0000659 printf("FORGET %li/%i\n", in->nodeid, arg->version);
Miklos Szeredi43696432001-11-18 19:15:05 +0000660 fflush(stdout);
661 }
Miklos Szeredia13d9002004-11-02 17:32:03 +0000662 destroy_node(f, in->nodeid, arg->version);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000663}
664
665static void do_getattr(struct fuse *f, struct fuse_in_header *in)
666{
667 int res;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000668 char *path;
669 struct stat buf;
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000670 struct fuse_attr_out arg;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000671
Miklos Szeredi5e183482001-10-31 14:52:35 +0000672 res = -ENOENT;
Miklos Szeredia13d9002004-11-02 17:32:03 +0000673 path = get_path(f, in->nodeid);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000674 if (path != NULL) {
Miklos Szeredi5e183482001-10-31 14:52:35 +0000675 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000676 if (f->op.getattr)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000677 res = f->op.getattr(path, &buf);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000678 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000679 }
Miklos Szeredi0f48a262002-12-05 14:23:01 +0000680
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000681 if (res == 0) {
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000682 memset(&arg, 0, sizeof(struct fuse_attr_out));
683 arg.attr_valid = ATTR_REVALIDATE_TIME;
684 arg.attr_valid_nsec = 0;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000685 convert_stat(&buf, &arg.attr);
Miklos Szeredia13d9002004-11-02 17:32:03 +0000686 if (!(f->flags & FUSE_USE_INO))
687 arg.attr.ino = in->nodeid;
688 else {
689 struct node *node = get_node(f, in->nodeid);
690 node->ino = arg.attr.ino;
691 }
Miklos Szeredi0f48a262002-12-05 14:23:01 +0000692 }
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000693
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000694 send_reply(f, in, res, &arg, sizeof(arg));
695}
696
Miklos Szeredi680a69a2001-11-16 13:31:14 +0000697static int do_chmod(struct fuse *f, const char *path, struct fuse_attr *attr)
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000698{
699 int res;
700
701 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000702 if (f->op.chmod)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000703 res = f->op.chmod(path, attr->mode);
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000704
705 return res;
706}
707
Miklos Szeredi680a69a2001-11-16 13:31:14 +0000708static int do_chown(struct fuse *f, const char *path, struct fuse_attr *attr,
Miklos Szeredi2e50d432001-12-20 12:17:25 +0000709 int valid)
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000710{
711 int res;
712 uid_t uid = (valid & FATTR_UID) ? attr->uid : (uid_t) -1;
713 gid_t gid = (valid & FATTR_GID) ? attr->gid : (gid_t) -1;
714
715 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000716 if (f->op.chown)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000717 res = f->op.chown(path, uid, gid);
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000718
719 return res;
720}
721
Miklos Szeredi680a69a2001-11-16 13:31:14 +0000722static int do_truncate(struct fuse *f, const char *path,
723 struct fuse_attr *attr)
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000724{
725 int res;
726
727 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000728 if (f->op.truncate)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000729 res = f->op.truncate(path, attr->size);
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000730
731 return res;
732}
733
Miklos Szeredi680a69a2001-11-16 13:31:14 +0000734static int do_utime(struct fuse *f, const char *path, struct fuse_attr *attr)
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000735{
736 int res;
737 struct utimbuf buf;
738 buf.actime = attr->atime;
739 buf.modtime = attr->mtime;
740 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000741 if (f->op.utime)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000742 res = f->op.utime(path, &buf);
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000743
744 return res;
745}
746
Miklos Szeredi5e183482001-10-31 14:52:35 +0000747static void do_setattr(struct fuse *f, struct fuse_in_header *in,
748 struct fuse_setattr_in *arg)
749{
750 int res;
751 char *path;
752 int valid = arg->valid;
753 struct fuse_attr *attr = &arg->attr;
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000754 struct fuse_attr_out outarg;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000755
756 res = -ENOENT;
Miklos Szeredia13d9002004-11-02 17:32:03 +0000757 path = get_path(f, in->nodeid);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000758 if (path != NULL) {
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000759 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000760 if (f->op.getattr) {
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000761 res = 0;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000762 if (!res && (valid & FATTR_MODE))
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000763 res = do_chmod(f, path, attr);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000764 if (!res && (valid & (FATTR_UID | FATTR_GID)))
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000765 res = do_chown(f, path, attr, valid);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000766 if (!res && (valid & FATTR_SIZE))
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000767 res = do_truncate(f, path, attr);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000768 if (!res && (valid & (FATTR_ATIME | FATTR_MTIME)) ==
Miklos Szeredib5958612004-02-20 14:10:49 +0000769 (FATTR_ATIME | FATTR_MTIME))
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000770 res = do_utime(f, path, attr);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000771 if (!res) {
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000772 struct stat buf;
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000773 res = f->op.getattr(path, &buf);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000774 if (!res) {
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000775 memset(&outarg, 0, sizeof(struct fuse_attr_out));
776 outarg.attr_valid = ATTR_REVALIDATE_TIME;
777 outarg.attr_valid_nsec = 0;
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000778 convert_stat(&buf, &outarg.attr);
Miklos Szeredia13d9002004-11-02 17:32:03 +0000779 if (!(f->flags & FUSE_USE_INO))
780 outarg.attr.ino = in->nodeid;
781 else {
782 struct node *node = get_node(f, in->nodeid);
783 node->ino = outarg.attr.ino;
784 }
Miklos Szeredi0f48a262002-12-05 14:23:01 +0000785 }
Miklos Szeredia181e612001-11-06 12:03:23 +0000786 }
Miklos Szeredi5e183482001-10-31 14:52:35 +0000787 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000788 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000789 }
Miklos Szeredia181e612001-11-06 12:03:23 +0000790 send_reply(f, in, res, &outarg, sizeof(outarg));
Miklos Szeredi5e183482001-10-31 14:52:35 +0000791}
792
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000793static void do_readlink(struct fuse *f, struct fuse_in_header *in)
794{
795 int res;
796 char link[PATH_MAX + 1];
Miklos Szeredib483c932001-10-29 14:57:57 +0000797 char *path;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000798
Miklos Szeredi5e183482001-10-31 14:52:35 +0000799 res = -ENOENT;
Miklos Szeredia13d9002004-11-02 17:32:03 +0000800 path = get_path(f, in->nodeid);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000801 if (path != NULL) {
Miklos Szeredi5e183482001-10-31 14:52:35 +0000802 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000803 if (f->op.readlink)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000804 res = f->op.readlink(path, link, sizeof(link));
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000805 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000806 }
Miklos Szeredi2df1c042001-11-06 15:07:17 +0000807 link[PATH_MAX] = '\0';
Miklos Szeredi4b2bef42002-01-09 12:23:27 +0000808 send_reply(f, in, res, link, res == 0 ? strlen(link) : 0);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000809}
810
811static void do_getdir(struct fuse *f, struct fuse_in_header *in)
812{
813 int res;
814 struct fuse_getdir_out arg;
Miklos Szeredia181e612001-11-06 12:03:23 +0000815 struct fuse_dirhandle dh;
Miklos Szeredib483c932001-10-29 14:57:57 +0000816 char *path;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000817
Miklos Szeredib483c932001-10-29 14:57:57 +0000818 dh.fuse = f;
819 dh.fp = tmpfile();
Miklos Szeredia13d9002004-11-02 17:32:03 +0000820 dh.dir = in->nodeid;
Miklos Szeredi0f48a262002-12-05 14:23:01 +0000821
Miklos Szeredi65afea12004-09-14 07:13:45 +0000822 res = -EIO;
823 if (dh.fp == NULL)
824 perror("fuse: failed to create temporary file");
825 else {
826 res = -ENOENT;
Miklos Szeredia13d9002004-11-02 17:32:03 +0000827 path = get_path(f, in->nodeid);
Miklos Szeredi65afea12004-09-14 07:13:45 +0000828 if (path != NULL) {
829 res = -ENOSYS;
830 if (f->op.getdir)
Miklos Szeredi8fb48fe2004-11-08 14:48:52 +0000831 res = f->op.getdir(path, &dh, fill_dir);
Miklos Szeredi65afea12004-09-14 07:13:45 +0000832 free(path);
833 }
834 fflush(dh.fp);
835 }
Miklos Szeredi0f48a262002-12-05 14:23:01 +0000836 memset(&arg, 0, sizeof(struct fuse_getdir_out));
Miklos Szeredi65afea12004-09-14 07:13:45 +0000837 if (res == 0)
838 arg.fd = fileno(dh.fp);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000839 send_reply(f, in, res, &arg, sizeof(arg));
Miklos Szeredi65afea12004-09-14 07:13:45 +0000840 if (dh.fp != NULL)
841 fclose(dh.fp);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000842}
843
Miklos Szeredib483c932001-10-29 14:57:57 +0000844static void do_mknod(struct fuse *f, struct fuse_in_header *in,
845 struct fuse_mknod_in *inarg)
846{
847 int res;
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000848 int res2;
Miklos Szeredib483c932001-10-29 14:57:57 +0000849 char *path;
Miklos Szeredi76f65782004-02-19 16:55:40 +0000850 char *name = PARAM(inarg);
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000851 struct fuse_entry_out outarg;
Miklos Szeredib483c932001-10-29 14:57:57 +0000852
Miklos Szeredi5e183482001-10-31 14:52:35 +0000853 res = -ENOENT;
Miklos Szeredia13d9002004-11-02 17:32:03 +0000854 path = get_path_name(f, in->nodeid, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000855 if (path != NULL) {
856 if (f->flags & FUSE_DEBUG) {
Miklos Szeredi76f65782004-02-19 16:55:40 +0000857 printf("MKNOD %s\n", path);
858 fflush(stdout);
859 }
Miklos Szeredi5e183482001-10-31 14:52:35 +0000860 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000861 if (f->op.mknod && f->op.getattr) {
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000862 res = f->op.mknod(path, inarg->mode, inarg->rdev);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000863 if (res == 0)
Miklos Szeredia13d9002004-11-02 17:32:03 +0000864 res = lookup_path(f, in->nodeid, in->unique, name, path, &outarg);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000865 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000866 free(path);
Miklos Szeredib483c932001-10-29 14:57:57 +0000867 }
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000868 res2 = send_reply(f, in, res, &outarg, sizeof(outarg));
869 if (res == 0 && res2 == -ENOENT)
Miklos Szeredia13d9002004-11-02 17:32:03 +0000870 destroy_node(f, outarg.nodeid, in->unique);
Miklos Szeredib483c932001-10-29 14:57:57 +0000871}
872
873static void do_mkdir(struct fuse *f, struct fuse_in_header *in,
874 struct fuse_mkdir_in *inarg)
875{
876 int res;
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000877 int res2;
Miklos Szeredib483c932001-10-29 14:57:57 +0000878 char *path;
Miklos Szeredi76f65782004-02-19 16:55:40 +0000879 char *name = PARAM(inarg);
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000880 struct fuse_entry_out outarg;
Miklos Szeredib483c932001-10-29 14:57:57 +0000881
Miklos Szeredi5e183482001-10-31 14:52:35 +0000882 res = -ENOENT;
Miklos Szeredia13d9002004-11-02 17:32:03 +0000883 path = get_path_name(f, in->nodeid, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000884 if (path != NULL) {
885 if (f->flags & FUSE_DEBUG) {
Miklos Szeredi76f65782004-02-19 16:55:40 +0000886 printf("MKDIR %s\n", path);
887 fflush(stdout);
888 }
Miklos Szeredi5e183482001-10-31 14:52:35 +0000889 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000890 if (f->op.mkdir && f->op.getattr) {
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000891 res = f->op.mkdir(path, inarg->mode);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000892 if (res == 0)
Miklos Szeredia13d9002004-11-02 17:32:03 +0000893 res = lookup_path(f, in->nodeid, in->unique, name, path, &outarg);
Miklos Szeredi76f65782004-02-19 16:55:40 +0000894 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000895 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000896 }
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000897 res2 = send_reply(f, in, res, &outarg, sizeof(outarg));
898 if (res == 0 && res2 == -ENOENT)
Miklos Szeredia13d9002004-11-02 17:32:03 +0000899 destroy_node(f, outarg.nodeid, in->unique);
Miklos Szeredib483c932001-10-29 14:57:57 +0000900}
901
Miklos Szeredib5958612004-02-20 14:10:49 +0000902static void do_unlink(struct fuse *f, struct fuse_in_header *in, char *name)
Miklos Szeredib483c932001-10-29 14:57:57 +0000903{
904 int res;
905 char *path;
906
Miklos Szeredi5e183482001-10-31 14:52:35 +0000907 res = -ENOENT;
Miklos Szeredia13d9002004-11-02 17:32:03 +0000908 path = get_path_name(f, in->nodeid, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000909 if (path != NULL) {
Miklos Szeredi209f5d02004-07-24 19:56:16 +0000910 if (f->flags & FUSE_DEBUG) {
911 printf("UNLINK %s\n", path);
912 fflush(stdout);
913 }
Miklos Szeredi5e183482001-10-31 14:52:35 +0000914 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000915 if (f->op.unlink) {
Miklos Szeredia13d9002004-11-02 17:32:03 +0000916 if (!(f->flags & FUSE_HARD_REMOVE) && is_open(f, in->nodeid, name))
917 res = hide_node(f, path, in->nodeid, name);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000918 else {
919 res = f->op.unlink(path);
920 if (res == 0)
Miklos Szeredia13d9002004-11-02 17:32:03 +0000921 remove_node(f, in->nodeid, name);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000922 }
Miklos Szeredi5e183482001-10-31 14:52:35 +0000923 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000924 free(path);
Miklos Szeredib483c932001-10-29 14:57:57 +0000925 }
Miklos Szeredib5958612004-02-20 14:10:49 +0000926 send_reply(f, in, res, NULL, 0);
927}
928
929static void do_rmdir(struct fuse *f, struct fuse_in_header *in, char *name)
930{
931 int res;
932 char *path;
933
934 res = -ENOENT;
Miklos Szeredia13d9002004-11-02 17:32:03 +0000935 path = get_path_name(f, in->nodeid, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000936 if (path != NULL) {
Miklos Szeredi209f5d02004-07-24 19:56:16 +0000937 if (f->flags & FUSE_DEBUG) {
938 printf("RMDIR %s\n", path);
939 fflush(stdout);
940 }
Miklos Szeredib5958612004-02-20 14:10:49 +0000941 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000942 if (f->op.rmdir) {
Miklos Szeredib5958612004-02-20 14:10:49 +0000943 res = f->op.rmdir(path);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000944 if (res == 0)
Miklos Szeredia13d9002004-11-02 17:32:03 +0000945 remove_node(f, in->nodeid, name);
Miklos Szeredib5958612004-02-20 14:10:49 +0000946 }
947 free(path);
948 }
Miklos Szeredib483c932001-10-29 14:57:57 +0000949 send_reply(f, in, res, NULL, 0);
950}
951
952static void do_symlink(struct fuse *f, struct fuse_in_header *in, char *name,
953 char *link)
954{
955 int res;
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000956 int res2;
Miklos Szeredib483c932001-10-29 14:57:57 +0000957 char *path;
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000958 struct fuse_entry_out outarg;
Miklos Szeredib483c932001-10-29 14:57:57 +0000959
Miklos Szeredi5e183482001-10-31 14:52:35 +0000960 res = -ENOENT;
Miklos Szeredia13d9002004-11-02 17:32:03 +0000961 path = get_path_name(f, in->nodeid, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000962 if (path != NULL) {
963 if (f->flags & FUSE_DEBUG) {
Miklos Szeredi76f65782004-02-19 16:55:40 +0000964 printf("SYMLINK %s\n", path);
965 fflush(stdout);
966 }
Miklos Szeredi5e183482001-10-31 14:52:35 +0000967 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000968 if (f->op.symlink && f->op.getattr) {
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000969 res = f->op.symlink(link, path);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000970 if (res == 0)
Miklos Szeredia13d9002004-11-02 17:32:03 +0000971 res = lookup_path(f, in->nodeid, in->unique, name, path, &outarg);
Miklos Szeredi76f65782004-02-19 16:55:40 +0000972 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000973 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000974 }
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000975 res2 = send_reply(f, in, res, &outarg, sizeof(outarg));
976 if (res == 0 && res2 == -ENOENT)
Miklos Szeredia13d9002004-11-02 17:32:03 +0000977 destroy_node(f, outarg.nodeid, in->unique);
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000978
Miklos Szeredib483c932001-10-29 14:57:57 +0000979}
980
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000981static void do_rename(struct fuse *f, struct fuse_in_header *in,
982 struct fuse_rename_in *inarg)
983{
984 int res;
Miklos Szeredia13d9002004-11-02 17:32:03 +0000985 nodeid_t olddir = in->nodeid;
986 nodeid_t newdir = inarg->newdir;
Miklos Szeredi6bf8b682002-10-28 08:49:39 +0000987 char *oldname = PARAM(inarg);
988 char *newname = oldname + strlen(oldname) + 1;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000989 char *oldpath;
990 char *newpath;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000991
Miklos Szeredi5e183482001-10-31 14:52:35 +0000992 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000993 oldpath = get_path_name(f, olddir, oldname);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000994 if (oldpath != NULL) {
Miklos Szeredia181e612001-11-06 12:03:23 +0000995 newpath = get_path_name(f, newdir, newname);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000996 if (newpath != NULL) {
Miklos Szeredi209f5d02004-07-24 19:56:16 +0000997 if (f->flags & FUSE_DEBUG) {
998 printf("RENAME %s -> %s\n", oldpath, newpath);
999 fflush(stdout);
1000 }
Miklos Szeredi5e183482001-10-31 14:52:35 +00001001 res = -ENOSYS;
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001002 if (f->op.rename) {
1003 res = 0;
Miklos Szeredi2529ca22004-07-13 15:36:52 +00001004 if (!(f->flags & FUSE_HARD_REMOVE) &&
1005 is_open(f, newdir, newname))
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001006 res = hide_node(f, newpath, newdir, newname);
1007 if (res == 0) {
1008 res = f->op.rename(oldpath, newpath);
1009 if (res == 0)
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001010 res = rename_node(f, olddir, oldname, newdir, newname, 0);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001011 }
1012 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001013 free(newpath);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001014 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001015 free(oldpath);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001016 }
Miklos Szeredi19dff1b2001-10-30 15:06:52 +00001017 send_reply(f, in, res, NULL, 0);
1018}
1019
1020static void do_link(struct fuse *f, struct fuse_in_header *in,
Miklos Szeredi5e183482001-10-31 14:52:35 +00001021 struct fuse_link_in *arg)
Miklos Szeredi19dff1b2001-10-30 15:06:52 +00001022{
1023 int res;
Miklos Szeredi2778f6c2004-06-21 09:45:30 +00001024 int res2;
Miklos Szeredi5e183482001-10-31 14:52:35 +00001025 char *oldpath;
1026 char *newpath;
Miklos Szeredi76f65782004-02-19 16:55:40 +00001027 char *name = PARAM(arg);
Miklos Szeredi254d5ed2004-03-02 11:11:24 +00001028 struct fuse_entry_out outarg;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +00001029
Miklos Szeredi5e183482001-10-31 14:52:35 +00001030 res = -ENOENT;
Miklos Szeredia13d9002004-11-02 17:32:03 +00001031 oldpath = get_path(f, in->nodeid);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001032 if (oldpath != NULL) {
Miklos Szeredi76f65782004-02-19 16:55:40 +00001033 newpath = get_path_name(f, arg->newdir, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001034 if (newpath != NULL) {
1035 if (f->flags & FUSE_DEBUG) {
Miklos Szeredi76f65782004-02-19 16:55:40 +00001036 printf("LINK %s\n", newpath);
1037 fflush(stdout);
1038 }
Miklos Szeredi5e183482001-10-31 14:52:35 +00001039 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001040 if (f->op.link && f->op.getattr) {
Miklos Szeredi0a7077f2001-11-11 18:20:17 +00001041 res = f->op.link(oldpath, newpath);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001042 if (res == 0)
Miklos Szeredi76f65782004-02-19 16:55:40 +00001043 res = lookup_path(f, arg->newdir, in->unique, name,
1044 newpath, &outarg);
1045 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001046 free(newpath);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001047 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001048 free(oldpath);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001049 }
Miklos Szeredi2778f6c2004-06-21 09:45:30 +00001050 res2 = send_reply(f, in, res, &outarg, sizeof(outarg));
1051 if (res == 0 && res2 == -ENOENT)
Miklos Szeredia13d9002004-11-02 17:32:03 +00001052 destroy_node(f, outarg.nodeid, in->unique);
Miklos Szeredi19dff1b2001-10-30 15:06:52 +00001053}
1054
Miklos Szeredi5e183482001-10-31 14:52:35 +00001055static void do_open(struct fuse *f, struct fuse_in_header *in,
1056 struct fuse_open_in *arg)
1057{
1058 int res;
1059 char *path;
Miklos Szeredi209f5d02004-07-24 19:56:16 +00001060 struct fuse_open_out outarg;
Miklos Szeredi5e183482001-10-31 14:52:35 +00001061
1062 res = -ENOENT;
Miklos Szeredia13d9002004-11-02 17:32:03 +00001063 path = get_path(f, in->nodeid);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001064 if (path != NULL) {
Miklos Szeredi5e183482001-10-31 14:52:35 +00001065 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001066 if (f->op.open)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +00001067 res = f->op.open(path, arg->flags);
Miklos Szeredi40b9a5a2002-12-10 16:09:02 +00001068 }
Miklos Szeredi73798f92004-07-12 15:55:11 +00001069 if (res == 0) {
1070 int res2;
1071
1072 /* If the request is interrupted the lock must be held until
1073 the cancellation is finished. Otherwise there could be
1074 races with rename/unlink, against which the kernel can't
1075 protect */
1076 pthread_mutex_lock(&f->lock);
Miklos Szeredi209f5d02004-07-24 19:56:16 +00001077 f->fh_ctr ++;
1078 outarg.fh = f->fh_ctr;
1079 if (f->flags & FUSE_DEBUG) {
Miklos Szeredi1eea0322004-09-27 18:50:11 +00001080 printf("OPEN[%lu] flags: 0x%x\n", outarg.fh, arg->flags);
Miklos Szeredi209f5d02004-07-24 19:56:16 +00001081 fflush(stdout);
1082 }
1083
1084 res2 = __send_reply(f, in, res, &outarg, sizeof(outarg), 1);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001085 if(res2 == -ENOENT) {
1086 /* The open syscall was interrupted, so it must be cancelled */
1087 if(f->op.release)
1088 f->op.release(path, arg->flags);
Miklos Szeredi73798f92004-07-12 15:55:11 +00001089 } else
Miklos Szeredia13d9002004-11-02 17:32:03 +00001090 get_node(f, in->nodeid)->open_count ++;
Miklos Szeredi73798f92004-07-12 15:55:11 +00001091 pthread_mutex_unlock(&f->lock);
1092
1093 } else
1094 send_reply(f, in, res, NULL, 0);
1095
Miklos Szeredi9a31cca2004-06-26 21:11:25 +00001096 if (path)
1097 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001098}
1099
Miklos Szeredi209f5d02004-07-24 19:56:16 +00001100static void do_flush(struct fuse *f, struct fuse_in_header *in,
1101 struct fuse_flush_in *arg)
Miklos Szeredie2e4ac22004-05-18 08:45:28 +00001102{
1103 char *path;
1104 int res;
1105
1106 res = -ENOENT;
Miklos Szeredia13d9002004-11-02 17:32:03 +00001107 path = get_path(f, in->nodeid);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001108 if (path != NULL) {
Miklos Szeredi209f5d02004-07-24 19:56:16 +00001109 if (f->flags & FUSE_DEBUG) {
Miklos Szeredi1eea0322004-09-27 18:50:11 +00001110 printf("FLUSH[%lu]\n", arg->fh);
Miklos Szeredi209f5d02004-07-24 19:56:16 +00001111 fflush(stdout);
1112 }
Miklos Szeredie2e4ac22004-05-18 08:45:28 +00001113 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001114 if (f->op.flush)
Miklos Szeredie2e4ac22004-05-18 08:45:28 +00001115 res = f->op.flush(path);
1116 free(path);
1117 }
1118 send_reply(f, in, res, NULL, 0);
1119}
1120
Miklos Szeredi9478e862002-12-11 09:50:26 +00001121static void do_release(struct fuse *f, struct fuse_in_header *in,
Miklos Szeredi209f5d02004-07-24 19:56:16 +00001122 struct fuse_release_in *arg)
Miklos Szeredic8ba2372002-12-10 12:26:00 +00001123{
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001124 struct node *node;
1125 char *path;
Miklos Szeredic8ba2372002-12-10 12:26:00 +00001126
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001127 pthread_mutex_lock(&f->lock);
Miklos Szeredia13d9002004-11-02 17:32:03 +00001128 node = get_node(f, in->nodeid);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001129 --node->open_count;
1130 pthread_mutex_unlock(&f->lock);
1131
Miklos Szeredia13d9002004-11-02 17:32:03 +00001132 path = get_path(f, in->nodeid);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001133 if (path != NULL) {
Miklos Szeredi209f5d02004-07-24 19:56:16 +00001134 if (f->flags & FUSE_DEBUG) {
Miklos Szeredi1eea0322004-09-27 18:50:11 +00001135 printf("RELEASE[%lu]\n", arg->fh);
Miklos Szeredi209f5d02004-07-24 19:56:16 +00001136 fflush(stdout);
1137 }
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001138 if (f->op.release)
Miklos Szeredib3210582004-06-23 13:54:33 +00001139 f->op.release(path, arg->flags);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001140
1141 if(node->is_hidden && node->open_count == 0)
1142 /* can now clean up this hidden file */
1143 f->op.unlink(path);
1144
1145 free(path);
Miklos Szeredic8ba2372002-12-10 12:26:00 +00001146 }
Miklos Szeredi556d03d2004-06-30 11:13:41 +00001147 send_reply(f, in, 0, NULL, 0);
Miklos Szeredic8ba2372002-12-10 12:26:00 +00001148}
1149
Miklos Szeredi5e183482001-10-31 14:52:35 +00001150static void do_read(struct fuse *f, struct fuse_in_header *in,
1151 struct fuse_read_in *arg)
1152{
1153 int res;
1154 char *path;
Miklos Szeredi43696432001-11-18 19:15:05 +00001155 char *outbuf = (char *) malloc(sizeof(struct fuse_out_header) + arg->size);
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001156 if (outbuf == NULL)
1157 send_reply(f, in, -ENOMEM, NULL, 0);
1158 else {
1159 struct fuse_out_header *out = (struct fuse_out_header *) outbuf;
1160 char *buf = outbuf + sizeof(struct fuse_out_header);
1161 size_t size;
1162 size_t outsize;
1163
1164 res = -ENOENT;
Miklos Szeredia13d9002004-11-02 17:32:03 +00001165 path = get_path(f, in->nodeid);
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001166 if (path != NULL) {
1167 if (f->flags & FUSE_DEBUG) {
Miklos Szeredi1eea0322004-09-27 18:50:11 +00001168 printf("READ[%lu] %u bytes from %llu\n", arg->fh, arg->size,
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001169 arg->offset);
1170 fflush(stdout);
1171 }
1172
1173 res = -ENOSYS;
1174 if (f->op.read)
1175 res = f->op.read(path, buf, arg->size, arg->offset);
1176 free(path);
Miklos Szeredi6ebe2342002-01-06 21:44:16 +00001177 }
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001178
1179 size = 0;
1180 if (res >= 0) {
1181 size = res;
1182 res = 0;
1183 if (f->flags & FUSE_DEBUG) {
Miklos Szeredi1eea0322004-09-27 18:50:11 +00001184 printf(" READ[%lu] %u bytes\n", arg->fh, size);
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001185 fflush(stdout);
1186 }
Miklos Szeredi6ebe2342002-01-06 21:44:16 +00001187 }
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001188 memset(out, 0, sizeof(struct fuse_out_header));
1189 out->unique = in->unique;
1190 out->error = res;
1191 outsize = sizeof(struct fuse_out_header) + size;
1192
1193 send_reply_raw(f, outbuf, outsize, 0);
1194 free(outbuf);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001195 }
Miklos Szeredi5e183482001-10-31 14:52:35 +00001196}
Miklos Szeredib483c932001-10-29 14:57:57 +00001197
Miklos Szeredia181e612001-11-06 12:03:23 +00001198static void do_write(struct fuse *f, struct fuse_in_header *in,
1199 struct fuse_write_in *arg)
1200{
1201 int res;
1202 char *path;
Miklos Szerediad051c32004-07-02 09:22:50 +00001203 struct fuse_write_out outarg;
Miklos Szeredia181e612001-11-06 12:03:23 +00001204
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001205 res = -ENOENT;
Miklos Szeredia13d9002004-11-02 17:32:03 +00001206 path = get_path(f, in->nodeid);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001207 if (path != NULL) {
1208 if (f->flags & FUSE_DEBUG) {
Miklos Szeredi1eea0322004-09-27 18:50:11 +00001209 printf("WRITE%s[%lu] %u bytes to %llu\n",
Miklos Szeredi209f5d02004-07-24 19:56:16 +00001210 arg->writepage ? "PAGE" : "", arg->fh, arg->size,
1211 arg->offset);
Miklos Szeredi6ebe2342002-01-06 21:44:16 +00001212 fflush(stdout);
1213 }
1214
Miklos Szeredia181e612001-11-06 12:03:23 +00001215 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001216 if (f->op.write)
Miklos Szeredi6bf8b682002-10-28 08:49:39 +00001217 res = f->op.write(path, PARAM(arg), arg->size, arg->offset);
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001218 free(path);
Miklos Szeredia181e612001-11-06 12:03:23 +00001219 }
1220
Miklos Szerediad051c32004-07-02 09:22:50 +00001221 if (res >= 0) {
1222 outarg.size = res;
1223 res = 0;
Miklos Szeredia181e612001-11-06 12:03:23 +00001224 }
1225
Miklos Szerediad051c32004-07-02 09:22:50 +00001226 send_reply(f, in, res, &outarg, sizeof(outarg));
Miklos Szeredia181e612001-11-06 12:03:23 +00001227}
1228
Miklos Szeredi77f39942004-03-25 11:17:52 +00001229static int default_statfs(struct statfs *buf)
1230{
1231 buf->f_namelen = 255;
1232 buf->f_bsize = 512;
1233 return 0;
1234}
1235
Miklos Szeredi18e75e42004-02-19 14:23:27 +00001236static void convert_statfs(struct statfs *statfs, struct fuse_kstatfs *kstatfs)
1237{
1238 kstatfs->bsize = statfs->f_bsize;
1239 kstatfs->blocks = statfs->f_blocks;
1240 kstatfs->bfree = statfs->f_bfree;
1241 kstatfs->bavail = statfs->f_bavail;
1242 kstatfs->files = statfs->f_files;
1243 kstatfs->ffree = statfs->f_ffree;
1244 kstatfs->namelen = statfs->f_namelen;
1245}
1246
Mark Glinesd84b39a2002-01-07 16:32:02 +00001247static void do_statfs(struct fuse *f, struct fuse_in_header *in)
1248{
1249 int res;
Mark Glinesd84b39a2002-01-07 16:32:02 +00001250 struct fuse_statfs_out arg;
Miklos Szeredi18e75e42004-02-19 14:23:27 +00001251 struct statfs buf;
Mark Glinesd84b39a2002-01-07 16:32:02 +00001252
Miklos Szeredi77f39942004-03-25 11:17:52 +00001253 memset(&buf, 0, sizeof(struct statfs));
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001254 if (f->op.statfs)
Miklos Szeredi18e75e42004-02-19 14:23:27 +00001255 res = f->op.statfs("/", &buf);
Miklos Szeredi77f39942004-03-25 11:17:52 +00001256 else
1257 res = default_statfs(&buf);
1258
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001259 if (res == 0)
Miklos Szeredi77f39942004-03-25 11:17:52 +00001260 convert_statfs(&buf, &arg.st);
Miklos Szeredi4b2bef42002-01-09 12:23:27 +00001261
Mark Glinesd84b39a2002-01-07 16:32:02 +00001262 send_reply(f, in, res, &arg, sizeof(arg));
1263}
1264
Miklos Szeredi5e43f2c2003-12-12 14:06:41 +00001265static void do_fsync(struct fuse *f, struct fuse_in_header *in,
1266 struct fuse_fsync_in *inarg)
1267{
1268 int res;
1269 char *path;
1270
1271 res = -ENOENT;
Miklos Szeredia13d9002004-11-02 17:32:03 +00001272 path = get_path(f, in->nodeid);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001273 if (path != NULL) {
Miklos Szeredi209f5d02004-07-24 19:56:16 +00001274 if (f->flags & FUSE_DEBUG) {
Miklos Szeredi1eea0322004-09-27 18:50:11 +00001275 printf("FSYNC[%lu]\n", inarg->fh);
Miklos Szeredi209f5d02004-07-24 19:56:16 +00001276 fflush(stdout);
1277 }
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001278 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001279 if (f->op.fsync)
Miklos Szeredi5e43f2c2003-12-12 14:06:41 +00001280 res = f->op.fsync(path, inarg->datasync);
1281 free(path);
1282 }
1283 send_reply(f, in, res, NULL, 0);
1284}
1285
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001286static void do_setxattr(struct fuse *f, struct fuse_in_header *in,
1287 struct fuse_setxattr_in *arg)
1288{
1289 int res;
1290 char *path;
1291 char *name = PARAM(arg);
1292 unsigned char *value = name + strlen(name) + 1;
1293
1294 res = -ENOENT;
Miklos Szeredia13d9002004-11-02 17:32:03 +00001295 path = get_path(f, in->nodeid);
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001296 if (path != NULL) {
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001297 res = -ENOSYS;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001298 if (f->op.setxattr)
1299 res = f->op.setxattr(path, name, value, arg->size, arg->flags);
1300 free(path);
1301 }
1302 send_reply(f, in, res, NULL, 0);
1303}
1304
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001305static int common_getxattr(struct fuse *f, struct fuse_in_header *in,
1306 const char *name, char *value, size_t size)
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001307{
1308 int res;
1309 char *path;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001310
1311 res = -ENOENT;
Miklos Szeredia13d9002004-11-02 17:32:03 +00001312 path = get_path(f, in->nodeid);
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001313 if (path != NULL) {
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001314 res = -ENOSYS;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001315 if (f->op.getxattr)
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001316 res = f->op.getxattr(path, name, value, size);
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001317 free(path);
1318 }
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001319 return res;
1320}
1321
1322static void do_getxattr_read(struct fuse *f, struct fuse_in_header *in,
1323 const char *name, size_t size)
1324{
1325 int res;
1326 char *outbuf = (char *) malloc(sizeof(struct fuse_out_header) + size);
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001327 if (outbuf == NULL)
1328 send_reply(f, in, -ENOMEM, NULL, 0);
1329 else {
1330 struct fuse_out_header *out = (struct fuse_out_header *) outbuf;
1331 char *value = outbuf + sizeof(struct fuse_out_header);
1332
1333 res = common_getxattr(f, in, name, value, size);
1334 size = 0;
1335 if (res > 0) {
1336 size = res;
1337 res = 0;
1338 }
1339 memset(out, 0, sizeof(struct fuse_out_header));
1340 out->unique = in->unique;
1341 out->error = res;
1342
1343 send_reply_raw(f, outbuf, sizeof(struct fuse_out_header) + size, 0);
1344 free(outbuf);
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001345 }
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001346}
1347
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001348static void do_getxattr_size(struct fuse *f, struct fuse_in_header *in,
1349 const char *name)
1350{
1351 int res;
1352 struct fuse_getxattr_out arg;
1353
1354 res = common_getxattr(f, in, name, NULL, 0);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001355 if (res >= 0) {
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001356 arg.size = res;
1357 res = 0;
1358 }
1359 send_reply(f, in, res, &arg, sizeof(arg));
1360}
1361
1362static void do_getxattr(struct fuse *f, struct fuse_in_header *in,
1363 struct fuse_getxattr_in *arg)
1364{
1365 char *name = PARAM(arg);
1366
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001367 if (arg->size)
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001368 do_getxattr_read(f, in, name, arg->size);
1369 else
1370 do_getxattr_size(f, in, name);
1371}
1372
1373static int common_listxattr(struct fuse *f, struct fuse_in_header *in,
1374 char *list, size_t size)
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001375{
1376 int res;
1377 char *path;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001378
1379 res = -ENOENT;
Miklos Szeredia13d9002004-11-02 17:32:03 +00001380 path = get_path(f, in->nodeid);
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001381 if (path != NULL) {
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001382 res = -ENOSYS;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001383 if (f->op.listxattr)
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001384 res = f->op.listxattr(path, list, size);
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001385 free(path);
1386 }
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001387 return res;
1388}
1389
1390static void do_listxattr_read(struct fuse *f, struct fuse_in_header *in,
1391 size_t size)
1392{
1393 int res;
1394 char *outbuf = (char *) malloc(sizeof(struct fuse_out_header) + size);
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001395 if (outbuf == NULL)
1396 send_reply(f, in, -ENOMEM, NULL, 0);
1397 else {
1398 struct fuse_out_header *out = (struct fuse_out_header *) outbuf;
1399 char *list = outbuf + sizeof(struct fuse_out_header);
1400
1401 res = common_listxattr(f, in, list, size);
1402 size = 0;
1403 if (res > 0) {
1404 size = res;
1405 res = 0;
1406 }
1407 memset(out, 0, sizeof(struct fuse_out_header));
1408 out->unique = in->unique;
1409 out->error = res;
1410
1411 send_reply_raw(f, outbuf, sizeof(struct fuse_out_header) + size, 0);
1412 free(outbuf);
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001413 }
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001414}
1415
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001416static void do_listxattr_size(struct fuse *f, struct fuse_in_header *in)
1417{
1418 int res;
1419 struct fuse_getxattr_out arg;
1420
1421 res = common_listxattr(f, in, NULL, 0);
1422 if (res >= 0) {
1423 arg.size = res;
1424 res = 0;
1425 }
1426 send_reply(f, in, res, &arg, sizeof(arg));
1427}
1428
1429static void do_listxattr(struct fuse *f, struct fuse_in_header *in,
1430 struct fuse_getxattr_in *arg)
1431{
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001432 if (arg->size)
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001433 do_listxattr_read(f, in, arg->size);
1434 else
1435 do_listxattr_size(f, in);
1436}
1437
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001438static void do_removexattr(struct fuse *f, struct fuse_in_header *in,
1439 char *name)
1440{
1441 int res;
1442 char *path;
1443
1444 res = -ENOENT;
Miklos Szeredia13d9002004-11-02 17:32:03 +00001445 path = get_path(f, in->nodeid);
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001446 if (path != NULL) {
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001447 res = -ENOSYS;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001448 if (f->op.removexattr)
1449 res = f->op.removexattr(path, name);
1450 free(path);
1451 }
1452 send_reply(f, in, res, NULL, 0);
1453}
1454
1455
Miklos Szeredi43696432001-11-18 19:15:05 +00001456static void free_cmd(struct fuse_cmd *cmd)
1457{
1458 free(cmd->buf);
1459 free(cmd);
1460}
1461
Miklos Szeredifff56ab2001-11-16 10:12:59 +00001462void __fuse_process_cmd(struct fuse *f, struct fuse_cmd *cmd)
Miklos Szeredia181e612001-11-06 12:03:23 +00001463{
Miklos Szeredia181e612001-11-06 12:03:23 +00001464 struct fuse_in_header *in = (struct fuse_in_header *) cmd->buf;
1465 void *inarg = cmd->buf + sizeof(struct fuse_in_header);
1466 size_t argsize;
Miklos Szeredid169f312004-09-22 08:48:26 +00001467 struct fuse_context *ctx = fuse_get_context();
Miklos Szeredia181e612001-11-06 12:03:23 +00001468
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +00001469 dec_avail(f);
Miklos Szeredi33232032001-11-19 17:55:51 +00001470
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001471 if ((f->flags & FUSE_DEBUG)) {
Miklos Szeredia13d9002004-11-02 17:32:03 +00001472 printf("unique: %i, opcode: %s (%i), nodeid: %li, insize: %i\n",
1473 in->unique, opname(in->opcode), in->opcode, in->nodeid,
Miklos Szeredic8ba2372002-12-10 12:26:00 +00001474 cmd->buflen);
Miklos Szeredic0938ea2001-11-07 12:35:06 +00001475 fflush(stdout);
1476 }
Miklos Szeredife25def2001-12-20 15:38:05 +00001477
Miklos Szeredid169f312004-09-22 08:48:26 +00001478 ctx->fuse = f;
Miklos Szeredife25def2001-12-20 15:38:05 +00001479 ctx->uid = in->uid;
1480 ctx->gid = in->gid;
Miklos Szeredi1f18db52004-09-27 06:54:49 +00001481 ctx->pid = in->pid;
Miklos Szeredia181e612001-11-06 12:03:23 +00001482
1483 argsize = cmd->buflen - sizeof(struct fuse_in_header);
1484
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001485 switch (in->opcode) {
Miklos Szeredia181e612001-11-06 12:03:23 +00001486 case FUSE_LOOKUP:
1487 do_lookup(f, in, (char *) inarg);
1488 break;
1489
Miklos Szeredia181e612001-11-06 12:03:23 +00001490 case FUSE_GETATTR:
1491 do_getattr(f, in);
1492 break;
1493
1494 case FUSE_SETATTR:
1495 do_setattr(f, in, (struct fuse_setattr_in *) inarg);
1496 break;
1497
1498 case FUSE_READLINK:
1499 do_readlink(f, in);
1500 break;
1501
1502 case FUSE_GETDIR:
1503 do_getdir(f, in);
1504 break;
1505
1506 case FUSE_MKNOD:
1507 do_mknod(f, in, (struct fuse_mknod_in *) inarg);
1508 break;
1509
1510 case FUSE_MKDIR:
1511 do_mkdir(f, in, (struct fuse_mkdir_in *) inarg);
1512 break;
1513
1514 case FUSE_UNLINK:
Miklos Szeredib5958612004-02-20 14:10:49 +00001515 do_unlink(f, in, (char *) inarg);
1516 break;
1517
Miklos Szeredia181e612001-11-06 12:03:23 +00001518 case FUSE_RMDIR:
Miklos Szeredib5958612004-02-20 14:10:49 +00001519 do_rmdir(f, in, (char *) inarg);
Miklos Szeredia181e612001-11-06 12:03:23 +00001520 break;
1521
1522 case FUSE_SYMLINK:
1523 do_symlink(f, in, (char *) inarg,
1524 ((char *) inarg) + strlen((char *) inarg) + 1);
1525 break;
1526
1527 case FUSE_RENAME:
1528 do_rename(f, in, (struct fuse_rename_in *) inarg);
1529 break;
1530
1531 case FUSE_LINK:
1532 do_link(f, in, (struct fuse_link_in *) inarg);
1533 break;
1534
1535 case FUSE_OPEN:
1536 do_open(f, in, (struct fuse_open_in *) inarg);
1537 break;
1538
Miklos Szeredie2e4ac22004-05-18 08:45:28 +00001539 case FUSE_FLUSH:
Miklos Szeredi209f5d02004-07-24 19:56:16 +00001540 do_flush(f, in, (struct fuse_flush_in *) inarg);
Miklos Szeredie2e4ac22004-05-18 08:45:28 +00001541 break;
1542
Miklos Szeredi9478e862002-12-11 09:50:26 +00001543 case FUSE_RELEASE:
Miklos Szeredi209f5d02004-07-24 19:56:16 +00001544 do_release(f, in, (struct fuse_release_in *) inarg);
Miklos Szeredi9478e862002-12-11 09:50:26 +00001545 break;
1546
Miklos Szeredia181e612001-11-06 12:03:23 +00001547 case FUSE_READ:
1548 do_read(f, in, (struct fuse_read_in *) inarg);
1549 break;
1550
1551 case FUSE_WRITE:
1552 do_write(f, in, (struct fuse_write_in *) inarg);
1553 break;
1554
Mark Glinesd84b39a2002-01-07 16:32:02 +00001555 case FUSE_STATFS:
1556 do_statfs(f, in);
1557 break;
1558
Miklos Szeredi5e43f2c2003-12-12 14:06:41 +00001559 case FUSE_FSYNC:
1560 do_fsync(f, in, (struct fuse_fsync_in *) inarg);
1561 break;
1562
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001563 case FUSE_SETXATTR:
1564 do_setxattr(f, in, (struct fuse_setxattr_in *) inarg);
1565 break;
1566
1567 case FUSE_GETXATTR:
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001568 do_getxattr(f, in, (struct fuse_getxattr_in *) inarg);
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001569 break;
1570
1571 case FUSE_LISTXATTR:
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001572 do_listxattr(f, in, (struct fuse_getxattr_in *) inarg);
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001573 break;
1574
1575 case FUSE_REMOVEXATTR:
1576 do_removexattr(f, in, (char *) inarg);
1577 break;
1578
Miklos Szeredia181e612001-11-06 12:03:23 +00001579 default:
Miklos Szeredi43696432001-11-18 19:15:05 +00001580 send_reply(f, in, -ENOSYS, NULL, 0);
Miklos Szeredia181e612001-11-06 12:03:23 +00001581 }
Miklos Szeredi43696432001-11-18 19:15:05 +00001582
1583 free_cmd(cmd);
Miklos Szeredia181e612001-11-06 12:03:23 +00001584}
1585
Miklos Szeredi65cf7c72004-06-30 11:34:56 +00001586int __fuse_exited(struct fuse* f)
1587{
1588 return f->exited;
1589}
1590
Miklos Szeredifff56ab2001-11-16 10:12:59 +00001591struct fuse_cmd *__fuse_read_cmd(struct fuse *f)
Miklos Szeredi2df1c042001-11-06 15:07:17 +00001592{
Miklos Szeredifff56ab2001-11-16 10:12:59 +00001593 ssize_t res;
Miklos Szeredifff56ab2001-11-16 10:12:59 +00001594 struct fuse_cmd *cmd;
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +00001595 struct fuse_in_header *in;
1596 void *inarg;
Miklos Szeredifff56ab2001-11-16 10:12:59 +00001597
Miklos Szeredi43696432001-11-18 19:15:05 +00001598 cmd = (struct fuse_cmd *) malloc(sizeof(struct fuse_cmd));
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001599 if (cmd == NULL) {
1600 fprintf(stderr, "fuse: failed to allocate cmd in read\n");
1601 return NULL;
1602 }
Miklos Szeredi43696432001-11-18 19:15:05 +00001603 cmd->buf = (char *) malloc(FUSE_MAX_IN);
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001604 if (cmd->buf == NULL) {
1605 fprintf(stderr, "fuse: failed to allocate read buffer\n");
1606 free(cmd);
1607 return NULL;
1608 }
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +00001609 in = (struct fuse_in_header *) cmd->buf;
1610 inarg = cmd->buf + sizeof(struct fuse_in_header);
Miklos Szeredi43696432001-11-18 19:15:05 +00001611
Miklos Szeredi65cf7c72004-06-30 11:34:56 +00001612 res = read(f->fd, cmd->buf, FUSE_MAX_IN);
1613 if (res == -1) {
1614 free_cmd(cmd);
1615 if (__fuse_exited(f) || errno == EINTR)
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +00001616 return NULL;
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +00001617
Miklos Szeredi65cf7c72004-06-30 11:34:56 +00001618 /* ENODEV means we got unmounted, so we silenty return failure */
1619 if (errno != ENODEV) {
1620 /* BAD... This will happen again */
1621 perror("fuse: reading device");
1622 }
1623
1624 fuse_exit(f);
1625 return NULL;
1626 }
1627 if ((size_t) res < sizeof(struct fuse_in_header)) {
1628 free_cmd(cmd);
1629 /* Cannot happen */
1630 fprintf(stderr, "short read on fuse device\n");
1631 fuse_exit(f);
1632 return NULL;
1633 }
1634 cmd->buflen = res;
1635
1636 /* Forget is special, it can be done without messing with threads. */
1637 if (in->opcode == FUSE_FORGET) {
1638 do_forget(f, in, (struct fuse_forget_in *) inarg);
1639 free_cmd(cmd);
1640 return NULL;
1641 }
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +00001642
Miklos Szeredifff56ab2001-11-16 10:12:59 +00001643 return cmd;
Miklos Szeredi2df1c042001-11-06 15:07:17 +00001644}
1645
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001646int fuse_loop(struct fuse *f)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001647{
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001648 if (f == NULL)
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001649 return -1;
Miklos Szeredic40748a2004-02-20 16:38:45 +00001650
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001651 while (1) {
Miklos Szeredi0f48a262002-12-05 14:23:01 +00001652 struct fuse_cmd *cmd;
1653
Miklos Szeredi65cf7c72004-06-30 11:34:56 +00001654 if (__fuse_exited(f))
Miklos Szeredi874e3c12004-11-01 23:15:20 +00001655 break;
Miklos Szeredi0f48a262002-12-05 14:23:01 +00001656
1657 cmd = __fuse_read_cmd(f);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001658 if (cmd == NULL)
Miklos Szeredi0f48a262002-12-05 14:23:01 +00001659 continue;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001660
Miklos Szeredifff56ab2001-11-16 10:12:59 +00001661 __fuse_process_cmd(f, cmd);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001662 }
Miklos Szeredi874e3c12004-11-01 23:15:20 +00001663 f->exited = 0;
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001664 return 0;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001665}
1666
Miklos Szeredi891b8742004-07-29 09:27:49 +00001667int fuse_invalidate(struct fuse *f, const char *path)
1668{
1669 int res;
1670 int err;
Miklos Szeredia13d9002004-11-02 17:32:03 +00001671 nodeid_t nodeid;
1672 unsigned long ino;
Miklos Szeredi891b8742004-07-29 09:27:49 +00001673 struct fuse_user_header h;
1674
Miklos Szeredia13d9002004-11-02 17:32:03 +00001675 err = path_lookup(f, path, &nodeid, &ino);
Miklos Szeredi891b8742004-07-29 09:27:49 +00001676 if (err) {
1677 if (err == -ENOENT)
1678 return 0;
1679 else
1680 return err;
1681 }
1682
1683 memset(&h, 0, sizeof(struct fuse_user_header));
1684 h.opcode = FUSE_INVALIDATE;
Miklos Szeredia13d9002004-11-02 17:32:03 +00001685 h.nodeid = nodeid;
Miklos Szeredi891b8742004-07-29 09:27:49 +00001686 h.ino = ino;
1687
1688 if ((f->flags & FUSE_DEBUG)) {
Miklos Szeredia13d9002004-11-02 17:32:03 +00001689 printf("INVALIDATE nodeid: %li\n", nodeid);
Miklos Szeredi891b8742004-07-29 09:27:49 +00001690 fflush(stdout);
1691 }
1692
1693 res = write(f->fd, &h, sizeof(struct fuse_user_header));
1694 if (res == -1) {
1695 if (errno != ENOENT) {
1696 perror("fuse: writing device");
1697 return -errno;
1698 }
1699 }
1700 return 0;
1701}
1702
Miklos Szeredi0f48a262002-12-05 14:23:01 +00001703void fuse_exit(struct fuse *f)
1704{
1705 f->exited = 1;
1706}
1707
Miklos Szeredid169f312004-09-22 08:48:26 +00001708struct fuse_context *fuse_get_context()
Miklos Szeredi2e50d432001-12-20 12:17:25 +00001709{
Miklos Szeredid169f312004-09-22 08:48:26 +00001710 static struct fuse_context context;
1711 if (fuse_getcontext)
1712 return fuse_getcontext();
Miklos Szeredi2e50d432001-12-20 12:17:25 +00001713 else
Miklos Szeredid169f312004-09-22 08:48:26 +00001714 return &context;
1715}
1716
1717void __fuse_set_getcontext_func(struct fuse_context *(*func)(void))
1718{
1719 fuse_getcontext = func;
Miklos Szeredi2e50d432001-12-20 12:17:25 +00001720}
1721
Miklos Szeredic40748a2004-02-20 16:38:45 +00001722static int check_version(struct fuse *f)
1723{
1724 int res;
Miklos Szeredif3845c42004-11-20 11:18:34 +00001725 const char *version_file = FUSE_VERSION_FILE;
1726 FILE *vf = fopen(version_file, "r");
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001727 if (vf == NULL) {
Miklos Szeredia25d4c22004-11-23 22:32:16 +00001728 version_file = FUSE_VERSION_FILE_OLD;
Miklos Szeredif3845c42004-11-20 11:18:34 +00001729 vf = fopen(version_file, "r");
1730 if (vf == NULL) {
Miklos Szeredia25d4c22004-11-23 22:32:16 +00001731 struct stat tmp;
1732 if (stat(FUSE_DEV_OLD, &tmp) != -1) {
1733 fprintf(stderr, "fuse: kernel interface too old, need >= %i.%i\n",
1734 FUSE_KERNEL_VERSION, FUSE_KERNEL_MINOR_VERSION);
1735 return -1;
1736 } else {
1737 fprintf(stderr, "fuse: warning: version of kernel interface unknown\n");
1738 return 0;
1739 }
Miklos Szeredif3845c42004-11-20 11:18:34 +00001740 }
Miklos Szeredic40748a2004-02-20 16:38:45 +00001741 }
1742 res = fscanf(vf, "%i.%i", &f->majorver, &f->minorver);
1743 fclose(vf);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001744 if (res != 2) {
Miklos Szeredif3845c42004-11-20 11:18:34 +00001745 fprintf(stderr, "fuse: error reading %s\n", version_file);
Miklos Szeredic40748a2004-02-20 16:38:45 +00001746 return -1;
1747 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001748 if (f->majorver != FUSE_KERNEL_VERSION) {
Miklos Szeredic40748a2004-02-20 16:38:45 +00001749 fprintf(stderr, "fuse: bad kernel interface major version: needs %i\n",
1750 FUSE_KERNEL_VERSION);
1751 return -1;
1752 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001753 if (f->minorver < FUSE_KERNEL_MINOR_VERSION) {
Miklos Szeredi256739a2004-11-20 12:22:37 +00001754 fprintf(stderr, "fuse: kernel interface too old: need >= %i.%i\n",
Miklos Szeredic40748a2004-02-20 16:38:45 +00001755 FUSE_KERNEL_VERSION, FUSE_KERNEL_MINOR_VERSION);
1756 return -1;
1757 }
1758
1759 return 0;
1760}
1761
Miklos Szeredibd7661b2004-07-23 17:16:29 +00001762
1763int fuse_is_lib_option(const char *opt)
1764{
1765 if (strcmp(opt, "debug") == 0 ||
Miklos Szeredia13d9002004-11-02 17:32:03 +00001766 strcmp(opt, "hard_remove") == 0 ||
1767 strcmp(opt, "use_ino") == 0)
Miklos Szeredibd7661b2004-07-23 17:16:29 +00001768 return 1;
1769 else
1770 return 0;
1771}
1772
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001773static int parse_lib_opts(struct fuse *f, const char *opts)
Miklos Szeredibd7661b2004-07-23 17:16:29 +00001774{
1775 if (opts) {
1776 char *xopts = strdup(opts);
1777 char *s = xopts;
1778 char *opt;
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001779
1780 if (xopts == NULL)
1781 return -1;
Miklos Szeredibd7661b2004-07-23 17:16:29 +00001782
1783 while((opt = strsep(&s, ","))) {
1784 if (strcmp(opt, "debug") == 0)
1785 f->flags |= FUSE_DEBUG;
1786 else if (strcmp(opt, "hard_remove") == 0)
1787 f->flags |= FUSE_HARD_REMOVE;
Miklos Szeredia13d9002004-11-02 17:32:03 +00001788 else if (strcmp(opt, "use_ino") == 0)
1789 f->flags |= FUSE_USE_INO;
Miklos Szeredibd7661b2004-07-23 17:16:29 +00001790 else
1791 fprintf(stderr, "fuse: warning: unknown option `%s'\n", opt);
1792 }
1793 free(xopts);
1794 }
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001795 return 0;
Miklos Szeredibd7661b2004-07-23 17:16:29 +00001796}
1797
1798struct fuse *fuse_new(int fd, const char *opts, const struct fuse_operations *op)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001799{
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001800 struct fuse *f;
1801 struct node *root;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001802
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001803 f = (struct fuse *) calloc(1, sizeof(struct fuse));
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001804 if (f == NULL)
1805 goto out;
Miklos Szeredi2df1c042001-11-06 15:07:17 +00001806
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001807 if (check_version(f) == -1)
1808 goto out_free;
Miklos Szeredic40748a2004-02-20 16:38:45 +00001809
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001810 if (parse_lib_opts(f, opts) == -1)
1811 goto out_free;
1812
Miklos Szeredi8cffdb92001-11-09 14:49:18 +00001813 f->fd = fd;
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001814 f->ctr = 0;
Miklos Szeredi76f65782004-02-19 16:55:40 +00001815 f->generation = 0;
Miklos Szeredifff56ab2001-11-16 10:12:59 +00001816 /* FIXME: Dynamic hash table */
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001817 f->name_table_size = 14057;
1818 f->name_table = (struct node **)
1819 calloc(1, sizeof(struct node *) * f->name_table_size);
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001820 if (f->name_table == NULL)
1821 goto out_free;
1822
Miklos Szeredia13d9002004-11-02 17:32:03 +00001823 f->id_table_size = 14057;
1824 f->id_table = (struct node **)
1825 calloc(1, sizeof(struct node *) * f->id_table_size);
1826 if (f->id_table == NULL)
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001827 goto out_free_name_table;
1828
Miklos Szeredia25d4c22004-11-23 22:32:16 +00001829#ifndef USE_UCLIBC
1830 pthread_mutex_init(&f->lock, NULL);
1831#else
1832 {
1833 pthread_mutexattr_t attr;
1834 pthread_mutexattr_init(&attr);
1835 pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ADAPTIVE_NP);
1836 pthread_mutex_init(&f->lock, &attr);
1837 pthread_mutexattr_destroy(&attr);
1838 }
1839#endif
Miklos Szeredi33232032001-11-19 17:55:51 +00001840 f->numworker = 0;
1841 f->numavail = 0;
Miklos Szeredi2e50d432001-12-20 12:17:25 +00001842 f->op = *op;
Miklos Szeredi0f48a262002-12-05 14:23:01 +00001843 f->exited = 0;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001844
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001845 root = (struct node *) calloc(1, sizeof(struct node));
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001846 if (root == NULL)
Miklos Szeredia13d9002004-11-02 17:32:03 +00001847 goto out_free_id_table;
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001848
Miklos Szeredi8cffdb92001-11-09 14:49:18 +00001849 root->mode = 0;
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001850 root->rdev = 0;
1851 root->name = strdup("/");
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001852 if (root->name == NULL)
1853 goto out_free_root;
1854
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001855 root->parent = 0;
Miklos Szeredia13d9002004-11-02 17:32:03 +00001856 root->nodeid = FUSE_ROOT_ID;
Miklos Szeredi76f65782004-02-19 16:55:40 +00001857 root->generation = 0;
Miklos Szeredia13d9002004-11-02 17:32:03 +00001858 hash_id(f, root);
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001859
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001860 return f;
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001861
1862 out_free_root:
1863 free(root);
Miklos Szeredia13d9002004-11-02 17:32:03 +00001864 out_free_id_table:
1865 free(f->id_table);
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001866 out_free_name_table:
1867 free(f->name_table);
1868 out_free:
1869 free(f);
1870 out:
1871 fprintf(stderr, "fuse: failed to allocate fuse object\n");
1872 return NULL;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001873}
1874
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001875void fuse_destroy(struct fuse *f)
1876{
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001877 size_t i;
Miklos Szeredia13d9002004-11-02 17:32:03 +00001878 for (i = 0; i < f->id_table_size; i++) {
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001879 struct node *node;
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001880
Miklos Szeredia13d9002004-11-02 17:32:03 +00001881 for (node = f->id_table[i]; node != NULL; node = node->id_next) {
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001882 if (node->is_hidden) {
Miklos Szeredia13d9002004-11-02 17:32:03 +00001883 char *path = get_path(f, node->nodeid);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001884 if (path)
1885 f->op.unlink(path);
1886 }
1887 }
1888 }
Miklos Szeredia13d9002004-11-02 17:32:03 +00001889 for (i = 0; i < f->id_table_size; i++) {
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001890 struct node *node;
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001891 struct node *next;
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001892
Miklos Szeredia13d9002004-11-02 17:32:03 +00001893 for (node = f->id_table[i]; node != NULL; node = next) {
1894 next = node->id_next;
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001895 free_node(node);
1896 }
1897 }
Miklos Szeredia13d9002004-11-02 17:32:03 +00001898 free(f->id_table);
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001899 free(f->name_table);
Miklos Szeredia181e612001-11-06 12:03:23 +00001900 pthread_mutex_destroy(&f->lock);
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001901 free(f);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001902}