Commit | Line | Data |
---|---|---|
b2441318 | 1 | // SPDX-License-Identifier: GPL-2.0 |
1da177e4 LT |
2 | /* |
3 | * linux/fs/ext2/namei.c | |
4 | * | |
5 | * Rewrite to pagecache. Almost all code had been changed, so blame me | |
6 | * if the things go wrong. Please, send bug reports to | |
7 | * viro@parcelfarce.linux.theplanet.co.uk | |
8 | * | |
9 | * Stuff here is basically a glue between the VFS and generic UNIXish | |
10 | * filesystem that keeps everything in pagecache. All knowledge of the | |
11 | * directory layout is in fs/ext2/dir.c - it turned out to be easily separatable | |
12 | * and it's easier to debug that way. In principle we might want to | |
13 | * generalize that a bit and turn it into a library. Or not. | |
14 | * | |
15 | * The only non-static object here is ext2_dir_inode_operations. | |
16 | * | |
17 | * TODO: get rid of kmap() use, add readahead. | |
18 | * | |
19 | * Copyright (C) 1992, 1993, 1994, 1995 | |
20 | * Remy Card (card@masi.ibp.fr) | |
21 | * Laboratoire MASI - Institut Blaise Pascal | |
22 | * Universite Pierre et Marie Curie (Paris VI) | |
23 | * | |
24 | * from | |
25 | * | |
26 | * linux/fs/minix/namei.c | |
27 | * | |
28 | * Copyright (C) 1991, 1992 Linus Torvalds | |
29 | * | |
30 | * Big-endian to little-endian byte-swapping/bitmaps by | |
31 | * David S. Miller (davem@caip.rutgers.edu), 1995 | |
32 | */ | |
33 | ||
34 | #include <linux/pagemap.h> | |
907f4554 | 35 | #include <linux/quotaops.h> |
1da177e4 LT |
36 | #include "ext2.h" |
37 | #include "xattr.h" | |
38 | #include "acl.h" | |
39 | ||
1da177e4 LT |
40 | static inline int ext2_add_nondir(struct dentry *dentry, struct inode *inode) |
41 | { | |
42 | int err = ext2_add_link(dentry, inode); | |
43 | if (!err) { | |
1e2e547a | 44 | d_instantiate_new(dentry, inode); |
1da177e4 LT |
45 | return 0; |
46 | } | |
a513b035 | 47 | inode_dec_link_count(inode); |
2e5afe54 | 48 | discard_new_inode(inode); |
1da177e4 LT |
49 | return err; |
50 | } | |
51 | ||
52 | /* | |
53 | * Methods themselves. | |
54 | */ | |
55 | ||
00cd8dd3 | 56 | static struct dentry *ext2_lookup(struct inode * dir, struct dentry *dentry, unsigned int flags) |
1da177e4 LT |
57 | { |
58 | struct inode * inode; | |
a43850a3 | 59 | ino_t ino; |
b4962091 | 60 | int res; |
1da177e4 LT |
61 | |
62 | if (dentry->d_name.len > EXT2_NAME_LEN) | |
63 | return ERR_PTR(-ENAMETOOLONG); | |
64 | ||
b4962091 | 65 | res = ext2_inode_by_name(dir, &dentry->d_name, &ino); |
a43850a3 | 66 | if (res) { |
67 | if (res != -ENOENT) | |
68 | return ERR_PTR(res); | |
69 | inode = NULL; | |
70 | } else { | |
52fcf703 | 71 | inode = ext2_iget(dir->i_sb, ino); |
a9049376 AV |
72 | if (inode == ERR_PTR(-ESTALE)) { |
73 | ext2_error(dir->i_sb, __func__, | |
74 | "deleted inode referenced: %lu", | |
75 | (unsigned long) ino); | |
76 | return ERR_PTR(-EIO); | |
4d6c13f8 | 77 | } |
1da177e4 | 78 | } |
082a05c6 | 79 | return d_splice_alias(inode, dentry); |
1da177e4 LT |
80 | } |
81 | ||
82 | struct dentry *ext2_get_parent(struct dentry *child) | |
83 | { | |
a43850a3 | 84 | ino_t ino; |
b4962091 | 85 | int res; |
86 | ||
80e5d1ff | 87 | res = ext2_inode_by_name(d_inode(child), &dotdot_name, &ino); |
b4962091 | 88 | if (res) |
89 | return ERR_PTR(res); | |
a43850a3 | 90 | |
fc64005c | 91 | return d_obtain_alias(ext2_iget(child->d_sb, ino)); |
1da177e4 LT |
92 | } |
93 | ||
94 | /* | |
95 | * By the time this is called, we already have created | |
96 | * the directory cache entry for the new file, but it | |
97 | * is so far negative - it has no inode. | |
98 | * | |
99 | * If the create succeeds, we fill in the inode information | |
100 | * with d_instantiate(). | |
101 | */ | |
6c960e68 | 102 | static int ext2_create (struct mnt_idmap * idmap, |
549c7297 CB |
103 | struct inode * dir, struct dentry * dentry, |
104 | umode_t mode, bool excl) | |
1da177e4 | 105 | { |
907f4554 | 106 | struct inode *inode; |
c2edb305 | 107 | int err; |
907f4554 | 108 | |
c2edb305 JK |
109 | err = dquot_initialize(dir); |
110 | if (err) | |
111 | return err; | |
907f4554 | 112 | |
2a7dba39 | 113 | inode = ext2_new_inode(dir, mode, &dentry->d_name); |
907f4554 CH |
114 | if (IS_ERR(inode)) |
115 | return PTR_ERR(inode); | |
116 | ||
fb094c90 | 117 | ext2_set_file_ops(inode); |
907f4554 CH |
118 | mark_inode_dirty(inode); |
119 | return ext2_add_nondir(dentry, inode); | |
1da177e4 LT |
120 | } |
121 | ||
011e2b71 | 122 | static int ext2_tmpfile(struct mnt_idmap *idmap, struct inode *dir, |
863f144f | 123 | struct file *file, umode_t mode) |
60545d0d AV |
124 | { |
125 | struct inode *inode = ext2_new_inode(dir, mode, NULL); | |
126 | if (IS_ERR(inode)) | |
127 | return PTR_ERR(inode); | |
128 | ||
fb094c90 | 129 | ext2_set_file_ops(inode); |
60545d0d | 130 | mark_inode_dirty(inode); |
863f144f | 131 | d_tmpfile(file, inode); |
60545d0d | 132 | unlock_new_inode(inode); |
863f144f | 133 | return finish_open_simple(file, 0); |
60545d0d AV |
134 | } |
135 | ||
5ebb29be | 136 | static int ext2_mknod (struct mnt_idmap * idmap, struct inode * dir, |
549c7297 | 137 | struct dentry *dentry, umode_t mode, dev_t rdev) |
1da177e4 LT |
138 | { |
139 | struct inode * inode; | |
140 | int err; | |
141 | ||
c2edb305 JK |
142 | err = dquot_initialize(dir); |
143 | if (err) | |
144 | return err; | |
907f4554 | 145 | |
2a7dba39 | 146 | inode = ext2_new_inode (dir, mode, &dentry->d_name); |
1da177e4 LT |
147 | err = PTR_ERR(inode); |
148 | if (!IS_ERR(inode)) { | |
149 | init_special_inode(inode, inode->i_mode, rdev); | |
1da177e4 | 150 | inode->i_op = &ext2_special_inode_operations; |
1da177e4 LT |
151 | mark_inode_dirty(inode); |
152 | err = ext2_add_nondir(dentry, inode); | |
153 | } | |
154 | return err; | |
155 | } | |
156 | ||
7a77db95 | 157 | static int ext2_symlink (struct mnt_idmap * idmap, struct inode * dir, |
549c7297 | 158 | struct dentry * dentry, const char * symname) |
1da177e4 LT |
159 | { |
160 | struct super_block * sb = dir->i_sb; | |
161 | int err = -ENAMETOOLONG; | |
162 | unsigned l = strlen(symname)+1; | |
163 | struct inode * inode; | |
164 | ||
165 | if (l > sb->s_blocksize) | |
166 | goto out; | |
167 | ||
c2edb305 JK |
168 | err = dquot_initialize(dir); |
169 | if (err) | |
170 | goto out; | |
907f4554 | 171 | |
2a7dba39 | 172 | inode = ext2_new_inode (dir, S_IFLNK | S_IRWXUGO, &dentry->d_name); |
1da177e4 LT |
173 | err = PTR_ERR(inode); |
174 | if (IS_ERR(inode)) | |
175 | goto out; | |
176 | ||
177 | if (l > sizeof (EXT2_I(inode)->i_data)) { | |
178 | /* slow symlink */ | |
179 | inode->i_op = &ext2_symlink_inode_operations; | |
21fc61c7 | 180 | inode_nohighmem(inode); |
0cc5b4ce | 181 | inode->i_mapping->a_ops = &ext2_aops; |
1da177e4 LT |
182 | err = page_symlink(inode, symname, l); |
183 | if (err) | |
184 | goto out_fail; | |
185 | } else { | |
186 | /* fast symlink */ | |
187 | inode->i_op = &ext2_fast_symlink_inode_operations; | |
cbe0fa38 AV |
188 | inode->i_link = (char*)EXT2_I(inode)->i_data; |
189 | memcpy(inode->i_link, symname, l); | |
1da177e4 LT |
190 | inode->i_size = l-1; |
191 | } | |
192 | mark_inode_dirty(inode); | |
193 | ||
194 | err = ext2_add_nondir(dentry, inode); | |
195 | out: | |
196 | return err; | |
197 | ||
198 | out_fail: | |
a513b035 | 199 | inode_dec_link_count(inode); |
2e5afe54 | 200 | discard_new_inode(inode); |
1da177e4 LT |
201 | goto out; |
202 | } | |
203 | ||
204 | static int ext2_link (struct dentry * old_dentry, struct inode * dir, | |
205 | struct dentry *dentry) | |
206 | { | |
2b0143b5 | 207 | struct inode *inode = d_inode(old_dentry); |
41080b5a | 208 | int err; |
1da177e4 | 209 | |
c2edb305 JK |
210 | err = dquot_initialize(dir); |
211 | if (err) | |
212 | return err; | |
907f4554 | 213 | |
02027d42 | 214 | inode->i_ctime = current_time(inode); |
a513b035 | 215 | inode_inc_link_count(inode); |
7de9c6ee | 216 | ihold(inode); |
1da177e4 | 217 | |
41080b5a AV |
218 | err = ext2_add_link(dentry, inode); |
219 | if (!err) { | |
220 | d_instantiate(dentry, inode); | |
221 | return 0; | |
222 | } | |
223 | inode_dec_link_count(inode); | |
224 | iput(inode); | |
225 | return err; | |
1da177e4 LT |
226 | } |
227 | ||
c54bd91e | 228 | static int ext2_mkdir(struct mnt_idmap * idmap, |
549c7297 | 229 | struct inode * dir, struct dentry * dentry, umode_t mode) |
1da177e4 LT |
230 | { |
231 | struct inode * inode; | |
8de52778 | 232 | int err; |
1da177e4 | 233 | |
c2edb305 JK |
234 | err = dquot_initialize(dir); |
235 | if (err) | |
236 | return err; | |
907f4554 | 237 | |
a513b035 | 238 | inode_inc_link_count(dir); |
1da177e4 | 239 | |
2a7dba39 | 240 | inode = ext2_new_inode(dir, S_IFDIR | mode, &dentry->d_name); |
1da177e4 LT |
241 | err = PTR_ERR(inode); |
242 | if (IS_ERR(inode)) | |
243 | goto out_dir; | |
244 | ||
245 | inode->i_op = &ext2_dir_inode_operations; | |
246 | inode->i_fop = &ext2_dir_operations; | |
0cc5b4ce | 247 | inode->i_mapping->a_ops = &ext2_aops; |
1da177e4 | 248 | |
a513b035 | 249 | inode_inc_link_count(inode); |
1da177e4 LT |
250 | |
251 | err = ext2_make_empty(inode, dir); | |
252 | if (err) | |
253 | goto out_fail; | |
254 | ||
255 | err = ext2_add_link(dentry, inode); | |
256 | if (err) | |
257 | goto out_fail; | |
258 | ||
1e2e547a | 259 | d_instantiate_new(dentry, inode); |
1da177e4 LT |
260 | out: |
261 | return err; | |
262 | ||
263 | out_fail: | |
a513b035 AD |
264 | inode_dec_link_count(inode); |
265 | inode_dec_link_count(inode); | |
2e5afe54 | 266 | discard_new_inode(inode); |
1da177e4 | 267 | out_dir: |
a513b035 | 268 | inode_dec_link_count(dir); |
1da177e4 LT |
269 | goto out; |
270 | } | |
271 | ||
272 | static int ext2_unlink(struct inode * dir, struct dentry *dentry) | |
273 | { | |
2b0143b5 | 274 | struct inode * inode = d_inode(dentry); |
1da177e4 LT |
275 | struct ext2_dir_entry_2 * de; |
276 | struct page * page; | |
782b76d7 | 277 | void *page_addr; |
c2edb305 | 278 | int err; |
1da177e4 | 279 | |
c2edb305 JK |
280 | err = dquot_initialize(dir); |
281 | if (err) | |
282 | goto out; | |
907f4554 | 283 | |
782b76d7 | 284 | de = ext2_find_entry(dir, &dentry->d_name, &page, &page_addr); |
b4962091 | 285 | if (IS_ERR(de)) { |
286 | err = PTR_ERR(de); | |
287 | goto out; | |
288 | } | |
1da177e4 | 289 | |
728d392f | 290 | err = ext2_delete_entry (de, page, page_addr); |
782b76d7 | 291 | ext2_put_page(page, page_addr); |
1da177e4 LT |
292 | if (err) |
293 | goto out; | |
294 | ||
295 | inode->i_ctime = dir->i_ctime; | |
a513b035 | 296 | inode_dec_link_count(inode); |
1da177e4 LT |
297 | err = 0; |
298 | out: | |
299 | return err; | |
300 | } | |
301 | ||
302 | static int ext2_rmdir (struct inode * dir, struct dentry *dentry) | |
303 | { | |
2b0143b5 | 304 | struct inode * inode = d_inode(dentry); |
1da177e4 LT |
305 | int err = -ENOTEMPTY; |
306 | ||
307 | if (ext2_empty_dir(inode)) { | |
308 | err = ext2_unlink(dir, dentry); | |
309 | if (!err) { | |
310 | inode->i_size = 0; | |
a513b035 AD |
311 | inode_dec_link_count(inode); |
312 | inode_dec_link_count(dir); | |
1da177e4 LT |
313 | } |
314 | } | |
315 | return err; | |
316 | } | |
317 | ||
e18275ae | 318 | static int ext2_rename (struct mnt_idmap * idmap, |
549c7297 CB |
319 | struct inode * old_dir, struct dentry * old_dentry, |
320 | struct inode * new_dir, struct dentry * new_dentry, | |
f03b8ad8 | 321 | unsigned int flags) |
1da177e4 | 322 | { |
2b0143b5 DH |
323 | struct inode * old_inode = d_inode(old_dentry); |
324 | struct inode * new_inode = d_inode(new_dentry); | |
1da177e4 | 325 | struct page * dir_page = NULL; |
782b76d7 | 326 | void *dir_page_addr; |
1da177e4 LT |
327 | struct ext2_dir_entry_2 * dir_de = NULL; |
328 | struct page * old_page; | |
782b76d7 | 329 | void *old_page_addr; |
1da177e4 | 330 | struct ext2_dir_entry_2 * old_de; |
c2edb305 | 331 | int err; |
1da177e4 | 332 | |
f03b8ad8 MS |
333 | if (flags & ~RENAME_NOREPLACE) |
334 | return -EINVAL; | |
335 | ||
c2edb305 JK |
336 | err = dquot_initialize(old_dir); |
337 | if (err) | |
338 | goto out; | |
339 | ||
340 | err = dquot_initialize(new_dir); | |
341 | if (err) | |
342 | goto out; | |
907f4554 | 343 | |
782b76d7 IW |
344 | old_de = ext2_find_entry(old_dir, &old_dentry->d_name, &old_page, |
345 | &old_page_addr); | |
b4962091 | 346 | if (IS_ERR(old_de)) { |
347 | err = PTR_ERR(old_de); | |
348 | goto out; | |
349 | } | |
1da177e4 LT |
350 | |
351 | if (S_ISDIR(old_inode->i_mode)) { | |
352 | err = -EIO; | |
782b76d7 | 353 | dir_de = ext2_dotdot(old_inode, &dir_page, &dir_page_addr); |
1da177e4 LT |
354 | if (!dir_de) |
355 | goto out_old; | |
356 | } | |
357 | ||
358 | if (new_inode) { | |
782b76d7 | 359 | void *page_addr; |
1da177e4 LT |
360 | struct page *new_page; |
361 | struct ext2_dir_entry_2 *new_de; | |
362 | ||
363 | err = -ENOTEMPTY; | |
364 | if (dir_de && !ext2_empty_dir (new_inode)) | |
365 | goto out_dir; | |
366 | ||
782b76d7 IW |
367 | new_de = ext2_find_entry(new_dir, &new_dentry->d_name, |
368 | &new_page, &page_addr); | |
b4962091 | 369 | if (IS_ERR(new_de)) { |
370 | err = PTR_ERR(new_de); | |
371 | goto out_dir; | |
372 | } | |
7a5fa171 CH |
373 | err = ext2_set_link(new_dir, new_de, new_page, page_addr, |
374 | old_inode, true); | |
782b76d7 | 375 | ext2_put_page(new_page, page_addr); |
7a5fa171 CH |
376 | if (err) |
377 | goto out_dir; | |
02027d42 | 378 | new_inode->i_ctime = current_time(new_inode); |
1da177e4 | 379 | if (dir_de) |
9a53c3a7 | 380 | drop_nlink(new_inode); |
a513b035 | 381 | inode_dec_link_count(new_inode); |
1da177e4 | 382 | } else { |
1da177e4 | 383 | err = ext2_add_link(new_dentry, old_inode); |
e8a80c6f | 384 | if (err) |
1da177e4 | 385 | goto out_dir; |
1da177e4 | 386 | if (dir_de) |
a513b035 | 387 | inode_inc_link_count(new_dir); |
1da177e4 LT |
388 | } |
389 | ||
390 | /* | |
391 | * Like most other Unix systems, set the ctime for inodes on a | |
392 | * rename. | |
1da177e4 | 393 | */ |
02027d42 | 394 | old_inode->i_ctime = current_time(old_inode); |
e8a80c6f | 395 | mark_inode_dirty(old_inode); |
1da177e4 | 396 | |
728d392f | 397 | ext2_delete_entry(old_de, old_page, old_page_addr); |
1da177e4 LT |
398 | |
399 | if (dir_de) { | |
7a5fa171 CH |
400 | if (old_dir != new_dir) { |
401 | err = ext2_set_link(old_inode, dir_de, dir_page, | |
402 | dir_page_addr, new_dir, false); | |
e2ebb123 | 403 | |
7a5fa171 | 404 | } |
782b76d7 | 405 | ext2_put_page(dir_page, dir_page_addr); |
a513b035 | 406 | inode_dec_link_count(old_dir); |
1da177e4 | 407 | } |
1da177e4 | 408 | |
7a5fa171 | 409 | out_old: |
782b76d7 | 410 | ext2_put_page(old_page, old_page_addr); |
7a5fa171 CH |
411 | out: |
412 | return err; | |
1da177e4 LT |
413 | |
414 | out_dir: | |
a6fbd0ab | 415 | if (dir_de) |
782b76d7 | 416 | ext2_put_page(dir_page, dir_page_addr); |
7a5fa171 | 417 | goto out_old; |
1da177e4 LT |
418 | } |
419 | ||
754661f1 | 420 | const struct inode_operations ext2_dir_inode_operations = { |
1da177e4 LT |
421 | .create = ext2_create, |
422 | .lookup = ext2_lookup, | |
423 | .link = ext2_link, | |
424 | .unlink = ext2_unlink, | |
425 | .symlink = ext2_symlink, | |
426 | .mkdir = ext2_mkdir, | |
427 | .rmdir = ext2_rmdir, | |
428 | .mknod = ext2_mknod, | |
429 | .rename = ext2_rename, | |
1da177e4 | 430 | .listxattr = ext2_listxattr, |
93bc420e | 431 | .getattr = ext2_getattr, |
1da177e4 | 432 | .setattr = ext2_setattr, |
cac2f8b8 | 433 | .get_inode_acl = ext2_get_acl, |
64e178a7 | 434 | .set_acl = ext2_set_acl, |
60545d0d | 435 | .tmpfile = ext2_tmpfile, |
aba405e3 MS |
436 | .fileattr_get = ext2_fileattr_get, |
437 | .fileattr_set = ext2_fileattr_set, | |
1da177e4 LT |
438 | }; |
439 | ||
754661f1 | 440 | const struct inode_operations ext2_special_inode_operations = { |
1da177e4 | 441 | .listxattr = ext2_listxattr, |
93bc420e | 442 | .getattr = ext2_getattr, |
1da177e4 | 443 | .setattr = ext2_setattr, |
cac2f8b8 | 444 | .get_inode_acl = ext2_get_acl, |
64e178a7 | 445 | .set_acl = ext2_set_acl, |
1da177e4 | 446 | }; |