This source file includes following definitions.
- ext2fs_dirconv2ffs
- ext2fs_readdir
- ext2fs_lookup
- ext2fs_dirbadentry
- ext2fs_direnter
- ext2fs_dirremove
- ext2fs_dirrewrite
- ext2fs_dirempty
- ext2fs_checkpath
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51 #include <sys/param.h>
52 #include <sys/systm.h>
53 #include <sys/namei.h>
54 #include <sys/buf.h>
55 #include <sys/file.h>
56 #include <sys/mount.h>
57 #include <sys/vnode.h>
58 #include <sys/malloc.h>
59 #include <sys/dirent.h>
60
61 #include <ufs/ufs/quota.h>
62 #include <ufs/ufs/inode.h>
63 #include <ufs/ufs/ufsmount.h>
64 #include <ufs/ufs/ufs_extern.h>
65
66 #include <ufs/ext2fs/ext2fs_extern.h>
67 #include <ufs/ext2fs/ext2fs_dir.h>
68 #include <ufs/ext2fs/ext2fs.h>
69
70 extern int dirchk;
71
72 static void ext2fs_dirconv2ffs(struct ext2fs_direct *e2dir,
73 struct dirent *ffsdir);
74 static int ext2fs_dirbadentry(struct vnode *dp,
75 struct ext2fs_direct *de,
76 int entryoffsetinblock);
77
78
79
80
81
82
83
84
85
86
87
88 static void
89 ext2fs_dirconv2ffs(struct ext2fs_direct *e2dir, struct dirent *ffsdir)
90 {
91 memset(ffsdir, 0, sizeof(struct dirent));
92 ffsdir->d_fileno = fs2h32(e2dir->e2d_ino);
93 ffsdir->d_namlen = e2dir->e2d_namlen;
94
95 ffsdir->d_type = DT_UNKNOWN;
96 #ifdef DIAGNOSTIC
97
98
99
100
101
102
103
104
105 #endif
106 strncpy(ffsdir->d_name, e2dir->e2d_name, ffsdir->d_namlen);
107
108
109
110
111
112 ffsdir->d_reclen = DIRENT_SIZE(ffsdir);
113 }
114
115
116
117
118
119
120
121
122
123
124
125
126 int
127 ext2fs_readdir(void *v)
128 {
129 struct vop_readdir_args *ap = v;
130 struct uio *uio = ap->a_uio;
131 int error;
132 size_t e2fs_count, readcnt, entries;
133 struct vnode *vp = ap->a_vp;
134 struct m_ext2fs *fs = VTOI(vp)->i_e2fs;
135
136 struct ext2fs_direct *dp;
137 struct dirent dstd;
138 struct uio auio;
139 struct iovec aiov;
140 caddr_t dirbuf;
141 off_t off = uio->uio_offset;
142 u_long *cookies = NULL;
143 int nc = 0, ncookies = 0;
144 int e2d_reclen;
145
146 if (vp->v_type != VDIR)
147 return (ENOTDIR);
148
149 e2fs_count = uio->uio_resid;
150 entries = (uio->uio_offset + e2fs_count) & (fs->e2fs_bsize - 1);
151
152
153 if (e2fs_count <= entries)
154 return (EINVAL);
155
156 e2fs_count -= entries;
157 auio = *uio;
158 auio.uio_iov = &aiov;
159 auio.uio_iovcnt = 1;
160 auio.uio_segflg = UIO_SYSSPACE;
161 aiov.iov_len = e2fs_count;
162 auio.uio_resid = e2fs_count;
163 MALLOC(dirbuf, caddr_t, e2fs_count, M_TEMP, M_WAITOK);
164 if (ap->a_ncookies) {
165 nc = ncookies = e2fs_count / 16;
166 cookies = malloc(sizeof (off_t) * ncookies, M_TEMP, M_WAITOK);
167 *ap->a_cookies = cookies;
168 }
169 memset(dirbuf, 0, e2fs_count);
170 aiov.iov_base = dirbuf;
171
172 error = VOP_READ(ap->a_vp, &auio, 0, ap->a_cred);
173 if (error == 0) {
174 readcnt = e2fs_count - auio.uio_resid;
175 for (dp = (struct ext2fs_direct *)dirbuf;
176 (char *)dp < (char *)dirbuf + readcnt; ) {
177 e2d_reclen = fs2h16(dp->e2d_reclen);
178 if (e2d_reclen == 0) {
179 error = EIO;
180 break;
181 }
182 ext2fs_dirconv2ffs(dp, &dstd);
183 if(dstd.d_reclen > uio->uio_resid) {
184 break;
185 }
186 if ((error = uiomove((caddr_t)&dstd, dstd.d_reclen, uio)) != 0) {
187 break;
188 }
189 off = off + e2d_reclen;
190 if (cookies != NULL) {
191 *cookies++ = off;
192 if (--ncookies <= 0){
193 break;
194 }
195 }
196
197 dp = (struct ext2fs_direct *) ((char *)dp + e2d_reclen);
198 }
199
200 uio->uio_offset = off;
201 }
202 FREE(dirbuf, M_TEMP);
203 *ap->a_eofflag = ext2fs_size(VTOI(ap->a_vp)) <= uio->uio_offset;
204 if (ap->a_ncookies) {
205 if (error) {
206 free(*ap->a_cookies, M_TEMP);
207 *ap->a_ncookies = 0;
208 *ap->a_cookies = NULL;
209 } else
210 *ap->a_ncookies = nc - ncookies;
211 }
212 return (error);
213 }
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248 int
249 ext2fs_lookup(void *v)
250 {
251 struct vop_lookup_args *ap = v;
252 struct vnode *vdp;
253 struct inode *dp;
254 struct buf *bp;
255 struct ext2fs_direct *ep;
256 int entryoffsetinblock;
257 enum {NONE, COMPACT, FOUND} slotstatus;
258 doff_t slotoffset;
259 int slotsize;
260 int slotfreespace;
261 int slotneeded;
262 int numdirpasses;
263 doff_t endsearch;
264 doff_t prevoff;
265 struct vnode *pdp;
266 struct vnode *tdp;
267 doff_t enduseful;
268 u_long bmask;
269 int lockparent;
270 int wantparent;
271 int namlen, error;
272 struct vnode **vpp = ap->a_vpp;
273 struct componentname *cnp = ap->a_cnp;
274 struct ucred *cred = cnp->cn_cred;
275 int flags = cnp->cn_flags;
276 int nameiop = cnp->cn_nameiop;
277 struct proc *p = cnp->cn_proc;
278 int dirblksize = VTOI(ap->a_dvp)->i_e2fs->e2fs_bsize;
279
280 bp = NULL;
281 slotoffset = -1;
282 *vpp = NULL;
283 vdp = ap->a_dvp;
284 dp = VTOI(vdp);
285 lockparent = flags & LOCKPARENT;
286 wantparent = flags & (LOCKPARENT|WANTPARENT);
287
288
289
290 if ((error = VOP_ACCESS(vdp, VEXEC, cred, cnp->cn_proc)) != 0)
291 return (error);
292
293 if ((flags & ISLASTCN) && (vdp->v_mount->mnt_flag & MNT_RDONLY) &&
294 (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME))
295 return (EROFS);
296
297
298
299
300
301
302
303
304 if ((error = cache_lookup(vdp, vpp, cnp)) >= 0)
305 return (error);
306
307
308
309
310
311
312
313 slotstatus = FOUND;
314 slotfreespace = slotsize = slotneeded = 0;
315 if ((nameiop == CREATE || nameiop == RENAME) &&
316 (flags & ISLASTCN)) {
317 slotstatus = NONE;
318 slotneeded = EXT2FS_DIRSIZ(cnp->cn_namelen);
319 }
320
321
322
323
324
325
326
327
328
329
330
331
332 bmask = VFSTOUFS(vdp->v_mount)->um_mountp->mnt_stat.f_iosize - 1;
333 if (nameiop != LOOKUP || dp->i_diroff == 0 ||
334 dp->i_diroff >ext2fs_size(dp)) {
335 entryoffsetinblock = 0;
336 dp->i_offset = 0;
337 numdirpasses = 1;
338 } else {
339 dp->i_offset = dp->i_diroff;
340 if ((entryoffsetinblock = dp->i_offset & bmask) &&
341 (error = ext2fs_bufatoff(dp, (off_t)dp->i_offset,
342 NULL, &bp)))
343 return (error);
344 numdirpasses = 2;
345 }
346 prevoff = dp->i_offset;
347 endsearch = roundup(ext2fs_size(dp), dirblksize);
348 enduseful = 0;
349
350 searchloop:
351 while (dp->i_offset < endsearch) {
352
353
354
355 if ((dp->i_offset & bmask) == 0) {
356 if (bp != NULL)
357 brelse(bp);
358 error = ext2fs_bufatoff(dp, (off_t)dp->i_offset,
359 NULL, &bp);
360 if (error != 0)
361 return (error);
362 entryoffsetinblock = 0;
363 }
364
365
366
367
368 if (slotstatus == NONE &&
369 (entryoffsetinblock & (dirblksize - 1)) == 0) {
370 slotoffset = -1;
371 slotfreespace = 0;
372 }
373
374
375
376
377
378
379
380 ep = (struct ext2fs_direct *)
381 ((char *)bp->b_data + entryoffsetinblock);
382 if (ep->e2d_reclen == 0 ||
383 (dirchk &&
384 ext2fs_dirbadentry(vdp, ep, entryoffsetinblock))) {
385 int i;
386 ufs_dirbad(dp, dp->i_offset, "mangled entry");
387 i = dirblksize -
388 (entryoffsetinblock & (dirblksize - 1));
389 dp->i_offset += i;
390 entryoffsetinblock += i;
391 continue;
392 }
393
394
395
396
397
398
399
400 if (slotstatus != FOUND) {
401 int size = fs2h16(ep->e2d_reclen);
402
403 if (ep->e2d_ino != 0)
404 size -= EXT2FS_DIRSIZ(ep->e2d_namlen);
405 if (size > 0) {
406 if (size >= slotneeded) {
407 slotstatus = FOUND;
408 slotoffset = dp->i_offset;
409 slotsize = fs2h16(ep->e2d_reclen);
410 } else if (slotstatus == NONE) {
411 slotfreespace += size;
412 if (slotoffset == -1)
413 slotoffset = dp->i_offset;
414 if (slotfreespace >= slotneeded) {
415 slotstatus = COMPACT;
416 slotsize = dp->i_offset +
417 fs2h16(ep->e2d_reclen) - slotoffset;
418 }
419 }
420 }
421 }
422
423
424
425
426 if (ep->e2d_ino) {
427 namlen = ep->e2d_namlen;
428 if (namlen == cnp->cn_namelen &&
429 !memcmp(cnp->cn_nameptr, ep->e2d_name,
430 (unsigned)namlen)) {
431
432
433
434
435
436 dp->i_ino = fs2h32(ep->e2d_ino);
437 dp->i_reclen = fs2h16(ep->e2d_reclen);
438 brelse(bp);
439 goto found;
440 }
441 }
442 prevoff = dp->i_offset;
443 dp->i_offset += fs2h16(ep->e2d_reclen);
444 entryoffsetinblock += fs2h16(ep->e2d_reclen);
445 if (ep->e2d_ino)
446 enduseful = dp->i_offset;
447 }
448
449
450
451
452
453 if (numdirpasses == 2) {
454 numdirpasses--;
455 dp->i_offset = 0;
456 endsearch = dp->i_diroff;
457 goto searchloop;
458 }
459 if (bp != NULL)
460 brelse(bp);
461
462
463
464
465
466 if ((nameiop == CREATE || nameiop == RENAME) &&
467 (flags & ISLASTCN) && dp->i_e2fs_nlink != 0) {
468
469
470
471
472 if (vdp->v_mount->mnt_flag & MNT_RDONLY)
473 return (EROFS);
474
475
476
477
478 if ((error = VOP_ACCESS(vdp, VWRITE, cred, cnp->cn_proc)) != 0)
479 return (error);
480
481
482
483
484
485
486
487
488
489 if (slotstatus == NONE) {
490 dp->i_offset = roundup(ext2fs_size(dp), dirblksize);
491 dp->i_count = 0;
492 enduseful = dp->i_offset;
493 } else {
494 dp->i_offset = slotoffset;
495 dp->i_count = slotsize;
496 if (enduseful < slotoffset + slotsize)
497 enduseful = slotoffset + slotsize;
498 }
499 dp->i_endoff = roundup(enduseful, dirblksize);
500 dp->i_flag |= IN_CHANGE | IN_UPDATE;
501
502
503
504
505
506
507
508
509
510
511
512
513
514 cnp->cn_flags |= SAVENAME;
515 if (!lockparent) {
516 VOP_UNLOCK(vdp, 0, p);
517 cnp->cn_flags |= PDIRUNLOCK;
518 }
519 return (EJUSTRETURN);
520 }
521
522
523
524 if ((cnp->cn_flags & MAKEENTRY) && nameiop != CREATE)
525 cache_enter(vdp, *vpp, cnp);
526 return (ENOENT);
527
528 found:
529
530
531
532
533 if (entryoffsetinblock + EXT2FS_DIRSIZ(ep->e2d_namlen)
534 > ext2fs_size(dp)) {
535 ufs_dirbad(dp, dp->i_offset, "i_size too small");
536 error = ext2fs_setsize(dp,
537 entryoffsetinblock + EXT2FS_DIRSIZ(ep->e2d_namlen));
538 if (error) {
539 brelse(bp);
540 return(error);
541 }
542 dp->i_flag |= IN_CHANGE | IN_UPDATE;
543 }
544
545
546
547
548
549
550 if ((flags & ISLASTCN) && nameiop == LOOKUP)
551 dp->i_diroff = dp->i_offset &~ (dirblksize - 1);
552
553
554
555
556
557
558
559
560 if (nameiop == DELETE && (flags & ISLASTCN)) {
561
562
563
564 if ((error = VOP_ACCESS(vdp, VWRITE, cred, cnp->cn_proc)) != 0)
565 return (error);
566
567
568
569
570
571
572 if ((dp->i_offset & (dirblksize - 1)) == 0)
573 dp->i_count = 0;
574 else
575 dp->i_count = dp->i_offset - prevoff;
576 if (dp->i_number == dp->i_ino) {
577 VREF(vdp);
578 *vpp = vdp;
579 return (0);
580 }
581 if ((error = VFS_VGET(vdp->v_mount, dp->i_ino, &tdp)) != 0)
582 return (error);
583
584
585
586
587
588
589 if ((dp->i_e2fs_mode & ISVTX) &&
590 cred->cr_uid != 0 &&
591 cred->cr_uid != dp->i_e2fs_uid &&
592 VTOI(tdp)->i_e2fs_uid != cred->cr_uid) {
593 vput(tdp);
594 return (EPERM);
595 }
596 *vpp = tdp;
597 if (!lockparent) {
598 VOP_UNLOCK(vdp, 0, p);
599 cnp->cn_flags |= PDIRUNLOCK;
600 }
601 return (0);
602 }
603
604
605
606
607
608
609
610 if (nameiop == RENAME && wantparent &&
611 (flags & ISLASTCN)) {
612 if ((error = VOP_ACCESS(vdp, VWRITE, cred, cnp->cn_proc)) != 0)
613 return (error);
614
615
616
617
618 if (dp->i_number == dp->i_ino)
619 return (EISDIR);
620 if ((error = VFS_VGET(vdp->v_mount, dp->i_ino, &tdp)) != 0)
621 return (error);
622 *vpp = tdp;
623 cnp->cn_flags |= SAVENAME;
624 if (!lockparent) {
625 VOP_UNLOCK(vdp, 0, p);
626 cnp->cn_flags |= PDIRUNLOCK;
627 }
628 return (0);
629 }
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650 pdp = vdp;
651 if (flags & ISDOTDOT) {
652 VOP_UNLOCK(pdp, 0, p);
653 cnp->cn_flags |= PDIRUNLOCK;
654 if ((error = VFS_VGET(vdp->v_mount, dp->i_ino, &tdp)) != 0) {
655 if (vn_lock(pdp, LK_EXCLUSIVE | LK_RETRY, p) == 0)
656 cnp->cn_flags &= ~PDIRUNLOCK;
657 return (error);
658 }
659 if (lockparent && (flags & ISLASTCN)) {
660 if ((error = vn_lock(pdp, LK_EXCLUSIVE, p)) != 0) {
661 vput(tdp);
662 return (error);
663 }
664 cnp->cn_flags &= ~PDIRUNLOCK;
665 }
666 *vpp = tdp;
667 } else if (dp->i_number == dp->i_ino) {
668 VREF(vdp);
669 *vpp = vdp;
670 } else {
671 if ((error = VFS_VGET(vdp->v_mount, dp->i_ino, &tdp)) != 0)
672 return (error);
673 if (!lockparent || !(flags & ISLASTCN)) {
674 VOP_UNLOCK(pdp, 0, p);
675 cnp->cn_flags |= PDIRUNLOCK;
676 }
677 *vpp = tdp;
678 }
679
680
681
682
683 if (cnp->cn_flags & MAKEENTRY)
684 cache_enter(vdp, *vpp, cnp);
685 return (0);
686 }
687
688
689
690
691
692
693
694
695
696
697
698
699 static int
700 ext2fs_dirbadentry(struct vnode *dp, struct ext2fs_direct *de,
701 int entryoffsetinblock)
702 {
703 int dirblksize = VTOI(dp)->i_e2fs->e2fs_bsize;
704
705 char * error_msg = NULL;
706 int reclen = fs2h16(de->e2d_reclen);
707 int namlen = de->e2d_namlen;
708
709 if (reclen < EXT2FS_DIRSIZ(1))
710 error_msg = "rec_len is smaller than minimal";
711 else if (reclen % 4 != 0)
712 error_msg = "rec_len % 4 != 0";
713 else if (reclen < EXT2FS_DIRSIZ(namlen))
714 error_msg = "reclen is too small for name_len";
715 else if (entryoffsetinblock + reclen > dirblksize)
716 error_msg = "directory entry across blocks";
717 else if (fs2h32(de->e2d_ino) >
718 VTOI(dp)->i_e2fs->e2fs.e2fs_icount)
719 error_msg = "inode out of bounds";
720
721 if (error_msg != NULL) {
722 printf( "bad directory entry: %s\n"
723 "offset=%d, inode=%lu, rec_len=%d, name_len=%d \n",
724 error_msg, entryoffsetinblock,
725 (unsigned long) fs2h32(de->e2d_ino),
726 reclen, namlen);
727 panic("ext2fs_dirbadentry");
728 }
729 return error_msg == NULL ? 0 : 1;
730 }
731
732
733
734
735
736
737
738
739
740 int
741 ext2fs_direnter(struct inode *ip, struct vnode *dvp,
742 struct componentname *cnp)
743 {
744 struct ext2fs_direct *ep, *nep;
745 struct inode *dp;
746 struct buf *bp;
747 struct ext2fs_direct newdir;
748 struct iovec aiov;
749 struct uio auio;
750 u_int dsize;
751 int error, loc, newentrysize, spacefree;
752 char *dirbuf;
753 int dirblksize = ip->i_e2fs->e2fs_bsize;
754
755
756 #ifdef DIAGNOSTIC
757 if ((cnp->cn_flags & SAVENAME) == 0)
758 panic("direnter: missing name");
759 #endif
760 dp = VTOI(dvp);
761 newdir.e2d_ino = h2fs32(ip->i_number);
762 newdir.e2d_namlen = cnp->cn_namelen;
763 if (ip->i_e2fs->e2fs.e2fs_rev > E2FS_REV0 &&
764 (ip->i_e2fs->e2fs.e2fs_features_incompat & EXT2F_INCOMPAT_FTYPE)) {
765 newdir.e2d_type = inot2ext2dt(IFTODT(ip->i_e2fs_mode));
766 } else {
767 newdir.e2d_type = 0;
768 };
769 memcpy(newdir.e2d_name, cnp->cn_nameptr, (unsigned)cnp->cn_namelen + 1);
770 newentrysize = EXT2FS_DIRSIZ(cnp->cn_namelen);
771 if (dp->i_count == 0) {
772
773
774
775
776
777
778 if (dp->i_offset & (dirblksize - 1))
779 panic("ext2fs_direnter: newblk");
780 auio.uio_offset = dp->i_offset;
781 newdir.e2d_reclen = h2fs16(dirblksize);
782 auio.uio_resid = newentrysize;
783 aiov.iov_len = newentrysize;
784 aiov.iov_base = (caddr_t)&newdir;
785 auio.uio_iov = &aiov;
786 auio.uio_iovcnt = 1;
787 auio.uio_rw = UIO_WRITE;
788 auio.uio_segflg = UIO_SYSSPACE;
789 auio.uio_procp = (struct proc *)0;
790 error = VOP_WRITE(dvp, &auio, IO_SYNC, cnp->cn_cred);
791 if (dirblksize >
792 VFSTOUFS(dvp->v_mount)->um_mountp->mnt_stat.f_bsize)
793
794 panic("ext2fs_direnter: frag size");
795 else if (!error) {
796 error = ext2fs_setsize(dp,
797 roundup(ext2fs_size(dp), dirblksize));
798 if (error)
799 return (error);
800 dp->i_flag |= IN_CHANGE;
801 }
802 return (error);
803 }
804
805
806
807
808
809
810
811
812
813
814
815
816
817 if ((error = ext2fs_bufatoff(dp, (off_t)dp->i_offset, &dirbuf, &bp))
818 != 0)
819 return (error);
820
821
822
823
824
825
826
827 ep = (struct ext2fs_direct *)dirbuf;
828 dsize = EXT2FS_DIRSIZ(ep->e2d_namlen);
829 spacefree = fs2h16(ep->e2d_reclen) - dsize;
830 for (loc = fs2h16(ep->e2d_reclen); loc < dp->i_count; ) {
831 nep = (struct ext2fs_direct *)(dirbuf + loc);
832 if (ep->e2d_ino) {
833
834 ep->e2d_reclen = h2fs16(dsize);
835 ep = (struct ext2fs_direct *)((char *)ep + dsize);
836 } else {
837
838 spacefree += dsize;
839 }
840 dsize = EXT2FS_DIRSIZ(nep->e2d_namlen);
841 spacefree += fs2h16(nep->e2d_reclen) - dsize;
842 loc += fs2h16(nep->e2d_reclen);
843 memcpy((caddr_t)ep, (caddr_t)nep, dsize);
844 }
845
846
847
848
849 if (ep->e2d_ino == 0) {
850 #ifdef DIAGNOSTIC
851 if (spacefree + dsize < newentrysize)
852 panic("ext2fs_direnter: compact1");
853 #endif
854 newdir.e2d_reclen = h2fs16(spacefree + dsize);
855 } else {
856 #ifdef DIAGNOSTIC
857 if (spacefree < newentrysize) {
858 printf("ext2fs_direnter: compact2 %u %u",
859 (u_int)spacefree, (u_int)newentrysize);
860 panic("ext2fs_direnter: compact2");
861 }
862 #endif
863 newdir.e2d_reclen = h2fs16(spacefree);
864 ep->e2d_reclen = h2fs16(dsize);
865 ep = (struct ext2fs_direct *)((char *)ep + dsize);
866 }
867 memcpy((caddr_t)ep, (caddr_t)&newdir, (u_int)newentrysize);
868 error = VOP_BWRITE(bp);
869 dp->i_flag |= IN_CHANGE | IN_UPDATE;
870 if (!error && dp->i_endoff && dp->i_endoff < ext2fs_size(dp))
871 error = ext2fs_truncate(dp, (off_t)dp->i_endoff, IO_SYNC,
872 cnp->cn_cred);
873 return (error);
874 }
875
876
877
878
879
880
881
882
883
884
885
886
887
888 int
889 ext2fs_dirremove(struct vnode *dvp, struct componentname *cnp)
890 {
891 struct inode *dp;
892 struct ext2fs_direct *ep;
893 struct buf *bp;
894 int error;
895
896 dp = VTOI(dvp);
897 if (dp->i_count == 0) {
898
899
900
901 error = ext2fs_bufatoff(dp, (off_t)dp->i_offset, (char **)&ep,
902 &bp);
903 if (error != 0)
904 return (error);
905 ep->e2d_ino = 0;
906 error = VOP_BWRITE(bp);
907 dp->i_flag |= IN_CHANGE | IN_UPDATE;
908 return (error);
909 }
910
911
912
913 error = ext2fs_bufatoff(dp, (off_t)(dp->i_offset - dp->i_count),
914 (char **)&ep, &bp);
915 if (error != 0)
916 return (error);
917 ep->e2d_reclen = h2fs16(fs2h16(ep->e2d_reclen) + dp->i_reclen);
918 error = VOP_BWRITE(bp);
919 dp->i_flag |= IN_CHANGE | IN_UPDATE;
920 return (error);
921 }
922
923
924
925
926
927
928 int
929 ext2fs_dirrewrite(struct inode *dp, struct inode *ip,
930 struct componentname *cnp)
931 {
932 struct buf *bp;
933 struct ext2fs_direct *ep;
934 int error;
935
936 error = ext2fs_bufatoff(dp, (off_t)dp->i_offset, (char **)&ep, &bp);
937 if (error != 0)
938 return (error);
939 ep->e2d_ino = h2fs32(ip->i_number);
940 if (ip->i_e2fs->e2fs.e2fs_rev > E2FS_REV0 &&
941 (ip->i_e2fs->e2fs.e2fs_features_incompat & EXT2F_INCOMPAT_FTYPE)) {
942 ep->e2d_type = inot2ext2dt(IFTODT(ip->i_e2fs_mode));
943 } else {
944 ep->e2d_type = 0;
945 }
946 error = VOP_BWRITE(bp);
947 dp->i_flag |= IN_CHANGE | IN_UPDATE;
948 return (error);
949 }
950
951
952
953
954
955
956
957
958
959
960 int
961 ext2fs_dirempty(struct inode *ip, ino_t parentino, struct ucred *cred)
962 {
963 off_t off;
964 struct ext2fs_dirtemplate dbuf;
965 struct ext2fs_direct *dp = (struct ext2fs_direct *)&dbuf;
966 int error, namlen;
967 size_t count;
968
969 #define MINDIRSIZ (sizeof (struct ext2fs_dirtemplate) / 2)
970
971 for (off = 0; off < ext2fs_size(ip); off += fs2h16(dp->e2d_reclen)) {
972 error = vn_rdwr(UIO_READ, ITOV(ip), (caddr_t)dp, MINDIRSIZ, off,
973 UIO_SYSSPACE, IO_NODELOCKED, cred, &count, (struct proc *)0);
974
975
976
977
978 if (error || count != 0)
979 return (0);
980
981 if (dp->e2d_reclen == 0)
982 return (0);
983
984 if (dp->e2d_ino == 0)
985 continue;
986
987 namlen = dp->e2d_namlen;
988 if (namlen > 2)
989 return (0);
990 if (dp->e2d_name[0] != '.')
991 return (0);
992
993
994
995
996
997 if (namlen == 1)
998 continue;
999 if (dp->e2d_name[1] == '.' && fs2h32(dp->e2d_ino) == parentino)
1000 continue;
1001 return (0);
1002 }
1003 return (1);
1004 }
1005
1006
1007
1008
1009
1010
1011 int
1012 ext2fs_checkpath(struct inode *source, struct inode *target,
1013 struct ucred *cred)
1014 {
1015 struct vnode *vp;
1016 int error, rootino, namlen;
1017 struct ext2fs_dirtemplate dirbuf;
1018 u_int32_t ino;
1019
1020 vp = ITOV(target);
1021 if (target->i_number == source->i_number) {
1022 error = EEXIST;
1023 goto out;
1024 }
1025 rootino = ROOTINO;
1026 error = 0;
1027 if (target->i_number == rootino)
1028 goto out;
1029
1030 for (;;) {
1031 if (vp->v_type != VDIR) {
1032 error = ENOTDIR;
1033 break;
1034 }
1035 error = vn_rdwr(UIO_READ, vp, (caddr_t)&dirbuf,
1036 sizeof (struct ext2fs_dirtemplate), (off_t)0,
1037 UIO_SYSSPACE, IO_NODELOCKED, cred, (size_t *)0,
1038 (struct proc *)0);
1039 if (error != 0)
1040 break;
1041 namlen = dirbuf.dotdot_namlen;
1042 if (namlen != 2 ||
1043 dirbuf.dotdot_name[0] != '.' ||
1044 dirbuf.dotdot_name[1] != '.') {
1045 error = ENOTDIR;
1046 break;
1047 }
1048 ino = fs2h32(dirbuf.dotdot_ino);
1049 if (ino == source->i_number) {
1050 error = EINVAL;
1051 break;
1052 }
1053 if (ino == rootino)
1054 break;
1055 vput(vp);
1056 error = VFS_VGET(vp->v_mount, ino, &vp);
1057 if (error != 0) {
1058 vp = NULL;
1059 break;
1060 }
1061 }
1062
1063 out:
1064 if (error == ENOTDIR) {
1065 printf("checkpath: .. not a directory\n");
1066 panic("checkpath");
1067 }
1068 if (vp != NULL)
1069 vput(vp);
1070 return (error);
1071 }