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/pagemap.h> 16#include "sysv.h" 17 18static int add_nondir(struct dentry *dentry, struct inode *inode) 19{ 20 int err = sysv_add_link(dentry, inode); 21 if (!err) { 22 d_instantiate(dentry, inode); 23 return 0; 24 } 25 inode_dec_link_count(inode); 26 iput(inode); 27 return err; 28} 29 30static int sysv_hash(const struct dentry *dentry, struct qstr *qstr) 31{ 32 /* Truncate the name in place, avoids having to define a compare 33 function. */ 34 if (qstr->len > SYSV_NAMELEN) { 35 qstr->len = SYSV_NAMELEN; 36 qstr->hash = full_name_hash(qstr->name, qstr->len); 37 } 38 return 0; 39} 40 41const struct dentry_operations sysv_dentry_operations = { 42 .d_hash = sysv_hash, 43}; 44 45static struct dentry *sysv_lookup(struct inode * dir, struct dentry * dentry, unsigned int flags) 46{ 47 struct inode * inode = NULL; 48 ino_t ino; 49 50 if (dentry->d_name.len > SYSV_NAMELEN) 51 return ERR_PTR(-ENAMETOOLONG); 52 ino = sysv_inode_by_name(dentry); 53 54 if (ino) { 55 inode = sysv_iget(dir->i_sb, ino); 56 if (IS_ERR(inode)) 57 return ERR_CAST(inode); 58 } 59 d_add(dentry, inode); 60 return NULL; 61} 62 63static int sysv_mknod(struct inode * dir, struct dentry * dentry, umode_t mode, dev_t rdev) 64{ 65 struct inode * inode; 66 int err; 67 68 if (!old_valid_dev(rdev)) 69 return -EINVAL; 70 71 inode = sysv_new_inode(dir, mode); 72 err = PTR_ERR(inode); 73 74 if (!IS_ERR(inode)) { 75 sysv_set_inode(inode, rdev); 76 mark_inode_dirty(inode); 77 err = add_nondir(dentry, inode); 78 } 79 return err; 80} 81 82static int sysv_create(struct inode * dir, struct dentry * dentry, umode_t mode, bool excl) 83{ 84 return sysv_mknod(dir, dentry, mode, 0); 85} 86 87static int sysv_symlink(struct inode * dir, struct dentry * dentry, 88 const char * symname) 89{ 90 int err = -ENAMETOOLONG; 91 int l = strlen(symname)+1; 92 struct inode * inode; 93 94 if (l > dir->i_sb->s_blocksize) 95 goto out; 96 97 inode = sysv_new_inode(dir, S_IFLNK|0777); 98 err = PTR_ERR(inode); 99 if (IS_ERR(inode)) 100 goto out; 101 102 sysv_set_inode(inode, 0); 103 err = page_symlink(inode, symname, l); 104 if (err) 105 goto out_fail; 106 107 mark_inode_dirty(inode); 108 err = add_nondir(dentry, inode); 109out: 110 return err; 111 112out_fail: 113 inode_dec_link_count(inode); 114 iput(inode); 115 goto out; 116} 117 118static int sysv_link(struct dentry * old_dentry, struct inode * dir, 119 struct dentry * dentry) 120{ 121 struct inode *inode = d_inode(old_dentry); 122 123 inode->i_ctime = CURRENT_TIME_SEC; 124 inode_inc_link_count(inode); 125 ihold(inode); 126 127 return add_nondir(dentry, inode); 128} 129 130static int sysv_mkdir(struct inode * dir, struct dentry *dentry, umode_t mode) 131{ 132 struct inode * inode; 133 int err; 134 135 inode_inc_link_count(dir); 136 137 inode = sysv_new_inode(dir, S_IFDIR|mode); 138 err = PTR_ERR(inode); 139 if (IS_ERR(inode)) 140 goto out_dir; 141 142 sysv_set_inode(inode, 0); 143 144 inode_inc_link_count(inode); 145 146 err = sysv_make_empty(inode, dir); 147 if (err) 148 goto out_fail; 149 150 err = sysv_add_link(dentry, inode); 151 if (err) 152 goto out_fail; 153 154 d_instantiate(dentry, inode); 155out: 156 return err; 157 158out_fail: 159 inode_dec_link_count(inode); 160 inode_dec_link_count(inode); 161 iput(inode); 162out_dir: 163 inode_dec_link_count(dir); 164 goto out; 165} 166 167static int sysv_unlink(struct inode * dir, struct dentry * dentry) 168{ 169 struct inode * inode = d_inode(dentry); 170 struct page * page; 171 struct sysv_dir_entry * de; 172 int err = -ENOENT; 173 174 de = sysv_find_entry(dentry, &page); 175 if (!de) 176 goto out; 177 178 err = sysv_delete_entry (de, page); 179 if (err) 180 goto out; 181 182 inode->i_ctime = dir->i_ctime; 183 inode_dec_link_count(inode); 184out: 185 return err; 186} 187 188static int sysv_rmdir(struct inode * dir, struct dentry * dentry) 189{ 190 struct inode *inode = d_inode(dentry); 191 int err = -ENOTEMPTY; 192 193 if (sysv_empty_dir(inode)) { 194 err = sysv_unlink(dir, dentry); 195 if (!err) { 196 inode->i_size = 0; 197 inode_dec_link_count(inode); 198 inode_dec_link_count(dir); 199 } 200 } 201 return err; 202} 203 204/* 205 * Anybody can rename anything with this: the permission checks are left to the 206 * higher-level routines. 207 */ 208static int sysv_rename(struct inode * old_dir, struct dentry * old_dentry, 209 struct inode * new_dir, struct dentry * new_dentry) 210{ 211 struct inode * old_inode = d_inode(old_dentry); 212 struct inode * new_inode = d_inode(new_dentry); 213 struct page * dir_page = NULL; 214 struct sysv_dir_entry * dir_de = NULL; 215 struct page * old_page; 216 struct sysv_dir_entry * old_de; 217 int err = -ENOENT; 218 219 old_de = sysv_find_entry(old_dentry, &old_page); 220 if (!old_de) 221 goto out; 222 223 if (S_ISDIR(old_inode->i_mode)) { 224 err = -EIO; 225 dir_de = sysv_dotdot(old_inode, &dir_page); 226 if (!dir_de) 227 goto out_old; 228 } 229 230 if (new_inode) { 231 struct page * new_page; 232 struct sysv_dir_entry * new_de; 233 234 err = -ENOTEMPTY; 235 if (dir_de && !sysv_empty_dir(new_inode)) 236 goto out_dir; 237 238 err = -ENOENT; 239 new_de = sysv_find_entry(new_dentry, &new_page); 240 if (!new_de) 241 goto out_dir; 242 sysv_set_link(new_de, new_page, old_inode); 243 new_inode->i_ctime = CURRENT_TIME_SEC; 244 if (dir_de) 245 drop_nlink(new_inode); 246 inode_dec_link_count(new_inode); 247 } else { 248 err = sysv_add_link(new_dentry, old_inode); 249 if (err) 250 goto out_dir; 251 if (dir_de) 252 inode_inc_link_count(new_dir); 253 } 254 255 sysv_delete_entry(old_de, old_page); 256 mark_inode_dirty(old_inode); 257 258 if (dir_de) { 259 sysv_set_link(dir_de, dir_page, new_dir); 260 inode_dec_link_count(old_dir); 261 } 262 return 0; 263 264out_dir: 265 if (dir_de) { 266 kunmap(dir_page); 267 page_cache_release(dir_page); 268 } 269out_old: 270 kunmap(old_page); 271 page_cache_release(old_page); 272out: 273 return err; 274} 275 276/* 277 * directories can handle most operations... 278 */ 279const struct inode_operations sysv_dir_inode_operations = { 280 .create = sysv_create, 281 .lookup = sysv_lookup, 282 .link = sysv_link, 283 .unlink = sysv_unlink, 284 .symlink = sysv_symlink, 285 .mkdir = sysv_mkdir, 286 .rmdir = sysv_rmdir, 287 .mknod = sysv_mknod, 288 .rename = sysv_rename, 289 .getattr = sysv_getattr, 290}; 291