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 inode * dir, struct dentry *dentry, umode_t mode, dev_t rdev) 37 { 38 int error; 39 struct inode *inode; 40 41 if (!old_valid_dev(rdev)) 42 return -EINVAL; 43 44 inode = minix_new_inode(dir, mode, &error); 45 46 if (inode) { 47 minix_set_inode(inode, rdev); 48 mark_inode_dirty(inode); 49 error = add_nondir(dentry, inode); 50 } 51 return error; 52 } 53 54 static int minix_tmpfile(struct inode *dir, struct dentry *dentry, umode_t mode) 55 { 56 int error; 57 struct inode *inode = minix_new_inode(dir, mode, &error); 58 if (inode) { 59 minix_set_inode(inode, 0); 60 mark_inode_dirty(inode); 61 d_tmpfile(dentry, inode); 62 } 63 return error; 64 } 65 66 static int minix_create(struct inode *dir, struct dentry *dentry, umode_t mode, 67 bool excl) 68 { 69 return minix_mknod(dir, dentry, mode, 0); 70 } 71 72 static int minix_symlink(struct inode * dir, struct dentry *dentry, 73 const char * symname) 74 { 75 int err = -ENAMETOOLONG; 76 int i = strlen(symname)+1; 77 struct inode * inode; 78 79 if (i > dir->i_sb->s_blocksize) 80 goto out; 81 82 inode = minix_new_inode(dir, S_IFLNK | 0777, &err); 83 if (!inode) 84 goto out; 85 86 minix_set_inode(inode, 0); 87 err = page_symlink(inode, symname, i); 88 if (err) 89 goto out_fail; 90 91 err = add_nondir(dentry, inode); 92 out: 93 return err; 94 95 out_fail: 96 inode_dec_link_count(inode); 97 iput(inode); 98 goto out; 99 } 100 101 static int minix_link(struct dentry * old_dentry, struct inode * dir, 102 struct dentry *dentry) 103 { 104 struct inode *inode = d_inode(old_dentry); 105 106 inode->i_ctime = current_time(inode); 107 inode_inc_link_count(inode); 108 ihold(inode); 109 return add_nondir(dentry, inode); 110 } 111 112 static int minix_mkdir(struct inode * dir, struct dentry *dentry, umode_t mode) 113 { 114 struct inode * inode; 115 int err; 116 117 inode_inc_link_count(dir); 118 119 inode = minix_new_inode(dir, S_IFDIR | mode, &err); 120 if (!inode) 121 goto out_dir; 122 123 minix_set_inode(inode, 0); 124 125 inode_inc_link_count(inode); 126 127 err = minix_make_empty(inode, dir); 128 if (err) 129 goto out_fail; 130 131 err = minix_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 minix_unlink(struct inode * dir, struct dentry *dentry) 149 { 150 int err = -ENOENT; 151 struct inode * inode = d_inode(dentry); 152 struct page * page; 153 struct minix_dir_entry * de; 154 155 de = minix_find_entry(dentry, &page); 156 if (!de) 157 goto end_unlink; 158 159 err = minix_delete_entry(de, page); 160 if (err) 161 goto end_unlink; 162 163 inode->i_ctime = dir->i_ctime; 164 inode_dec_link_count(inode); 165 end_unlink: 166 return err; 167 } 168 169 static int minix_rmdir(struct inode * dir, struct dentry *dentry) 170 { 171 struct inode * inode = d_inode(dentry); 172 int err = -ENOTEMPTY; 173 174 if (minix_empty_dir(inode)) { 175 err = minix_unlink(dir, dentry); 176 if (!err) { 177 inode_dec_link_count(dir); 178 inode_dec_link_count(inode); 179 } 180 } 181 return err; 182 } 183 184 static int minix_rename(struct inode * old_dir, struct dentry *old_dentry, 185 struct inode * new_dir, struct dentry *new_dentry, 186 unsigned int flags) 187 { 188 struct inode * old_inode = d_inode(old_dentry); 189 struct inode * new_inode = d_inode(new_dentry); 190 struct page * dir_page = NULL; 191 struct minix_dir_entry * dir_de = NULL; 192 struct page * old_page; 193 struct minix_dir_entry * old_de; 194 int err = -ENOENT; 195 196 if (flags & ~RENAME_NOREPLACE) 197 return -EINVAL; 198 199 old_de = minix_find_entry(old_dentry, &old_page); 200 if (!old_de) 201 goto out; 202 203 if (S_ISDIR(old_inode->i_mode)) { 204 err = -EIO; 205 dir_de = minix_dotdot(old_inode, &dir_page); 206 if (!dir_de) 207 goto out_old; 208 } 209 210 if (new_inode) { 211 struct page * new_page; 212 struct minix_dir_entry * new_de; 213 214 err = -ENOTEMPTY; 215 if (dir_de && !minix_empty_dir(new_inode)) 216 goto out_dir; 217 218 err = -ENOENT; 219 new_de = minix_find_entry(new_dentry, &new_page); 220 if (!new_de) 221 goto out_dir; 222 minix_set_link(new_de, new_page, old_inode); 223 new_inode->i_ctime = current_time(new_inode); 224 if (dir_de) 225 drop_nlink(new_inode); 226 inode_dec_link_count(new_inode); 227 } else { 228 err = minix_add_link(new_dentry, old_inode); 229 if (err) 230 goto out_dir; 231 if (dir_de) 232 inode_inc_link_count(new_dir); 233 } 234 235 minix_delete_entry(old_de, old_page); 236 mark_inode_dirty(old_inode); 237 238 if (dir_de) { 239 minix_set_link(dir_de, dir_page, new_dir); 240 inode_dec_link_count(old_dir); 241 } 242 return 0; 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