Annotation of src/sys/ufs/ext2fs/ext2fs_vnops.c, Revision 1.74.18.1
1.74.18.1! yamt 1: /* $NetBSD: ext2fs_vnops.c,v 1.74 2007/03/04 06:03:43 christos Exp $ */
1.1 bouyer 2:
3: /*
4: * Copyright (c) 1982, 1986, 1989, 1993
5: * The Regents of the University of California. All rights reserved.
6: * (c) UNIX System Laboratories, Inc.
7: * All or some portions of this file are derived from material licensed
8: * to the University of California by American Telephone and Telegraph
9: * Co. or Unix System Laboratories, Inc. and are reproduced herein with
10: * the permission of UNIX System Laboratories, Inc.
11: *
12: * Redistribution and use in source and binary forms, with or without
13: * modification, are permitted provided that the following conditions
14: * are met:
15: * 1. Redistributions of source code must retain the above copyright
16: * notice, this list of conditions and the following disclaimer.
17: * 2. Redistributions in binary form must reproduce the above copyright
18: * notice, this list of conditions and the following disclaimer in the
19: * documentation and/or other materials provided with the distribution.
1.49 agc 20: * 3. Neither the name of the University nor the names of its contributors
21: * may be used to endorse or promote products derived from this software
22: * without specific prior written permission.
23: *
24: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34: * SUCH DAMAGE.
35: *
36: * @(#)ufs_vnops.c 8.14 (Berkeley) 10/26/94
37: * Modified for ext2fs by Manuel Bouyer.
38: */
39:
40: /*
41: * Copyright (c) 1997 Manuel Bouyer.
42: *
43: * Redistribution and use in source and binary forms, with or without
44: * modification, are permitted provided that the following conditions
45: * are met:
46: * 1. Redistributions of source code must retain the above copyright
47: * notice, this list of conditions and the following disclaimer.
48: * 2. Redistributions in binary form must reproduce the above copyright
49: * notice, this list of conditions and the following disclaimer in the
50: * documentation and/or other materials provided with the distribution.
1.1 bouyer 51: * 3. All advertising materials mentioning features or use of this software
52: * must display the following acknowledgement:
1.51 bouyer 53: * This product includes software developed by Manuel Bouyer.
54: * 4. The name of the author may not be used to endorse or promote products
55: * derived from this software without specific prior written permission.
1.1 bouyer 56: *
1.52 bouyer 57: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
58: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
59: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
60: * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
61: * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
62: * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
63: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
64: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
65: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
66: * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
1.1 bouyer 67: *
68: * @(#)ufs_vnops.c 8.14 (Berkeley) 10/26/94
69: * Modified for ext2fs by Manuel Bouyer.
70: */
1.40 lukem 71:
72: #include <sys/cdefs.h>
1.74.18.1! yamt 73: __KERNEL_RCSID(0, "$NetBSD: ext2fs_vnops.c,v 1.74 2007/03/04 06:03:43 christos Exp $");
1.7 mrg 74:
1.1 bouyer 75: #include <sys/param.h>
76: #include <sys/systm.h>
77: #include <sys/resourcevar.h>
78: #include <sys/kernel.h>
79: #include <sys/file.h>
80: #include <sys/stat.h>
81: #include <sys/buf.h>
82: #include <sys/proc.h>
83: #include <sys/mount.h>
84: #include <sys/namei.h>
85: #include <sys/vnode.h>
86: #include <sys/lockf.h>
87: #include <sys/malloc.h>
1.14 thorpej 88: #include <sys/pool.h>
1.1 bouyer 89: #include <sys/signalvar.h>
1.65 elad 90: #include <sys/kauth.h>
1.1 bouyer 91:
92: #include <miscfs/fifofs/fifo.h>
93: #include <miscfs/genfs/genfs.h>
94: #include <miscfs/specfs/specdev.h>
95:
96: #include <ufs/ufs/inode.h>
97: #include <ufs/ufs/ufs_extern.h>
98: #include <ufs/ufs/ufsmount.h>
99:
100: #include <ufs/ext2fs/ext2fs.h>
101: #include <ufs/ext2fs/ext2fs_extern.h>
102: #include <ufs/ext2fs/ext2fs_dir.h>
103:
1.32 tsutsui 104: extern int prtactive;
1.1 bouyer 105:
1.67 ad 106: static int ext2fs_chmod(struct vnode *, int, kauth_cred_t, struct lwp *);
1.65 elad 107: static int ext2fs_chown(struct vnode *, uid_t, gid_t, kauth_cred_t,
1.67 ad 108: struct lwp *);
1.1 bouyer 109:
110: union _qcvt {
111: int64_t qcvt;
112: int32_t val[2];
113: };
1.61 xtraeme 114:
1.1 bouyer 115: #define SETHIGH(q, h) { \
116: union _qcvt tmp; \
117: tmp.qcvt = (q); \
118: tmp.val[_QUAD_HIGHWORD] = (h); \
119: (q) = tmp.qcvt; \
120: }
121: #define SETLOW(q, l) { \
122: union _qcvt tmp; \
123: tmp.qcvt = (q); \
124: tmp.val[_QUAD_LOWWORD] = (l); \
125: (q) = tmp.qcvt; \
126: }
127:
128: /*
129: * Create a regular file
130: */
131: int
1.61 xtraeme 132: ext2fs_create(void *v)
1.1 bouyer 133: {
134: struct vop_create_args /* {
135: struct vnode *a_dvp;
136: struct vnode **a_vpp;
137: struct componentname *a_cnp;
138: struct vattr *a_vap;
139: } */ *ap = v;
1.42 jdolecek 140: int error;
141:
142: error =
143: ext2fs_makeinode(MAKEIMODE(ap->a_vap->va_type, ap->a_vap->va_mode),
144: ap->a_dvp, ap->a_vpp, ap->a_cnp);
145:
146: if (error)
147: return (error);
148: VN_KNOTE(ap->a_dvp, NOTE_WRITE);
149: return (0);
1.1 bouyer 150: }
151:
152: /*
153: * Mknod vnode call
154: */
155: /* ARGSUSED */
156: int
1.61 xtraeme 157: ext2fs_mknod(void *v)
1.1 bouyer 158: {
159: struct vop_mknod_args /* {
160: struct vnode *a_dvp;
161: struct vnode **a_vpp;
162: struct componentname *a_cnp;
163: struct vattr *a_vap;
164: } */ *ap = v;
1.25 augustss 165: struct vattr *vap = ap->a_vap;
166: struct vnode **vpp = ap->a_vpp;
167: struct inode *ip;
1.1 bouyer 168: int error;
1.59 perry 169: struct mount *mp;
1.34 assar 170: ino_t ino;
1.1 bouyer 171:
1.8 fvdl 172: if ((error = ext2fs_makeinode(MAKEIMODE(vap->va_type, vap->va_mode),
173: ap->a_dvp, vpp, ap->a_cnp)) != 0)
1.1 bouyer 174: return (error);
1.42 jdolecek 175: VN_KNOTE(ap->a_dvp, NOTE_WRITE);
1.1 bouyer 176: ip = VTOI(*vpp);
1.34 assar 177: mp = (*vpp)->v_mount;
178: ino = ip->i_number;
1.1 bouyer 179: ip->i_flag |= IN_ACCESS | IN_CHANGE | IN_UPDATE;
180: if (vap->va_rdev != VNOVAL) {
181: /*
182: * Want to be able to use this to make badblock
183: * inodes, so don't truncate the dev number.
184: */
1.44 fvdl 185: ip->i_din.e2fs_din->e2di_rdev = h2fs32(vap->va_rdev);
1.1 bouyer 186: }
187: /*
188: * Remove inode so that it will be reloaded by VFS_VGET and
189: * checked to see if it is an alias of an existing entry in
190: * the inode cache.
191: */
192: vput(*vpp);
193: (*vpp)->v_type = VNON;
194: vgone(*vpp);
1.47 thorpej 195: error = VFS_VGET(mp, ino, vpp);
1.34 assar 196: if (error != 0) {
197: *vpp = NULL;
198: return (error);
199: }
1.1 bouyer 200: return (0);
201: }
202:
203: /*
204: * Open called.
205: *
206: * Just check the APPEND flag.
207: */
208: /* ARGSUSED */
209: int
1.61 xtraeme 210: ext2fs_open(void *v)
1.1 bouyer 211: {
212: struct vop_open_args /* {
213: struct vnode *a_vp;
214: int a_mode;
1.65 elad 215: kauth_cred_t a_cred;
1.64 christos 216: struct lwp *a_l;
1.1 bouyer 217: } */ *ap = v;
218:
219: /*
220: * Files marked append-only must be opened for appending.
221: */
222: if ((VTOI(ap->a_vp)->i_e2fs_flags & EXT2_APPEND) &&
223: (ap->a_mode & (FWRITE | O_APPEND)) == FWRITE)
224: return (EPERM);
225: return (0);
226: }
227:
228: int
1.61 xtraeme 229: ext2fs_access(void *v)
1.1 bouyer 230: {
231: struct vop_access_args /* {
232: struct vnode *a_vp;
233: int a_mode;
1.65 elad 234: kauth_cred_t a_cred;
1.64 christos 235: struct lwp *a_l;
1.1 bouyer 236: } */ *ap = v;
1.8 fvdl 237: struct vnode *vp = ap->a_vp;
238: struct inode *ip = VTOI(vp);
1.1 bouyer 239: mode_t mode = ap->a_mode;
240:
1.8 fvdl 241: /*
242: * Disallow write attempts on read-only file systems;
243: * unless the file is a socket, fifo, or a block or
244: * character device resident on the file system.
245: */
246: if (mode & VWRITE) {
247: switch (vp->v_type) {
248: case VDIR:
249: case VLNK:
250: case VREG:
251: if (vp->v_mount->mnt_flag & MNT_RDONLY)
252: return (EROFS);
253: break;
254: default:
255: break;
256: }
1.1 bouyer 257: }
258:
259: /* If immutable bit set, nobody gets to write it. */
260: if ((mode & VWRITE) && (ip->i_e2fs_flags & EXT2_IMMUTABLE))
261: return (EPERM);
262:
263: return (vaccess(vp->v_type, ip->i_e2fs_mode & ALLPERMS,
264: ip->i_e2fs_uid, ip->i_e2fs_gid, mode, ap->a_cred));
265: }
266:
267: /* ARGSUSED */
268: int
1.61 xtraeme 269: ext2fs_getattr(void *v)
1.1 bouyer 270: {
271: struct vop_getattr_args /* {
272: struct vnode *a_vp;
273: struct vattr *a_vap;
1.65 elad 274: kauth_cred_t a_cred;
1.64 christos 275: struct lwp *a_l;
1.1 bouyer 276: } */ *ap = v;
1.25 augustss 277: struct vnode *vp = ap->a_vp;
278: struct inode *ip = VTOI(vp);
279: struct vattr *vap = ap->a_vap;
1.1 bouyer 280:
1.62 christos 281: EXT2FS_ITIMES(ip, NULL, NULL, NULL);
1.1 bouyer 282: /*
283: * Copy from inode table
284: */
285: vap->va_fsid = ip->i_dev;
286: vap->va_fileid = ip->i_number;
287: vap->va_mode = ip->i_e2fs_mode & ALLPERMS;
288: vap->va_nlink = ip->i_e2fs_nlink;
289: vap->va_uid = ip->i_e2fs_uid;
290: vap->va_gid = ip->i_e2fs_gid;
1.44 fvdl 291: vap->va_rdev = (dev_t)fs2h32(ip->i_din.e2fs_din->e2di_rdev);
1.37 chs 292: vap->va_size = vp->v_size;
1.1 bouyer 293: vap->va_atime.tv_sec = ip->i_e2fs_atime;
294: vap->va_atime.tv_nsec = 0;
295: vap->va_mtime.tv_sec = ip->i_e2fs_mtime;
296: vap->va_mtime.tv_nsec = 0;
297: vap->va_ctime.tv_sec = ip->i_e2fs_ctime;
298: vap->va_ctime.tv_nsec = 0;
299: #ifdef EXT2FS_SYSTEM_FLAGS
300: vap->va_flags = (ip->i_e2fs_flags & EXT2_APPEND) ? SF_APPEND : 0;
301: vap->va_flags |= (ip->i_e2fs_flags & EXT2_IMMUTABLE) ? SF_IMMUTABLE : 0;
302: #else
303: vap->va_flags = (ip->i_e2fs_flags & EXT2_APPEND) ? UF_APPEND : 0;
304: vap->va_flags |= (ip->i_e2fs_flags & EXT2_IMMUTABLE) ? UF_IMMUTABLE : 0;
305: #endif
306: vap->va_gen = ip->i_e2fs_gen;
307: /* this doesn't belong here */
308: if (vp->v_type == VBLK)
309: vap->va_blocksize = BLKDEV_IOSIZE;
310: else if (vp->v_type == VCHR)
311: vap->va_blocksize = MAXBSIZE;
312: else
313: vap->va_blocksize = vp->v_mount->mnt_stat.f_iosize;
1.8 fvdl 314: vap->va_bytes = dbtob((u_quad_t)ip->i_e2fs_nblock);
1.1 bouyer 315: vap->va_type = vp->v_type;
316: vap->va_filerev = ip->i_modrev;
317: return (0);
318: }
319:
320: /*
321: * Set attribute vnode op. called from several syscalls
322: */
323: int
1.61 xtraeme 324: ext2fs_setattr(void *v)
1.1 bouyer 325: {
326: struct vop_setattr_args /* {
327: struct vnode *a_vp;
328: struct vattr *a_vap;
1.65 elad 329: kauth_cred_t a_cred;
1.64 christos 330: struct lwp *a_l;
1.1 bouyer 331: } */ *ap = v;
1.8 fvdl 332: struct vattr *vap = ap->a_vap;
333: struct vnode *vp = ap->a_vp;
334: struct inode *ip = VTOI(vp);
1.65 elad 335: kauth_cred_t cred = ap->a_cred;
1.64 christos 336: struct lwp *l = ap->a_l;
1.1 bouyer 337: int error;
338:
339: /*
340: * Check for unsettable attributes.
341: */
1.5 christos 342: if ((vap->va_type != VNON) || (vap->va_nlink != (nlink_t)VNOVAL) ||
1.24 thorpej 343: (vap->va_fsid != VNOVAL) || (vap->va_fileid != VNOVAL) ||
344: (vap->va_blocksize != VNOVAL) || (vap->va_rdev != VNOVAL) ||
345: ((int)vap->va_bytes != VNOVAL) || (vap->va_gen != VNOVAL)) {
1.1 bouyer 346: return (EINVAL);
347: }
348: if (vap->va_flags != VNOVAL) {
1.8 fvdl 349: if (vp->v_mount->mnt_flag & MNT_RDONLY)
350: return (EROFS);
1.65 elad 351: if (kauth_cred_geteuid(cred) != ip->i_e2fs_uid &&
1.67 ad 352: (error = kauth_authorize_generic(cred, KAUTH_GENERIC_ISSUSER,
1.72 elad 353: NULL)))
1.1 bouyer 354: return (error);
355: #ifdef EXT2FS_SYSTEM_FLAGS
1.72 elad 356: if (kauth_authorize_generic(cred, KAUTH_GENERIC_ISSUSER,
357: NULL) == 0) {
1.24 thorpej 358: if ((ip->i_e2fs_flags &
1.71 elad 359: (EXT2_APPEND | EXT2_IMMUTABLE)) &&
360: kauth_authorize_system(l->l_cred,
361: KAUTH_SYSTEM_CHSYSFLAGS, 0, NULL, NULL, NULL))
1.1 bouyer 362: return (EPERM);
363: ip->i_e2fs_flags &= ~(EXT2_APPEND | EXT2_IMMUTABLE);
1.24 thorpej 364: ip->i_e2fs_flags |=
365: (vap->va_flags & SF_APPEND) ? EXT2_APPEND : 0 |
366: (vap->va_flags & SF_IMMUTABLE) ? EXT2_IMMUTABLE : 0;
367: } else
1.1 bouyer 368: return (EPERM);
369: #else
370: ip->i_e2fs_flags &= ~(EXT2_APPEND | EXT2_IMMUTABLE);
1.24 thorpej 371: ip->i_e2fs_flags |=
372: (vap->va_flags & UF_APPEND) ? EXT2_APPEND : 0 |
373: (vap->va_flags & UF_IMMUTABLE) ? EXT2_IMMUTABLE : 0;
1.1 bouyer 374: #endif
375: ip->i_flag |= IN_CHANGE;
376: if (vap->va_flags & (IMMUTABLE | APPEND))
377: return (0);
378: }
379: if (ip->i_e2fs_flags & (EXT2_APPEND | EXT2_IMMUTABLE))
380: return (EPERM);
381: /*
382: * Go through the fields and update iff not VNOVAL.
383: */
384: if (vap->va_uid != (uid_t)VNOVAL || vap->va_gid != (gid_t)VNOVAL) {
1.8 fvdl 385: if (vp->v_mount->mnt_flag & MNT_RDONLY)
386: return (EROFS);
1.67 ad 387: error = ext2fs_chown(vp, vap->va_uid, vap->va_gid, cred, l);
1.1 bouyer 388: if (error)
389: return (error);
390: }
391: if (vap->va_size != VNOVAL) {
1.8 fvdl 392: /*
393: * Disallow write attempts on read-only file systems;
394: * unless the file is a socket, fifo, or a block or
395: * character device resident on the file system.
396: */
397: switch (vp->v_type) {
398: case VDIR:
1.1 bouyer 399: return (EISDIR);
1.8 fvdl 400: case VLNK:
401: case VREG:
402: if (vp->v_mount->mnt_flag & MNT_RDONLY)
403: return (EROFS);
404: default:
405: break;
406: }
1.64 christos 407: error = ext2fs_truncate(vp, vap->va_size, 0, cred, l->l_proc);
1.1 bouyer 408: if (error)
409: return (error);
410: }
411: ip = VTOI(vp);
412: if (vap->va_atime.tv_sec != VNOVAL || vap->va_mtime.tv_sec != VNOVAL) {
1.8 fvdl 413: if (vp->v_mount->mnt_flag & MNT_RDONLY)
414: return (EROFS);
1.65 elad 415: if (kauth_cred_geteuid(cred) != ip->i_e2fs_uid &&
416: (error = kauth_authorize_generic(cred, KAUTH_GENERIC_ISSUSER,
1.72 elad 417: NULL)) &&
1.59 perry 418: ((vap->va_vaflags & VA_UTIMES_NULL) == 0 ||
1.64 christos 419: (error = VOP_ACCESS(vp, VWRITE, cred, l))))
1.1 bouyer 420: return (error);
421: if (vap->va_atime.tv_sec != VNOVAL)
422: if (!(vp->v_mount->mnt_flag & MNT_NOATIME))
423: ip->i_flag |= IN_ACCESS;
424: if (vap->va_mtime.tv_sec != VNOVAL)
425: ip->i_flag |= IN_CHANGE | IN_UPDATE;
1.63 yamt 426: error = ext2fs_update(vp, &vap->va_atime, &vap->va_mtime,
1.26 perseant 427: UPDATE_WAIT);
1.1 bouyer 428: if (error)
429: return (error);
430: }
431: error = 0;
1.8 fvdl 432: if (vap->va_mode != (mode_t)VNOVAL) {
433: if (vp->v_mount->mnt_flag & MNT_RDONLY)
434: return (EROFS);
1.67 ad 435: error = ext2fs_chmod(vp, (int)vap->va_mode, cred, l);
1.8 fvdl 436: }
1.42 jdolecek 437: VN_KNOTE(vp, NOTE_ATTRIB);
1.1 bouyer 438: return (error);
439: }
440:
441: /*
442: * Change the mode on a file.
443: * Inode must be locked before calling.
444: */
445: static int
1.67 ad 446: ext2fs_chmod(struct vnode *vp, int mode, kauth_cred_t cred, struct lwp *l)
1.1 bouyer 447: {
1.25 augustss 448: struct inode *ip = VTOI(vp);
1.65 elad 449: int error, ismember = 0;
1.1 bouyer 450:
1.65 elad 451: if (kauth_cred_geteuid(cred) != ip->i_e2fs_uid &&
1.67 ad 452: (error = kauth_authorize_generic(cred, KAUTH_GENERIC_ISSUSER,
1.72 elad 453: NULL)))
1.1 bouyer 454: return (error);
1.72 elad 455: if (kauth_authorize_generic(cred, KAUTH_GENERIC_ISSUSER, NULL)) {
1.1 bouyer 456: if (vp->v_type != VDIR && (mode & S_ISTXT))
457: return (EFTYPE);
1.65 elad 458: if ((kauth_cred_ismember_gid(cred, ip->i_e2fs_gid, &ismember) != 0 ||
459: !ismember) && (mode & ISGID))
1.1 bouyer 460: return (EPERM);
461: }
462: ip->i_e2fs_mode &= ~ALLPERMS;
463: ip->i_e2fs_mode |= (mode & ALLPERMS);
464: ip->i_flag |= IN_CHANGE;
465: return (0);
466: }
467:
468: /*
469: * Perform chown operation on inode ip;
470: * inode must be locked prior to call.
471: */
472: static int
1.65 elad 473: ext2fs_chown(struct vnode *vp, uid_t uid, gid_t gid, kauth_cred_t cred,
1.67 ad 474: struct lwp *l)
1.1 bouyer 475: {
1.25 augustss 476: struct inode *ip = VTOI(vp);
1.1 bouyer 477: uid_t ouid;
478: gid_t ogid;
1.65 elad 479: int error = 0, ismember = 0;
1.1 bouyer 480:
481: if (uid == (uid_t)VNOVAL)
482: uid = ip->i_e2fs_uid;
483: if (gid == (gid_t)VNOVAL)
484: gid = ip->i_e2fs_gid;
485: /*
486: * If we don't own the file, are trying to change the owner
487: * of the file, or are not a member of the target group,
488: * the caller must be superuser or the call fails.
489: */
1.65 elad 490: if ((kauth_cred_geteuid(cred) != ip->i_e2fs_uid || uid != ip->i_e2fs_uid ||
1.67 ad 491: (gid != ip->i_e2fs_gid &&
492: !(kauth_cred_getegid(cred) == gid ||
493: (kauth_cred_ismember_gid(cred, gid, &ismember) == 0 && ismember)))) &&
1.72 elad 494: (error = kauth_authorize_generic(cred, KAUTH_GENERIC_ISSUSER, NULL)))
1.1 bouyer 495: return (error);
496: ogid = ip->i_e2fs_gid;
497: ouid = ip->i_e2fs_uid;
498:
499: ip->i_e2fs_gid = gid;
500: ip->i_e2fs_uid = uid;
501: if (ouid != uid || ogid != gid)
502: ip->i_flag |= IN_CHANGE;
1.72 elad 503: if (ouid != uid && kauth_authorize_generic(cred,
504: KAUTH_GENERIC_ISSUSER, NULL) != 0)
1.1 bouyer 505: ip->i_e2fs_mode &= ~ISUID;
1.72 elad 506: if (ogid != gid && kauth_authorize_generic(cred,
507: KAUTH_GENERIC_ISSUSER, NULL) != 0)
1.1 bouyer 508: ip->i_e2fs_mode &= ~ISGID;
509: return (0);
510: }
511:
512: int
1.61 xtraeme 513: ext2fs_remove(void *v)
1.1 bouyer 514: {
515: struct vop_remove_args /* {
516: struct vnode *a_dvp;
517: struct vnode *a_vp;
518: struct componentname *a_cnp;
519: } */ *ap = v;
1.8 fvdl 520: struct inode *ip;
521: struct vnode *vp = ap->a_vp;
522: struct vnode *dvp = ap->a_dvp;
1.1 bouyer 523: int error;
524:
525: ip = VTOI(vp);
1.2 fvdl 526: if (vp->v_type == VDIR ||
527: (ip->i_e2fs_flags & (EXT2_IMMUTABLE | EXT2_APPEND)) ||
1.1 bouyer 528: (VTOI(dvp)->i_e2fs_flags & EXT2_APPEND)) {
529: error = EPERM;
1.43 jdolecek 530: } else {
531: error = ext2fs_dirremove(dvp, ap->a_cnp);
532: if (error == 0) {
533: ip->i_e2fs_nlink--;
534: ip->i_flag |= IN_CHANGE;
535: }
1.1 bouyer 536: }
1.43 jdolecek 537:
1.42 jdolecek 538: VN_KNOTE(vp, NOTE_DELETE);
539: VN_KNOTE(dvp, NOTE_WRITE);
1.1 bouyer 540: if (dvp == vp)
541: vrele(vp);
542: else
543: vput(vp);
544: vput(dvp);
545: return (error);
546: }
547:
548: /*
549: * link vnode call
550: */
551: int
1.61 xtraeme 552: ext2fs_link(void *v)
1.1 bouyer 553: {
554: struct vop_link_args /* {
555: struct vnode *a_dvp;
556: struct vnode *a_vp;
557: struct componentname *a_cnp;
558: } */ *ap = v;
1.8 fvdl 559: struct vnode *dvp = ap->a_dvp;
560: struct vnode *vp = ap->a_vp;
561: struct componentname *cnp = ap->a_cnp;
562: struct inode *ip;
1.1 bouyer 563: int error;
564:
565: #ifdef DIAGNOSTIC
566: if ((cnp->cn_flags & HASBUF) == 0)
567: panic("ext2fs_link: no name");
568: #endif
569: if (vp->v_type == VDIR) {
570: VOP_ABORTOP(dvp, cnp);
571: error = EISDIR;
572: goto out2;
573: }
574: if (dvp->v_mount != vp->v_mount) {
575: VOP_ABORTOP(dvp, cnp);
576: error = EXDEV;
577: goto out2;
578: }
1.8 fvdl 579: if (dvp != vp && (error = vn_lock(vp, LK_EXCLUSIVE))) {
1.1 bouyer 580: VOP_ABORTOP(dvp, cnp);
581: goto out2;
582: }
583: ip = VTOI(vp);
584: if ((nlink_t)ip->i_e2fs_nlink >= LINK_MAX) {
585: VOP_ABORTOP(dvp, cnp);
586: error = EMLINK;
587: goto out1;
588: }
589: if (ip->i_e2fs_flags & (EXT2_IMMUTABLE | EXT2_APPEND)) {
590: VOP_ABORTOP(dvp, cnp);
591: error = EPERM;
592: goto out1;
593: }
594: ip->i_e2fs_nlink++;
595: ip->i_flag |= IN_CHANGE;
1.63 yamt 596: error = ext2fs_update(vp, NULL, NULL, UPDATE_WAIT);
1.1 bouyer 597: if (!error)
598: error = ext2fs_direnter(ip, dvp, cnp);
599: if (error) {
600: ip->i_e2fs_nlink--;
601: ip->i_flag |= IN_CHANGE;
602: }
1.29 thorpej 603: PNBUF_PUT(cnp->cn_pnbuf);
1.1 bouyer 604: out1:
605: if (dvp != vp)
1.8 fvdl 606: VOP_UNLOCK(vp, 0);
1.1 bouyer 607: out2:
1.42 jdolecek 608: VN_KNOTE(vp, NOTE_LINK);
609: VN_KNOTE(dvp, NOTE_WRITE);
1.1 bouyer 610: vput(dvp);
611: return (error);
612: }
613:
614: /*
615: * Rename system call.
616: * rename("foo", "bar");
617: * is essentially
618: * unlink("bar");
619: * link("foo", "bar");
620: * unlink("foo");
621: * but ``atomically''. Can't do full commit without saving state in the
622: * inode on disk which isn't feasible at this time. Best we can do is
623: * always guarantee the target exists.
624: *
625: * Basic algorithm is:
626: *
627: * 1) Bump link count on source while we're linking it to the
628: * target. This also ensure the inode won't be deleted out
629: * from underneath us while we work (it may be truncated by
630: * a concurrent `trunc' or `open' for creation).
631: * 2) Link source to destination. If destination already exists,
632: * delete it first.
633: * 3) Unlink source reference to inode if still around. If a
634: * directory was moved and the parent of the destination
635: * is different from the source, patch the ".." entry in the
636: * directory.
637: */
638: int
1.61 xtraeme 639: ext2fs_rename(void *v)
1.1 bouyer 640: {
641: struct vop_rename_args /* {
642: struct vnode *a_fdvp;
643: struct vnode *a_fvp;
644: struct componentname *a_fcnp;
645: struct vnode *a_tdvp;
646: struct vnode *a_tvp;
647: struct componentname *a_tcnp;
648: } */ *ap = v;
649: struct vnode *tvp = ap->a_tvp;
1.25 augustss 650: struct vnode *tdvp = ap->a_tdvp;
1.1 bouyer 651: struct vnode *fvp = ap->a_fvp;
1.8 fvdl 652: struct vnode *fdvp = ap->a_fdvp;
653: struct componentname *tcnp = ap->a_tcnp;
654: struct componentname *fcnp = ap->a_fcnp;
655: struct inode *ip, *xp, *dp;
1.1 bouyer 656: struct ext2fs_dirtemplate dirbuf;
657: int doingdirectory = 0, oldparent = 0, newparent = 0;
658: int error = 0;
659: u_char namlen;
660:
661: #ifdef DIAGNOSTIC
662: if ((tcnp->cn_flags & HASBUF) == 0 ||
663: (fcnp->cn_flags & HASBUF) == 0)
664: panic("ext2fs_rename: no name");
665: #endif
666: /*
667: * Check for cross-device rename.
668: */
669: if ((fvp->v_mount != tdvp->v_mount) ||
670: (tvp && (fvp->v_mount != tvp->v_mount))) {
671: error = EXDEV;
672: abortit:
673: VOP_ABORTOP(tdvp, tcnp); /* XXX, why not in NFS? */
674: if (tdvp == tvp)
675: vrele(tdvp);
676: else
677: vput(tdvp);
678: if (tvp)
679: vput(tvp);
680: VOP_ABORTOP(fdvp, fcnp); /* XXX, why not in NFS? */
681: vrele(fdvp);
682: vrele(fvp);
683: return (error);
684: }
685:
686: /*
687: * Check if just deleting a link name.
688: */
689: if (tvp && ((VTOI(tvp)->i_e2fs_flags & (EXT2_IMMUTABLE | EXT2_APPEND)) ||
690: (VTOI(tdvp)->i_e2fs_flags & EXT2_APPEND))) {
691: error = EPERM;
692: goto abortit;
693: }
694: if (fvp == tvp) {
695: if (fvp->v_type == VDIR) {
696: error = EINVAL;
697: goto abortit;
698: }
699:
700: /* Release destination completely. */
701: VOP_ABORTOP(tdvp, tcnp);
702: vput(tdvp);
703: vput(tvp);
704:
705: /* Delete source. */
706: vrele(fvp);
1.70 chs 707: fcnp->cn_flags &= ~(MODMASK | SAVESTART);
1.1 bouyer 708: fcnp->cn_flags |= LOCKPARENT | LOCKLEAF;
709: fcnp->cn_nameiop = DELETE;
1.70 chs 710: vn_lock(fdvp, LK_EXCLUSIVE | LK_RETRY);
711: if ((error = relookup(fdvp, &fvp, fcnp))) {
712: vput(fdvp);
713: return (error);
714: }
1.1 bouyer 715: return (VOP_REMOVE(fdvp, fvp, fcnp));
716: }
1.8 fvdl 717: if ((error = vn_lock(fvp, LK_EXCLUSIVE)) != 0)
1.1 bouyer 718: goto abortit;
719: dp = VTOI(fdvp);
720: ip = VTOI(fvp);
1.17 mrg 721: if ((nlink_t) ip->i_e2fs_nlink >= LINK_MAX) {
722: VOP_UNLOCK(fvp, 0);
723: error = EMLINK;
724: goto abortit;
725: }
1.1 bouyer 726: if ((ip->i_e2fs_flags & (EXT2_IMMUTABLE | EXT2_APPEND)) ||
727: (dp->i_e2fs_flags & EXT2_APPEND)) {
1.8 fvdl 728: VOP_UNLOCK(fvp, 0);
1.1 bouyer 729: error = EPERM;
730: goto abortit;
731: }
732: if ((ip->i_e2fs_mode & IFMT) == IFDIR) {
1.64 christos 733: error = VOP_ACCESS(fvp, VWRITE, tcnp->cn_cred, tcnp->cn_lwp);
1.16 bouyer 734: if (!error && tvp)
735: error = VOP_ACCESS(tvp, VWRITE, tcnp->cn_cred,
1.64 christos 736: tcnp->cn_lwp);
1.16 bouyer 737: if (error) {
738: VOP_UNLOCK(fvp, 0);
739: error = EACCES;
740: goto abortit;
741: }
1.1 bouyer 742: /*
743: * Avoid ".", "..", and aliases of "." for obvious reasons.
744: */
745: if ((fcnp->cn_namelen == 1 && fcnp->cn_nameptr[0] == '.') ||
1.3 bouyer 746: dp == ip ||
1.70 chs 747: (fcnp->cn_flags & ISDOTDOT) ||
1.16 bouyer 748: (tcnp->cn_flags & ISDOTDOT) ||
1.1 bouyer 749: (ip->i_flag & IN_RENAME)) {
1.8 fvdl 750: VOP_UNLOCK(fvp, 0);
1.1 bouyer 751: error = EINVAL;
752: goto abortit;
753: }
754: ip->i_flag |= IN_RENAME;
755: oldparent = dp->i_number;
1.70 chs 756: doingdirectory = 1;
1.1 bouyer 757: }
1.42 jdolecek 758: VN_KNOTE(fdvp, NOTE_WRITE); /* XXXLUKEM/XXX: right place? */
1.1 bouyer 759:
760: /*
761: * When the target exists, both the directory
762: * and target vnodes are returned locked.
763: */
764: dp = VTOI(tdvp);
765: xp = NULL;
766: if (tvp)
767: xp = VTOI(tvp);
768:
769: /*
770: * 1) Bump link count while we're moving stuff
771: * around. If we crash somewhere before
772: * completing our work, the link count
773: * may be wrong, but correctable.
774: */
775: ip->i_e2fs_nlink++;
776: ip->i_flag |= IN_CHANGE;
1.63 yamt 777: if ((error = ext2fs_update(fvp, NULL, NULL, UPDATE_WAIT)) != 0) {
1.8 fvdl 778: VOP_UNLOCK(fvp, 0);
1.1 bouyer 779: goto bad;
780: }
781:
782: /*
783: * If ".." must be changed (ie the directory gets a new
784: * parent) then the source directory must not be in the
1.36 wiz 785: * directory hierarchy above the target, as this would
1.1 bouyer 786: * orphan everything below the source directory. Also
787: * the user must have write permission in the source so
1.59 perry 788: * as to be able to change "..". We must repeat the call
1.1 bouyer 789: * to namei, as the parent directory is unlocked by the
790: * call to checkpath().
791: */
1.64 christos 792: error = VOP_ACCESS(fvp, VWRITE, tcnp->cn_cred, tcnp->cn_lwp);
1.8 fvdl 793: VOP_UNLOCK(fvp, 0);
1.1 bouyer 794: if (oldparent != dp->i_number)
795: newparent = dp->i_number;
796: if (doingdirectory && newparent) {
797: if (error) /* write access check above */
798: goto bad;
799: if (xp != NULL)
800: vput(tvp);
1.70 chs 801: vref(tdvp); /* compensate for the ref checkpath loses */
1.47 thorpej 802: error = ext2fs_checkpath(ip, dp, tcnp->cn_cred);
1.70 chs 803: if (error != 0) {
804: vrele(tdvp);
1.1 bouyer 805: goto out;
1.70 chs 806: }
807: tcnp->cn_flags &= ~SAVESTART;
808: vn_lock(tdvp, LK_EXCLUSIVE | LK_RETRY);
809: if ((error = relookup(tdvp, &tvp, tcnp)) != 0) {
810: vput(tdvp);
1.1 bouyer 811: goto out;
1.70 chs 812: }
1.1 bouyer 813: dp = VTOI(tdvp);
814: xp = NULL;
815: if (tvp)
816: xp = VTOI(tvp);
817: }
818: /*
819: * 2) If target doesn't exist, link the target
1.59 perry 820: * to the source and unlink the source.
1.1 bouyer 821: * Otherwise, rewrite the target directory
822: * entry to reference the source inode and
823: * expunge the original entry's existence.
824: */
825: if (xp == NULL) {
826: if (dp->i_dev != ip->i_dev)
827: panic("rename: EXDEV");
828: /*
829: * Account for ".." in new directory.
830: * When source and destination have the same
831: * parent we don't fool with the link count.
832: */
833: if (doingdirectory && newparent) {
834: if ((nlink_t)dp->i_e2fs_nlink >= LINK_MAX) {
835: error = EMLINK;
836: goto bad;
837: }
838: dp->i_e2fs_nlink++;
839: dp->i_flag |= IN_CHANGE;
1.63 yamt 840: if ((error = ext2fs_update(tdvp, NULL, NULL,
841: UPDATE_WAIT)) != 0)
1.1 bouyer 842: goto bad;
843: }
844: error = ext2fs_direnter(ip, tdvp, tcnp);
845: if (error != 0) {
846: if (doingdirectory && newparent) {
847: dp->i_e2fs_nlink--;
848: dp->i_flag |= IN_CHANGE;
1.63 yamt 849: (void)ext2fs_update(tdvp, NULL, NULL,
850: UPDATE_WAIT);
1.1 bouyer 851: }
852: goto bad;
853: }
1.42 jdolecek 854: VN_KNOTE(tdvp, NOTE_WRITE);
1.1 bouyer 855: vput(tdvp);
856: } else {
857: if (xp->i_dev != dp->i_dev || xp->i_dev != ip->i_dev)
858: panic("rename: EXDEV");
859: /*
860: * Short circuit rename(foo, foo).
861: */
862: if (xp->i_number == ip->i_number)
863: panic("rename: same file");
864: /*
865: * If the parent directory is "sticky", then the user must
866: * own the parent directory, or the destination of the rename,
867: * otherwise the destination may not be changed (except by
868: * root). This implements append-only directories.
869: */
1.72 elad 870: if ((dp->i_e2fs_mode & S_ISTXT) &&
871: kauth_authorize_generic(tcnp->cn_cred,
872: KAUTH_GENERIC_ISSUSER, NULL) != 0 &&
1.65 elad 873: kauth_cred_geteuid(tcnp->cn_cred) != dp->i_e2fs_uid &&
874: xp->i_e2fs_uid != kauth_cred_geteuid(tcnp->cn_cred)) {
1.1 bouyer 875: error = EPERM;
876: goto bad;
877: }
878: /*
879: * Target must be empty if a directory and have no links
880: * to it. Also, ensure source and target are compatible
881: * (both directories, or both not directories).
882: */
883: if ((xp->i_e2fs_mode & IFMT) == IFDIR) {
884: if (!ext2fs_dirempty(xp, dp->i_number, tcnp->cn_cred) ||
885: xp->i_e2fs_nlink > 2) {
886: error = ENOTEMPTY;
887: goto bad;
888: }
889: if (!doingdirectory) {
890: error = ENOTDIR;
891: goto bad;
892: }
893: cache_purge(tdvp);
894: } else if (doingdirectory) {
895: error = EISDIR;
896: goto bad;
897: }
898: error = ext2fs_dirrewrite(dp, ip, tcnp);
899: if (error != 0)
900: goto bad;
901: /*
902: * If the target directory is in the same
903: * directory as the source directory,
904: * decrement the link count on the parent
905: * of the target directory.
906: */
907: if (doingdirectory && !newparent) {
908: dp->i_e2fs_nlink--;
909: dp->i_flag |= IN_CHANGE;
910: }
911: /*
912: * Adjust the link count of the target to
913: * reflect the dirrewrite above. If this is
914: * a directory it is empty and there are
915: * no links to it, so we can squash the inode and
916: * any space associated with it. We disallowed
917: * renaming over top of a directory with links to
918: * it above, as the remaining link would point to
919: * a directory without "." or ".." entries.
920: */
921: xp->i_e2fs_nlink--;
922: if (doingdirectory) {
923: if (--xp->i_e2fs_nlink != 0)
924: panic("rename: linked directory");
1.63 yamt 925: error = ext2fs_truncate(tvp, (off_t)0, IO_SYNC,
1.64 christos 926: tcnp->cn_cred, tcnp->cn_lwp->l_proc);
1.1 bouyer 927: }
928: xp->i_flag |= IN_CHANGE;
1.70 chs 929: VN_KNOTE(tdvp, NOTE_WRITE);
930: vput(tdvp);
1.42 jdolecek 931: VN_KNOTE(tvp, NOTE_DELETE);
1.1 bouyer 932: vput(tvp);
933: xp = NULL;
934: }
935:
936: /*
937: * 3) Unlink the source.
938: */
1.70 chs 939: fcnp->cn_flags &= ~(MODMASK | SAVESTART);
1.1 bouyer 940: fcnp->cn_flags |= LOCKPARENT | LOCKLEAF;
1.70 chs 941: vn_lock(fdvp, LK_EXCLUSIVE | LK_RETRY);
942: if ((error = relookup(fdvp, &fvp, fcnp))) {
943: vput(fdvp);
944: vrele(ap->a_fvp);
945: return (error);
946: }
1.1 bouyer 947: if (fvp != NULL) {
948: xp = VTOI(fvp);
949: dp = VTOI(fdvp);
950: } else {
951: /*
952: * From name has disappeared.
953: */
954: if (doingdirectory)
955: panic("ext2fs_rename: lost dir entry");
956: vrele(ap->a_fvp);
957: return (0);
958: }
959: /*
960: * Ensure that the directory entry still exists and has not
961: * changed while the new name has been entered. If the source is
962: * a file then the entry may have been unlinked or renamed. In
963: * either case there is no further work to be done. If the source
964: * is a directory then it cannot have been rmdir'ed; its link
965: * count of three would cause a rmdir to fail with ENOTEMPTY.
966: * The IRENAME flag ensures that it cannot be moved by another
967: * rename.
968: */
969: if (xp != ip) {
970: if (doingdirectory)
971: panic("ext2fs_rename: lost dir entry");
972: } else {
973: /*
974: * If the source is a directory with a
975: * new parent, the link count of the old
976: * parent directory must be decremented
977: * and ".." set to point to the new parent.
978: */
979: if (doingdirectory && newparent) {
1.69 christos 980: KASSERT(dp != NULL);
1.1 bouyer 981: dp->i_e2fs_nlink--;
982: dp->i_flag |= IN_CHANGE;
1.74 christos 983: error = vn_rdwr(UIO_READ, fvp, (void *)&dirbuf,
1.1 bouyer 984: sizeof (struct ext2fs_dirtemplate), (off_t)0,
1.59 perry 985: UIO_SYSSPACE, IO_NODELOCKED,
1.56 skrll 986: tcnp->cn_cred, (size_t *)0, NULL);
1.1 bouyer 987: if (error == 0) {
1.22 bouyer 988: namlen = dirbuf.dotdot_namlen;
1.1 bouyer 989: if (namlen != 2 ||
990: dirbuf.dotdot_name[0] != '.' ||
991: dirbuf.dotdot_name[1] != '.') {
992: ufs_dirbad(xp, (doff_t)12,
993: "ext2fs_rename: mangled dir");
994: } else {
1.4 bouyer 995: dirbuf.dotdot_ino = h2fs32(newparent);
1.1 bouyer 996: (void) vn_rdwr(UIO_WRITE, fvp,
1.74 christos 997: (void *)&dirbuf,
1.1 bouyer 998: sizeof (struct dirtemplate),
999: (off_t)0, UIO_SYSSPACE,
1000: IO_NODELOCKED|IO_SYNC,
1.12 mjacob 1001: tcnp->cn_cred, (size_t *)0,
1.56 skrll 1002: NULL);
1.1 bouyer 1003: cache_purge(fdvp);
1004: }
1005: }
1006: }
1007: error = ext2fs_dirremove(fdvp, fcnp);
1008: if (!error) {
1009: xp->i_e2fs_nlink--;
1010: xp->i_flag |= IN_CHANGE;
1011: }
1012: xp->i_flag &= ~IN_RENAME;
1013: }
1.42 jdolecek 1014: VN_KNOTE(fvp, NOTE_RENAME);
1.70 chs 1015: if (dp)
1016: vput(fdvp);
1.1 bouyer 1017: if (xp)
1018: vput(fvp);
1.70 chs 1019: vrele(ap->a_fvp);
1.1 bouyer 1020: return (error);
1021:
1022: bad:
1023: if (xp)
1024: vput(ITOV(xp));
1025: vput(ITOV(dp));
1026: out:
1027: if (doingdirectory)
1028: ip->i_flag &= ~IN_RENAME;
1.8 fvdl 1029: if (vn_lock(fvp, LK_EXCLUSIVE) == 0) {
1.1 bouyer 1030: ip->i_e2fs_nlink--;
1031: ip->i_flag |= IN_CHANGE;
1032: vput(fvp);
1033: } else
1034: vrele(fvp);
1.70 chs 1035: vrele(fdvp);
1.1 bouyer 1036: return (error);
1037: }
1038:
1039: /*
1040: * Mkdir system call
1041: */
1042: int
1.61 xtraeme 1043: ext2fs_mkdir(void *v)
1.1 bouyer 1044: {
1045: struct vop_mkdir_args /* {
1046: struct vnode *a_dvp;
1047: struct vnode **a_vpp;
1048: struct componentname *a_cnp;
1049: struct vattr *a_vap;
1050: } */ *ap = v;
1.55 mycroft 1051: struct vnode *dvp = ap->a_dvp;
1052: struct vattr *vap = ap->a_vap;
1053: struct componentname *cnp = ap->a_cnp;
1054: struct inode *ip, *dp = VTOI(dvp);
1055: struct vnode *tvp;
1.4 bouyer 1056: struct ext2fs_dirtemplate dirtemplate;
1.55 mycroft 1057: int error, dmode;
1.1 bouyer 1058:
1059: #ifdef DIAGNOSTIC
1060: if ((cnp->cn_flags & HASBUF) == 0)
1061: panic("ext2fs_mkdir: no name");
1062: #endif
1063: if ((nlink_t)dp->i_e2fs_nlink >= LINK_MAX) {
1064: error = EMLINK;
1065: goto out;
1066: }
1067: dmode = vap->va_mode & ACCESSPERMS;
1068: dmode |= IFDIR;
1069: /*
1070: * Must simulate part of ext2fs_makeinode here to acquire the inode,
1071: * but not have it entered in the parent directory. The entry is
1072: * made later after writing "." and ".." entries.
1073: */
1.63 yamt 1074: if ((error = ext2fs_valloc(dvp, dmode, cnp->cn_cred, &tvp)) != 0)
1.1 bouyer 1075: goto out;
1076: ip = VTOI(tvp);
1.65 elad 1077: ip->i_e2fs_uid = kauth_cred_geteuid(cnp->cn_cred);
1.1 bouyer 1078: ip->i_e2fs_gid = dp->i_e2fs_gid;
1079: ip->i_flag |= IN_ACCESS | IN_CHANGE | IN_UPDATE;
1080: ip->i_e2fs_mode = dmode;
1081: tvp->v_type = VDIR; /* Rest init'd in getnewvnode(). */
1082: ip->i_e2fs_nlink = 2;
1083:
1084: /*
1085: * Bump link count in parent directory
1086: * to reflect work done below. Should
1087: * be done before reference is created
1088: * so reparation is possible if we crash.
1089: */
1090: dp->i_e2fs_nlink++;
1091: dp->i_flag |= IN_CHANGE;
1.63 yamt 1092: if ((error = ext2fs_update(dvp, NULL, NULL, UPDATE_DIROP)) != 0)
1.1 bouyer 1093: goto bad;
1094:
1095: /* Initialize directory with "." and ".." from static template. */
1.13 perry 1096: memset(&dirtemplate, 0, sizeof(dirtemplate));
1.4 bouyer 1097: dirtemplate.dot_ino = h2fs32(ip->i_number);
1098: dirtemplate.dot_reclen = h2fs16(12);
1.22 bouyer 1099: dirtemplate.dot_namlen = 1;
1100: if (ip->i_e2fs->e2fs.e2fs_rev > E2FS_REV0 &&
1101: (ip->i_e2fs->e2fs.e2fs_features_incompat & EXT2F_INCOMPAT_FTYPE)) {
1.23 bouyer 1102: dirtemplate.dot_type = EXT2_FT_DIR;
1.22 bouyer 1103: }
1.4 bouyer 1104: dirtemplate.dot_name[0] = '.';
1105: dirtemplate.dotdot_ino = h2fs32(dp->i_number);
1106: dirtemplate.dotdot_reclen = h2fs16(VTOI(dvp)->i_e2fs->e2fs_bsize - 12);
1.22 bouyer 1107: dirtemplate.dotdot_namlen = 2;
1108: if (ip->i_e2fs->e2fs.e2fs_rev > E2FS_REV0 &&
1109: (ip->i_e2fs->e2fs.e2fs_features_incompat & EXT2F_INCOMPAT_FTYPE)) {
1.23 bouyer 1110: dirtemplate.dotdot_type = EXT2_FT_DIR;
1.22 bouyer 1111: }
1.4 bouyer 1112: dirtemplate.dotdot_name[0] = dirtemplate.dotdot_name[1] = '.';
1.74 christos 1113: error = vn_rdwr(UIO_WRITE, tvp, (void *)&dirtemplate,
1.1 bouyer 1114: sizeof (dirtemplate), (off_t)0, UIO_SYSSPACE,
1.56 skrll 1115: IO_NODELOCKED|IO_SYNC, cnp->cn_cred, (size_t *)0, NULL);
1.1 bouyer 1116: if (error) {
1117: dp->i_e2fs_nlink--;
1118: dp->i_flag |= IN_CHANGE;
1119: goto bad;
1120: }
1.55 mycroft 1121: if (VTOI(dvp)->i_e2fs->e2fs_bsize > dvp->v_mount->mnt_stat.f_bsize)
1.1 bouyer 1122: panic("ext2fs_mkdir: blksize"); /* XXX should grow with balloc() */
1123: else {
1.58 ws 1124: error = ext2fs_setsize(ip, VTOI(dvp)->i_e2fs->e2fs_bsize);
1125: if (error) {
1126: dp->i_e2fs_nlink--;
1127: dp->i_flag |= IN_CHANGE;
1128: goto bad;
1129: }
1.1 bouyer 1130: ip->i_flag |= IN_CHANGE;
1.60 kml 1131: uvm_vnp_setsize(tvp, ext2fs_size(ip));
1.1 bouyer 1132: }
1133:
1134: /* Directory set up, now install it's entry in the parent directory. */
1135: error = ext2fs_direnter(ip, dvp, cnp);
1136: if (error != 0) {
1137: dp->i_e2fs_nlink--;
1138: dp->i_flag |= IN_CHANGE;
1139: }
1140: bad:
1141: /*
1.63 yamt 1142: * No need to do an explicit ext2fs_truncate here, vrele will do this
1.1 bouyer 1143: * for us because we set the link count to 0.
1144: */
1145: if (error) {
1146: ip->i_e2fs_nlink = 0;
1147: ip->i_flag |= IN_CHANGE;
1148: vput(tvp);
1.42 jdolecek 1149: } else {
1150: VN_KNOTE(dvp, NOTE_WRITE | NOTE_LINK);
1.1 bouyer 1151: *ap->a_vpp = tvp;
1.42 jdolecek 1152: }
1.1 bouyer 1153: out:
1.29 thorpej 1154: PNBUF_PUT(cnp->cn_pnbuf);
1.1 bouyer 1155: vput(dvp);
1156: return (error);
1157: }
1158:
1159: /*
1160: * Rmdir system call.
1161: */
1162: int
1.61 xtraeme 1163: ext2fs_rmdir(void *v)
1.1 bouyer 1164: {
1165: struct vop_rmdir_args /* {
1166: struct vnode *a_dvp;
1167: struct vnode *a_vp;
1168: struct componentname *a_cnp;
1169: } */ *ap = v;
1.25 augustss 1170: struct vnode *vp = ap->a_vp;
1171: struct vnode *dvp = ap->a_dvp;
1172: struct componentname *cnp = ap->a_cnp;
1173: struct inode *ip, *dp;
1.1 bouyer 1174: int error;
1175:
1176: ip = VTOI(vp);
1177: dp = VTOI(dvp);
1178: /*
1179: * No rmdir "." please.
1180: */
1181: if (dp == ip) {
1182: vrele(dvp);
1183: vput(vp);
1184: return (EINVAL);
1185: }
1186: /*
1187: * Verify the directory is empty (and valid).
1188: * (Rmdir ".." won't be valid since
1189: * ".." will contain a reference to
1190: * the current directory and thus be
1191: * non-empty.)
1192: */
1193: error = 0;
1194: if (ip->i_e2fs_nlink != 2 ||
1195: !ext2fs_dirempty(ip, dp->i_number, cnp->cn_cred)) {
1196: error = ENOTEMPTY;
1197: goto out;
1198: }
1199: if ((dp->i_e2fs_flags & EXT2_APPEND) ||
1200: (ip->i_e2fs_flags & (EXT2_IMMUTABLE | EXT2_APPEND))) {
1201: error = EPERM;
1202: goto out;
1203: }
1204: /*
1205: * Delete reference to directory before purging
1206: * inode. If we crash in between, the directory
1207: * will be reattached to lost+found,
1208: */
1209: error = ext2fs_dirremove(dvp, cnp);
1210: if (error != 0)
1211: goto out;
1212: dp->i_e2fs_nlink--;
1213: dp->i_flag |= IN_CHANGE;
1.42 jdolecek 1214: VN_KNOTE(dvp, NOTE_WRITE | NOTE_LINK);
1.1 bouyer 1215: cache_purge(dvp);
1216: vput(dvp);
1217: dvp = NULL;
1218: /*
1219: * Truncate inode. The only stuff left
1220: * in the directory is "." and "..". The
1221: * "." reference is inconsequential since
1222: * we're quashing it. The ".." reference
1223: * has already been adjusted above. We've
1224: * removed the "." reference and the reference
1225: * in the parent directory, but there may be
1226: * other hard links so decrement by 2 and
1227: * worry about them later.
1228: */
1229: ip->i_e2fs_nlink -= 2;
1.63 yamt 1230: error = ext2fs_truncate(vp, (off_t)0, IO_SYNC, cnp->cn_cred,
1.64 christos 1231: cnp->cn_lwp->l_proc);
1.1 bouyer 1232: cache_purge(ITOV(ip));
1233: out:
1.42 jdolecek 1234: VN_KNOTE(vp, NOTE_DELETE);
1.1 bouyer 1235: if (dvp)
1236: vput(dvp);
1237: vput(vp);
1238: return (error);
1239: }
1240:
1241: /*
1242: * symlink -- make a symbolic link
1243: */
1244: int
1.61 xtraeme 1245: ext2fs_symlink(void *v)
1.1 bouyer 1246: {
1247: struct vop_symlink_args /* {
1248: struct vnode *a_dvp;
1249: struct vnode **a_vpp;
1250: struct componentname *a_cnp;
1251: struct vattr *a_vap;
1252: char *a_target;
1253: } */ *ap = v;
1.55 mycroft 1254: struct vnode *vp, **vpp;
1255: struct inode *ip;
1256: int len, error;
1.1 bouyer 1257:
1.55 mycroft 1258: vpp = ap->a_vpp;
1.1 bouyer 1259: error = ext2fs_makeinode(IFLNK | ap->a_vap->va_mode, ap->a_dvp,
1260: vpp, ap->a_cnp);
1261: if (error)
1262: return (error);
1.42 jdolecek 1263: VN_KNOTE(ap->a_dvp, NOTE_WRITE);
1.1 bouyer 1264: vp = *vpp;
1265: len = strlen(ap->a_target);
1.55 mycroft 1266: ip = VTOI(vp);
1267: if (len < ip->i_ump->um_maxsymlinklen) {
1.44 fvdl 1268: memcpy((char *)ip->i_din.e2fs_din->e2di_shortlink, ap->a_target, len);
1.58 ws 1269: error = ext2fs_setsize(ip, len);
1270: if (error)
1271: goto bad;
1.1 bouyer 1272: ip->i_flag |= IN_CHANGE | IN_UPDATE;
1.60 kml 1273: uvm_vnp_setsize(vp, len);
1.1 bouyer 1274: } else
1275: error = vn_rdwr(UIO_WRITE, vp, ap->a_target, len, (off_t)0,
1.12 mjacob 1276: UIO_SYSSPACE, IO_NODELOCKED, ap->a_cnp->cn_cred,
1.56 skrll 1277: (size_t *)0, NULL);
1.58 ws 1278: bad:
1.34 assar 1279: if (error)
1280: vput(vp);
1.1 bouyer 1281: return (error);
1282: }
1283:
1284: /*
1285: * Return target name of a symbolic link
1286: */
1287: int
1.61 xtraeme 1288: ext2fs_readlink(void *v)
1.1 bouyer 1289: {
1290: struct vop_readlink_args /* {
1291: struct vnode *a_vp;
1292: struct uio *a_uio;
1.65 elad 1293: kauth_cred_t a_cred;
1.1 bouyer 1294: } */ *ap = v;
1.55 mycroft 1295: struct vnode *vp = ap->a_vp;
1296: struct inode *ip = VTOI(vp);
1297: struct ufsmount *ump = ip->i_ump;
1298: int isize;
1.1 bouyer 1299:
1.58 ws 1300: isize = ext2fs_size(ip);
1.55 mycroft 1301: if (isize < ump->um_maxsymlinklen ||
1302: (ump->um_maxsymlinklen == 0 && ip->i_e2fs_nblock == 0)) {
1.44 fvdl 1303: uiomove((char *)ip->i_din.e2fs_din->e2di_shortlink, isize, ap->a_uio);
1.1 bouyer 1304: return (0);
1305: }
1306: return (VOP_READ(vp, ap->a_uio, 0, ap->a_cred));
1307: }
1308:
1309: /*
1310: * Advisory record locking support
1311: */
1312: int
1.61 xtraeme 1313: ext2fs_advlock(void *v)
1.1 bouyer 1314: {
1315: struct vop_advlock_args /* {
1316: struct vnode *a_vp;
1.74 christos 1317: void * a_id;
1.1 bouyer 1318: int a_op;
1319: struct flock *a_fl;
1320: int a_flags;
1321: } */ *ap = v;
1.25 augustss 1322: struct inode *ip = VTOI(ap->a_vp);
1.1 bouyer 1323:
1.58 ws 1324: return lf_advlock(ap, &ip->i_lockf, ext2fs_size(ip));
1.1 bouyer 1325: }
1326:
1.63 yamt 1327: int
1328: ext2fs_fsync(void *v)
1329: {
1330: struct vop_fsync_args /* {
1331: struct vnode *a_vp;
1.65 elad 1332: kauth_cred_t a_cred;
1.63 yamt 1333: int a_flags;
1334: off_t offlo;
1335: off_t offhi;
1336: struct proc *a_p;
1337: } */ *ap = v;
1338: struct vnode *vp = ap->a_vp;
1339: int wait;
1340: int error;
1341:
1342: wait = (ap->a_flags & FSYNC_WAIT) != 0;
1343: vflushbuf(vp, wait);
1344: if ((ap->a_flags & FSYNC_DATAONLY) != 0)
1345: error = 0;
1346: else
1347: error = ext2fs_update(vp, NULL, NULL, wait ? UPDATE_WAIT : 0);
1348:
1349: if (error == 0 && ap->a_flags & FSYNC_CACHE) {
1350: int l = 0;
1351: error = VOP_IOCTL(VTOI(vp)->i_devvp, DIOCCACHESYNC, &l, FWRITE,
1.67 ad 1352: ap->a_l->l_cred, ap->a_l);
1.63 yamt 1353: }
1354:
1355: return error;
1356: }
1357:
1.1 bouyer 1358: /*
1359: * Initialize the vnode associated with a new inode, handle aliased
1360: * vnodes.
1361: */
1362: int
1.61 xtraeme 1363: ext2fs_vinit(struct mount *mntp, int (**specops)(void *),
1364: int (**fifoops)(void *), struct vnode **vpp)
1.1 bouyer 1365: {
1.66 kardel 1366: struct timeval tv;
1.1 bouyer 1367: struct inode *ip;
1368: struct vnode *vp, *nvp;
1369:
1370: vp = *vpp;
1371: ip = VTOI(vp);
1372: switch(vp->v_type = IFTOVT(ip->i_e2fs_mode)) {
1373: case VCHR:
1374: case VBLK:
1375: vp->v_op = specops;
1.16 bouyer 1376: if ((nvp = checkalias(vp,
1.44 fvdl 1377: fs2h32(ip->i_din.e2fs_din->e2di_rdev), mntp)) != NULL) {
1.1 bouyer 1378: /*
1379: * Discard unneeded vnode, but save its inode.
1380: */
1381: nvp->v_data = vp->v_data;
1382: vp->v_data = NULL;
1.74.18.1! yamt 1383: vp->v_vflag &= ~VV_LOCKSWORK;
1.33 fvdl 1384: VOP_UNLOCK(vp, 0);
1.1 bouyer 1385: vp->v_op = spec_vnodeop_p;
1.33 fvdl 1386: vrele(vp);
1.1 bouyer 1387: vgone(vp);
1.20 wrstuden 1388: lockmgr(&nvp->v_lock, LK_EXCLUSIVE, &nvp->v_interlock);
1.1 bouyer 1389: /*
1390: * Reinitialize aliased inode.
1391: */
1392: vp = nvp;
1393: ip->i_vnode = vp;
1394: }
1395: break;
1396: case VFIFO:
1397: vp->v_op = fifoops;
1398: break;
1399: case VNON:
1400: case VBAD:
1401: case VSOCK:
1402: case VLNK:
1403: case VDIR:
1404: case VREG:
1405: break;
1406: }
1407: if (ip->i_number == ROOTINO)
1.74.18.1! yamt 1408: vp->v_vflag |= VV_ROOT;
1.1 bouyer 1409: /*
1410: * Initialize modrev times
1411: */
1.66 kardel 1412: getmicrouptime(&tv);
1413: SETHIGH(ip->i_modrev, tv.tv_sec);
1414: SETLOW(ip->i_modrev, tv.tv_usec * 4294);
1.1 bouyer 1415: *vpp = vp;
1416: return (0);
1417: }
1418:
1419: /*
1420: * Allocate a new inode.
1421: */
1422: int
1.61 xtraeme 1423: ext2fs_makeinode(int mode, struct vnode *dvp, struct vnode **vpp,
1424: struct componentname *cnp)
1.1 bouyer 1425: {
1.25 augustss 1426: struct inode *ip, *pdir;
1.1 bouyer 1427: struct vnode *tvp;
1.65 elad 1428: int error, ismember = 0;
1.1 bouyer 1429:
1430: pdir = VTOI(dvp);
1431: #ifdef DIAGNOSTIC
1432: if ((cnp->cn_flags & HASBUF) == 0)
1433: panic("ext2fs_makeinode: no name");
1434: #endif
1435: *vpp = NULL;
1436: if ((mode & IFMT) == 0)
1437: mode |= IFREG;
1438:
1.63 yamt 1439: if ((error = ext2fs_valloc(dvp, mode, cnp->cn_cred, &tvp)) != 0) {
1.29 thorpej 1440: PNBUF_PUT(cnp->cn_pnbuf);
1.1 bouyer 1441: vput(dvp);
1442: return (error);
1443: }
1444: ip = VTOI(tvp);
1445: ip->i_e2fs_gid = pdir->i_e2fs_gid;
1.65 elad 1446: ip->i_e2fs_uid = kauth_cred_geteuid(cnp->cn_cred);
1.1 bouyer 1447: ip->i_flag |= IN_ACCESS | IN_CHANGE | IN_UPDATE;
1448: ip->i_e2fs_mode = mode;
1449: tvp->v_type = IFTOVT(mode); /* Rest init'd in getnewvnode(). */
1450: ip->i_e2fs_nlink = 1;
1.65 elad 1451: if ((ip->i_e2fs_mode & ISGID) && (kauth_cred_ismember_gid(cnp->cn_cred,
1452: ip->i_e2fs_gid, &ismember) != 0 || !ismember) &&
1453: kauth_authorize_generic(cnp->cn_cred, KAUTH_GENERIC_ISSUSER, NULL))
1.1 bouyer 1454: ip->i_e2fs_mode &= ~ISGID;
1455:
1456: /*
1457: * Make sure inode goes to disk before directory entry.
1458: */
1.63 yamt 1459: if ((error = ext2fs_update(tvp, NULL, NULL, UPDATE_WAIT)) != 0)
1.1 bouyer 1460: goto bad;
1461: error = ext2fs_direnter(ip, dvp, cnp);
1462: if (error != 0)
1463: goto bad;
1464: if ((cnp->cn_flags & SAVESTART) == 0)
1.29 thorpej 1465: PNBUF_PUT(cnp->cn_pnbuf);
1.1 bouyer 1466: vput(dvp);
1467: *vpp = tvp;
1468: return (0);
1469:
1470: bad:
1471: /*
1472: * Write error occurred trying to update the inode
1473: * or the directory so must deallocate the inode.
1474: */
1.50 dsl 1475: tvp->v_type = VNON; /* Stop explosion if VBLK */
1.1 bouyer 1476: ip->i_e2fs_nlink = 0;
1477: ip->i_flag |= IN_CHANGE;
1478: vput(tvp);
1.50 dsl 1479: PNBUF_PUT(cnp->cn_pnbuf);
1480: vput(dvp);
1.1 bouyer 1481: return (error);
1482: }
1483:
1484: /*
1485: * Reclaim an inode so that it can be used for other purposes.
1486: */
1487: int
1.61 xtraeme 1488: ext2fs_reclaim(void *v)
1.1 bouyer 1489: {
1490: struct vop_reclaim_args /* {
1491: struct vnode *a_vp;
1492: } */ *ap = v;
1.25 augustss 1493: struct vnode *vp = ap->a_vp;
1.54 mycroft 1494: struct inode *ip = VTOI(vp);
1495: int error;
1.45 fvdl 1496:
1.64 christos 1497: if ((error = ufs_reclaim(vp, ap->a_l)) != 0)
1.54 mycroft 1498: return (error);
1.45 fvdl 1499: if (ip->i_din.e2fs_din != NULL)
1500: pool_put(&ext2fs_dinode_pool, ip->i_din.e2fs_din);
1.73 ad 1501: genfs_node_destroy(vp);
1.14 thorpej 1502: pool_put(&ext2fs_inode_pool, vp->v_data);
1.1 bouyer 1503: vp->v_data = NULL;
1504: return (0);
1505: }
1506:
1507: /* Global vfs data structures for ext2fs. */
1.61 xtraeme 1508: int (**ext2fs_vnodeop_p)(void *);
1.31 jdolecek 1509: const struct vnodeopv_entry_desc ext2fs_vnodeop_entries[] = {
1.1 bouyer 1510: { &vop_default_desc, vn_default_error },
1.8 fvdl 1511: { &vop_lookup_desc, ext2fs_lookup }, /* lookup */
1512: { &vop_create_desc, ext2fs_create }, /* create */
1.1 bouyer 1513: { &vop_mknod_desc, ext2fs_mknod }, /* mknod */
1514: { &vop_open_desc, ext2fs_open }, /* open */
1515: { &vop_close_desc, ufs_close }, /* close */
1.8 fvdl 1516: { &vop_access_desc, ext2fs_access }, /* access */
1517: { &vop_getattr_desc, ext2fs_getattr }, /* getattr */
1518: { &vop_setattr_desc, ext2fs_setattr }, /* setattr */
1.1 bouyer 1519: { &vop_read_desc, ext2fs_read }, /* read */
1520: { &vop_write_desc, ext2fs_write }, /* write */
1.8 fvdl 1521: { &vop_lease_desc, ufs_lease_check }, /* lease */
1.1 bouyer 1522: { &vop_ioctl_desc, ufs_ioctl }, /* ioctl */
1.21 wrstuden 1523: { &vop_fcntl_desc, ufs_fcntl }, /* fcntl */
1.1 bouyer 1524: { &vop_poll_desc, ufs_poll }, /* poll */
1.42 jdolecek 1525: { &vop_kqfilter_desc, genfs_kqfilter }, /* kqfilter */
1.8 fvdl 1526: { &vop_revoke_desc, ufs_revoke }, /* revoke */
1.1 bouyer 1527: { &vop_mmap_desc, ufs_mmap }, /* mmap */
1528: { &vop_fsync_desc, ext2fs_fsync }, /* fsync */
1529: { &vop_seek_desc, ufs_seek }, /* seek */
1.8 fvdl 1530: { &vop_remove_desc, ext2fs_remove }, /* remove */
1.1 bouyer 1531: { &vop_link_desc, ext2fs_link }, /* link */
1.8 fvdl 1532: { &vop_rename_desc, ext2fs_rename }, /* rename */
1.1 bouyer 1533: { &vop_mkdir_desc, ext2fs_mkdir }, /* mkdir */
1534: { &vop_rmdir_desc, ext2fs_rmdir }, /* rmdir */
1.8 fvdl 1535: { &vop_symlink_desc, ext2fs_symlink }, /* symlink */
1536: { &vop_readdir_desc, ext2fs_readdir }, /* readdir */
1537: { &vop_readlink_desc, ext2fs_readlink }, /* readlink */
1.1 bouyer 1538: { &vop_abortop_desc, ufs_abortop }, /* abortop */
1.8 fvdl 1539: { &vop_inactive_desc, ext2fs_inactive }, /* inactive */
1540: { &vop_reclaim_desc, ext2fs_reclaim }, /* reclaim */
1.1 bouyer 1541: { &vop_lock_desc, ufs_lock }, /* lock */
1542: { &vop_unlock_desc, ufs_unlock }, /* unlock */
1543: { &vop_bmap_desc, ext2fs_bmap }, /* bmap */
1.8 fvdl 1544: { &vop_strategy_desc, ufs_strategy }, /* strategy */
1.1 bouyer 1545: { &vop_print_desc, ufs_print }, /* print */
1.8 fvdl 1546: { &vop_islocked_desc, ufs_islocked }, /* islocked */
1547: { &vop_pathconf_desc, ufs_pathconf }, /* pathconf */
1548: { &vop_advlock_desc, ext2fs_advlock }, /* advlock */
1.1 bouyer 1549: { &vop_bwrite_desc, vn_bwrite }, /* bwrite */
1.30 chs 1550: { &vop_getpages_desc, genfs_getpages }, /* getpages */
1551: { &vop_putpages_desc, genfs_putpages }, /* putpages */
1552: { NULL, NULL }
1.1 bouyer 1553: };
1.31 jdolecek 1554: const struct vnodeopv_desc ext2fs_vnodeop_opv_desc =
1.1 bouyer 1555: { &ext2fs_vnodeop_p, ext2fs_vnodeop_entries };
1556:
1.61 xtraeme 1557: int (**ext2fs_specop_p)(void *);
1.31 jdolecek 1558: const struct vnodeopv_entry_desc ext2fs_specop_entries[] = {
1.1 bouyer 1559: { &vop_default_desc, vn_default_error },
1560: { &vop_lookup_desc, spec_lookup }, /* lookup */
1561: { &vop_create_desc, spec_create }, /* create */
1562: { &vop_mknod_desc, spec_mknod }, /* mknod */
1563: { &vop_open_desc, spec_open }, /* open */
1564: { &vop_close_desc, ufsspec_close }, /* close */
1.8 fvdl 1565: { &vop_access_desc, ext2fs_access }, /* access */
1566: { &vop_getattr_desc, ext2fs_getattr }, /* getattr */
1567: { &vop_setattr_desc, ext2fs_setattr }, /* setattr */
1.1 bouyer 1568: { &vop_read_desc, ufsspec_read }, /* read */
1569: { &vop_write_desc, ufsspec_write }, /* write */
1.8 fvdl 1570: { &vop_lease_desc, spec_lease_check }, /* lease */
1.1 bouyer 1571: { &vop_ioctl_desc, spec_ioctl }, /* ioctl */
1.21 wrstuden 1572: { &vop_fcntl_desc, ufs_fcntl }, /* fcntl */
1.1 bouyer 1573: { &vop_poll_desc, spec_poll }, /* poll */
1.42 jdolecek 1574: { &vop_kqfilter_desc, spec_kqfilter }, /* kqfilter */
1.8 fvdl 1575: { &vop_revoke_desc, spec_revoke }, /* revoke */
1.1 bouyer 1576: { &vop_mmap_desc, spec_mmap }, /* mmap */
1577: { &vop_fsync_desc, ext2fs_fsync }, /* fsync */
1578: { &vop_seek_desc, spec_seek }, /* seek */
1579: { &vop_remove_desc, spec_remove }, /* remove */
1580: { &vop_link_desc, spec_link }, /* link */
1581: { &vop_rename_desc, spec_rename }, /* rename */
1582: { &vop_mkdir_desc, spec_mkdir }, /* mkdir */
1583: { &vop_rmdir_desc, spec_rmdir }, /* rmdir */
1.8 fvdl 1584: { &vop_symlink_desc, spec_symlink }, /* symlink */
1585: { &vop_readdir_desc, spec_readdir }, /* readdir */
1586: { &vop_readlink_desc, spec_readlink }, /* readlink */
1587: { &vop_abortop_desc, spec_abortop }, /* abortop */
1588: { &vop_inactive_desc, ext2fs_inactive }, /* inactive */
1589: { &vop_reclaim_desc, ext2fs_reclaim }, /* reclaim */
1.1 bouyer 1590: { &vop_lock_desc, ufs_lock }, /* lock */
1591: { &vop_unlock_desc, ufs_unlock }, /* unlock */
1592: { &vop_bmap_desc, spec_bmap }, /* bmap */
1.8 fvdl 1593: { &vop_strategy_desc, spec_strategy }, /* strategy */
1.1 bouyer 1594: { &vop_print_desc, ufs_print }, /* print */
1.8 fvdl 1595: { &vop_islocked_desc, ufs_islocked }, /* islocked */
1596: { &vop_pathconf_desc, spec_pathconf }, /* pathconf */
1597: { &vop_advlock_desc, spec_advlock }, /* advlock */
1.1 bouyer 1598: { &vop_bwrite_desc, vn_bwrite }, /* bwrite */
1.35 chs 1599: { &vop_getpages_desc, spec_getpages }, /* getpages */
1600: { &vop_putpages_desc, spec_putpages }, /* putpages */
1.30 chs 1601: { NULL, NULL }
1.1 bouyer 1602: };
1.31 jdolecek 1603: const struct vnodeopv_desc ext2fs_specop_opv_desc =
1.1 bouyer 1604: { &ext2fs_specop_p, ext2fs_specop_entries };
1605:
1.61 xtraeme 1606: int (**ext2fs_fifoop_p)(void *);
1.31 jdolecek 1607: const struct vnodeopv_entry_desc ext2fs_fifoop_entries[] = {
1.1 bouyer 1608: { &vop_default_desc, vn_default_error },
1609: { &vop_lookup_desc, fifo_lookup }, /* lookup */
1610: { &vop_create_desc, fifo_create }, /* create */
1611: { &vop_mknod_desc, fifo_mknod }, /* mknod */
1612: { &vop_open_desc, fifo_open }, /* open */
1613: { &vop_close_desc, ufsfifo_close }, /* close */
1.8 fvdl 1614: { &vop_access_desc, ext2fs_access }, /* access */
1615: { &vop_getattr_desc, ext2fs_getattr }, /* getattr */
1616: { &vop_setattr_desc, ext2fs_setattr }, /* setattr */
1.1 bouyer 1617: { &vop_read_desc, ufsfifo_read }, /* read */
1618: { &vop_write_desc, ufsfifo_write }, /* write */
1.8 fvdl 1619: { &vop_lease_desc, fifo_lease_check }, /* lease */
1.1 bouyer 1620: { &vop_ioctl_desc, fifo_ioctl }, /* ioctl */
1.21 wrstuden 1621: { &vop_fcntl_desc, ufs_fcntl }, /* fcntl */
1.1 bouyer 1622: { &vop_poll_desc, fifo_poll }, /* poll */
1.42 jdolecek 1623: { &vop_kqfilter_desc, fifo_kqfilter }, /* kqfilter */
1.8 fvdl 1624: { &vop_revoke_desc, fifo_revoke }, /* revoke */
1.1 bouyer 1625: { &vop_mmap_desc, fifo_mmap }, /* mmap */
1626: { &vop_fsync_desc, ext2fs_fsync }, /* fsync */
1627: { &vop_seek_desc, fifo_seek }, /* seek */
1628: { &vop_remove_desc, fifo_remove }, /* remove */
1629: { &vop_link_desc, fifo_link }, /* link */
1630: { &vop_rename_desc, fifo_rename }, /* rename */
1631: { &vop_mkdir_desc, fifo_mkdir }, /* mkdir */
1632: { &vop_rmdir_desc, fifo_rmdir }, /* rmdir */
1.8 fvdl 1633: { &vop_symlink_desc, fifo_symlink }, /* symlink */
1634: { &vop_readdir_desc, fifo_readdir }, /* readdir */
1635: { &vop_readlink_desc, fifo_readlink }, /* readlink */
1636: { &vop_abortop_desc, fifo_abortop }, /* abortop */
1637: { &vop_inactive_desc, ext2fs_inactive }, /* inactive */
1638: { &vop_reclaim_desc, ext2fs_reclaim }, /* reclaim */
1.1 bouyer 1639: { &vop_lock_desc, ufs_lock }, /* lock */
1640: { &vop_unlock_desc, ufs_unlock }, /* unlock */
1641: { &vop_bmap_desc, fifo_bmap }, /* bmap */
1.8 fvdl 1642: { &vop_strategy_desc, fifo_strategy }, /* strategy */
1.1 bouyer 1643: { &vop_print_desc, ufs_print }, /* print */
1.8 fvdl 1644: { &vop_islocked_desc, ufs_islocked }, /* islocked */
1645: { &vop_pathconf_desc, fifo_pathconf }, /* pathconf */
1646: { &vop_advlock_desc, fifo_advlock }, /* advlock */
1.1 bouyer 1647: { &vop_bwrite_desc, vn_bwrite }, /* bwrite */
1.38 sommerfe 1648: { &vop_putpages_desc, fifo_putpages }, /* putpages */
1.30 chs 1649: { NULL, NULL }
1.1 bouyer 1650: };
1.31 jdolecek 1651: const struct vnodeopv_desc ext2fs_fifoop_opv_desc =
1.1 bouyer 1652: { &ext2fs_fifoop_p, ext2fs_fifoop_entries };
CVSweb <webmaster@jp.NetBSD.org>