ftp://ftp.kernel.org/pub/linux/kernel/v2.6/linux-2.6.6.tar.bz2
[linux-2.6.git] / fs / minix / namei.c
1 /*
2  *  linux/fs/minix/namei.c
3  *
4  *  Copyright (C) 1991, 1992  Linus Torvalds
5  */
6
7 #include "minix.h"
8
9 static inline void inc_count(struct inode *inode)
10 {
11         inode->i_nlink++;
12         mark_inode_dirty(inode);
13 }
14
15 static inline void dec_count(struct inode *inode)
16 {
17         inode->i_nlink--;
18         mark_inode_dirty(inode);
19 }
20
21 static int add_nondir(struct dentry *dentry, struct inode *inode)
22 {
23         int err = minix_add_link(dentry, inode);
24         if (!err) {
25                 d_instantiate(dentry, inode);
26                 return 0;
27         }
28         dec_count(inode);
29         iput(inode);
30         return err;
31 }
32
33 static int minix_hash(struct dentry *dentry, struct qstr *qstr)
34 {
35         unsigned long hash;
36         int i;
37         const unsigned char *name;
38
39         i = minix_sb(dentry->d_inode->i_sb)->s_namelen;
40         if (i >= qstr->len)
41                 return 0;
42         /* Truncate the name in place, avoids having to define a compare
43            function. */
44         qstr->len = i;
45         name = qstr->name;
46         hash = init_name_hash();
47         while (i--)
48                 hash = partial_name_hash(*name++, hash);
49         qstr->hash = end_name_hash(hash);
50         return 0;
51 }
52
53 struct dentry_operations minix_dentry_operations = {
54         .d_hash         = minix_hash,
55 };
56
57 static struct dentry *minix_lookup(struct inode * dir, struct dentry *dentry, struct nameidata *nd)
58 {
59         struct inode * inode = NULL;
60         ino_t ino;
61
62         dentry->d_op = dir->i_sb->s_root->d_op;
63
64         if (dentry->d_name.len > minix_sb(dir->i_sb)->s_namelen)
65                 return ERR_PTR(-ENAMETOOLONG);
66
67         ino = minix_inode_by_name(dentry);
68         if (ino) {
69                 inode = iget(dir->i_sb, ino);
70  
71                 if (!inode)
72                         return ERR_PTR(-EACCES);
73         }
74         d_add(dentry, inode);
75         return NULL;
76 }
77
78 static int minix_mknod(struct inode * dir, struct dentry *dentry, int mode, dev_t rdev)
79 {
80         int error;
81         struct inode *inode;
82
83         if (!old_valid_dev(rdev))
84                 return -EINVAL;
85
86         inode = minix_new_inode(dir, &error);
87
88         if (inode) {
89                 inode->i_mode = mode;
90                 minix_set_inode(inode, rdev);
91                 mark_inode_dirty(inode);
92                 error = add_nondir(dentry, inode);
93         }
94         return error;
95 }
96
97 static int minix_create(struct inode * dir, struct dentry *dentry, int mode,
98                 struct nameidata *nd)
99 {
100         return minix_mknod(dir, dentry, mode, 0);
101 }
102
103 static int minix_symlink(struct inode * dir, struct dentry *dentry,
104           const char * symname)
105 {
106         int err = -ENAMETOOLONG;
107         int i = strlen(symname)+1;
108         struct inode * inode;
109
110         if (i > dir->i_sb->s_blocksize)
111                 goto out;
112
113         inode = minix_new_inode(dir, &err);
114         if (!inode)
115                 goto out;
116
117         inode->i_mode = S_IFLNK | 0777;
118         minix_set_inode(inode, 0);
119         err = page_symlink(inode, symname, i);
120         if (err)
121                 goto out_fail;
122
123         err = add_nondir(dentry, inode);
124 out:
125         return err;
126
127 out_fail:
128         dec_count(inode);
129         iput(inode);
130         goto out;
131 }
132
133 static int minix_link(struct dentry * old_dentry, struct inode * dir,
134         struct dentry *dentry)
135 {
136         struct inode *inode = old_dentry->d_inode;
137
138         if (inode->i_nlink >= minix_sb(inode->i_sb)->s_link_max)
139                 return -EMLINK;
140
141         inode->i_ctime = CURRENT_TIME;
142         inc_count(inode);
143         atomic_inc(&inode->i_count);
144         return add_nondir(dentry, inode);
145 }
146
147 static int minix_mkdir(struct inode * dir, struct dentry *dentry, int mode)
148 {
149         struct inode * inode;
150         int err = -EMLINK;
151
152         if (dir->i_nlink >= minix_sb(dir->i_sb)->s_link_max)
153                 goto out;
154
155         inc_count(dir);
156
157         inode = minix_new_inode(dir, &err);
158         if (!inode)
159                 goto out_dir;
160
161         inode->i_mode = S_IFDIR | mode;
162         if (dir->i_mode & S_ISGID)
163                 inode->i_mode |= S_ISGID;
164         minix_set_inode(inode, 0);
165
166         inc_count(inode);
167
168         err = minix_make_empty(inode, dir);
169         if (err)
170                 goto out_fail;
171
172         err = minix_add_link(dentry, inode);
173         if (err)
174                 goto out_fail;
175
176         d_instantiate(dentry, inode);
177 out:
178         return err;
179
180 out_fail:
181         dec_count(inode);
182         dec_count(inode);
183         iput(inode);
184 out_dir:
185         dec_count(dir);
186         goto out;
187 }
188
189 static int minix_unlink(struct inode * dir, struct dentry *dentry)
190 {
191         int err = -ENOENT;
192         struct inode * inode = dentry->d_inode;
193         struct page * page;
194         struct minix_dir_entry * de;
195
196         de = minix_find_entry(dentry, &page);
197         if (!de)
198                 goto end_unlink;
199
200         err = minix_delete_entry(de, page);
201         if (err)
202                 goto end_unlink;
203
204         inode->i_ctime = dir->i_ctime;
205         dec_count(inode);
206 end_unlink:
207         return err;
208 }
209
210 static int minix_rmdir(struct inode * dir, struct dentry *dentry)
211 {
212         struct inode * inode = dentry->d_inode;
213         int err = -ENOTEMPTY;
214
215         if (minix_empty_dir(inode)) {
216                 err = minix_unlink(dir, dentry);
217                 if (!err) {
218                         dec_count(dir);
219                         dec_count(inode);
220                 }
221         }
222         return err;
223 }
224
225 static int minix_rename(struct inode * old_dir, struct dentry *old_dentry,
226                            struct inode * new_dir, struct dentry *new_dentry)
227 {
228         struct minix_sb_info * info = minix_sb(old_dir->i_sb);
229         struct inode * old_inode = old_dentry->d_inode;
230         struct inode * new_inode = new_dentry->d_inode;
231         struct page * dir_page = NULL;
232         struct minix_dir_entry * dir_de = NULL;
233         struct page * old_page;
234         struct minix_dir_entry * old_de;
235         int err = -ENOENT;
236
237         old_de = minix_find_entry(old_dentry, &old_page);
238         if (!old_de)
239                 goto out;
240
241         if (S_ISDIR(old_inode->i_mode)) {
242                 err = -EIO;
243                 dir_de = minix_dotdot(old_inode, &dir_page);
244                 if (!dir_de)
245                         goto out_old;
246         }
247
248         if (new_inode) {
249                 struct page * new_page;
250                 struct minix_dir_entry * new_de;
251
252                 err = -ENOTEMPTY;
253                 if (dir_de && !minix_empty_dir(new_inode))
254                         goto out_dir;
255
256                 err = -ENOENT;
257                 new_de = minix_find_entry(new_dentry, &new_page);
258                 if (!new_de)
259                         goto out_dir;
260                 inc_count(old_inode);
261                 minix_set_link(new_de, new_page, old_inode);
262                 new_inode->i_ctime = CURRENT_TIME;
263                 if (dir_de)
264                         new_inode->i_nlink--;
265                 dec_count(new_inode);
266         } else {
267                 if (dir_de) {
268                         err = -EMLINK;
269                         if (new_dir->i_nlink >= info->s_link_max)
270                                 goto out_dir;
271                 }
272                 inc_count(old_inode);
273                 err = minix_add_link(new_dentry, old_inode);
274                 if (err) {
275                         dec_count(old_inode);
276                         goto out_dir;
277                 }
278                 if (dir_de)
279                         inc_count(new_dir);
280         }
281
282         minix_delete_entry(old_de, old_page);
283         dec_count(old_inode);
284
285         if (dir_de) {
286                 minix_set_link(dir_de, dir_page, new_dir);
287                 dec_count(old_dir);
288         }
289         return 0;
290
291 out_dir:
292         if (dir_de) {
293                 kunmap(dir_page);
294                 page_cache_release(dir_page);
295         }
296 out_old:
297         kunmap(old_page);
298         page_cache_release(old_page);
299 out:
300         return err;
301 }
302
303 /*
304  * directories can handle most operations...
305  */
306 struct inode_operations minix_dir_inode_operations = {
307         .create         = minix_create,
308         .lookup         = minix_lookup,
309         .link           = minix_link,
310         .unlink         = minix_unlink,
311         .symlink        = minix_symlink,
312         .mkdir          = minix_mkdir,
313         .rmdir          = minix_rmdir,
314         .mknod          = minix_mknod,
315         .rename         = minix_rename,
316         .getattr        = minix_getattr,
317 };