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