Import 2.3.1pre2
[davej-history.git] / fs / sysv / namei.c
blob455d34b7acdb2389188f03b22e152ae8dfa817a0
1 /*
2 * linux/fs/sysv/namei.c
4 * minix/namei.c
5 * Copyright (C) 1991, 1992 Linus Torvalds
7 * coh/namei.c
8 * Copyright (C) 1993 Pascal Haible, Bruno Haible
10 * sysv/namei.c
11 * Copyright (C) 1993 Bruno Haible
12 * Copyright (C) 1997, 1998 Krzysztof G. Baranowski
16 #include <linux/sched.h>
17 #include <linux/kernel.h>
18 #include <linux/fs.h>
19 #include <linux/sysv_fs.h>
20 #include <linux/string.h>
21 #include <linux/stat.h>
22 #include <linux/errno.h>
24 /* compare strings: name[0..len-1] (not zero-terminated) and
25 * buffer[0..] (filled with zeroes up to buffer[0..maxlen-1])
27 static inline int namecompare(int len, int maxlen,
28 const char * name, const char * buffer)
30 if (len > maxlen)
31 return 0;
32 if (len < maxlen && buffer[len])
33 return 0;
34 return !memcmp(name, buffer, len);
38 * ok, we cannot use strncmp, as the name is not in our data space. [Now it is!]
39 * Thus we'll have to use sysv_match. No big problem. Match also makes
40 * some sanity tests.
42 * NOTE! unlike strncmp, sysv_match returns 1 for success, 0 for failure.
44 static int sysv_match(int len, const char * name, struct sysv_dir_entry * de)
46 if (!de->inode || len > SYSV_NAMELEN)
47 return 0;
48 /* "" means "." ---> so paths like "/usr/lib//libc.a" work */
49 if (!len && (de->name[0]=='.') && (de->name[1]=='\0'))
50 return 1;
51 return namecompare(len, SYSV_NAMELEN, name, de->name);
55 * sysv_find_entry()
57 * finds an entry in the specified directory with the wanted name. It
58 * returns the cache buffer in which the entry was found, and the entry
59 * itself (as a parameter - res_dir). It does NOT read the inode of the
60 * entry - you'll have to do that yourself if you want to.
62 static struct buffer_head * sysv_find_entry(struct inode * dir,
63 const char * name, int namelen, struct sysv_dir_entry ** res_dir)
65 struct super_block * sb;
66 unsigned long pos, block, offset; /* pos = block * block_size + offset */
67 struct buffer_head * bh;
69 *res_dir = NULL;
70 sb = dir->i_sb;
71 if (namelen > SYSV_NAMELEN) {
72 if (sb->sv_truncate)
73 namelen = SYSV_NAMELEN;
74 else
75 return NULL;
77 bh = NULL;
78 pos = block = offset = 0;
79 while (pos < dir->i_size) {
80 if (!bh) {
81 bh = sysv_file_bread(dir, block, 0);
82 if (!bh) {
83 /* offset = 0; */ block++;
84 pos += sb->sv_block_size;
85 continue;
88 if (sysv_match(namelen, name,
89 *res_dir = (struct sysv_dir_entry *) (bh->b_data + offset) ))
90 return bh;
91 pos += SYSV_DIRSIZE;
92 offset += SYSV_DIRSIZE;
93 if (offset < sb->sv_block_size)
94 continue;
95 brelse(bh);
96 bh = NULL;
97 offset = 0; block++;
99 brelse(bh);
100 *res_dir = NULL;
101 return NULL;
104 struct dentry *sysv_lookup(struct inode * dir, struct dentry * dentry)
106 struct inode * inode = NULL;
107 struct sysv_dir_entry * de;
108 struct buffer_head * bh;
110 bh = sysv_find_entry(dir, dentry->d_name.name, dentry->d_name.len, &de);
112 if (bh) {
113 int ino = de->inode;
114 brelse(bh);
115 inode = iget(dir->i_sb, ino);
117 if (!inode)
118 return ERR_PTR(-EACCES);
120 d_add(dentry, inode);
121 return NULL;
125 * sysv_add_entry()
127 * adds a file entry to the specified directory, returning a possible
128 * error value if it fails.
130 * NOTE!! The inode part of 'de' is left at 0 - which means you
131 * may not sleep between calling this and putting something into
132 * the entry, as someone else might have used it while you slept.
134 static int sysv_add_entry(struct inode * dir,
135 const char * name, int namelen,
136 struct buffer_head ** res_buf,
137 struct sysv_dir_entry ** res_dir)
139 struct super_block * sb;
140 int i;
141 unsigned long pos, block, offset; /* pos = block * block_size + offset */
142 struct buffer_head * bh;
143 struct sysv_dir_entry * de;
145 *res_buf = NULL;
146 *res_dir = NULL;
147 if (!dir)
148 return -ENOENT;
149 sb = dir->i_sb;
150 if (namelen > SYSV_NAMELEN) {
151 if (sb->sv_truncate)
152 namelen = SYSV_NAMELEN;
153 else
154 return -ENAMETOOLONG;
156 if (!namelen)
157 return -ENOENT;
158 bh = NULL;
159 pos = block = offset = 0;
160 while (1) {
161 if (!bh) {
162 bh = sysv_file_bread(dir, block, 1);
163 if (!bh)
164 return -ENOSPC;
166 de = (struct sysv_dir_entry *) (bh->b_data + offset);
167 pos += SYSV_DIRSIZE;
168 offset += SYSV_DIRSIZE;
169 if (pos > dir->i_size) {
170 de->inode = 0;
171 dir->i_size = pos;
172 mark_inode_dirty(dir);
174 if (de->inode) {
175 if (namecompare(namelen, SYSV_NAMELEN, name, de->name)) {
176 brelse(bh);
177 return -EEXIST;
179 } else {
180 dir->i_mtime = dir->i_ctime = CURRENT_TIME;
181 mark_inode_dirty(dir);
182 for (i = 0; i < SYSV_NAMELEN ; i++)
183 de->name[i] = (i < namelen) ? name[i] : 0;
184 mark_buffer_dirty(bh, 1);
185 *res_dir = de;
186 break;
188 if (offset < sb->sv_block_size)
189 continue;
190 brelse(bh);
191 bh = NULL;
192 offset = 0; block++;
194 *res_buf = bh;
195 return 0;
198 int sysv_create(struct inode * dir, struct dentry * dentry, int mode)
200 int error;
201 struct inode * inode;
202 struct buffer_head * bh;
203 struct sysv_dir_entry * de;
205 inode = sysv_new_inode(dir);
206 if (!inode)
207 return -ENOSPC;
208 inode->i_op = &sysv_file_inode_operations;
209 inode->i_mode = mode;
210 mark_inode_dirty(inode);
211 error = sysv_add_entry(dir, dentry->d_name.name,
212 dentry->d_name.len, &bh, &de);
213 if (error) {
214 inode->i_nlink--;
215 mark_inode_dirty(inode);
216 iput(inode);
217 return error;
219 de->inode = inode->i_ino;
220 mark_buffer_dirty(bh, 1);
221 brelse(bh);
222 d_instantiate(dentry, inode);
223 return 0;
226 int sysv_mknod(struct inode * dir, struct dentry * dentry, int mode, int rdev)
228 int error;
229 struct inode * inode;
230 struct buffer_head * bh;
231 struct sysv_dir_entry * de;
233 bh = sysv_find_entry(dir, dentry->d_name.name,
234 dentry->d_name.len, &de);
235 if (bh) {
236 brelse(bh);
237 return -EEXIST;
239 inode = sysv_new_inode(dir);
240 if (!inode)
241 return -ENOSPC;
242 inode->i_uid = current->fsuid;
243 init_special_inode(inode, mode, rdev);
244 mark_inode_dirty(inode);
245 error = sysv_add_entry(dir, dentry->d_name.name,
246 dentry->d_name.len, &bh, &de);
247 if (error) {
248 inode->i_nlink--;
249 mark_inode_dirty(inode);
250 iput(inode);
251 return error;
253 de->inode = inode->i_ino;
254 mark_buffer_dirty(bh, 1);
255 brelse(bh);
256 d_instantiate(dentry, inode);
257 return 0;
260 int sysv_mkdir(struct inode * dir, struct dentry *dentry, int mode)
262 int error;
263 struct inode * inode;
264 struct buffer_head * bh, *dir_block;
265 struct sysv_dir_entry * de;
267 bh = sysv_find_entry(dir, dentry->d_name.name,
268 dentry->d_name.len, &de);
269 if (bh) {
270 brelse(bh);
271 return -EEXIST;
273 if (dir->i_nlink >= dir->i_sb->sv_link_max)
274 return -EMLINK;
275 inode = sysv_new_inode(dir);
276 if (!inode)
277 return -ENOSPC;
278 inode->i_op = &sysv_dir_inode_operations;
279 inode->i_size = 2 * SYSV_DIRSIZE;
280 dir_block = sysv_file_bread(inode,0,1);
281 if (!dir_block) {
282 inode->i_nlink--;
283 mark_inode_dirty(inode);
284 iput(inode);
285 return -ENOSPC;
287 de = (struct sysv_dir_entry *) (dir_block->b_data + 0*SYSV_DIRSIZE);
288 de->inode = inode->i_ino;
289 strcpy(de->name,"."); /* rest of de->name is zero, see sysv_new_block */
290 de = (struct sysv_dir_entry *) (dir_block->b_data + 1*SYSV_DIRSIZE);
291 de->inode = dir->i_ino;
292 strcpy(de->name,".."); /* rest of de->name is zero, see sysv_new_block */
293 inode->i_nlink = 2;
294 mark_buffer_dirty(dir_block, 1);
295 brelse(dir_block);
296 inode->i_mode = S_IFDIR | (mode & 0777 & ~current->fs->umask);
297 if (dir->i_mode & S_ISGID)
298 inode->i_mode |= S_ISGID;
299 mark_inode_dirty(inode);
300 error = sysv_add_entry(dir, dentry->d_name.name,
301 dentry->d_name.len, &bh, &de);
302 if (error) {
303 inode->i_nlink=0;
304 iput(inode);
305 return error;
307 de->inode = inode->i_ino;
308 mark_buffer_dirty(bh, 1);
309 dir->i_nlink++;
310 mark_inode_dirty(dir);
311 brelse(bh);
312 d_instantiate(dentry, inode);
313 return 0;
317 * routine to check that the specified directory is empty (for rmdir)
319 static int empty_dir(struct inode * inode)
321 struct super_block * sb;
322 unsigned long pos, block, offset; /* pos = block * block_size + offset */
323 struct buffer_head * bh;
324 struct sysv_dir_entry * de;
326 if (!inode)
327 return 1;
328 block = 0;
329 bh = NULL;
330 pos = offset = 2*SYSV_DIRSIZE;
331 if (inode->i_size % SYSV_DIRSIZE)
332 goto bad_dir;
333 if (inode->i_size < pos)
334 goto bad_dir;
335 bh = sysv_file_bread(inode, 0, 0);
336 if (!bh)
337 goto bad_dir;
338 de = (struct sysv_dir_entry *) (bh->b_data + 0*SYSV_DIRSIZE);
339 if (!de->inode || strcmp(de->name,"."))
340 goto bad_dir;
341 de = (struct sysv_dir_entry *) (bh->b_data + 1*SYSV_DIRSIZE);
342 if (!de->inode || strcmp(de->name,".."))
343 goto bad_dir;
344 sb = inode->i_sb;
345 while (pos < inode->i_size) {
346 if (!bh) {
347 bh = sysv_file_bread(inode, block, 0);
348 if (!bh) {
349 /* offset = 0; */ block++;
350 pos += sb->sv_block_size;
351 continue;
354 de = (struct sysv_dir_entry *) (bh->b_data + offset);
355 pos += SYSV_DIRSIZE;
356 offset += SYSV_DIRSIZE;
357 if (de->inode) {
358 brelse(bh);
359 return 0;
361 if (offset < sb->sv_block_size)
362 continue;
363 brelse(bh);
364 bh = NULL;
365 offset = 0; block++;
367 brelse(bh);
368 return 1;
369 bad_dir:
370 brelse(bh);
371 printk("Bad directory on device %s\n",
372 kdevname(inode->i_dev));
373 return 1;
376 int sysv_rmdir(struct inode * dir, struct dentry * dentry)
378 int retval;
379 struct inode * inode;
380 struct buffer_head * bh;
381 struct sysv_dir_entry * de;
383 inode = NULL;
384 bh = sysv_find_entry(dir, dentry->d_name.name,
385 dentry->d_name.len, &de);
386 retval = -ENOENT;
387 if (!bh)
388 goto end_rmdir;
389 inode = dentry->d_inode;
391 if (!empty_dir(inode)) {
392 retval = -ENOTEMPTY;
393 goto end_rmdir;
395 if (de->inode != inode->i_ino) {
396 retval = -ENOENT;
397 goto end_rmdir;
399 if (!list_empty(&dentry->d_hash)) {
400 retval = -EBUSY;
401 goto end_rmdir;
403 if (inode->i_nlink != 2)
404 printk("empty directory has nlink!=2 (%d)\n", inode->i_nlink);
405 de->inode = 0;
406 mark_buffer_dirty(bh, 1);
407 inode->i_nlink=0;
408 mark_inode_dirty(inode);
409 dir->i_nlink--;
410 inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
411 mark_inode_dirty(dir);
412 d_delete(dentry);
413 retval = 0;
414 end_rmdir:
415 brelse(bh);
416 return retval;
419 int sysv_unlink(struct inode * dir, struct dentry * dentry)
421 int retval;
422 struct inode * inode;
423 struct buffer_head * bh;
424 struct sysv_dir_entry * de;
426 repeat:
427 retval = -ENOENT;
428 inode = NULL;
429 bh = sysv_find_entry(dir, dentry->d_name.name,
430 dentry->d_name.len, &de);
431 if (!bh)
432 goto end_unlink;
433 inode = dentry->d_inode;
435 retval = -EPERM;
436 if (de->inode != inode->i_ino) {
437 brelse(bh);
438 current->counter = 0;
439 schedule();
440 goto repeat;
442 if (de->inode != inode->i_ino) {
443 retval = -ENOENT;
444 goto end_unlink;
446 if (!inode->i_nlink) {
447 printk("Deleting nonexistent file (%s:%lu), %d\n",
448 kdevname(inode->i_dev), inode->i_ino, inode->i_nlink);
449 inode->i_nlink=1;
451 de->inode = 0;
452 mark_buffer_dirty(bh, 1);
453 dir->i_ctime = dir->i_mtime = CURRENT_TIME;
454 mark_inode_dirty(dir);
455 inode->i_nlink--;
456 inode->i_ctime = dir->i_ctime;
457 mark_inode_dirty(inode);
458 d_delete(dentry);
459 retval = 0;
460 end_unlink:
461 brelse(bh);
462 return retval;
465 int sysv_symlink(struct inode * dir, struct dentry * dentry,
466 const char * symname)
468 struct sysv_dir_entry * de;
469 struct inode * inode;
470 struct buffer_head * name_block;
471 char * name_block_data;
472 struct super_block * sb;
473 int i;
474 char c;
475 struct buffer_head * bh;
477 if (!(inode = sysv_new_inode(dir)))
478 return -ENOSPC;
480 inode->i_mode = S_IFLNK | 0777;
481 inode->i_op = &sysv_symlink_inode_operations;
482 name_block = sysv_file_bread(inode, 0, 1);
483 if (!name_block) {
484 inode->i_nlink--;
485 mark_inode_dirty(inode);
486 iput(inode);
487 return -ENOSPC;
489 sb = inode->i_sb;
490 name_block_data = name_block->b_data;
491 i = 0;
492 while (i < sb->sv_block_size_1 && (c = *(symname++)))
493 name_block_data[i++] = c;
494 name_block_data[i] = 0;
495 mark_buffer_dirty(name_block, 1);
496 brelse(name_block);
497 inode->i_size = i;
498 mark_inode_dirty(inode);
499 bh = sysv_find_entry(dir, dentry->d_name.name,
500 dentry->d_name.len, &de);
501 if (bh) {
502 inode->i_nlink--;
503 mark_inode_dirty(inode);
504 iput(inode);
505 brelse(bh);
506 return -EEXIST;
508 i = sysv_add_entry(dir, dentry->d_name.name,
509 dentry->d_name.len, &bh, &de);
510 if (i) {
511 inode->i_nlink--;
512 mark_inode_dirty(inode);
513 iput(inode);
514 return i;
516 de->inode = inode->i_ino;
517 mark_buffer_dirty(bh, 1);
518 brelse(bh);
519 d_instantiate(dentry, inode);
520 return 0;
523 int sysv_link(struct dentry * old_dentry, struct inode * dir,
524 struct dentry * dentry)
526 struct inode *oldinode = old_dentry->d_inode;
527 int error;
528 struct sysv_dir_entry * de;
529 struct buffer_head * bh;
531 if (S_ISDIR(oldinode->i_mode)) {
532 return -EPERM;
534 if (oldinode->i_nlink >= oldinode->i_sb->sv_link_max) {
535 return -EMLINK;
537 bh = sysv_find_entry(dir, dentry->d_name.name,
538 dentry->d_name.len, &de);
539 if (bh) {
540 brelse(bh);
541 return -EEXIST;
543 error = sysv_add_entry(dir, dentry->d_name.name,
544 dentry->d_name.len, &bh, &de);
545 if (error) {
546 brelse(bh);
547 return error;
549 de->inode = oldinode->i_ino;
550 mark_buffer_dirty(bh, 1);
551 brelse(bh);
552 oldinode->i_nlink++;
553 oldinode->i_ctime = CURRENT_TIME;
554 mark_inode_dirty(oldinode);
555 oldinode->i_count++;
556 d_instantiate(dentry, oldinode);
557 return 0;
560 #define PARENT_INO(buffer) \
561 (((struct sysv_dir_entry *) ((buffer) + 1*SYSV_DIRSIZE))->inode)
564 * rename uses retrying to avoid race-conditions: at least they should be minimal.
565 * it tries to allocate all the blocks, then sanity-checks, and if the sanity-
566 * checks fail, it tries to restart itself again. Very practical - no changes
567 * are done until we know everything works ok.. and then all the changes can be
568 * done in one fell swoop when we have claimed all the buffers needed.
570 * Anybody can rename anything with this: the permission checks are left to the
571 * higher-level routines.
573 int sysv_rename(struct inode * old_dir, struct dentry * old_dentry,
574 struct inode * new_dir, struct dentry * new_dentry)
576 struct inode * old_inode, * new_inode;
577 struct buffer_head * old_bh, * new_bh, * dir_bh;
578 struct sysv_dir_entry * old_de, * new_de;
579 int retval;
581 goto start_up;
582 try_again:
583 brelse(old_bh);
584 brelse(new_bh);
585 brelse(dir_bh);
586 current->counter = 0;
587 schedule();
588 start_up:
589 old_inode = new_inode = NULL;
590 old_bh = new_bh = dir_bh = NULL;
591 old_bh = sysv_find_entry(old_dir, old_dentry->d_name.name,
592 old_dentry->d_name.len, &old_de);
593 retval = -ENOENT;
594 if (!old_bh)
595 goto end_rename;
596 old_inode = old_dentry->d_inode; /* don't cross mnt-points */
597 retval = -EPERM;
598 new_inode = new_dentry->d_inode;
599 new_bh = sysv_find_entry(new_dir, new_dentry->d_name.name,
600 new_dentry->d_name.len, &new_de);
601 if (new_bh) {
602 if (!new_inode) {
603 brelse(new_bh);
604 new_bh = NULL;
607 if (S_ISDIR(old_inode->i_mode)) {
608 if (new_inode) {
609 retval = -ENOTEMPTY;
610 if (!empty_dir(new_inode))
611 goto end_rename;
613 retval = -EIO;
614 dir_bh = sysv_file_bread(old_inode, 0, 0);
615 if (!dir_bh)
616 goto end_rename;
617 if (PARENT_INO(dir_bh->b_data) != old_dir->i_ino)
618 goto end_rename;
619 retval = -EMLINK;
620 if (!new_inode && new_dir->i_nlink >= new_dir->i_sb->sv_link_max)
621 goto end_rename;
623 if (!new_bh) {
624 retval = sysv_add_entry(new_dir, new_dentry->d_name.name,
625 new_dentry->d_name.len, &new_bh, &new_de);
626 if (retval)
627 goto end_rename;
629 /* sanity checking before doing the rename - avoid races */
630 if (new_inode && (new_de->inode != new_inode->i_ino))
631 goto try_again;
632 if (new_de->inode && !new_inode)
633 goto try_again;
634 if (old_de->inode != old_inode->i_ino)
635 goto try_again;
636 /* ok, that's it */
637 old_de->inode = 0;
638 new_de->inode = old_inode->i_ino;
639 old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME;
640 mark_inode_dirty(old_dir);
641 new_dir->i_ctime = new_dir->i_mtime = CURRENT_TIME;
642 mark_inode_dirty(new_dir);
643 if (new_inode) {
644 new_inode->i_nlink--;
645 new_inode->i_ctime = CURRENT_TIME;
646 mark_inode_dirty(new_inode);
648 mark_buffer_dirty(old_bh, 1);
649 mark_buffer_dirty(new_bh, 1);
650 if (dir_bh) {
651 PARENT_INO(dir_bh->b_data) = new_dir->i_ino;
652 mark_buffer_dirty(dir_bh, 1);
653 old_dir->i_nlink--;
654 mark_inode_dirty(old_dir);
655 if (new_inode) {
656 new_inode->i_nlink--;
657 mark_inode_dirty(new_inode);
658 } else {
659 new_dir->i_nlink++;
660 mark_inode_dirty(new_dir);
663 retval = 0;
664 end_rename:
665 brelse(dir_bh);
666 brelse(old_bh);
667 brelse(new_bh);
668 return retval;