Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v4.12-rc1 294 lines 6.0 kB view raw
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(dentry, 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(inode); 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 unsigned int flags) 211{ 212 struct inode * old_inode = d_inode(old_dentry); 213 struct inode * new_inode = d_inode(new_dentry); 214 struct page * dir_page = NULL; 215 struct sysv_dir_entry * dir_de = NULL; 216 struct page * old_page; 217 struct sysv_dir_entry * old_de; 218 int err = -ENOENT; 219 220 if (flags & ~RENAME_NOREPLACE) 221 return -EINVAL; 222 223 old_de = sysv_find_entry(old_dentry, &old_page); 224 if (!old_de) 225 goto out; 226 227 if (S_ISDIR(old_inode->i_mode)) { 228 err = -EIO; 229 dir_de = sysv_dotdot(old_inode, &dir_page); 230 if (!dir_de) 231 goto out_old; 232 } 233 234 if (new_inode) { 235 struct page * new_page; 236 struct sysv_dir_entry * new_de; 237 238 err = -ENOTEMPTY; 239 if (dir_de && !sysv_empty_dir(new_inode)) 240 goto out_dir; 241 242 err = -ENOENT; 243 new_de = sysv_find_entry(new_dentry, &new_page); 244 if (!new_de) 245 goto out_dir; 246 sysv_set_link(new_de, new_page, old_inode); 247 new_inode->i_ctime = current_time(new_inode); 248 if (dir_de) 249 drop_nlink(new_inode); 250 inode_dec_link_count(new_inode); 251 } else { 252 err = sysv_add_link(new_dentry, old_inode); 253 if (err) 254 goto out_dir; 255 if (dir_de) 256 inode_inc_link_count(new_dir); 257 } 258 259 sysv_delete_entry(old_de, old_page); 260 mark_inode_dirty(old_inode); 261 262 if (dir_de) { 263 sysv_set_link(dir_de, dir_page, new_dir); 264 inode_dec_link_count(old_dir); 265 } 266 return 0; 267 268out_dir: 269 if (dir_de) { 270 kunmap(dir_page); 271 put_page(dir_page); 272 } 273out_old: 274 kunmap(old_page); 275 put_page(old_page); 276out: 277 return err; 278} 279 280/* 281 * directories can handle most operations... 282 */ 283const struct inode_operations sysv_dir_inode_operations = { 284 .create = sysv_create, 285 .lookup = sysv_lookup, 286 .link = sysv_link, 287 .unlink = sysv_unlink, 288 .symlink = sysv_symlink, 289 .mkdir = sysv_mkdir, 290 .rmdir = sysv_rmdir, 291 .mknod = sysv_mknod, 292 .rename = sysv_rename, 293 .getattr = sysv_getattr, 294};