* added 0.99 linux version
[mascara-docs.git] / i386 / linux / linux-0.99 / fs / ext / namei.c
bloba8bc1cb31b9bb1af1a3ce7543c1b518686860a85
1 /*
2 * linux/fs/ext/namei.c
4 * Copyright (C) 1992 Remy Card (card@masi.ibp.fr)
6 * from
8 * linux/fs/minix/namei.c
10 * Copyright (C) 1991, 1992 Linus Torvalds
13 #include <linux/sched.h>
14 #include <linux/ext_fs.h>
15 #include <linux/kernel.h>
16 #include <linux/string.h>
17 #include <linux/stat.h>
18 #include <linux/fcntl.h>
19 #include <linux/errno.h>
21 #include <asm/segment.h>
24 * comment out this line if you want names > EXT_NAME_LEN chars to be
25 * truncated. Else they will be disallowed.
27 /* #define NO_TRUNCATE */
30 * EXT_DIR_PAD defines the directory entries boundaries
32 * NOTE: It must be a power of 2 and must be greater or equal than 8
33 * because a directory entry needs 8 bytes for its fixed part
34 * (4 bytes for the inode, 2 bytes for the entry length and 2 bytes
35 * for the name length)
37 #define EXT_DIR_PAD 8
41 * EXT_DIR_MIN_SIZE is the minimal size of a directory entry
43 * During allocations, a directory entry is split into 2 ones
44 * *ONLY* if the size of the unused part is greater than or
45 * equal to EXT_DIR_MIN_SIZE
47 #define EXT_DIR_MIN_SIZE 12
50 * ok, we cannot use strncmp, as the name is not in our data space.
51 * Thus we'll have to use ext_match. No big problem. Match also makes
52 * some sanity tests.
54 * NOTE! unlike strncmp, ext_match returns 1 for success, 0 for failure.
56 static int ext_match(int len,const char * name,struct ext_dir_entry * de)
58 register int same __asm__("ax");
60 if (!de || !de->inode || len > EXT_NAME_LEN)
61 return 0;
62 /* "" means "." ---> so paths like "/usr/lib//libc.a" work */
63 if (!len && (de->name[0]=='.') && (de->name[1]=='\0'))
64 return 1;
65 if (len < EXT_NAME_LEN && len != de->name_len)
66 return 0;
67 __asm__("cld\n\t"
68 "repe ; cmpsb\n\t"
69 "setz %%al"
70 :"=a" (same)
71 :"0" (0),"S" ((long) name),"D" ((long) de->name),"c" (len)
72 :"cx","di","si");
73 return same;
77 * ext_find_entry()
79 * finds an entry in the specified directory with the wanted name. It
80 * returns the cache buffer in which the entry was found, and the entry
81 * itself (as a parameter - res_dir). It does NOT read the inode of the
82 * entry - you'll have to do that yourself if you want to.
84 * addition for the ext file system : this function returns the previous
85 * and next directory entries in the parameters prev_dir and next_dir
87 static struct buffer_head * ext_find_entry(struct inode * dir,
88 const char * name, int namelen, struct ext_dir_entry ** res_dir,
89 struct ext_dir_entry ** prev_dir, struct ext_dir_entry ** next_dir)
91 long offset;
92 struct buffer_head * bh;
93 struct ext_dir_entry * de;
95 *res_dir = NULL;
96 if (!dir)
97 return NULL;
98 #ifdef NO_TRUNCATE
99 if (namelen > EXT_NAME_LEN)
100 return NULL;
101 #else
102 if (namelen > EXT_NAME_LEN)
103 namelen = EXT_NAME_LEN;
104 #endif
105 bh = ext_bread(dir,0,0);
106 if (!bh)
107 return NULL;
108 if (prev_dir)
109 *prev_dir = NULL;
110 if (next_dir)
111 *next_dir = NULL;
112 offset = 0;
113 de = (struct ext_dir_entry *) bh->b_data;
114 while (offset < dir->i_size) {
115 if ((char *)de >= BLOCK_SIZE+bh->b_data) {
116 brelse(bh);
117 bh = NULL;
118 bh = ext_bread(dir,offset>>BLOCK_SIZE_BITS,0);
119 if (!bh)
120 continue;
121 de = (struct ext_dir_entry *) bh->b_data;
122 if (prev_dir)
123 *prev_dir = NULL;
125 if (de->rec_len < 8 || de->rec_len % 8 != 0 ||
126 de->rec_len < de->name_len + 8 ||
127 (((char *) de) + de->rec_len-1 >= BLOCK_SIZE+bh->b_data)) {
128 printk ("ext_find_entry: bad dir entry\n");
129 printk ("dev=%d, dir=%d, offset=%d, rec_len=%d, name_len=%d\n",
130 dir->i_dev, dir->i_ino, offset, de->rec_len, de->name_len);
131 de = (struct ext_dir_entry *) (bh->b_data+BLOCK_SIZE);
132 offset = ((offset / BLOCK_SIZE) + 1) * BLOCK_SIZE;
133 continue;
134 /* brelse (bh);
135 return NULL; */
137 if (ext_match(namelen,name,de)) {
138 *res_dir = de;
139 if (next_dir)
140 if (offset + de->rec_len < dir->i_size &&
141 ((char *)de) + de->rec_len < BLOCK_SIZE+bh->b_data)
142 *next_dir = (struct ext_dir_entry *)
143 ((char *) de + de->rec_len);
144 else
145 *next_dir = NULL;
146 return bh;
148 offset += de->rec_len;
149 if (prev_dir)
150 *prev_dir = de;
151 de = (struct ext_dir_entry *) ((char *) de + de->rec_len);
153 brelse(bh);
154 return NULL;
157 int ext_lookup(struct inode * dir,const char * name, int len,
158 struct inode ** result)
160 int ino;
161 struct ext_dir_entry * de;
162 struct buffer_head * bh;
164 *result = NULL;
165 if (!dir)
166 return -ENOENT;
167 if (!S_ISDIR(dir->i_mode)) {
168 iput(dir);
169 return -ENOENT;
171 if (!(bh = ext_find_entry(dir,name,len,&de,NULL,NULL))) {
172 iput(dir);
173 return -ENOENT;
175 ino = de->inode;
176 brelse(bh);
177 if (!(*result = iget(dir->i_sb,ino))) {
178 iput(dir);
179 return -EACCES;
181 iput(dir);
182 return 0;
186 * ext_add_entry()
188 * adds a file entry to the specified directory, using the same
189 * semantics as ext_find_entry(). It returns NULL if it failed.
191 * NOTE!! The inode part of 'de' is left at 0 - which means you
192 * may not sleep between calling this and putting something into
193 * the entry, as someone else might have used it while you slept.
195 static struct buffer_head * ext_add_entry(struct inode * dir,
196 const char * name, int namelen, struct ext_dir_entry ** res_dir)
198 int i;
199 long offset;
200 unsigned short rec_len;
201 struct buffer_head * bh;
202 struct ext_dir_entry * de, * de1;
204 *res_dir = NULL;
205 if (!dir)
206 return NULL;
207 #ifdef NO_TRUNCATE
208 if (namelen > EXT_NAME_LEN)
209 return NULL;
210 #else
211 if (namelen > EXT_NAME_LEN)
212 namelen = EXT_NAME_LEN;
213 #endif
214 if (!namelen)
215 return NULL;
216 bh = ext_bread(dir,0,0);
217 if (!bh)
218 return NULL;
219 rec_len = ((8 + namelen + EXT_DIR_PAD - 1) / EXT_DIR_PAD) * EXT_DIR_PAD;
220 offset = 0;
221 de = (struct ext_dir_entry *) bh->b_data;
222 while (1) {
223 if ((char *)de >= BLOCK_SIZE+bh->b_data && offset < dir->i_size) {
224 #ifdef EXTFS_DEBUG
225 printk ("ext_add_entry: skipping to next block\n");
226 #endif
227 brelse(bh);
228 bh = NULL;
229 bh = ext_bread(dir,offset>>BLOCK_SIZE_BITS,0);
230 if (!bh)
231 return NULL;
232 de = (struct ext_dir_entry *) bh->b_data;
234 if (offset >= dir->i_size) {
235 /* Check that the directory entry fits in the block */
236 if (offset % BLOCK_SIZE == 0 ||
237 (BLOCK_SIZE - (offset % BLOCK_SIZE)) < rec_len) {
238 if ((offset % BLOCK_SIZE) != 0) {
239 /* If the entry does not fit in the
240 block, the remainder of the block
241 becomes an unused entry */
242 de->inode = 0;
243 de->rec_len = BLOCK_SIZE
244 - (offset & (BLOCK_SIZE - 1));
245 de->name_len = 0;
246 offset += de->rec_len;
247 dir->i_size += de->rec_len;
248 dir->i_dirt = 1;
249 #if 0
250 dir->i_ctime = CURRENT_TIME;
251 #endif
252 bh->b_dirt = 1;
254 brelse (bh);
255 bh = NULL;
256 #ifdef EXTFS_DEBUG
257 printk ("ext_add_entry : creating next block\n");
258 #endif
259 bh = ext_bread(dir,offset>>BLOCK_SIZE_BITS,1);
260 if (!bh)
261 return NULL; /* Other thing to do ??? */
262 de = (struct ext_dir_entry *) bh->b_data;
264 /* Allocate the entry */
265 de->inode=0;
266 de->rec_len = rec_len;
267 dir->i_size += de->rec_len;
268 dir->i_dirt = 1;
269 #if 0
270 dir->i_ctime = CURRENT_TIME;
271 #endif
273 if (de->rec_len < 8 || de->rec_len % 4 != 0 ||
274 de->rec_len < de->name_len + 8 ||
275 (((char *) de) + de->rec_len-1 >= BLOCK_SIZE+bh->b_data)) {
276 printk ("ext_addr_entry: bad dir entry\n");
277 printk ("dev=%d, dir=%d, offset=%d, rec_len=%d, name_len=%d\n",
278 dir->i_dev, dir->i_ino, offset, de->rec_len, de->name_len);
279 brelse (bh);
280 return NULL;
282 if (!de->inode && de->rec_len >= rec_len) {
283 if (de->rec_len > rec_len
284 && de->rec_len - rec_len >= EXT_DIR_MIN_SIZE) {
285 /* The found entry is too big : it is split
286 into 2 ones :
287 - the 1st one will be used to hold the name,
288 - the 2nd one is unused */
289 de1 = (struct ext_dir_entry *) ((char *) de + rec_len);
290 de1->inode = 0;
291 de1->rec_len = de->rec_len - rec_len;
292 de1->name_len = 0;
293 de->rec_len = rec_len;
295 dir->i_mtime = dir->i_ctime = CURRENT_TIME;
296 de->name_len = namelen;
297 for (i=0; i < namelen ; i++)
298 de->name[i] = name[i];
299 bh->b_dirt = 1;
300 *res_dir = de;
301 return bh;
303 offset += de->rec_len;
304 de = (struct ext_dir_entry *) ((char *) de + de->rec_len);
306 brelse(bh);
307 return NULL;
310 int ext_create(struct inode * dir,const char * name, int len, int mode,
311 struct inode ** result)
313 struct inode * inode;
314 struct buffer_head * bh;
315 struct ext_dir_entry * de;
317 *result = NULL;
318 if (!dir)
319 return -ENOENT;
320 inode = ext_new_inode(dir);
321 if (!inode) {
322 iput(dir);
323 return -ENOSPC;
325 inode->i_op = &ext_file_inode_operations;
326 inode->i_mode = mode;
327 inode->i_dirt = 1;
328 bh = ext_add_entry(dir,name,len,&de);
329 if (!bh) {
330 inode->i_nlink--;
331 inode->i_dirt = 1;
332 iput(inode);
333 iput(dir);
334 return -ENOSPC;
336 de->inode = inode->i_ino;
337 bh->b_dirt = 1;
338 brelse(bh);
339 iput(dir);
340 *result = inode;
341 return 0;
344 int ext_mknod(struct inode * dir, const char * name, int len, int mode, int rdev)
346 struct inode * inode;
347 struct buffer_head * bh;
348 struct ext_dir_entry * de;
350 if (!dir)
351 return -ENOENT;
352 bh = ext_find_entry(dir,name,len,&de,NULL,NULL);
353 if (bh) {
354 brelse(bh);
355 iput(dir);
356 return -EEXIST;
358 inode = ext_new_inode(dir);
359 if (!inode) {
360 iput(dir);
361 return -ENOSPC;
363 inode->i_uid = current->euid;
364 inode->i_mode = mode;
365 inode->i_op = NULL;
366 if (S_ISREG(inode->i_mode))
367 inode->i_op = &ext_file_inode_operations;
368 else if (S_ISDIR(inode->i_mode)) {
369 inode->i_op = &ext_dir_inode_operations;
370 if (dir->i_mode & S_ISGID)
371 inode->i_mode |= S_ISGID;
373 else if (S_ISLNK(inode->i_mode))
374 inode->i_op = &ext_symlink_inode_operations;
375 else if (S_ISCHR(inode->i_mode))
376 inode->i_op = &chrdev_inode_operations;
377 else if (S_ISBLK(inode->i_mode))
378 inode->i_op = &blkdev_inode_operations;
379 else if (S_ISFIFO(inode->i_mode))
380 init_fifo(inode);
381 if (S_ISBLK(mode) || S_ISCHR(mode))
382 inode->i_rdev = rdev;
383 #if 0
384 inode->i_mtime = inode->i_atime = CURRENT_TIME;
385 #endif
386 inode->i_dirt = 1;
387 bh = ext_add_entry(dir,name,len,&de);
388 if (!bh) {
389 inode->i_nlink--;
390 inode->i_dirt = 1;
391 iput(inode);
392 iput(dir);
393 return -ENOSPC;
395 de->inode = inode->i_ino;
396 bh->b_dirt = 1;
397 brelse(bh);
398 iput(dir);
399 iput(inode);
400 return 0;
403 int ext_mkdir(struct inode * dir, const char * name, int len, int mode)
405 struct inode * inode;
406 struct buffer_head * bh, *dir_block;
407 struct ext_dir_entry * de;
409 bh = ext_find_entry(dir,name,len,&de,NULL,NULL);
410 if (bh) {
411 brelse(bh);
412 iput(dir);
413 return -EEXIST;
415 inode = ext_new_inode(dir);
416 if (!inode) {
417 iput(dir);
418 return -ENOSPC;
420 inode->i_op = &ext_dir_inode_operations;
421 inode->i_size = 2 * 16; /* Each entry is coded on 16 bytes for "." and ".."
422 - 4 bytes for the inode number,
423 - 2 bytes for the record length
424 - 2 bytes for the name length
425 - 8 bytes for the name */
426 #if 0
427 inode->i_mtime = inode->i_atime = CURRENT_TIME;
428 #endif
429 dir_block = ext_bread(inode,0,1);
430 if (!dir_block) {
431 iput(dir);
432 inode->i_nlink--;
433 inode->i_dirt = 1;
434 iput(inode);
435 return -ENOSPC;
437 de = (struct ext_dir_entry *) dir_block->b_data;
438 de->inode=inode->i_ino;
439 de->rec_len=16;
440 de->name_len=1;
441 strcpy(de->name,".");
442 de = (struct ext_dir_entry *) ((char *) de + de->rec_len);
443 de->inode = dir->i_ino;
444 de->rec_len=16;
445 de->name_len=2;
446 strcpy(de->name,"..");
447 inode->i_nlink = 2;
448 dir_block->b_dirt = 1;
449 brelse(dir_block);
450 inode->i_mode = S_IFDIR | (mode & 0777 & ~current->umask);
451 if (dir->i_mode & S_ISGID)
452 inode->i_mode |= S_ISGID;
453 inode->i_dirt = 1;
454 bh = ext_add_entry(dir,name,len,&de);
455 if (!bh) {
456 iput(dir);
457 inode->i_nlink=0;
458 iput(inode);
459 return -ENOSPC;
461 de->inode = inode->i_ino;
462 bh->b_dirt = 1;
463 dir->i_nlink++;
464 dir->i_dirt = 1;
465 iput(dir);
466 iput(inode);
467 brelse(bh);
468 return 0;
472 * routine to check that the specified directory is empty (for rmdir)
474 static int empty_dir(struct inode * inode)
476 unsigned long offset;
477 struct buffer_head * bh;
478 struct ext_dir_entry * de, * de1;
480 if (inode->i_size < 2 * 12 || !(bh = ext_bread(inode,0,0))) {
481 printk("warning - bad directory on dev %04x\n",inode->i_dev);
482 return 1;
484 de = (struct ext_dir_entry *) bh->b_data;
485 de1 = (struct ext_dir_entry *) ((char *) de + de->rec_len);
486 if (de->inode != inode->i_ino || !de1->inode ||
487 strcmp(".",de->name) || strcmp("..",de1->name)) {
488 printk("warning - bad directory on dev %04x\n",inode->i_dev);
489 return 1;
491 offset = de->rec_len + de1->rec_len;
492 de = (struct ext_dir_entry *) ((char *) de1 + de1->rec_len);
493 while (offset < inode->i_size ) {
494 if ((void *) de >= (void *) (bh->b_data+BLOCK_SIZE)) {
495 brelse(bh);
496 bh = ext_bread(inode, offset >> BLOCK_SIZE_BITS,1);
497 if (!bh) {
498 offset += BLOCK_SIZE;
499 continue;
501 de = (struct ext_dir_entry *) bh->b_data;
503 if (de->rec_len < 8 || de->rec_len %4 != 0 ||
504 de->rec_len < de->name_len + 8) {
505 printk ("empty_dir: bad dir entry\n");
506 printk ("dev=%d, dir=%d, offset=%d, rec_len=%d, name_len=%d\n",
507 inode->i_dev, inode->i_ino, offset, de->rec_len, de->name_len);
508 brelse (bh);
509 return 1;
511 if (de->inode) {
512 brelse(bh);
513 return 0;
515 offset += de->rec_len;
516 de = (struct ext_dir_entry *) ((char *) de + de->rec_len);
518 brelse(bh);
519 return 1;
522 static inline void ext_merge_entries (struct ext_dir_entry * de,
523 struct ext_dir_entry * pde, struct ext_dir_entry * nde)
525 if (nde && !nde->inode)
526 de->rec_len += nde->rec_len;
527 if (pde && !pde->inode)
528 pde->rec_len += de->rec_len;
531 int ext_rmdir(struct inode * dir, const char * name, int len)
533 int retval;
534 struct inode * inode;
535 struct buffer_head * bh;
536 struct ext_dir_entry * de, * pde, * nde;
538 inode = NULL;
539 bh = ext_find_entry(dir,name,len,&de,&pde,&nde);
540 retval = -ENOENT;
541 if (!bh)
542 goto end_rmdir;
543 retval = -EPERM;
544 if (!(inode = iget(dir->i_sb, de->inode)))
545 goto end_rmdir;
546 if ((dir->i_mode & S_ISVTX) && current->euid &&
547 inode->i_uid != current->euid)
548 goto end_rmdir;
549 if (inode->i_dev != dir->i_dev)
550 goto end_rmdir;
551 if (inode == dir) /* we may not delete ".", but "../dir" is ok */
552 goto end_rmdir;
553 if (!S_ISDIR(inode->i_mode)) {
554 retval = -ENOTDIR;
555 goto end_rmdir;
557 if (!empty_dir(inode)) {
558 retval = -ENOTEMPTY;
559 goto end_rmdir;
561 if (inode->i_count > 1) {
562 retval = -EBUSY;
563 goto end_rmdir;
565 if (inode->i_nlink != 2)
566 printk("empty directory has nlink!=2 (%d)\n",inode->i_nlink);
567 de->inode = 0;
568 de->name_len = 0;
569 ext_merge_entries (de, pde, nde);
570 bh->b_dirt = 1;
571 inode->i_nlink=0;
572 inode->i_dirt=1;
573 dir->i_nlink--;
574 inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
575 dir->i_dirt=1;
576 retval = 0;
577 end_rmdir:
578 iput(dir);
579 iput(inode);
580 brelse(bh);
581 return retval;
584 int ext_unlink(struct inode * dir, const char * name, int len)
586 int retval;
587 struct inode * inode;
588 struct buffer_head * bh;
589 struct ext_dir_entry * de, * pde, * nde;
591 retval = -ENOENT;
592 inode = NULL;
593 bh = ext_find_entry(dir,name,len,&de,&pde,&nde);
594 if (!bh)
595 goto end_unlink;
596 if (!(inode = iget(dir->i_sb, de->inode)))
597 goto end_unlink;
598 retval = -EPERM;
599 if ((dir->i_mode & S_ISVTX) && !suser() &&
600 current->euid != inode->i_uid &&
601 current->euid != dir->i_uid)
602 goto end_unlink;
603 if (S_ISDIR(inode->i_mode))
604 goto end_unlink;
605 if (!inode->i_nlink) {
606 printk("Deleting nonexistent file (%04x:%d), %d\n",
607 inode->i_dev,inode->i_ino,inode->i_nlink);
608 inode->i_nlink=1;
610 de->inode = 0;
611 de->name_len = 0;
612 ext_merge_entries (de, pde, nde);
613 bh->b_dirt = 1;
614 inode->i_nlink--;
615 inode->i_dirt = 1;
616 inode->i_ctime = CURRENT_TIME;
617 dir->i_ctime = dir->i_mtime = inode->i_ctime;
618 dir->i_dirt = 1;
619 retval = 0;
620 end_unlink:
621 brelse(bh);
622 iput(inode);
623 iput(dir);
624 return retval;
627 int ext_symlink(struct inode * dir, const char * name, int len, const char * symname)
629 struct ext_dir_entry * de;
630 struct inode * inode = NULL;
631 struct buffer_head * bh = NULL, * name_block = NULL;
632 int i;
633 char c;
635 if (!(inode = ext_new_inode(dir))) {
636 iput(dir);
637 return -ENOSPC;
639 inode->i_mode = S_IFLNK | 0777;
640 inode->i_op = &ext_symlink_inode_operations;
641 name_block = ext_bread(inode,0,1);
642 if (!name_block) {
643 iput(dir);
644 inode->i_nlink--;
645 inode->i_dirt = 1;
646 iput(inode);
647 return -ENOSPC;
649 i = 0;
650 while (i < 1023 && (c = *(symname++)))
651 name_block->b_data[i++] = c;
652 name_block->b_data[i] = 0;
653 name_block->b_dirt = 1;
654 brelse(name_block);
655 inode->i_size = i;
656 inode->i_dirt = 1;
657 bh = ext_find_entry(dir,name,len,&de,NULL,NULL);
658 if (bh) {
659 inode->i_nlink--;
660 inode->i_dirt = 1;
661 iput(inode);
662 brelse(bh);
663 iput(dir);
664 return -EEXIST;
666 bh = ext_add_entry(dir,name,len,&de);
667 if (!bh) {
668 inode->i_nlink--;
669 inode->i_dirt = 1;
670 iput(inode);
671 iput(dir);
672 return -ENOSPC;
674 de->inode = inode->i_ino;
675 bh->b_dirt = 1;
676 brelse(bh);
677 iput(dir);
678 iput(inode);
679 return 0;
682 int ext_link(struct inode * oldinode, struct inode * dir, const char * name, int len)
684 struct ext_dir_entry * de;
685 struct buffer_head * bh;
687 if (S_ISDIR(oldinode->i_mode)) {
688 iput(oldinode);
689 iput(dir);
690 return -EPERM;
692 if (oldinode->i_nlink > 32000) {
693 iput(oldinode);
694 iput(dir);
695 return -EMLINK;
697 bh = ext_find_entry(dir,name,len,&de,NULL,NULL);
698 if (bh) {
699 brelse(bh);
700 iput(dir);
701 iput(oldinode);
702 return -EEXIST;
704 bh = ext_add_entry(dir,name,len,&de);
705 if (!bh) {
706 iput(dir);
707 iput(oldinode);
708 return -ENOSPC;
710 de->inode = oldinode->i_ino;
711 bh->b_dirt = 1;
712 brelse(bh);
713 iput(dir);
714 oldinode->i_nlink++;
715 oldinode->i_ctime = CURRENT_TIME;
716 oldinode->i_dirt = 1;
717 iput(oldinode);
718 return 0;
721 static int subdir(struct inode * new_inode, struct inode * old_inode)
723 int ino;
724 int result;
726 new_inode->i_count++;
727 result = 0;
728 for (;;) {
729 if (new_inode == old_inode) {
730 result = 1;
731 break;
733 if (new_inode->i_dev != old_inode->i_dev)
734 break;
735 ino = new_inode->i_ino;
736 if (ext_lookup(new_inode,"..",2,&new_inode))
737 break;
738 if (new_inode->i_ino == ino)
739 break;
741 iput(new_inode);
742 return result;
745 #define PARENT_INO(buffer) \
746 ((struct ext_dir_entry *) ((char *) buffer + \
747 ((struct ext_dir_entry *) buffer)->rec_len))->inode
749 #define PARENT_NAME(buffer) \
750 ((struct ext_dir_entry *) ((char *) buffer + \
751 ((struct ext_dir_entry *) buffer)->rec_len))->name
754 * rename uses retrying to avoid race-conditions: at least they should be minimal.
755 * it tries to allocate all the blocks, then sanity-checks, and if the sanity-
756 * checks fail, it tries to restart itself again. Very practical - no changes
757 * are done until we know everything works ok.. and then all the changes can be
758 * done in one fell swoop when we have claimed all the buffers needed.
760 * Anybody can rename anything with this: the permission checks are left to the
761 * higher-level routines.
763 static int do_ext_rename(struct inode * old_dir, const char * old_name, int old_len,
764 struct inode * new_dir, const char * new_name, int new_len)
766 struct inode * old_inode, * new_inode;
767 struct buffer_head * old_bh, * new_bh, * dir_bh;
768 struct ext_dir_entry * old_de, * new_de, * pde, * nde;
769 int retval;
771 goto start_up;
772 try_again:
773 brelse(old_bh);
774 brelse(new_bh);
775 brelse(dir_bh);
776 iput(old_inode);
777 iput(new_inode);
778 current->counter = 0;
779 schedule();
780 start_up:
781 old_inode = new_inode = NULL;
782 old_bh = new_bh = dir_bh = NULL;
783 old_bh = ext_find_entry(old_dir,old_name,old_len,&old_de,&pde,&nde);
784 retval = -ENOENT;
785 if (!old_bh)
786 goto end_rename;
787 old_inode = __iget(old_dir->i_sb, old_de->inode,0); /* don't cross mnt-points */
788 if (!old_inode)
789 goto end_rename;
790 retval = -EPERM;
791 if ((old_dir->i_mode & S_ISVTX) &&
792 current->euid != old_inode->i_uid &&
793 current->euid != old_dir->i_uid && !suser())
794 goto end_rename;
795 new_bh = ext_find_entry(new_dir,new_name,new_len,&new_de,NULL,NULL);
796 if (new_bh) {
797 new_inode = __iget(new_dir->i_sb, new_de->inode,0); /* don't cross mnt-points */
798 if (!new_inode) {
799 brelse(new_bh);
800 new_bh = NULL;
803 if (new_inode == old_inode) {
804 retval = 0;
805 goto end_rename;
807 if (new_inode && S_ISDIR(new_inode->i_mode)) {
808 retval = -EEXIST;
809 goto end_rename;
811 retval = -EPERM;
812 if (new_inode && (new_dir->i_mode & S_ISVTX) &&
813 current->euid != new_inode->i_uid &&
814 current->euid != new_dir->i_uid && !suser())
815 goto end_rename;
816 if (S_ISDIR(old_inode->i_mode)) {
817 retval = -EEXIST;
818 if (new_bh)
819 goto end_rename;
820 retval = -EACCES;
821 if (!permission(old_inode, MAY_WRITE))
822 goto end_rename;
823 retval = -EINVAL;
824 if (subdir(new_dir, old_inode))
825 goto end_rename;
826 retval = -EIO;
827 dir_bh = ext_bread(old_inode,0,0);
828 if (!dir_bh)
829 goto end_rename;
830 if (PARENT_INO(dir_bh->b_data) != old_dir->i_ino)
831 goto end_rename;
833 if (!new_bh)
834 new_bh = ext_add_entry(new_dir,new_name,new_len,&new_de);
835 retval = -ENOSPC;
836 if (!new_bh)
837 goto end_rename;
838 /* sanity checking before doing the rename - avoid races */
839 if (new_inode && (new_de->inode != new_inode->i_ino))
840 goto try_again;
841 if (new_de->inode && !new_inode)
842 goto try_again;
843 if (old_de->inode != old_inode->i_ino)
844 goto try_again;
845 /* ok, that's it */
846 old_de->inode = 0;
847 old_de->name_len = 0;
848 new_de->inode = old_inode->i_ino;
849 ext_merge_entries (old_de, pde, nde);
850 if (new_inode) {
851 new_inode->i_nlink--;
852 new_inode->i_dirt = 1;
854 old_bh->b_dirt = 1;
855 new_bh->b_dirt = 1;
856 if (dir_bh) {
857 PARENT_INO(dir_bh->b_data) = new_dir->i_ino;
858 dir_bh->b_dirt = 1;
859 old_dir->i_nlink--;
860 new_dir->i_nlink++;
861 old_dir->i_dirt = 1;
862 new_dir->i_dirt = 1;
864 retval = 0;
865 end_rename:
866 brelse(dir_bh);
867 brelse(old_bh);
868 brelse(new_bh);
869 iput(old_inode);
870 iput(new_inode);
871 iput(old_dir);
872 iput(new_dir);
873 return retval;
877 * Ok, rename also locks out other renames, as they can change the parent of
878 * a directory, and we don't want any races. Other races are checked for by
879 * "do_rename()", which restarts if there are inconsistencies.
881 * Note that there is no race between different filesystems: it's only within
882 * the same device that races occur: many renames can happen at once, as long
883 * as they are on different partitions.
885 int ext_rename(struct inode * old_dir, const char * old_name, int old_len,
886 struct inode * new_dir, const char * new_name, int new_len)
888 static struct wait_queue * wait = NULL;
889 static int lock = 0;
890 int result;
892 while (lock)
893 sleep_on(&wait);
894 lock = 1;
895 result = do_ext_rename(old_dir, old_name, old_len,
896 new_dir, new_name, new_len);
897 lock = 0;
898 wake_up(&wait);
899 return result;