xref: /linux/fs/minix/namei.c (revision 2b64b2ed277ff23e785fbdb65098ee7e1252d64f)
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