blob: eeae295a9d6fe689a12767226cca8afe4d5f93e6 [file] [log] [blame]
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001/*
2 FUSE: Filesystem in Userspace
3 Copyright (C) 2001 Miklos Szeredi (mszeredi@inf.bme.hu)
4
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
9#include "fuse_i.h"
10#include <linux/fuse.h>
11
12#include <string.h>
Miklos Szeredi97c61e92001-11-07 12:09:43 +000013#include <stdlib.h>
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000014#include <unistd.h>
Miklos Szeredi97c61e92001-11-07 12:09:43 +000015#include <limits.h>
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000016#include <errno.h>
Miklos Szeredi019b4e92001-12-26 18:08:09 +000017#include <sys/param.h>
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000018
Miklos Szeredi97c61e92001-11-07 12:09:43 +000019#define FUSE_MAX_PATH 4096
Miklos Szeredi6bf8b682002-10-28 08:49:39 +000020#define PARAM(inarg) (((char *)(inarg)) + sizeof(*inarg))
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000021
Miklos Szeredi254d5ed2004-03-02 11:11:24 +000022#define ENTRY_REVALIDATE_TIME 1 /* sec */
23#define ATTR_REVALIDATE_TIME 1 /* sec */
24
Miklos Szeredic8ba2372002-12-10 12:26:00 +000025static const char *opname(enum fuse_opcode opcode)
26{
Miklos Szeredi7eafcce2004-06-19 22:42:38 +000027 switch (opcode) {
Miklos Szeredi3ed84232004-03-30 15:17:26 +000028 case FUSE_LOOKUP: return "LOOKUP";
29 case FUSE_FORGET: return "FORGET";
30 case FUSE_GETATTR: return "GETATTR";
31 case FUSE_SETATTR: return "SETATTR";
32 case FUSE_READLINK: return "READLINK";
33 case FUSE_SYMLINK: return "SYMLINK";
34 case FUSE_GETDIR: return "GETDIR";
35 case FUSE_MKNOD: return "MKNOD";
36 case FUSE_MKDIR: return "MKDIR";
37 case FUSE_UNLINK: return "UNLINK";
38 case FUSE_RMDIR: return "RMDIR";
39 case FUSE_RENAME: return "RENAME";
40 case FUSE_LINK: return "LINK";
41 case FUSE_OPEN: return "OPEN";
42 case FUSE_READ: return "READ";
43 case FUSE_WRITE: return "WRITE";
44 case FUSE_STATFS: return "STATFS";
Miklos Szeredi99f20742004-05-19 08:01:10 +000045 case FUSE_FLUSH: return "FLUSH";
Miklos Szeredi3ed84232004-03-30 15:17:26 +000046 case FUSE_RELEASE: return "RELEASE";
47 case FUSE_FSYNC: return "FSYNC";
48 case FUSE_SETXATTR: return "SETXATTR";
49 case FUSE_GETXATTR: return "GETXATTR";
50 case FUSE_LISTXATTR: return "LISTXATTR";
51 case FUSE_REMOVEXATTR: return "REMOVEXATTR";
Miklos Szeredi99f20742004-05-19 08:01:10 +000052 default: return "???";
Miklos Szeredic8ba2372002-12-10 12:26:00 +000053 }
54}
55
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +000056static inline void inc_avail(struct fuse *f)
57{
58 pthread_mutex_lock(&f->lock);
59 f->numavail ++;
60 pthread_mutex_unlock(&f->lock);
61}
62
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 Szeredi97c61e92001-11-07 12:09:43 +000070static struct node *__get_node(struct fuse *f, fino_t ino)
Miklos Szeredia181e612001-11-06 12:03:23 +000071{
Miklos Szeredi97c61e92001-11-07 12:09:43 +000072 size_t hash = ino % f->ino_table_size;
73 struct node *node;
74
Miklos Szeredi7eafcce2004-06-19 22:42:38 +000075 for (node = f->ino_table[hash]; node != NULL; node = node->ino_next)
76 if (node->ino == ino)
Miklos Szeredi97c61e92001-11-07 12:09:43 +000077 return node;
78
79 return NULL;
Miklos Szeredia181e612001-11-06 12:03:23 +000080}
81
Miklos Szeredi97c61e92001-11-07 12:09:43 +000082static struct node *get_node(struct fuse *f, fino_t ino)
Miklos Szeredia181e612001-11-06 12:03:23 +000083{
Miklos Szeredi97c61e92001-11-07 12:09:43 +000084 struct node *node = __get_node(f, ino);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +000085 if (node != NULL)
Miklos Szeredi97c61e92001-11-07 12:09:43 +000086 return node;
87
88 fprintf(stderr, "fuse internal error: inode %lu not found\n", ino);
89 abort();
Miklos Szeredia181e612001-11-06 12:03:23 +000090}
91
Miklos Szeredi76f65782004-02-19 16:55:40 +000092static void hash_ino(struct fuse *f, struct node *node)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000093{
Miklos Szeredi76f65782004-02-19 16:55:40 +000094 size_t hash = node->ino % f->ino_table_size;
Miklos Szeredi97c61e92001-11-07 12:09:43 +000095 node->ino_next = f->ino_table[hash];
96 f->ino_table[hash] = node;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000097}
98
Miklos Szeredi97c61e92001-11-07 12:09:43 +000099static void unhash_ino(struct fuse *f, struct node *node)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000100{
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000101 size_t hash = node->ino % f->ino_table_size;
102 struct node **nodep = &f->ino_table[hash];
103
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000104 for (; *nodep != NULL; nodep = &(*nodep)->ino_next)
105 if (*nodep == node) {
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000106 *nodep = node->ino_next;
107 return;
108 }
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000109}
110
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000111static fino_t next_ino(struct fuse *f)
112{
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
127static unsigned int name_hash(struct fuse *f, fino_t parent, const char *name)
128{
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 Szeredi19dff1b2001-10-30 15:06:52 +0000138static struct node *lookup_node(struct fuse *f, fino_t parent,
139 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 Szeredi97c61e92001-11-07 12:09:43 +0000151static void hash_name(struct fuse *f, struct node *node, fino_t parent,
Miklos Szeredia181e612001-11-06 12:03:23 +0000152 const char *name)
Miklos Szeredi5e183482001-10-31 14:52:35 +0000153{
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000154 size_t hash = name_hash(f, parent, name);
Miklos Szeredia181e612001-11-06 12:03:23 +0000155 node->parent = parent;
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000156 node->name = strdup(name);
157 node->name_next = f->name_table[hash];
158 f->name_table[hash] = node;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000159}
160
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000161static void unhash_name(struct fuse *f, struct node *node)
Miklos Szeredia181e612001-11-06 12:03:23 +0000162{
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000163 if (node->name != NULL) {
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000164 size_t hash = name_hash(f, node->parent, node->name);
165 struct node **nodep = &f->name_table[hash];
166
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000167 for (; *nodep != NULL; nodep = &(*nodep)->name_next)
168 if (*nodep == node) {
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000169 *nodep = node->name_next;
170 node->name_next = NULL;
171 free(node->name);
172 node->name = NULL;
173 node->parent = 0;
174 return;
175 }
176 fprintf(stderr, "fuse internal error: unable to unhash node: %lu\n",
177 node->ino);
178 abort();
Miklos Szeredia181e612001-11-06 12:03:23 +0000179 }
180}
181
Miklos Szeredi76f65782004-02-19 16:55:40 +0000182static struct node *find_node(struct fuse *f, fino_t parent, char *name,
183 struct fuse_attr *attr, int version)
Miklos Szeredi5e183482001-10-31 14:52:35 +0000184{
185 struct node *node;
Miklos Szeredia181e612001-11-06 12:03:23 +0000186 int mode = attr->mode & S_IFMT;
187 int rdev = 0;
188
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000189 if (S_ISCHR(mode) || S_ISBLK(mode))
Miklos Szeredia181e612001-11-06 12:03:23 +0000190 rdev = attr->rdev;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000191
Miklos Szeredia181e612001-11-06 12:03:23 +0000192 pthread_mutex_lock(&f->lock);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000193 node = lookup_node(f, parent, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000194 if (node != NULL) {
195 if (node->mode == mode && node->rdev == rdev)
Miklos Szeredia181e612001-11-06 12:03:23 +0000196 goto out;
197
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000198 unhash_name(f, node);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000199 }
200
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000201 node = (struct node *) calloc(1, sizeof(struct node));
Miklos Szeredia181e612001-11-06 12:03:23 +0000202 node->mode = mode;
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000203 node->rdev = rdev;
Miklos Szeredi76f65782004-02-19 16:55:40 +0000204 node->ino = next_ino(f);
205 node->generation = f->generation;
206 hash_ino(f, node);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000207 hash_name(f, node, parent, name);
Miklos Szeredia181e612001-11-06 12:03:23 +0000208
209 out:
210 node->version = version;
211 pthread_mutex_unlock(&f->lock);
Miklos Szeredi76f65782004-02-19 16:55:40 +0000212 return node;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000213}
214
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000215static char *add_name(char *buf, char *s, const char *name)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000216{
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000217 size_t len = strlen(name);
218 s -= len;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000219 if (s <= buf) {
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000220 fprintf(stderr, "fuse: path too long: ...%s\n", s + len);
221 return NULL;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000222 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000223 strncpy(s, name, len);
224 s--;
225 *s = '/';
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000226
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000227 return s;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000228}
229
Miklos Szeredia181e612001-11-06 12:03:23 +0000230static char *get_path_name(struct fuse *f, fino_t ino, const char *name)
Miklos Szeredib483c932001-10-29 14:57:57 +0000231{
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000232 char buf[FUSE_MAX_PATH];
233 char *s = buf + FUSE_MAX_PATH - 1;
234 struct node *node;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000235
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000236 *s = '\0';
Miklos Szeredia181e612001-11-06 12:03:23 +0000237
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000238 if (name != NULL) {
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000239 s = add_name(buf, s, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000240 if (s == NULL)
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000241 return NULL;
242 }
243
244 pthread_mutex_lock(&f->lock);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000245 for (node = get_node(f, ino); node->ino != FUSE_ROOT_INO;
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000246 node = get_node(f, node->parent)) {
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000247 if (node->name == NULL) {
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000248 s = NULL;
249 break;
250 }
251
252 s = add_name(buf, s, node->name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000253 if (s == NULL)
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000254 break;
255 }
256 pthread_mutex_unlock(&f->lock);
257
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000258 if (s == NULL)
Miklos Szeredi5e183482001-10-31 14:52:35 +0000259 return NULL;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000260 else if (*s == '\0')
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000261 return strdup("/");
262 else
263 return strdup(s);
264}
Miklos Szeredia181e612001-11-06 12:03:23 +0000265
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000266static char *get_path(struct fuse *f, fino_t ino)
267{
268 return get_path_name(f, ino, NULL);
Miklos Szeredib483c932001-10-29 14:57:57 +0000269}
270
Miklos Szeredia181e612001-11-06 12:03:23 +0000271static void destroy_node(struct fuse *f, fino_t ino, int version)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000272{
Miklos Szeredia181e612001-11-06 12:03:23 +0000273 struct node *node;
274
275 pthread_mutex_lock(&f->lock);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000276 node = get_node(f, ino);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000277 if (node->version == version && ino != FUSE_ROOT_INO) {
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000278 unhash_name(f, node);
279 unhash_ino(f, node);
Miklos Szeredia181e612001-11-06 12:03:23 +0000280 free_node(node);
281 }
282 pthread_mutex_unlock(&f->lock);
283
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000284}
285
Miklos Szeredi5e183482001-10-31 14:52:35 +0000286static void remove_node(struct fuse *f, fino_t dir, const char *name)
287{
Miklos Szeredia181e612001-11-06 12:03:23 +0000288 struct node *node;
289
290 pthread_mutex_lock(&f->lock);
291 node = lookup_node(f, dir, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000292 if (node == NULL) {
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000293 fprintf(stderr, "fuse internal error: unable to remove node %lu/%s\n",
294 dir, name);
295 abort();
296 }
297 unhash_name(f, node);
Miklos Szeredia181e612001-11-06 12:03:23 +0000298 pthread_mutex_unlock(&f->lock);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000299}
300
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000301static void rename_node(struct fuse *f, fino_t olddir, const char *oldname,
302 fino_t newdir, const char *newname)
303{
Miklos Szeredia181e612001-11-06 12:03:23 +0000304 struct node *node;
305 struct node *newnode;
306
307 pthread_mutex_lock(&f->lock);
308 node = lookup_node(f, olddir, oldname);
309 newnode = lookup_node(f, newdir, newname);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000310 if (node == NULL) {
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000311 fprintf(stderr, "fuse internal error: unable to rename node %lu/%s\n",
312 olddir, oldname);
313 abort();
314 }
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000315
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000316 if (newnode != NULL)
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000317 unhash_name(f, newnode);
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000318
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000319 unhash_name(f, node);
320 hash_name(f, node, newdir, newname);
Miklos Szeredia181e612001-11-06 12:03:23 +0000321 pthread_mutex_unlock(&f->lock);
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000322}
323
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000324static void convert_stat(struct stat *stbuf, struct fuse_attr *attr)
325{
Miklos Szeredib5958612004-02-20 14:10:49 +0000326 attr->mode = stbuf->st_mode;
327 attr->nlink = stbuf->st_nlink;
328 attr->uid = stbuf->st_uid;
329 attr->gid = stbuf->st_gid;
330 attr->rdev = stbuf->st_rdev;
331 attr->size = stbuf->st_size;
332 attr->blocks = stbuf->st_blocks;
333 attr->atime = stbuf->st_atime;
334 attr->atimensec = stbuf->st_atim.tv_nsec;
335 attr->mtime = stbuf->st_mtime;
336 attr->mtimensec = stbuf->st_mtim.tv_nsec;
337 attr->ctime = stbuf->st_ctime;
338 attr->ctimensec = stbuf->st_ctim.tv_nsec;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000339}
340
Miklos Szeredia181e612001-11-06 12:03:23 +0000341static int fill_dir(struct fuse_dirhandle *dh, char *name, int type)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000342{
343 struct fuse_dirent dirent;
344 size_t reclen;
345 size_t res;
346
Miklos Szeredi43696432001-11-18 19:15:05 +0000347 dirent.ino = (unsigned long) -1;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000348 dirent.namelen = strlen(name);
349 strncpy(dirent.name, name, sizeof(dirent.name));
350 dirent.type = type;
351 reclen = FUSE_DIRENT_SIZE(&dirent);
352 res = fwrite(&dirent, reclen, 1, dh->fp);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000353 if (res == 0) {
Miklos Szeredi96249982001-11-21 12:21:19 +0000354 perror("fuse: writing directory file");
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000355 return -EIO;
356 }
357 return 0;
358}
359
Miklos Szeredi40b9a5a2002-12-10 16:09:02 +0000360static int send_reply_raw(struct fuse *f, char *outbuf, size_t outsize)
Miklos Szeredi43696432001-11-18 19:15:05 +0000361{
362 int res;
363
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000364 if ((f->flags & FUSE_DEBUG)) {
Miklos Szeredi43696432001-11-18 19:15:05 +0000365 struct fuse_out_header *out = (struct fuse_out_header *) outbuf;
366 printf(" unique: %i, error: %i (%s), outsize: %i\n", out->unique,
367 out->error, strerror(-out->error), outsize);
368 fflush(stdout);
369 }
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +0000370
Miklos Szeredi4e71c9f2004-02-09 12:05:14 +0000371 /* This needs to be done before the reply, otherwise the scheduler
372 could play tricks with us, and only let the counter be increased
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +0000373 long after the operation is done */
374 inc_avail(f);
375
Miklos Szeredi43696432001-11-18 19:15:05 +0000376 res = write(f->fd, outbuf, outsize);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000377 if (res == -1) {
Miklos Szeredi43696432001-11-18 19:15:05 +0000378 /* ENOENT means the operation was interrupted */
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000379 if (!f->exited && errno != ENOENT)
Miklos Szeredi96249982001-11-21 12:21:19 +0000380 perror("fuse: writing device");
Miklos Szeredi40b9a5a2002-12-10 16:09:02 +0000381 return -errno;
Miklos Szeredi43696432001-11-18 19:15:05 +0000382 }
Miklos Szeredi40b9a5a2002-12-10 16:09:02 +0000383 return 0;
Miklos Szeredi43696432001-11-18 19:15:05 +0000384}
385
Miklos Szeredi40b9a5a2002-12-10 16:09:02 +0000386static int send_reply(struct fuse *f, struct fuse_in_header *in, int error,
387 void *arg, size_t argsize)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000388{
Miklos Szeredi40b9a5a2002-12-10 16:09:02 +0000389 int res;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000390 char *outbuf;
391 size_t outsize;
392 struct fuse_out_header *out;
393
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000394 if (error <= -1000 || error > 0) {
Miklos Szeredi0f48a262002-12-05 14:23:01 +0000395 fprintf(stderr, "fuse: bad error value: %i\n", error);
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000396 error = -ERANGE;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000397 }
398
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000399 if (error)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000400 argsize = 0;
401
402 outsize = sizeof(struct fuse_out_header) + argsize;
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000403 outbuf = (char *) malloc(outsize);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000404 out = (struct fuse_out_header *) outbuf;
Miklos Szeredi0f48a262002-12-05 14:23:01 +0000405 memset(out, 0, sizeof(struct fuse_out_header));
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000406 out->unique = in->unique;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000407 out->error = error;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000408 if (argsize != 0)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000409 memcpy(outbuf + sizeof(struct fuse_out_header), arg, argsize);
410
Miklos Szeredi40b9a5a2002-12-10 16:09:02 +0000411 res = send_reply_raw(f, outbuf, outsize);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000412 free(outbuf);
Miklos Szeredi40b9a5a2002-12-10 16:09:02 +0000413
414 return res;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000415}
416
Miklos Szeredi76f65782004-02-19 16:55:40 +0000417static int lookup_path(struct fuse *f, fino_t ino, int version, char *name,
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000418 const char *path, struct fuse_entry_out *arg)
Miklos Szeredi76f65782004-02-19 16:55:40 +0000419{
420 int res;
421 struct stat buf;
422
423 res = f->op.getattr(path, &buf);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000424 if (res == 0) {
Miklos Szeredi76f65782004-02-19 16:55:40 +0000425 struct node *node;
426
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000427 memset(arg, 0, sizeof(struct fuse_entry_out));
Miklos Szeredi76f65782004-02-19 16:55:40 +0000428 convert_stat(&buf, &arg->attr);
429 node = find_node(f, ino, name, &arg->attr, version);
430 arg->ino = node->ino;
431 arg->generation = node->generation;
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000432 arg->entry_valid = ENTRY_REVALIDATE_TIME;
433 arg->entry_valid_nsec = 0;
434 arg->attr_valid = ATTR_REVALIDATE_TIME;
435 arg->attr_valid_nsec = 0;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000436 if (f->flags & FUSE_DEBUG) {
Miklos Szeredi76f65782004-02-19 16:55:40 +0000437 printf(" INO: %li\n", arg->ino);
438 fflush(stdout);
439 }
440 }
441 return res;
442}
443
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000444static void do_lookup(struct fuse *f, struct fuse_in_header *in, char *name)
445{
446 int res;
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000447 int res2;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000448 char *path;
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000449 struct fuse_entry_out arg;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000450
Miklos Szeredi5e183482001-10-31 14:52:35 +0000451 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000452 path = get_path_name(f, in->ino, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000453 if (path != NULL) {
454 if (f->flags & FUSE_DEBUG) {
Miklos Szeredi6ebe2342002-01-06 21:44:16 +0000455 printf("LOOKUP %s\n", path);
456 fflush(stdout);
457 }
Miklos Szeredi5e183482001-10-31 14:52:35 +0000458 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000459 if (f->op.getattr)
Miklos Szeredi76f65782004-02-19 16:55:40 +0000460 res = lookup_path(f, in->ino, in->unique, name, path, &arg);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000461 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000462 }
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000463 res2 = send_reply(f, in, res, &arg, sizeof(arg));
464 if (res == 0 && res2 == -ENOENT)
465 destroy_node(f, arg.ino, in->unique);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000466}
467
Miklos Szeredia181e612001-11-06 12:03:23 +0000468static void do_forget(struct fuse *f, struct fuse_in_header *in,
469 struct fuse_forget_in *arg)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000470{
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000471 if (f->flags & FUSE_DEBUG) {
Miklos Szeredi43696432001-11-18 19:15:05 +0000472 printf("FORGET %li/%i\n", in->ino, arg->version);
473 fflush(stdout);
474 }
Miklos Szeredia181e612001-11-06 12:03:23 +0000475 destroy_node(f, in->ino, arg->version);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000476}
477
478static void do_getattr(struct fuse *f, struct fuse_in_header *in)
479{
480 int res;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000481 char *path;
482 struct stat buf;
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000483 struct fuse_attr_out arg;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000484
Miklos Szeredi5e183482001-10-31 14:52:35 +0000485 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000486 path = get_path(f, in->ino);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000487 if (path != NULL) {
Miklos Szeredi5e183482001-10-31 14:52:35 +0000488 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000489 if (f->op.getattr)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000490 res = f->op.getattr(path, &buf);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000491 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000492 }
Miklos Szeredi0f48a262002-12-05 14:23:01 +0000493
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000494 if (res == 0) {
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000495 memset(&arg, 0, sizeof(struct fuse_attr_out));
496 arg.attr_valid = ATTR_REVALIDATE_TIME;
497 arg.attr_valid_nsec = 0;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000498 convert_stat(&buf, &arg.attr);
Miklos Szeredi0f48a262002-12-05 14:23:01 +0000499 }
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000500
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000501 send_reply(f, in, res, &arg, sizeof(arg));
502}
503
Miklos Szeredi680a69a2001-11-16 13:31:14 +0000504static int do_chmod(struct fuse *f, const char *path, struct fuse_attr *attr)
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000505{
506 int res;
507
508 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000509 if (f->op.chmod)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000510 res = f->op.chmod(path, attr->mode);
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000511
512 return res;
513}
514
Miklos Szeredi680a69a2001-11-16 13:31:14 +0000515static int do_chown(struct fuse *f, const char *path, struct fuse_attr *attr,
Miklos Szeredi2e50d432001-12-20 12:17:25 +0000516 int valid)
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000517{
518 int res;
519 uid_t uid = (valid & FATTR_UID) ? attr->uid : (uid_t) -1;
520 gid_t gid = (valid & FATTR_GID) ? attr->gid : (gid_t) -1;
521
522 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000523 if (f->op.chown)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000524 res = f->op.chown(path, uid, gid);
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000525
526 return res;
527}
528
Miklos Szeredi680a69a2001-11-16 13:31:14 +0000529static int do_truncate(struct fuse *f, const char *path,
530 struct fuse_attr *attr)
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000531{
532 int res;
533
534 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000535 if (f->op.truncate)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000536 res = f->op.truncate(path, attr->size);
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000537
538 return res;
539}
540
Miklos Szeredi680a69a2001-11-16 13:31:14 +0000541static int do_utime(struct fuse *f, const char *path, struct fuse_attr *attr)
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000542{
543 int res;
544 struct utimbuf buf;
545 buf.actime = attr->atime;
546 buf.modtime = attr->mtime;
547 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000548 if (f->op.utime)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000549 res = f->op.utime(path, &buf);
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000550
551 return res;
552}
553
Miklos Szeredi5e183482001-10-31 14:52:35 +0000554static void do_setattr(struct fuse *f, struct fuse_in_header *in,
555 struct fuse_setattr_in *arg)
556{
557 int res;
558 char *path;
559 int valid = arg->valid;
560 struct fuse_attr *attr = &arg->attr;
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000561 struct fuse_attr_out outarg;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000562
563 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000564 path = get_path(f, in->ino);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000565 if (path != NULL) {
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000566 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000567 if (f->op.getattr) {
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000568 res = 0;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000569 if (!res && (valid & FATTR_MODE))
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000570 res = do_chmod(f, path, attr);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000571 if (!res && (valid & (FATTR_UID | FATTR_GID)))
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000572 res = do_chown(f, path, attr, valid);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000573 if (!res && (valid & FATTR_SIZE))
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000574 res = do_truncate(f, path, attr);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000575 if (!res && (valid & (FATTR_ATIME | FATTR_MTIME)) ==
Miklos Szeredib5958612004-02-20 14:10:49 +0000576 (FATTR_ATIME | FATTR_MTIME))
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000577 res = do_utime(f, path, attr);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000578 if (!res) {
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000579 struct stat buf;
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000580 res = f->op.getattr(path, &buf);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000581 if (!res) {
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000582 memset(&outarg, 0, sizeof(struct fuse_attr_out));
583 outarg.attr_valid = ATTR_REVALIDATE_TIME;
584 outarg.attr_valid_nsec = 0;
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000585 convert_stat(&buf, &outarg.attr);
Miklos Szeredi0f48a262002-12-05 14:23:01 +0000586 }
Miklos Szeredia181e612001-11-06 12:03:23 +0000587 }
Miklos Szeredi5e183482001-10-31 14:52:35 +0000588 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000589 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000590 }
Miklos Szeredia181e612001-11-06 12:03:23 +0000591 send_reply(f, in, res, &outarg, sizeof(outarg));
Miklos Szeredi5e183482001-10-31 14:52:35 +0000592}
593
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000594static void do_readlink(struct fuse *f, struct fuse_in_header *in)
595{
596 int res;
597 char link[PATH_MAX + 1];
Miklos Szeredib483c932001-10-29 14:57:57 +0000598 char *path;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000599
Miklos Szeredi5e183482001-10-31 14:52:35 +0000600 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000601 path = get_path(f, in->ino);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000602 if (path != NULL) {
Miklos Szeredi5e183482001-10-31 14:52:35 +0000603 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000604 if (f->op.readlink)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000605 res = f->op.readlink(path, link, sizeof(link));
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000606 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000607 }
Miklos Szeredi2df1c042001-11-06 15:07:17 +0000608 link[PATH_MAX] = '\0';
Miklos Szeredi4b2bef42002-01-09 12:23:27 +0000609 send_reply(f, in, res, link, res == 0 ? strlen(link) : 0);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000610}
611
612static void do_getdir(struct fuse *f, struct fuse_in_header *in)
613{
614 int res;
615 struct fuse_getdir_out arg;
Miklos Szeredia181e612001-11-06 12:03:23 +0000616 struct fuse_dirhandle dh;
Miklos Szeredib483c932001-10-29 14:57:57 +0000617 char *path;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000618
Miklos Szeredib483c932001-10-29 14:57:57 +0000619 dh.fuse = f;
620 dh.fp = tmpfile();
621 dh.dir = in->ino;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000622 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000623 path = get_path(f, in->ino);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000624 if (path != NULL) {
Miklos Szeredi5e183482001-10-31 14:52:35 +0000625 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000626 if (f->op.getdir)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000627 res = f->op.getdir(path, &dh, (fuse_dirfil_t) fill_dir);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000628 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000629 }
Miklos Szeredib483c932001-10-29 14:57:57 +0000630 fflush(dh.fp);
Miklos Szeredi0f48a262002-12-05 14:23:01 +0000631
632 memset(&arg, 0, sizeof(struct fuse_getdir_out));
Miklos Szeredib483c932001-10-29 14:57:57 +0000633 arg.fd = fileno(dh.fp);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000634 send_reply(f, in, res, &arg, sizeof(arg));
Miklos Szeredib483c932001-10-29 14:57:57 +0000635 fclose(dh.fp);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000636}
637
Miklos Szeredib483c932001-10-29 14:57:57 +0000638static void do_mknod(struct fuse *f, struct fuse_in_header *in,
639 struct fuse_mknod_in *inarg)
640{
641 int res;
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000642 int res2;
Miklos Szeredib483c932001-10-29 14:57:57 +0000643 char *path;
Miklos Szeredi76f65782004-02-19 16:55:40 +0000644 char *name = PARAM(inarg);
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000645 struct fuse_entry_out outarg;
Miklos Szeredib483c932001-10-29 14:57:57 +0000646
Miklos Szeredi5e183482001-10-31 14:52:35 +0000647 res = -ENOENT;
Miklos Szeredi76f65782004-02-19 16:55:40 +0000648 path = get_path_name(f, in->ino, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000649 if (path != NULL) {
650 if (f->flags & FUSE_DEBUG) {
Miklos Szeredi76f65782004-02-19 16:55:40 +0000651 printf("MKNOD %s\n", path);
652 fflush(stdout);
653 }
Miklos Szeredi5e183482001-10-31 14:52:35 +0000654 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000655 if (f->op.mknod && f->op.getattr) {
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000656 res = f->op.mknod(path, inarg->mode, inarg->rdev);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000657 if (res == 0)
Miklos Szeredi76f65782004-02-19 16:55:40 +0000658 res = lookup_path(f, in->ino, in->unique, name, path, &outarg);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000659 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000660 free(path);
Miklos Szeredib483c932001-10-29 14:57:57 +0000661 }
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000662 res2 = send_reply(f, in, res, &outarg, sizeof(outarg));
663 if (res == 0 && res2 == -ENOENT)
664 destroy_node(f, outarg.ino, in->unique);
Miklos Szeredib483c932001-10-29 14:57:57 +0000665}
666
667static void do_mkdir(struct fuse *f, struct fuse_in_header *in,
668 struct fuse_mkdir_in *inarg)
669{
670 int res;
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000671 int res2;
Miklos Szeredib483c932001-10-29 14:57:57 +0000672 char *path;
Miklos Szeredi76f65782004-02-19 16:55:40 +0000673 char *name = PARAM(inarg);
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000674 struct fuse_entry_out outarg;
Miklos Szeredib483c932001-10-29 14:57:57 +0000675
Miklos Szeredi5e183482001-10-31 14:52:35 +0000676 res = -ENOENT;
Miklos Szeredi76f65782004-02-19 16:55:40 +0000677 path = get_path_name(f, in->ino, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000678 if (path != NULL) {
679 if (f->flags & FUSE_DEBUG) {
Miklos Szeredi76f65782004-02-19 16:55:40 +0000680 printf("MKDIR %s\n", path);
681 fflush(stdout);
682 }
Miklos Szeredi5e183482001-10-31 14:52:35 +0000683 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000684 if (f->op.mkdir && f->op.getattr) {
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000685 res = f->op.mkdir(path, inarg->mode);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000686 if (res == 0)
Miklos Szeredi76f65782004-02-19 16:55:40 +0000687 res = lookup_path(f, in->ino, in->unique, name, path, &outarg);
688 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000689 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000690 }
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000691 res2 = send_reply(f, in, res, &outarg, sizeof(outarg));
692 if (res == 0 && res2 == -ENOENT)
693 destroy_node(f, outarg.ino, in->unique);
Miklos Szeredib483c932001-10-29 14:57:57 +0000694}
695
Miklos Szeredib5958612004-02-20 14:10:49 +0000696static void do_unlink(struct fuse *f, struct fuse_in_header *in, char *name)
Miklos Szeredib483c932001-10-29 14:57:57 +0000697{
698 int res;
699 char *path;
700
Miklos Szeredi5e183482001-10-31 14:52:35 +0000701 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000702 path = get_path_name(f, in->ino, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000703 if (path != NULL) {
Miklos Szeredi5e183482001-10-31 14:52:35 +0000704 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000705 if (f->op.unlink) {
Miklos Szeredib5958612004-02-20 14:10:49 +0000706 res = f->op.unlink(path);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000707 if (res == 0)
Miklos Szeredib5958612004-02-20 14:10:49 +0000708 remove_node(f, in->ino, name);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000709 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000710 free(path);
Miklos Szeredib483c932001-10-29 14:57:57 +0000711 }
Miklos Szeredib5958612004-02-20 14:10:49 +0000712 send_reply(f, in, res, NULL, 0);
713}
714
715static void do_rmdir(struct fuse *f, struct fuse_in_header *in, char *name)
716{
717 int res;
718 char *path;
719
720 res = -ENOENT;
721 path = get_path_name(f, in->ino, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000722 if (path != NULL) {
Miklos Szeredib5958612004-02-20 14:10:49 +0000723 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000724 if (f->op.rmdir) {
Miklos Szeredib5958612004-02-20 14:10:49 +0000725 res = f->op.rmdir(path);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000726 if (res == 0)
Miklos Szeredib5958612004-02-20 14:10:49 +0000727 remove_node(f, in->ino, name);
728 }
729 free(path);
730 }
Miklos Szeredib483c932001-10-29 14:57:57 +0000731 send_reply(f, in, res, NULL, 0);
732}
733
734static void do_symlink(struct fuse *f, struct fuse_in_header *in, char *name,
735 char *link)
736{
737 int res;
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000738 int res2;
Miklos Szeredib483c932001-10-29 14:57:57 +0000739 char *path;
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000740 struct fuse_entry_out outarg;
Miklos Szeredib483c932001-10-29 14:57:57 +0000741
Miklos Szeredi5e183482001-10-31 14:52:35 +0000742 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000743 path = get_path_name(f, in->ino, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000744 if (path != NULL) {
745 if (f->flags & FUSE_DEBUG) {
Miklos Szeredi76f65782004-02-19 16:55:40 +0000746 printf("SYMLINK %s\n", path);
747 fflush(stdout);
748 }
Miklos Szeredi5e183482001-10-31 14:52:35 +0000749 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000750 if (f->op.symlink && f->op.getattr) {
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000751 res = f->op.symlink(link, path);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000752 if (res == 0)
Miklos Szeredi76f65782004-02-19 16:55:40 +0000753 res = lookup_path(f, in->ino, in->unique, name, path, &outarg);
754 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000755 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000756 }
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000757 res2 = send_reply(f, in, res, &outarg, sizeof(outarg));
758 if (res == 0 && res2 == -ENOENT)
759 destroy_node(f, outarg.ino, in->unique);
760
Miklos Szeredib483c932001-10-29 14:57:57 +0000761}
762
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000763static void do_rename(struct fuse *f, struct fuse_in_header *in,
764 struct fuse_rename_in *inarg)
765{
766 int res;
767 fino_t olddir = in->ino;
768 fino_t newdir = inarg->newdir;
Miklos Szeredi6bf8b682002-10-28 08:49:39 +0000769 char *oldname = PARAM(inarg);
770 char *newname = oldname + strlen(oldname) + 1;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000771 char *oldpath;
772 char *newpath;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000773
Miklos Szeredi5e183482001-10-31 14:52:35 +0000774 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000775 oldpath = get_path_name(f, olddir, oldname);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000776 if (oldpath != NULL) {
Miklos Szeredia181e612001-11-06 12:03:23 +0000777 newpath = get_path_name(f, newdir, newname);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000778 if (newpath != NULL) {
Miklos Szeredi5e183482001-10-31 14:52:35 +0000779 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000780 if (f->op.rename)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000781 res = f->op.rename(oldpath, newpath);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000782 if (res == 0)
Miklos Szeredi5e183482001-10-31 14:52:35 +0000783 rename_node(f, olddir, oldname, newdir, newname);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000784 free(newpath);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000785 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000786 free(oldpath);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000787 }
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000788 send_reply(f, in, res, NULL, 0);
789}
790
791static void do_link(struct fuse *f, struct fuse_in_header *in,
Miklos Szeredi5e183482001-10-31 14:52:35 +0000792 struct fuse_link_in *arg)
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000793{
794 int res;
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000795 int res2;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000796 char *oldpath;
797 char *newpath;
Miklos Szeredi76f65782004-02-19 16:55:40 +0000798 char *name = PARAM(arg);
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000799 struct fuse_entry_out outarg;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000800
Miklos Szeredi5e183482001-10-31 14:52:35 +0000801 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000802 oldpath = get_path(f, in->ino);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000803 if (oldpath != NULL) {
Miklos Szeredi76f65782004-02-19 16:55:40 +0000804 newpath = get_path_name(f, arg->newdir, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000805 if (newpath != NULL) {
806 if (f->flags & FUSE_DEBUG) {
Miklos Szeredi76f65782004-02-19 16:55:40 +0000807 printf("LINK %s\n", newpath);
808 fflush(stdout);
809 }
Miklos Szeredi5e183482001-10-31 14:52:35 +0000810 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000811 if (f->op.link && f->op.getattr) {
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000812 res = f->op.link(oldpath, newpath);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000813 if (res == 0)
Miklos Szeredi76f65782004-02-19 16:55:40 +0000814 res = lookup_path(f, arg->newdir, in->unique, name,
815 newpath, &outarg);
816 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000817 free(newpath);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000818 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000819 free(oldpath);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000820 }
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000821 res2 = send_reply(f, in, res, &outarg, sizeof(outarg));
822 if (res == 0 && res2 == -ENOENT)
823 destroy_node(f, outarg.ino, in->unique);
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000824}
825
Miklos Szeredi5e183482001-10-31 14:52:35 +0000826static void do_open(struct fuse *f, struct fuse_in_header *in,
827 struct fuse_open_in *arg)
828{
829 int res;
Miklos Szeredi40b9a5a2002-12-10 16:09:02 +0000830 int res2;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000831 char *path;
832
833 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000834 path = get_path(f, in->ino);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000835 if (path != NULL) {
Miklos Szeredi5e183482001-10-31 14:52:35 +0000836 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000837 if (f->op.open)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000838 res = f->op.open(path, arg->flags);
Miklos Szeredi40b9a5a2002-12-10 16:09:02 +0000839 }
840 res2 = send_reply(f, in, res, NULL, 0);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000841 if (path != NULL) {
Miklos Szeredi40b9a5a2002-12-10 16:09:02 +0000842 /* The open syscall was interrupted, so it must be cancelled */
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000843 if (res == 0 && res2 == -ENOENT && f->op.release)
Miklos Szeredi9478e862002-12-11 09:50:26 +0000844 f->op.release(path, arg->flags);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000845 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000846 }
Miklos Szeredi5e183482001-10-31 14:52:35 +0000847}
848
Miklos Szeredie2e4ac22004-05-18 08:45:28 +0000849static void do_flush(struct fuse *f, struct fuse_in_header *in)
850{
851 char *path;
852 int res;
853
854 res = -ENOENT;
855 path = get_path(f, in->ino);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000856 if (path != NULL) {
Miklos Szeredie2e4ac22004-05-18 08:45:28 +0000857 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000858 if (f->op.flush)
Miklos Szeredie2e4ac22004-05-18 08:45:28 +0000859 res = f->op.flush(path);
860 free(path);
861 }
862 send_reply(f, in, res, NULL, 0);
863}
864
Miklos Szeredi9478e862002-12-11 09:50:26 +0000865static void do_release(struct fuse *f, struct fuse_in_header *in,
866 struct fuse_open_in *arg)
Miklos Szeredic8ba2372002-12-10 12:26:00 +0000867{
Miklos Szeredic8ba2372002-12-10 12:26:00 +0000868 char *path;
869
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000870 if (!f->op.release) {
871 send_reply(f, in, -ENOSYS, NULL, 0);
872 return;
873 }
874
Miklos Szeredic8ba2372002-12-10 12:26:00 +0000875 path = get_path(f, in->ino);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000876 if (path != NULL) {
877 f->op.release(path, arg->flags);
Miklos Szeredic8ba2372002-12-10 12:26:00 +0000878 free(path);
879 }
Miklos Szeredic8ba2372002-12-10 12:26:00 +0000880}
881
Miklos Szeredi5e183482001-10-31 14:52:35 +0000882static void do_read(struct fuse *f, struct fuse_in_header *in,
883 struct fuse_read_in *arg)
884{
885 int res;
886 char *path;
Miklos Szeredi43696432001-11-18 19:15:05 +0000887 char *outbuf = (char *) malloc(sizeof(struct fuse_out_header) + arg->size);
888 struct fuse_out_header *out = (struct fuse_out_header *) outbuf;
889 char *buf = outbuf + sizeof(struct fuse_out_header);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000890 size_t size;
Miklos Szeredi43696432001-11-18 19:15:05 +0000891 size_t outsize;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000892
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000893 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000894 path = get_path(f, in->ino);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000895 if (path != NULL) {
896 if (f->flags & FUSE_DEBUG) {
Miklos Szeredi6ebe2342002-01-06 21:44:16 +0000897 printf("READ %u bytes from %llu\n", arg->size, arg->offset);
898 fflush(stdout);
899 }
900
Miklos Szeredi5e183482001-10-31 14:52:35 +0000901 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000902 if (f->op.read)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000903 res = f->op.read(path, buf, arg->size, arg->offset);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000904 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000905 }
906
907 size = 0;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000908 if (res > 0) {
Miklos Szeredi5e183482001-10-31 14:52:35 +0000909 size = res;
910 res = 0;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000911 if (f->flags & FUSE_DEBUG) {
Miklos Szeredi6ebe2342002-01-06 21:44:16 +0000912 printf(" READ %u bytes\n", size);
913 fflush(stdout);
914 }
Miklos Szeredi5e183482001-10-31 14:52:35 +0000915 }
Miklos Szeredi0f48a262002-12-05 14:23:01 +0000916 memset(out, 0, sizeof(struct fuse_out_header));
Miklos Szeredi43696432001-11-18 19:15:05 +0000917 out->unique = in->unique;
918 out->error = res;
919 outsize = sizeof(struct fuse_out_header) + size;
920
921 send_reply_raw(f, outbuf, outsize);
922 free(outbuf);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000923}
Miklos Szeredib483c932001-10-29 14:57:57 +0000924
Miklos Szeredia181e612001-11-06 12:03:23 +0000925static void do_write(struct fuse *f, struct fuse_in_header *in,
926 struct fuse_write_in *arg)
927{
928 int res;
929 char *path;
Miklos Szeredia181e612001-11-06 12:03:23 +0000930
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000931 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000932 path = get_path(f, in->ino);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000933 if (path != NULL) {
934 if (f->flags & FUSE_DEBUG) {
Miklos Szeredi6ebe2342002-01-06 21:44:16 +0000935 printf("WRITE %u bytes to %llu\n", arg->size, arg->offset);
936 fflush(stdout);
937 }
938
Miklos Szeredia181e612001-11-06 12:03:23 +0000939 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000940 if (f->op.write)
Miklos Szeredi6bf8b682002-10-28 08:49:39 +0000941 res = f->op.write(path, PARAM(arg), arg->size, arg->offset);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000942 free(path);
Miklos Szeredia181e612001-11-06 12:03:23 +0000943 }
944
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000945 if (res > 0) {
946 if ((size_t) res != arg->size) {
Miklos Szeredia181e612001-11-06 12:03:23 +0000947 fprintf(stderr, "short write: %u (should be %u)\n", res,
948 arg->size);
Miklos Szeredi0e535082003-10-13 10:08:06 +0000949 res = -EINVAL;
Miklos Szeredia181e612001-11-06 12:03:23 +0000950 }
951 else
952 res = 0;
953 }
954
955 send_reply(f, in, res, NULL, 0);
956}
957
Miklos Szeredi77f39942004-03-25 11:17:52 +0000958static int default_statfs(struct statfs *buf)
959{
960 buf->f_namelen = 255;
961 buf->f_bsize = 512;
962 return 0;
963}
964
Miklos Szeredi18e75e42004-02-19 14:23:27 +0000965static void convert_statfs(struct statfs *statfs, struct fuse_kstatfs *kstatfs)
966{
967 kstatfs->bsize = statfs->f_bsize;
968 kstatfs->blocks = statfs->f_blocks;
969 kstatfs->bfree = statfs->f_bfree;
970 kstatfs->bavail = statfs->f_bavail;
971 kstatfs->files = statfs->f_files;
972 kstatfs->ffree = statfs->f_ffree;
973 kstatfs->namelen = statfs->f_namelen;
974}
975
Mark Glinesd84b39a2002-01-07 16:32:02 +0000976static void do_statfs(struct fuse *f, struct fuse_in_header *in)
977{
978 int res;
Mark Glinesd84b39a2002-01-07 16:32:02 +0000979 struct fuse_statfs_out arg;
Miklos Szeredi18e75e42004-02-19 14:23:27 +0000980 struct statfs buf;
Mark Glinesd84b39a2002-01-07 16:32:02 +0000981
Miklos Szeredi77f39942004-03-25 11:17:52 +0000982 memset(&buf, 0, sizeof(struct statfs));
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000983 if (f->op.statfs)
Miklos Szeredi18e75e42004-02-19 14:23:27 +0000984 res = f->op.statfs("/", &buf);
Miklos Szeredi77f39942004-03-25 11:17:52 +0000985 else
986 res = default_statfs(&buf);
987
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000988 if (res == 0)
Miklos Szeredi77f39942004-03-25 11:17:52 +0000989 convert_statfs(&buf, &arg.st);
Miklos Szeredi4b2bef42002-01-09 12:23:27 +0000990
Mark Glinesd84b39a2002-01-07 16:32:02 +0000991 send_reply(f, in, res, &arg, sizeof(arg));
992}
993
Miklos Szeredi5e43f2c2003-12-12 14:06:41 +0000994static void do_fsync(struct fuse *f, struct fuse_in_header *in,
995 struct fuse_fsync_in *inarg)
996{
997 int res;
998 char *path;
999
1000 res = -ENOENT;
1001 path = get_path(f, in->ino);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001002 if (path != NULL) {
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001003 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001004 if (f->op.fsync)
Miklos Szeredi5e43f2c2003-12-12 14:06:41 +00001005 res = f->op.fsync(path, inarg->datasync);
1006 free(path);
1007 }
1008 send_reply(f, in, res, NULL, 0);
1009}
1010
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001011static void do_setxattr(struct fuse *f, struct fuse_in_header *in,
1012 struct fuse_setxattr_in *arg)
1013{
1014 int res;
1015 char *path;
1016 char *name = PARAM(arg);
1017 unsigned char *value = name + strlen(name) + 1;
1018
1019 res = -ENOENT;
1020 path = get_path(f, in->ino);
1021 if (path != NULL) {
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001022 res = -ENOSYS;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001023 if (f->op.setxattr)
1024 res = f->op.setxattr(path, name, value, arg->size, arg->flags);
1025 free(path);
1026 }
1027 send_reply(f, in, res, NULL, 0);
1028}
1029
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001030static int common_getxattr(struct fuse *f, struct fuse_in_header *in,
1031 const char *name, char *value, size_t size)
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001032{
1033 int res;
1034 char *path;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001035
1036 res = -ENOENT;
1037 path = get_path(f, in->ino);
1038 if (path != NULL) {
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001039 res = -ENOSYS;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001040 if (f->op.getxattr)
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001041 res = f->op.getxattr(path, name, value, size);
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001042 free(path);
1043 }
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001044 return res;
1045}
1046
1047static void do_getxattr_read(struct fuse *f, struct fuse_in_header *in,
1048 const char *name, size_t size)
1049{
1050 int res;
1051 char *outbuf = (char *) malloc(sizeof(struct fuse_out_header) + size);
1052 struct fuse_out_header *out = (struct fuse_out_header *) outbuf;
1053 char *value = outbuf + sizeof(struct fuse_out_header);
1054
1055 res = common_getxattr(f, in, name, value, size);
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001056 size = 0;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001057 if (res > 0) {
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001058 size = res;
1059 res = 0;
1060 }
1061 memset(out, 0, sizeof(struct fuse_out_header));
1062 out->unique = in->unique;
1063 out->error = res;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001064
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001065 send_reply_raw(f, outbuf, sizeof(struct fuse_out_header) + size);
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001066 free(outbuf);
1067}
1068
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001069static void do_getxattr_size(struct fuse *f, struct fuse_in_header *in,
1070 const char *name)
1071{
1072 int res;
1073 struct fuse_getxattr_out arg;
1074
1075 res = common_getxattr(f, in, name, NULL, 0);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001076 if (res >= 0) {
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001077 arg.size = res;
1078 res = 0;
1079 }
1080 send_reply(f, in, res, &arg, sizeof(arg));
1081}
1082
1083static void do_getxattr(struct fuse *f, struct fuse_in_header *in,
1084 struct fuse_getxattr_in *arg)
1085{
1086 char *name = PARAM(arg);
1087
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001088 if (arg->size)
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001089 do_getxattr_read(f, in, name, arg->size);
1090 else
1091 do_getxattr_size(f, in, name);
1092}
1093
1094static int common_listxattr(struct fuse *f, struct fuse_in_header *in,
1095 char *list, size_t size)
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001096{
1097 int res;
1098 char *path;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001099
1100 res = -ENOENT;
1101 path = get_path(f, in->ino);
1102 if (path != NULL) {
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001103 res = -ENOSYS;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001104 if (f->op.listxattr)
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001105 res = f->op.listxattr(path, list, size);
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001106 free(path);
1107 }
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001108 return res;
1109}
1110
1111static void do_listxattr_read(struct fuse *f, struct fuse_in_header *in,
1112 size_t size)
1113{
1114 int res;
1115 char *outbuf = (char *) malloc(sizeof(struct fuse_out_header) + size);
1116 struct fuse_out_header *out = (struct fuse_out_header *) outbuf;
1117 char *list = outbuf + sizeof(struct fuse_out_header);
1118
1119 res = common_listxattr(f, in, list, size);
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001120 size = 0;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001121 if (res > 0) {
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001122 size = res;
1123 res = 0;
1124 }
1125 memset(out, 0, sizeof(struct fuse_out_header));
1126 out->unique = in->unique;
1127 out->error = res;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001128
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001129 send_reply_raw(f, outbuf, sizeof(struct fuse_out_header) + size);
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001130 free(outbuf);
1131}
1132
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001133static void do_listxattr_size(struct fuse *f, struct fuse_in_header *in)
1134{
1135 int res;
1136 struct fuse_getxattr_out arg;
1137
1138 res = common_listxattr(f, in, NULL, 0);
1139 if (res >= 0) {
1140 arg.size = res;
1141 res = 0;
1142 }
1143 send_reply(f, in, res, &arg, sizeof(arg));
1144}
1145
1146static void do_listxattr(struct fuse *f, struct fuse_in_header *in,
1147 struct fuse_getxattr_in *arg)
1148{
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001149 if (arg->size)
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001150 do_listxattr_read(f, in, arg->size);
1151 else
1152 do_listxattr_size(f, in);
1153}
1154
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001155static void do_removexattr(struct fuse *f, struct fuse_in_header *in,
1156 char *name)
1157{
1158 int res;
1159 char *path;
1160
1161 res = -ENOENT;
1162 path = get_path(f, in->ino);
1163 if (path != NULL) {
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001164 res = -ENOSYS;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001165 if (f->op.removexattr)
1166 res = f->op.removexattr(path, name);
1167 free(path);
1168 }
1169 send_reply(f, in, res, NULL, 0);
1170}
1171
1172
Miklos Szeredi43696432001-11-18 19:15:05 +00001173static void free_cmd(struct fuse_cmd *cmd)
1174{
1175 free(cmd->buf);
1176 free(cmd);
1177}
1178
Miklos Szeredifff56ab2001-11-16 10:12:59 +00001179void __fuse_process_cmd(struct fuse *f, struct fuse_cmd *cmd)
Miklos Szeredia181e612001-11-06 12:03:23 +00001180{
Miklos Szeredia181e612001-11-06 12:03:23 +00001181 struct fuse_in_header *in = (struct fuse_in_header *) cmd->buf;
1182 void *inarg = cmd->buf + sizeof(struct fuse_in_header);
1183 size_t argsize;
Miklos Szeredife25def2001-12-20 15:38:05 +00001184 struct fuse_context *ctx = fuse_get_context(f);
Miklos Szeredia181e612001-11-06 12:03:23 +00001185
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +00001186 dec_avail(f);
Miklos Szeredi33232032001-11-19 17:55:51 +00001187
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001188 if ((f->flags & FUSE_DEBUG)) {
Miklos Szeredic8ba2372002-12-10 12:26:00 +00001189 printf("unique: %i, opcode: %s (%i), ino: %li, insize: %i\n",
1190 in->unique, opname(in->opcode), in->opcode, in->ino,
1191 cmd->buflen);
Miklos Szeredic0938ea2001-11-07 12:35:06 +00001192 fflush(stdout);
1193 }
Miklos Szeredife25def2001-12-20 15:38:05 +00001194
1195 ctx->uid = in->uid;
1196 ctx->gid = in->gid;
Miklos Szeredia181e612001-11-06 12:03:23 +00001197
1198 argsize = cmd->buflen - sizeof(struct fuse_in_header);
1199
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001200 switch (in->opcode) {
Miklos Szeredia181e612001-11-06 12:03:23 +00001201 case FUSE_LOOKUP:
1202 do_lookup(f, in, (char *) inarg);
1203 break;
1204
Miklos Szeredia181e612001-11-06 12:03:23 +00001205 case FUSE_GETATTR:
1206 do_getattr(f, in);
1207 break;
1208
1209 case FUSE_SETATTR:
1210 do_setattr(f, in, (struct fuse_setattr_in *) inarg);
1211 break;
1212
1213 case FUSE_READLINK:
1214 do_readlink(f, in);
1215 break;
1216
1217 case FUSE_GETDIR:
1218 do_getdir(f, in);
1219 break;
1220
1221 case FUSE_MKNOD:
1222 do_mknod(f, in, (struct fuse_mknod_in *) inarg);
1223 break;
1224
1225 case FUSE_MKDIR:
1226 do_mkdir(f, in, (struct fuse_mkdir_in *) inarg);
1227 break;
1228
1229 case FUSE_UNLINK:
Miklos Szeredib5958612004-02-20 14:10:49 +00001230 do_unlink(f, in, (char *) inarg);
1231 break;
1232
Miklos Szeredia181e612001-11-06 12:03:23 +00001233 case FUSE_RMDIR:
Miklos Szeredib5958612004-02-20 14:10:49 +00001234 do_rmdir(f, in, (char *) inarg);
Miklos Szeredia181e612001-11-06 12:03:23 +00001235 break;
1236
1237 case FUSE_SYMLINK:
1238 do_symlink(f, in, (char *) inarg,
1239 ((char *) inarg) + strlen((char *) inarg) + 1);
1240 break;
1241
1242 case FUSE_RENAME:
1243 do_rename(f, in, (struct fuse_rename_in *) inarg);
1244 break;
1245
1246 case FUSE_LINK:
1247 do_link(f, in, (struct fuse_link_in *) inarg);
1248 break;
1249
1250 case FUSE_OPEN:
1251 do_open(f, in, (struct fuse_open_in *) inarg);
1252 break;
1253
Miklos Szeredie2e4ac22004-05-18 08:45:28 +00001254 case FUSE_FLUSH:
1255 do_flush(f, in);
1256 break;
1257
Miklos Szeredi9478e862002-12-11 09:50:26 +00001258 case FUSE_RELEASE:
1259 do_release(f, in, (struct fuse_open_in *) inarg);
1260 break;
1261
Miklos Szeredia181e612001-11-06 12:03:23 +00001262 case FUSE_READ:
1263 do_read(f, in, (struct fuse_read_in *) inarg);
1264 break;
1265
1266 case FUSE_WRITE:
1267 do_write(f, in, (struct fuse_write_in *) inarg);
1268 break;
1269
Mark Glinesd84b39a2002-01-07 16:32:02 +00001270 case FUSE_STATFS:
1271 do_statfs(f, in);
1272 break;
1273
Miklos Szeredi5e43f2c2003-12-12 14:06:41 +00001274 case FUSE_FSYNC:
1275 do_fsync(f, in, (struct fuse_fsync_in *) inarg);
1276 break;
1277
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001278 case FUSE_SETXATTR:
1279 do_setxattr(f, in, (struct fuse_setxattr_in *) inarg);
1280 break;
1281
1282 case FUSE_GETXATTR:
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001283 do_getxattr(f, in, (struct fuse_getxattr_in *) inarg);
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001284 break;
1285
1286 case FUSE_LISTXATTR:
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001287 do_listxattr(f, in, (struct fuse_getxattr_in *) inarg);
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001288 break;
1289
1290 case FUSE_REMOVEXATTR:
1291 do_removexattr(f, in, (char *) inarg);
1292 break;
1293
Miklos Szeredia181e612001-11-06 12:03:23 +00001294 default:
Miklos Szeredi43696432001-11-18 19:15:05 +00001295 send_reply(f, in, -ENOSYS, NULL, 0);
Miklos Szeredia181e612001-11-06 12:03:23 +00001296 }
Miklos Szeredi43696432001-11-18 19:15:05 +00001297
1298 free_cmd(cmd);
Miklos Szeredia181e612001-11-06 12:03:23 +00001299}
1300
Miklos Szeredifff56ab2001-11-16 10:12:59 +00001301struct fuse_cmd *__fuse_read_cmd(struct fuse *f)
Miklos Szeredi2df1c042001-11-06 15:07:17 +00001302{
Miklos Szeredifff56ab2001-11-16 10:12:59 +00001303 ssize_t res;
Miklos Szeredifff56ab2001-11-16 10:12:59 +00001304 struct fuse_cmd *cmd;
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +00001305 struct fuse_in_header *in;
1306 void *inarg;
Miklos Szeredifff56ab2001-11-16 10:12:59 +00001307
Miklos Szeredi43696432001-11-18 19:15:05 +00001308 cmd = (struct fuse_cmd *) malloc(sizeof(struct fuse_cmd));
1309 cmd->buf = (char *) malloc(FUSE_MAX_IN);
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +00001310 in = (struct fuse_in_header *) cmd->buf;
1311 inarg = cmd->buf + sizeof(struct fuse_in_header);
Miklos Szeredi43696432001-11-18 19:15:05 +00001312
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +00001313 do {
1314 res = read(f->fd, cmd->buf, FUSE_MAX_IN);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001315 if (res == -1) {
Miklos Szeredi0f48a262002-12-05 14:23:01 +00001316 free_cmd(cmd);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001317 if (f->exited || errno == EINTR)
Miklos Szeredi0f48a262002-12-05 14:23:01 +00001318 return NULL;
1319
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +00001320 /* ENODEV means we got unmounted, so we silenty return failure */
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001321 if (errno != ENODEV) {
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +00001322 /* BAD... This will happen again */
Miklos Szeredi0f48a262002-12-05 14:23:01 +00001323 perror("fuse: reading device");
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +00001324 }
Miklos Szeredi0f48a262002-12-05 14:23:01 +00001325
1326 fuse_exit(f);
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +00001327 return NULL;
Miklos Szeredi96249982001-11-21 12:21:19 +00001328 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001329 if ((size_t) res < sizeof(struct fuse_in_header)) {
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +00001330 free_cmd(cmd);
Miklos Szeredi0f48a262002-12-05 14:23:01 +00001331 /* Cannot happen */
1332 fprintf(stderr, "short read on fuse device\n");
1333 fuse_exit(f);
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +00001334 return NULL;
1335 }
1336 cmd->buflen = res;
1337
1338 /* Forget is special, it can be done without messing with threads. */
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001339 if (in->opcode == FUSE_FORGET)
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +00001340 do_forget(f, in, (struct fuse_forget_in *) inarg);
1341
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001342 } while (in->opcode == FUSE_FORGET);
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +00001343
Miklos Szeredifff56ab2001-11-16 10:12:59 +00001344 return cmd;
Miklos Szeredi2df1c042001-11-06 15:07:17 +00001345}
1346
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001347void fuse_loop(struct fuse *f)
1348{
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001349 if (f == NULL)
Miklos Szeredic40748a2004-02-20 16:38:45 +00001350 return;
1351
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001352 while (1) {
Miklos Szeredi0f48a262002-12-05 14:23:01 +00001353 struct fuse_cmd *cmd;
1354
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001355 if (f->exited)
Miklos Szeredi0f48a262002-12-05 14:23:01 +00001356 return;
1357
1358 cmd = __fuse_read_cmd(f);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001359 if (cmd == NULL)
Miklos Szeredi0f48a262002-12-05 14:23:01 +00001360 continue;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001361
Miklos Szeredifff56ab2001-11-16 10:12:59 +00001362 __fuse_process_cmd(f, cmd);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001363 }
1364}
1365
Miklos Szeredi0f48a262002-12-05 14:23:01 +00001366void fuse_exit(struct fuse *f)
1367{
1368 f->exited = 1;
1369}
1370
Miklos Szeredi2e50d432001-12-20 12:17:25 +00001371struct fuse_context *fuse_get_context(struct fuse *f)
1372{
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001373 if (f->getcontext)
Miklos Szeredi2e50d432001-12-20 12:17:25 +00001374 return f->getcontext(f);
1375 else
1376 return &f->context;
1377}
1378
Miklos Szeredic40748a2004-02-20 16:38:45 +00001379static int check_version(struct fuse *f)
1380{
1381 int res;
1382 FILE *vf = fopen(FUSE_VERSION_FILE, "r");
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001383 if (vf == NULL) {
Miklos Szeredic40748a2004-02-20 16:38:45 +00001384 fprintf(stderr, "fuse: kernel interface too old, need >= %i.%i\n",
1385 FUSE_KERNEL_VERSION, FUSE_KERNEL_MINOR_VERSION);
1386 return -1;
1387 }
1388 res = fscanf(vf, "%i.%i", &f->majorver, &f->minorver);
1389 fclose(vf);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001390 if (res != 2) {
Miklos Szeredic40748a2004-02-20 16:38:45 +00001391 fprintf(stderr, "fuse: error reading %s\n", FUSE_VERSION_FILE);
1392 return -1;
1393 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001394 if (f->majorver != FUSE_KERNEL_VERSION) {
Miklos Szeredic40748a2004-02-20 16:38:45 +00001395 fprintf(stderr, "fuse: bad kernel interface major version: needs %i\n",
1396 FUSE_KERNEL_VERSION);
1397 return -1;
1398 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001399 if (f->minorver < FUSE_KERNEL_MINOR_VERSION) {
Miklos Szeredic40748a2004-02-20 16:38:45 +00001400 fprintf(stderr, "fuse: kernel interface too old: need >= %i.%i",
1401 FUSE_KERNEL_VERSION, FUSE_KERNEL_MINOR_VERSION);
1402 return -1;
1403 }
1404
1405 return 0;
1406}
1407
Miklos Szeredi2e50d432001-12-20 12:17:25 +00001408struct fuse *fuse_new(int fd, int flags, const struct fuse_operations *op)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001409{
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001410 struct fuse *f;
1411 struct node *root;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001412
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001413 f = (struct fuse *) calloc(1, sizeof(struct fuse));
Miklos Szeredi2df1c042001-11-06 15:07:17 +00001414
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001415 if (check_version(f) == -1) {
Miklos Szeredic40748a2004-02-20 16:38:45 +00001416 free(f);
1417 return NULL;
1418 }
1419
Miklos Szeredia181e612001-11-06 12:03:23 +00001420 f->flags = flags;
Miklos Szeredi8cffdb92001-11-09 14:49:18 +00001421 f->fd = fd;
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001422 f->ctr = 0;
Miklos Szeredi76f65782004-02-19 16:55:40 +00001423 f->generation = 0;
Miklos Szeredifff56ab2001-11-16 10:12:59 +00001424 /* FIXME: Dynamic hash table */
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001425 f->name_table_size = 14057;
1426 f->name_table = (struct node **)
1427 calloc(1, sizeof(struct node *) * f->name_table_size);
1428 f->ino_table_size = 14057;
1429 f->ino_table = (struct node **)
1430 calloc(1, sizeof(struct node *) * f->ino_table_size);
Miklos Szeredia181e612001-11-06 12:03:23 +00001431 pthread_mutex_init(&f->lock, NULL);
Miklos Szeredi33232032001-11-19 17:55:51 +00001432 f->numworker = 0;
1433 f->numavail = 0;
Miklos Szeredi2e50d432001-12-20 12:17:25 +00001434 f->op = *op;
1435 f->getcontext = NULL;
1436 f->context.uid = 0;
1437 f->context.gid = 0;
Miklos Szeredi0f48a262002-12-05 14:23:01 +00001438 f->exited = 0;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001439
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001440 root = (struct node *) calloc(1, sizeof(struct node));
Miklos Szeredi8cffdb92001-11-09 14:49:18 +00001441 root->mode = 0;
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001442 root->rdev = 0;
1443 root->name = strdup("/");
1444 root->parent = 0;
Miklos Szeredi76f65782004-02-19 16:55:40 +00001445 root->ino = FUSE_ROOT_INO;
1446 root->generation = 0;
1447 hash_ino(f, root);
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001448
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001449 return f;
1450}
1451
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001452void fuse_destroy(struct fuse *f)
1453{
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001454 size_t i;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001455 for (i = 0; i < f->ino_table_size; i++) {
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001456 struct node *node;
1457 struct node *next;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001458 for (node = f->ino_table[i]; node != NULL; node = next) {
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001459 next = node->ino_next;
1460 free_node(node);
1461 }
1462 }
1463 free(f->ino_table);
1464 free(f->name_table);
Miklos Szeredia181e612001-11-06 12:03:23 +00001465 pthread_mutex_destroy(&f->lock);
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001466 free(f);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001467}