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 | */ | |
549c7297 CB |
102 | static int ext2_create (struct user_namespace * mnt_userns, |
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 | ||
549c7297 CB |
122 | static int ext2_tmpfile(struct user_namespace *mnt_userns, struct inode *dir, |
123 | struct dentry *dentry, 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 AV |
130 | mark_inode_dirty(inode); |
131 | d_tmpfile(dentry, inode); | |
132 | unlock_new_inode(inode); | |
133 | return 0; | |
134 | } | |
135 | ||
549c7297 CB |
136 | static int ext2_mknod (struct user_namespace * mnt_userns, struct inode * dir, |
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 | ||
549c7297 CB |
157 | static int ext2_symlink (struct user_namespace * mnt_userns, struct inode * dir, |
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); |
1da177e4 LT |
181 | if (test_opt(inode->i_sb, NOBH)) |
182 | inode->i_mapping->a_ops = &ext2_nobh_aops; | |
183 | else | |
184 | inode->i_mapping->a_ops = &ext2_aops; | |
185 | err = page_symlink(inode, symname, l); | |
186 | if (err) | |
187 | goto out_fail; | |
188 | } else { | |
189 | /* fast symlink */ | |
190 | inode->i_op = &ext2_fast_symlink_inode_operations; | |
cbe0fa38 AV |
191 | inode->i_link = (char*)EXT2_I(inode)->i_data; |
192 | memcpy(inode->i_link, symname, l); | |
1da177e4 LT |
193 | inode->i_size = l-1; |
194 | } | |
195 | mark_inode_dirty(inode); | |
196 | ||
197 | err = ext2_add_nondir(dentry, inode); | |
198 | out: | |
199 | return err; | |
200 | ||
201 | out_fail: | |
a513b035 | 202 | inode_dec_link_count(inode); |
2e5afe54 | 203 | discard_new_inode(inode); |
1da177e4 LT |
204 | goto out; |
205 | } | |
206 | ||
207 | static int ext2_link (struct dentry * old_dentry, struct inode * dir, | |
208 | struct dentry *dentry) | |
209 | { | |
2b0143b5 | 210 | struct inode *inode = d_inode(old_dentry); |
41080b5a | 211 | int err; |
1da177e4 | 212 | |
c2edb305 JK |
213 | err = dquot_initialize(dir); |
214 | if (err) | |
215 | return err; | |
907f4554 | 216 | |
02027d42 | 217 | inode->i_ctime = current_time(inode); |
a513b035 | 218 | inode_inc_link_count(inode); |
7de9c6ee | 219 | ihold(inode); |
1da177e4 | 220 | |
41080b5a AV |
221 | err = ext2_add_link(dentry, inode); |
222 | if (!err) { | |
223 | d_instantiate(dentry, inode); | |
224 | return 0; | |
225 | } | |
226 | inode_dec_link_count(inode); | |
227 | iput(inode); | |
228 | return err; | |
1da177e4 LT |
229 | } |
230 | ||
549c7297 CB |
231 | static int ext2_mkdir(struct user_namespace * mnt_userns, |
232 | struct inode * dir, struct dentry * dentry, umode_t mode) | |
1da177e4 LT |
233 | { |
234 | struct inode * inode; | |
8de52778 | 235 | int err; |
1da177e4 | 236 | |
c2edb305 JK |
237 | err = dquot_initialize(dir); |
238 | if (err) | |
239 | return err; | |
907f4554 | 240 | |
a513b035 | 241 | inode_inc_link_count(dir); |
1da177e4 | 242 | |
2a7dba39 | 243 | inode = ext2_new_inode(dir, S_IFDIR | mode, &dentry->d_name); |
1da177e4 LT |
244 | err = PTR_ERR(inode); |
245 | if (IS_ERR(inode)) | |
246 | goto out_dir; | |
247 | ||
248 | inode->i_op = &ext2_dir_inode_operations; | |
249 | inode->i_fop = &ext2_dir_operations; | |
250 | if (test_opt(inode->i_sb, NOBH)) | |
251 | inode->i_mapping->a_ops = &ext2_nobh_aops; | |
252 | else | |
253 | inode->i_mapping->a_ops = &ext2_aops; | |
254 | ||
a513b035 | 255 | inode_inc_link_count(inode); |
1da177e4 LT |
256 | |
257 | err = ext2_make_empty(inode, dir); | |
258 | if (err) | |
259 | goto out_fail; | |
260 | ||
261 | err = ext2_add_link(dentry, inode); | |
262 | if (err) | |
263 | goto out_fail; | |
264 | ||
1e2e547a | 265 | d_instantiate_new(dentry, inode); |
1da177e4 LT |
266 | out: |
267 | return err; | |
268 | ||
269 | out_fail: | |
a513b035 AD |
270 | inode_dec_link_count(inode); |
271 | inode_dec_link_count(inode); | |
2e5afe54 | 272 | discard_new_inode(inode); |
1da177e4 | 273 | out_dir: |
a513b035 | 274 | inode_dec_link_count(dir); |
1da177e4 LT |
275 | goto out; |
276 | } | |
277 | ||
278 | static int ext2_unlink(struct inode * dir, struct dentry *dentry) | |
279 | { | |
2b0143b5 | 280 | struct inode * inode = d_inode(dentry); |
1da177e4 LT |
281 | struct ext2_dir_entry_2 * de; |
282 | struct page * page; | |
782b76d7 | 283 | void *page_addr; |
c2edb305 | 284 | int err; |
1da177e4 | 285 | |
c2edb305 JK |
286 | err = dquot_initialize(dir); |
287 | if (err) | |
288 | goto out; | |
907f4554 | 289 | |
782b76d7 | 290 | de = ext2_find_entry(dir, &dentry->d_name, &page, &page_addr); |
b4962091 | 291 | if (IS_ERR(de)) { |
292 | err = PTR_ERR(de); | |
293 | goto out; | |
294 | } | |
1da177e4 LT |
295 | |
296 | err = ext2_delete_entry (de, page); | |
782b76d7 | 297 | ext2_put_page(page, page_addr); |
1da177e4 LT |
298 | if (err) |
299 | goto out; | |
300 | ||
301 | inode->i_ctime = dir->i_ctime; | |
a513b035 | 302 | inode_dec_link_count(inode); |
1da177e4 LT |
303 | err = 0; |
304 | out: | |
305 | return err; | |
306 | } | |
307 | ||
308 | static int ext2_rmdir (struct inode * dir, struct dentry *dentry) | |
309 | { | |
2b0143b5 | 310 | struct inode * inode = d_inode(dentry); |
1da177e4 LT |
311 | int err = -ENOTEMPTY; |
312 | ||
313 | if (ext2_empty_dir(inode)) { | |
314 | err = ext2_unlink(dir, dentry); | |
315 | if (!err) { | |
316 | inode->i_size = 0; | |
a513b035 AD |
317 | inode_dec_link_count(inode); |
318 | inode_dec_link_count(dir); | |
1da177e4 LT |
319 | } |
320 | } | |
321 | return err; | |
322 | } | |
323 | ||
549c7297 CB |
324 | static int ext2_rename (struct user_namespace * mnt_userns, |
325 | struct inode * old_dir, struct dentry * old_dentry, | |
326 | struct inode * new_dir, struct dentry * new_dentry, | |
f03b8ad8 | 327 | unsigned int flags) |
1da177e4 | 328 | { |
2b0143b5 DH |
329 | struct inode * old_inode = d_inode(old_dentry); |
330 | struct inode * new_inode = d_inode(new_dentry); | |
1da177e4 | 331 | struct page * dir_page = NULL; |
782b76d7 | 332 | void *dir_page_addr; |
1da177e4 LT |
333 | struct ext2_dir_entry_2 * dir_de = NULL; |
334 | struct page * old_page; | |
782b76d7 | 335 | void *old_page_addr; |
1da177e4 | 336 | struct ext2_dir_entry_2 * old_de; |
c2edb305 | 337 | int err; |
1da177e4 | 338 | |
f03b8ad8 MS |
339 | if (flags & ~RENAME_NOREPLACE) |
340 | return -EINVAL; | |
341 | ||
c2edb305 JK |
342 | err = dquot_initialize(old_dir); |
343 | if (err) | |
344 | goto out; | |
345 | ||
346 | err = dquot_initialize(new_dir); | |
347 | if (err) | |
348 | goto out; | |
907f4554 | 349 | |
782b76d7 IW |
350 | old_de = ext2_find_entry(old_dir, &old_dentry->d_name, &old_page, |
351 | &old_page_addr); | |
b4962091 | 352 | if (IS_ERR(old_de)) { |
353 | err = PTR_ERR(old_de); | |
354 | goto out; | |
355 | } | |
1da177e4 LT |
356 | |
357 | if (S_ISDIR(old_inode->i_mode)) { | |
358 | err = -EIO; | |
782b76d7 | 359 | dir_de = ext2_dotdot(old_inode, &dir_page, &dir_page_addr); |
1da177e4 LT |
360 | if (!dir_de) |
361 | goto out_old; | |
362 | } | |
363 | ||
364 | if (new_inode) { | |
782b76d7 | 365 | void *page_addr; |
1da177e4 LT |
366 | struct page *new_page; |
367 | struct ext2_dir_entry_2 *new_de; | |
368 | ||
369 | err = -ENOTEMPTY; | |
370 | if (dir_de && !ext2_empty_dir (new_inode)) | |
371 | goto out_dir; | |
372 | ||
782b76d7 IW |
373 | new_de = ext2_find_entry(new_dir, &new_dentry->d_name, |
374 | &new_page, &page_addr); | |
b4962091 | 375 | if (IS_ERR(new_de)) { |
376 | err = PTR_ERR(new_de); | |
377 | goto out_dir; | |
378 | } | |
782b76d7 IW |
379 | ext2_set_link(new_dir, new_de, new_page, page_addr, old_inode, 1); |
380 | ext2_put_page(new_page, page_addr); | |
02027d42 | 381 | new_inode->i_ctime = current_time(new_inode); |
1da177e4 | 382 | if (dir_de) |
9a53c3a7 | 383 | drop_nlink(new_inode); |
a513b035 | 384 | inode_dec_link_count(new_inode); |
1da177e4 | 385 | } else { |
1da177e4 | 386 | err = ext2_add_link(new_dentry, old_inode); |
e8a80c6f | 387 | if (err) |
1da177e4 | 388 | goto out_dir; |
1da177e4 | 389 | if (dir_de) |
a513b035 | 390 | inode_inc_link_count(new_dir); |
1da177e4 LT |
391 | } |
392 | ||
393 | /* | |
394 | * Like most other Unix systems, set the ctime for inodes on a | |
395 | * rename. | |
1da177e4 | 396 | */ |
02027d42 | 397 | old_inode->i_ctime = current_time(old_inode); |
e8a80c6f | 398 | mark_inode_dirty(old_inode); |
1da177e4 | 399 | |
782b76d7 | 400 | ext2_delete_entry(old_de, old_page); |
1da177e4 LT |
401 | |
402 | if (dir_de) { | |
39fe7557 | 403 | if (old_dir != new_dir) |
782b76d7 IW |
404 | ext2_set_link(old_inode, dir_de, dir_page, |
405 | dir_page_addr, new_dir, 0); | |
e2ebb123 | 406 | |
782b76d7 | 407 | ext2_put_page(dir_page, dir_page_addr); |
a513b035 | 408 | inode_dec_link_count(old_dir); |
1da177e4 | 409 | } |
1da177e4 | 410 | |
782b76d7 IW |
411 | ext2_put_page(old_page, old_page_addr); |
412 | return 0; | |
1da177e4 LT |
413 | |
414 | out_dir: | |
a6fbd0ab | 415 | if (dir_de) |
782b76d7 | 416 | ext2_put_page(dir_page, dir_page_addr); |
1da177e4 | 417 | out_old: |
782b76d7 | 418 | ext2_put_page(old_page, old_page_addr); |
1da177e4 LT |
419 | out: |
420 | return err; | |
421 | } | |
422 | ||
754661f1 | 423 | const struct inode_operations ext2_dir_inode_operations = { |
1da177e4 LT |
424 | .create = ext2_create, |
425 | .lookup = ext2_lookup, | |
426 | .link = ext2_link, | |
427 | .unlink = ext2_unlink, | |
428 | .symlink = ext2_symlink, | |
429 | .mkdir = ext2_mkdir, | |
430 | .rmdir = ext2_rmdir, | |
431 | .mknod = ext2_mknod, | |
432 | .rename = ext2_rename, | |
1da177e4 | 433 | .listxattr = ext2_listxattr, |
93bc420e | 434 | .getattr = ext2_getattr, |
1da177e4 | 435 | .setattr = ext2_setattr, |
4e34e719 | 436 | .get_acl = ext2_get_acl, |
64e178a7 | 437 | .set_acl = ext2_set_acl, |
60545d0d | 438 | .tmpfile = ext2_tmpfile, |
aba405e3 MS |
439 | .fileattr_get = ext2_fileattr_get, |
440 | .fileattr_set = ext2_fileattr_set, | |
1da177e4 LT |
441 | }; |
442 | ||
754661f1 | 443 | const struct inode_operations ext2_special_inode_operations = { |
1da177e4 | 444 | .listxattr = ext2_listxattr, |
93bc420e | 445 | .getattr = ext2_getattr, |
1da177e4 | 446 | .setattr = ext2_setattr, |
4e34e719 | 447 | .get_acl = ext2_get_acl, |
64e178a7 | 448 | .set_acl = ext2_set_acl, |
1da177e4 | 449 | }; |