1/* 2 * linux/fs/sysv/namei.c 3 * 4 * minix/namei.c 5 * Copyright (C) 1991, 1992 Linus Torvalds 6 * 7 * coh/namei.c 8 * Copyright (C) 1993 Pascal Haible, Bruno Haible 9 * 10 * sysv/namei.c 11 * Copyright (C) 1993 Bruno Haible 12 * Copyright (C) 1997, 1998 Krzysztof G. Baranowski 13 */ 14 15#include <linux/fs.h> 16#include <linux/sysv_fs.h> 17#include <linux/pagemap.h> 18 19static inline void inc_count(struct inode *inode) 20{ 21 inode->i_nlink++; 22 mark_inode_dirty(inode); 23} 24 25static inline void dec_count(struct inode *inode) 26{ 27 inode->i_nlink--; 28 mark_inode_dirty(inode); 29} 30 31static int add_nondir(struct dentry *dentry, struct inode *inode) 32{ 33 int err = sysv_add_link(dentry, inode); 34 if (!err) { 35 d_instantiate(dentry, inode); 36 return 0; 37 } 38 dec_count(inode); 39 iput(inode); 40 return err; 41} 42 43static int sysv_hash(struct dentry *dentry, struct qstr *qstr) 44{ 45 unsigned long hash; 46 int i; 47 const unsigned char *name; 48 49 i = SYSV_NAMELEN; 50 if (i >= qstr->len) 51 return 0; 52 /* Truncate the name in place, avoids having to define a compare 53 function. */ 54 qstr->len = i; 55 name = qstr->name; 56 hash = init_name_hash(); 57 while (i--) 58 hash = partial_name_hash(*name++, hash); 59 qstr->hash = end_name_hash(hash); 60 return 0; 61} 62 63struct dentry_operations sysv_dentry_operations = { 64 d_hash: sysv_hash, 65}; 66 67static struct dentry *sysv_lookup(struct inode * dir, struct dentry * dentry) 68{ 69 struct inode * inode = NULL; 70 ino_t ino; 71 72 dentry->d_op = dir->i_sb->s_root->d_op; 73 if (dentry->d_name.len > SYSV_NAMELEN) 74 return ERR_PTR(-ENAMETOOLONG); 75 ino = sysv_inode_by_name(dentry); 76 77 if (ino) { 78 inode = iget(dir->i_sb, ino); 79 if (!inode) 80 return ERR_PTR(-EACCES); 81 } 82 d_add(dentry, inode); 83 return NULL; 84} 85 86static int sysv_mknod(struct inode * dir, struct dentry * dentry, int mode, int rdev) 87{ 88 struct inode * inode = sysv_new_inode(dir, mode); 89 int err = PTR_ERR(inode); 90 91 if (!IS_ERR(inode)) { 92 sysv_set_inode(inode, rdev); 93 mark_inode_dirty(inode); 94 err = add_nondir(dentry, inode); 95 } 96 return err; 97} 98 99static int sysv_create(struct inode * dir, struct dentry * dentry, int mode) 100{ 101 return sysv_mknod(dir, dentry, mode, 0); 102} 103 104static int sysv_symlink(struct inode * dir, struct dentry * dentry, 105 const char * symname) 106{ 107 int err = -ENAMETOOLONG; 108 int l = strlen(symname)+1; 109 struct inode * inode; 110 111 if (l > dir->i_sb->s_blocksize) 112 goto out; 113 114 inode = sysv_new_inode(dir, S_IFLNK|0777); 115 err = PTR_ERR(inode); 116 if (IS_ERR(inode)) 117 goto out; 118 119 sysv_set_inode(inode, 0); 120 err = block_symlink(inode, symname, l); 121 if (err) 122 goto out_fail; 123 124 mark_inode_dirty(inode); 125 err = add_nondir(dentry, inode); 126out: 127 return err; 128 129out_fail: 130 dec_count(inode); 131 iput(inode); 132 goto out; 133} 134 135static int sysv_link(struct dentry * old_dentry, struct inode * dir, 136 struct dentry * dentry) 137{ 138 struct inode *inode = old_dentry->d_inode; 139 140 if (S_ISDIR(inode->i_mode)) 141 return -EPERM; 142 143 if (inode->i_nlink >= inode->i_sb->sv_link_max) 144 return -EMLINK; 145 146 inode->i_ctime = CURRENT_TIME; 147 inc_count(inode); 148 atomic_inc(&inode->i_count); 149 150 return add_nondir(dentry, inode); 151} 152 153static int sysv_mkdir(struct inode * dir, struct dentry *dentry, int mode) 154{ 155 struct inode * inode; 156 int err = -EMLINK; 157 158 if (dir->i_nlink >= dir->i_sb->sv_link_max) 159 goto out; 160 inc_count(dir); 161 162 inode = sysv_new_inode(dir, S_IFDIR|mode); 163 err = PTR_ERR(inode); 164 if (IS_ERR(inode)) 165 goto out_dir; 166 167 sysv_set_inode(inode, 0); 168 169 inc_count(inode); 170 171 err = sysv_make_empty(inode, dir); 172 if (err) 173 goto out_fail; 174 175 err = sysv_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 dec_count(inode); 185 dec_count(inode); 186 iput(inode); 187out_dir: 188 dec_count(dir); 189 goto out; 190} 191 192static int sysv_unlink(struct inode * dir, struct dentry * dentry) 193{ 194 struct inode * inode = dentry->d_inode; 195 struct page * page; 196 struct sysv_dir_entry * de; 197 int err = -ENOENT; 198 199 de = sysv_find_entry(dentry, &page); 200 if (!de) 201 goto out; 202 203 err = sysv_delete_entry (de, page); 204 if (err) 205 goto out; 206 207 inode->i_ctime = dir->i_ctime; 208 dec_count(inode); 209out: 210 return err; 211} 212 213static int sysv_rmdir(struct inode * dir, struct dentry * dentry) 214{ 215 struct inode *inode = dentry->d_inode; 216 int err = -ENOTEMPTY; 217 218 if (sysv_empty_dir(inode)) { 219 err = sysv_unlink(dir, dentry); 220 if (!err) { 221 inode->i_size = 0; 222 dec_count(inode); 223 dec_count(dir); 224 } 225 } 226 return err; 227} 228 229/* 230 * Anybody can rename anything with this: the permission checks are left to the 231 * higher-level routines. 232 */ 233static int sysv_rename(struct inode * old_dir, struct dentry * old_dentry, 234 struct inode * new_dir, struct dentry * new_dentry) 235{ 236 struct inode * old_inode = old_dentry->d_inode; 237 struct inode * new_inode = new_dentry->d_inode; 238 struct page * dir_page = NULL; 239 struct sysv_dir_entry * dir_de = NULL; 240 struct page * old_page; 241 struct sysv_dir_entry * old_de; 242 int err = -ENOENT; 243 244 old_de = sysv_find_entry(old_dentry, &old_page); 245 if (!old_de) 246 goto out; 247 248 if (S_ISDIR(old_inode->i_mode)) { 249 err = -EIO; 250 dir_de = sysv_dotdot(old_inode, &dir_page); 251 if (!dir_de) 252 goto out_old; 253 } 254 255 if (new_inode) { 256 struct page * new_page; 257 struct sysv_dir_entry * new_de; 258 259 err = -ENOTEMPTY; 260 if (dir_de && !sysv_empty_dir(new_inode)) 261 goto out_dir; 262 263 err = -ENOENT; 264 new_de = sysv_find_entry(new_dentry, &new_page); 265 if (!new_de) 266 goto out_dir; 267 inc_count(old_inode); 268 sysv_set_link(new_de, new_page, old_inode); 269 new_inode->i_ctime = CURRENT_TIME; 270 if (dir_de) 271 new_inode->i_nlink--; 272 dec_count(new_inode); 273 } else { 274 if (dir_de) { 275 err = -EMLINK; 276 if (new_dir->i_nlink >= new_dir->i_sb->sv_link_max) 277 goto out_dir; 278 } 279 inc_count(old_inode); 280 err = sysv_add_link(new_dentry, old_inode); 281 if (err) { 282 dec_count(old_inode); 283 goto out_dir; 284 } 285 if (dir_de) 286 inc_count(new_dir); 287 } 288 289 sysv_delete_entry(old_de, old_page); 290 dec_count(old_inode); 291 292 if (dir_de) { 293 sysv_set_link(dir_de, dir_page, new_dir); 294 dec_count(old_dir); 295 } 296 return 0; 297 298out_dir: 299 if (dir_de) { 300 kunmap(dir_page); 301 page_cache_release(dir_page); 302 } 303out_old: 304 kunmap(old_page); 305 page_cache_release(old_page); 306out: 307 return err; 308} 309 310/* 311 * directories can handle most operations... 312 */ 313struct inode_operations sysv_dir_inode_operations = { 314 create: sysv_create, 315 lookup: sysv_lookup, 316 link: sysv_link, 317 unlink: sysv_unlink, 318 symlink: sysv_symlink, 319 mkdir: sysv_mkdir, 320 rmdir: sysv_rmdir, 321 mknod: sysv_mknod, 322 rename: sysv_rename, 323}; 324