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 register int same;
59
60 if (!de || !de->inode || len > EXT_NAME_LEN)
61 return 0;
62
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__ __volatile__(
68 "cld\n\t"
69 "repe ; cmpsb\n\t"
70 "setz %%al"
71 :"=a" (same)
72 :"0" (0),"S" ((long) name),"D" ((long) de->name),"c" (len)
73 :"cx","di","si");
74 return same;
75 }
76
77
78
79
80
81
82
83
84
85
86
87
88 static struct buffer_head * ext_find_entry(struct inode * dir,
89 const char * name, int namelen, struct ext_dir_entry ** res_dir,
90 struct ext_dir_entry ** prev_dir, struct ext_dir_entry ** next_dir)
91 {
92 long offset;
93 struct buffer_head * bh;
94 struct ext_dir_entry * de;
95
96 *res_dir = NULL;
97 if (!dir)
98 return NULL;
99 #ifdef NO_TRUNCATE
100 if (namelen > EXT_NAME_LEN)
101 return NULL;
102 #else
103 if (namelen > EXT_NAME_LEN)
104 namelen = EXT_NAME_LEN;
105 #endif
106 bh = ext_bread(dir,0,0);
107 if (!bh)
108 return NULL;
109 if (prev_dir)
110 *prev_dir = NULL;
111 if (next_dir)
112 *next_dir = NULL;
113 offset = 0;
114 de = (struct ext_dir_entry *) bh->b_data;
115 while (offset < dir->i_size) {
116 if ((char *)de >= BLOCK_SIZE+bh->b_data) {
117 brelse(bh);
118 bh = NULL;
119 bh = ext_bread(dir,offset>>BLOCK_SIZE_BITS,0);
120 if (!bh)
121 continue;
122 de = (struct ext_dir_entry *) bh->b_data;
123 if (prev_dir)
124 *prev_dir = NULL;
125 }
126 if (de->rec_len < 8 || de->rec_len % 8 != 0 ||
127 de->rec_len < de->name_len + 8 ||
128 (((char *) de) + de->rec_len-1 >= BLOCK_SIZE+bh->b_data)) {
129 printk ("ext_find_entry: bad dir entry\n");
130 printk ("dev=%d, dir=%ld, offset=%ld, rec_len=%d, name_len=%d\n",
131 dir->i_dev, dir->i_ino, offset, de->rec_len, de->name_len);
132 de = (struct ext_dir_entry *) (bh->b_data+BLOCK_SIZE);
133 offset = ((offset / BLOCK_SIZE) + 1) * BLOCK_SIZE;
134 continue;
135
136
137 }
138 if (ext_match(namelen,name,de)) {
139 *res_dir = de;
140 if (next_dir)
141 if (offset + de->rec_len < dir->i_size &&
142 ((char *)de) + de->rec_len < BLOCK_SIZE+bh->b_data)
143 *next_dir = (struct ext_dir_entry *)
144 ((char *) de + de->rec_len);
145 else
146 *next_dir = NULL;
147 return bh;
148 }
149 offset += de->rec_len;
150 if (prev_dir)
151 *prev_dir = de;
152 de = (struct ext_dir_entry *) ((char *) de + de->rec_len);
153 }
154 brelse(bh);
155 return NULL;
156 }
157
158 int ext_lookup(struct inode * dir,const char * name, int len,
159 struct inode ** result)
160 {
161 int ino;
162 struct ext_dir_entry * de;
163 struct buffer_head * bh;
164
165 *result = NULL;
166 if (!dir)
167 return -ENOENT;
168 if (!S_ISDIR(dir->i_mode)) {
169 iput(dir);
170 return -ENOENT;
171 }
172 if (!(bh = ext_find_entry(dir,name,len,&de,NULL,NULL))) {
173 iput(dir);
174 return -ENOENT;
175 }
176 ino = de->inode;
177 brelse(bh);
178 if (!(*result = iget(dir->i_sb,ino))) {
179 iput(dir);
180 return -EACCES;
181 }
182 iput(dir);
183 return 0;
184 }
185
186
187
188
189
190
191
192
193
194
195
196 static struct buffer_head * ext_add_entry(struct inode * dir,
197 const char * name, int namelen, struct ext_dir_entry ** res_dir)
198 {
199 int i;
200 long offset;
201 unsigned short rec_len;
202 struct buffer_head * bh;
203 struct ext_dir_entry * de, * de1;
204
205 *res_dir = NULL;
206 if (!dir)
207 return NULL;
208 #ifdef NO_TRUNCATE
209 if (namelen > EXT_NAME_LEN)
210 return NULL;
211 #else
212 if (namelen > EXT_NAME_LEN)
213 namelen = EXT_NAME_LEN;
214 #endif
215 if (!namelen)
216 return NULL;
217 bh = ext_bread(dir,0,0);
218 if (!bh)
219 return NULL;
220 rec_len = ((8 + namelen + EXT_DIR_PAD - 1) / EXT_DIR_PAD) * EXT_DIR_PAD;
221 offset = 0;
222 de = (struct ext_dir_entry *) bh->b_data;
223 while (1) {
224 if ((char *)de >= BLOCK_SIZE+bh->b_data && offset < dir->i_size) {
225 #ifdef EXTFS_DEBUG
226 printk ("ext_add_entry: skipping to next block\n");
227 #endif
228 brelse(bh);
229 bh = NULL;
230 bh = ext_bread(dir,offset>>BLOCK_SIZE_BITS,0);
231 if (!bh)
232 return NULL;
233 de = (struct ext_dir_entry *) bh->b_data;
234 }
235 if (offset >= dir->i_size) {
236
237 if (offset % BLOCK_SIZE == 0 ||
238 (BLOCK_SIZE - (offset % BLOCK_SIZE)) < rec_len) {
239 if ((offset % BLOCK_SIZE) != 0) {
240
241
242
243 de->inode = 0;
244 de->rec_len = BLOCK_SIZE
245 - (offset & (BLOCK_SIZE - 1));
246 de->name_len = 0;
247 offset += de->rec_len;
248 dir->i_size += de->rec_len;
249 dir->i_dirt = 1;
250 #if 0
251 dir->i_ctime = CURRENT_TIME;
252 #endif
253 mark_buffer_dirty(bh, 1);
254 }
255 brelse (bh);
256 bh = NULL;
257 #ifdef EXTFS_DEBUG
258 printk ("ext_add_entry : creating next block\n");
259 #endif
260 bh = ext_bread(dir,offset>>BLOCK_SIZE_BITS,1);
261 if (!bh)
262 return NULL;
263 de = (struct ext_dir_entry *) bh->b_data;
264 }
265
266 de->inode=0;
267 de->rec_len = rec_len;
268 dir->i_size += de->rec_len;
269 dir->i_dirt = 1;
270 #if 0
271 dir->i_ctime = CURRENT_TIME;
272 #endif
273 }
274 if (de->rec_len < 8 || de->rec_len % 4 != 0 ||
275 de->rec_len < de->name_len + 8 ||
276 (((char *) de) + de->rec_len-1 >= BLOCK_SIZE+bh->b_data)) {
277 printk ("ext_addr_entry: bad dir entry\n");
278 printk ("dev=%d, dir=%ld, offset=%ld, rec_len=%d, name_len=%d\n",
279 dir->i_dev, dir->i_ino, offset, de->rec_len, de->name_len);
280 brelse (bh);
281 return NULL;
282 }
283 if (!de->inode && de->rec_len >= rec_len) {
284 if (de->rec_len > rec_len
285 && de->rec_len - rec_len >= EXT_DIR_MIN_SIZE) {
286
287
288
289
290 de1 = (struct ext_dir_entry *) ((char *) de + rec_len);
291 de1->inode = 0;
292 de1->rec_len = de->rec_len - rec_len;
293 de1->name_len = 0;
294 de->rec_len = rec_len;
295 }
296 dir->i_mtime = dir->i_ctime = CURRENT_TIME;
297 de->name_len = namelen;
298 for (i=0; i < namelen ; i++)
299 de->name[i] = name[i];
300 mark_buffer_dirty(bh, 1);
301 *res_dir = de;
302 return bh;
303 }
304 offset += de->rec_len;
305 de = (struct ext_dir_entry *) ((char *) de + de->rec_len);
306 }
307 brelse(bh);
308 return NULL;
309 }
310
311 int ext_create(struct inode * dir,const char * name, int len, int mode,
312 struct inode ** result)
313 {
314 struct inode * inode;
315 struct buffer_head * bh;
316 struct ext_dir_entry * de;
317
318 *result = NULL;
319 if (!dir)
320 return -ENOENT;
321 inode = ext_new_inode(dir);
322 if (!inode) {
323 iput(dir);
324 return -ENOSPC;
325 }
326 inode->i_op = &ext_file_inode_operations;
327 inode->i_mode = mode;
328 inode->i_dirt = 1;
329 bh = ext_add_entry(dir,name,len,&de);
330 if (!bh) {
331 inode->i_nlink--;
332 inode->i_dirt = 1;
333 iput(inode);
334 iput(dir);
335 return -ENOSPC;
336 }
337 de->inode = inode->i_ino;
338 mark_buffer_dirty(bh, 1);
339 brelse(bh);
340 iput(dir);
341 *result = inode;
342 return 0;
343 }
344
345 int ext_mknod(struct inode * dir, const char * name, int len, int mode, int rdev)
346 {
347 struct inode * inode;
348 struct buffer_head * bh;
349 struct ext_dir_entry * de;
350
351 if (!dir)
352 return -ENOENT;
353 bh = ext_find_entry(dir,name,len,&de,NULL,NULL);
354 if (bh) {
355 brelse(bh);
356 iput(dir);
357 return -EEXIST;
358 }
359 inode = ext_new_inode(dir);
360 if (!inode) {
361 iput(dir);
362 return -ENOSPC;
363 }
364 inode->i_uid = current->fsuid;
365 inode->i_mode = mode;
366 inode->i_op = NULL;
367 if (S_ISREG(inode->i_mode))
368 inode->i_op = &ext_file_inode_operations;
369 else if (S_ISDIR(inode->i_mode)) {
370 inode->i_op = &ext_dir_inode_operations;
371 if (dir->i_mode & S_ISGID)
372 inode->i_mode |= S_ISGID;
373 }
374 else if (S_ISLNK(inode->i_mode))
375 inode->i_op = &ext_symlink_inode_operations;
376 else if (S_ISCHR(inode->i_mode))
377 inode->i_op = &chrdev_inode_operations;
378 else if (S_ISBLK(inode->i_mode))
379 inode->i_op = &blkdev_inode_operations;
380 else if (S_ISFIFO(inode->i_mode))
381 init_fifo(inode);
382 if (S_ISBLK(mode) || S_ISCHR(mode))
383 inode->i_rdev = rdev;
384 #if 0
385 inode->i_mtime = inode->i_atime = CURRENT_TIME;
386 #endif
387 inode->i_dirt = 1;
388 bh = ext_add_entry(dir,name,len,&de);
389 if (!bh) {
390 inode->i_nlink--;
391 inode->i_dirt = 1;
392 iput(inode);
393 iput(dir);
394 return -ENOSPC;
395 }
396 de->inode = inode->i_ino;
397 mark_buffer_dirty(bh, 1);
398 brelse(bh);
399 iput(dir);
400 iput(inode);
401 return 0;
402 }
403
404 int ext_mkdir(struct inode * dir, const char * name, int len, int mode)
405 {
406 struct inode * inode;
407 struct buffer_head * bh, *dir_block;
408 struct ext_dir_entry * de;
409
410 bh = ext_find_entry(dir,name,len,&de,NULL,NULL);
411 if (bh) {
412 brelse(bh);
413 iput(dir);
414 return -EEXIST;
415 }
416 inode = ext_new_inode(dir);
417 if (!inode) {
418 iput(dir);
419 return -ENOSPC;
420 }
421 inode->i_op = &ext_dir_inode_operations;
422 inode->i_size = 2 * 16;
423
424
425
426
427 #if 0
428 inode->i_mtime = inode->i_atime = CURRENT_TIME;
429 #endif
430 dir_block = ext_bread(inode,0,1);
431 if (!dir_block) {
432 iput(dir);
433 inode->i_nlink--;
434 inode->i_dirt = 1;
435 iput(inode);
436 return -ENOSPC;
437 }
438 de = (struct ext_dir_entry *) dir_block->b_data;
439 de->inode=inode->i_ino;
440 de->rec_len=16;
441 de->name_len=1;
442 strcpy(de->name,".");
443 de = (struct ext_dir_entry *) ((char *) de + de->rec_len);
444 de->inode = dir->i_ino;
445 de->rec_len=16;
446 de->name_len=2;
447 strcpy(de->name,"..");
448 inode->i_nlink = 2;
449 mark_buffer_dirty(dir_block, 1);
450 brelse(dir_block);
451 inode->i_mode = S_IFDIR | (mode & 0777 & ~current->fs->umask);
452 if (dir->i_mode & S_ISGID)
453 inode->i_mode |= S_ISGID;
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 mark_buffer_dirty(bh, 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 unsigned long offset;
478 struct buffer_head * bh;
479 struct ext_dir_entry * de, * de1;
480
481 if (inode->i_size < 2 * 12 || !(bh = ext_bread(inode,0,0))) {
482 printk("warning - bad directory on dev %04x\n",inode->i_dev);
483 return 1;
484 }
485 de = (struct ext_dir_entry *) bh->b_data;
486 de1 = (struct ext_dir_entry *) ((char *) de + de->rec_len);
487 if (de->inode != inode->i_ino || !de1->inode ||
488 strcmp(".",de->name) || strcmp("..",de1->name)) {
489 printk("warning - bad directory on dev %04x\n",inode->i_dev);
490 return 1;
491 }
492 offset = de->rec_len + de1->rec_len;
493 de = (struct ext_dir_entry *) ((char *) de1 + de1->rec_len);
494 while (offset < inode->i_size ) {
495 if ((void *) de >= (void *) (bh->b_data+BLOCK_SIZE)) {
496 brelse(bh);
497 bh = ext_bread(inode, offset >> BLOCK_SIZE_BITS,1);
498 if (!bh) {
499 offset += BLOCK_SIZE;
500 continue;
501 }
502 de = (struct ext_dir_entry *) bh->b_data;
503 }
504 if (de->rec_len < 8 || de->rec_len %4 != 0 ||
505 de->rec_len < de->name_len + 8) {
506 printk ("empty_dir: bad dir entry\n");
507 printk ("dev=%d, dir=%ld, offset=%ld, rec_len=%d, name_len=%d\n",
508 inode->i_dev, inode->i_ino, 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 (%04x:%ld), %d\n",
609 inode->i_dev,inode->i_ino,inode->i_nlink);
610 inode->i_nlink=1;
611 }
612 de->inode = 0;
613 de->name_len = 0;
614 ext_merge_entries (de, pde, nde);
615 mark_buffer_dirty(bh, 1);
616 inode->i_nlink--;
617 inode->i_dirt = 1;
618 inode->i_ctime = CURRENT_TIME;
619 dir->i_ctime = dir->i_mtime = inode->i_ctime;
620 dir->i_dirt = 1;
621 retval = 0;
622 end_unlink:
623 brelse(bh);
624 iput(inode);
625 iput(dir);
626 return retval;
627 }
628
629 int ext_symlink(struct inode * dir, const char * name, int len, const char * symname)
630 {
631 struct ext_dir_entry * de;
632 struct inode * inode = NULL;
633 struct buffer_head * bh = NULL, * name_block = NULL;
634 int i;
635 char c;
636
637 if (!(inode = ext_new_inode(dir))) {
638 iput(dir);
639 return -ENOSPC;
640 }
641 inode->i_mode = S_IFLNK | 0777;
642 inode->i_op = &ext_symlink_inode_operations;
643 name_block = ext_bread(inode,0,1);
644 if (!name_block) {
645 iput(dir);
646 inode->i_nlink--;
647 inode->i_dirt = 1;
648 iput(inode);
649 return -ENOSPC;
650 }
651 i = 0;
652 while (i < 1023 && (c = *(symname++)))
653 name_block->b_data[i++] = c;
654 name_block->b_data[i] = 0;
655 mark_buffer_dirty(name_block, 1);
656 brelse(name_block);
657 inode->i_size = i;
658 inode->i_dirt = 1;
659 bh = ext_find_entry(dir,name,len,&de,NULL,NULL);
660 if (bh) {
661 inode->i_nlink--;
662 inode->i_dirt = 1;
663 iput(inode);
664 brelse(bh);
665 iput(dir);
666 return -EEXIST;
667 }
668 bh = ext_add_entry(dir,name,len,&de);
669 if (!bh) {
670 inode->i_nlink--;
671 inode->i_dirt = 1;
672 iput(inode);
673 iput(dir);
674 return -ENOSPC;
675 }
676 de->inode = inode->i_ino;
677 mark_buffer_dirty(bh, 1);
678 brelse(bh);
679 iput(dir);
680 iput(inode);
681 return 0;
682 }
683
684 int ext_link(struct inode * oldinode, struct inode * dir, const char * name, int len)
685 {
686 struct ext_dir_entry * de;
687 struct buffer_head * bh;
688
689 if (S_ISDIR(oldinode->i_mode)) {
690 iput(oldinode);
691 iput(dir);
692 return -EPERM;
693 }
694 if (oldinode->i_nlink > 32000) {
695 iput(oldinode);
696 iput(dir);
697 return -EMLINK;
698 }
699 bh = ext_find_entry(dir,name,len,&de,NULL,NULL);
700 if (bh) {
701 brelse(bh);
702 iput(dir);
703 iput(oldinode);
704 return -EEXIST;
705 }
706 bh = ext_add_entry(dir,name,len,&de);
707 if (!bh) {
708 iput(dir);
709 iput(oldinode);
710 return -ENOSPC;
711 }
712 de->inode = oldinode->i_ino;
713 mark_buffer_dirty(bh, 1);
714 brelse(bh);
715 iput(dir);
716 oldinode->i_nlink++;
717 oldinode->i_ctime = CURRENT_TIME;
718 oldinode->i_dirt = 1;
719 iput(oldinode);
720 return 0;
721 }
722
723 static int subdir(struct inode * new_inode, struct inode * old_inode)
724 {
725 int ino;
726 int result;
727
728 new_inode->i_count++;
729 result = 0;
730 for (;;) {
731 if (new_inode == old_inode) {
732 result = 1;
733 break;
734 }
735 if (new_inode->i_dev != old_inode->i_dev)
736 break;
737 ino = new_inode->i_ino;
738 if (ext_lookup(new_inode,"..",2,&new_inode))
739 break;
740 if (new_inode->i_ino == ino)
741 break;
742 }
743 iput(new_inode);
744 return result;
745 }
746
747 #define PARENT_INO(buffer) \
748 ((struct ext_dir_entry *) ((char *) buffer + \
749 ((struct ext_dir_entry *) buffer)->rec_len))->inode
750
751 #define PARENT_NAME(buffer) \
752 ((struct ext_dir_entry *) ((char *) buffer + \
753 ((struct ext_dir_entry *) buffer)->rec_len))->name
754
755
756
757
758
759
760
761
762
763
764
765 static int do_ext_rename(struct inode * old_dir, const char * old_name, int old_len,
766 struct inode * new_dir, const char * new_name, int new_len)
767 {
768 struct inode * old_inode, * new_inode;
769 struct buffer_head * old_bh, * new_bh, * dir_bh;
770 struct ext_dir_entry * old_de, * new_de, * pde, * nde;
771 int retval;
772
773 goto start_up;
774 try_again:
775 brelse(old_bh);
776 brelse(new_bh);
777 brelse(dir_bh);
778 iput(old_inode);
779 iput(new_inode);
780 current->counter = 0;
781 schedule();
782 start_up:
783 old_inode = new_inode = NULL;
784 old_bh = new_bh = dir_bh = NULL;
785 old_bh = ext_find_entry(old_dir,old_name,old_len,&old_de,&pde,&nde);
786 retval = -ENOENT;
787 if (!old_bh)
788 goto end_rename;
789 old_inode = __iget(old_dir->i_sb, old_de->inode,0);
790 if (!old_inode)
791 goto end_rename;
792 retval = -EPERM;
793 if ((old_dir->i_mode & S_ISVTX) &&
794 current->fsuid != old_inode->i_uid &&
795 current->fsuid != old_dir->i_uid && !fsuser())
796 goto end_rename;
797 new_bh = ext_find_entry(new_dir,new_name,new_len,&new_de,NULL,NULL);
798 if (new_bh) {
799 new_inode = __iget(new_dir->i_sb, new_de->inode,0);
800 if (!new_inode) {
801 brelse(new_bh);
802 new_bh = NULL;
803 }
804 }
805 if (new_inode == old_inode) {
806 retval = 0;
807 goto end_rename;
808 }
809 if (new_inode && S_ISDIR(new_inode->i_mode)) {
810 retval = -EEXIST;
811 goto end_rename;
812 }
813 retval = -EPERM;
814 if (new_inode && (new_dir->i_mode & S_ISVTX) &&
815 current->fsuid != new_inode->i_uid &&
816 current->fsuid != new_dir->i_uid && !fsuser())
817 goto end_rename;
818 if (S_ISDIR(old_inode->i_mode)) {
819 retval = -EEXIST;
820 if (new_bh)
821 goto end_rename;
822 retval = -EACCES;
823 if (!permission(old_inode, MAY_WRITE))
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 }