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