Miklos Szeredi | 85c74fc | 2001-10-28 19:44:14 +0000 | [diff] [blame] | 1 | /* |
| 2 | FUSE: Filesystem in Userspace |
| 3 | Copyright (C) 2001 Miklos Szeredi (mszeredi@inf.bme.hu) |
| 4 | |
| 5 | This program can be distributed under the terms of the GNU GPL. |
| 6 | See the file COPYING. |
| 7 | */ |
| 8 | |
| 9 | #include "fuse_i.h" |
| 10 | |
Miklos Szeredi | 0503304 | 2001-11-13 16:11:35 +0000 | [diff] [blame] | 11 | #include <linux/pagemap.h> |
Miklos Szeredi | 85c74fc | 2001-10-28 19:44:14 +0000 | [diff] [blame] | 12 | #include <linux/slab.h> |
Miklos Szeredi | 5e18348 | 2001-10-31 14:52:35 +0000 | [diff] [blame] | 13 | #include <linux/file.h> |
Miklos Szeredi | 85c74fc | 2001-10-28 19:44:14 +0000 | [diff] [blame] | 14 | |
Miklos Szeredi | b483c93 | 2001-10-29 14:57:57 +0000 | [diff] [blame] | 15 | static struct inode_operations fuse_dir_inode_operations; |
| 16 | static struct inode_operations fuse_file_inode_operations; |
| 17 | static struct inode_operations fuse_symlink_inode_operations; |
Miklos Szeredi | b483c93 | 2001-10-29 14:57:57 +0000 | [diff] [blame] | 18 | |
| 19 | static struct file_operations fuse_dir_operations; |
Miklos Szeredi | b483c93 | 2001-10-29 14:57:57 +0000 | [diff] [blame] | 20 | |
Miklos Szeredi | 19dff1b | 2001-10-30 15:06:52 +0000 | [diff] [blame] | 21 | static struct dentry_operations fuse_dentry_opertations; |
Miklos Szeredi | b483c93 | 2001-10-29 14:57:57 +0000 | [diff] [blame] | 22 | |
Miklos Szeredi | f3ea83b | 2001-11-07 14:55:16 +0000 | [diff] [blame] | 23 | /* FIXME: This should be user configurable */ |
| 24 | #define FUSE_REVALIDATE_TIME (1 * HZ) |
Miklos Szeredi | 97c61e9 | 2001-11-07 12:09:43 +0000 | [diff] [blame] | 25 | |
Miklos Szeredi | 85c74fc | 2001-10-28 19:44:14 +0000 | [diff] [blame] | 26 | static void change_attributes(struct inode *inode, struct fuse_attr *attr) |
| 27 | { |
Miklos Szeredi | a181e61 | 2001-11-06 12:03:23 +0000 | [diff] [blame] | 28 | if(S_ISREG(inode->i_mode) && inode->i_size != attr->size) |
| 29 | invalidate_inode_pages(inode); |
| 30 | |
Miklos Szeredi | 5e18348 | 2001-10-31 14:52:35 +0000 | [diff] [blame] | 31 | inode->i_mode = (inode->i_mode & S_IFMT) + (attr->mode & 07777); |
Miklos Szeredi | 85c74fc | 2001-10-28 19:44:14 +0000 | [diff] [blame] | 32 | inode->i_nlink = attr->nlink; |
| 33 | inode->i_uid = attr->uid; |
| 34 | inode->i_gid = attr->gid; |
| 35 | inode->i_size = attr->size; |
Miklos Szeredi | 0503304 | 2001-11-13 16:11:35 +0000 | [diff] [blame] | 36 | inode->i_blksize = PAGE_CACHE_SIZE; |
Miklos Szeredi | 85c74fc | 2001-10-28 19:44:14 +0000 | [diff] [blame] | 37 | inode->i_blocks = attr->blocks; |
| 38 | inode->i_atime = attr->atime; |
| 39 | inode->i_mtime = attr->mtime; |
| 40 | inode->i_ctime = attr->ctime; |
| 41 | } |
| 42 | |
Miklos Szeredi | a181e61 | 2001-11-06 12:03:23 +0000 | [diff] [blame] | 43 | static void fuse_init_inode(struct inode *inode, struct fuse_attr *attr) |
Miklos Szeredi | 85c74fc | 2001-10-28 19:44:14 +0000 | [diff] [blame] | 44 | { |
Miklos Szeredi | a181e61 | 2001-11-06 12:03:23 +0000 | [diff] [blame] | 45 | inode->i_mode = attr->mode & S_IFMT; |
| 46 | inode->i_size = attr->size; |
Miklos Szeredi | b483c93 | 2001-10-29 14:57:57 +0000 | [diff] [blame] | 47 | if(S_ISREG(inode->i_mode)) { |
| 48 | inode->i_op = &fuse_file_inode_operations; |
Miklos Szeredi | 5e18348 | 2001-10-31 14:52:35 +0000 | [diff] [blame] | 49 | fuse_init_file_inode(inode); |
Miklos Szeredi | b483c93 | 2001-10-29 14:57:57 +0000 | [diff] [blame] | 50 | } |
| 51 | else if(S_ISDIR(inode->i_mode)) { |
| 52 | inode->i_op = &fuse_dir_inode_operations; |
| 53 | inode->i_fop = &fuse_dir_operations; |
| 54 | } |
Miklos Szeredi | 5e18348 | 2001-10-31 14:52:35 +0000 | [diff] [blame] | 55 | else if(S_ISLNK(inode->i_mode)) { |
Miklos Szeredi | b483c93 | 2001-10-29 14:57:57 +0000 | [diff] [blame] | 56 | inode->i_op = &fuse_symlink_inode_operations; |
Miklos Szeredi | 5e18348 | 2001-10-31 14:52:35 +0000 | [diff] [blame] | 57 | } |
Miklos Szeredi | 85c74fc | 2001-10-28 19:44:14 +0000 | [diff] [blame] | 58 | else { |
Miklos Szeredi | a181e61 | 2001-11-06 12:03:23 +0000 | [diff] [blame] | 59 | inode->i_op = &fuse_file_inode_operations; |
| 60 | init_special_inode(inode, inode->i_mode, attr->rdev); |
Miklos Szeredi | 85c74fc | 2001-10-28 19:44:14 +0000 | [diff] [blame] | 61 | } |
Miklos Szeredi | 5e18348 | 2001-10-31 14:52:35 +0000 | [diff] [blame] | 62 | inode->u.generic_ip = inode; |
| 63 | } |
| 64 | |
| 65 | struct inode *fuse_iget(struct super_block *sb, ino_t ino, |
Miklos Szeredi | a181e61 | 2001-11-06 12:03:23 +0000 | [diff] [blame] | 66 | struct fuse_attr *attr, int version) |
Miklos Szeredi | 5e18348 | 2001-10-31 14:52:35 +0000 | [diff] [blame] | 67 | { |
| 68 | struct inode *inode; |
| 69 | |
| 70 | inode = iget(sb, ino); |
| 71 | if(inode) { |
| 72 | if(!inode->u.generic_ip) |
Miklos Szeredi | a181e61 | 2001-11-06 12:03:23 +0000 | [diff] [blame] | 73 | fuse_init_inode(inode, attr); |
Miklos Szeredi | 5e18348 | 2001-10-31 14:52:35 +0000 | [diff] [blame] | 74 | |
| 75 | change_attributes(inode, attr); |
Miklos Szeredi | a181e61 | 2001-11-06 12:03:23 +0000 | [diff] [blame] | 76 | inode->i_version = version; |
Miklos Szeredi | 5e18348 | 2001-10-31 14:52:35 +0000 | [diff] [blame] | 77 | } |
| 78 | |
| 79 | return inode; |
Miklos Szeredi | 85c74fc | 2001-10-28 19:44:14 +0000 | [diff] [blame] | 80 | } |
| 81 | |
Miklos Szeredi | 4369643 | 2001-11-18 19:15:05 +0000 | [diff] [blame^] | 82 | /* If the inode belongs to an existing directory, then it cannot be |
| 83 | assigned to new dentry */ |
| 84 | static int inode_ok(struct inode *inode) |
| 85 | { |
| 86 | struct dentry *alias; |
| 87 | if(S_ISDIR(inode->i_mode) && (alias = d_find_alias(inode)) != NULL) { |
| 88 | dput(alias); |
| 89 | printk("fuse: cannot assign an existing directory\n"); |
| 90 | return 0; |
| 91 | |
| 92 | } |
| 93 | return 1; |
| 94 | } |
| 95 | |
Miklos Szeredi | 85c74fc | 2001-10-28 19:44:14 +0000 | [diff] [blame] | 96 | static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry) |
| 97 | { |
Miklos Szeredi | a181e61 | 2001-11-06 12:03:23 +0000 | [diff] [blame] | 98 | int ret; |
Miklos Szeredi | 5e18348 | 2001-10-31 14:52:35 +0000 | [diff] [blame] | 99 | struct fuse_conn *fc = INO_FC(dir); |
Miklos Szeredi | 85c74fc | 2001-10-28 19:44:14 +0000 | [diff] [blame] | 100 | struct fuse_in in = FUSE_IN_INIT; |
| 101 | struct fuse_out out = FUSE_OUT_INIT; |
Miklos Szeredi | 4369643 | 2001-11-18 19:15:05 +0000 | [diff] [blame^] | 102 | struct fuse_lookup_out outarg; |
Miklos Szeredi | 85c74fc | 2001-10-28 19:44:14 +0000 | [diff] [blame] | 103 | struct inode *inode; |
Miklos Szeredi | a181e61 | 2001-11-06 12:03:23 +0000 | [diff] [blame] | 104 | |
Miklos Szeredi | 85c74fc | 2001-10-28 19:44:14 +0000 | [diff] [blame] | 105 | in.h.opcode = FUSE_LOOKUP; |
| 106 | in.h.ino = dir->i_ino; |
Miklos Szeredi | 4369643 | 2001-11-18 19:15:05 +0000 | [diff] [blame^] | 107 | in.numargs = 1; |
| 108 | in.args[0].size = entry->d_name.len + 1; |
| 109 | in.args[0].value = entry->d_name.name; |
| 110 | out.numargs = 1; |
| 111 | out.args[0].size = sizeof(outarg); |
| 112 | out.args[0].value = &outarg; |
Miklos Szeredi | 85c74fc | 2001-10-28 19:44:14 +0000 | [diff] [blame] | 113 | request_send(fc, &in, &out); |
| 114 | |
Miklos Szeredi | 19dff1b | 2001-10-30 15:06:52 +0000 | [diff] [blame] | 115 | inode = NULL; |
| 116 | if(!out.h.error) { |
Miklos Szeredi | a181e61 | 2001-11-06 12:03:23 +0000 | [diff] [blame] | 117 | ret = -ENOMEM; |
Miklos Szeredi | 4369643 | 2001-11-18 19:15:05 +0000 | [diff] [blame^] | 118 | inode = fuse_iget(dir->i_sb, outarg.ino, &outarg.attr, |
| 119 | out.h.unique); |
Miklos Szeredi | 19dff1b | 2001-10-30 15:06:52 +0000 | [diff] [blame] | 120 | if(!inode) |
Miklos Szeredi | a181e61 | 2001-11-06 12:03:23 +0000 | [diff] [blame] | 121 | goto err; |
Miklos Szeredi | 4369643 | 2001-11-18 19:15:05 +0000 | [diff] [blame^] | 122 | |
| 123 | ret = -EPROTO; |
| 124 | if(!inode_ok(inode)) { |
| 125 | iput(inode); |
| 126 | goto err; |
| 127 | } |
Miklos Szeredi | 85c74fc | 2001-10-28 19:44:14 +0000 | [diff] [blame] | 128 | } |
Miklos Szeredi | a181e61 | 2001-11-06 12:03:23 +0000 | [diff] [blame] | 129 | else if(out.h.error != -ENOENT) { |
| 130 | ret = out.h.error; |
| 131 | goto err; |
| 132 | } |
Miklos Szeredi | 85c74fc | 2001-10-28 19:44:14 +0000 | [diff] [blame] | 133 | |
Miklos Szeredi | a181e61 | 2001-11-06 12:03:23 +0000 | [diff] [blame] | 134 | entry->d_time = jiffies; |
Miklos Szeredi | 19dff1b | 2001-10-30 15:06:52 +0000 | [diff] [blame] | 135 | entry->d_op = &fuse_dentry_opertations; |
Miklos Szeredi | 85c74fc | 2001-10-28 19:44:14 +0000 | [diff] [blame] | 136 | d_add(entry, inode); |
Miklos Szeredi | a181e61 | 2001-11-06 12:03:23 +0000 | [diff] [blame] | 137 | |
Miklos Szeredi | 85c74fc | 2001-10-28 19:44:14 +0000 | [diff] [blame] | 138 | return NULL; |
Miklos Szeredi | a181e61 | 2001-11-06 12:03:23 +0000 | [diff] [blame] | 139 | |
| 140 | err: |
| 141 | return ERR_PTR(ret); |
Miklos Szeredi | 85c74fc | 2001-10-28 19:44:14 +0000 | [diff] [blame] | 142 | } |
| 143 | |
Miklos Szeredi | 0a7077f | 2001-11-11 18:20:17 +0000 | [diff] [blame] | 144 | /* create needs to return a positive entry, so this is actually an |
| 145 | mknod+lookup */ |
Miklos Szeredi | 85c74fc | 2001-10-28 19:44:14 +0000 | [diff] [blame] | 146 | static int fuse_mknod(struct inode *dir, struct dentry *entry, int mode, |
| 147 | int rdev) |
| 148 | { |
Miklos Szeredi | 5e18348 | 2001-10-31 14:52:35 +0000 | [diff] [blame] | 149 | struct fuse_conn *fc = INO_FC(dir); |
Miklos Szeredi | 85c74fc | 2001-10-28 19:44:14 +0000 | [diff] [blame] | 150 | struct fuse_in in = FUSE_IN_INIT; |
| 151 | struct fuse_out out = FUSE_OUT_INIT; |
Miklos Szeredi | 4369643 | 2001-11-18 19:15:05 +0000 | [diff] [blame^] | 152 | struct fuse_mknod_in inarg; |
Miklos Szeredi | 85c74fc | 2001-10-28 19:44:14 +0000 | [diff] [blame] | 153 | struct fuse_mknod_out outarg; |
| 154 | struct inode *inode; |
Miklos Szeredi | 4369643 | 2001-11-18 19:15:05 +0000 | [diff] [blame^] | 155 | |
| 156 | memset(&inarg, 0, sizeof(inarg)); |
| 157 | inarg.mode = mode; |
| 158 | inarg.rdev = rdev; |
Miklos Szeredi | 85c74fc | 2001-10-28 19:44:14 +0000 | [diff] [blame] | 159 | |
| 160 | in.h.opcode = FUSE_MKNOD; |
| 161 | in.h.ino = dir->i_ino; |
Miklos Szeredi | 4369643 | 2001-11-18 19:15:05 +0000 | [diff] [blame^] | 162 | in.numargs = 2; |
| 163 | in.args[0].size = sizeof(inarg); |
| 164 | in.args[0].value = &inarg; |
| 165 | in.args[1].size = entry->d_name.len + 1; |
| 166 | in.args[1].value = entry->d_name.name; |
| 167 | out.numargs = 1; |
| 168 | out.args[0].size = sizeof(outarg); |
| 169 | out.args[0].value = &outarg; |
Miklos Szeredi | 85c74fc | 2001-10-28 19:44:14 +0000 | [diff] [blame] | 170 | request_send(fc, &in, &out); |
Miklos Szeredi | b483c93 | 2001-10-29 14:57:57 +0000 | [diff] [blame] | 171 | |
Miklos Szeredi | 19dff1b | 2001-10-30 15:06:52 +0000 | [diff] [blame] | 172 | if(out.h.error) |
| 173 | return out.h.error; |
Miklos Szeredi | 85c74fc | 2001-10-28 19:44:14 +0000 | [diff] [blame] | 174 | |
Miklos Szeredi | a181e61 | 2001-11-06 12:03:23 +0000 | [diff] [blame] | 175 | inode = fuse_iget(dir->i_sb, outarg.ino, &outarg.attr, out.h.unique); |
Miklos Szeredi | 85c74fc | 2001-10-28 19:44:14 +0000 | [diff] [blame] | 176 | if(!inode) |
| 177 | return -ENOMEM; |
Miklos Szeredi | 5e18348 | 2001-10-31 14:52:35 +0000 | [diff] [blame] | 178 | |
Miklos Szeredi | 4369643 | 2001-11-18 19:15:05 +0000 | [diff] [blame^] | 179 | /* Don't allow userspace to do really stupid things... */ |
| 180 | if((inode->i_mode ^ mode) & S_IFMT) { |
| 181 | iput(inode); |
| 182 | printk("fuse_mknod: inode has wrong type\n"); |
| 183 | return -EPROTO; |
| 184 | } |
| 185 | |
| 186 | if(!inode_ok(inode)) { |
| 187 | iput(inode); |
| 188 | return -EPROTO; |
| 189 | } |
| 190 | |
Miklos Szeredi | 19dff1b | 2001-10-30 15:06:52 +0000 | [diff] [blame] | 191 | d_instantiate(entry, inode); |
Miklos Szeredi | 85c74fc | 2001-10-28 19:44:14 +0000 | [diff] [blame] | 192 | return 0; |
| 193 | } |
| 194 | |
Miklos Szeredi | b483c93 | 2001-10-29 14:57:57 +0000 | [diff] [blame] | 195 | |
Miklos Szeredi | 85c74fc | 2001-10-28 19:44:14 +0000 | [diff] [blame] | 196 | static int fuse_create(struct inode *dir, struct dentry *entry, int mode) |
| 197 | { |
| 198 | return fuse_mknod(dir, entry, mode, 0); |
| 199 | } |
| 200 | |
Miklos Szeredi | b483c93 | 2001-10-29 14:57:57 +0000 | [diff] [blame] | 201 | static int fuse_mkdir(struct inode *dir, struct dentry *entry, int mode) |
| 202 | { |
Miklos Szeredi | 5e18348 | 2001-10-31 14:52:35 +0000 | [diff] [blame] | 203 | struct fuse_conn *fc = INO_FC(dir); |
Miklos Szeredi | b483c93 | 2001-10-29 14:57:57 +0000 | [diff] [blame] | 204 | struct fuse_in in = FUSE_IN_INIT; |
| 205 | struct fuse_out out = FUSE_OUT_INIT; |
Miklos Szeredi | 4369643 | 2001-11-18 19:15:05 +0000 | [diff] [blame^] | 206 | struct fuse_mkdir_in inarg; |
| 207 | |
| 208 | memset(&inarg, 0, sizeof(inarg)); |
| 209 | inarg.mode = mode; |
Miklos Szeredi | b483c93 | 2001-10-29 14:57:57 +0000 | [diff] [blame] | 210 | |
| 211 | in.h.opcode = FUSE_MKDIR; |
| 212 | in.h.ino = dir->i_ino; |
Miklos Szeredi | 4369643 | 2001-11-18 19:15:05 +0000 | [diff] [blame^] | 213 | in.numargs = 2; |
| 214 | in.args[0].size = sizeof(inarg); |
| 215 | in.args[0].value = &inarg; |
| 216 | in.args[1].size = entry->d_name.len + 1; |
| 217 | in.args[1].value = entry->d_name.name; |
Miklos Szeredi | b483c93 | 2001-10-29 14:57:57 +0000 | [diff] [blame] | 218 | request_send(fc, &in, &out); |
Miklos Szeredi | b483c93 | 2001-10-29 14:57:57 +0000 | [diff] [blame] | 219 | |
Miklos Szeredi | 19dff1b | 2001-10-30 15:06:52 +0000 | [diff] [blame] | 220 | return out.h.error; |
Miklos Szeredi | b483c93 | 2001-10-29 14:57:57 +0000 | [diff] [blame] | 221 | } |
| 222 | |
| 223 | static int fuse_symlink(struct inode *dir, struct dentry *entry, |
| 224 | const char *link) |
| 225 | { |
Miklos Szeredi | 5e18348 | 2001-10-31 14:52:35 +0000 | [diff] [blame] | 226 | struct fuse_conn *fc = INO_FC(dir); |
Miklos Szeredi | b483c93 | 2001-10-29 14:57:57 +0000 | [diff] [blame] | 227 | struct fuse_in in = FUSE_IN_INIT; |
| 228 | struct fuse_out out = FUSE_OUT_INIT; |
Miklos Szeredi | b483c93 | 2001-10-29 14:57:57 +0000 | [diff] [blame] | 229 | |
| 230 | in.h.opcode = FUSE_SYMLINK; |
| 231 | in.h.ino = dir->i_ino; |
Miklos Szeredi | 4369643 | 2001-11-18 19:15:05 +0000 | [diff] [blame^] | 232 | in.numargs = 2; |
| 233 | in.args[0].size = entry->d_name.len + 1; |
| 234 | in.args[0].value = entry->d_name.name; |
| 235 | in.args[1].size = strlen(link) + 1; |
| 236 | in.args[1].value = link; |
Miklos Szeredi | b483c93 | 2001-10-29 14:57:57 +0000 | [diff] [blame] | 237 | request_send(fc, &in, &out); |
Miklos Szeredi | 4369643 | 2001-11-18 19:15:05 +0000 | [diff] [blame^] | 238 | |
Miklos Szeredi | 19dff1b | 2001-10-30 15:06:52 +0000 | [diff] [blame] | 239 | return out.h.error; |
Miklos Szeredi | b483c93 | 2001-10-29 14:57:57 +0000 | [diff] [blame] | 240 | } |
| 241 | |
| 242 | static int fuse_remove(struct inode *dir, struct dentry *entry, |
| 243 | enum fuse_opcode op) |
| 244 | { |
Miklos Szeredi | 5e18348 | 2001-10-31 14:52:35 +0000 | [diff] [blame] | 245 | struct fuse_conn *fc = INO_FC(dir); |
Miklos Szeredi | b483c93 | 2001-10-29 14:57:57 +0000 | [diff] [blame] | 246 | struct fuse_in in = FUSE_IN_INIT; |
| 247 | struct fuse_out out = FUSE_OUT_INIT; |
| 248 | |
| 249 | in.h.opcode = op; |
| 250 | in.h.ino = dir->i_ino; |
Miklos Szeredi | 4369643 | 2001-11-18 19:15:05 +0000 | [diff] [blame^] | 251 | in.numargs = 1; |
| 252 | in.args[0].size = entry->d_name.len + 1; |
| 253 | in.args[0].value = entry->d_name.name; |
Miklos Szeredi | b483c93 | 2001-10-29 14:57:57 +0000 | [diff] [blame] | 254 | request_send(fc, &in, &out); |
Miklos Szeredi | 4369643 | 2001-11-18 19:15:05 +0000 | [diff] [blame^] | 255 | |
Miklos Szeredi | 19dff1b | 2001-10-30 15:06:52 +0000 | [diff] [blame] | 256 | return out.h.error; |
Miklos Szeredi | b483c93 | 2001-10-29 14:57:57 +0000 | [diff] [blame] | 257 | } |
| 258 | |
| 259 | static int fuse_unlink(struct inode *dir, struct dentry *entry) |
| 260 | { |
| 261 | return fuse_remove(dir, entry, FUSE_UNLINK); |
| 262 | } |
| 263 | |
| 264 | static int fuse_rmdir(struct inode *dir, struct dentry *entry) |
| 265 | { |
| 266 | return fuse_remove(dir, entry, FUSE_RMDIR); |
| 267 | } |
| 268 | |
| 269 | static int fuse_rename(struct inode *olddir, struct dentry *oldent, |
| 270 | struct inode *newdir, struct dentry *newent) |
| 271 | { |
Miklos Szeredi | 5e18348 | 2001-10-31 14:52:35 +0000 | [diff] [blame] | 272 | struct fuse_conn *fc = INO_FC(olddir); |
Miklos Szeredi | b483c93 | 2001-10-29 14:57:57 +0000 | [diff] [blame] | 273 | struct fuse_in in = FUSE_IN_INIT; |
| 274 | struct fuse_out out = FUSE_OUT_INIT; |
Miklos Szeredi | 4369643 | 2001-11-18 19:15:05 +0000 | [diff] [blame^] | 275 | struct fuse_rename_in inarg; |
Miklos Szeredi | b483c93 | 2001-10-29 14:57:57 +0000 | [diff] [blame] | 276 | |
Miklos Szeredi | 4369643 | 2001-11-18 19:15:05 +0000 | [diff] [blame^] | 277 | memset(&inarg, 0, sizeof(inarg)); |
| 278 | inarg.newdir = newdir->i_ino; |
Miklos Szeredi | b483c93 | 2001-10-29 14:57:57 +0000 | [diff] [blame] | 279 | |
| 280 | in.h.opcode = FUSE_RENAME; |
| 281 | in.h.ino = olddir->i_ino; |
Miklos Szeredi | 4369643 | 2001-11-18 19:15:05 +0000 | [diff] [blame^] | 282 | in.numargs = 3; |
| 283 | in.args[0].size = sizeof(inarg); |
| 284 | in.args[0].value = &inarg; |
| 285 | in.args[1].size = oldent->d_name.len + 1; |
| 286 | in.args[1].value = oldent->d_name.name; |
| 287 | in.args[2].size = newent->d_name.len + 1; |
| 288 | in.args[2].value = newent->d_name.name; |
Miklos Szeredi | b483c93 | 2001-10-29 14:57:57 +0000 | [diff] [blame] | 289 | request_send(fc, &in, &out); |
Miklos Szeredi | b483c93 | 2001-10-29 14:57:57 +0000 | [diff] [blame] | 290 | |
Miklos Szeredi | 19dff1b | 2001-10-30 15:06:52 +0000 | [diff] [blame] | 291 | return out.h.error; |
| 292 | } |
| 293 | |
| 294 | static int fuse_link(struct dentry *entry, struct inode *newdir, |
| 295 | struct dentry *newent) |
| 296 | { |
| 297 | struct inode *inode = entry->d_inode; |
Miklos Szeredi | 5e18348 | 2001-10-31 14:52:35 +0000 | [diff] [blame] | 298 | struct fuse_conn *fc = INO_FC(inode); |
Miklos Szeredi | 19dff1b | 2001-10-30 15:06:52 +0000 | [diff] [blame] | 299 | struct fuse_in in = FUSE_IN_INIT; |
| 300 | struct fuse_out out = FUSE_OUT_INIT; |
Miklos Szeredi | 4369643 | 2001-11-18 19:15:05 +0000 | [diff] [blame^] | 301 | struct fuse_link_in inarg; |
Miklos Szeredi | 19dff1b | 2001-10-30 15:06:52 +0000 | [diff] [blame] | 302 | |
Miklos Szeredi | 4369643 | 2001-11-18 19:15:05 +0000 | [diff] [blame^] | 303 | memset(&inarg, 0, sizeof(inarg)); |
| 304 | inarg.newdir = newdir->i_ino; |
Miklos Szeredi | 19dff1b | 2001-10-30 15:06:52 +0000 | [diff] [blame] | 305 | |
| 306 | in.h.opcode = FUSE_LINK; |
| 307 | in.h.ino = inode->i_ino; |
Miklos Szeredi | 4369643 | 2001-11-18 19:15:05 +0000 | [diff] [blame^] | 308 | in.numargs = 2; |
| 309 | in.args[0].size = sizeof(inarg); |
| 310 | in.args[0].value = &inarg; |
| 311 | in.args[1].size = newent->d_name.len + 1; |
| 312 | in.args[1].value = newent->d_name.name; |
Miklos Szeredi | 19dff1b | 2001-10-30 15:06:52 +0000 | [diff] [blame] | 313 | request_send(fc, &in, &out); |
Miklos Szeredi | 19dff1b | 2001-10-30 15:06:52 +0000 | [diff] [blame] | 314 | |
| 315 | return out.h.error; |
Miklos Szeredi | b483c93 | 2001-10-29 14:57:57 +0000 | [diff] [blame] | 316 | } |
| 317 | |
Miklos Szeredi | 85c74fc | 2001-10-28 19:44:14 +0000 | [diff] [blame] | 318 | static int fuse_permission(struct inode *inode, int mask) |
| 319 | { |
Miklos Szeredi | 8cffdb9 | 2001-11-09 14:49:18 +0000 | [diff] [blame] | 320 | struct fuse_conn *fc = INO_FC(inode); |
| 321 | |
Miklos Szeredi | 0a7077f | 2001-11-11 18:20:17 +0000 | [diff] [blame] | 322 | /* (too) simple protection */ |
| 323 | if(current->fsuid == fc->uid) |
| 324 | return 0; |
| 325 | else |
| 326 | return -EACCES; |
Miklos Szeredi | 85c74fc | 2001-10-28 19:44:14 +0000 | [diff] [blame] | 327 | } |
| 328 | |
Miklos Szeredi | a181e61 | 2001-11-06 12:03:23 +0000 | [diff] [blame] | 329 | static int fuse_revalidate(struct dentry *entry) |
Miklos Szeredi | 85c74fc | 2001-10-28 19:44:14 +0000 | [diff] [blame] | 330 | { |
Miklos Szeredi | a181e61 | 2001-11-06 12:03:23 +0000 | [diff] [blame] | 331 | struct inode *inode = entry->d_inode; |
Miklos Szeredi | 5e18348 | 2001-10-31 14:52:35 +0000 | [diff] [blame] | 332 | struct fuse_conn *fc = INO_FC(inode); |
Miklos Szeredi | 85c74fc | 2001-10-28 19:44:14 +0000 | [diff] [blame] | 333 | struct fuse_in in = FUSE_IN_INIT; |
| 334 | struct fuse_out out = FUSE_OUT_INIT; |
| 335 | struct fuse_getattr_out arg; |
| 336 | |
Miklos Szeredi | a181e61 | 2001-11-06 12:03:23 +0000 | [diff] [blame] | 337 | if(inode->i_ino != FUSE_ROOT_INO && |
Miklos Szeredi | 97c61e9 | 2001-11-07 12:09:43 +0000 | [diff] [blame] | 338 | time_before_eq(jiffies, entry->d_time + FUSE_REVALIDATE_TIME)) |
Miklos Szeredi | 19dff1b | 2001-10-30 15:06:52 +0000 | [diff] [blame] | 339 | return 0; |
| 340 | |
Miklos Szeredi | 85c74fc | 2001-10-28 19:44:14 +0000 | [diff] [blame] | 341 | in.h.opcode = FUSE_GETATTR; |
| 342 | in.h.ino = inode->i_ino; |
Miklos Szeredi | 4369643 | 2001-11-18 19:15:05 +0000 | [diff] [blame^] | 343 | out.numargs = 1; |
| 344 | out.args[0].size = sizeof(arg); |
| 345 | out.args[0].value = &arg; |
Miklos Szeredi | 85c74fc | 2001-10-28 19:44:14 +0000 | [diff] [blame] | 346 | request_send(fc, &in, &out); |
| 347 | |
Miklos Szeredi | 19dff1b | 2001-10-30 15:06:52 +0000 | [diff] [blame] | 348 | if(!out.h.error) |
Miklos Szeredi | 85c74fc | 2001-10-28 19:44:14 +0000 | [diff] [blame] | 349 | change_attributes(inode, &arg.attr); |
Miklos Szeredi | 19dff1b | 2001-10-30 15:06:52 +0000 | [diff] [blame] | 350 | |
| 351 | return out.h.error; |
Miklos Szeredi | 85c74fc | 2001-10-28 19:44:14 +0000 | [diff] [blame] | 352 | } |
| 353 | |
Miklos Szeredi | b483c93 | 2001-10-29 14:57:57 +0000 | [diff] [blame] | 354 | static int parse_dirfile(char *buf, size_t nbytes, struct file *file, |
| 355 | void *dstbuf, filldir_t filldir) |
Miklos Szeredi | 85c74fc | 2001-10-28 19:44:14 +0000 | [diff] [blame] | 356 | { |
Miklos Szeredi | 85c74fc | 2001-10-28 19:44:14 +0000 | [diff] [blame] | 357 | while(nbytes >= FUSE_NAME_OFFSET) { |
Miklos Szeredi | b483c93 | 2001-10-29 14:57:57 +0000 | [diff] [blame] | 358 | struct fuse_dirent *dirent = (struct fuse_dirent *) buf; |
Miklos Szeredi | 85c74fc | 2001-10-28 19:44:14 +0000 | [diff] [blame] | 359 | size_t reclen = FUSE_DIRENT_SIZE(dirent); |
| 360 | int over; |
| 361 | if(dirent->namelen > NAME_MAX) { |
| 362 | printk("fuse_readdir: name too long\n"); |
Miklos Szeredi | b483c93 | 2001-10-29 14:57:57 +0000 | [diff] [blame] | 363 | return -EPROTO; |
Miklos Szeredi | 85c74fc | 2001-10-28 19:44:14 +0000 | [diff] [blame] | 364 | } |
| 365 | if(reclen > nbytes) |
| 366 | break; |
| 367 | |
| 368 | over = filldir(dstbuf, dirent->name, dirent->namelen, |
| 369 | file->f_pos, dirent->ino, dirent->type); |
| 370 | if(over) |
| 371 | break; |
| 372 | |
Miklos Szeredi | b483c93 | 2001-10-29 14:57:57 +0000 | [diff] [blame] | 373 | buf += reclen; |
Miklos Szeredi | 85c74fc | 2001-10-28 19:44:14 +0000 | [diff] [blame] | 374 | file->f_pos += reclen; |
| 375 | nbytes -= reclen; |
| 376 | } |
| 377 | |
Miklos Szeredi | b483c93 | 2001-10-29 14:57:57 +0000 | [diff] [blame] | 378 | return 0; |
| 379 | } |
| 380 | |
| 381 | #define DIR_BUFSIZE 2048 |
| 382 | static int fuse_readdir(struct file *file, void *dstbuf, filldir_t filldir) |
| 383 | { |
| 384 | struct file *cfile = file->private_data; |
| 385 | char *buf; |
| 386 | int ret; |
| 387 | |
| 388 | buf = kmalloc(DIR_BUFSIZE, GFP_KERNEL); |
| 389 | if(!buf) |
| 390 | return -ENOMEM; |
| 391 | |
| 392 | ret = kernel_read(cfile, file->f_pos, buf, DIR_BUFSIZE); |
| 393 | if(ret < 0) |
| 394 | printk("fuse_readdir: failed to read container file\n"); |
| 395 | else |
| 396 | ret = parse_dirfile(buf, ret, file, dstbuf, filldir); |
| 397 | |
Miklos Szeredi | 85c74fc | 2001-10-28 19:44:14 +0000 | [diff] [blame] | 398 | kfree(buf); |
| 399 | return ret; |
| 400 | } |
| 401 | |
Miklos Szeredi | 0503304 | 2001-11-13 16:11:35 +0000 | [diff] [blame] | 402 | static char *read_link(struct dentry *dentry) |
Miklos Szeredi | 85c74fc | 2001-10-28 19:44:14 +0000 | [diff] [blame] | 403 | { |
| 404 | struct inode *inode = dentry->d_inode; |
Miklos Szeredi | 5e18348 | 2001-10-31 14:52:35 +0000 | [diff] [blame] | 405 | struct fuse_conn *fc = INO_FC(inode); |
Miklos Szeredi | 85c74fc | 2001-10-28 19:44:14 +0000 | [diff] [blame] | 406 | struct fuse_in in = FUSE_IN_INIT; |
| 407 | struct fuse_out out = FUSE_OUT_INIT; |
Miklos Szeredi | 0503304 | 2001-11-13 16:11:35 +0000 | [diff] [blame] | 408 | char *link; |
Miklos Szeredi | 85c74fc | 2001-10-28 19:44:14 +0000 | [diff] [blame] | 409 | |
Miklos Szeredi | 0503304 | 2001-11-13 16:11:35 +0000 | [diff] [blame] | 410 | link = (char *) __get_free_page(GFP_KERNEL); |
| 411 | if(!link) |
| 412 | return ERR_PTR(-ENOMEM); |
Miklos Szeredi | 85c74fc | 2001-10-28 19:44:14 +0000 | [diff] [blame] | 413 | |
| 414 | in.h.opcode = FUSE_READLINK; |
| 415 | in.h.ino = inode->i_ino; |
Miklos Szeredi | 85c74fc | 2001-10-28 19:44:14 +0000 | [diff] [blame] | 416 | out.argvar = 1; |
Miklos Szeredi | 4369643 | 2001-11-18 19:15:05 +0000 | [diff] [blame^] | 417 | out.numargs = 1; |
| 418 | out.args[0].size = PAGE_SIZE - 1; |
| 419 | out.args[0].value = link; |
Miklos Szeredi | 85c74fc | 2001-10-28 19:44:14 +0000 | [diff] [blame] | 420 | request_send(fc, &in, &out); |
Miklos Szeredi | 19dff1b | 2001-10-30 15:06:52 +0000 | [diff] [blame] | 421 | if(out.h.error) { |
Miklos Szeredi | 0503304 | 2001-11-13 16:11:35 +0000 | [diff] [blame] | 422 | free_page((unsigned long) link); |
| 423 | return ERR_PTR(out.h.error); |
Miklos Szeredi | 85c74fc | 2001-10-28 19:44:14 +0000 | [diff] [blame] | 424 | } |
| 425 | |
Miklos Szeredi | 4369643 | 2001-11-18 19:15:05 +0000 | [diff] [blame^] | 426 | link[out.args[0].size] = '\0'; |
Miklos Szeredi | 0503304 | 2001-11-13 16:11:35 +0000 | [diff] [blame] | 427 | return link; |
Miklos Szeredi | 85c74fc | 2001-10-28 19:44:14 +0000 | [diff] [blame] | 428 | } |
| 429 | |
| 430 | static void free_link(char *link) |
| 431 | { |
Miklos Szeredi | 0503304 | 2001-11-13 16:11:35 +0000 | [diff] [blame] | 432 | if(!IS_ERR(link)) |
| 433 | free_page((unsigned long) link); |
Miklos Szeredi | 85c74fc | 2001-10-28 19:44:14 +0000 | [diff] [blame] | 434 | } |
| 435 | |
| 436 | static int fuse_readlink(struct dentry *dentry, char *buffer, int buflen) |
| 437 | { |
| 438 | int ret; |
| 439 | char *link; |
| 440 | |
Miklos Szeredi | 0503304 | 2001-11-13 16:11:35 +0000 | [diff] [blame] | 441 | link = read_link(dentry); |
Miklos Szeredi | 85c74fc | 2001-10-28 19:44:14 +0000 | [diff] [blame] | 442 | ret = vfs_readlink(dentry, buffer, buflen, link); |
| 443 | free_link(link); |
| 444 | return ret; |
| 445 | } |
| 446 | |
| 447 | static int fuse_follow_link(struct dentry *dentry, struct nameidata *nd) |
| 448 | { |
| 449 | int ret; |
| 450 | char *link; |
| 451 | |
Miklos Szeredi | 0503304 | 2001-11-13 16:11:35 +0000 | [diff] [blame] | 452 | link = read_link(dentry); |
Miklos Szeredi | 85c74fc | 2001-10-28 19:44:14 +0000 | [diff] [blame] | 453 | ret = vfs_follow_link(nd, link); |
| 454 | free_link(link); |
| 455 | return ret; |
| 456 | } |
| 457 | |
| 458 | static int fuse_dir_open(struct inode *inode, struct file *file) |
| 459 | { |
Miklos Szeredi | 5e18348 | 2001-10-31 14:52:35 +0000 | [diff] [blame] | 460 | struct fuse_conn *fc = INO_FC(inode); |
Miklos Szeredi | 85c74fc | 2001-10-28 19:44:14 +0000 | [diff] [blame] | 461 | struct fuse_in in = FUSE_IN_INIT; |
| 462 | struct fuse_out out = FUSE_OUT_INIT; |
| 463 | struct fuse_getdir_out outarg; |
| 464 | |
| 465 | if(!(file->f_flags & O_DIRECTORY)) |
Miklos Szeredi | a181e61 | 2001-11-06 12:03:23 +0000 | [diff] [blame] | 466 | return 0; |
Miklos Szeredi | 85c74fc | 2001-10-28 19:44:14 +0000 | [diff] [blame] | 467 | |
| 468 | in.h.opcode = FUSE_GETDIR; |
| 469 | in.h.ino = inode->i_ino; |
Miklos Szeredi | 4369643 | 2001-11-18 19:15:05 +0000 | [diff] [blame^] | 470 | out.numargs = 1; |
| 471 | out.args[0].size = sizeof(outarg); |
| 472 | out.args[0].value = &outarg; |
Miklos Szeredi | 85c74fc | 2001-10-28 19:44:14 +0000 | [diff] [blame] | 473 | request_send(fc, &in, &out); |
Miklos Szeredi | 19dff1b | 2001-10-30 15:06:52 +0000 | [diff] [blame] | 474 | if(!out.h.error) { |
Miklos Szeredi | 85c74fc | 2001-10-28 19:44:14 +0000 | [diff] [blame] | 475 | struct file *cfile = outarg.file; |
| 476 | struct inode *inode; |
| 477 | if(!cfile) { |
| 478 | printk("fuse_getdir: invalid file\n"); |
| 479 | return -EPROTO; |
| 480 | } |
| 481 | inode = cfile->f_dentry->d_inode; |
| 482 | if(!S_ISREG(inode->i_mode)) { |
| 483 | printk("fuse_getdir: not a regular file\n"); |
| 484 | fput(cfile); |
| 485 | return -EPROTO; |
| 486 | } |
| 487 | |
| 488 | file->private_data = cfile; |
| 489 | } |
| 490 | |
Miklos Szeredi | 19dff1b | 2001-10-30 15:06:52 +0000 | [diff] [blame] | 491 | return out.h.error; |
Miklos Szeredi | 85c74fc | 2001-10-28 19:44:14 +0000 | [diff] [blame] | 492 | } |
| 493 | |
| 494 | static int fuse_dir_release(struct inode *inode, struct file *file) |
| 495 | { |
| 496 | struct file *cfile = file->private_data; |
Miklos Szeredi | a181e61 | 2001-11-06 12:03:23 +0000 | [diff] [blame] | 497 | |
| 498 | if(cfile) |
| 499 | fput(cfile); |
Miklos Szeredi | 85c74fc | 2001-10-28 19:44:14 +0000 | [diff] [blame] | 500 | |
| 501 | return 0; |
| 502 | } |
| 503 | |
Miklos Szeredi | 5e18348 | 2001-10-31 14:52:35 +0000 | [diff] [blame] | 504 | static unsigned int iattr_to_fattr(struct iattr *iattr, |
| 505 | struct fuse_attr *fattr) |
| 506 | { |
| 507 | unsigned int ivalid = iattr->ia_valid; |
| 508 | unsigned int fvalid = 0; |
| 509 | |
| 510 | memset(fattr, 0, sizeof(*fattr)); |
| 511 | |
| 512 | if(ivalid & ATTR_MODE) |
| 513 | fvalid |= FATTR_MODE, fattr->mode = iattr->ia_mode; |
| 514 | if(ivalid & ATTR_UID) |
| 515 | fvalid |= FATTR_UID, fattr->uid = iattr->ia_uid; |
| 516 | if(ivalid & ATTR_GID) |
| 517 | fvalid |= FATTR_GID, fattr->gid = iattr->ia_gid; |
| 518 | if(ivalid & ATTR_SIZE) |
| 519 | fvalid |= FATTR_SIZE, fattr->size = iattr->ia_size; |
| 520 | /* You can only _set_ these together (they may change by themselves) */ |
| 521 | if((ivalid & (ATTR_ATIME | ATTR_MTIME)) == (ATTR_ATIME | ATTR_MTIME)) { |
| 522 | fvalid |= FATTR_UTIME; |
| 523 | fattr->atime = iattr->ia_atime; |
| 524 | fattr->mtime = iattr->ia_mtime; |
| 525 | } |
| 526 | |
| 527 | return fvalid; |
| 528 | } |
| 529 | |
| 530 | static int fuse_setattr(struct dentry *entry, struct iattr *attr) |
| 531 | { |
| 532 | struct inode *inode = entry->d_inode; |
| 533 | struct fuse_conn *fc = INO_FC(inode); |
| 534 | struct fuse_in in = FUSE_IN_INIT; |
| 535 | struct fuse_out out = FUSE_OUT_INIT; |
Miklos Szeredi | a181e61 | 2001-11-06 12:03:23 +0000 | [diff] [blame] | 536 | struct fuse_setattr_in inarg; |
| 537 | struct fuse_setattr_out outarg; |
Miklos Szeredi | 5e18348 | 2001-10-31 14:52:35 +0000 | [diff] [blame] | 538 | |
Miklos Szeredi | 4369643 | 2001-11-18 19:15:05 +0000 | [diff] [blame^] | 539 | memset(&inarg, 0, sizeof(inarg)); |
Miklos Szeredi | a181e61 | 2001-11-06 12:03:23 +0000 | [diff] [blame] | 540 | inarg.valid = iattr_to_fattr(attr, &inarg.attr); |
Miklos Szeredi | 5e18348 | 2001-10-31 14:52:35 +0000 | [diff] [blame] | 541 | |
| 542 | in.h.opcode = FUSE_SETATTR; |
| 543 | in.h.ino = inode->i_ino; |
Miklos Szeredi | 4369643 | 2001-11-18 19:15:05 +0000 | [diff] [blame^] | 544 | in.numargs = 1; |
| 545 | in.args[0].size = sizeof(inarg); |
| 546 | in.args[0].value = &inarg; |
| 547 | out.numargs = 1; |
| 548 | out.args[0].size = sizeof(outarg); |
| 549 | out.args[0].value = &outarg; |
Miklos Szeredi | 5e18348 | 2001-10-31 14:52:35 +0000 | [diff] [blame] | 550 | request_send(fc, &in, &out); |
| 551 | |
Miklos Szeredi | f3ea83b | 2001-11-07 14:55:16 +0000 | [diff] [blame] | 552 | if(!out.h.error) { |
| 553 | if(attr->ia_valid & ATTR_SIZE && |
| 554 | outarg.attr.size < inode->i_size) |
| 555 | vmtruncate(inode, outarg.attr.size); |
Miklos Szeredi | a181e61 | 2001-11-06 12:03:23 +0000 | [diff] [blame] | 556 | |
Miklos Szeredi | f3ea83b | 2001-11-07 14:55:16 +0000 | [diff] [blame] | 557 | change_attributes(inode, &outarg.attr); |
| 558 | } |
Miklos Szeredi | 5e18348 | 2001-10-31 14:52:35 +0000 | [diff] [blame] | 559 | return out.h.error; |
| 560 | } |
| 561 | |
Miklos Szeredi | 19dff1b | 2001-10-30 15:06:52 +0000 | [diff] [blame] | 562 | static int fuse_dentry_revalidate(struct dentry *entry, int flags) |
| 563 | { |
Miklos Szeredi | 97c61e9 | 2001-11-07 12:09:43 +0000 | [diff] [blame] | 564 | if(!entry->d_inode) |
| 565 | return 0; |
Miklos Szeredi | 4c74929 | 2001-11-16 21:40:00 +0000 | [diff] [blame] | 566 | /* Must not revaidate too soon, since kernel revalidate logic is |
| 567 | broken, and could return ENOENT */ |
| 568 | else if(!(flags & LOOKUP_CONTINUE) && |
| 569 | time_after(jiffies, entry->d_time + FUSE_REVALIDATE_TIME)) |
Miklos Szeredi | 19dff1b | 2001-10-30 15:06:52 +0000 | [diff] [blame] | 570 | return 0; |
| 571 | else |
| 572 | return 1; |
| 573 | } |
| 574 | |
Miklos Szeredi | 85c74fc | 2001-10-28 19:44:14 +0000 | [diff] [blame] | 575 | static struct inode_operations fuse_dir_inode_operations = |
| 576 | { |
| 577 | lookup: fuse_lookup, |
| 578 | create: fuse_create, |
| 579 | mknod: fuse_mknod, |
Miklos Szeredi | 85c74fc | 2001-10-28 19:44:14 +0000 | [diff] [blame] | 580 | mkdir: fuse_mkdir, |
Miklos Szeredi | b483c93 | 2001-10-29 14:57:57 +0000 | [diff] [blame] | 581 | symlink: fuse_symlink, |
| 582 | unlink: fuse_unlink, |
Miklos Szeredi | 85c74fc | 2001-10-28 19:44:14 +0000 | [diff] [blame] | 583 | rmdir: fuse_rmdir, |
| 584 | rename: fuse_rename, |
Miklos Szeredi | b483c93 | 2001-10-29 14:57:57 +0000 | [diff] [blame] | 585 | link: fuse_link, |
| 586 | setattr: fuse_setattr, |
Miklos Szeredi | 85c74fc | 2001-10-28 19:44:14 +0000 | [diff] [blame] | 587 | permission: fuse_permission, |
Miklos Szeredi | 19dff1b | 2001-10-30 15:06:52 +0000 | [diff] [blame] | 588 | revalidate: fuse_revalidate, |
Miklos Szeredi | 85c74fc | 2001-10-28 19:44:14 +0000 | [diff] [blame] | 589 | }; |
| 590 | |
| 591 | static struct file_operations fuse_dir_operations = { |
| 592 | read: generic_read_dir, |
| 593 | readdir: fuse_readdir, |
| 594 | open: fuse_dir_open, |
| 595 | release: fuse_dir_release, |
| 596 | }; |
| 597 | |
| 598 | static struct inode_operations fuse_file_inode_operations = { |
Miklos Szeredi | 5e18348 | 2001-10-31 14:52:35 +0000 | [diff] [blame] | 599 | setattr: fuse_setattr, |
Miklos Szeredi | 85c74fc | 2001-10-28 19:44:14 +0000 | [diff] [blame] | 600 | permission: fuse_permission, |
Miklos Szeredi | 19dff1b | 2001-10-30 15:06:52 +0000 | [diff] [blame] | 601 | revalidate: fuse_revalidate, |
Miklos Szeredi | 85c74fc | 2001-10-28 19:44:14 +0000 | [diff] [blame] | 602 | }; |
| 603 | |
Miklos Szeredi | 85c74fc | 2001-10-28 19:44:14 +0000 | [diff] [blame] | 604 | static struct inode_operations fuse_symlink_inode_operations = |
| 605 | { |
Miklos Szeredi | 5e18348 | 2001-10-31 14:52:35 +0000 | [diff] [blame] | 606 | setattr: fuse_setattr, |
Miklos Szeredi | 85c74fc | 2001-10-28 19:44:14 +0000 | [diff] [blame] | 607 | readlink: fuse_readlink, |
| 608 | follow_link: fuse_follow_link, |
Miklos Szeredi | 19dff1b | 2001-10-30 15:06:52 +0000 | [diff] [blame] | 609 | revalidate: fuse_revalidate, |
| 610 | }; |
| 611 | |
| 612 | static struct dentry_operations fuse_dentry_opertations = { |
| 613 | d_revalidate: fuse_dentry_revalidate, |
Miklos Szeredi | 85c74fc | 2001-10-28 19:44:14 +0000 | [diff] [blame] | 614 | }; |
| 615 | |
Miklos Szeredi | 85c74fc | 2001-10-28 19:44:14 +0000 | [diff] [blame] | 616 | /* |
| 617 | * Local Variables: |
| 618 | * indent-tabs-mode: t |
| 619 | * c-basic-offset: 8 |
| 620 | * End: |
| 621 | */ |