blob: 937fa5fae2b8e2ffdddcc120a9cebfff46bf81d8 [file] [log] [blame]
Greg Kroah-Hartmanb2441312017-11-01 15:07:57 +01001// SPDX-License-Identifier: GPL-2.0
Linus Torvalds1da177e2005-04-16 15:20:36 -07002/*
3 * linux/fs/minix/namei.c
4 *
5 * Copyright (C) 1991, 1992 Linus Torvalds
6 */
7
8#include "minix.h"
9
Linus Torvalds1da177e2005-04-16 15:20:36 -070010static 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 }
Alexey Dobriyan78ec7b62006-03-23 03:00:51 -080017 inode_dec_link_count(inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -070018 iput(inode);
19 return err;
20}
21
Al Viro00cd8dd2012-06-10 17:13:09 -040022static struct dentry *minix_lookup(struct inode * dir, struct dentry *dentry, unsigned int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -070023{
24 struct inode * inode = NULL;
25 ino_t ino;
26
Linus Torvalds1da177e2005-04-16 15:20:36 -070027 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);
Al Virob0149512018-04-30 19:57:34 -040031 if (ino)
David Howellsa90a08802008-02-07 00:15:44 -080032 inode = minix_iget(dir->i_sb, ino);
Al Virob0149512018-04-30 19:57:34 -040033 return d_splice_alias(inode, dentry);
Linus Torvalds1da177e2005-04-16 15:20:36 -070034}
35
Christian Brauner549c7292021-01-21 14:19:43 +010036static int minix_mknod(struct user_namespace *mnt_userns, struct inode *dir,
37 struct dentry *dentry, umode_t mode, dev_t rdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -070038{
39 int error;
40 struct inode *inode;
41
42 if (!old_valid_dev(rdev))
43 return -EINVAL;
44
Dmitry Monakhov9eed1fb2010-03-04 17:32:14 +030045 inode = minix_new_inode(dir, mode, &error);
Linus Torvalds1da177e2005-04-16 15:20:36 -070046
47 if (inode) {
Linus Torvalds1da177e2005-04-16 15:20:36 -070048 minix_set_inode(inode, rdev);
49 mark_inode_dirty(inode);
50 error = add_nondir(dentry, inode);
51 }
52 return error;
53}
54
Christian Brauner549c7292021-01-21 14:19:43 +010055static int minix_tmpfile(struct user_namespace *mnt_userns, struct inode *dir,
56 struct dentry *dentry, umode_t mode)
Al Viro60545d02013-06-07 01:20:27 -040057{
58 int error;
59 struct inode *inode = minix_new_inode(dir, mode, &error);
60 if (inode) {
61 minix_set_inode(inode, 0);
62 mark_inode_dirty(inode);
63 d_tmpfile(dentry, inode);
64 }
65 return error;
66}
67
Christian Brauner549c7292021-01-21 14:19:43 +010068static int minix_create(struct user_namespace *mnt_userns, struct inode *dir,
69 struct dentry *dentry, umode_t mode, bool excl)
Linus Torvalds1da177e2005-04-16 15:20:36 -070070{
Christian Brauner549c7292021-01-21 14:19:43 +010071 return minix_mknod(mnt_userns, dir, dentry, mode, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070072}
73
Christian Brauner549c7292021-01-21 14:19:43 +010074static int minix_symlink(struct user_namespace *mnt_userns, struct inode *dir,
75 struct dentry *dentry, const char *symname)
Linus Torvalds1da177e2005-04-16 15:20:36 -070076{
77 int err = -ENAMETOOLONG;
78 int i = strlen(symname)+1;
79 struct inode * inode;
80
81 if (i > dir->i_sb->s_blocksize)
82 goto out;
83
Dmitry Monakhov9eed1fb2010-03-04 17:32:14 +030084 inode = minix_new_inode(dir, S_IFLNK | 0777, &err);
Linus Torvalds1da177e2005-04-16 15:20:36 -070085 if (!inode)
86 goto out;
87
Linus Torvalds1da177e2005-04-16 15:20:36 -070088 minix_set_inode(inode, 0);
89 err = page_symlink(inode, symname, i);
90 if (err)
91 goto out_fail;
92
93 err = add_nondir(dentry, inode);
94out:
95 return err;
96
97out_fail:
Alexey Dobriyan78ec7b62006-03-23 03:00:51 -080098 inode_dec_link_count(inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -070099 iput(inode);
100 goto out;
101}
102
103static int minix_link(struct dentry * old_dentry, struct inode * dir,
104 struct dentry *dentry)
105{
David Howells2b0143b2015-03-17 22:25:59 +0000106 struct inode *inode = d_inode(old_dentry);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700107
Deepa Dinamani02027d42016-09-14 07:48:05 -0700108 inode->i_ctime = current_time(inode);
Alexey Dobriyan78ec7b62006-03-23 03:00:51 -0800109 inode_inc_link_count(inode);
Al Viro7de9c6ee2010-10-23 11:11:40 -0400110 ihold(inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700111 return add_nondir(dentry, inode);
112}
113
Christian Brauner549c7292021-01-21 14:19:43 +0100114static int minix_mkdir(struct user_namespace *mnt_userns, struct inode *dir,
115 struct dentry *dentry, umode_t mode)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700116{
117 struct inode * inode;
Al Viro8de52772012-02-06 12:45:27 -0500118 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700119
Alexey Dobriyan78ec7b62006-03-23 03:00:51 -0800120 inode_inc_link_count(dir);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700121
Jorge Boncompte [DTI2]eee743f2010-09-09 16:38:19 -0700122 inode = minix_new_inode(dir, S_IFDIR | mode, &err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700123 if (!inode)
124 goto out_dir;
125
Linus Torvalds1da177e2005-04-16 15:20:36 -0700126 minix_set_inode(inode, 0);
127
Alexey Dobriyan78ec7b62006-03-23 03:00:51 -0800128 inode_inc_link_count(inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700129
130 err = minix_make_empty(inode, dir);
131 if (err)
132 goto out_fail;
133
134 err = minix_add_link(dentry, inode);
135 if (err)
136 goto out_fail;
137
138 d_instantiate(dentry, inode);
139out:
140 return err;
141
142out_fail:
Alexey Dobriyan78ec7b62006-03-23 03:00:51 -0800143 inode_dec_link_count(inode);
144 inode_dec_link_count(inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700145 iput(inode);
146out_dir:
Alexey Dobriyan78ec7b62006-03-23 03:00:51 -0800147 inode_dec_link_count(dir);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700148 goto out;
149}
150
151static int minix_unlink(struct inode * dir, struct dentry *dentry)
152{
153 int err = -ENOENT;
David Howells2b0143b2015-03-17 22:25:59 +0000154 struct inode * inode = d_inode(dentry);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700155 struct page * page;
156 struct minix_dir_entry * de;
157
158 de = minix_find_entry(dentry, &page);
159 if (!de)
160 goto end_unlink;
161
162 err = minix_delete_entry(de, page);
163 if (err)
164 goto end_unlink;
165
166 inode->i_ctime = dir->i_ctime;
Alexey Dobriyan78ec7b62006-03-23 03:00:51 -0800167 inode_dec_link_count(inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700168end_unlink:
169 return err;
170}
171
172static int minix_rmdir(struct inode * dir, struct dentry *dentry)
173{
David Howells2b0143b2015-03-17 22:25:59 +0000174 struct inode * inode = d_inode(dentry);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700175 int err = -ENOTEMPTY;
176
177 if (minix_empty_dir(inode)) {
178 err = minix_unlink(dir, dentry);
179 if (!err) {
Alexey Dobriyan78ec7b62006-03-23 03:00:51 -0800180 inode_dec_link_count(dir);
181 inode_dec_link_count(inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700182 }
183 }
184 return err;
185}
186
Christian Brauner549c7292021-01-21 14:19:43 +0100187static int minix_rename(struct user_namespace *mnt_userns,
188 struct inode *old_dir, struct dentry *old_dentry,
189 struct inode *new_dir, struct dentry *new_dentry,
Miklos Szeredif03b8ad2016-09-27 11:03:57 +0200190 unsigned int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700191{
David Howells2b0143b2015-03-17 22:25:59 +0000192 struct inode * old_inode = d_inode(old_dentry);
193 struct inode * new_inode = d_inode(new_dentry);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700194 struct page * dir_page = NULL;
195 struct minix_dir_entry * dir_de = NULL;
196 struct page * old_page;
197 struct minix_dir_entry * old_de;
198 int err = -ENOENT;
199
Miklos Szeredif03b8ad2016-09-27 11:03:57 +0200200 if (flags & ~RENAME_NOREPLACE)
201 return -EINVAL;
202
Linus Torvalds1da177e2005-04-16 15:20:36 -0700203 old_de = minix_find_entry(old_dentry, &old_page);
204 if (!old_de)
205 goto out;
206
207 if (S_ISDIR(old_inode->i_mode)) {
208 err = -EIO;
209 dir_de = minix_dotdot(old_inode, &dir_page);
210 if (!dir_de)
211 goto out_old;
212 }
213
214 if (new_inode) {
215 struct page * new_page;
216 struct minix_dir_entry * new_de;
217
218 err = -ENOTEMPTY;
219 if (dir_de && !minix_empty_dir(new_inode))
220 goto out_dir;
221
222 err = -ENOENT;
223 new_de = minix_find_entry(new_dentry, &new_page);
224 if (!new_de)
225 goto out_dir;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700226 minix_set_link(new_de, new_page, old_inode);
Deepa Dinamani02027d42016-09-14 07:48:05 -0700227 new_inode->i_ctime = current_time(new_inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700228 if (dir_de)
Dave Hansen9a53c3a2006-09-30 23:29:03 -0700229 drop_nlink(new_inode);
Alexey Dobriyan78ec7b62006-03-23 03:00:51 -0800230 inode_dec_link_count(new_inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700231 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700232 err = minix_add_link(new_dentry, old_inode);
Al Viro6f880492011-03-02 09:41:38 -0500233 if (err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700234 goto out_dir;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700235 if (dir_de)
Alexey Dobriyan78ec7b62006-03-23 03:00:51 -0800236 inode_inc_link_count(new_dir);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700237 }
238
239 minix_delete_entry(old_de, old_page);
Al Viro6f880492011-03-02 09:41:38 -0500240 mark_inode_dirty(old_inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700241
242 if (dir_de) {
243 minix_set_link(dir_de, dir_page, new_dir);
Alexey Dobriyan78ec7b62006-03-23 03:00:51 -0800244 inode_dec_link_count(old_dir);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700245 }
246 return 0;
247
248out_dir:
249 if (dir_de) {
250 kunmap(dir_page);
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +0300251 put_page(dir_page);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700252 }
253out_old:
254 kunmap(old_page);
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +0300255 put_page(old_page);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700256out:
257 return err;
258}
259
260/*
261 * directories can handle most operations...
262 */
Arjan van de Ven92e1d5b2007-02-12 00:55:39 -0800263const struct inode_operations minix_dir_inode_operations = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700264 .create = minix_create,
265 .lookup = minix_lookup,
266 .link = minix_link,
267 .unlink = minix_unlink,
268 .symlink = minix_symlink,
269 .mkdir = minix_mkdir,
270 .rmdir = minix_rmdir,
271 .mknod = minix_mknod,
272 .rename = minix_rename,
273 .getattr = minix_getattr,
Al Viro60545d02013-06-07 01:20:27 -0400274 .tmpfile = minix_tmpfile,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700275};