This source file includes following definitions.
- ext2fs_create
- ext2fs_mknod
- ext2fs_open
- ext2fs_access
- ext2fs_getattr
- ext2fs_setattr
- ext2fs_chmod
- ext2fs_chown
- ext2fs_remove
- ext2fs_link
- ext2fs_rename
- ext2fs_mkdir
- ext2fs_rmdir
- ext2fs_symlink
- ext2fs_readlink
- ext2fs_advlock
- ext2fs_makeinode
- ext2fs_fsync
- ext2fs_reclaim
- ext2fsfifo_reclaim
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 #include <sys/param.h>
43 #include <sys/systm.h>
44 #include <sys/resourcevar.h>
45 #include <sys/kernel.h>
46 #include <sys/file.h>
47 #include <sys/stat.h>
48 #include <sys/buf.h>
49 #include <sys/proc.h>
50 #include <sys/conf.h>
51 #include <sys/mount.h>
52 #include <sys/namei.h>
53 #include <sys/vnode.h>
54 #include <sys/lockf.h>
55 #include <sys/malloc.h>
56 #include <sys/pool.h>
57 #include <sys/signalvar.h>
58
59 #include <uvm/uvm_extern.h>
60
61 #include <miscfs/fifofs/fifo.h>
62 #include <miscfs/specfs/specdev.h>
63
64 #include <ufs/ufs/quota.h>
65 #include <ufs/ufs/inode.h>
66 #include <ufs/ufs/ufs_extern.h>
67 #include <ufs/ufs/ufsmount.h>
68
69 #include <ufs/ext2fs/ext2fs.h>
70 #include <ufs/ext2fs/ext2fs_extern.h>
71 #include <ufs/ext2fs/ext2fs_dir.h>
72
73 static int ext2fs_chmod(struct vnode *, mode_t, struct ucred *, struct proc *);
74 static int ext2fs_chown(struct vnode *, uid_t, gid_t, struct ucred *, struct proc *);
75
76
77
78
79 int
80 ext2fs_create(void *v)
81 {
82 struct vop_create_args *ap = v;
83 return ext2fs_makeinode(MAKEIMODE(ap->a_vap->va_type,
84 ap->a_vap->va_mode),
85 ap->a_dvp, ap->a_vpp, ap->a_cnp);
86 }
87
88
89
90
91
92 int
93 ext2fs_mknod(void *v)
94 {
95 struct vop_mknod_args *ap = v;
96 struct vattr *vap = ap->a_vap;
97 struct vnode **vpp = ap->a_vpp;
98 struct inode *ip;
99 int error;
100
101 if ((error =
102 ext2fs_makeinode(MAKEIMODE(vap->va_type, vap->va_mode),
103 ap->a_dvp, vpp, ap->a_cnp)) != 0)
104 return (error);
105 ip = VTOI(*vpp);
106 ip->i_flag |= IN_ACCESS | IN_CHANGE | IN_UPDATE;
107 if (vap->va_rdev != VNOVAL) {
108
109
110
111
112 ip->i_e2din->e2di_rdev = h2fs32(vap->va_rdev);
113 }
114
115
116
117
118
119 vput(*vpp);
120 (*vpp)->v_type = VNON;
121 vgone(*vpp);
122 *vpp = 0;
123 return (0);
124 }
125
126
127
128
129
130
131
132 int
133 ext2fs_open(void *v)
134 {
135 struct vop_open_args *ap = v;
136
137
138
139
140 if ((VTOI(ap->a_vp)->i_e2fs_flags & EXT2_APPEND) &&
141 (ap->a_mode & (FWRITE | O_APPEND)) == FWRITE)
142 return (EPERM);
143 return (0);
144 }
145
146 int
147 ext2fs_access(void *v)
148 {
149 struct vop_access_args *ap = v;
150 struct vnode *vp = ap->a_vp;
151 struct inode *ip = VTOI(vp);
152 mode_t mode = ap->a_mode;
153
154
155 if ((mode & VWRITE) && (ip->i_e2fs_flags & EXT2_IMMUTABLE))
156 return (EPERM);
157
158 return (vaccess(ip->i_e2fs_mode, ip->i_e2fs_uid, ip->i_e2fs_gid, mode,
159 ap->a_cred));
160 }
161
162
163 int
164 ext2fs_getattr(void *v)
165 {
166 struct vop_getattr_args *ap = v;
167 struct vnode *vp = ap->a_vp;
168 struct inode *ip = VTOI(vp);
169 struct vattr *vap = ap->a_vap;
170 struct timeval tv;
171
172 getmicrotime(&tv);
173 EXT2FS_ITIMES(ip, &tv, &tv);
174
175
176
177 vap->va_fsid = ip->i_dev;
178 vap->va_fileid = ip->i_number;
179 vap->va_mode = ip->i_e2fs_mode & ALLPERMS;
180 vap->va_nlink = ip->i_e2fs_nlink;
181 vap->va_uid = ip->i_e2fs_uid;
182 vap->va_gid = ip->i_e2fs_gid;
183 vap->va_rdev = (dev_t)fs2h32(ip->i_e2din->e2di_rdev);
184 vap->va_size = ext2fs_size(ip);
185 vap->va_atime.tv_sec = ip->i_e2fs_atime;
186 vap->va_atime.tv_nsec = 0;
187 vap->va_mtime.tv_sec = ip->i_e2fs_mtime;
188 vap->va_mtime.tv_nsec = 0;
189 vap->va_ctime.tv_sec = ip->i_e2fs_ctime;
190 vap->va_ctime.tv_nsec = 0;
191 #ifdef EXT2FS_SYSTEM_FLAGS
192 vap->va_flags = (ip->i_e2fs_flags & EXT2_APPEND) ? SF_APPEND : 0;
193 vap->va_flags |= (ip->i_e2fs_flags & EXT2_IMMUTABLE) ? SF_IMMUTABLE : 0;
194 #else
195 vap->va_flags = (ip->i_e2fs_flags & EXT2_APPEND) ? UF_APPEND : 0;
196 vap->va_flags |= (ip->i_e2fs_flags & EXT2_IMMUTABLE) ? UF_IMMUTABLE : 0;
197 #endif
198 vap->va_gen = ip->i_e2fs_gen;
199
200 if (vp->v_type == VBLK)
201 vap->va_blocksize = BLKDEV_IOSIZE;
202 else if (vp->v_type == VCHR)
203 vap->va_blocksize = MAXBSIZE;
204 else
205 vap->va_blocksize = vp->v_mount->mnt_stat.f_iosize;
206 vap->va_bytes = dbtob((u_quad_t)ip->i_e2fs_nblock);
207 vap->va_type = vp->v_type;
208 vap->va_filerev = ip->i_modrev;
209 return (0);
210 }
211
212
213
214
215 int
216 ext2fs_setattr(void *v)
217 {
218 struct vop_setattr_args *ap = v;
219 struct vattr *vap = ap->a_vap;
220 struct vnode *vp = ap->a_vp;
221 struct inode *ip = VTOI(vp);
222 struct ucred *cred = ap->a_cred;
223 struct proc *p = ap->a_p;
224 int error;
225
226
227
228
229 if ((vap->va_type != VNON) || (vap->va_nlink != VNOVAL) ||
230 (vap->va_fsid != VNOVAL) || (vap->va_fileid != VNOVAL) ||
231 (vap->va_blocksize != VNOVAL) || (vap->va_rdev != VNOVAL) ||
232 ((int)vap->va_bytes != VNOVAL) || (vap->va_gen != VNOVAL)) {
233 return (EINVAL);
234 }
235 if (vap->va_flags != VNOVAL) {
236 if (vp->v_mount->mnt_flag & MNT_RDONLY)
237 return (EROFS);
238 if (cred->cr_uid != ip->i_e2fs_uid &&
239 (error = suser_ucred(cred)))
240 return (error);
241 #ifdef EXT2FS_SYSTEM_FLAGS
242 if (cred->cr_uid == 0) {
243 if ((ip->i_e2fs_flags &
244 (EXT2_APPEND | EXT2_IMMUTABLE)) && securelevel > 0)
245 return (EPERM);
246 ip->i_e2fs_flags &= ~(EXT2_APPEND | EXT2_IMMUTABLE);
247 ip->i_e2fs_flags |=
248 (vap->va_flags & SF_APPEND) ? EXT2_APPEND : 0 |
249 (vap->va_flags & SF_IMMUTABLE) ? EXT2_IMMUTABLE: 0;
250 } else {
251 return (EPERM);
252 }
253 #else
254 ip->i_e2fs_flags &= ~(EXT2_APPEND | EXT2_IMMUTABLE);
255 ip->i_e2fs_flags |=
256 (vap->va_flags & UF_APPEND) ? EXT2_APPEND : 0 |
257 (vap->va_flags & UF_IMMUTABLE) ? EXT2_IMMUTABLE: 0;
258 #endif
259 ip->i_flag |= IN_CHANGE;
260 if (vap->va_flags & (IMMUTABLE | APPEND))
261 return (0);
262 }
263 if (ip->i_e2fs_flags & (EXT2_APPEND | EXT2_IMMUTABLE))
264 return (EPERM);
265
266
267
268 if (vap->va_uid != (uid_t)VNOVAL || vap->va_gid != (gid_t)VNOVAL) {
269 if (vp->v_mount->mnt_flag & MNT_RDONLY)
270 return (EROFS);
271 error = ext2fs_chown(vp, vap->va_uid, vap->va_gid, cred, p);
272 if (error)
273 return (error);
274 }
275 if (vap->va_size != VNOVAL) {
276
277
278
279
280
281 switch (vp->v_type) {
282 case VDIR:
283 return (EISDIR);
284 case VLNK:
285 case VREG:
286 if (vp->v_mount->mnt_flag & MNT_RDONLY)
287 return (EROFS);
288 default:
289 break;
290 }
291 error = ext2fs_truncate(ip, vap->va_size, 0, cred);
292 if (error)
293 return (error);
294 }
295 if (vap->va_atime.tv_sec != VNOVAL || vap->va_mtime.tv_sec != VNOVAL) {
296 if (vp->v_mount->mnt_flag & MNT_RDONLY)
297 return (EROFS);
298 if (cred->cr_uid != ip->i_e2fs_uid &&
299 (error = suser_ucred(cred)) &&
300 ((vap->va_vaflags & VA_UTIMES_NULL) == 0 ||
301 (error = VOP_ACCESS(vp, VWRITE, cred, p))))
302 return (error);
303 if (vap->va_atime.tv_sec != VNOVAL)
304 if (!(vp->v_mount->mnt_flag & MNT_NOATIME))
305 ip->i_flag |= IN_ACCESS;
306 if (vap->va_mtime.tv_sec != VNOVAL)
307 ip->i_flag |= IN_CHANGE | IN_UPDATE;
308 error = ext2fs_update(ip, &vap->va_atime, &vap->va_mtime, 1);
309 if (error)
310 return (error);
311 }
312 error = 0;
313 if (vap->va_mode != (mode_t)VNOVAL) {
314 if (vp->v_mount->mnt_flag & MNT_RDONLY)
315 return (EROFS);
316 error = ext2fs_chmod(vp, (int)vap->va_mode, cred, p);
317 }
318 return (error);
319 }
320
321
322
323
324
325 static int
326 ext2fs_chmod(struct vnode *vp, mode_t mode, struct ucred *cred, struct proc *p)
327 {
328 struct inode *ip = VTOI(vp);
329 int error;
330
331 if (cred->cr_uid != ip->i_e2fs_uid && (error = suser_ucred(cred)))
332 return (error);
333 if (cred->cr_uid) {
334 if (vp->v_type != VDIR && (mode & S_ISTXT))
335 return (EFTYPE);
336 if (!groupmember(ip->i_e2fs_gid, cred) && (mode & ISGID))
337 return (EPERM);
338 }
339 ip->i_e2fs_mode &= ~ALLPERMS;
340 ip->i_e2fs_mode |= (mode & ALLPERMS);
341 ip->i_flag |= IN_CHANGE;
342 if ((vp->v_flag & VTEXT) && (ip->i_e2fs_mode & S_ISTXT) == 0)
343 (void) uvm_vnp_uncache(vp);
344 return (0);
345 }
346
347
348
349
350
351 static int
352 ext2fs_chown(struct vnode *vp, uid_t uid, gid_t gid, struct ucred *cred, struct proc *p)
353 {
354 struct inode *ip = VTOI(vp);
355 uid_t ouid;
356 gid_t ogid;
357 int error = 0;
358
359 if (uid == (uid_t)VNOVAL)
360 uid = ip->i_e2fs_uid;
361 if (gid == (gid_t)VNOVAL)
362 gid = ip->i_e2fs_gid;
363
364
365
366
367
368 if ((cred->cr_uid != ip->i_e2fs_uid || uid != ip->i_e2fs_uid ||
369 (gid != ip->i_e2fs_gid && !groupmember((gid_t)gid, cred))) &&
370 (error = suser_ucred(cred)))
371 return (error);
372 ogid = ip->i_e2fs_gid;
373 ouid = ip->i_e2fs_uid;
374
375 ip->i_e2fs_gid = gid;
376 ip->i_e2fs_uid = uid;
377 if (ouid != uid || ogid != gid)
378 ip->i_flag |= IN_CHANGE;
379 if (ouid != uid && cred->cr_uid != 0)
380 ip->i_e2fs_mode &= ~ISUID;
381 if (ogid != gid && cred->cr_uid != 0)
382 ip->i_e2fs_mode &= ~ISGID;
383 return (0);
384 }
385
386 int
387 ext2fs_remove(void *v)
388 {
389 struct vop_remove_args *ap = v;
390 struct inode *ip;
391 struct vnode *vp = ap->a_vp;
392 struct vnode *dvp = ap->a_dvp;
393 int error;
394
395 ip = VTOI(vp);
396 if (vp->v_type == VDIR ||
397 (ip->i_e2fs_flags & (EXT2_IMMUTABLE | EXT2_APPEND)) ||
398 (VTOI(dvp)->i_e2fs_flags & EXT2_APPEND)) {
399 error = EPERM;
400 goto out;
401 }
402 error = ext2fs_dirremove(dvp, ap->a_cnp);
403 if (error == 0) {
404 ip->i_e2fs_nlink--;
405 ip->i_flag |= IN_CHANGE;
406 }
407 out:
408 if (dvp == vp)
409 vrele(vp);
410 else
411 vput(vp);
412 vput(dvp);
413 return (error);
414 }
415
416
417
418
419 int
420 ext2fs_link(void *v)
421 {
422 struct vop_link_args *ap = v;
423 struct vnode *dvp = ap->a_dvp;
424 struct vnode *vp = ap->a_vp;
425 struct componentname *cnp = ap->a_cnp;
426 struct proc *p = cnp->cn_proc;
427 struct inode *ip;
428 int error;
429
430 #ifdef DIAGNOSTIC
431 if ((cnp->cn_flags & HASBUF) == 0)
432 panic("ext2fs_link: no name");
433 #endif
434 if (vp->v_type == VDIR) {
435 VOP_ABORTOP(dvp, cnp);
436 error = EISDIR;
437 goto out2;
438 }
439 if (dvp->v_mount != vp->v_mount) {
440 VOP_ABORTOP(dvp, cnp);
441 error = EXDEV;
442 goto out2;
443 }
444 if (dvp != vp && (error = vn_lock(vp, LK_EXCLUSIVE, p))) {
445 VOP_ABORTOP(dvp, cnp);
446 goto out2;
447 }
448 ip = VTOI(vp);
449 if ((nlink_t)ip->i_e2fs_nlink >= LINK_MAX) {
450 VOP_ABORTOP(dvp, cnp);
451 error = EMLINK;
452 goto out1;
453 }
454 if (ip->i_e2fs_flags & (EXT2_IMMUTABLE | EXT2_APPEND)) {
455 VOP_ABORTOP(dvp, cnp);
456 error = EPERM;
457 goto out1;
458 }
459 ip->i_e2fs_nlink++;
460 ip->i_flag |= IN_CHANGE;
461 error = ext2fs_update(ip, NULL, NULL, 1);
462 if (!error)
463 error = ext2fs_direnter(ip, dvp, cnp);
464 if (error) {
465 ip->i_e2fs_nlink--;
466 ip->i_flag |= IN_CHANGE;
467 }
468 pool_put(&namei_pool, cnp->cn_pnbuf);
469 out1:
470 if (dvp != vp)
471 VOP_UNLOCK(vp, 0, p);
472 out2:
473 vput(dvp);
474 return (error);
475 }
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501 int
502 ext2fs_rename(void *v)
503 {
504 struct vop_rename_args *ap = v;
505 struct vnode *tvp = ap->a_tvp;
506 struct vnode *tdvp = ap->a_tdvp;
507 struct vnode *fvp = ap->a_fvp;
508 struct vnode *fdvp = ap->a_fdvp;
509 struct componentname *tcnp = ap->a_tcnp;
510 struct componentname *fcnp = ap->a_fcnp;
511 struct inode *ip, *xp, *dp;
512 struct proc *p = fcnp->cn_proc;
513 struct ext2fs_dirtemplate dirbuf;
514
515 int doingdirectory = 0, oldparent = 0, newparent = 0;
516 int error = 0;
517 u_char namlen;
518
519 #ifdef DIAGNOSTIC
520 if ((tcnp->cn_flags & HASBUF) == 0 ||
521 (fcnp->cn_flags & HASBUF) == 0)
522 panic("ext2fs_rename: no name");
523 #endif
524
525
526
527 if ((fvp->v_mount != tdvp->v_mount) ||
528 (tvp && (fvp->v_mount != tvp->v_mount))) {
529 error = EXDEV;
530 abortit:
531 VOP_ABORTOP(tdvp, tcnp);
532 if (tdvp == tvp)
533 vrele(tdvp);
534 else
535 vput(tdvp);
536 if (tvp)
537 vput(tvp);
538 VOP_ABORTOP(fdvp, fcnp);
539 vrele(fdvp);
540 vrele(fvp);
541 return (error);
542 }
543
544
545
546
547 if (tvp && ((VTOI(tvp)->i_e2fs_flags & (EXT2_IMMUTABLE | EXT2_APPEND)) ||
548 (VTOI(tdvp)->i_e2fs_flags & EXT2_APPEND))) {
549 error = EPERM;
550 goto abortit;
551 }
552 if (fvp == tvp) {
553 if (fvp->v_type == VDIR) {
554 error = EINVAL;
555 goto abortit;
556 }
557
558
559 VOP_ABORTOP(tdvp, tcnp);
560 vput(tdvp);
561 vput(tvp);
562
563
564 vrele(fdvp);
565 vrele(fvp);
566 fcnp->cn_flags &= ~MODMASK;
567 fcnp->cn_flags |= LOCKPARENT | LOCKLEAF;
568 if ((fcnp->cn_flags & SAVESTART) == 0)
569 panic("ext2fs_rename: lost from startdir");
570 fcnp->cn_nameiop = DELETE;
571 (void) relookup(fdvp, &fvp, fcnp);
572 return (VOP_REMOVE(fdvp, fvp, fcnp));
573 }
574 if ((error = vn_lock(fvp, LK_EXCLUSIVE, p)) != 0)
575 goto abortit;
576 dp = VTOI(fdvp);
577 ip = VTOI(fvp);
578 if ((nlink_t)ip->i_e2fs_nlink >= LINK_MAX) {
579 VOP_UNLOCK(fvp, 0, p);
580 error = EMLINK;
581 goto abortit;
582 }
583 if ((ip->i_e2fs_flags & (EXT2_IMMUTABLE | EXT2_APPEND)) ||
584 (dp->i_e2fs_flags & EXT2_APPEND)) {
585 VOP_UNLOCK(fvp, 0, p);
586 error = EPERM;
587 goto abortit;
588 }
589 if ((ip->i_e2fs_mode & IFMT) == IFDIR) {
590 error = VOP_ACCESS(fvp, VWRITE, tcnp->cn_cred, tcnp->cn_proc);
591 if (!error && tvp)
592 error = VOP_ACCESS(tvp, VWRITE, tcnp->cn_cred,
593 tcnp->cn_proc);
594 if (error) {
595 VOP_UNLOCK(fvp, 0, p);
596 error = EACCES;
597 goto abortit;
598 }
599
600
601
602 if ((fcnp->cn_namelen == 1 && fcnp->cn_nameptr[0] == '.') ||
603 dp == ip ||
604 (fcnp->cn_flags&ISDOTDOT) ||
605 (tcnp->cn_flags & ISDOTDOT) ||
606 (ip->i_flag & IN_RENAME)) {
607 VOP_UNLOCK(fvp, 0, p);
608 error = EINVAL;
609 goto abortit;
610 }
611 ip->i_flag |= IN_RENAME;
612 oldparent = dp->i_number;
613 doingdirectory++;
614 }
615 vrele(fdvp);
616
617
618
619
620
621 dp = VTOI(tdvp);
622 xp = NULL;
623 if (tvp)
624 xp = VTOI(tvp);
625
626
627
628
629
630
631
632 ip->i_e2fs_nlink++;
633 ip->i_flag |= IN_CHANGE;
634 if ((error = ext2fs_update(ip, NULL, NULL, 1)) != 0) {
635 VOP_UNLOCK(fvp, 0, p);
636 goto bad;
637 }
638
639
640
641
642
643
644
645
646
647
648
649 error = VOP_ACCESS(fvp, VWRITE, tcnp->cn_cred, tcnp->cn_proc);
650 VOP_UNLOCK(fvp, 0, p);
651 if (oldparent != dp->i_number)
652 newparent = dp->i_number;
653 if (doingdirectory && newparent) {
654 if (error)
655 goto bad;
656 if (xp != NULL)
657 vput(tvp);
658 error = ext2fs_checkpath(ip, dp, tcnp->cn_cred);
659 if (error != 0)
660 goto out;
661 if ((tcnp->cn_flags & SAVESTART) == 0)
662 panic("ext2fs_rename: lost to startdir");
663 if ((error = relookup(tdvp, &tvp, tcnp)) != 0)
664 goto out;
665 dp = VTOI(tdvp);
666 xp = NULL;
667 if (tvp)
668 xp = VTOI(tvp);
669 }
670
671
672
673
674
675
676
677 if (xp == NULL) {
678 if (dp->i_dev != ip->i_dev)
679 panic("rename: EXDEV");
680
681
682
683
684
685 if (doingdirectory && newparent) {
686 if ((nlink_t)dp->i_e2fs_nlink >= LINK_MAX) {
687 error = EMLINK;
688 goto bad;
689 }
690 dp->i_e2fs_nlink++;
691 dp->i_flag |= IN_CHANGE;
692 if ((error = ext2fs_update(dp, NULL, NULL, 1)) != 0)
693 goto bad;
694 }
695 error = ext2fs_direnter(ip, tdvp, tcnp);
696 if (error != 0) {
697 if (doingdirectory && newparent) {
698 dp->i_e2fs_nlink--;
699 dp->i_flag |= IN_CHANGE;
700 (void)ext2fs_update(dp, NULL, NULL, 1);
701 }
702 goto bad;
703 }
704 vput(tdvp);
705 } else {
706 if (xp->i_dev != dp->i_dev || xp->i_dev != ip->i_dev)
707 panic("rename: EXDEV");
708
709
710
711 if (xp->i_number == ip->i_number)
712 panic("rename: same file");
713
714
715
716
717
718
719 if ((dp->i_e2fs_mode & S_ISTXT) && tcnp->cn_cred->cr_uid != 0 &&
720 tcnp->cn_cred->cr_uid != dp->i_e2fs_uid &&
721 xp->i_e2fs_uid != tcnp->cn_cred->cr_uid) {
722 error = EPERM;
723 goto bad;
724 }
725
726
727
728
729
730 if ((xp->i_e2fs_mode & IFMT) == IFDIR) {
731 if (!ext2fs_dirempty(xp, dp->i_number, tcnp->cn_cred) ||
732 xp->i_e2fs_nlink > 2) {
733 error = ENOTEMPTY;
734 goto bad;
735 }
736 if (!doingdirectory) {
737 error = ENOTDIR;
738 goto bad;
739 }
740 cache_purge(tdvp);
741 } else if (doingdirectory) {
742 error = EISDIR;
743 goto bad;
744 }
745 error = ext2fs_dirrewrite(dp, ip, tcnp);
746 if (error != 0)
747 goto bad;
748
749
750
751
752
753
754 if (doingdirectory && !newparent) {
755 dp->i_e2fs_nlink--;
756 dp->i_flag |= IN_CHANGE;
757 }
758 vput(tdvp);
759
760
761
762
763
764
765
766
767
768
769 xp->i_e2fs_nlink--;
770 if (doingdirectory) {
771 if (--xp->i_e2fs_nlink != 0)
772 panic("rename: linked directory");
773 error = ext2fs_truncate(xp, (off_t)0, IO_SYNC,
774 tcnp->cn_cred);
775 }
776 xp->i_flag |= IN_CHANGE;
777 vput(tvp);
778 xp = NULL;
779 }
780
781
782
783
784 fcnp->cn_flags &= ~MODMASK;
785 fcnp->cn_flags |= LOCKPARENT | LOCKLEAF;
786 if ((fcnp->cn_flags & SAVESTART) == 0)
787 panic("ext2fs_rename: lost from startdir");
788 (void) relookup(fdvp, &fvp, fcnp);
789 if (fvp != NULL) {
790 xp = VTOI(fvp);
791 dp = VTOI(fdvp);
792 } else {
793
794
795
796 if (doingdirectory)
797 panic("ext2fs_rename: lost dir entry");
798 vrele(ap->a_fvp);
799 return (0);
800 }
801
802
803
804
805
806
807
808
809
810
811 if (xp != ip) {
812 if (doingdirectory)
813 panic("ext2fs_rename: lost dir entry");
814 } else {
815
816
817
818
819
820
821 if (doingdirectory && newparent) {
822 dp->i_e2fs_nlink--;
823 dp->i_flag |= IN_CHANGE;
824 error = vn_rdwr(UIO_READ, fvp, (caddr_t)&dirbuf,
825 sizeof (struct ext2fs_dirtemplate), (off_t)0,
826 UIO_SYSSPACE, IO_NODELOCKED,
827 tcnp->cn_cred, (size_t *)0, (struct proc *)0);
828 if (error == 0) {
829 namlen = dirbuf.dotdot_namlen;
830 if (namlen != 2 ||
831 dirbuf.dotdot_name[0] != '.' ||
832 dirbuf.dotdot_name[1] != '.') {
833 ufs_dirbad(xp, (doff_t)12,
834 "ext2fs_rename: mangled dir");
835 } else {
836 dirbuf.dotdot_ino = h2fs32(newparent);
837 (void) vn_rdwr(UIO_WRITE, fvp,
838 (caddr_t)&dirbuf,
839 sizeof (struct dirtemplate),
840 (off_t)0, UIO_SYSSPACE,
841 IO_NODELOCKED|IO_SYNC,
842 tcnp->cn_cred, (size_t *)0,
843 (struct proc *)0);
844 cache_purge(fdvp);
845 }
846 }
847 }
848 error = ext2fs_dirremove(fdvp, fcnp);
849 if (!error) {
850 xp->i_e2fs_nlink--;
851 xp->i_flag |= IN_CHANGE;
852 }
853 xp->i_flag &= ~IN_RENAME;
854 }
855 if (dp)
856 vput(fdvp);
857 if (xp)
858 vput(fvp);
859 vrele(ap->a_fvp);
860 return (error);
861
862 bad:
863 if (xp)
864 vput(ITOV(xp));
865 vput(ITOV(dp));
866 out:
867 if (doingdirectory)
868 ip->i_flag &= ~IN_RENAME;
869 if (vn_lock(fvp, LK_EXCLUSIVE, p) == 0) {
870 ip->i_e2fs_nlink--;
871 ip->i_flag |= IN_CHANGE;
872 vput(fvp);
873 } else
874 vrele(fvp);
875 return (error);
876 }
877
878
879
880
881 int
882 ext2fs_mkdir(void *v)
883 {
884 struct vop_mkdir_args *ap = v;
885 struct vnode *dvp = ap->a_dvp;
886 struct vattr *vap = ap->a_vap;
887 struct componentname *cnp = ap->a_cnp;
888 struct inode *ip, *dp;
889 struct vnode *tvp;
890 struct ext2fs_dirtemplate dirtemplate;
891 mode_t dmode;
892 int error;
893
894 #ifdef DIAGNOSTIC
895 if ((cnp->cn_flags & HASBUF) == 0)
896 panic("ext2fs_mkdir: no name");
897 #endif
898 dp = VTOI(dvp);
899 if ((nlink_t)dp->i_e2fs_nlink >= LINK_MAX) {
900 error = EMLINK;
901 goto out;
902 }
903 dmode = vap->va_mode & ACCESSPERMS;
904 dmode |= IFDIR;
905
906
907
908
909
910 if ((error = ext2fs_inode_alloc(dp, dmode, cnp->cn_cred, &tvp)) != 0)
911 goto out;
912 ip = VTOI(tvp);
913 ip->i_e2fs_uid = cnp->cn_cred->cr_uid;
914 ip->i_e2fs_gid = dp->i_e2fs_gid;
915 ip->i_flag |= IN_ACCESS | IN_CHANGE | IN_UPDATE;
916 ip->i_e2fs_mode = dmode;
917 tvp->v_type = VDIR;
918 ip->i_e2fs_nlink = 2;
919 error = ext2fs_update(ip, NULL, NULL, 1);
920
921
922
923
924
925
926
927 dp->i_e2fs_nlink++;
928 dp->i_flag |= IN_CHANGE;
929 if ((error = ext2fs_update(dp, NULL, NULL, 1)) != 0)
930 goto bad;
931
932
933 bzero(&dirtemplate, sizeof(dirtemplate));
934 dirtemplate.dot_ino = h2fs32(ip->i_number);
935 dirtemplate.dot_reclen = h2fs16(12);
936 dirtemplate.dot_namlen = 1;
937 if (ip->i_e2fs->e2fs.e2fs_rev > E2FS_REV0 &&
938 (ip->i_e2fs->e2fs.e2fs_features_incompat & EXT2F_INCOMPAT_FTYPE)) {
939 dirtemplate.dot_type = EXT2_FT_DIR;
940 }
941 dirtemplate.dot_name[0] = '.';
942 dirtemplate.dotdot_ino = h2fs32(dp->i_number);
943 dirtemplate.dotdot_reclen = h2fs16(VTOI(dvp)->i_e2fs->e2fs_bsize - 12);
944 dirtemplate.dotdot_namlen = 2;
945 if (ip->i_e2fs->e2fs.e2fs_rev > E2FS_REV0 &&
946 (ip->i_e2fs->e2fs.e2fs_features_incompat & EXT2F_INCOMPAT_FTYPE)) {
947 dirtemplate.dotdot_type = EXT2_FT_DIR;
948 }
949 dirtemplate.dotdot_name[0] = dirtemplate.dotdot_name[1] = '.';
950 error = vn_rdwr(UIO_WRITE, tvp, (caddr_t)&dirtemplate,
951 sizeof (dirtemplate), (off_t)0, UIO_SYSSPACE,
952 IO_NODELOCKED|IO_SYNC, cnp->cn_cred, (size_t *)0, (struct proc *)0);
953 if (error) {
954 dp->i_e2fs_nlink--;
955 dp->i_flag |= IN_CHANGE;
956 goto bad;
957 }
958 if (VTOI(dvp)->i_e2fs->e2fs_bsize >
959 VFSTOUFS(dvp->v_mount)->um_mountp->mnt_stat.f_bsize)
960 panic("ext2fs_mkdir: blksize");
961 else {
962 error = ext2fs_setsize(ip, VTOI(dvp)->i_e2fs->e2fs_bsize);
963 if (error) {
964 dp->i_e2fs_nlink--;
965 dp->i_flag |= IN_CHANGE;
966 goto bad;
967 }
968 ip->i_flag |= IN_CHANGE;
969 }
970
971
972 error = ext2fs_direnter(ip, dvp, cnp);
973 if (error != 0) {
974 dp->i_e2fs_nlink--;
975 dp->i_flag |= IN_CHANGE;
976 }
977 bad:
978
979
980
981
982 if (error) {
983 ip->i_e2fs_nlink = 0;
984 ip->i_flag |= IN_CHANGE;
985 vput(tvp);
986 } else
987 *ap->a_vpp = tvp;
988 out:
989 pool_put(&namei_pool, cnp->cn_pnbuf);
990 vput(dvp);
991 return (error);
992 }
993
994
995
996
997 int
998 ext2fs_rmdir(void *v)
999 {
1000 struct vop_rmdir_args *ap = v;
1001 struct vnode *vp = ap->a_vp;
1002 struct vnode *dvp = ap->a_dvp;
1003 struct componentname *cnp = ap->a_cnp;
1004 struct inode *ip, *dp;
1005 int error;
1006
1007 ip = VTOI(vp);
1008 dp = VTOI(dvp);
1009
1010
1011
1012 if (dp == ip) {
1013 vrele(dvp);
1014 vput(vp);
1015 return (EINVAL);
1016 }
1017
1018
1019
1020
1021
1022
1023
1024 error = 0;
1025 if (ip->i_e2fs_nlink != 2 ||
1026 !ext2fs_dirempty(ip, dp->i_number, cnp->cn_cred)) {
1027 error = ENOTEMPTY;
1028 goto out;
1029 }
1030 if ((dp->i_e2fs_flags & EXT2_APPEND) ||
1031 (ip->i_e2fs_flags & (EXT2_IMMUTABLE | EXT2_APPEND))) {
1032 error = EPERM;
1033 goto out;
1034 }
1035
1036
1037
1038
1039
1040 error = ext2fs_dirremove(dvp, cnp);
1041 if (error != 0)
1042 goto out;
1043 dp->i_e2fs_nlink--;
1044 dp->i_flag |= IN_CHANGE;
1045 cache_purge(dvp);
1046 vput(dvp);
1047 dvp = NULL;
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059 ip->i_e2fs_nlink -= 2;
1060 error = ext2fs_truncate(ip, (off_t)0, IO_SYNC, cnp->cn_cred);
1061 cache_purge(ITOV(ip));
1062 out:
1063 if (dvp)
1064 vput(dvp);
1065 vput(vp);
1066 return (error);
1067 }
1068
1069
1070
1071
1072 int
1073 ext2fs_symlink(void *v)
1074 {
1075 struct vop_symlink_args *ap = v;
1076 struct vnode *vp, **vpp = ap->a_vpp;
1077 struct inode *ip;
1078 int len, error;
1079
1080 error = ext2fs_makeinode(IFLNK | ap->a_vap->va_mode, ap->a_dvp,
1081 vpp, ap->a_cnp);
1082 if (error)
1083 return (error);
1084 vp = *vpp;
1085 len = strlen(ap->a_target);
1086 if (len < vp->v_mount->mnt_maxsymlinklen) {
1087 ip = VTOI(vp);
1088 bcopy(ap->a_target, (char *)ip->i_e2din->e2di_shortlink, len);
1089 error = ext2fs_setsize(ip, len);
1090 if (error)
1091 goto bad;
1092 ip->i_flag |= IN_CHANGE | IN_UPDATE;
1093 } else
1094 error = vn_rdwr(UIO_WRITE, vp, ap->a_target, len, (off_t)0,
1095 UIO_SYSSPACE, IO_NODELOCKED, ap->a_cnp->cn_cred, NULL,
1096 (struct proc *)0);
1097 bad:
1098 vput(vp);
1099 return (error);
1100 }
1101
1102
1103
1104
1105 int
1106 ext2fs_readlink(void *v)
1107 {
1108 struct vop_readlink_args *ap = v;
1109 struct vnode *vp = ap->a_vp;
1110 struct inode *ip = VTOI(vp);
1111 int isize;
1112
1113 isize = ext2fs_size(ip);
1114 if (isize < vp->v_mount->mnt_maxsymlinklen ||
1115 (vp->v_mount->mnt_maxsymlinklen == 0 && ip->i_e2fs_nblock == 0)) {
1116 uiomove((char *)ip->i_e2din->e2di_shortlink, isize, ap->a_uio);
1117 return (0);
1118 }
1119 return (VOP_READ(vp, ap->a_uio, 0, ap->a_cred));
1120 }
1121
1122
1123
1124
1125 int
1126 ext2fs_advlock(void *v)
1127 {
1128 struct vop_advlock_args *ap = v;
1129 struct inode *ip = VTOI(ap->a_vp);
1130
1131 return (lf_advlock(&ip->i_lockf, ext2fs_size(ip), ap->a_id, ap->a_op,
1132 ap->a_fl, ap->a_flags));
1133 }
1134
1135
1136
1137
1138 int
1139 ext2fs_makeinode(int mode, struct vnode *dvp, struct vnode **vpp,
1140 struct componentname *cnp)
1141 {
1142 struct inode *ip, *pdir;
1143 struct vnode *tvp;
1144 int error;
1145
1146 pdir = VTOI(dvp);
1147 #ifdef DIAGNOSTIC
1148 if ((cnp->cn_flags & HASBUF) == 0)
1149 panic("ext2fs_makeinode: no name");
1150 #endif
1151 *vpp = NULL;
1152 if ((mode & IFMT) == 0)
1153 mode |= IFREG;
1154
1155 if ((error = ext2fs_inode_alloc(pdir, mode, cnp->cn_cred, &tvp))
1156 != 0) {
1157 pool_put(&namei_pool, cnp->cn_pnbuf);
1158 vput(dvp);
1159 return (error);
1160 }
1161 ip = VTOI(tvp);
1162 ip->i_e2fs_gid = pdir->i_e2fs_gid;
1163 ip->i_e2fs_uid = cnp->cn_cred->cr_uid;
1164 ip->i_flag |= IN_ACCESS | IN_CHANGE | IN_UPDATE;
1165 ip->i_e2fs_mode = mode;
1166 tvp->v_type = IFTOVT(mode);
1167 ip->i_e2fs_nlink = 1;
1168 if ((ip->i_e2fs_mode & ISGID) &&
1169 !groupmember(ip->i_e2fs_gid, cnp->cn_cred) &&
1170 suser_ucred(cnp->cn_cred))
1171 ip->i_e2fs_mode &= ~ISGID;
1172
1173
1174
1175
1176 if ((error = ext2fs_update(ip, NULL, NULL, 1)) != 0)
1177 goto bad;
1178 error = ext2fs_direnter(ip, dvp, cnp);
1179 if (error != 0)
1180 goto bad;
1181 if ((cnp->cn_flags & SAVESTART) == 0)
1182 pool_put(&namei_pool, cnp->cn_pnbuf);
1183 vput(dvp);
1184 *vpp = tvp;
1185 return (0);
1186
1187 bad:
1188
1189
1190
1191
1192 pool_put(&namei_pool, cnp->cn_pnbuf);
1193 vput(dvp);
1194 ip->i_e2fs_nlink = 0;
1195 ip->i_flag |= IN_CHANGE;
1196 tvp->v_type = VNON;
1197 vput(tvp);
1198 return (error);
1199 }
1200
1201
1202
1203
1204
1205 int
1206 ext2fs_fsync(void *v)
1207 {
1208 struct vop_fsync_args *ap = v;
1209 struct vnode *vp = ap->a_vp;
1210
1211 vflushbuf(vp, ap->a_waitfor == MNT_WAIT);
1212 return (ext2fs_update(VTOI(ap->a_vp), NULL, NULL,
1213 ap->a_waitfor == MNT_WAIT));
1214 }
1215
1216
1217
1218
1219 int
1220 ext2fs_reclaim(void *v)
1221 {
1222 struct vop_reclaim_args *ap = v;
1223 struct vnode *vp = ap->a_vp;
1224 struct inode *ip;
1225 #ifdef DIAGNOSTIC
1226 extern int prtactive;
1227
1228 if (prtactive && vp->v_usecount != 0)
1229 vprint("ext2fs_reclaim: pushing active", vp);
1230 #endif
1231
1232
1233
1234
1235 ip = VTOI(vp);
1236 ufs_ihashrem(ip);
1237
1238
1239
1240
1241 cache_purge(vp);
1242 if (ip->i_devvp)
1243 vrele(ip->i_devvp);
1244
1245 if (ip->i_e2din != NULL)
1246 pool_put(&ext2fs_dinode_pool, ip->i_e2din);
1247
1248 pool_put(&ext2fs_inode_pool, ip);
1249
1250 vp->v_data = NULL;
1251
1252 return (0);
1253 }
1254
1255
1256 int (**ext2fs_vnodeop_p)(void *);
1257 struct vnodeopv_entry_desc ext2fs_vnodeop_entries[] = {
1258 { &vop_default_desc, vn_default_error },
1259 { &vop_lookup_desc, ext2fs_lookup },
1260 { &vop_create_desc, ext2fs_create },
1261 { &vop_mknod_desc, ext2fs_mknod },
1262 { &vop_open_desc, ext2fs_open },
1263 { &vop_close_desc, ufs_close },
1264 { &vop_access_desc, ext2fs_access },
1265 { &vop_getattr_desc, ext2fs_getattr },
1266 { &vop_setattr_desc, ext2fs_setattr },
1267 { &vop_read_desc, ext2fs_read },
1268 { &vop_write_desc, ext2fs_write },
1269 { &vop_ioctl_desc, ufs_ioctl },
1270 { &vop_poll_desc, ufs_poll },
1271 { &vop_kqfilter_desc, vop_generic_kqfilter },
1272 { &vop_fsync_desc, ext2fs_fsync },
1273 { &vop_remove_desc, ext2fs_remove },
1274 { &vop_link_desc, ext2fs_link },
1275 { &vop_rename_desc, ext2fs_rename },
1276 { &vop_mkdir_desc, ext2fs_mkdir },
1277 { &vop_rmdir_desc, ext2fs_rmdir },
1278 { &vop_symlink_desc, ext2fs_symlink },
1279 { &vop_readdir_desc, ext2fs_readdir },
1280 { &vop_readlink_desc, ext2fs_readlink },
1281 { &vop_abortop_desc, vop_generic_abortop },
1282 { &vop_inactive_desc, ext2fs_inactive },
1283 { &vop_reclaim_desc, ext2fs_reclaim },
1284 { &vop_lock_desc, ufs_lock },
1285 { &vop_unlock_desc, ufs_unlock },
1286 { &vop_bmap_desc, ext2fs_bmap },
1287 { &vop_strategy_desc, ufs_strategy },
1288 { &vop_print_desc, ufs_print },
1289 { &vop_islocked_desc, ufs_islocked },
1290 { &vop_pathconf_desc, ufs_pathconf },
1291 { &vop_advlock_desc, ext2fs_advlock },
1292 { &vop_bwrite_desc, vop_generic_bwrite },
1293 { NULL, NULL }
1294 };
1295 struct vnodeopv_desc ext2fs_vnodeop_opv_desc =
1296 { &ext2fs_vnodeop_p, ext2fs_vnodeop_entries };
1297
1298 int (**ext2fs_specop_p)(void *);
1299 struct vnodeopv_entry_desc ext2fs_specop_entries[] = {
1300 { &vop_default_desc, spec_vnoperate },
1301 { &vop_close_desc, ufsspec_close },
1302 { &vop_access_desc, ext2fs_access },
1303 { &vop_getattr_desc, ext2fs_getattr },
1304 { &vop_setattr_desc, ext2fs_setattr },
1305 { &vop_read_desc, ufsspec_read },
1306 { &vop_write_desc, ufsspec_write },
1307 { &vop_fsync_desc, ext2fs_fsync },
1308 { &vop_inactive_desc, ext2fs_inactive },
1309 { &vop_reclaim_desc, ext2fs_reclaim },
1310 { &vop_lock_desc, ufs_lock },
1311 { &vop_unlock_desc, ufs_unlock },
1312 { &vop_print_desc, ufs_print },
1313 { &vop_islocked_desc, ufs_islocked },
1314 { NULL, NULL }
1315 };
1316 struct vnodeopv_desc ext2fs_specop_opv_desc =
1317 { &ext2fs_specop_p, ext2fs_specop_entries };
1318
1319 #ifdef FIFO
1320 int (**ext2fs_fifoop_p)(void *);
1321 struct vnodeopv_entry_desc ext2fs_fifoop_entries[] = {
1322 { &vop_default_desc, fifo_vnoperate },
1323 { &vop_close_desc, ufsfifo_close },
1324 { &vop_access_desc, ext2fs_access },
1325 { &vop_getattr_desc, ext2fs_getattr },
1326 { &vop_setattr_desc, ext2fs_setattr },
1327 { &vop_read_desc, ufsfifo_read },
1328 { &vop_write_desc, ufsfifo_write },
1329 { &vop_fsync_desc, ext2fs_fsync },
1330 { &vop_inactive_desc, ext2fs_inactive },
1331 { &vop_reclaim_desc, ext2fsfifo_reclaim },
1332 { &vop_lock_desc, ufs_lock },
1333 { &vop_unlock_desc, ufs_unlock },
1334 { &vop_print_desc, ufs_print },
1335 { &vop_islocked_desc, ufs_islocked },
1336 { &vop_bwrite_desc, vop_generic_bwrite },
1337 { NULL, NULL }
1338 };
1339 struct vnodeopv_desc ext2fs_fifoop_opv_desc =
1340 { &ext2fs_fifoop_p, ext2fs_fifoop_entries };
1341
1342 int
1343 ext2fsfifo_reclaim(void *v)
1344 {
1345 fifo_reclaim(v);
1346 return (ext2fs_reclaim(v));
1347 }
1348 #endif