1/* 2 * Copyright (C) 2005, 2006 3 * Avishay Traeger (avishay@gmail.com) 4 * Copyright (C) 2008, 2009 5 * Boaz Harrosh <ooo@electrozaur.com> 6 * 7 * Copyrights for code taken from ext2: 8 * Copyright (C) 1992, 1993, 1994, 1995 9 * Remy Card (card@masi.ibp.fr) 10 * Laboratoire MASI - Institut Blaise Pascal 11 * Universite Pierre et Marie Curie (Paris VI) 12 * from 13 * linux/fs/minix/inode.c 14 * Copyright (C) 1991, 1992 Linus Torvalds 15 * 16 * This file is part of exofs. 17 * 18 * exofs is free software; you can redistribute it and/or modify 19 * it under the terms of the GNU General Public License as published by 20 * the Free Software Foundation. Since it is based on ext2, and the only 21 * valid version of GPL for the Linux kernel is version 2, the only valid 22 * version of GPL for exofs is version 2. 23 * 24 * exofs is distributed in the hope that it will be useful, 25 * but WITHOUT ANY WARRANTY; without even the implied warranty of 26 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 27 * GNU General Public License for more details. 28 * 29 * You should have received a copy of the GNU General Public License 30 * along with exofs; if not, write to the Free Software 31 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 32 */ 33 34#include "exofs.h" 35 36static inline int exofs_add_nondir(struct dentry *dentry, struct inode *inode) 37{ 38 int err = exofs_add_link(dentry, inode); 39 if (!err) { 40 d_instantiate(dentry, inode); 41 return 0; 42 } 43 inode_dec_link_count(inode); 44 iput(inode); 45 return err; 46} 47 48static struct dentry *exofs_lookup(struct inode *dir, struct dentry *dentry, 49 unsigned int flags) 50{ 51 struct inode *inode; 52 ino_t ino; 53 54 if (dentry->d_name.len > EXOFS_NAME_LEN) 55 return ERR_PTR(-ENAMETOOLONG); 56 57 ino = exofs_inode_by_name(dir, dentry); 58 inode = ino ? exofs_iget(dir->i_sb, ino) : NULL; 59 return d_splice_alias(inode, dentry); 60} 61 62static int exofs_create(struct inode *dir, struct dentry *dentry, umode_t mode, 63 bool excl) 64{ 65 struct inode *inode = exofs_new_inode(dir, mode); 66 int err = PTR_ERR(inode); 67 if (!IS_ERR(inode)) { 68 inode->i_op = &exofs_file_inode_operations; 69 inode->i_fop = &exofs_file_operations; 70 inode->i_mapping->a_ops = &exofs_aops; 71 mark_inode_dirty(inode); 72 err = exofs_add_nondir(dentry, inode); 73 } 74 return err; 75} 76 77static int exofs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, 78 dev_t rdev) 79{ 80 struct inode *inode; 81 int err; 82 83 if (!new_valid_dev(rdev)) 84 return -EINVAL; 85 86 inode = exofs_new_inode(dir, mode); 87 err = PTR_ERR(inode); 88 if (!IS_ERR(inode)) { 89 init_special_inode(inode, inode->i_mode, rdev); 90 mark_inode_dirty(inode); 91 err = exofs_add_nondir(dentry, inode); 92 } 93 return err; 94} 95 96static int exofs_symlink(struct inode *dir, struct dentry *dentry, 97 const char *symname) 98{ 99 struct super_block *sb = dir->i_sb; 100 int err = -ENAMETOOLONG; 101 unsigned l = strlen(symname)+1; 102 struct inode *inode; 103 struct exofs_i_info *oi; 104 105 if (l > sb->s_blocksize) 106 goto out; 107 108 inode = exofs_new_inode(dir, S_IFLNK | S_IRWXUGO); 109 err = PTR_ERR(inode); 110 if (IS_ERR(inode)) 111 goto out; 112 113 oi = exofs_i(inode); 114 if (l > sizeof(oi->i_data)) { 115 /* slow symlink */ 116 inode->i_op = &exofs_symlink_inode_operations; 117 inode->i_mapping->a_ops = &exofs_aops; 118 memset(oi->i_data, 0, sizeof(oi->i_data)); 119 120 err = page_symlink(inode, symname, l); 121 if (err) 122 goto out_fail; 123 } else { 124 /* fast symlink */ 125 inode->i_op = &exofs_fast_symlink_inode_operations; 126 memcpy(oi->i_data, symname, l); 127 inode->i_size = l-1; 128 } 129 mark_inode_dirty(inode); 130 131 err = exofs_add_nondir(dentry, inode); 132out: 133 return err; 134 135out_fail: 136 inode_dec_link_count(inode); 137 iput(inode); 138 goto out; 139} 140 141static int exofs_link(struct dentry *old_dentry, struct inode *dir, 142 struct dentry *dentry) 143{ 144 struct inode *inode = old_dentry->d_inode; 145 146 inode->i_ctime = CURRENT_TIME; 147 inode_inc_link_count(inode); 148 ihold(inode); 149 150 return exofs_add_nondir(dentry, inode); 151} 152 153static int exofs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) 154{ 155 struct inode *inode; 156 int err; 157 158 inode_inc_link_count(dir); 159 160 inode = exofs_new_inode(dir, S_IFDIR | mode); 161 err = PTR_ERR(inode); 162 if (IS_ERR(inode)) 163 goto out_dir; 164 165 inode->i_op = &exofs_dir_inode_operations; 166 inode->i_fop = &exofs_dir_operations; 167 inode->i_mapping->a_ops = &exofs_aops; 168 169 inode_inc_link_count(inode); 170 171 err = exofs_make_empty(inode, dir); 172 if (err) 173 goto out_fail; 174 175 err = exofs_add_link(dentry, inode); 176 if (err) 177 goto out_fail; 178 179 d_instantiate(dentry, inode); 180out: 181 return err; 182 183out_fail: 184 inode_dec_link_count(inode); 185 inode_dec_link_count(inode); 186 iput(inode); 187out_dir: 188 inode_dec_link_count(dir); 189 goto out; 190} 191 192static int exofs_unlink(struct inode *dir, struct dentry *dentry) 193{ 194 struct inode *inode = dentry->d_inode; 195 struct exofs_dir_entry *de; 196 struct page *page; 197 int err = -ENOENT; 198 199 de = exofs_find_entry(dir, dentry, &page); 200 if (!de) 201 goto out; 202 203 err = exofs_delete_entry(de, page); 204 if (err) 205 goto out; 206 207 inode->i_ctime = dir->i_ctime; 208 inode_dec_link_count(inode); 209 err = 0; 210out: 211 return err; 212} 213 214static int exofs_rmdir(struct inode *dir, struct dentry *dentry) 215{ 216 struct inode *inode = dentry->d_inode; 217 int err = -ENOTEMPTY; 218 219 if (exofs_empty_dir(inode)) { 220 err = exofs_unlink(dir, dentry); 221 if (!err) { 222 inode->i_size = 0; 223 inode_dec_link_count(inode); 224 inode_dec_link_count(dir); 225 } 226 } 227 return err; 228} 229 230static int exofs_rename(struct inode *old_dir, struct dentry *old_dentry, 231 struct inode *new_dir, struct dentry *new_dentry) 232{ 233 struct inode *old_inode = old_dentry->d_inode; 234 struct inode *new_inode = new_dentry->d_inode; 235 struct page *dir_page = NULL; 236 struct exofs_dir_entry *dir_de = NULL; 237 struct page *old_page; 238 struct exofs_dir_entry *old_de; 239 int err = -ENOENT; 240 241 old_de = exofs_find_entry(old_dir, old_dentry, &old_page); 242 if (!old_de) 243 goto out; 244 245 if (S_ISDIR(old_inode->i_mode)) { 246 err = -EIO; 247 dir_de = exofs_dotdot(old_inode, &dir_page); 248 if (!dir_de) 249 goto out_old; 250 } 251 252 if (new_inode) { 253 struct page *new_page; 254 struct exofs_dir_entry *new_de; 255 256 err = -ENOTEMPTY; 257 if (dir_de && !exofs_empty_dir(new_inode)) 258 goto out_dir; 259 260 err = -ENOENT; 261 new_de = exofs_find_entry(new_dir, new_dentry, &new_page); 262 if (!new_de) 263 goto out_dir; 264 err = exofs_set_link(new_dir, new_de, new_page, old_inode); 265 new_inode->i_ctime = CURRENT_TIME; 266 if (dir_de) 267 drop_nlink(new_inode); 268 inode_dec_link_count(new_inode); 269 if (err) 270 goto out_dir; 271 } else { 272 err = exofs_add_link(new_dentry, old_inode); 273 if (err) 274 goto out_dir; 275 if (dir_de) 276 inode_inc_link_count(new_dir); 277 } 278 279 old_inode->i_ctime = CURRENT_TIME; 280 281 exofs_delete_entry(old_de, old_page); 282 mark_inode_dirty(old_inode); 283 284 if (dir_de) { 285 err = exofs_set_link(old_inode, dir_de, dir_page, new_dir); 286 inode_dec_link_count(old_dir); 287 if (err) 288 goto out_dir; 289 } 290 return 0; 291 292 293out_dir: 294 if (dir_de) { 295 kunmap(dir_page); 296 page_cache_release(dir_page); 297 } 298out_old: 299 kunmap(old_page); 300 page_cache_release(old_page); 301out: 302 return err; 303} 304 305const struct inode_operations exofs_dir_inode_operations = { 306 .create = exofs_create, 307 .lookup = exofs_lookup, 308 .link = exofs_link, 309 .unlink = exofs_unlink, 310 .symlink = exofs_symlink, 311 .mkdir = exofs_mkdir, 312 .rmdir = exofs_rmdir, 313 .mknod = exofs_mknod, 314 .rename = exofs_rename, 315 .setattr = exofs_setattr, 316}; 317 318const struct inode_operations exofs_special_inode_operations = { 319 .setattr = exofs_setattr, 320}; 321