1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * linux/fs/minix/namei.c 4 * 5 * Copyright (C) 1991, 1992 Linus Torvalds 6 */ 7 8 #include "minix.h" 9 10 static int add_nondir(struct dentry *dentry, struct inode *inode) 11 { 12 int err = minix_add_link(dentry, inode); 13 if (!err) { 14 d_instantiate(dentry, inode); 15 return 0; 16 } 17 inode_dec_link_count(inode); 18 iput(inode); 19 return err; 20 } 21 22 static struct dentry *minix_lookup(struct inode * dir, struct dentry *dentry, unsigned int flags) 23 { 24 struct inode * inode = NULL; 25 ino_t ino; 26 27 if (dentry->d_name.len > minix_sb(dir->i_sb)->s_namelen) 28 return ERR_PTR(-ENAMETOOLONG); 29 30 ino = minix_inode_by_name(dentry); 31 if (ino) 32 inode = minix_iget(dir->i_sb, ino); 33 return d_splice_alias(inode, dentry); 34 } 35 36 static int minix_mknod(struct mnt_idmap *idmap, struct inode *dir, 37 struct dentry *dentry, umode_t mode, dev_t rdev) 38 { 39 struct inode *inode; 40 41 if (!old_valid_dev(rdev)) 42 return -EINVAL; 43 44 inode = minix_new_inode(dir, mode); 45 if (IS_ERR(inode)) 46 return PTR_ERR(inode); 47 48 minix_set_inode(inode, rdev); 49 mark_inode_dirty(inode); 50 return add_nondir(dentry, inode); 51 } 52 53 static int minix_tmpfile(struct mnt_idmap *idmap, struct inode *dir, 54 struct file *file, umode_t mode) 55 { 56 struct inode *inode = minix_new_inode(dir, mode); 57 58 if (IS_ERR(inode)) 59 return finish_open_simple(file, PTR_ERR(inode)); 60 minix_set_inode(inode, 0); 61 mark_inode_dirty(inode); 62 d_tmpfile(file, inode); 63 return finish_open_simple(file, 0); 64 } 65 66 static int minix_create(struct mnt_idmap *idmap, struct inode *dir, 67 struct dentry *dentry, umode_t mode, bool excl) 68 { 69 return minix_mknod(&nop_mnt_idmap, dir, dentry, mode, 0); 70 } 71 72 static int minix_symlink(struct mnt_idmap *idmap, struct inode *dir, 73 struct dentry *dentry, const char *symname) 74 { 75 int i = strlen(symname)+1; 76 struct inode * inode; 77 int err; 78 79 if (i > dir->i_sb->s_blocksize) 80 return -ENAMETOOLONG; 81 82 inode = minix_new_inode(dir, S_IFLNK | 0777); 83 if (IS_ERR(inode)) 84 return PTR_ERR(inode); 85 86 minix_set_inode(inode, 0); 87 err = page_symlink(inode, symname, i); 88 if (unlikely(err)) { 89 inode_dec_link_count(inode); 90 iput(inode); 91 return err; 92 } 93 return add_nondir(dentry, inode); 94 } 95 96 static int minix_link(struct dentry * old_dentry, struct inode * dir, 97 struct dentry *dentry) 98 { 99 struct inode *inode = d_inode(old_dentry); 100 101 inode_set_ctime_current(inode); 102 inode_inc_link_count(inode); 103 ihold(inode); 104 return add_nondir(dentry, inode); 105 } 106 107 static struct dentry *minix_mkdir(struct mnt_idmap *idmap, struct inode *dir, 108 struct dentry *dentry, umode_t mode) 109 { 110 struct inode * inode; 111 int err; 112 113 inode = minix_new_inode(dir, S_IFDIR | mode); 114 if (IS_ERR(inode)) 115 return ERR_CAST(inode); 116 117 inode_inc_link_count(dir); 118 minix_set_inode(inode, 0); 119 inode_inc_link_count(inode); 120 121 err = minix_make_empty(inode, dir); 122 if (err) 123 goto out_fail; 124 125 err = minix_add_link(dentry, inode); 126 if (err) 127 goto out_fail; 128 129 d_instantiate(dentry, inode); 130 out: 131 return ERR_PTR(err); 132 133 out_fail: 134 inode_dec_link_count(inode); 135 inode_dec_link_count(inode); 136 iput(inode); 137 inode_dec_link_count(dir); 138 goto out; 139 } 140 141 static int minix_unlink(struct inode * dir, struct dentry *dentry) 142 { 143 struct inode * inode = d_inode(dentry); 144 struct folio *folio; 145 struct minix_dir_entry * de; 146 int err; 147 148 if (inode->i_nlink == 0) { 149 minix_error_inode(inode, "inode has corrupted nlink"); 150 return -EFSCORRUPTED; 151 } 152 153 de = minix_find_entry(dentry, &folio); 154 if (!de) 155 return -ENOENT; 156 err = minix_delete_entry(de, folio); 157 folio_release_kmap(folio, de); 158 159 if (err) 160 return err; 161 inode_set_ctime_to_ts(inode, inode_get_ctime(dir)); 162 inode_dec_link_count(inode); 163 return 0; 164 } 165 166 static int minix_rmdir(struct inode * dir, struct dentry *dentry) 167 { 168 struct inode * inode = d_inode(dentry); 169 int err = -EFSCORRUPTED; 170 171 if (dir->i_nlink <= 2) { 172 minix_error_inode(dir, "inode has corrupted nlink"); 173 goto out; 174 } 175 176 err = -ENOTEMPTY; 177 if (!minix_empty_dir(inode)) 178 goto out; 179 180 err = minix_unlink(dir, dentry); 181 if (!err) { 182 inode_dec_link_count(dir); 183 inode_dec_link_count(inode); 184 } 185 186 out: 187 return err; 188 } 189 190 static int minix_rename(struct mnt_idmap *idmap, 191 struct inode *old_dir, struct dentry *old_dentry, 192 struct inode *new_dir, struct dentry *new_dentry, 193 unsigned int flags) 194 { 195 struct inode * old_inode = d_inode(old_dentry); 196 struct inode * new_inode = d_inode(new_dentry); 197 struct folio * dir_folio = NULL; 198 struct minix_dir_entry * dir_de = NULL; 199 struct folio *old_folio; 200 struct minix_dir_entry * old_de; 201 int err = -ENOENT; 202 203 if (flags & ~RENAME_NOREPLACE) 204 return -EINVAL; 205 206 old_de = minix_find_entry(old_dentry, &old_folio); 207 if (!old_de) 208 goto out; 209 210 if (S_ISDIR(old_inode->i_mode)) { 211 err = -EIO; 212 dir_de = minix_dotdot(old_inode, &dir_folio); 213 if (!dir_de) 214 goto out_old; 215 } 216 217 if (new_inode) { 218 struct folio *new_folio; 219 struct minix_dir_entry * new_de; 220 221 err = -ENOTEMPTY; 222 if (dir_de && !minix_empty_dir(new_inode)) 223 goto out_dir; 224 225 err = -EFSCORRUPTED; 226 if (new_inode->i_nlink == 0 || (dir_de && new_inode->i_nlink != 2)) { 227 minix_error_inode(new_inode, "inode has corrupted nlink"); 228 goto out_dir; 229 } 230 231 if (dir_de && old_dir->i_nlink <= 2) { 232 minix_error_inode(old_dir, "inode has corrupted nlink"); 233 goto out_dir; 234 } 235 236 err = -ENOENT; 237 new_de = minix_find_entry(new_dentry, &new_folio); 238 if (!new_de) 239 goto out_dir; 240 err = minix_set_link(new_de, new_folio, old_inode); 241 folio_release_kmap(new_folio, new_de); 242 if (err) 243 goto out_dir; 244 inode_set_ctime_current(new_inode); 245 if (dir_de) 246 drop_nlink(new_inode); 247 inode_dec_link_count(new_inode); 248 } else { 249 err = minix_add_link(new_dentry, old_inode); 250 if (err) 251 goto out_dir; 252 if (dir_de) 253 inode_inc_link_count(new_dir); 254 } 255 256 err = minix_delete_entry(old_de, old_folio); 257 if (err) 258 goto out_dir; 259 260 mark_inode_dirty(old_inode); 261 262 if (dir_de) { 263 err = minix_set_link(dir_de, dir_folio, new_dir); 264 if (!err) 265 inode_dec_link_count(old_dir); 266 } 267 out_dir: 268 if (dir_de) 269 folio_release_kmap(dir_folio, dir_de); 270 out_old: 271 folio_release_kmap(old_folio, old_de); 272 out: 273 return err; 274 } 275 276 /* 277 * directories can handle most operations... 278 */ 279 const struct inode_operations minix_dir_inode_operations = { 280 .create = minix_create, 281 .lookup = minix_lookup, 282 .link = minix_link, 283 .unlink = minix_unlink, 284 .symlink = minix_symlink, 285 .mkdir = minix_mkdir, 286 .rmdir = minix_rmdir, 287 .mknod = minix_mknod, 288 .rename = minix_rename, 289 .getattr = minix_getattr, 290 .tmpfile = minix_tmpfile, 291 }; 292