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 int 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 PTR_ERR(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; 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 de = minix_find_entry(dentry, &folio); 149 if (!de) 150 return -ENOENT; 151 err = minix_delete_entry(de, folio); 152 folio_release_kmap(folio, de); 153 154 if (err) 155 return err; 156 inode_set_ctime_to_ts(inode, inode_get_ctime(dir)); 157 inode_dec_link_count(inode); 158 return 0; 159 } 160 161 static int minix_rmdir(struct inode * dir, struct dentry *dentry) 162 { 163 struct inode * inode = d_inode(dentry); 164 int err = -ENOTEMPTY; 165 166 if (minix_empty_dir(inode)) { 167 err = minix_unlink(dir, dentry); 168 if (!err) { 169 inode_dec_link_count(dir); 170 inode_dec_link_count(inode); 171 } 172 } 173 return err; 174 } 175 176 static int minix_rename(struct mnt_idmap *idmap, 177 struct inode *old_dir, struct dentry *old_dentry, 178 struct inode *new_dir, struct dentry *new_dentry, 179 unsigned int flags) 180 { 181 struct inode * old_inode = d_inode(old_dentry); 182 struct inode * new_inode = d_inode(new_dentry); 183 struct folio * dir_folio = NULL; 184 struct minix_dir_entry * dir_de = NULL; 185 struct folio *old_folio; 186 struct minix_dir_entry * old_de; 187 int err = -ENOENT; 188 189 if (flags & ~RENAME_NOREPLACE) 190 return -EINVAL; 191 192 old_de = minix_find_entry(old_dentry, &old_folio); 193 if (!old_de) 194 goto out; 195 196 if (S_ISDIR(old_inode->i_mode)) { 197 err = -EIO; 198 dir_de = minix_dotdot(old_inode, &dir_folio); 199 if (!dir_de) 200 goto out_old; 201 } 202 203 if (new_inode) { 204 struct folio *new_folio; 205 struct minix_dir_entry * new_de; 206 207 err = -ENOTEMPTY; 208 if (dir_de && !minix_empty_dir(new_inode)) 209 goto out_dir; 210 211 err = -ENOENT; 212 new_de = minix_find_entry(new_dentry, &new_folio); 213 if (!new_de) 214 goto out_dir; 215 err = minix_set_link(new_de, new_folio, old_inode); 216 folio_release_kmap(new_folio, new_de); 217 if (err) 218 goto out_dir; 219 inode_set_ctime_current(new_inode); 220 if (dir_de) 221 drop_nlink(new_inode); 222 inode_dec_link_count(new_inode); 223 } else { 224 err = minix_add_link(new_dentry, old_inode); 225 if (err) 226 goto out_dir; 227 if (dir_de) 228 inode_inc_link_count(new_dir); 229 } 230 231 err = minix_delete_entry(old_de, old_folio); 232 if (err) 233 goto out_dir; 234 235 mark_inode_dirty(old_inode); 236 237 if (dir_de) { 238 err = minix_set_link(dir_de, dir_folio, new_dir); 239 if (!err) 240 inode_dec_link_count(old_dir); 241 } 242 out_dir: 243 if (dir_de) 244 folio_release_kmap(dir_folio, dir_de); 245 out_old: 246 folio_release_kmap(old_folio, old_de); 247 out: 248 return err; 249 } 250 251 /* 252 * directories can handle most operations... 253 */ 254 const struct inode_operations minix_dir_inode_operations = { 255 .create = minix_create, 256 .lookup = minix_lookup, 257 .link = minix_link, 258 .unlink = minix_unlink, 259 .symlink = minix_symlink, 260 .mkdir = minix_mkdir, 261 .rmdir = minix_rmdir, 262 .mknod = minix_mknod, 263 .rename = minix_rename, 264 .getattr = minix_getattr, 265 .tmpfile = minix_tmpfile, 266 }; 267