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 de->name_len = namelen;
289 for (i=0; i < namelen ; i++)
290 de->name[i] = name[i];
291 mark_buffer_dirty(bh, 1);
292 *res_dir = de;
293 return bh;
294 }
295 offset += de->rec_len;
296 de = (struct ext_dir_entry *) ((char *) de + de->rec_len);
297 }
298 brelse(bh);
299 return NULL;
300 }
301
302 int ext_create(struct inode * dir,const char * name, int len, int mode,
303 struct inode ** result)
304 {
305 struct inode * inode;
306 struct buffer_head * bh;
307 struct ext_dir_entry * de;
308
309 *result = NULL;
310 if (!dir)
311 return -ENOENT;
312 inode = ext_new_inode(dir);
313 if (!inode) {
314 iput(dir);
315 return -ENOSPC;
316 }
317 inode->i_op = &ext_file_inode_operations;
318 inode->i_mode = mode;
319 inode->i_dirt = 1;
320 bh = ext_add_entry(dir,name,len,&de);
321 if (!bh) {
322 inode->i_nlink--;
323 inode->i_dirt = 1;
324 iput(inode);
325 iput(dir);
326 return -ENOSPC;
327 }
328 de->inode = inode->i_ino;
329 mark_buffer_dirty(bh, 1);
330 brelse(bh);
331 iput(dir);
332 *result = inode;
333 return 0;
334 }
335
336 int ext_mknod(struct inode * dir, const char * name, int len, int mode, int rdev)
337 {
338 struct inode * inode;
339 struct buffer_head * bh;
340 struct ext_dir_entry * de;
341
342 if (!dir)
343 return -ENOENT;
344 bh = ext_find_entry(dir,name,len,&de,NULL,NULL);
345 if (bh) {
346 brelse(bh);
347 iput(dir);
348 return -EEXIST;
349 }
350 inode = ext_new_inode(dir);
351 if (!inode) {
352 iput(dir);
353 return -ENOSPC;
354 }
355 inode->i_uid = current->fsuid;
356 inode->i_mode = mode;
357 inode->i_op = NULL;
358 if (S_ISREG(inode->i_mode))
359 inode->i_op = &ext_file_inode_operations;
360 else if (S_ISDIR(inode->i_mode)) {
361 inode->i_op = &ext_dir_inode_operations;
362 if (dir->i_mode & S_ISGID)
363 inode->i_mode |= S_ISGID;
364 }
365 else if (S_ISLNK(inode->i_mode))
366 inode->i_op = &ext_symlink_inode_operations;
367 else if (S_ISCHR(inode->i_mode))
368 inode->i_op = &chrdev_inode_operations;
369 else if (S_ISBLK(inode->i_mode))
370 inode->i_op = &blkdev_inode_operations;
371 else if (S_ISFIFO(inode->i_mode))
372 init_fifo(inode);
373 if (S_ISBLK(mode) || S_ISCHR(mode))
374 inode->i_rdev = rdev;
375 #if 0
376 inode->i_mtime = inode->i_atime = CURRENT_TIME;
377 #endif
378 inode->i_dirt = 1;
379 bh = ext_add_entry(dir,name,len,&de);
380 if (!bh) {
381 inode->i_nlink--;
382 inode->i_dirt = 1;
383 iput(inode);
384 iput(dir);
385 return -ENOSPC;
386 }
387 de->inode = inode->i_ino;
388 mark_buffer_dirty(bh, 1);
389 brelse(bh);
390 iput(dir);
391 iput(inode);
392 return 0;
393 }
394
395 int ext_mkdir(struct inode * dir, const char * name, int len, int mode)
396 {
397 struct inode * inode;
398 struct buffer_head * bh, *dir_block;
399 struct ext_dir_entry * de;
400
401 bh = ext_find_entry(dir,name,len,&de,NULL,NULL);
402 if (bh) {
403 brelse(bh);
404 iput(dir);
405 return -EEXIST;
406 }
407 inode = ext_new_inode(dir);
408 if (!inode) {
409 iput(dir);
410 return -ENOSPC;
411 }
412 inode->i_op = &ext_dir_inode_operations;
413 inode->i_size = 2 * 16;
414
415
416
417
418 #if 0
419 inode->i_mtime = inode->i_atime = CURRENT_TIME;
420 #endif
421 dir_block = ext_bread(inode,0,1);
422 if (!dir_block) {
423 iput(dir);
424 inode->i_nlink--;
425 inode->i_dirt = 1;
426 iput(inode);
427 return -ENOSPC;
428 }
429 de = (struct ext_dir_entry *) dir_block->b_data;
430 de->inode=inode->i_ino;
431 de->rec_len=16;
432 de->name_len=1;
433 strcpy(de->name,".");
434 de = (struct ext_dir_entry *) ((char *) de + de->rec_len);
435 de->inode = dir->i_ino;
436 de->rec_len=16;
437 de->name_len=2;
438 strcpy(de->name,"..");
439 inode->i_nlink = 2;
440 mark_buffer_dirty(dir_block, 1);
441 brelse(dir_block);
442 inode->i_mode = S_IFDIR | (mode & 0777 & ~current->fs->umask);
443 if (dir->i_mode & S_ISGID)
444 inode->i_mode |= S_ISGID;
445 inode->i_dirt = 1;
446 bh = ext_add_entry(dir,name,len,&de);
447 if (!bh) {
448 iput(dir);
449 inode->i_nlink=0;
450 iput(inode);
451 return -ENOSPC;
452 }
453 de->inode = inode->i_ino;
454 mark_buffer_dirty(bh, 1);
455 dir->i_nlink++;
456 dir->i_dirt = 1;
457 iput(dir);
458 iput(inode);
459 brelse(bh);
460 return 0;
461 }
462
463
464
465
466 static int empty_dir(struct inode * inode)
467 {
468 unsigned long offset;
469 struct buffer_head * bh;
470 struct ext_dir_entry * de, * de1;
471
472 if (inode->i_size < 2 * 12 || !(bh = ext_bread(inode,0,0))) {
473 printk("warning - bad directory on dev %04x\n",inode->i_dev);
474 return 1;
475 }
476 de = (struct ext_dir_entry *) bh->b_data;
477 de1 = (struct ext_dir_entry *) ((char *) de + de->rec_len);
478 if (de->inode != inode->i_ino || !de1->inode ||
479 strcmp(".",de->name) || strcmp("..",de1->name)) {
480 printk("warning - bad directory on dev %04x\n",inode->i_dev);
481 return 1;
482 }
483 offset = de->rec_len + de1->rec_len;
484 de = (struct ext_dir_entry *) ((char *) de1 + de1->rec_len);
485 while (offset < inode->i_size ) {
486 if ((void *) de >= (void *) (bh->b_data+BLOCK_SIZE)) {
487 brelse(bh);
488 bh = ext_bread(inode, offset >> BLOCK_SIZE_BITS,1);
489 if (!bh) {
490 offset += BLOCK_SIZE;
491 continue;
492 }
493 de = (struct ext_dir_entry *) bh->b_data;
494 }
495 if (de->rec_len < 8 || de->rec_len %4 != 0 ||
496 de->rec_len < de->name_len + 8) {
497 printk ("empty_dir: bad dir entry\n");
498 printk ("dev=%d, dir=%ld, offset=%ld, rec_len=%d, name_len=%d\n",
499 inode->i_dev, inode->i_ino, offset, de->rec_len, de->name_len);
500 brelse (bh);
501 return 1;
502 }
503 if (de->inode) {
504 brelse(bh);
505 return 0;
506 }
507 offset += de->rec_len;
508 de = (struct ext_dir_entry *) ((char *) de + de->rec_len);
509 }
510 brelse(bh);
511 return 1;
512 }
513
514 static inline void ext_merge_entries (struct ext_dir_entry * de,
515 struct ext_dir_entry * pde, struct ext_dir_entry * nde)
516 {
517 if (nde && !nde->inode)
518 de->rec_len += nde->rec_len;
519 if (pde && !pde->inode)
520 pde->rec_len += de->rec_len;
521 }
522
523 int ext_rmdir(struct inode * dir, const char * name, int len)
524 {
525 int retval;
526 struct inode * inode;
527 struct buffer_head * bh;
528 struct ext_dir_entry * de, * pde, * nde;
529
530 inode = NULL;
531 bh = ext_find_entry(dir,name,len,&de,&pde,&nde);
532 retval = -ENOENT;
533 if (!bh)
534 goto end_rmdir;
535 retval = -EPERM;
536 if (!(inode = iget(dir->i_sb, de->inode)))
537 goto end_rmdir;
538 if ((dir->i_mode & S_ISVTX) && !fsuser() &&
539 current->fsuid != inode->i_uid &&
540 current->fsuid != dir->i_uid)
541 goto end_rmdir;
542 if (inode->i_dev != dir->i_dev)
543 goto end_rmdir;
544 if (inode == dir)
545 goto end_rmdir;
546 if (!S_ISDIR(inode->i_mode)) {
547 retval = -ENOTDIR;
548 goto end_rmdir;
549 }
550 if (!empty_dir(inode)) {
551 retval = -ENOTEMPTY;
552 goto end_rmdir;
553 }
554 if (inode->i_count > 1) {
555 retval = -EBUSY;
556 goto end_rmdir;
557 }
558 if (inode->i_nlink != 2)
559 printk("empty directory has nlink!=2 (%d)\n",inode->i_nlink);
560 de->inode = 0;
561 de->name_len = 0;
562 ext_merge_entries (de, pde, nde);
563 mark_buffer_dirty(bh, 1);
564 inode->i_nlink=0;
565 inode->i_dirt=1;
566 dir->i_nlink--;
567 inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
568 dir->i_dirt=1;
569 retval = 0;
570 end_rmdir:
571 iput(dir);
572 iput(inode);
573 brelse(bh);
574 return retval;
575 }
576
577 int ext_unlink(struct inode * dir, const char * name, int len)
578 {
579 int retval;
580 struct inode * inode;
581 struct buffer_head * bh;
582 struct ext_dir_entry * de, * pde, * nde;
583
584 retval = -ENOENT;
585 inode = NULL;
586 bh = ext_find_entry(dir,name,len,&de,&pde,&nde);
587 if (!bh)
588 goto end_unlink;
589 if (!(inode = iget(dir->i_sb, de->inode)))
590 goto end_unlink;
591 retval = -EPERM;
592 if ((dir->i_mode & S_ISVTX) && !fsuser() &&
593 current->fsuid != inode->i_uid &&
594 current->fsuid != dir->i_uid)
595 goto end_unlink;
596 if (S_ISDIR(inode->i_mode))
597 goto end_unlink;
598 if (!inode->i_nlink) {
599 printk("Deleting nonexistent file (%04x:%ld), %d\n",
600 inode->i_dev,inode->i_ino,inode->i_nlink);
601 inode->i_nlink=1;
602 }
603 de->inode = 0;
604 de->name_len = 0;
605 ext_merge_entries (de, pde, nde);
606 mark_buffer_dirty(bh, 1);
607 inode->i_nlink--;
608 inode->i_dirt = 1;
609 inode->i_ctime = CURRENT_TIME;
610 dir->i_ctime = dir->i_mtime = inode->i_ctime;
611 dir->i_dirt = 1;
612 retval = 0;
613 end_unlink:
614 brelse(bh);
615 iput(inode);
616 iput(dir);
617 return retval;
618 }
619
620 int ext_symlink(struct inode * dir, const char * name, int len, const char * symname)
621 {
622 struct ext_dir_entry * de;
623 struct inode * inode = NULL;
624 struct buffer_head * bh = NULL, * name_block = NULL;
625 int i;
626 char c;
627
628 if (!(inode = ext_new_inode(dir))) {
629 iput(dir);
630 return -ENOSPC;
631 }
632 inode->i_mode = S_IFLNK | 0777;
633 inode->i_op = &ext_symlink_inode_operations;
634 name_block = ext_bread(inode,0,1);
635 if (!name_block) {
636 iput(dir);
637 inode->i_nlink--;
638 inode->i_dirt = 1;
639 iput(inode);
640 return -ENOSPC;
641 }
642 i = 0;
643 while (i < 1023 && (c = *(symname++)))
644 name_block->b_data[i++] = c;
645 name_block->b_data[i] = 0;
646 mark_buffer_dirty(name_block, 1);
647 brelse(name_block);
648 inode->i_size = i;
649 inode->i_dirt = 1;
650 bh = ext_find_entry(dir,name,len,&de,NULL,NULL);
651 if (bh) {
652 inode->i_nlink--;
653 inode->i_dirt = 1;
654 iput(inode);
655 brelse(bh);
656 iput(dir);
657 return -EEXIST;
658 }
659 bh = ext_add_entry(dir,name,len,&de);
660 if (!bh) {
661 inode->i_nlink--;
662 inode->i_dirt = 1;
663 iput(inode);
664 iput(dir);
665 return -ENOSPC;
666 }
667 de->inode = inode->i_ino;
668 mark_buffer_dirty(bh, 1);
669 brelse(bh);
670 iput(dir);
671 iput(inode);
672 return 0;
673 }
674
675 int ext_link(struct inode * oldinode, struct inode * dir, const char * name, int len)
676 {
677 struct ext_dir_entry * de;
678 struct buffer_head * bh;
679
680 if (S_ISDIR(oldinode->i_mode)) {
681 iput(oldinode);
682 iput(dir);
683 return -EPERM;
684 }
685 if (oldinode->i_nlink > 32000) {
686 iput(oldinode);
687 iput(dir);
688 return -EMLINK;
689 }
690 bh = ext_find_entry(dir,name,len,&de,NULL,NULL);
691 if (bh) {
692 brelse(bh);
693 iput(dir);
694 iput(oldinode);
695 return -EEXIST;
696 }
697 bh = ext_add_entry(dir,name,len,&de);
698 if (!bh) {
699 iput(dir);
700 iput(oldinode);
701 return -ENOSPC;
702 }
703 de->inode = oldinode->i_ino;
704 mark_buffer_dirty(bh, 1);
705 brelse(bh);
706 iput(dir);
707 oldinode->i_nlink++;
708 oldinode->i_ctime = CURRENT_TIME;
709 oldinode->i_dirt = 1;
710 iput(oldinode);
711 return 0;
712 }
713
714 static int subdir(struct inode * new_inode, struct inode * old_inode)
715 {
716 int ino;
717 int result;
718
719 new_inode->i_count++;
720 result = 0;
721 for (;;) {
722 if (new_inode == old_inode) {
723 result = 1;
724 break;
725 }
726 if (new_inode->i_dev != old_inode->i_dev)
727 break;
728 ino = new_inode->i_ino;
729 if (ext_lookup(new_inode,"..",2,&new_inode))
730 break;
731 if (new_inode->i_ino == ino)
732 break;
733 }
734 iput(new_inode);
735 return result;
736 }
737
738 #define PARENT_INO(buffer) \
739 ((struct ext_dir_entry *) ((char *) buffer + \
740 ((struct ext_dir_entry *) buffer)->rec_len))->inode
741
742 #define PARENT_NAME(buffer) \
743 ((struct ext_dir_entry *) ((char *) buffer + \
744 ((struct ext_dir_entry *) buffer)->rec_len))->name
745
746
747
748
749
750
751
752
753
754
755
756 static int do_ext_rename(struct inode * old_dir, const char * old_name, int old_len,
757 struct inode * new_dir, const char * new_name, int new_len)
758 {
759 struct inode * old_inode, * new_inode;
760 struct buffer_head * old_bh, * new_bh, * dir_bh;
761 struct ext_dir_entry * old_de, * new_de, * pde, * nde;
762 int retval;
763
764 goto start_up;
765 try_again:
766 brelse(old_bh);
767 brelse(new_bh);
768 brelse(dir_bh);
769 iput(old_inode);
770 iput(new_inode);
771 current->counter = 0;
772 schedule();
773 start_up:
774 old_inode = new_inode = NULL;
775 old_bh = new_bh = dir_bh = NULL;
776 old_bh = ext_find_entry(old_dir,old_name,old_len,&old_de,&pde,&nde);
777 retval = -ENOENT;
778 if (!old_bh)
779 goto end_rename;
780 old_inode = __iget(old_dir->i_sb, old_de->inode,0);
781 if (!old_inode)
782 goto end_rename;
783 retval = -EPERM;
784 if ((old_dir->i_mode & S_ISVTX) &&
785 current->fsuid != old_inode->i_uid &&
786 current->fsuid != old_dir->i_uid && !fsuser())
787 goto end_rename;
788 new_bh = ext_find_entry(new_dir,new_name,new_len,&new_de,NULL,NULL);
789 if (new_bh) {
790 new_inode = __iget(new_dir->i_sb, new_de->inode,0);
791 if (!new_inode) {
792 brelse(new_bh);
793 new_bh = NULL;
794 }
795 }
796 if (new_inode == old_inode) {
797 retval = 0;
798 goto end_rename;
799 }
800 if (new_inode && S_ISDIR(new_inode->i_mode)) {
801 retval = -EEXIST;
802 goto end_rename;
803 }
804 retval = -EPERM;
805 if (new_inode && (new_dir->i_mode & S_ISVTX) &&
806 current->fsuid != new_inode->i_uid &&
807 current->fsuid != new_dir->i_uid && !fsuser())
808 goto end_rename;
809 if (S_ISDIR(old_inode->i_mode)) {
810 retval = -EEXIST;
811 if (new_bh)
812 goto end_rename;
813 retval = -EACCES;
814 if (!permission(old_inode, MAY_WRITE))
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 }