This source file includes following definitions.
- ext_match
- ext_find_entry
- ext_lookup
- ext_add_entry
- ext_create
- ext_mknod
- ext_mkdir
- empty_dir
- ext_merge_entries
- ext_rmdir
- ext_unlink
- ext_symlink
- ext_link
- subdir
- do_ext_rename
- ext_rename
1
2
3
4
5
6
7
8
9
10
11
12
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>
20
21 #include <asm/segment.h>
22
23 #include <const.h>
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39 #define EXT_DIR_PAD 8
40
41
42
43
44
45
46
47
48
49 #define EXT_DIR_MIN_SIZE 12
50
51
52
53
54
55
56
57
58 static int ext_match(int len,const char * name,struct ext_dir_entry * de)
59 {
60 register int same __asm__("ax");
61
62 if (!de || !de->inode || len > EXT_NAME_LEN)
63 return 0;
64
65 if (!len && (de->name[0]=='.') && (de->name[1]=='\0'))
66 return 1;
67
68
69 if (len < EXT_NAME_LEN && len != de->name_len)
70 return 0;
71 __asm__("cld\n\t"
72 "fs ; repe ; cmpsb\n\t"
73 "setz %%al"
74 :"=a" (same)
75 :"0" (0),"S" ((long) name),"D" ((long) de->name),"c" (len)
76 :"cx","di","si");
77 return same;
78 }
79
80
81
82
83
84
85
86
87
88
89
90
91 static struct buffer_head * ext_find_entry(struct inode * dir,
92 const char * name, int namelen, struct ext_dir_entry ** res_dir,
93 struct ext_dir_entry ** prev_dir, struct ext_dir_entry ** next_dir)
94 {
95
96 int block ;
97 long offset;
98 struct buffer_head * bh;
99 struct ext_dir_entry * de;
100
101 *res_dir = NULL;
102 if (!dir)
103 return NULL;
104 #ifdef NO_TRUNCATE
105 if (namelen > EXT_NAME_LEN)
106 return NULL;
107 #else
108 if (namelen > EXT_NAME_LEN)
109 namelen = EXT_NAME_LEN;
110 #endif
111
112 if (!(block = dir->i_data[0]))
113 return NULL;
114 if (!(bh = bread(dir->i_dev, block, BLOCK_SIZE)))
115 return NULL;
116 if (prev_dir)
117 *prev_dir = NULL;
118 if (next_dir)
119 *next_dir = NULL;
120
121 offset = 0;
122 de = (struct ext_dir_entry *) bh->b_data;
123 while (offset < dir->i_size) {
124 if ((char *)de >= BLOCK_SIZE+bh->b_data) {
125 brelse(bh);
126 bh = NULL;
127 if (!(block = ext_bmap(dir,offset>>BLOCK_SIZE_BITS)) ||
128 !(bh = bread(dir->i_dev, block, BLOCK_SIZE))) {
129
130
131 continue;
132 }
133 de = (struct ext_dir_entry *) bh->b_data;
134 if (prev_dir)
135 *prev_dir = NULL;
136 }
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 *next_dir = (struct ext_dir_entry *)
142 ((char *) de + de->rec_len);
143 else
144 *next_dir = NULL;
145 return bh;
146 }
147 offset += de->rec_len;
148 if (prev_dir)
149 *prev_dir = de;
150 de = (struct ext_dir_entry *) ((char *) de + de->rec_len);
151
152 }
153 brelse(bh);
154 return NULL;
155 }
156
157 int ext_lookup(struct inode * dir,const char * name, int len,
158 struct inode ** result)
159 {
160 int ino;
161 struct ext_dir_entry * de;
162 struct buffer_head * bh;
163
164 *result = NULL;
165 if (!dir)
166 return -ENOENT;
167 if (!S_ISDIR(dir->i_mode)) {
168 iput(dir);
169 return -ENOENT;
170 }
171 if (!(bh = ext_find_entry(dir,name,len,&de,NULL,NULL))) {
172 iput(dir);
173 return -ENOENT;
174 }
175 ino = de->inode;
176 brelse(bh);
177 if (!(*result = iget(dir->i_dev,ino))) {
178 iput(dir);
179 return -EACCES;
180 }
181 iput(dir);
182 return 0;
183 }
184
185
186
187
188
189
190
191
192
193
194
195 static struct buffer_head * ext_add_entry(struct inode * dir,
196 const char * name, int namelen, struct ext_dir_entry ** res_dir)
197 {
198 int block,i;
199 long offset;
200 unsigned short rec_len;
201 struct buffer_head * bh;
202 struct ext_dir_entry * de, * de1;
203
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 if (!(block = dir->i_data[0]))
217 return NULL;
218 if (!(bh = bread(dir->i_dev, block, BLOCK_SIZE)))
219 return NULL;
220 rec_len = ((8 + namelen + EXT_DIR_PAD - 1) / EXT_DIR_PAD) * EXT_DIR_PAD;
221
222 offset = 0;
223 de = (struct ext_dir_entry *) bh->b_data;
224 while (1) {
225 if ((char *)de >= BLOCK_SIZE+bh->b_data && offset < dir->i_size) {
226 #ifdef EXTFS_DEBUG
227 printk ("ext_add_entry: skipping to next block\n");
228 #endif
229 brelse(bh);
230 bh = NULL;
231 block = ext_create_block(dir,offset>>BLOCK_SIZE_BITS);
232 if (!block)
233 return NULL;
234 if (!(bh = bread(dir->i_dev, block, BLOCK_SIZE))) {
235
236 offset += BLOCK_SIZE;
237 continue;
238 }
239 de = (struct ext_dir_entry *) bh->b_data;
240 }
241 if (offset >= dir->i_size) {
242
243 if (offset % BLOCK_SIZE == 0
244 || (BLOCK_SIZE - (offset % BLOCK_SIZE)) < rec_len) {
245 if ((offset % BLOCK_SIZE) != 0) {
246
247
248
249 de->inode = 0;
250 de->rec_len = BLOCK_SIZE
251 - (offset & (BLOCK_SIZE - 1));
252 de->name_len = 0;
253 offset += de->rec_len;
254 dir->i_size += de->rec_len;
255 dir->i_dirt = 1;
256 dir->i_ctime = CURRENT_TIME;
257 bh->b_dirt = 1;
258 }
259 brelse (bh);
260 bh = NULL;
261 block = ext_create_block (dir,offset>>BLOCK_SIZE_BITS);
262 #ifdef EXTFS_DEBUG
263 printk ("ext_add_entry : creating next block\n");
264 #endif
265 if (!block)
266 return NULL;
267 if (!(bh = bread(dir->i_dev, block, BLOCK_SIZE)))
268 return NULL;
269 de = (struct ext_dir_entry *) bh->b_data;
270 }
271
272 de->inode=0;
273 de->rec_len = rec_len;
274
275 dir->i_size += de->rec_len;
276 dir->i_dirt = 1;
277 dir->i_ctime = CURRENT_TIME;
278 }
279 if (!de->inode && de->rec_len >= rec_len) {
280 if (de->rec_len > rec_len
281 && de->rec_len - rec_len >= EXT_DIR_MIN_SIZE) {
282
283
284
285
286 de1 = (struct ext_dir_entry *) ((char *) de + rec_len);
287 de1->inode = 0;
288 de1->rec_len = de->rec_len - rec_len;
289 de1->name_len = 0;
290 de->rec_len = rec_len;
291 }
292 dir->i_mtime = CURRENT_TIME;
293 de->name_len = namelen;
294 for (i=0; i < namelen ; i++)
295 de->name[i]=get_fs_byte(name+i);
296 bh->b_dirt = 1;
297 *res_dir = de;
298 return bh;
299 }
300 offset += de->rec_len;
301 de = (struct ext_dir_entry *) ((char *) de + de->rec_len);
302 }
303 brelse(bh);
304 return NULL;
305 }
306
307 int ext_create(struct inode * dir,const char * name, int len, int mode,
308 struct inode ** result)
309 {
310 struct inode * inode;
311 struct buffer_head * bh;
312 struct ext_dir_entry * de;
313
314 *result = NULL;
315 if (!dir)
316 return -ENOENT;
317 inode = ext_new_inode(dir->i_dev);
318 if (!inode) {
319 iput(dir);
320 return -ENOSPC;
321 }
322 inode->i_op = &ext_file_inode_operations;
323 inode->i_mode = mode;
324 inode->i_dirt = 1;
325 bh = ext_add_entry(dir,name,len,&de);
326 if (!bh) {
327 inode->i_nlink--;
328 inode->i_dirt = 1;
329 iput(inode);
330 iput(dir);
331 return -ENOSPC;
332 }
333 de->inode = inode->i_ino;
334 bh->b_dirt = 1;
335 brelse(bh);
336 iput(dir);
337 *result = inode;
338 return 0;
339 }
340
341 int ext_mknod(struct inode * dir, const char * name, int len, int mode, int rdev)
342 {
343 struct inode * inode;
344 struct buffer_head * bh;
345 struct ext_dir_entry * de;
346
347 if (!dir)
348 return -ENOENT;
349 bh = ext_find_entry(dir,name,len,&de,NULL,NULL);
350 if (bh) {
351 brelse(bh);
352 iput(dir);
353 return -EEXIST;
354 }
355 inode = ext_new_inode(dir->i_dev);
356 if (!inode) {
357 iput(dir);
358 return -ENOSPC;
359 }
360 inode->i_uid = current->euid;
361 inode->i_mode = mode;
362 inode->i_op = NULL;
363 if (S_ISREG(inode->i_mode))
364 inode->i_op = &ext_file_inode_operations;
365 else if (S_ISDIR(inode->i_mode))
366 inode->i_op = &ext_dir_inode_operations;
367 else if (S_ISLNK(inode->i_mode))
368 inode->i_op = &ext_symlink_inode_operations;
369 else if (S_ISCHR(inode->i_mode))
370 inode->i_op = &ext_chrdev_inode_operations;
371 else if (S_ISBLK(inode->i_mode))
372 inode->i_op = &ext_blkdev_inode_operations;
373 else if (S_ISFIFO(inode->i_mode)) {
374 inode->i_op = &ext_fifo_inode_operations;
375 inode->i_size = 0;
376 inode->i_pipe = 1;
377 PIPE_HEAD(*inode) = PIPE_TAIL(*inode) = 0;
378 PIPE_READERS(*inode) = PIPE_WRITERS(*inode) = 0;
379 }
380 if (S_ISBLK(mode) || S_ISCHR(mode))
381 inode->i_rdev = rdev;
382 inode->i_mtime = inode->i_atime = CURRENT_TIME;
383 inode->i_dirt = 1;
384 bh = ext_add_entry(dir,name,len,&de);
385 if (!bh) {
386 inode->i_nlink--;
387 inode->i_dirt = 1;
388 iput(inode);
389 iput(dir);
390 return -ENOSPC;
391 }
392 de->inode = inode->i_ino;
393 bh->b_dirt = 1;
394 brelse(bh);
395 iput(dir);
396 iput(inode);
397 return 0;
398 }
399
400 int ext_mkdir(struct inode * dir, const char * name, int len, int mode)
401 {
402 struct inode * inode;
403 struct buffer_head * bh, *dir_block;
404 struct ext_dir_entry * de;
405
406 bh = ext_find_entry(dir,name,len,&de,NULL,NULL);
407 if (bh) {
408 brelse(bh);
409 iput(dir);
410 return -EEXIST;
411 }
412 inode = ext_new_inode(dir->i_dev);
413 if (!inode) {
414 iput(dir);
415 return -ENOSPC;
416 }
417 inode->i_op = &ext_dir_inode_operations;
418 inode->i_size = 2 * 16;
419
420
421
422
423 inode->i_mtime = inode->i_atime = CURRENT_TIME;
424 if (!(inode->i_data[0] = ext_new_block(inode->i_dev))) {
425 iput(dir);
426 inode->i_nlink--;
427 inode->i_dirt = 1;
428 iput(inode);
429 return -ENOSPC;
430 }
431 inode->i_dirt = 1;
432 if (!(dir_block = bread(inode->i_dev, inode->i_data[0], BLOCK_SIZE))) {
433 iput(dir);
434 inode->i_nlink--;
435 inode->i_dirt = 1;
436 iput(inode);
437 return -EIO;
438 }
439 de = (struct ext_dir_entry *) dir_block->b_data;
440 de->inode=inode->i_ino;
441 de->rec_len=16;
442 de->name_len=1;
443 strcpy(de->name,".");
444
445 de = (struct ext_dir_entry *) ((char *) de + de->rec_len);
446 de->inode = dir->i_ino;
447 de->rec_len=16;
448 de->name_len=2;
449 strcpy(de->name,"..");
450 inode->i_nlink = 2;
451 dir_block->b_dirt = 1;
452 brelse(dir_block);
453 inode->i_mode = I_DIRECTORY | (mode & 0777 & ~current->umask);
454 inode->i_dirt = 1;
455 bh = ext_add_entry(dir,name,len,&de);
456 if (!bh) {
457 iput(dir);
458 inode->i_nlink=0;
459 iput(inode);
460 return -ENOSPC;
461 }
462 de->inode = inode->i_ino;
463 bh->b_dirt = 1;
464 dir->i_nlink++;
465 dir->i_dirt = 1;
466 iput(dir);
467 iput(inode);
468 brelse(bh);
469 return 0;
470 }
471
472
473
474
475 static int empty_dir(struct inode * inode)
476 {
477 int block;
478
479 unsigned long offset;
480 struct buffer_head * bh;
481 struct ext_dir_entry * de, * de1;
482
483
484 if (inode->i_size < 2 * 12 || !inode->i_data[0] ||
485 !(bh=bread(inode->i_dev, inode->i_data[0], BLOCK_SIZE))) {
486 printk("warning - bad directory on dev %04x\n",inode->i_dev);
487 return 0;
488 }
489 de = (struct ext_dir_entry *) bh->b_data;
490 de1 = (struct ext_dir_entry *) ((char *) de + de->rec_len);
491 if (de->inode != inode->i_ino || !de1->inode ||
492 strcmp(".",de->name) || strcmp("..",de1->name)) {
493 printk("warning - bad directory on dev %04x\n",inode->i_dev);
494 return 0;
495 }
496
497 offset = de->rec_len + de1->rec_len;
498 de = (struct ext_dir_entry *) ((char *) de1 + de1->rec_len);
499 while (offset < inode->i_size ) {
500 if ((void *) de >= (void *) (bh->b_data+BLOCK_SIZE)) {
501 brelse(bh);
502 block = ext_bmap(inode, offset >> BLOCK_SIZE_BITS);
503 if (!block) {
504 offset += BLOCK_SIZE;
505 continue;
506 }
507 if (!(bh=bread(inode->i_dev, block, BLOCK_SIZE)))
508 return 0;
509 de = (struct ext_dir_entry *) bh->b_data;
510 }
511 if (de->inode) {
512 brelse(bh);
513 return 0;
514 }
515 offset += de->rec_len;
516 de = (struct ext_dir_entry *) ((char *) de + de->rec_len);
517 }
518 brelse(bh);
519 return 1;
520 }
521
522 static inline void ext_merge_entries (struct ext_dir_entry * de,
523 struct ext_dir_entry * pde, struct ext_dir_entry * nde)
524 {
525 if (! nde->inode)
526 de->rec_len += nde->rec_len;
527 if (! pde->inode)
528 pde->rec_len += de->rec_len;
529 }
530
531 int ext_rmdir(struct inode * dir, const char * name, int len)
532 {
533 int retval;
534 struct inode * inode;
535 struct buffer_head * bh;
536 struct ext_dir_entry * de, * pde, * nde;
537
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_dev, 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)
552 goto end_rmdir;
553 if (!S_ISDIR(inode->i_mode)) {
554 retval = -ENOTDIR;
555 goto end_rmdir;
556 }
557 if (!empty_dir(inode)) {
558 retval = -ENOTEMPTY;
559 goto end_rmdir;
560 }
561 if (inode->i_count > 1) {
562 retval = -EBUSY;
563 goto end_rmdir;
564 }
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 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;
582 }
583
584 int ext_unlink(struct inode * dir, const char * name, int len)
585 {
586 int retval;
587 struct inode * inode;
588 struct buffer_head * bh;
589 struct ext_dir_entry * de, * pde, * nde;
590
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_dev, 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;
609 }
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 retval = 0;
618 end_unlink:
619 brelse(bh);
620 iput(inode);
621 iput(dir);
622 return retval;
623 }
624
625 int ext_symlink(struct inode * dir, const char * name, int len, const char * symname)
626 {
627 struct ext_dir_entry * de;
628 struct inode * inode = NULL;
629 struct buffer_head * bh = NULL, * name_block = NULL;
630 int i;
631 char c;
632
633 if (!(inode = ext_new_inode(dir->i_dev))) {
634 iput(dir);
635 return -ENOSPC;
636 }
637 inode->i_mode = S_IFLNK | 0777;
638 inode->i_op = &ext_symlink_inode_operations;
639 if (!(inode->i_data[0] = ext_new_block(inode->i_dev))) {
640 iput(dir);
641 inode->i_nlink--;
642 inode->i_dirt = 1;
643 iput(inode);
644 return -ENOSPC;
645 }
646 inode->i_dirt = 1;
647 if (!(name_block = bread(inode->i_dev, inode->i_data[0], BLOCK_SIZE))) {
648 iput(dir);
649 inode->i_nlink--;
650 inode->i_dirt = 1;
651 iput(inode);
652 return -EIO;
653 }
654 i = 0;
655 while (i < 1023 && (c=get_fs_byte(symname++)))
656 name_block->b_data[i++] = c;
657 name_block->b_data[i] = 0;
658 name_block->b_dirt = 1;
659 brelse(name_block);
660 inode->i_size = i;
661 inode->i_dirt = 1;
662 bh = ext_find_entry(dir,name,len,&de,NULL,NULL);
663 if (bh) {
664 inode->i_nlink--;
665 inode->i_dirt = 1;
666 iput(inode);
667 brelse(bh);
668 iput(dir);
669 return -EEXIST;
670 }
671 bh = ext_add_entry(dir,name,len,&de);
672 if (!bh) {
673 inode->i_nlink--;
674 inode->i_dirt = 1;
675 iput(inode);
676 iput(dir);
677 return -ENOSPC;
678 }
679 de->inode = inode->i_ino;
680 bh->b_dirt = 1;
681 brelse(bh);
682 iput(dir);
683 iput(inode);
684 return 0;
685 }
686
687 int ext_link(struct inode * oldinode, struct inode * dir, const char * name, int len)
688 {
689 struct ext_dir_entry * de;
690 struct buffer_head * bh;
691
692 if (S_ISDIR(oldinode->i_mode)) {
693 iput(oldinode);
694 iput(dir);
695 return -EPERM;
696 }
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;
703 }
704 bh = ext_add_entry(dir,name,len,&de);
705 if (!bh) {
706 iput(dir);
707 iput(oldinode);
708 return -ENOSPC;
709 }
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;
719 }
720
721 static int subdir(struct inode * new, struct inode * old)
722 {
723 unsigned short fs;
724 int ino;
725 int result;
726
727 __asm__("mov %%fs,%0":"=r" (fs));
728 __asm__("mov %0,%%fs"::"r" ((unsigned short) 0x10));
729 new->i_count++;
730 result = 0;
731 for (;;) {
732 if (new == old) {
733 result = 1;
734 break;
735 }
736 if (new->i_dev != old->i_dev)
737 break;
738 ino = new->i_ino;
739 if (ext_lookup(new,"..",2,&new))
740 break;
741 if (new->i_ino == ino)
742 break;
743 }
744 iput(new);
745 __asm__("mov %0,%%fs"::"r" (fs));
746 return result;
747 }
748
749 #define PARENT_INO(buffer) \
750 ((struct ext_dir_entry *) ((char *) buffer + \
751 ((struct ext_dir_entry *) buffer)->rec_len))->inode
752
753
754 #define PARENT_NAME(buffer) \
755 ((struct ext_dir_entry *) ((char *) buffer + \
756 ((struct ext_dir_entry *) buffer)->rec_len))->name
757
758
759
760
761
762
763
764
765
766
767
768
769 static int do_ext_rename(struct inode * old_dir, const char * old_name, int old_len,
770 struct inode * new_dir, const char * new_name, int new_len)
771 {
772 struct inode * old_inode, * new_inode;
773 struct buffer_head * old_bh, * new_bh, * dir_bh;
774 struct ext_dir_entry * old_de, * new_de, * pde, * nde;
775 int retval;
776
777 goto start_up;
778 try_again:
779 brelse(old_bh);
780 brelse(new_bh);
781 brelse(dir_bh);
782 iput(old_inode);
783 iput(new_inode);
784 current->counter = 0;
785 schedule();
786 start_up:
787 old_inode = new_inode = NULL;
788 old_bh = new_bh = dir_bh = NULL;
789 old_bh = ext_find_entry(old_dir,old_name,old_len,&old_de,&pde,&nde);
790 retval = -ENOENT;
791 if (!old_bh)
792 goto end_rename;
793 old_inode = iget(old_dir->i_dev, old_de->inode);
794 if (!old_inode)
795 goto end_rename;
796 if ((old_dir->i_mode & S_ISVTX) &&
797 current->euid != old_inode->i_uid &&
798 current->euid != old_dir->i_uid && !suser())
799 goto end_rename;
800 new_bh = ext_find_entry(new_dir,new_name,new_len,&new_de,NULL,NULL);
801 if (new_bh) {
802 new_inode = iget(new_dir->i_dev, new_de->inode);
803 if (!new_inode) {
804 brelse(new_bh);
805 new_bh = NULL;
806 }
807 }
808 if (new_inode == old_inode) {
809 retval = 0;
810 goto end_rename;
811 }
812 if (S_ISDIR(new_inode->i_mode)) {
813 retval = -EEXIST;
814 goto end_rename;
815 }
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 if (!old_inode->i_data[0])
828 goto end_rename;
829 if (!(dir_bh = bread(old_inode->i_dev, old_inode->i_data[0], BLOCK_SIZE)))
830 goto end_rename;
831 if (PARENT_INO(dir_bh->b_data) != old_dir->i_ino)
832 goto end_rename;
833 }
834 if (!new_bh)
835 new_bh = ext_add_entry(new_dir,new_name,new_len,&new_de);
836 retval = -ENOSPC;
837 if (!new_bh)
838 goto end_rename;
839
840 if (new_inode && (new_de->inode != new_inode->i_ino))
841 goto try_again;
842 if (new_de->inode && !new_inode)
843 goto try_again;
844 if (old_de->inode != old_inode->i_ino)
845 goto try_again;
846
847 old_de->inode = 0;
848 old_de->name_len = 0;
849 new_de->inode = old_inode->i_ino;
850 ext_merge_entries (old_de, pde, nde);
851 if (new_inode) {
852 new_inode->i_nlink--;
853 new_inode->i_dirt = 1;
854 }
855 old_bh->b_dirt = 1;
856 new_bh->b_dirt = 1;
857 if (dir_bh) {
858 PARENT_INO(dir_bh->b_data) = new_dir->i_ino;
859 dir_bh->b_dirt = 1;
860 old_dir->i_nlink--;
861 new_dir->i_nlink++;
862 old_dir->i_dirt = 1;
863 new_dir->i_dirt = 1;
864 }
865 retval = 0;
866 end_rename:
867 brelse(dir_bh);
868 brelse(old_bh);
869 brelse(new_bh);
870 iput(old_inode);
871 iput(new_inode);
872 iput(old_dir);
873 iput(new_dir);
874 return retval;
875 }
876
877
878
879
880
881
882
883
884
885
886 int ext_rename(struct inode * old_dir, const char * old_name, int old_len,
887 struct inode * new_dir, const char * new_name, int new_len)
888 {
889 static struct wait_queue * wait = NULL;
890 static int lock = 0;
891 int result;
892
893 while (lock)
894 sleep_on(&wait);
895 lock = 1;
896 result = do_ext_rename(old_dir, old_name, old_len,
897 new_dir, new_name, new_len);
898 lock = 0;
899 wake_up(&wait);
900 return result;
901 }