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