1 /*
2 * linux/fs/minix/namei.c
3 *
4 * Copyright (C) 1991, 1992 Linus Torvalds
5 */
6
7 #include <linux/sched.h>
8 #include <linux/minix_fs.h>
9 #include <linux/kernel.h>
10 #include <linux/string.h>
11 #include <linux/stat.h>
12 #include <linux/fcntl.h>
13 #include <linux/errno.h>
14 #include <linux/quotaops.h>
15
16 #include <asm/uaccess.h>
17
18 /*
19 * comment out this line if you want names > info->s_namelen chars to be
20 * truncated. Else they will be disallowed (ENAMETOOLONG).
21 */
22 /* #define NO_TRUNCATE */
23
24 static inline int namecompare(int len, int maxlen,
25 const char * name, const char * buffer)
26 {
27 if (len < maxlen && buffer[len])
28 return 0;
29 return !memcmp(name, buffer, len);
30 }
31
32 /*
33 * minix_find_entry()
34 *
35 * finds an entry in the specified directory with the wanted name. It
36 * returns the cache buffer in which the entry was found, and the entry
37 * itself (as a parameter - res_dir). It does NOT read the inode of the
38 * entry - you'll have to do that yourself if you want to.
39 */
40 static struct buffer_head * minix_find_entry(struct inode * dir,
41 const char * name, int namelen, struct minix_dir_entry ** res_dir)
42 {
43 unsigned long block, offset;
44 struct buffer_head * bh;
45 struct minix_sb_info * info;
46 struct minix_dir_entry *de;
47
48 *res_dir = NULL;
49 info = &dir->i_sb->u.minix_sb;
50 if (namelen > info->s_namelen) {
51 #ifdef NO_TRUNCATE
52 return NULL;
53 #else
54 namelen = info->s_namelen;
55 #endif
56 }
57 bh = NULL;
58 block = offset = 0;
59 while (block*BLOCK_SIZE+offset < dir->i_size) {
60 if (!bh) {
61 bh = minix_bread(dir,block,0);
62 if (!bh) {
63 block++;
64 continue;
65 }
66 }
67 de = (struct minix_dir_entry *) (bh->b_data + offset);
68 offset += info->s_dirsize;
69 if (de->inode && namecompare(namelen,info->s_namelen,name,de->name)) {
70 *res_dir = de;
71 return bh;
72 }
73 if (offset < bh->b_size)
74 continue;
75 brelse(bh);
76 bh = NULL;
77 offset = 0;
78 block++;
79 }
80 brelse(bh);
81 return NULL;
82 }
83
84 #ifndef NO_TRUNCATE
85
86 static int minix_hash(struct dentry *dentry, struct qstr *qstr)
87 {
88 unsigned long hash;
89 int i;
90 const unsigned char *name;
91
92 i = dentry->d_inode->i_sb->u.minix_sb.s_namelen;
93 if (i >= qstr->len)
94 return 0;
95 /* Truncate the name in place, avoids having to define a compare
96 function. */
97 qstr->len = i;
98 name = qstr->name;
99 hash = init_name_hash();
100 while (i--)
101 hash = partial_name_hash(*name++, hash);
102 qstr->hash = end_name_hash(hash);
103 return 0;
104 }
105
106 #endif
107
108 struct dentry_operations minix_dentry_operations = {
109 #ifndef NO_TRUNCATE
110 d_hash: minix_hash,
111 #endif
112 };
113
114 static struct dentry *minix_lookup(struct inode * dir, struct dentry *dentry)
115 {
116 struct inode * inode = NULL;
117 struct minix_dir_entry * de;
118 struct buffer_head * bh;
119
120 #ifndef NO_TRUNCATE
121 dentry->d_op = &minix_dentry_operations;
122 #endif
123 bh = minix_find_entry(dir, dentry->d_name.name, dentry->d_name.len, &de);
124 if (bh) {
125 int ino = de->inode;
126 brelse (bh);
127 inode = iget(dir->i_sb, ino);
128
129 if (!inode)
130 return ERR_PTR(-EACCES);
131 }
132 d_add(dentry, inode);
133 return NULL;
134 }
135
136 /*
137 * minix_add_entry()
138 *
139 * adds a file entry to the specified directory, returning a possible
140 * error value if it fails.
141 *
142 * NOTE!! The inode part of 'de' is left at 0 - which means you
143 * may not sleep between calling this and putting something into
144 * the entry, as someone else might have used it while you slept.
145 */
146 static int minix_add_entry(struct inode * dir,
147 const char * name, int namelen,
148 struct buffer_head ** res_buf,
149 struct minix_dir_entry ** res_dir)
150 {
151 int i;
152 unsigned long block, offset;
153 struct buffer_head * bh;
154 struct minix_dir_entry * de;
155 struct minix_sb_info * info;
156
157 *res_buf = NULL;
158 *res_dir = NULL;
159 info = &dir->i_sb->u.minix_sb;
160 if (namelen > info->s_namelen) {
161 #ifdef NO_TRUNCATE
162 return -ENAMETOOLONG;
163 #else
164 namelen = info->s_namelen;
165 #endif
166 }
167 if (!namelen)
168 return -ENOENT;
169 bh = NULL;
170 block = offset = 0;
171 while (1) {
172 if (!bh) {
173 bh = minix_bread(dir,block,1);
174 if (!bh)
175 return -ENOSPC;
176 }
177 de = (struct minix_dir_entry *) (bh->b_data + offset);
178 offset += info->s_dirsize;
179 if (block*bh->b_size + offset > dir->i_size) {
180 de->inode = 0;
181 dir->i_size = block*bh->b_size + offset;
182 mark_inode_dirty(dir);
183 }
184 if (!de->inode) {
185 dir->i_mtime = dir->i_ctime = CURRENT_TIME;
186 mark_inode_dirty(dir);
187 for (i = 0; i < info->s_namelen ; i++)
188 de->name[i] = (i < namelen) ? name[i] : 0;
189 dir->i_version = ++event;
190 mark_buffer_dirty(bh);
191 *res_dir = de;
192 break;
193 }
194 if (offset < bh->b_size)
195 continue;
196 brelse(bh);
197 bh = NULL;
198 offset = 0;
199 block++;
200 }
201 *res_buf = bh;
202 return 0;
203 }
204
205 static int minix_create(struct inode * dir, struct dentry *dentry, int mode)
206 {
207 int error;
208 struct inode * inode;
209 struct buffer_head * bh;
210 struct minix_dir_entry * de;
211
212 inode = minix_new_inode(dir, &error);
213 if (!inode)
214 return error;
215 inode->i_op = &minix_file_inode_operations;
216 inode->i_fop = &minix_file_operations;
217 inode->i_mapping->a_ops = &minix_aops;
218 inode->i_mode = mode;
219 mark_inode_dirty(inode);
220 error = minix_add_entry(dir, dentry->d_name.name,
221 dentry->d_name.len, &bh ,&de);
222 if (error) {
223 inode->i_nlink--;
224 mark_inode_dirty(inode);
225 iput(inode);
226 return error;
227 }
228 de->inode = inode->i_ino;
229 mark_buffer_dirty(bh);
230 brelse(bh);
231 d_instantiate(dentry, inode);
232 return 0;
233 }
234
235 static int minix_mknod(struct inode * dir, struct dentry *dentry, int mode, int rdev)
236 {
237 int error;
238 struct inode * inode;
239 struct buffer_head * bh;
240 struct minix_dir_entry * de;
241
242 inode = minix_new_inode(dir, &error);
243 if (!inode)
244 return error;
245 inode->i_uid = current->fsuid;
246 init_special_inode(inode, mode, rdev);
247 mark_inode_dirty(inode);
248 error = minix_add_entry(dir, dentry->d_name.name, dentry->d_name.len, &bh, &de);
249 if (error) {
250 inode->i_nlink--;
251 mark_inode_dirty(inode);
252 iput(inode);
253 return error;
254 }
255 de->inode = inode->i_ino;
256 mark_buffer_dirty(bh);
257 brelse(bh);
258 d_instantiate(dentry, inode);
259 return 0;
260 }
261
262 static int minix_mkdir(struct inode * dir, struct dentry *dentry, int mode)
263 {
264 int error;
265 struct inode * inode;
266 struct buffer_head * bh, *dir_block;
267 struct minix_dir_entry * de;
268 struct minix_sb_info * info;
269
270 info = &dir->i_sb->u.minix_sb;
271 if (dir->i_nlink >= info->s_link_max)
272 return -EMLINK;
273 inode = minix_new_inode(dir, &error);
274 if (!inode)
275 return error;
276 inode->i_op = &minix_dir_inode_operations;
277 inode->i_fop = &minix_dir_operations;
278 inode->i_size = 2 * info->s_dirsize;
279 dir_block = minix_bread(inode,0,1);
280 if (!dir_block) {
281 inode->i_nlink--;
282 mark_inode_dirty(inode);
283 iput(inode);
284 return -ENOSPC;
285 }
286 de = (struct minix_dir_entry *) dir_block->b_data;
287 de->inode=inode->i_ino;
288 strcpy(de->name,".");
289 de = (struct minix_dir_entry *) (dir_block->b_data + info->s_dirsize);
290 de->inode = dir->i_ino;
291 strcpy(de->name,"..");
292 inode->i_nlink = 2;
293 mark_buffer_dirty(dir_block);
294 brelse(dir_block);
295 inode->i_mode = S_IFDIR | mode;
296 if (dir->i_mode & S_ISGID)
297 inode->i_mode |= S_ISGID;
298 mark_inode_dirty(inode);
299 error = minix_add_entry(dir, dentry->d_name.name,
300 dentry->d_name.len, &bh, &de);
301 if (error) {
302 inode->i_nlink=0;
303 iput(inode);
304 return error;
305 }
306 de->inode = inode->i_ino;
307 mark_buffer_dirty(bh);
308 dir->i_nlink++;
309 mark_inode_dirty(dir);
310 brelse(bh);
311 d_instantiate(dentry, inode);
312 return 0;
313 }
314
315 /*
316 * routine to check that the specified directory is empty (for rmdir)
317 */
318 static int empty_dir(struct inode * inode)
319 {
320 unsigned int block, offset;
321 struct buffer_head * bh;
322 struct minix_dir_entry * de;
323 struct minix_sb_info * info;
324
325 info = &inode->i_sb->u.minix_sb;
326 block = 0;
327 bh = NULL;
328 offset = 2*info->s_dirsize;
329 if (inode->i_size & (info->s_dirsize-1))
330 goto bad_dir;
331 if (inode->i_size < offset)
332 goto bad_dir;
333 bh = minix_bread(inode,0,0);
334 if (!bh)
335 goto bad_dir;
336 de = (struct minix_dir_entry *) bh->b_data;
337 if (!de->inode || strcmp(de->name,"."))
338 goto bad_dir;
339 de = (struct minix_dir_entry *) (bh->b_data + info->s_dirsize);
340 if (!de->inode || strcmp(de->name,".."))
341 goto bad_dir;
342 while (block*BLOCK_SIZE+offset < inode->i_size) {
343 if (!bh) {
344 bh = minix_bread(inode,block,0);
345 if (!bh) {
346 block++;
347 continue;
348 }
349 }
350 de = (struct minix_dir_entry *) (bh->b_data + offset);
351 offset += info->s_dirsize;
352 if (de->inode) {
353 brelse(bh);
354 return 0;
355 }
356 if (offset < bh->b_size)
357 continue;
358 brelse(bh);
359 bh = NULL;
360 offset = 0;
361 block++;
362 }
363 brelse(bh);
364 return 1;
365 bad_dir:
366 brelse(bh);
367 printk("Bad directory on device %s\n",
368 kdevname(inode->i_dev));
369 return 1;
370 }
371
372 static int minix_rmdir(struct inode * dir, struct dentry *dentry)
373 {
374 int retval;
375 struct inode * inode;
376 struct buffer_head * bh;
377 struct minix_dir_entry * de;
378
379 inode = NULL;
380 bh = minix_find_entry(dir, dentry->d_name.name,
381 dentry->d_name.len, &de);
382 retval = -ENOENT;
383 if (!bh)
384 goto end_rmdir;
385 inode = dentry->d_inode;
386
387 if (!empty_dir(inode)) {
388 retval = -ENOTEMPTY;
389 goto end_rmdir;
390 }
391 if (de->inode != inode->i_ino) {
392 retval = -ENOENT;
393 goto end_rmdir;
394 }
395 if (inode->i_nlink != 2)
396 printk("empty directory has nlink!=2 (%d)\n",inode->i_nlink);
397 de->inode = 0;
398 dir->i_version = ++event;
399 mark_buffer_dirty(bh);
400 inode->i_nlink=0;
401 mark_inode_dirty(inode);
402 inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
403 dir->i_nlink--;
404 mark_inode_dirty(dir);
405 retval = 0;
406 end_rmdir:
407 brelse(bh);
408 return retval;
409 }
410
411 static int minix_unlink(struct inode * dir, struct dentry *dentry)
412 {
413 int retval;
414 struct inode * inode;
415 struct buffer_head * bh;
416 struct minix_dir_entry * de;
417
418 retval = -ENOENT;
419 inode = dentry->d_inode;
420 bh = minix_find_entry(dir, dentry->d_name.name,
421 dentry->d_name.len, &de);
422 if (!bh || de->inode != inode->i_ino)
423 goto end_unlink;
424 if (!inode->i_nlink) {
425 printk("Deleting nonexistent file (%s:%lu), %d\n",
426 kdevname(inode->i_dev),
427 inode->i_ino, inode->i_nlink);
428 inode->i_nlink=1;
429 }
430 de->inode = 0;
431 dir->i_version = ++event;
432 mark_buffer_dirty(bh);
433 dir->i_ctime = dir->i_mtime = CURRENT_TIME;
434 mark_inode_dirty(dir);
435 inode->i_nlink--;
436 inode->i_ctime = dir->i_ctime;
437 mark_inode_dirty(inode);
438 retval = 0;
439 end_unlink:
440 brelse(bh);
441 return retval;
442 }
443
444 static int minix_symlink(struct inode * dir, struct dentry *dentry,
445 const char * symname)
446 {
447 struct minix_dir_entry * de;
448 struct inode * inode = NULL;
449 struct buffer_head * bh = NULL;
450 int i;
451 int err;
452
453 err = -ENAMETOOLONG;
454 i = strlen(symname)+1;
455 if (i>1024)
456 goto out;
457 inode = minix_new_inode(dir, &err);
458 if (!inode)
459 goto out;
460
461 inode->i_mode = S_IFLNK | 0777;
462 inode->i_op = &page_symlink_inode_operations;
463 inode->i_mapping->a_ops = &minix_aops;
464 err = block_symlink(inode, symname, i);
465 if (err)
466 goto fail;
467
468 err = minix_add_entry(dir, dentry->d_name.name,
469 dentry->d_name.len, &bh, &de);
470 if (err)
471 goto fail;
472
473 de->inode = inode->i_ino;
474 mark_buffer_dirty(bh);
475 brelse(bh);
476 d_instantiate(dentry, inode);
477 out:
478 return err;
479 fail:
480 inode->i_nlink--;
481 mark_inode_dirty(inode);
482 iput(inode);
483 goto out;
484 }
485
486 static int minix_link(struct dentry * old_dentry, struct inode * dir,
487 struct dentry *dentry)
488 {
489 int error;
490 struct inode *inode = old_dentry->d_inode;
491 struct minix_dir_entry * de;
492 struct buffer_head * bh;
493
494 if (S_ISDIR(inode->i_mode))
495 return -EPERM;
496
497 if (inode->i_nlink >= inode->i_sb->u.minix_sb.s_link_max)
498 return -EMLINK;
499
500 error = minix_add_entry(dir, dentry->d_name.name,
501 dentry->d_name.len, &bh, &de);
502 if (error) {
503 brelse(bh);
504 return error;
505 }
506 de->inode = inode->i_ino;
507 mark_buffer_dirty(bh);
508 brelse(bh);
509 inode->i_nlink++;
510 inode->i_ctime = CURRENT_TIME;
511 mark_inode_dirty(inode);
512 atomic_inc(&inode->i_count);
513 d_instantiate(dentry, inode);
514 return 0;
515 }
516
517 #define PARENT_INO(buffer) \
518 (((struct minix_dir_entry *) ((buffer)+info->s_dirsize))->inode)
519
520 /*
521 * Anybody can rename anything with this: the permission checks are left to the
522 * higher-level routines.
523 */
524 static int minix_rename(struct inode * old_dir, struct dentry *old_dentry,
525 struct inode * new_dir, struct dentry *new_dentry)
526 {
527 struct inode * old_inode, * new_inode;
528 struct buffer_head * old_bh, * new_bh, * dir_bh;
529 struct minix_dir_entry * old_de, * new_de;
530 struct minix_sb_info * info;
531 int retval;
532
533 info = &old_dir->i_sb->u.minix_sb;
534 new_bh = dir_bh = NULL;
535 old_inode = old_dentry->d_inode;
536 new_inode = new_dentry->d_inode;
537 old_bh = minix_find_entry(old_dir, old_dentry->d_name.name,
538 old_dentry->d_name.len, &old_de);
539 retval = -ENOENT;
540 if (!old_bh || old_de->inode != old_inode->i_ino)
541 goto end_rename;
542 retval = -EPERM;
543 new_bh = minix_find_entry(new_dir, new_dentry->d_name.name,
544 new_dentry->d_name.len, &new_de);
545 if (new_bh) {
546 if (!new_inode) {
547 brelse(new_bh);
548 new_bh = NULL;
549 }
550 }
551 if (S_ISDIR(old_inode->i_mode)) {
552 if (new_inode) {
553 retval = -ENOTEMPTY;
554 if (!empty_dir(new_inode))
555 goto end_rename;
556 }
557 retval = -EIO;
558 dir_bh = minix_bread(old_inode,0,0);
559 if (!dir_bh)
560 goto end_rename;
561 if (PARENT_INO(dir_bh->b_data) != old_dir->i_ino)
562 goto end_rename;
563 retval = -EMLINK;
564 if (!new_inode && new_dir != old_dir &&
565 new_dir->i_nlink >= info->s_link_max)
566 goto end_rename;
567 }
568 if (!new_bh) {
569 retval = minix_add_entry(new_dir,
570 new_dentry->d_name.name,
571 new_dentry->d_name.len,
572 &new_bh, &new_de);
573 if (retval)
574 goto end_rename;
575 }
576 /* ok, that's it */
577 new_de->inode = old_inode->i_ino;
578 old_de->inode = 0;
579 old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME;
580 old_dir->i_version = ++event;
581 mark_inode_dirty(old_dir);
582 new_dir->i_ctime = new_dir->i_mtime = CURRENT_TIME;
583 new_dir->i_version = ++event;
584 mark_inode_dirty(new_dir);
585 if (new_inode) {
586 new_inode->i_nlink--;
587 new_inode->i_ctime = CURRENT_TIME;
588 mark_inode_dirty(new_inode);
589 }
590 mark_buffer_dirty(old_bh);
591 mark_buffer_dirty(new_bh);
592 if (dir_bh) {
593 PARENT_INO(dir_bh->b_data) = new_dir->i_ino;
594 mark_buffer_dirty(dir_bh);
595 old_dir->i_nlink--;
596 mark_inode_dirty(old_dir);
597 if (new_inode) {
598 new_inode->i_nlink--;
599 mark_inode_dirty(new_inode);
600 } else {
601 new_dir->i_nlink++;
602 mark_inode_dirty(new_dir);
603 }
604 }
605 retval = 0;
606 end_rename:
607 brelse(dir_bh);
608 brelse(old_bh);
609 brelse(new_bh);
610 return retval;
611 }
612
613 /*
614 * directories can handle most operations...
615 */
616 struct inode_operations minix_dir_inode_operations = {
617 create: minix_create,
618 lookup: minix_lookup,
619 link: minix_link,
620 unlink: minix_unlink,
621 symlink: minix_symlink,
622 mkdir: minix_mkdir,
623 rmdir: minix_rmdir,
624 mknod: minix_mknod,
625 rename: minix_rename,
626 };
627
This page was automatically generated by the
LXR engine.
Visit the LXR main site for more
information.