blob: fe392f3eeed547e70a751dd7b88bf09c8efc6fcb [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 Szeredib3210582004-06-23 13:54:33 +0000868 if (f->op.release) {
869 char *path;
Miklos Szeredic8ba2372002-12-10 12:26:00 +0000870
Miklos Szeredib3210582004-06-23 13:54:33 +0000871 path = get_path(f, in->ino);
872 if (path != NULL) {
873 f->op.release(path, arg->flags);
874 free(path);
875 }
Miklos Szeredic8ba2372002-12-10 12:26:00 +0000876 }
Miklos Szeredic8ba2372002-12-10 12:26:00 +0000877}
878
Miklos Szeredi5e183482001-10-31 14:52:35 +0000879static void do_read(struct fuse *f, struct fuse_in_header *in,
880 struct fuse_read_in *arg)
881{
882 int res;
883 char *path;
Miklos Szeredi43696432001-11-18 19:15:05 +0000884 char *outbuf = (char *) malloc(sizeof(struct fuse_out_header) + arg->size);
885 struct fuse_out_header *out = (struct fuse_out_header *) outbuf;
886 char *buf = outbuf + sizeof(struct fuse_out_header);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000887 size_t size;
Miklos Szeredi43696432001-11-18 19:15:05 +0000888 size_t outsize;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000889
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000890 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000891 path = get_path(f, in->ino);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000892 if (path != NULL) {
893 if (f->flags & FUSE_DEBUG) {
Miklos Szeredi6ebe2342002-01-06 21:44:16 +0000894 printf("READ %u bytes from %llu\n", arg->size, arg->offset);
895 fflush(stdout);
896 }
897
Miklos Szeredi5e183482001-10-31 14:52:35 +0000898 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000899 if (f->op.read)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000900 res = f->op.read(path, buf, arg->size, arg->offset);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000901 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000902 }
903
904 size = 0;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000905 if (res > 0) {
Miklos Szeredi5e183482001-10-31 14:52:35 +0000906 size = res;
907 res = 0;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000908 if (f->flags & FUSE_DEBUG) {
Miklos Szeredi6ebe2342002-01-06 21:44:16 +0000909 printf(" READ %u bytes\n", size);
910 fflush(stdout);
911 }
Miklos Szeredi5e183482001-10-31 14:52:35 +0000912 }
Miklos Szeredi0f48a262002-12-05 14:23:01 +0000913 memset(out, 0, sizeof(struct fuse_out_header));
Miklos Szeredi43696432001-11-18 19:15:05 +0000914 out->unique = in->unique;
915 out->error = res;
916 outsize = sizeof(struct fuse_out_header) + size;
917
918 send_reply_raw(f, outbuf, outsize);
919 free(outbuf);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000920}
Miklos Szeredib483c932001-10-29 14:57:57 +0000921
Miklos Szeredia181e612001-11-06 12:03:23 +0000922static void do_write(struct fuse *f, struct fuse_in_header *in,
923 struct fuse_write_in *arg)
924{
925 int res;
926 char *path;
Miklos Szeredia181e612001-11-06 12:03:23 +0000927
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000928 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000929 path = get_path(f, in->ino);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000930 if (path != NULL) {
931 if (f->flags & FUSE_DEBUG) {
Miklos Szeredi6ebe2342002-01-06 21:44:16 +0000932 printf("WRITE %u bytes to %llu\n", arg->size, arg->offset);
933 fflush(stdout);
934 }
935
Miklos Szeredia181e612001-11-06 12:03:23 +0000936 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000937 if (f->op.write)
Miklos Szeredi6bf8b682002-10-28 08:49:39 +0000938 res = f->op.write(path, PARAM(arg), arg->size, arg->offset);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000939 free(path);
Miklos Szeredia181e612001-11-06 12:03:23 +0000940 }
941
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000942 if (res > 0) {
943 if ((size_t) res != arg->size) {
Miklos Szeredia181e612001-11-06 12:03:23 +0000944 fprintf(stderr, "short write: %u (should be %u)\n", res,
945 arg->size);
Miklos Szeredi0e535082003-10-13 10:08:06 +0000946 res = -EINVAL;
Miklos Szeredia181e612001-11-06 12:03:23 +0000947 }
948 else
949 res = 0;
950 }
951
952 send_reply(f, in, res, NULL, 0);
953}
954
Miklos Szeredi77f39942004-03-25 11:17:52 +0000955static int default_statfs(struct statfs *buf)
956{
957 buf->f_namelen = 255;
958 buf->f_bsize = 512;
959 return 0;
960}
961
Miklos Szeredi18e75e42004-02-19 14:23:27 +0000962static void convert_statfs(struct statfs *statfs, struct fuse_kstatfs *kstatfs)
963{
964 kstatfs->bsize = statfs->f_bsize;
965 kstatfs->blocks = statfs->f_blocks;
966 kstatfs->bfree = statfs->f_bfree;
967 kstatfs->bavail = statfs->f_bavail;
968 kstatfs->files = statfs->f_files;
969 kstatfs->ffree = statfs->f_ffree;
970 kstatfs->namelen = statfs->f_namelen;
971}
972
Mark Glinesd84b39a2002-01-07 16:32:02 +0000973static void do_statfs(struct fuse *f, struct fuse_in_header *in)
974{
975 int res;
Mark Glinesd84b39a2002-01-07 16:32:02 +0000976 struct fuse_statfs_out arg;
Miklos Szeredi18e75e42004-02-19 14:23:27 +0000977 struct statfs buf;
Mark Glinesd84b39a2002-01-07 16:32:02 +0000978
Miklos Szeredi77f39942004-03-25 11:17:52 +0000979 memset(&buf, 0, sizeof(struct statfs));
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000980 if (f->op.statfs)
Miklos Szeredi18e75e42004-02-19 14:23:27 +0000981 res = f->op.statfs("/", &buf);
Miklos Szeredi77f39942004-03-25 11:17:52 +0000982 else
983 res = default_statfs(&buf);
984
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000985 if (res == 0)
Miklos Szeredi77f39942004-03-25 11:17:52 +0000986 convert_statfs(&buf, &arg.st);
Miklos Szeredi4b2bef42002-01-09 12:23:27 +0000987
Mark Glinesd84b39a2002-01-07 16:32:02 +0000988 send_reply(f, in, res, &arg, sizeof(arg));
989}
990
Miklos Szeredi5e43f2c2003-12-12 14:06:41 +0000991static void do_fsync(struct fuse *f, struct fuse_in_header *in,
992 struct fuse_fsync_in *inarg)
993{
994 int res;
995 char *path;
996
997 res = -ENOENT;
998 path = get_path(f, in->ino);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000999 if (path != NULL) {
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001000 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001001 if (f->op.fsync)
Miklos Szeredi5e43f2c2003-12-12 14:06:41 +00001002 res = f->op.fsync(path, inarg->datasync);
1003 free(path);
1004 }
1005 send_reply(f, in, res, NULL, 0);
1006}
1007
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001008static void do_setxattr(struct fuse *f, struct fuse_in_header *in,
1009 struct fuse_setxattr_in *arg)
1010{
1011 int res;
1012 char *path;
1013 char *name = PARAM(arg);
1014 unsigned char *value = name + strlen(name) + 1;
1015
1016 res = -ENOENT;
1017 path = get_path(f, in->ino);
1018 if (path != NULL) {
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001019 res = -ENOSYS;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001020 if (f->op.setxattr)
1021 res = f->op.setxattr(path, name, value, arg->size, arg->flags);
1022 free(path);
1023 }
1024 send_reply(f, in, res, NULL, 0);
1025}
1026
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001027static int common_getxattr(struct fuse *f, struct fuse_in_header *in,
1028 const char *name, char *value, size_t size)
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001029{
1030 int res;
1031 char *path;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001032
1033 res = -ENOENT;
1034 path = get_path(f, in->ino);
1035 if (path != NULL) {
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001036 res = -ENOSYS;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001037 if (f->op.getxattr)
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001038 res = f->op.getxattr(path, name, value, size);
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001039 free(path);
1040 }
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001041 return res;
1042}
1043
1044static void do_getxattr_read(struct fuse *f, struct fuse_in_header *in,
1045 const char *name, size_t size)
1046{
1047 int res;
1048 char *outbuf = (char *) malloc(sizeof(struct fuse_out_header) + size);
1049 struct fuse_out_header *out = (struct fuse_out_header *) outbuf;
1050 char *value = outbuf + sizeof(struct fuse_out_header);
1051
1052 res = common_getxattr(f, in, name, value, size);
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001053 size = 0;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001054 if (res > 0) {
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001055 size = res;
1056 res = 0;
1057 }
1058 memset(out, 0, sizeof(struct fuse_out_header));
1059 out->unique = in->unique;
1060 out->error = res;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001061
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001062 send_reply_raw(f, outbuf, sizeof(struct fuse_out_header) + size);
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001063 free(outbuf);
1064}
1065
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001066static void do_getxattr_size(struct fuse *f, struct fuse_in_header *in,
1067 const char *name)
1068{
1069 int res;
1070 struct fuse_getxattr_out arg;
1071
1072 res = common_getxattr(f, in, name, NULL, 0);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001073 if (res >= 0) {
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001074 arg.size = res;
1075 res = 0;
1076 }
1077 send_reply(f, in, res, &arg, sizeof(arg));
1078}
1079
1080static void do_getxattr(struct fuse *f, struct fuse_in_header *in,
1081 struct fuse_getxattr_in *arg)
1082{
1083 char *name = PARAM(arg);
1084
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001085 if (arg->size)
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001086 do_getxattr_read(f, in, name, arg->size);
1087 else
1088 do_getxattr_size(f, in, name);
1089}
1090
1091static int common_listxattr(struct fuse *f, struct fuse_in_header *in,
1092 char *list, size_t size)
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001093{
1094 int res;
1095 char *path;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001096
1097 res = -ENOENT;
1098 path = get_path(f, in->ino);
1099 if (path != NULL) {
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001100 res = -ENOSYS;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001101 if (f->op.listxattr)
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001102 res = f->op.listxattr(path, list, size);
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001103 free(path);
1104 }
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001105 return res;
1106}
1107
1108static void do_listxattr_read(struct fuse *f, struct fuse_in_header *in,
1109 size_t size)
1110{
1111 int res;
1112 char *outbuf = (char *) malloc(sizeof(struct fuse_out_header) + size);
1113 struct fuse_out_header *out = (struct fuse_out_header *) outbuf;
1114 char *list = outbuf + sizeof(struct fuse_out_header);
1115
1116 res = common_listxattr(f, in, list, size);
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001117 size = 0;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001118 if (res > 0) {
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001119 size = res;
1120 res = 0;
1121 }
1122 memset(out, 0, sizeof(struct fuse_out_header));
1123 out->unique = in->unique;
1124 out->error = res;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001125
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001126 send_reply_raw(f, outbuf, sizeof(struct fuse_out_header) + size);
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001127 free(outbuf);
1128}
1129
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001130static void do_listxattr_size(struct fuse *f, struct fuse_in_header *in)
1131{
1132 int res;
1133 struct fuse_getxattr_out arg;
1134
1135 res = common_listxattr(f, in, NULL, 0);
1136 if (res >= 0) {
1137 arg.size = res;
1138 res = 0;
1139 }
1140 send_reply(f, in, res, &arg, sizeof(arg));
1141}
1142
1143static void do_listxattr(struct fuse *f, struct fuse_in_header *in,
1144 struct fuse_getxattr_in *arg)
1145{
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001146 if (arg->size)
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001147 do_listxattr_read(f, in, arg->size);
1148 else
1149 do_listxattr_size(f, in);
1150}
1151
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001152static void do_removexattr(struct fuse *f, struct fuse_in_header *in,
1153 char *name)
1154{
1155 int res;
1156 char *path;
1157
1158 res = -ENOENT;
1159 path = get_path(f, in->ino);
1160 if (path != NULL) {
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001161 res = -ENOSYS;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001162 if (f->op.removexattr)
1163 res = f->op.removexattr(path, name);
1164 free(path);
1165 }
1166 send_reply(f, in, res, NULL, 0);
1167}
1168
1169
Miklos Szeredi43696432001-11-18 19:15:05 +00001170static void free_cmd(struct fuse_cmd *cmd)
1171{
1172 free(cmd->buf);
1173 free(cmd);
1174}
1175
Miklos Szeredifff56ab2001-11-16 10:12:59 +00001176void __fuse_process_cmd(struct fuse *f, struct fuse_cmd *cmd)
Miklos Szeredia181e612001-11-06 12:03:23 +00001177{
Miklos Szeredia181e612001-11-06 12:03:23 +00001178 struct fuse_in_header *in = (struct fuse_in_header *) cmd->buf;
1179 void *inarg = cmd->buf + sizeof(struct fuse_in_header);
1180 size_t argsize;
Miklos Szeredife25def2001-12-20 15:38:05 +00001181 struct fuse_context *ctx = fuse_get_context(f);
Miklos Szeredia181e612001-11-06 12:03:23 +00001182
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +00001183 dec_avail(f);
Miklos Szeredi33232032001-11-19 17:55:51 +00001184
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001185 if ((f->flags & FUSE_DEBUG)) {
Miklos Szeredic8ba2372002-12-10 12:26:00 +00001186 printf("unique: %i, opcode: %s (%i), ino: %li, insize: %i\n",
1187 in->unique, opname(in->opcode), in->opcode, in->ino,
1188 cmd->buflen);
Miklos Szeredic0938ea2001-11-07 12:35:06 +00001189 fflush(stdout);
1190 }
Miklos Szeredife25def2001-12-20 15:38:05 +00001191
1192 ctx->uid = in->uid;
1193 ctx->gid = in->gid;
Miklos Szeredia181e612001-11-06 12:03:23 +00001194
1195 argsize = cmd->buflen - sizeof(struct fuse_in_header);
1196
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001197 switch (in->opcode) {
Miklos Szeredia181e612001-11-06 12:03:23 +00001198 case FUSE_LOOKUP:
1199 do_lookup(f, in, (char *) inarg);
1200 break;
1201
Miklos Szeredia181e612001-11-06 12:03:23 +00001202 case FUSE_GETATTR:
1203 do_getattr(f, in);
1204 break;
1205
1206 case FUSE_SETATTR:
1207 do_setattr(f, in, (struct fuse_setattr_in *) inarg);
1208 break;
1209
1210 case FUSE_READLINK:
1211 do_readlink(f, in);
1212 break;
1213
1214 case FUSE_GETDIR:
1215 do_getdir(f, in);
1216 break;
1217
1218 case FUSE_MKNOD:
1219 do_mknod(f, in, (struct fuse_mknod_in *) inarg);
1220 break;
1221
1222 case FUSE_MKDIR:
1223 do_mkdir(f, in, (struct fuse_mkdir_in *) inarg);
1224 break;
1225
1226 case FUSE_UNLINK:
Miklos Szeredib5958612004-02-20 14:10:49 +00001227 do_unlink(f, in, (char *) inarg);
1228 break;
1229
Miklos Szeredia181e612001-11-06 12:03:23 +00001230 case FUSE_RMDIR:
Miklos Szeredib5958612004-02-20 14:10:49 +00001231 do_rmdir(f, in, (char *) inarg);
Miklos Szeredia181e612001-11-06 12:03:23 +00001232 break;
1233
1234 case FUSE_SYMLINK:
1235 do_symlink(f, in, (char *) inarg,
1236 ((char *) inarg) + strlen((char *) inarg) + 1);
1237 break;
1238
1239 case FUSE_RENAME:
1240 do_rename(f, in, (struct fuse_rename_in *) inarg);
1241 break;
1242
1243 case FUSE_LINK:
1244 do_link(f, in, (struct fuse_link_in *) inarg);
1245 break;
1246
1247 case FUSE_OPEN:
1248 do_open(f, in, (struct fuse_open_in *) inarg);
1249 break;
1250
Miklos Szeredie2e4ac22004-05-18 08:45:28 +00001251 case FUSE_FLUSH:
1252 do_flush(f, in);
1253 break;
1254
Miklos Szeredi9478e862002-12-11 09:50:26 +00001255 case FUSE_RELEASE:
1256 do_release(f, in, (struct fuse_open_in *) inarg);
1257 break;
1258
Miklos Szeredia181e612001-11-06 12:03:23 +00001259 case FUSE_READ:
1260 do_read(f, in, (struct fuse_read_in *) inarg);
1261 break;
1262
1263 case FUSE_WRITE:
1264 do_write(f, in, (struct fuse_write_in *) inarg);
1265 break;
1266
Mark Glinesd84b39a2002-01-07 16:32:02 +00001267 case FUSE_STATFS:
1268 do_statfs(f, in);
1269 break;
1270
Miklos Szeredi5e43f2c2003-12-12 14:06:41 +00001271 case FUSE_FSYNC:
1272 do_fsync(f, in, (struct fuse_fsync_in *) inarg);
1273 break;
1274
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001275 case FUSE_SETXATTR:
1276 do_setxattr(f, in, (struct fuse_setxattr_in *) inarg);
1277 break;
1278
1279 case FUSE_GETXATTR:
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001280 do_getxattr(f, in, (struct fuse_getxattr_in *) inarg);
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001281 break;
1282
1283 case FUSE_LISTXATTR:
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001284 do_listxattr(f, in, (struct fuse_getxattr_in *) inarg);
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001285 break;
1286
1287 case FUSE_REMOVEXATTR:
1288 do_removexattr(f, in, (char *) inarg);
1289 break;
1290
Miklos Szeredia181e612001-11-06 12:03:23 +00001291 default:
Miklos Szeredi43696432001-11-18 19:15:05 +00001292 send_reply(f, in, -ENOSYS, NULL, 0);
Miklos Szeredia181e612001-11-06 12:03:23 +00001293 }
Miklos Szeredi43696432001-11-18 19:15:05 +00001294
1295 free_cmd(cmd);
Miklos Szeredia181e612001-11-06 12:03:23 +00001296}
1297
Miklos Szeredifff56ab2001-11-16 10:12:59 +00001298struct fuse_cmd *__fuse_read_cmd(struct fuse *f)
Miklos Szeredi2df1c042001-11-06 15:07:17 +00001299{
Miklos Szeredifff56ab2001-11-16 10:12:59 +00001300 ssize_t res;
Miklos Szeredifff56ab2001-11-16 10:12:59 +00001301 struct fuse_cmd *cmd;
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +00001302 struct fuse_in_header *in;
1303 void *inarg;
Miklos Szeredifff56ab2001-11-16 10:12:59 +00001304
Miklos Szeredi43696432001-11-18 19:15:05 +00001305 cmd = (struct fuse_cmd *) malloc(sizeof(struct fuse_cmd));
1306 cmd->buf = (char *) malloc(FUSE_MAX_IN);
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +00001307 in = (struct fuse_in_header *) cmd->buf;
1308 inarg = cmd->buf + sizeof(struct fuse_in_header);
Miklos Szeredi43696432001-11-18 19:15:05 +00001309
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +00001310 do {
1311 res = read(f->fd, cmd->buf, FUSE_MAX_IN);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001312 if (res == -1) {
Miklos Szeredi0f48a262002-12-05 14:23:01 +00001313 free_cmd(cmd);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001314 if (f->exited || errno == EINTR)
Miklos Szeredi0f48a262002-12-05 14:23:01 +00001315 return NULL;
1316
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +00001317 /* ENODEV means we got unmounted, so we silenty return failure */
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001318 if (errno != ENODEV) {
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +00001319 /* BAD... This will happen again */
Miklos Szeredi0f48a262002-12-05 14:23:01 +00001320 perror("fuse: reading device");
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +00001321 }
Miklos Szeredi0f48a262002-12-05 14:23:01 +00001322
1323 fuse_exit(f);
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +00001324 return NULL;
Miklos Szeredi96249982001-11-21 12:21:19 +00001325 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001326 if ((size_t) res < sizeof(struct fuse_in_header)) {
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +00001327 free_cmd(cmd);
Miklos Szeredi0f48a262002-12-05 14:23:01 +00001328 /* Cannot happen */
1329 fprintf(stderr, "short read on fuse device\n");
1330 fuse_exit(f);
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +00001331 return NULL;
1332 }
1333 cmd->buflen = res;
1334
1335 /* Forget is special, it can be done without messing with threads. */
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001336 if (in->opcode == FUSE_FORGET)
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +00001337 do_forget(f, in, (struct fuse_forget_in *) inarg);
1338
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001339 } while (in->opcode == FUSE_FORGET);
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +00001340
Miklos Szeredifff56ab2001-11-16 10:12:59 +00001341 return cmd;
Miklos Szeredi2df1c042001-11-06 15:07:17 +00001342}
1343
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001344void fuse_loop(struct fuse *f)
1345{
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001346 if (f == NULL)
Miklos Szeredic40748a2004-02-20 16:38:45 +00001347 return;
1348
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001349 while (1) {
Miklos Szeredi0f48a262002-12-05 14:23:01 +00001350 struct fuse_cmd *cmd;
1351
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001352 if (f->exited)
Miklos Szeredi0f48a262002-12-05 14:23:01 +00001353 return;
1354
1355 cmd = __fuse_read_cmd(f);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001356 if (cmd == NULL)
Miklos Szeredi0f48a262002-12-05 14:23:01 +00001357 continue;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001358
Miklos Szeredifff56ab2001-11-16 10:12:59 +00001359 __fuse_process_cmd(f, cmd);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001360 }
1361}
1362
Miklos Szeredi0f48a262002-12-05 14:23:01 +00001363void fuse_exit(struct fuse *f)
1364{
1365 f->exited = 1;
1366}
1367
Miklos Szeredi2e50d432001-12-20 12:17:25 +00001368struct fuse_context *fuse_get_context(struct fuse *f)
1369{
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001370 if (f->getcontext)
Miklos Szeredi2e50d432001-12-20 12:17:25 +00001371 return f->getcontext(f);
1372 else
1373 return &f->context;
1374}
1375
Miklos Szeredic40748a2004-02-20 16:38:45 +00001376static int check_version(struct fuse *f)
1377{
1378 int res;
1379 FILE *vf = fopen(FUSE_VERSION_FILE, "r");
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001380 if (vf == NULL) {
Miklos Szeredic40748a2004-02-20 16:38:45 +00001381 fprintf(stderr, "fuse: kernel interface too old, need >= %i.%i\n",
1382 FUSE_KERNEL_VERSION, FUSE_KERNEL_MINOR_VERSION);
1383 return -1;
1384 }
1385 res = fscanf(vf, "%i.%i", &f->majorver, &f->minorver);
1386 fclose(vf);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001387 if (res != 2) {
Miklos Szeredic40748a2004-02-20 16:38:45 +00001388 fprintf(stderr, "fuse: error reading %s\n", FUSE_VERSION_FILE);
1389 return -1;
1390 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001391 if (f->majorver != FUSE_KERNEL_VERSION) {
Miklos Szeredic40748a2004-02-20 16:38:45 +00001392 fprintf(stderr, "fuse: bad kernel interface major version: needs %i\n",
1393 FUSE_KERNEL_VERSION);
1394 return -1;
1395 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001396 if (f->minorver < FUSE_KERNEL_MINOR_VERSION) {
Miklos Szeredic40748a2004-02-20 16:38:45 +00001397 fprintf(stderr, "fuse: kernel interface too old: need >= %i.%i",
1398 FUSE_KERNEL_VERSION, FUSE_KERNEL_MINOR_VERSION);
1399 return -1;
1400 }
1401
1402 return 0;
1403}
1404
Miklos Szeredi2e50d432001-12-20 12:17:25 +00001405struct fuse *fuse_new(int fd, int flags, const struct fuse_operations *op)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001406{
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001407 struct fuse *f;
1408 struct node *root;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001409
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001410 f = (struct fuse *) calloc(1, sizeof(struct fuse));
Miklos Szeredi2df1c042001-11-06 15:07:17 +00001411
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001412 if (check_version(f) == -1) {
Miklos Szeredic40748a2004-02-20 16:38:45 +00001413 free(f);
1414 return NULL;
1415 }
1416
Miklos Szeredia181e612001-11-06 12:03:23 +00001417 f->flags = flags;
Miklos Szeredi8cffdb92001-11-09 14:49:18 +00001418 f->fd = fd;
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001419 f->ctr = 0;
Miklos Szeredi76f65782004-02-19 16:55:40 +00001420 f->generation = 0;
Miklos Szeredifff56ab2001-11-16 10:12:59 +00001421 /* FIXME: Dynamic hash table */
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001422 f->name_table_size = 14057;
1423 f->name_table = (struct node **)
1424 calloc(1, sizeof(struct node *) * f->name_table_size);
1425 f->ino_table_size = 14057;
1426 f->ino_table = (struct node **)
1427 calloc(1, sizeof(struct node *) * f->ino_table_size);
Miklos Szeredia181e612001-11-06 12:03:23 +00001428 pthread_mutex_init(&f->lock, NULL);
Miklos Szeredi33232032001-11-19 17:55:51 +00001429 f->numworker = 0;
1430 f->numavail = 0;
Miklos Szeredi2e50d432001-12-20 12:17:25 +00001431 f->op = *op;
1432 f->getcontext = NULL;
1433 f->context.uid = 0;
1434 f->context.gid = 0;
Miklos Szeredi0f48a262002-12-05 14:23:01 +00001435 f->exited = 0;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001436
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001437 root = (struct node *) calloc(1, sizeof(struct node));
Miklos Szeredi8cffdb92001-11-09 14:49:18 +00001438 root->mode = 0;
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001439 root->rdev = 0;
1440 root->name = strdup("/");
1441 root->parent = 0;
Miklos Szeredi76f65782004-02-19 16:55:40 +00001442 root->ino = FUSE_ROOT_INO;
1443 root->generation = 0;
1444 hash_ino(f, root);
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001445
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001446 return f;
1447}
1448
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001449void fuse_destroy(struct fuse *f)
1450{
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001451 size_t i;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001452 for (i = 0; i < f->ino_table_size; i++) {
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001453 struct node *node;
1454 struct node *next;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001455 for (node = f->ino_table[i]; node != NULL; node = next) {
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001456 next = node->ino_next;
1457 free_node(node);
1458 }
1459 }
1460 free(f->ino_table);
1461 free(f->name_table);
Miklos Szeredia181e612001-11-06 12:03:23 +00001462 pthread_mutex_destroy(&f->lock);
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001463 free(f);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001464}