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
24
25
26
27
28
29
30
31
32
33
34
35
36
37 #define EXT_DIR_PAD 8
38
39
40
41
42
43
44
45
46
47 #define EXT_DIR_MIN_SIZE 12
48
49
50
51
52
53
54
55
56 static int ext_match(int len,const char * name,struct ext_dir_entry * de)
57 {
58 if (!de || !de->inode || len > EXT_NAME_LEN)
59 return 0;
60
61 if (!len && (de->name[0]=='.') && (de->name[1]=='\0'))
62 return 1;
63 if (len != de->name_len)
64 return 0;
65 return !memcmp(name, de->name, len);
66 }
67
68
69
70
71
72
73
74
75
76
77
78
79 static struct buffer_head * ext_find_entry(struct inode * dir,
80 const char * name, int namelen, struct ext_dir_entry ** res_dir,
81 struct ext_dir_entry ** prev_dir, struct ext_dir_entry ** next_dir)
82 {
83 long offset;
84 struct buffer_head * bh;
85 struct ext_dir_entry * de;
86
87 *res_dir = NULL;
88 if (!dir)
89 return NULL;
90 #ifdef NO_TRUNCATE
91 if (namelen > EXT_NAME_LEN)
92 return NULL;
93 #else
94 if (namelen > EXT_NAME_LEN)
95 namelen = EXT_NAME_LEN;
96 #endif
97 bh = ext_bread(dir,0,0);
98 if (!bh)
99 return NULL;
100 if (prev_dir)
101 *prev_dir = NULL;
102 if (next_dir)
103 *next_dir = NULL;
104 offset = 0;
105 de = (struct ext_dir_entry *) bh->b_data;
106 while (offset < dir->i_size) {
107 if ((char *)de >= BLOCK_SIZE+bh->b_data) {
108 brelse(bh);
109 bh = NULL;
110 bh = ext_bread(dir,offset>>BLOCK_SIZE_BITS,0);
111 if (!bh)
112 continue;
113 de = (struct ext_dir_entry *) bh->b_data;
114 if (prev_dir)
115 *prev_dir = NULL;
116 }
117 if (de->rec_len < 8 || de->rec_len % 8 != 0 ||
118 de->rec_len < de->name_len + 8 ||
119 (((char *) de) + de->rec_len-1 >= BLOCK_SIZE+bh->b_data)) {
120 printk ("ext_find_entry: bad dir entry\n");
121 printk ("dev=%s, dir=%ld, offset=%ld, "
122 "rec_len=%d, name_len=%d\n",
123 kdevname(dir->i_dev), dir->i_ino, offset,
124 de->rec_len, de->name_len);
125 de = (struct ext_dir_entry *) (bh->b_data+BLOCK_SIZE);
126 offset = ((offset / BLOCK_SIZE) + 1) * BLOCK_SIZE;
127 continue;
128
129
130 }
131 if (ext_match(namelen,name,de)) {
132 *res_dir = de;
133 if (next_dir)
134 if (offset + de->rec_len < dir->i_size &&
135 ((char *)de) + de->rec_len < BLOCK_SIZE+bh->b_data)
136 *next_dir = (struct ext_dir_entry *)
137 ((char *) de + de->rec_len);
138 else
139 *next_dir = NULL;
140 return bh;
141 }
142 offset += de->rec_len;
143 if (prev_dir)
144 *prev_dir = de;
145 de = (struct ext_dir_entry *) ((char *) de + de->rec_len);
146 }
147 brelse(bh);
148 return NULL;
149 }
150
151 int ext_lookup(struct inode * dir,const char * name, int len,
152 struct inode ** result)
153 {
154 int ino;
155 struct ext_dir_entry * de;
156 struct buffer_head * bh;
157
158 *result = NULL;
159 if (!dir)
160 return -ENOENT;
161 if (!S_ISDIR(dir->i_mode)) {
162 iput(dir);
163 return -ENOENT;
164 }
165 if (!(bh = ext_find_entry(dir,name,len,&de,NULL,NULL))) {
166 iput(dir);
167 return -ENOENT;
168 }
169 ino = de->inode;
170 brelse(bh);
171 if (!(*result = iget(dir->i_sb,ino))) {
172 iput(dir);
173 return -EACCES;
174 }
175 iput(dir);
176 return 0;
177 }
178
179
180
181
182
183
184
185
186
187
188
189 static struct buffer_head * ext_add_entry(struct inode * dir,
190 const char * name, int namelen, struct ext_dir_entry ** res_dir)
191 {
192 int i;
193 long offset;
194 unsigned short rec_len;
195 struct buffer_head * bh;
196 struct ext_dir_entry * de, * de1;
197
198 *res_dir = NULL;
199 if (!dir)
200 return NULL;
201 #ifdef NO_TRUNCATE
202 if (namelen > EXT_NAME_LEN)
203 return NULL;
204 #else
205 if (namelen > EXT_NAME_LEN)
206 namelen = EXT_NAME_LEN;
207 #endif
208 if (!namelen)
209 return NULL;
210 bh = ext_bread(dir,0,0);
211 if (!bh)
212 return NULL;
213 rec_len = ((8 + namelen + EXT_DIR_PAD - 1) / EXT_DIR_PAD) * EXT_DIR_PAD;
214 offset = 0;
215 de = (struct ext_dir_entry *) bh->b_data;
216 while (1) {
217 if ((char *)de >= BLOCK_SIZE+bh->b_data && offset < dir->i_size) {
218 #ifdef EXTFS_DEBUG
219 printk ("ext_add_entry: skipping to next block\n");
220 #endif
221 brelse(bh);
222 bh = NULL;
223 bh = ext_bread(dir,offset>>BLOCK_SIZE_BITS,0);
224 if (!bh)
225 return NULL;
226 de = (struct ext_dir_entry *) bh->b_data;
227 }
228 if (offset >= dir->i_size) {
229
230 if (offset % BLOCK_SIZE == 0 ||
231 (BLOCK_SIZE - (offset % BLOCK_SIZE)) < rec_len) {
232 if ((offset % BLOCK_SIZE) != 0) {
233
234
235
236 de->inode = 0;
237 de->rec_len = BLOCK_SIZE
238 - (offset & (BLOCK_SIZE - 1));
239 de->name_len = 0;
240 offset += de->rec_len;
241 dir->i_size += de->rec_len;
242 dir->i_dirt = 1;
243 #if 0
244 dir->i_ctime = CURRENT_TIME;
245 #endif
246 mark_buffer_dirty(bh, 1);
247 }
248 brelse (bh);
249 bh = NULL;
250 #ifdef EXTFS_DEBUG
251 printk ("ext_add_entry : creating next block\n");
252 #endif
253 bh = ext_bread(dir,offset>>BLOCK_SIZE_BITS,1);
254 if (!bh)
255 return NULL;
256 de = (struct ext_dir_entry *) bh->b_data;
257 }
258
259 de->inode=0;
260 de->rec_len = rec_len;
261 dir->i_size += de->rec_len;
262 dir->i_dirt = 1;
263 #if 0
264 dir->i_ctime = CURRENT_TIME;
265 #endif
266 }
267 if (de->rec_len < 8 || de->rec_len % 4 != 0 ||
268 de->rec_len < de->name_len + 8 ||
269 (((char *) de) + de->rec_len-1 >= BLOCK_SIZE+bh->b_data)) {
270 printk ("ext_addr_entry: bad dir entry\n");
271 printk ("dev=%s, dir=%ld, offset=%ld, "
272 "rec_len=%d, name_len=%d\n",
273 kdevname(dir->i_dev), dir->i_ino, offset,
274 de->rec_len, de->name_len);
275 brelse (bh);
276 return NULL;
277 }
278 if (!de->inode && de->rec_len >= rec_len) {
279 if (de->rec_len > rec_len
280 && de->rec_len - rec_len >= EXT_DIR_MIN_SIZE) {
281
282
283
284
285 de1 = (struct ext_dir_entry *) ((char *) de + rec_len);
286 de1->inode = 0;
287 de1->rec_len = de->rec_len - rec_len;
288 de1->name_len = 0;
289 de->rec_len = rec_len;
290 }
291 dir->i_mtime = dir->i_ctime = CURRENT_TIME;
292 dir->i_dirt = 1;
293 de->name_len = namelen;
294 for (i=0; i < namelen ; i++)
295 de->name[i] = name[i];
296 mark_buffer_dirty(bh, 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);
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 mark_buffer_dirty(bh, 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);
356 if (!inode) {
357 iput(dir);
358 return -ENOSPC;
359 }
360 inode->i_uid = current->fsuid;
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 if (dir->i_mode & S_ISGID)
368 inode->i_mode |= S_ISGID;
369 }
370 else if (S_ISLNK(inode->i_mode))
371 inode->i_op = &ext_symlink_inode_operations;
372 else if (S_ISCHR(inode->i_mode))
373 inode->i_op = &chrdev_inode_operations;
374 else if (S_ISBLK(inode->i_mode))
375 inode->i_op = &blkdev_inode_operations;
376 else if (S_ISFIFO(inode->i_mode))
377 init_fifo(inode);
378 if (S_ISBLK(mode) || S_ISCHR(mode))
379 inode->i_rdev = to_kdev_t(rdev);
380 #if 0
381 inode->i_mtime = inode->i_atime = CURRENT_TIME;
382 #endif
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 mark_buffer_dirty(bh, 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);
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 #if 0
424 inode->i_mtime = inode->i_atime = CURRENT_TIME;
425 #endif
426 dir_block = ext_bread(inode,0,1);
427 if (!dir_block) {
428 iput(dir);
429 inode->i_nlink--;
430 inode->i_dirt = 1;
431 iput(inode);
432 return -ENOSPC;
433 }
434 de = (struct ext_dir_entry *) dir_block->b_data;
435 de->inode=inode->i_ino;
436 de->rec_len=16;
437 de->name_len=1;
438 strcpy(de->name,".");
439 de = (struct ext_dir_entry *) ((char *) de + de->rec_len);
440 de->inode = dir->i_ino;
441 de->rec_len=16;
442 de->name_len=2;
443 strcpy(de->name,"..");
444 inode->i_nlink = 2;
445 mark_buffer_dirty(dir_block, 1);
446 brelse(dir_block);
447 inode->i_mode = S_IFDIR | (mode & 0777 & ~current->fs->umask);
448 if (dir->i_mode & S_ISGID)
449 inode->i_mode |= S_ISGID;
450 inode->i_dirt = 1;
451 bh = ext_add_entry(dir,name,len,&de);
452 if (!bh) {
453 iput(dir);
454 inode->i_nlink=0;
455 iput(inode);
456 return -ENOSPC;
457 }
458 de->inode = inode->i_ino;
459 mark_buffer_dirty(bh, 1);
460 dir->i_nlink++;
461 dir->i_dirt = 1;
462 iput(dir);
463 iput(inode);
464 brelse(bh);
465 return 0;
466 }
467
468
469
470
471 static int empty_dir(struct inode * inode)
472 {
473 unsigned long offset;
474 struct buffer_head * bh;
475 struct ext_dir_entry * de, * de1;
476
477 if (inode->i_size < 2 * 12 || !(bh = ext_bread(inode,0,0))) {
478 printk("warning - bad directory on dev %s\n",
479 kdevname(inode->i_dev));
480 return 1;
481 }
482 de = (struct ext_dir_entry *) bh->b_data;
483 de1 = (struct ext_dir_entry *) ((char *) de + de->rec_len);
484 if (de->inode != inode->i_ino || !de1->inode ||
485 strcmp(".",de->name) || strcmp("..",de1->name)) {
486 printk("warning - bad directory on dev %s\n",
487 kdevname(inode->i_dev));
488 return 1;
489 }
490 offset = de->rec_len + de1->rec_len;
491 de = (struct ext_dir_entry *) ((char *) de1 + de1->rec_len);
492 while (offset < inode->i_size ) {
493 if ((void *) de >= (void *) (bh->b_data+BLOCK_SIZE)) {
494 brelse(bh);
495 bh = ext_bread(inode, offset >> BLOCK_SIZE_BITS,1);
496 if (!bh) {
497 offset += BLOCK_SIZE;
498 continue;
499 }
500 de = (struct ext_dir_entry *) bh->b_data;
501 }
502 if (de->rec_len < 8 || de->rec_len %4 != 0 ||
503 de->rec_len < de->name_len + 8) {
504 printk ("empty_dir: bad dir entry\n");
505 printk ("dev=%s, dir=%ld, offset=%ld, "
506 "rec_len=%d, name_len=%d\n",
507 kdevname(inode->i_dev), inode->i_ino,
508 offset, de->rec_len, de->name_len);
509 brelse (bh);
510 return 1;
511 }
512 if (de->inode) {
513 brelse(bh);
514 return 0;
515 }
516 offset += de->rec_len;
517 de = (struct ext_dir_entry *) ((char *) de + de->rec_len);
518 }
519 brelse(bh);
520 return 1;
521 }
522
523 static inline void ext_merge_entries (struct ext_dir_entry * de,
524 struct ext_dir_entry * pde, struct ext_dir_entry * nde)
525 {
526 if (nde && !nde->inode)
527 de->rec_len += nde->rec_len;
528 if (pde && !pde->inode)
529 pde->rec_len += de->rec_len;
530 }
531
532 int ext_rmdir(struct inode * dir, const char * name, int len)
533 {
534 int retval;
535 struct inode * inode;
536 struct buffer_head * bh;
537 struct ext_dir_entry * de, * pde, * nde;
538
539 inode = NULL;
540 bh = ext_find_entry(dir,name,len,&de,&pde,&nde);
541 retval = -ENOENT;
542 if (!bh)
543 goto end_rmdir;
544 retval = -EPERM;
545 if (!(inode = iget(dir->i_sb, de->inode)))
546 goto end_rmdir;
547 if ((dir->i_mode & S_ISVTX) && !fsuser() &&
548 current->fsuid != inode->i_uid &&
549 current->fsuid != dir->i_uid)
550 goto end_rmdir;
551 if (inode->i_dev != dir->i_dev)
552 goto end_rmdir;
553 if (inode == dir)
554 goto end_rmdir;
555 if (!S_ISDIR(inode->i_mode)) {
556 retval = -ENOTDIR;
557 goto end_rmdir;
558 }
559 if (!empty_dir(inode)) {
560 retval = -ENOTEMPTY;
561 goto end_rmdir;
562 }
563 if (inode->i_count > 1) {
564 retval = -EBUSY;
565 goto end_rmdir;
566 }
567 if (inode->i_nlink != 2)
568 printk("empty directory has nlink!=2 (%d)\n",inode->i_nlink);
569 de->inode = 0;
570 de->name_len = 0;
571 ext_merge_entries (de, pde, nde);
572 mark_buffer_dirty(bh, 1);
573 inode->i_nlink=0;
574 inode->i_dirt=1;
575 dir->i_nlink--;
576 inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
577 dir->i_dirt=1;
578 retval = 0;
579 end_rmdir:
580 iput(dir);
581 iput(inode);
582 brelse(bh);
583 return retval;
584 }
585
586 int ext_unlink(struct inode * dir, const char * name, int len)
587 {
588 int retval;
589 struct inode * inode;
590 struct buffer_head * bh;
591 struct ext_dir_entry * de, * pde, * nde;
592
593 retval = -ENOENT;
594 inode = NULL;
595 bh = ext_find_entry(dir,name,len,&de,&pde,&nde);
596 if (!bh)
597 goto end_unlink;
598 if (!(inode = iget(dir->i_sb, de->inode)))
599 goto end_unlink;
600 retval = -EPERM;
601 if ((dir->i_mode & S_ISVTX) && !fsuser() &&
602 current->fsuid != inode->i_uid &&
603 current->fsuid != dir->i_uid)
604 goto end_unlink;
605 if (S_ISDIR(inode->i_mode))
606 goto end_unlink;
607 if (!inode->i_nlink) {
608 printk("Deleting nonexistent file (%s:%ld), %d\n",
609 kdevname(inode->i_dev), inode->i_ino,
610 inode->i_nlink);
611 inode->i_nlink=1;
612 }
613 de->inode = 0;
614 de->name_len = 0;
615 ext_merge_entries (de, pde, nde);
616 mark_buffer_dirty(bh, 1);
617 inode->i_nlink--;
618 inode->i_dirt = 1;
619 inode->i_ctime = CURRENT_TIME;
620 dir->i_ctime = dir->i_mtime = inode->i_ctime;
621 dir->i_dirt = 1;
622 retval = 0;
623 end_unlink:
624 brelse(bh);
625 iput(inode);
626 iput(dir);
627 return retval;
628 }
629
630 int ext_symlink(struct inode * dir, const char * name, int len, const char * symname)
631 {
632 struct ext_dir_entry * de;
633 struct inode * inode = NULL;
634 struct buffer_head * bh = NULL, * name_block = NULL;
635 int i;
636 char c;
637
638 if (!(inode = ext_new_inode(dir))) {
639 iput(dir);
640 return -ENOSPC;
641 }
642 inode->i_mode = S_IFLNK | 0777;
643 inode->i_op = &ext_symlink_inode_operations;
644 name_block = ext_bread(inode,0,1);
645 if (!name_block) {
646 iput(dir);
647 inode->i_nlink--;
648 inode->i_dirt = 1;
649 iput(inode);
650 return -ENOSPC;
651 }
652 i = 0;
653 while (i < 1023 && (c = *(symname++)))
654 name_block->b_data[i++] = c;
655 name_block->b_data[i] = 0;
656 mark_buffer_dirty(name_block, 1);
657 brelse(name_block);
658 inode->i_size = i;
659 inode->i_dirt = 1;
660 bh = ext_find_entry(dir,name,len,&de,NULL,NULL);
661 if (bh) {
662 inode->i_nlink--;
663 inode->i_dirt = 1;
664 iput(inode);
665 brelse(bh);
666 iput(dir);
667 return -EEXIST;
668 }
669 bh = ext_add_entry(dir,name,len,&de);
670 if (!bh) {
671 inode->i_nlink--;
672 inode->i_dirt = 1;
673 iput(inode);
674 iput(dir);
675 return -ENOSPC;
676 }
677 de->inode = inode->i_ino;
678 mark_buffer_dirty(bh, 1);
679 brelse(bh);
680 iput(dir);
681 iput(inode);
682 return 0;
683 }
684
685 int ext_link(struct inode * oldinode, struct inode * dir, const char * name, int len)
686 {
687 struct ext_dir_entry * de;
688 struct buffer_head * bh;
689
690 if (S_ISDIR(oldinode->i_mode)) {
691 iput(oldinode);
692 iput(dir);
693 return -EPERM;
694 }
695 if (oldinode->i_nlink > 32000) {
696 iput(oldinode);
697 iput(dir);
698 return -EMLINK;
699 }
700 bh = ext_find_entry(dir,name,len,&de,NULL,NULL);
701 if (bh) {
702 brelse(bh);
703 iput(dir);
704 iput(oldinode);
705 return -EEXIST;
706 }
707 bh = ext_add_entry(dir,name,len,&de);
708 if (!bh) {
709 iput(dir);
710 iput(oldinode);
711 return -ENOSPC;
712 }
713 de->inode = oldinode->i_ino;
714 mark_buffer_dirty(bh, 1);
715 brelse(bh);
716 iput(dir);
717 oldinode->i_nlink++;
718 oldinode->i_ctime = CURRENT_TIME;
719 oldinode->i_dirt = 1;
720 iput(oldinode);
721 return 0;
722 }
723
724 static int subdir(struct inode * new_inode, struct inode * old_inode)
725 {
726 int ino;
727 int result;
728
729 new_inode->i_count++;
730 result = 0;
731 for (;;) {
732 if (new_inode == old_inode) {
733 result = 1;
734 break;
735 }
736 if (new_inode->i_dev != old_inode->i_dev)
737 break;
738 ino = new_inode->i_ino;
739 if (ext_lookup(new_inode,"..",2,&new_inode))
740 break;
741 if (new_inode->i_ino == ino)
742 break;
743 }
744 iput(new_inode);
745 return result;
746 }
747
748 #define PARENT_INO(buffer) \
749 ((struct ext_dir_entry *) ((char *) buffer + \
750 ((struct ext_dir_entry *) buffer)->rec_len))->inode
751
752 #define PARENT_NAME(buffer) \
753 ((struct ext_dir_entry *) ((char *) buffer + \
754 ((struct ext_dir_entry *) buffer)->rec_len))->name
755
756
757
758
759
760
761
762
763
764
765
766 static int do_ext_rename(struct inode * old_dir, const char * old_name, int old_len,
767 struct inode * new_dir, const char * new_name, int new_len)
768 {
769 struct inode * old_inode, * new_inode;
770 struct buffer_head * old_bh, * new_bh, * dir_bh;
771 struct ext_dir_entry * old_de, * new_de, * pde, * nde;
772 int retval;
773
774 goto start_up;
775 try_again:
776 brelse(old_bh);
777 brelse(new_bh);
778 brelse(dir_bh);
779 iput(old_inode);
780 iput(new_inode);
781 current->counter = 0;
782 schedule();
783 start_up:
784 old_inode = new_inode = NULL;
785 old_bh = new_bh = dir_bh = NULL;
786 old_bh = ext_find_entry(old_dir,old_name,old_len,&old_de,&pde,&nde);
787 retval = -ENOENT;
788 if (!old_bh)
789 goto end_rename;
790 old_inode = __iget(old_dir->i_sb, old_de->inode,0);
791 if (!old_inode)
792 goto end_rename;
793 retval = -EPERM;
794 if ((old_dir->i_mode & S_ISVTX) &&
795 current->fsuid != old_inode->i_uid &&
796 current->fsuid != old_dir->i_uid && !fsuser())
797 goto end_rename;
798 new_bh = ext_find_entry(new_dir,new_name,new_len,&new_de,NULL,NULL);
799 if (new_bh) {
800 new_inode = __iget(new_dir->i_sb, new_de->inode,0);
801 if (!new_inode) {
802 brelse(new_bh);
803 new_bh = NULL;
804 }
805 }
806 if (new_inode == old_inode) {
807 retval = 0;
808 goto end_rename;
809 }
810 if (new_inode && S_ISDIR(new_inode->i_mode)) {
811 retval = -EEXIST;
812 goto end_rename;
813 }
814 retval = -EPERM;
815 if (new_inode && (new_dir->i_mode & S_ISVTX) &&
816 current->fsuid != new_inode->i_uid &&
817 current->fsuid != new_dir->i_uid && !fsuser())
818 goto end_rename;
819 if (S_ISDIR(old_inode->i_mode)) {
820 retval = -EEXIST;
821 if (new_bh)
822 goto end_rename;
823 if ((retval = permission(old_inode, MAY_WRITE)) != 0)
824 goto end_rename;
825 retval = -EINVAL;
826 if (subdir(new_dir, old_inode))
827 goto end_rename;
828 retval = -EIO;
829 dir_bh = ext_bread(old_inode,0,0);
830 if (!dir_bh)
831 goto end_rename;
832 if (PARENT_INO(dir_bh->b_data) != old_dir->i_ino)
833 goto end_rename;
834 }
835 if (!new_bh)
836 new_bh = ext_add_entry(new_dir,new_name,new_len,&new_de);
837 retval = -ENOSPC;
838 if (!new_bh)
839 goto end_rename;
840
841 if (new_inode && (new_de->inode != new_inode->i_ino))
842 goto try_again;
843 if (new_de->inode && !new_inode)
844 goto try_again;
845 if (old_de->inode != old_inode->i_ino)
846 goto try_again;
847
848 old_de->inode = 0;
849 old_de->name_len = 0;
850 new_de->inode = old_inode->i_ino;
851 ext_merge_entries (old_de, pde, nde);
852 if (new_inode) {
853 new_inode->i_nlink--;
854 new_inode->i_dirt = 1;
855 }
856 mark_buffer_dirty(old_bh, 1);
857 mark_buffer_dirty(new_bh, 1);
858 if (dir_bh) {
859 PARENT_INO(dir_bh->b_data) = new_dir->i_ino;
860 mark_buffer_dirty(dir_bh, 1);
861 old_dir->i_nlink--;
862 new_dir->i_nlink++;
863 old_dir->i_dirt = 1;
864 new_dir->i_dirt = 1;
865 }
866 retval = 0;
867 end_rename:
868 brelse(dir_bh);
869 brelse(old_bh);
870 brelse(new_bh);
871 iput(old_inode);
872 iput(new_inode);
873 iput(old_dir);
874 iput(new_dir);
875 return retval;
876 }
877
878
879
880
881
882
883
884
885
886
887 int ext_rename(struct inode * old_dir, const char * old_name, int old_len,
888 struct inode * new_dir, const char * new_name, int new_len)
889 {
890 static struct wait_queue * wait = NULL;
891 static int lock = 0;
892 int result;
893
894 while (lock)
895 sleep_on(&wait);
896 lock = 1;
897 result = do_ext_rename(old_dir, old_name, old_len,
898 new_dir, new_name, new_len);
899 lock = 0;
900 wake_up(&wait);
901 return result;
902 }