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