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=%d, dir=%ld, offset=%ld, rec_len=%d, name_len=%d\n",
122 dir->i_dev, dir->i_ino, offset, de->rec_len, de->name_len);
123 de = (struct ext_dir_entry *) (bh->b_data+BLOCK_SIZE);
124 offset = ((offset / BLOCK_SIZE) + 1) * BLOCK_SIZE;
125 continue;
126
127
128 }
129 if (ext_match(namelen,name,de)) {
130 *res_dir = de;
131 if (next_dir)
132 if (offset + de->rec_len < dir->i_size &&
133 ((char *)de) + de->rec_len < BLOCK_SIZE+bh->b_data)
134 *next_dir = (struct ext_dir_entry *)
135 ((char *) de + de->rec_len);
136 else
137 *next_dir = NULL;
138 return bh;
139 }
140 offset += de->rec_len;
141 if (prev_dir)
142 *prev_dir = de;
143 de = (struct ext_dir_entry *) ((char *) de + de->rec_len);
144 }
145 brelse(bh);
146 return NULL;
147 }
148
149 int ext_lookup(struct inode * dir,const char * name, int len,
150 struct inode ** result)
151 {
152 int ino;
153 struct ext_dir_entry * de;
154 struct buffer_head * bh;
155
156 *result = NULL;
157 if (!dir)
158 return -ENOENT;
159 if (!S_ISDIR(dir->i_mode)) {
160 iput(dir);
161 return -ENOENT;
162 }
163 if (!(bh = ext_find_entry(dir,name,len,&de,NULL,NULL))) {
164 iput(dir);
165 return -ENOENT;
166 }
167 ino = de->inode;
168 brelse(bh);
169 if (!(*result = iget(dir->i_sb,ino))) {
170 iput(dir);
171 return -EACCES;
172 }
173 iput(dir);
174 return 0;
175 }
176
177
178
179
180
181
182
183
184
185
186
187 static struct buffer_head * ext_add_entry(struct inode * dir,
188 const char * name, int namelen, struct ext_dir_entry ** res_dir)
189 {
190 int i;
191 long offset;
192 unsigned short rec_len;
193 struct buffer_head * bh;
194 struct ext_dir_entry * de, * de1;
195
196 *res_dir = NULL;
197 if (!dir)
198 return NULL;
199 #ifdef NO_TRUNCATE
200 if (namelen > EXT_NAME_LEN)
201 return NULL;
202 #else
203 if (namelen > EXT_NAME_LEN)
204 namelen = EXT_NAME_LEN;
205 #endif
206 if (!namelen)
207 return NULL;
208 bh = ext_bread(dir,0,0);
209 if (!bh)
210 return NULL;
211 rec_len = ((8 + namelen + EXT_DIR_PAD - 1) / EXT_DIR_PAD) * EXT_DIR_PAD;
212 offset = 0;
213 de = (struct ext_dir_entry *) bh->b_data;
214 while (1) {
215 if ((char *)de >= BLOCK_SIZE+bh->b_data && offset < dir->i_size) {
216 #ifdef EXTFS_DEBUG
217 printk ("ext_add_entry: skipping to next block\n");
218 #endif
219 brelse(bh);
220 bh = NULL;
221 bh = ext_bread(dir,offset>>BLOCK_SIZE_BITS,0);
222 if (!bh)
223 return NULL;
224 de = (struct ext_dir_entry *) bh->b_data;
225 }
226 if (offset >= dir->i_size) {
227
228 if (offset % BLOCK_SIZE == 0 ||
229 (BLOCK_SIZE - (offset % BLOCK_SIZE)) < rec_len) {
230 if ((offset % BLOCK_SIZE) != 0) {
231
232
233
234 de->inode = 0;
235 de->rec_len = BLOCK_SIZE
236 - (offset & (BLOCK_SIZE - 1));
237 de->name_len = 0;
238 offset += de->rec_len;
239 dir->i_size += de->rec_len;
240 dir->i_dirt = 1;
241 #if 0
242 dir->i_ctime = CURRENT_TIME;
243 #endif
244 mark_buffer_dirty(bh, 1);
245 }
246 brelse (bh);
247 bh = NULL;
248 #ifdef EXTFS_DEBUG
249 printk ("ext_add_entry : creating next block\n");
250 #endif
251 bh = ext_bread(dir,offset>>BLOCK_SIZE_BITS,1);
252 if (!bh)
253 return NULL;
254 de = (struct ext_dir_entry *) bh->b_data;
255 }
256
257 de->inode=0;
258 de->rec_len = rec_len;
259 dir->i_size += de->rec_len;
260 dir->i_dirt = 1;
261 #if 0
262 dir->i_ctime = CURRENT_TIME;
263 #endif
264 }
265 if (de->rec_len < 8 || de->rec_len % 4 != 0 ||
266 de->rec_len < de->name_len + 8 ||
267 (((char *) de) + de->rec_len-1 >= BLOCK_SIZE+bh->b_data)) {
268 printk ("ext_addr_entry: bad dir entry\n");
269 printk ("dev=%d, dir=%ld, offset=%ld, rec_len=%d, name_len=%d\n",
270 dir->i_dev, dir->i_ino, offset, de->rec_len, de->name_len);
271 brelse (bh);
272 return NULL;
273 }
274 if (!de->inode && de->rec_len >= rec_len) {
275 if (de->rec_len > rec_len
276 && de->rec_len - rec_len >= EXT_DIR_MIN_SIZE) {
277
278
279
280
281 de1 = (struct ext_dir_entry *) ((char *) de + rec_len);
282 de1->inode = 0;
283 de1->rec_len = de->rec_len - rec_len;
284 de1->name_len = 0;
285 de->rec_len = rec_len;
286 }
287 dir->i_mtime = dir->i_ctime = CURRENT_TIME;
288 dir->i_dirt = 1;
289 de->name_len = namelen;
290 for (i=0; i < namelen ; i++)
291 de->name[i] = name[i];
292 mark_buffer_dirty(bh, 1);
293 *res_dir = de;
294 return bh;
295 }
296 offset += de->rec_len;
297 de = (struct ext_dir_entry *) ((char *) de + de->rec_len);
298 }
299 brelse(bh);
300 return NULL;
301 }
302
303 int ext_create(struct inode * dir,const char * name, int len, int mode,
304 struct inode ** result)
305 {
306 struct inode * inode;
307 struct buffer_head * bh;
308 struct ext_dir_entry * de;
309
310 *result = NULL;
311 if (!dir)
312 return -ENOENT;
313 inode = ext_new_inode(dir);
314 if (!inode) {
315 iput(dir);
316 return -ENOSPC;
317 }
318 inode->i_op = &ext_file_inode_operations;
319 inode->i_mode = mode;
320 inode->i_dirt = 1;
321 bh = ext_add_entry(dir,name,len,&de);
322 if (!bh) {
323 inode->i_nlink--;
324 inode->i_dirt = 1;
325 iput(inode);
326 iput(dir);
327 return -ENOSPC;
328 }
329 de->inode = inode->i_ino;
330 mark_buffer_dirty(bh, 1);
331 brelse(bh);
332 iput(dir);
333 *result = inode;
334 return 0;
335 }
336
337 int ext_mknod(struct inode * dir, const char * name, int len, int mode, int rdev)
338 {
339 struct inode * inode;
340 struct buffer_head * bh;
341 struct ext_dir_entry * de;
342
343 if (!dir)
344 return -ENOENT;
345 bh = ext_find_entry(dir,name,len,&de,NULL,NULL);
346 if (bh) {
347 brelse(bh);
348 iput(dir);
349 return -EEXIST;
350 }
351 inode = ext_new_inode(dir);
352 if (!inode) {
353 iput(dir);
354 return -ENOSPC;
355 }
356 inode->i_uid = current->fsuid;
357 inode->i_mode = mode;
358 inode->i_op = NULL;
359 if (S_ISREG(inode->i_mode))
360 inode->i_op = &ext_file_inode_operations;
361 else if (S_ISDIR(inode->i_mode)) {
362 inode->i_op = &ext_dir_inode_operations;
363 if (dir->i_mode & S_ISGID)
364 inode->i_mode |= S_ISGID;
365 }
366 else if (S_ISLNK(inode->i_mode))
367 inode->i_op = &ext_symlink_inode_operations;
368 else if (S_ISCHR(inode->i_mode))
369 inode->i_op = &chrdev_inode_operations;
370 else if (S_ISBLK(inode->i_mode))
371 inode->i_op = &blkdev_inode_operations;
372 else if (S_ISFIFO(inode->i_mode))
373 init_fifo(inode);
374 if (S_ISBLK(mode) || S_ISCHR(mode))
375 inode->i_rdev = rdev;
376 #if 0
377 inode->i_mtime = inode->i_atime = CURRENT_TIME;
378 #endif
379 inode->i_dirt = 1;
380 bh = ext_add_entry(dir,name,len,&de);
381 if (!bh) {
382 inode->i_nlink--;
383 inode->i_dirt = 1;
384 iput(inode);
385 iput(dir);
386 return -ENOSPC;
387 }
388 de->inode = inode->i_ino;
389 mark_buffer_dirty(bh, 1);
390 brelse(bh);
391 iput(dir);
392 iput(inode);
393 return 0;
394 }
395
396 int ext_mkdir(struct inode * dir, const char * name, int len, int mode)
397 {
398 struct inode * inode;
399 struct buffer_head * bh, *dir_block;
400 struct ext_dir_entry * de;
401
402 bh = ext_find_entry(dir,name,len,&de,NULL,NULL);
403 if (bh) {
404 brelse(bh);
405 iput(dir);
406 return -EEXIST;
407 }
408 inode = ext_new_inode(dir);
409 if (!inode) {
410 iput(dir);
411 return -ENOSPC;
412 }
413 inode->i_op = &ext_dir_inode_operations;
414 inode->i_size = 2 * 16;
415
416
417
418
419 #if 0
420 inode->i_mtime = inode->i_atime = CURRENT_TIME;
421 #endif
422 dir_block = ext_bread(inode,0,1);
423 if (!dir_block) {
424 iput(dir);
425 inode->i_nlink--;
426 inode->i_dirt = 1;
427 iput(inode);
428 return -ENOSPC;
429 }
430 de = (struct ext_dir_entry *) dir_block->b_data;
431 de->inode=inode->i_ino;
432 de->rec_len=16;
433 de->name_len=1;
434 strcpy(de->name,".");
435 de = (struct ext_dir_entry *) ((char *) de + de->rec_len);
436 de->inode = dir->i_ino;
437 de->rec_len=16;
438 de->name_len=2;
439 strcpy(de->name,"..");
440 inode->i_nlink = 2;
441 mark_buffer_dirty(dir_block, 1);
442 brelse(dir_block);
443 inode->i_mode = S_IFDIR | (mode & 0777 & ~current->fs->umask);
444 if (dir->i_mode & S_ISGID)
445 inode->i_mode |= S_ISGID;
446 inode->i_dirt = 1;
447 bh = ext_add_entry(dir,name,len,&de);
448 if (!bh) {
449 iput(dir);
450 inode->i_nlink=0;
451 iput(inode);
452 return -ENOSPC;
453 }
454 de->inode = inode->i_ino;
455 mark_buffer_dirty(bh, 1);
456 dir->i_nlink++;
457 dir->i_dirt = 1;
458 iput(dir);
459 iput(inode);
460 brelse(bh);
461 return 0;
462 }
463
464
465
466
467 static int empty_dir(struct inode * inode)
468 {
469 unsigned long offset;
470 struct buffer_head * bh;
471 struct ext_dir_entry * de, * de1;
472
473 if (inode->i_size < 2 * 12 || !(bh = ext_bread(inode,0,0))) {
474 printk("warning - bad directory on dev %04x\n",inode->i_dev);
475 return 1;
476 }
477 de = (struct ext_dir_entry *) bh->b_data;
478 de1 = (struct ext_dir_entry *) ((char *) de + de->rec_len);
479 if (de->inode != inode->i_ino || !de1->inode ||
480 strcmp(".",de->name) || strcmp("..",de1->name)) {
481 printk("warning - bad directory on dev %04x\n",inode->i_dev);
482 return 1;
483 }
484 offset = de->rec_len + de1->rec_len;
485 de = (struct ext_dir_entry *) ((char *) de1 + de1->rec_len);
486 while (offset < inode->i_size ) {
487 if ((void *) de >= (void *) (bh->b_data+BLOCK_SIZE)) {
488 brelse(bh);
489 bh = ext_bread(inode, offset >> BLOCK_SIZE_BITS,1);
490 if (!bh) {
491 offset += BLOCK_SIZE;
492 continue;
493 }
494 de = (struct ext_dir_entry *) bh->b_data;
495 }
496 if (de->rec_len < 8 || de->rec_len %4 != 0 ||
497 de->rec_len < de->name_len + 8) {
498 printk ("empty_dir: bad dir entry\n");
499 printk ("dev=%d, dir=%ld, offset=%ld, rec_len=%d, name_len=%d\n",
500 inode->i_dev, inode->i_ino, offset, de->rec_len, de->name_len);
501 brelse (bh);
502 return 1;
503 }
504 if (de->inode) {
505 brelse(bh);
506 return 0;
507 }
508 offset += de->rec_len;
509 de = (struct ext_dir_entry *) ((char *) de + de->rec_len);
510 }
511 brelse(bh);
512 return 1;
513 }
514
515 static inline void ext_merge_entries (struct ext_dir_entry * de,
516 struct ext_dir_entry * pde, struct ext_dir_entry * nde)
517 {
518 if (nde && !nde->inode)
519 de->rec_len += nde->rec_len;
520 if (pde && !pde->inode)
521 pde->rec_len += de->rec_len;
522 }
523
524 int ext_rmdir(struct inode * dir, const char * name, int len)
525 {
526 int retval;
527 struct inode * inode;
528 struct buffer_head * bh;
529 struct ext_dir_entry * de, * pde, * nde;
530
531 inode = NULL;
532 bh = ext_find_entry(dir,name,len,&de,&pde,&nde);
533 retval = -ENOENT;
534 if (!bh)
535 goto end_rmdir;
536 retval = -EPERM;
537 if (!(inode = iget(dir->i_sb, de->inode)))
538 goto end_rmdir;
539 if ((dir->i_mode & S_ISVTX) && !fsuser() &&
540 current->fsuid != inode->i_uid &&
541 current->fsuid != dir->i_uid)
542 goto end_rmdir;
543 if (inode->i_dev != dir->i_dev)
544 goto end_rmdir;
545 if (inode == dir)
546 goto end_rmdir;
547 if (!S_ISDIR(inode->i_mode)) {
548 retval = -ENOTDIR;
549 goto end_rmdir;
550 }
551 if (!empty_dir(inode)) {
552 retval = -ENOTEMPTY;
553 goto end_rmdir;
554 }
555 if (inode->i_count > 1) {
556 retval = -EBUSY;
557 goto end_rmdir;
558 }
559 if (inode->i_nlink != 2)
560 printk("empty directory has nlink!=2 (%d)\n",inode->i_nlink);
561 de->inode = 0;
562 de->name_len = 0;
563 ext_merge_entries (de, pde, nde);
564 mark_buffer_dirty(bh, 1);
565 inode->i_nlink=0;
566 inode->i_dirt=1;
567 dir->i_nlink--;
568 inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
569 dir->i_dirt=1;
570 retval = 0;
571 end_rmdir:
572 iput(dir);
573 iput(inode);
574 brelse(bh);
575 return retval;
576 }
577
578 int ext_unlink(struct inode * dir, const char * name, int len)
579 {
580 int retval;
581 struct inode * inode;
582 struct buffer_head * bh;
583 struct ext_dir_entry * de, * pde, * nde;
584
585 retval = -ENOENT;
586 inode = NULL;
587 bh = ext_find_entry(dir,name,len,&de,&pde,&nde);
588 if (!bh)
589 goto end_unlink;
590 if (!(inode = iget(dir->i_sb, de->inode)))
591 goto end_unlink;
592 retval = -EPERM;
593 if ((dir->i_mode & S_ISVTX) && !fsuser() &&
594 current->fsuid != inode->i_uid &&
595 current->fsuid != dir->i_uid)
596 goto end_unlink;
597 if (S_ISDIR(inode->i_mode))
598 goto end_unlink;
599 if (!inode->i_nlink) {
600 printk("Deleting nonexistent file (%04x:%ld), %d\n",
601 inode->i_dev,inode->i_ino,inode->i_nlink);
602 inode->i_nlink=1;
603 }
604 de->inode = 0;
605 de->name_len = 0;
606 ext_merge_entries (de, pde, nde);
607 mark_buffer_dirty(bh, 1);
608 inode->i_nlink--;
609 inode->i_dirt = 1;
610 inode->i_ctime = CURRENT_TIME;
611 dir->i_ctime = dir->i_mtime = inode->i_ctime;
612 dir->i_dirt = 1;
613 retval = 0;
614 end_unlink:
615 brelse(bh);
616 iput(inode);
617 iput(dir);
618 return retval;
619 }
620
621 int ext_symlink(struct inode * dir, const char * name, int len, const char * symname)
622 {
623 struct ext_dir_entry * de;
624 struct inode * inode = NULL;
625 struct buffer_head * bh = NULL, * name_block = NULL;
626 int i;
627 char c;
628
629 if (!(inode = ext_new_inode(dir))) {
630 iput(dir);
631 return -ENOSPC;
632 }
633 inode->i_mode = S_IFLNK | 0777;
634 inode->i_op = &ext_symlink_inode_operations;
635 name_block = ext_bread(inode,0,1);
636 if (!name_block) {
637 iput(dir);
638 inode->i_nlink--;
639 inode->i_dirt = 1;
640 iput(inode);
641 return -ENOSPC;
642 }
643 i = 0;
644 while (i < 1023 && (c = *(symname++)))
645 name_block->b_data[i++] = c;
646 name_block->b_data[i] = 0;
647 mark_buffer_dirty(name_block, 1);
648 brelse(name_block);
649 inode->i_size = i;
650 inode->i_dirt = 1;
651 bh = ext_find_entry(dir,name,len,&de,NULL,NULL);
652 if (bh) {
653 inode->i_nlink--;
654 inode->i_dirt = 1;
655 iput(inode);
656 brelse(bh);
657 iput(dir);
658 return -EEXIST;
659 }
660 bh = ext_add_entry(dir,name,len,&de);
661 if (!bh) {
662 inode->i_nlink--;
663 inode->i_dirt = 1;
664 iput(inode);
665 iput(dir);
666 return -ENOSPC;
667 }
668 de->inode = inode->i_ino;
669 mark_buffer_dirty(bh, 1);
670 brelse(bh);
671 iput(dir);
672 iput(inode);
673 return 0;
674 }
675
676 int ext_link(struct inode * oldinode, struct inode * dir, const char * name, int len)
677 {
678 struct ext_dir_entry * de;
679 struct buffer_head * bh;
680
681 if (S_ISDIR(oldinode->i_mode)) {
682 iput(oldinode);
683 iput(dir);
684 return -EPERM;
685 }
686 if (oldinode->i_nlink > 32000) {
687 iput(oldinode);
688 iput(dir);
689 return -EMLINK;
690 }
691 bh = ext_find_entry(dir,name,len,&de,NULL,NULL);
692 if (bh) {
693 brelse(bh);
694 iput(dir);
695 iput(oldinode);
696 return -EEXIST;
697 }
698 bh = ext_add_entry(dir,name,len,&de);
699 if (!bh) {
700 iput(dir);
701 iput(oldinode);
702 return -ENOSPC;
703 }
704 de->inode = oldinode->i_ino;
705 mark_buffer_dirty(bh, 1);
706 brelse(bh);
707 iput(dir);
708 oldinode->i_nlink++;
709 oldinode->i_ctime = CURRENT_TIME;
710 oldinode->i_dirt = 1;
711 iput(oldinode);
712 return 0;
713 }
714
715 static int subdir(struct inode * new_inode, struct inode * old_inode)
716 {
717 int ino;
718 int result;
719
720 new_inode->i_count++;
721 result = 0;
722 for (;;) {
723 if (new_inode == old_inode) {
724 result = 1;
725 break;
726 }
727 if (new_inode->i_dev != old_inode->i_dev)
728 break;
729 ino = new_inode->i_ino;
730 if (ext_lookup(new_inode,"..",2,&new_inode))
731 break;
732 if (new_inode->i_ino == ino)
733 break;
734 }
735 iput(new_inode);
736 return result;
737 }
738
739 #define PARENT_INO(buffer) \
740 ((struct ext_dir_entry *) ((char *) buffer + \
741 ((struct ext_dir_entry *) buffer)->rec_len))->inode
742
743 #define PARENT_NAME(buffer) \
744 ((struct ext_dir_entry *) ((char *) buffer + \
745 ((struct ext_dir_entry *) buffer)->rec_len))->name
746
747
748
749
750
751
752
753
754
755
756
757 static int do_ext_rename(struct inode * old_dir, const char * old_name, int old_len,
758 struct inode * new_dir, const char * new_name, int new_len)
759 {
760 struct inode * old_inode, * new_inode;
761 struct buffer_head * old_bh, * new_bh, * dir_bh;
762 struct ext_dir_entry * old_de, * new_de, * pde, * nde;
763 int retval;
764
765 goto start_up;
766 try_again:
767 brelse(old_bh);
768 brelse(new_bh);
769 brelse(dir_bh);
770 iput(old_inode);
771 iput(new_inode);
772 current->counter = 0;
773 schedule();
774 start_up:
775 old_inode = new_inode = NULL;
776 old_bh = new_bh = dir_bh = NULL;
777 old_bh = ext_find_entry(old_dir,old_name,old_len,&old_de,&pde,&nde);
778 retval = -ENOENT;
779 if (!old_bh)
780 goto end_rename;
781 old_inode = __iget(old_dir->i_sb, old_de->inode,0);
782 if (!old_inode)
783 goto end_rename;
784 retval = -EPERM;
785 if ((old_dir->i_mode & S_ISVTX) &&
786 current->fsuid != old_inode->i_uid &&
787 current->fsuid != old_dir->i_uid && !fsuser())
788 goto end_rename;
789 new_bh = ext_find_entry(new_dir,new_name,new_len,&new_de,NULL,NULL);
790 if (new_bh) {
791 new_inode = __iget(new_dir->i_sb, new_de->inode,0);
792 if (!new_inode) {
793 brelse(new_bh);
794 new_bh = NULL;
795 }
796 }
797 if (new_inode == old_inode) {
798 retval = 0;
799 goto end_rename;
800 }
801 if (new_inode && S_ISDIR(new_inode->i_mode)) {
802 retval = -EEXIST;
803 goto end_rename;
804 }
805 retval = -EPERM;
806 if (new_inode && (new_dir->i_mode & S_ISVTX) &&
807 current->fsuid != new_inode->i_uid &&
808 current->fsuid != new_dir->i_uid && !fsuser())
809 goto end_rename;
810 if (S_ISDIR(old_inode->i_mode)) {
811 retval = -EEXIST;
812 if (new_bh)
813 goto end_rename;
814 if ((retval = permission(old_inode, MAY_WRITE)) != 0)
815 goto end_rename;
816 retval = -EINVAL;
817 if (subdir(new_dir, old_inode))
818 goto end_rename;
819 retval = -EIO;
820 dir_bh = ext_bread(old_inode,0,0);
821 if (!dir_bh)
822 goto end_rename;
823 if (PARENT_INO(dir_bh->b_data) != old_dir->i_ino)
824 goto end_rename;
825 }
826 if (!new_bh)
827 new_bh = ext_add_entry(new_dir,new_name,new_len,&new_de);
828 retval = -ENOSPC;
829 if (!new_bh)
830 goto end_rename;
831
832 if (new_inode && (new_de->inode != new_inode->i_ino))
833 goto try_again;
834 if (new_de->inode && !new_inode)
835 goto try_again;
836 if (old_de->inode != old_inode->i_ino)
837 goto try_again;
838
839 old_de->inode = 0;
840 old_de->name_len = 0;
841 new_de->inode = old_inode->i_ino;
842 ext_merge_entries (old_de, pde, nde);
843 if (new_inode) {
844 new_inode->i_nlink--;
845 new_inode->i_dirt = 1;
846 }
847 mark_buffer_dirty(old_bh, 1);
848 mark_buffer_dirty(new_bh, 1);
849 if (dir_bh) {
850 PARENT_INO(dir_bh->b_data) = new_dir->i_ino;
851 mark_buffer_dirty(dir_bh, 1);
852 old_dir->i_nlink--;
853 new_dir->i_nlink++;
854 old_dir->i_dirt = 1;
855 new_dir->i_dirt = 1;
856 }
857 retval = 0;
858 end_rename:
859 brelse(dir_bh);
860 brelse(old_bh);
861 brelse(new_bh);
862 iput(old_inode);
863 iput(new_inode);
864 iput(old_dir);
865 iput(new_dir);
866 return retval;
867 }
868
869
870
871
872
873
874
875
876
877
878 int ext_rename(struct inode * old_dir, const char * old_name, int old_len,
879 struct inode * new_dir, const char * new_name, int new_len)
880 {
881 static struct wait_queue * wait = NULL;
882 static int lock = 0;
883 int result;
884
885 while (lock)
886 sleep_on(&wait);
887 lock = 1;
888 result = do_ext_rename(old_dir, old_name, old_len,
889 new_dir, new_name, new_len);
890 lock = 0;
891 wake_up(&wait);
892 return result;
893 }