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