Merge branch 'spectre' of git://git.armlinux.org.uk/~rmk/linux-arm
[sfrench/cifs-2.6.git] / fs / minix / namei.c
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 };