Annotation of src/sys/ufs/ext2fs/ext2fs_vnops.c, Revision 1.120
1.120 ! jdolecek 1: /* $NetBSD: ext2fs_vnops.c,v 1.119 2016/08/03 23:29:05 jdolecek 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: *
1.52 bouyer 52: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
53: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
54: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
55: * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
56: * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
57: * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
58: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
59: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
60: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
61: * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
1.1 bouyer 62: *
63: * @(#)ufs_vnops.c 8.14 (Berkeley) 10/26/94
64: * Modified for ext2fs by Manuel Bouyer.
65: */
1.40 lukem 66:
67: #include <sys/cdefs.h>
1.120 ! jdolecek 68: __KERNEL_RCSID(0, "$NetBSD: ext2fs_vnops.c,v 1.119 2016/08/03 23:29:05 jdolecek Exp $");
1.7 mrg 69:
1.1 bouyer 70: #include <sys/param.h>
71: #include <sys/systm.h>
72: #include <sys/resourcevar.h>
73: #include <sys/kernel.h>
74: #include <sys/file.h>
75: #include <sys/stat.h>
76: #include <sys/buf.h>
77: #include <sys/proc.h>
78: #include <sys/mount.h>
79: #include <sys/namei.h>
80: #include <sys/vnode.h>
81: #include <sys/lockf.h>
1.14 thorpej 82: #include <sys/pool.h>
1.1 bouyer 83: #include <sys/signalvar.h>
1.65 elad 84: #include <sys/kauth.h>
1.1 bouyer 85:
86: #include <miscfs/fifofs/fifo.h>
87: #include <miscfs/genfs/genfs.h>
88: #include <miscfs/specfs/specdev.h>
89:
90: #include <ufs/ufs/inode.h>
91: #include <ufs/ufs/ufs_extern.h>
92: #include <ufs/ufs/ufsmount.h>
93:
94: #include <ufs/ext2fs/ext2fs.h>
95: #include <ufs/ext2fs/ext2fs_extern.h>
96: #include <ufs/ext2fs/ext2fs_dir.h>
97:
1.32 tsutsui 98: extern int prtactive;
1.1 bouyer 99:
1.67 ad 100: static int ext2fs_chmod(struct vnode *, int, kauth_cred_t, struct lwp *);
1.65 elad 101: static int ext2fs_chown(struct vnode *, uid_t, gid_t, kauth_cred_t,
1.67 ad 102: struct lwp *);
1.1 bouyer 103:
104: union _qcvt {
105: int64_t qcvt;
106: int32_t val[2];
107: };
1.61 xtraeme 108:
1.1 bouyer 109: #define SETHIGH(q, h) { \
110: union _qcvt tmp; \
111: tmp.qcvt = (q); \
112: tmp.val[_QUAD_HIGHWORD] = (h); \
113: (q) = tmp.qcvt; \
114: }
115: #define SETLOW(q, l) { \
116: union _qcvt tmp; \
117: tmp.qcvt = (q); \
118: tmp.val[_QUAD_LOWWORD] = (l); \
119: (q) = tmp.qcvt; \
120: }
121:
122: /*
123: * Create a regular file
124: */
125: int
1.61 xtraeme 126: ext2fs_create(void *v)
1.1 bouyer 127: {
1.110 hannken 128: struct vop_create_v3_args /* {
1.1 bouyer 129: struct vnode *a_dvp;
130: struct vnode **a_vpp;
131: struct componentname *a_cnp;
132: struct vattr *a_vap;
133: } */ *ap = v;
1.42 jdolecek 134: int error;
135:
136: error =
137: ext2fs_makeinode(MAKEIMODE(ap->a_vap->va_type, ap->a_vap->va_mode),
138: ap->a_dvp, ap->a_vpp, ap->a_cnp);
139:
140: if (error)
141: return (error);
142: VN_KNOTE(ap->a_dvp, NOTE_WRITE);
1.110 hannken 143: VOP_UNLOCK(*ap->a_vpp);
1.42 jdolecek 144: return (0);
1.1 bouyer 145: }
146:
147: /*
148: * Mknod vnode call
149: */
150: /* ARGSUSED */
151: int
1.61 xtraeme 152: ext2fs_mknod(void *v)
1.1 bouyer 153: {
1.110 hannken 154: struct vop_mknod_v3_args /* {
1.1 bouyer 155: struct vnode *a_dvp;
156: struct vnode **a_vpp;
157: struct componentname *a_cnp;
158: struct vattr *a_vap;
159: } */ *ap = v;
1.25 augustss 160: struct vattr *vap = ap->a_vap;
161: struct vnode **vpp = ap->a_vpp;
162: struct inode *ip;
1.1 bouyer 163: int error;
1.59 perry 164: struct mount *mp;
1.34 assar 165: ino_t ino;
1.1 bouyer 166:
1.8 fvdl 167: if ((error = ext2fs_makeinode(MAKEIMODE(vap->va_type, vap->va_mode),
168: ap->a_dvp, vpp, ap->a_cnp)) != 0)
1.1 bouyer 169: return (error);
1.42 jdolecek 170: VN_KNOTE(ap->a_dvp, NOTE_WRITE);
1.1 bouyer 171: ip = VTOI(*vpp);
1.34 assar 172: mp = (*vpp)->v_mount;
173: ino = ip->i_number;
1.1 bouyer 174: ip->i_flag |= IN_ACCESS | IN_CHANGE | IN_UPDATE;
175: if (vap->va_rdev != VNOVAL) {
176: /*
177: * Want to be able to use this to make badblock
178: * inodes, so don't truncate the dev number.
179: */
1.44 fvdl 180: ip->i_din.e2fs_din->e2di_rdev = h2fs32(vap->va_rdev);
1.1 bouyer 181: }
182: /*
1.112 hannken 183: * Remove inode so that it will be reloaded by vcache_get and
1.1 bouyer 184: * checked to see if it is an alias of an existing entry in
185: * the inode cache.
186: */
1.109 hannken 187: (*vpp)->v_type = VNON;
1.93 hannken 188: VOP_UNLOCK(*vpp);
1.1 bouyer 189: vgone(*vpp);
1.112 hannken 190: error = vcache_get(mp, &ino, sizeof(ino), vpp);
1.34 assar 191: if (error != 0) {
192: *vpp = NULL;
193: return (error);
194: }
1.1 bouyer 195: return (0);
196: }
197:
198: /*
199: * Open called.
200: *
201: * Just check the APPEND flag.
202: */
203: /* ARGSUSED */
204: int
1.61 xtraeme 205: ext2fs_open(void *v)
1.1 bouyer 206: {
207: struct vop_open_args /* {
208: struct vnode *a_vp;
209: int a_mode;
1.65 elad 210: kauth_cred_t a_cred;
1.1 bouyer 211: } */ *ap = v;
212:
213: /*
214: * Files marked append-only must be opened for appending.
215: */
216: if ((VTOI(ap->a_vp)->i_e2fs_flags & EXT2_APPEND) &&
217: (ap->a_mode & (FWRITE | O_APPEND)) == FWRITE)
218: return (EPERM);
219: return (0);
220: }
221:
1.88 elad 222: static int
223: ext2fs_check_possible(struct vnode *vp, struct inode *ip, mode_t mode)
1.1 bouyer 224: {
225:
1.8 fvdl 226: /*
227: * Disallow write attempts on read-only file systems;
228: * unless the file is a socket, fifo, or a block or
229: * character device resident on the file system.
230: */
231: if (mode & VWRITE) {
232: switch (vp->v_type) {
233: case VDIR:
234: case VLNK:
235: case VREG:
236: if (vp->v_mount->mnt_flag & MNT_RDONLY)
237: return (EROFS);
238: break;
239: default:
240: break;
241: }
1.1 bouyer 242: }
243:
244: /* If immutable bit set, nobody gets to write it. */
245: if ((mode & VWRITE) && (ip->i_e2fs_flags & EXT2_IMMUTABLE))
246: return (EPERM);
247:
1.88 elad 248: return 0;
249: }
250:
251: static int
252: ext2fs_check_permitted(struct vnode *vp, struct inode *ip, mode_t mode,
253: kauth_cred_t cred)
254: {
255:
1.107 plunky 256: return kauth_authorize_vnode(cred, KAUTH_ACCESS_ACTION(mode, vp->v_type,
1.102 elad 257: ip->i_e2fs_mode & ALLPERMS), vp, NULL, genfs_can_access(vp->v_type,
258: ip->i_e2fs_mode & ALLPERMS, ip->i_uid, ip->i_gid, mode, cred));
1.88 elad 259: }
260:
261: int
262: ext2fs_access(void *v)
263: {
264: struct vop_access_args /* {
265: struct vnode *a_vp;
266: int a_mode;
267: kauth_cred_t a_cred;
268: } */ *ap = v;
269: struct vnode *vp = ap->a_vp;
270: struct inode *ip = VTOI(vp);
271: mode_t mode = ap->a_mode;
272: int error;
273:
274: error = ext2fs_check_possible(vp, ip, mode);
275: if (error)
276: return error;
277:
278: error = ext2fs_check_permitted(vp, ip, mode, ap->a_cred);
279:
280: return error;
1.1 bouyer 281: }
282:
283: /* ARGSUSED */
284: int
1.61 xtraeme 285: ext2fs_getattr(void *v)
1.1 bouyer 286: {
287: struct vop_getattr_args /* {
288: struct vnode *a_vp;
289: struct vattr *a_vap;
1.65 elad 290: kauth_cred_t a_cred;
1.1 bouyer 291: } */ *ap = v;
1.25 augustss 292: struct vnode *vp = ap->a_vp;
293: struct inode *ip = VTOI(vp);
294: struct vattr *vap = ap->a_vap;
1.1 bouyer 295:
1.62 christos 296: EXT2FS_ITIMES(ip, NULL, NULL, NULL);
1.1 bouyer 297: /*
298: * Copy from inode table
299: */
300: vap->va_fsid = ip->i_dev;
301: vap->va_fileid = ip->i_number;
302: vap->va_mode = ip->i_e2fs_mode & ALLPERMS;
303: vap->va_nlink = ip->i_e2fs_nlink;
1.83 mrg 304: vap->va_uid = ip->i_uid;
305: vap->va_gid = ip->i_gid;
1.44 fvdl 306: vap->va_rdev = (dev_t)fs2h32(ip->i_din.e2fs_din->e2di_rdev);
1.37 chs 307: vap->va_size = vp->v_size;
1.119 jdolecek 308: EXT2_DINODE_TIME_GET(&vap->va_atime, ip->i_din.e2fs_din, e2di_atime, EXT2_DINODE_SIZE(ip->i_e2fs));
309: EXT2_DINODE_TIME_GET(&vap->va_mtime, ip->i_din.e2fs_din, e2di_mtime, EXT2_DINODE_SIZE(ip->i_e2fs));
310: EXT2_DINODE_TIME_GET(&vap->va_ctime, ip->i_din.e2fs_din, e2di_ctime, EXT2_DINODE_SIZE(ip->i_e2fs));
311: if (EXT2_DINODE_FITS(ip->i_din.e2fs_din, e2di_crtime, EXT2_DINODE_SIZE(ip->i_e2fs))) {
312: EXT2_DINODE_TIME_GET(&vap->va_birthtime, ip->i_din.e2fs_din, e2di_crtime, EXT2_DINODE_SIZE(ip->i_e2fs));
313: }
1.120 ! jdolecek 314:
! 315: vap->va_flags = 0;
! 316: vap->va_flags |= (ip->i_e2fs_flags & EXT2_NODUMP) ? UF_NODUMP : 0;
1.1 bouyer 317: #ifdef EXT2FS_SYSTEM_FLAGS
318: vap->va_flags |= (ip->i_e2fs_flags & EXT2_IMMUTABLE) ? SF_IMMUTABLE : 0;
1.120 ! jdolecek 319: vap->va_flags |= (ip->i_e2fs_flags & EXT2_APPEND) ? SF_APPEND : 0;
1.1 bouyer 320: #else
321: vap->va_flags |= (ip->i_e2fs_flags & EXT2_IMMUTABLE) ? UF_IMMUTABLE : 0;
1.120 ! jdolecek 322: vap->va_flags |= (ip->i_e2fs_flags & EXT2_APPEND) ? UF_APPEND : 0;
1.1 bouyer 323: #endif
1.120 ! jdolecek 324:
1.1 bouyer 325: vap->va_gen = ip->i_e2fs_gen;
326: /* this doesn't belong here */
327: if (vp->v_type == VBLK)
328: vap->va_blocksize = BLKDEV_IOSIZE;
329: else if (vp->v_type == VCHR)
330: vap->va_blocksize = MAXBSIZE;
331: else
332: vap->va_blocksize = vp->v_mount->mnt_stat.f_iosize;
1.105 jakllsch 333: vap->va_bytes = dbtob(ext2fs_nblock(ip));
1.1 bouyer 334: vap->va_type = vp->v_type;
335: vap->va_filerev = ip->i_modrev;
336: return (0);
337: }
338:
339: /*
340: * Set attribute vnode op. called from several syscalls
341: */
342: int
1.61 xtraeme 343: ext2fs_setattr(void *v)
1.1 bouyer 344: {
345: struct vop_setattr_args /* {
346: struct vnode *a_vp;
347: struct vattr *a_vap;
1.65 elad 348: kauth_cred_t a_cred;
1.1 bouyer 349: } */ *ap = v;
1.8 fvdl 350: struct vattr *vap = ap->a_vap;
351: struct vnode *vp = ap->a_vp;
352: struct inode *ip = VTOI(vp);
1.65 elad 353: kauth_cred_t cred = ap->a_cred;
1.76 pooka 354: struct lwp *l = curlwp;
1.1 bouyer 355: int error;
1.102 elad 356: kauth_action_t action = KAUTH_VNODE_WRITE_FLAGS;
357: bool changing_sysflags = false;
1.1 bouyer 358:
359: /*
360: * Check for unsettable attributes.
361: */
1.5 christos 362: if ((vap->va_type != VNON) || (vap->va_nlink != (nlink_t)VNOVAL) ||
1.24 thorpej 363: (vap->va_fsid != VNOVAL) || (vap->va_fileid != VNOVAL) ||
364: (vap->va_blocksize != VNOVAL) || (vap->va_rdev != VNOVAL) ||
365: ((int)vap->va_bytes != VNOVAL) || (vap->va_gen != VNOVAL)) {
1.1 bouyer 366: return (EINVAL);
367: }
368: if (vap->va_flags != VNOVAL) {
1.8 fvdl 369: if (vp->v_mount->mnt_flag & MNT_RDONLY)
370: return (EROFS);
1.102 elad 371:
372: /*
373: * Check if we're allowed to change the flags.
374: * If EXT2FS_SYSTEM_FLAGS is set, then the flags are treated
375: * as system flags, otherwise they're considered to be user
376: * flags.
377: */
378: #ifdef EXT2FS_SYSTEM_FLAGS
379: /* Indicate we're changing system flags if we are. */
380: if ((vap->va_flags & SF_APPEND) ||
381: (vap->va_flags & SF_IMMUTABLE)) {
382: action |= KAUTH_VNODE_WRITE_SYSFLAGS;
383: changing_sysflags = true;
384: }
385:
386: /* Indicate the node has system flags if it does. */
387: if (ip->i_e2fs_flags & (EXT2_APPEND | EXT2_IMMUTABLE)) {
388: action |= KAUTH_VNODE_HAS_SYSFLAGS;
389: }
390: #endif /* EXT2FS_SYSTEM_FLAGS */
391:
392: error = kauth_authorize_vnode(cred, action, vp, NULL,
393: genfs_can_chflags(cred, vp->v_type, ip->i_uid,
394: changing_sysflags));
395: if (error)
1.1 bouyer 396: return (error);
1.102 elad 397:
1.120 ! jdolecek 398: ip->i_e2fs_flags &= ~(EXT2_APPEND | EXT2_IMMUTABLE | EXT2_NODUMP);
1.1 bouyer 399: #ifdef EXT2FS_SYSTEM_FLAGS
1.102 elad 400: ip->i_e2fs_flags |=
401: (vap->va_flags & SF_APPEND) ? EXT2_APPEND : 0 |
402: (vap->va_flags & SF_IMMUTABLE) ? EXT2_IMMUTABLE : 0;
1.1 bouyer 403: #else
1.24 thorpej 404: ip->i_e2fs_flags |=
405: (vap->va_flags & UF_APPEND) ? EXT2_APPEND : 0 |
406: (vap->va_flags & UF_IMMUTABLE) ? EXT2_IMMUTABLE : 0;
1.1 bouyer 407: #endif
1.120 ! jdolecek 408: ip->i_e2fs_flags |=
! 409: (vap->va_flags & UF_NODUMP) ? EXT2_NODUMP : 0;
1.1 bouyer 410: ip->i_flag |= IN_CHANGE;
411: if (vap->va_flags & (IMMUTABLE | APPEND))
412: return (0);
413: }
414: if (ip->i_e2fs_flags & (EXT2_APPEND | EXT2_IMMUTABLE))
415: return (EPERM);
416: /*
417: * Go through the fields and update iff not VNOVAL.
418: */
419: if (vap->va_uid != (uid_t)VNOVAL || vap->va_gid != (gid_t)VNOVAL) {
1.8 fvdl 420: if (vp->v_mount->mnt_flag & MNT_RDONLY)
421: return (EROFS);
1.67 ad 422: error = ext2fs_chown(vp, vap->va_uid, vap->va_gid, cred, l);
1.1 bouyer 423: if (error)
424: return (error);
425: }
426: if (vap->va_size != VNOVAL) {
1.8 fvdl 427: /*
428: * Disallow write attempts on read-only file systems;
429: * unless the file is a socket, fifo, or a block or
430: * character device resident on the file system.
431: */
432: switch (vp->v_type) {
433: case VDIR:
1.1 bouyer 434: return (EISDIR);
1.8 fvdl 435: case VLNK:
436: case VREG:
437: if (vp->v_mount->mnt_flag & MNT_RDONLY)
438: return (EROFS);
439: default:
440: break;
441: }
1.77 pooka 442: error = ext2fs_truncate(vp, vap->va_size, 0, cred);
1.1 bouyer 443: if (error)
444: return (error);
445: }
446: ip = VTOI(vp);
1.119 jdolecek 447: if (vap->va_atime.tv_sec != VNOVAL || vap->va_mtime.tv_sec != VNOVAL || vap->va_birthtime.tv_sec != VNOVAL) {
1.8 fvdl 448: if (vp->v_mount->mnt_flag & MNT_RDONLY)
449: return (EROFS);
1.102 elad 450: error = kauth_authorize_vnode(cred, KAUTH_VNODE_WRITE_TIMES, vp,
451: NULL, genfs_can_chtimes(vp, vap->va_vaflags, ip->i_uid,
452: cred));
1.86 elad 453: if (error)
1.1 bouyer 454: return (error);
455: if (vap->va_atime.tv_sec != VNOVAL)
456: if (!(vp->v_mount->mnt_flag & MNT_NOATIME))
457: ip->i_flag |= IN_ACCESS;
1.101 christos 458: if (vap->va_mtime.tv_sec != VNOVAL) {
1.1 bouyer 459: ip->i_flag |= IN_CHANGE | IN_UPDATE;
1.101 christos 460: if (vp->v_mount->mnt_flag & MNT_RELATIME)
461: ip->i_flag |= IN_ACCESS;
462: }
1.119 jdolecek 463: if (vap->va_birthtime.tv_sec != VNOVAL &&
464: EXT2_DINODE_FITS(ip->i_din.e2fs_din, e2di_crtime, EXT2_DINODE_SIZE(ip->i_e2fs))) {
465:
466: EXT2_DINODE_TIME_SET(&vap->va_birthtime, ip->i_din.e2fs_din, e2di_crtime, EXT2_DINODE_SIZE(ip->i_e2fs));
467: }
1.63 yamt 468: error = ext2fs_update(vp, &vap->va_atime, &vap->va_mtime,
1.26 perseant 469: UPDATE_WAIT);
1.1 bouyer 470: if (error)
471: return (error);
472: }
473: error = 0;
1.8 fvdl 474: if (vap->va_mode != (mode_t)VNOVAL) {
475: if (vp->v_mount->mnt_flag & MNT_RDONLY)
476: return (EROFS);
1.67 ad 477: error = ext2fs_chmod(vp, (int)vap->va_mode, cred, l);
1.8 fvdl 478: }
1.42 jdolecek 479: VN_KNOTE(vp, NOTE_ATTRIB);
1.1 bouyer 480: return (error);
481: }
482:
483: /*
484: * Change the mode on a file.
485: * Inode must be locked before calling.
486: */
487: static int
1.67 ad 488: ext2fs_chmod(struct vnode *vp, int mode, kauth_cred_t cred, struct lwp *l)
1.1 bouyer 489: {
1.25 augustss 490: struct inode *ip = VTOI(vp);
1.84 elad 491: int error;
1.1 bouyer 492:
1.102 elad 493: error = kauth_authorize_vnode(cred, KAUTH_VNODE_WRITE_SECURITY, vp,
494: NULL, genfs_can_chmod(vp->v_type, cred, ip->i_uid, ip->i_gid,
495: mode));
1.84 elad 496: if (error)
1.1 bouyer 497: return (error);
1.84 elad 498:
1.1 bouyer 499: ip->i_e2fs_mode &= ~ALLPERMS;
500: ip->i_e2fs_mode |= (mode & ALLPERMS);
501: ip->i_flag |= IN_CHANGE;
502: return (0);
503: }
504:
505: /*
506: * Perform chown operation on inode ip;
507: * inode must be locked prior to call.
508: */
509: static int
1.65 elad 510: ext2fs_chown(struct vnode *vp, uid_t uid, gid_t gid, kauth_cred_t cred,
1.67 ad 511: struct lwp *l)
1.1 bouyer 512: {
1.25 augustss 513: struct inode *ip = VTOI(vp);
1.1 bouyer 514: uid_t ouid;
515: gid_t ogid;
1.84 elad 516: int error;
1.1 bouyer 517:
518: if (uid == (uid_t)VNOVAL)
1.83 mrg 519: uid = ip->i_uid;
1.1 bouyer 520: if (gid == (gid_t)VNOVAL)
1.83 mrg 521: gid = ip->i_gid;
1.84 elad 522:
1.102 elad 523: error = kauth_authorize_vnode(cred, KAUTH_VNODE_CHANGE_OWNERSHIP, vp,
524: NULL, genfs_can_chown(cred, ip->i_uid, ip->i_gid, uid, gid));
1.84 elad 525: if (error)
1.1 bouyer 526: return (error);
1.84 elad 527:
1.83 mrg 528: ogid = ip->i_gid;
529: ouid = ip->i_uid;
1.1 bouyer 530:
1.83 mrg 531: ip->i_e2fs_gid = gid & 0xffff;
532: ip->i_e2fs_uid = uid & 0xffff;
533: if (ip->i_e2fs->e2fs.e2fs_rev > E2FS_REV0) {
534: ip->i_e2fs_gid_high = (gid >> 16) & 0xffff;
535: ip->i_e2fs_uid_high = (uid >> 16) & 0xffff;
536: } else {
537: ip->i_e2fs_gid_high = 0;
538: ip->i_e2fs_uid_high = 0;
539: }
1.91 pooka 540: if (ouid != uid || ogid != gid) {
541: ext2fs_set_inode_guid(ip);
1.1 bouyer 542: ip->i_flag |= IN_CHANGE;
1.91 pooka 543: }
1.102 elad 544: if (ouid != uid && (ip->i_e2fs_mode & ISUID) &&
545: kauth_authorize_vnode(cred, KAUTH_VNODE_RETAIN_SUID,
546: vp, NULL, EPERM) != 0)
1.1 bouyer 547: ip->i_e2fs_mode &= ~ISUID;
1.102 elad 548: if (ogid != gid && (ip->i_e2fs_mode & ISGID) &&
549: kauth_authorize_vnode(cred, KAUTH_VNODE_RETAIN_SGID,
550: vp, NULL, EPERM) != 0)
1.1 bouyer 551: ip->i_e2fs_mode &= ~ISGID;
552: return (0);
553: }
554:
555: int
1.61 xtraeme 556: ext2fs_remove(void *v)
1.1 bouyer 557: {
558: struct vop_remove_args /* {
559: struct vnode *a_dvp;
560: struct vnode *a_vp;
561: struct componentname *a_cnp;
562: } */ *ap = v;
1.8 fvdl 563: struct inode *ip;
564: struct vnode *vp = ap->a_vp;
565: struct vnode *dvp = ap->a_dvp;
1.100 dholland 566: struct ufs_lookup_results *ulr;
1.1 bouyer 567: int error;
568:
1.100 dholland 569: /* XXX should handle this material another way */
570: ulr = &VTOI(dvp)->i_crap;
571: UFS_CHECK_CRAPCOUNTER(VTOI(dvp));
572:
1.1 bouyer 573: ip = VTOI(vp);
1.2 fvdl 574: if (vp->v_type == VDIR ||
575: (ip->i_e2fs_flags & (EXT2_IMMUTABLE | EXT2_APPEND)) ||
1.1 bouyer 576: (VTOI(dvp)->i_e2fs_flags & EXT2_APPEND)) {
577: error = EPERM;
1.43 jdolecek 578: } else {
1.100 dholland 579: error = ext2fs_dirremove(dvp, ulr, ap->a_cnp);
1.43 jdolecek 580: if (error == 0) {
581: ip->i_e2fs_nlink--;
582: ip->i_flag |= IN_CHANGE;
583: }
1.1 bouyer 584: }
1.43 jdolecek 585:
1.42 jdolecek 586: VN_KNOTE(vp, NOTE_DELETE);
587: VN_KNOTE(dvp, NOTE_WRITE);
1.1 bouyer 588: if (dvp == vp)
589: vrele(vp);
590: else
591: vput(vp);
592: vput(dvp);
593: return (error);
594: }
595:
596: /*
1.98 rmind 597: * ext2fs_link: create hard link.
1.1 bouyer 598: */
599: int
1.61 xtraeme 600: ext2fs_link(void *v)
1.1 bouyer 601: {
1.117 riastrad 602: struct vop_link_v2_args /* {
1.1 bouyer 603: struct vnode *a_dvp;
604: struct vnode *a_vp;
605: struct componentname *a_cnp;
606: } */ *ap = v;
1.8 fvdl 607: struct vnode *dvp = ap->a_dvp;
608: struct vnode *vp = ap->a_vp;
609: struct componentname *cnp = ap->a_cnp;
610: struct inode *ip;
1.1 bouyer 611: int error;
1.100 dholland 612: struct ufs_lookup_results *ulr;
1.1 bouyer 613:
1.98 rmind 614: KASSERT(dvp != vp);
615: KASSERT(vp->v_type != VDIR);
616: KASSERT(dvp->v_mount == vp->v_mount);
617:
1.100 dholland 618: /* XXX should handle this material another way */
619: ulr = &VTOI(dvp)->i_crap;
620: UFS_CHECK_CRAPCOUNTER(VTOI(dvp));
621:
1.98 rmind 622: error = vn_lock(vp, LK_EXCLUSIVE);
623: if (error) {
1.1 bouyer 624: VOP_ABORTOP(dvp, cnp);
625: goto out2;
626: }
627: ip = VTOI(vp);
628: if ((nlink_t)ip->i_e2fs_nlink >= LINK_MAX) {
629: VOP_ABORTOP(dvp, cnp);
630: error = EMLINK;
631: goto out1;
632: }
633: if (ip->i_e2fs_flags & (EXT2_IMMUTABLE | EXT2_APPEND)) {
634: VOP_ABORTOP(dvp, cnp);
635: error = EPERM;
636: goto out1;
637: }
638: ip->i_e2fs_nlink++;
639: ip->i_flag |= IN_CHANGE;
1.63 yamt 640: error = ext2fs_update(vp, NULL, NULL, UPDATE_WAIT);
1.1 bouyer 641: if (!error)
1.100 dholland 642: error = ext2fs_direnter(ip, dvp, ulr, cnp);
1.1 bouyer 643: if (error) {
644: ip->i_e2fs_nlink--;
645: ip->i_flag |= IN_CHANGE;
646: }
647: out1:
1.98 rmind 648: VOP_UNLOCK(vp);
1.1 bouyer 649: out2:
1.42 jdolecek 650: VN_KNOTE(vp, NOTE_LINK);
651: VN_KNOTE(dvp, NOTE_WRITE);
1.1 bouyer 652: return (error);
653: }
654:
655: /*
656: * Mkdir system call
657: */
658: int
1.61 xtraeme 659: ext2fs_mkdir(void *v)
1.1 bouyer 660: {
1.110 hannken 661: struct vop_mkdir_v3_args /* {
1.1 bouyer 662: struct vnode *a_dvp;
663: struct vnode **a_vpp;
664: struct componentname *a_cnp;
665: struct vattr *a_vap;
666: } */ *ap = v;
1.55 mycroft 667: struct vnode *dvp = ap->a_dvp;
668: struct vattr *vap = ap->a_vap;
669: struct componentname *cnp = ap->a_cnp;
670: struct inode *ip, *dp = VTOI(dvp);
671: struct vnode *tvp;
1.4 bouyer 672: struct ext2fs_dirtemplate dirtemplate;
1.55 mycroft 673: int error, dmode;
1.100 dholland 674: struct ufs_lookup_results *ulr;
675:
676: /* XXX should handle this material another way */
677: ulr = &VTOI(dvp)->i_crap;
678: UFS_CHECK_CRAPCOUNTER(VTOI(dvp));
1.1 bouyer 679:
680: if ((nlink_t)dp->i_e2fs_nlink >= LINK_MAX) {
681: error = EMLINK;
682: goto out;
683: }
684: dmode = vap->va_mode & ACCESSPERMS;
685: dmode |= IFDIR;
686: /*
687: * Must simulate part of ext2fs_makeinode here to acquire the inode,
688: * but not have it entered in the parent directory. The entry is
689: * made later after writing "." and ".." entries.
690: */
1.63 yamt 691: if ((error = ext2fs_valloc(dvp, dmode, cnp->cn_cred, &tvp)) != 0)
1.1 bouyer 692: goto out;
693: ip = VTOI(tvp);
1.83 mrg 694: ip->i_uid = kauth_cred_geteuid(cnp->cn_cred);
695: ip->i_e2fs_uid = ip->i_uid & 0xffff;
1.1 bouyer 696: ip->i_e2fs_gid = dp->i_e2fs_gid;
1.83 mrg 697: if (ip->i_e2fs->e2fs.e2fs_rev > E2FS_REV0) {
698: ip->i_e2fs_uid_high = (ip->i_uid >> 16) & 0xffff;
699: ip->i_e2fs_gid_high = dp->i_e2fs_gid_high;
700: } else {
701: ip->i_e2fs_uid_high = 0;
702: ip->i_e2fs_gid_high = 0;
703: }
704: ip->i_gid = ip->i_e2fs_gid | (ip->i_e2fs_gid_high << 16);
1.1 bouyer 705: ip->i_flag |= IN_ACCESS | IN_CHANGE | IN_UPDATE;
706: ip->i_e2fs_mode = dmode;
707: tvp->v_type = VDIR; /* Rest init'd in getnewvnode(). */
708: ip->i_e2fs_nlink = 2;
709:
710: /*
711: * Bump link count in parent directory
712: * to reflect work done below. Should
713: * be done before reference is created
714: * so reparation is possible if we crash.
715: */
716: dp->i_e2fs_nlink++;
717: dp->i_flag |= IN_CHANGE;
1.63 yamt 718: if ((error = ext2fs_update(dvp, NULL, NULL, UPDATE_DIROP)) != 0)
1.1 bouyer 719: goto bad;
720:
721: /* Initialize directory with "." and ".." from static template. */
1.13 perry 722: memset(&dirtemplate, 0, sizeof(dirtemplate));
1.4 bouyer 723: dirtemplate.dot_ino = h2fs32(ip->i_number);
724: dirtemplate.dot_reclen = h2fs16(12);
1.22 bouyer 725: dirtemplate.dot_namlen = 1;
726: if (ip->i_e2fs->e2fs.e2fs_rev > E2FS_REV0 &&
727: (ip->i_e2fs->e2fs.e2fs_features_incompat & EXT2F_INCOMPAT_FTYPE)) {
1.23 bouyer 728: dirtemplate.dot_type = EXT2_FT_DIR;
1.22 bouyer 729: }
1.4 bouyer 730: dirtemplate.dot_name[0] = '.';
731: dirtemplate.dotdot_ino = h2fs32(dp->i_number);
732: dirtemplate.dotdot_reclen = h2fs16(VTOI(dvp)->i_e2fs->e2fs_bsize - 12);
1.22 bouyer 733: dirtemplate.dotdot_namlen = 2;
734: if (ip->i_e2fs->e2fs.e2fs_rev > E2FS_REV0 &&
735: (ip->i_e2fs->e2fs.e2fs_features_incompat & EXT2F_INCOMPAT_FTYPE)) {
1.23 bouyer 736: dirtemplate.dotdot_type = EXT2_FT_DIR;
1.22 bouyer 737: }
1.4 bouyer 738: dirtemplate.dotdot_name[0] = dirtemplate.dotdot_name[1] = '.';
1.116 riastrad 739: error = ufs_bufio(UIO_WRITE, tvp, (void *)&dirtemplate,
740: sizeof (dirtemplate), (off_t)0, IO_NODELOCKED|IO_SYNC,
741: cnp->cn_cred, (size_t *)0, NULL);
1.1 bouyer 742: if (error) {
743: dp->i_e2fs_nlink--;
744: dp->i_flag |= IN_CHANGE;
745: goto bad;
746: }
1.55 mycroft 747: if (VTOI(dvp)->i_e2fs->e2fs_bsize > dvp->v_mount->mnt_stat.f_bsize)
1.1 bouyer 748: panic("ext2fs_mkdir: blksize"); /* XXX should grow with balloc() */
749: else {
1.58 ws 750: error = ext2fs_setsize(ip, VTOI(dvp)->i_e2fs->e2fs_bsize);
751: if (error) {
752: dp->i_e2fs_nlink--;
753: dp->i_flag |= IN_CHANGE;
754: goto bad;
755: }
1.1 bouyer 756: ip->i_flag |= IN_CHANGE;
1.60 kml 757: uvm_vnp_setsize(tvp, ext2fs_size(ip));
1.1 bouyer 758: }
759:
1.114 snj 760: /* Directory set up, now install its entry in the parent directory. */
1.100 dholland 761: error = ext2fs_direnter(ip, dvp, ulr, cnp);
1.1 bouyer 762: if (error != 0) {
763: dp->i_e2fs_nlink--;
764: dp->i_flag |= IN_CHANGE;
765: }
766: bad:
767: /*
1.63 yamt 768: * No need to do an explicit ext2fs_truncate here, vrele will do this
1.1 bouyer 769: * for us because we set the link count to 0.
770: */
771: if (error) {
772: ip->i_e2fs_nlink = 0;
773: ip->i_flag |= IN_CHANGE;
774: vput(tvp);
1.42 jdolecek 775: } else {
776: VN_KNOTE(dvp, NOTE_WRITE | NOTE_LINK);
1.110 hannken 777: VOP_UNLOCK(tvp);
1.1 bouyer 778: *ap->a_vpp = tvp;
1.42 jdolecek 779: }
1.1 bouyer 780: out:
781: return (error);
782: }
783:
784: /*
785: * Rmdir system call.
786: */
787: int
1.61 xtraeme 788: ext2fs_rmdir(void *v)
1.1 bouyer 789: {
790: struct vop_rmdir_args /* {
791: struct vnode *a_dvp;
792: struct vnode *a_vp;
793: struct componentname *a_cnp;
794: } */ *ap = v;
1.25 augustss 795: struct vnode *vp = ap->a_vp;
796: struct vnode *dvp = ap->a_dvp;
797: struct componentname *cnp = ap->a_cnp;
798: struct inode *ip, *dp;
1.1 bouyer 799: int error;
1.100 dholland 800: struct ufs_lookup_results *ulr;
1.1 bouyer 801:
802: ip = VTOI(vp);
803: dp = VTOI(dvp);
1.100 dholland 804:
805: /* XXX should handle this material another way */
806: ulr = &dp->i_crap;
807: UFS_CHECK_CRAPCOUNTER(dp);
808:
1.1 bouyer 809: /*
810: * No rmdir "." please.
811: */
812: if (dp == ip) {
813: vrele(dvp);
814: vput(vp);
815: return (EINVAL);
816: }
817: /*
818: * Verify the directory is empty (and valid).
819: * (Rmdir ".." won't be valid since
820: * ".." will contain a reference to
821: * the current directory and thus be
822: * non-empty.)
823: */
824: error = 0;
825: if (ip->i_e2fs_nlink != 2 ||
826: !ext2fs_dirempty(ip, dp->i_number, cnp->cn_cred)) {
827: error = ENOTEMPTY;
828: goto out;
829: }
830: if ((dp->i_e2fs_flags & EXT2_APPEND) ||
831: (ip->i_e2fs_flags & (EXT2_IMMUTABLE | EXT2_APPEND))) {
832: error = EPERM;
833: goto out;
834: }
835: /*
836: * Delete reference to directory before purging
837: * inode. If we crash in between, the directory
838: * will be reattached to lost+found,
839: */
1.100 dholland 840: error = ext2fs_dirremove(dvp, ulr, cnp);
1.1 bouyer 841: if (error != 0)
842: goto out;
843: dp->i_e2fs_nlink--;
844: dp->i_flag |= IN_CHANGE;
1.42 jdolecek 845: VN_KNOTE(dvp, NOTE_WRITE | NOTE_LINK);
1.1 bouyer 846: cache_purge(dvp);
847: vput(dvp);
848: dvp = NULL;
849: /*
850: * Truncate inode. The only stuff left
851: * in the directory is "." and "..". The
852: * "." reference is inconsequential since
853: * we're quashing it. The ".." reference
854: * has already been adjusted above. We've
855: * removed the "." reference and the reference
856: * in the parent directory, but there may be
857: * other hard links so decrement by 2 and
858: * worry about them later.
859: */
860: ip->i_e2fs_nlink -= 2;
1.77 pooka 861: error = ext2fs_truncate(vp, (off_t)0, IO_SYNC, cnp->cn_cred);
1.1 bouyer 862: cache_purge(ITOV(ip));
863: out:
1.42 jdolecek 864: VN_KNOTE(vp, NOTE_DELETE);
1.1 bouyer 865: if (dvp)
866: vput(dvp);
867: vput(vp);
868: return (error);
869: }
870:
871: /*
872: * symlink -- make a symbolic link
873: */
874: int
1.61 xtraeme 875: ext2fs_symlink(void *v)
1.1 bouyer 876: {
1.110 hannken 877: struct vop_symlink_v3_args /* {
1.1 bouyer 878: struct vnode *a_dvp;
879: struct vnode **a_vpp;
880: struct componentname *a_cnp;
881: struct vattr *a_vap;
882: char *a_target;
883: } */ *ap = v;
1.55 mycroft 884: struct vnode *vp, **vpp;
885: struct inode *ip;
886: int len, error;
1.1 bouyer 887:
1.55 mycroft 888: vpp = ap->a_vpp;
1.1 bouyer 889: error = ext2fs_makeinode(IFLNK | ap->a_vap->va_mode, ap->a_dvp,
890: vpp, ap->a_cnp);
891: if (error)
892: return (error);
1.42 jdolecek 893: VN_KNOTE(ap->a_dvp, NOTE_WRITE);
1.1 bouyer 894: vp = *vpp;
895: len = strlen(ap->a_target);
1.55 mycroft 896: ip = VTOI(vp);
897: if (len < ip->i_ump->um_maxsymlinklen) {
1.44 fvdl 898: memcpy((char *)ip->i_din.e2fs_din->e2di_shortlink, ap->a_target, len);
1.58 ws 899: error = ext2fs_setsize(ip, len);
900: if (error)
901: goto bad;
1.1 bouyer 902: ip->i_flag |= IN_CHANGE | IN_UPDATE;
1.101 christos 903: if (vp->v_mount->mnt_flag & MNT_RELATIME)
904: ip->i_flag |= IN_ACCESS;
1.60 kml 905: uvm_vnp_setsize(vp, len);
1.1 bouyer 906: } else
1.116 riastrad 907: error = ufs_bufio(UIO_WRITE, vp, ap->a_target, len, (off_t)0,
908: IO_NODELOCKED, ap->a_cnp->cn_cred, (size_t *)0, NULL);
1.58 ws 909: bad:
1.110 hannken 910: VOP_UNLOCK(vp);
1.34 assar 911: if (error)
1.110 hannken 912: vrele(vp);
1.1 bouyer 913: return (error);
914: }
915:
916: /*
917: * Return target name of a symbolic link
918: */
919: int
1.61 xtraeme 920: ext2fs_readlink(void *v)
1.1 bouyer 921: {
922: struct vop_readlink_args /* {
923: struct vnode *a_vp;
924: struct uio *a_uio;
1.65 elad 925: kauth_cred_t a_cred;
1.1 bouyer 926: } */ *ap = v;
1.55 mycroft 927: struct vnode *vp = ap->a_vp;
928: struct inode *ip = VTOI(vp);
929: struct ufsmount *ump = ip->i_ump;
930: int isize;
1.1 bouyer 931:
1.58 ws 932: isize = ext2fs_size(ip);
1.55 mycroft 933: if (isize < ump->um_maxsymlinklen ||
1.105 jakllsch 934: (ump->um_maxsymlinklen == 0 && ext2fs_nblock(ip) == 0)) {
1.44 fvdl 935: uiomove((char *)ip->i_din.e2fs_din->e2di_shortlink, isize, ap->a_uio);
1.1 bouyer 936: return (0);
937: }
1.116 riastrad 938: return (UFS_BUFRD(vp, ap->a_uio, 0, ap->a_cred));
1.1 bouyer 939: }
940:
941: /*
942: * Advisory record locking support
943: */
944: int
1.61 xtraeme 945: ext2fs_advlock(void *v)
1.1 bouyer 946: {
947: struct vop_advlock_args /* {
948: struct vnode *a_vp;
1.74 christos 949: void * a_id;
1.1 bouyer 950: int a_op;
951: struct flock *a_fl;
952: int a_flags;
953: } */ *ap = v;
1.25 augustss 954: struct inode *ip = VTOI(ap->a_vp);
1.1 bouyer 955:
1.58 ws 956: return lf_advlock(ap, &ip->i_lockf, ext2fs_size(ip));
1.1 bouyer 957: }
958:
1.63 yamt 959: int
960: ext2fs_fsync(void *v)
961: {
962: struct vop_fsync_args /* {
963: struct vnode *a_vp;
1.65 elad 964: kauth_cred_t a_cred;
1.63 yamt 965: int a_flags;
966: off_t offlo;
967: off_t offhi;
968: struct proc *a_p;
969: } */ *ap = v;
970: struct vnode *vp = ap->a_vp;
971: int wait;
972: int error;
973:
974: wait = (ap->a_flags & FSYNC_WAIT) != 0;
1.82 ad 975:
976: if (vp->v_type == VBLK)
1.99 hannken 977: error = spec_fsync(v);
1.63 yamt 978: else
1.103 chs 979: error = vflushbuf(vp, ap->a_flags);
1.99 hannken 980: if (error == 0 && (ap->a_flags & FSYNC_DATAONLY) == 0)
1.63 yamt 981: error = ext2fs_update(vp, NULL, NULL, wait ? UPDATE_WAIT : 0);
982:
983: if (error == 0 && ap->a_flags & FSYNC_CACHE) {
984: int l = 0;
985: error = VOP_IOCTL(VTOI(vp)->i_devvp, DIOCCACHESYNC, &l, FWRITE,
1.76 pooka 986: curlwp->l_cred);
1.63 yamt 987: }
988:
989: return error;
990: }
991:
1.1 bouyer 992: /*
993: * Initialize the vnode associated with a new inode, handle aliased
994: * vnodes.
995: */
996: int
1.61 xtraeme 997: ext2fs_vinit(struct mount *mntp, int (**specops)(void *),
998: int (**fifoops)(void *), struct vnode **vpp)
1.1 bouyer 999: {
1.66 kardel 1000: struct timeval tv;
1.1 bouyer 1001: struct inode *ip;
1.80 ad 1002: struct vnode *vp;
1.1 bouyer 1003:
1004: vp = *vpp;
1005: ip = VTOI(vp);
1006: switch(vp->v_type = IFTOVT(ip->i_e2fs_mode)) {
1007: case VCHR:
1008: case VBLK:
1009: vp->v_op = specops;
1.80 ad 1010: spec_node_init(vp, fs2h32(ip->i_din.e2fs_din->e2di_rdev));
1.1 bouyer 1011: break;
1012: case VFIFO:
1013: vp->v_op = fifoops;
1014: break;
1015: case VNON:
1016: case VBAD:
1017: case VSOCK:
1018: case VLNK:
1019: case VDIR:
1020: case VREG:
1021: break;
1022: }
1.106 dholland 1023: if (ip->i_number == UFS_ROOTINO)
1.75 ad 1024: vp->v_vflag |= VV_ROOT;
1.1 bouyer 1025: /*
1026: * Initialize modrev times
1027: */
1.66 kardel 1028: getmicrouptime(&tv);
1029: SETHIGH(ip->i_modrev, tv.tv_sec);
1030: SETLOW(ip->i_modrev, tv.tv_usec * 4294);
1.1 bouyer 1031: *vpp = vp;
1032: return (0);
1033: }
1034:
1035: /*
1036: * Allocate a new inode.
1037: */
1038: int
1.61 xtraeme 1039: ext2fs_makeinode(int mode, struct vnode *dvp, struct vnode **vpp,
1040: struct componentname *cnp)
1.1 bouyer 1041: {
1.25 augustss 1042: struct inode *ip, *pdir;
1.1 bouyer 1043: struct vnode *tvp;
1.102 elad 1044: int error;
1.100 dholland 1045: struct ufs_lookup_results *ulr;
1.1 bouyer 1046:
1047: pdir = VTOI(dvp);
1.100 dholland 1048:
1049: /* XXX should handle this material another way */
1050: ulr = &pdir->i_crap;
1051: UFS_CHECK_CRAPCOUNTER(pdir);
1052:
1.1 bouyer 1053: *vpp = NULL;
1054: if ((mode & IFMT) == 0)
1055: mode |= IFREG;
1056:
1.63 yamt 1057: if ((error = ext2fs_valloc(dvp, mode, cnp->cn_cred, &tvp)) != 0) {
1.1 bouyer 1058: return (error);
1059: }
1060: ip = VTOI(tvp);
1.83 mrg 1061: ip->i_uid = kauth_cred_geteuid(cnp->cn_cred);
1062: ip->i_e2fs_uid = ip->i_uid & 0xffff;
1.1 bouyer 1063: ip->i_e2fs_gid = pdir->i_e2fs_gid;
1.83 mrg 1064: if (ip->i_e2fs->e2fs.e2fs_rev > E2FS_REV0) {
1065: ip->i_e2fs_uid_high = (ip->i_uid >> 16) & 0xffff;
1066: ip->i_e2fs_gid_high = pdir->i_e2fs_gid_high;
1067: } else {
1068: ip->i_e2fs_uid_high = 0;
1069: ip->i_e2fs_gid_high = 0;
1070: }
1071: ip->i_gid = ip->i_e2fs_gid | (ip->i_e2fs_gid_high << 16);
1.1 bouyer 1072: ip->i_flag |= IN_ACCESS | IN_CHANGE | IN_UPDATE;
1073: ip->i_e2fs_mode = mode;
1074: tvp->v_type = IFTOVT(mode); /* Rest init'd in getnewvnode(). */
1075: ip->i_e2fs_nlink = 1;
1.102 elad 1076:
1077: /* Authorize setting SGID if needed. */
1078: if (ip->i_e2fs_mode & ISGID) {
1079: error = kauth_authorize_vnode(cnp->cn_cred, KAUTH_VNODE_WRITE_SECURITY,
1080: tvp, NULL, genfs_can_chmod(tvp->v_type, cnp->cn_cred, ip->i_uid,
1081: ip->i_gid, mode));
1082: if (error)
1083: ip->i_e2fs_mode &= ~ISGID;
1084: }
1.1 bouyer 1085:
1086: /*
1087: * Make sure inode goes to disk before directory entry.
1088: */
1.63 yamt 1089: if ((error = ext2fs_update(tvp, NULL, NULL, UPDATE_WAIT)) != 0)
1.1 bouyer 1090: goto bad;
1.100 dholland 1091: error = ext2fs_direnter(ip, dvp, ulr, cnp);
1.1 bouyer 1092: if (error != 0)
1093: goto bad;
1094: *vpp = tvp;
1095: return (0);
1096:
1097: bad:
1098: /*
1099: * Write error occurred trying to update the inode
1100: * or the directory so must deallocate the inode.
1101: */
1.50 dsl 1102: tvp->v_type = VNON; /* Stop explosion if VBLK */
1.1 bouyer 1103: ip->i_e2fs_nlink = 0;
1104: ip->i_flag |= IN_CHANGE;
1105: vput(tvp);
1106: return (error);
1107: }
1108:
1109: /*
1110: * Reclaim an inode so that it can be used for other purposes.
1111: */
1112: int
1.61 xtraeme 1113: ext2fs_reclaim(void *v)
1.1 bouyer 1114: {
1115: struct vop_reclaim_args /* {
1116: struct vnode *a_vp;
1117: } */ *ap = v;
1.25 augustss 1118: struct vnode *vp = ap->a_vp;
1.54 mycroft 1119: struct inode *ip = VTOI(vp);
1120: int error;
1.45 fvdl 1121:
1.94 hannken 1122: /*
1123: * The inode must be freed and updated before being removed
1124: * from its hash chain. Other threads trying to gain a hold
1.111 hannken 1125: * or lock on the inode will be stalled.
1.94 hannken 1126: */
1127: if (ip->i_omode == 1 && (vp->v_mount->mnt_flag & MNT_RDONLY) == 0)
1128: ext2fs_vfree(vp, ip->i_number, ip->i_e2fs_mode);
1.76 pooka 1129: if ((error = ufs_reclaim(vp)) != 0)
1.54 mycroft 1130: return (error);
1.45 fvdl 1131: if (ip->i_din.e2fs_din != NULL)
1.118 jdolecek 1132: kmem_free(ip->i_din.e2fs_din, EXT2_DINODE_SIZE(ip->i_e2fs));
1.73 ad 1133: genfs_node_destroy(vp);
1.14 thorpej 1134: pool_put(&ext2fs_inode_pool, vp->v_data);
1.1 bouyer 1135: vp->v_data = NULL;
1136: return (0);
1137: }
1138:
1139: /* Global vfs data structures for ext2fs. */
1.61 xtraeme 1140: int (**ext2fs_vnodeop_p)(void *);
1.31 jdolecek 1141: const struct vnodeopv_entry_desc ext2fs_vnodeop_entries[] = {
1.1 bouyer 1142: { &vop_default_desc, vn_default_error },
1.8 fvdl 1143: { &vop_lookup_desc, ext2fs_lookup }, /* lookup */
1144: { &vop_create_desc, ext2fs_create }, /* create */
1.1 bouyer 1145: { &vop_mknod_desc, ext2fs_mknod }, /* mknod */
1146: { &vop_open_desc, ext2fs_open }, /* open */
1147: { &vop_close_desc, ufs_close }, /* close */
1.8 fvdl 1148: { &vop_access_desc, ext2fs_access }, /* access */
1149: { &vop_getattr_desc, ext2fs_getattr }, /* getattr */
1150: { &vop_setattr_desc, ext2fs_setattr }, /* setattr */
1.1 bouyer 1151: { &vop_read_desc, ext2fs_read }, /* read */
1152: { &vop_write_desc, ext2fs_write }, /* write */
1.113 dholland 1153: { &vop_fallocate_desc, genfs_eopnotsupp }, /* fallocate */
1154: { &vop_fdiscard_desc, genfs_eopnotsupp }, /* fdiscard */
1.1 bouyer 1155: { &vop_ioctl_desc, ufs_ioctl }, /* ioctl */
1.21 wrstuden 1156: { &vop_fcntl_desc, ufs_fcntl }, /* fcntl */
1.1 bouyer 1157: { &vop_poll_desc, ufs_poll }, /* poll */
1.42 jdolecek 1158: { &vop_kqfilter_desc, genfs_kqfilter }, /* kqfilter */
1.8 fvdl 1159: { &vop_revoke_desc, ufs_revoke }, /* revoke */
1.1 bouyer 1160: { &vop_mmap_desc, ufs_mmap }, /* mmap */
1161: { &vop_fsync_desc, ext2fs_fsync }, /* fsync */
1162: { &vop_seek_desc, ufs_seek }, /* seek */
1.8 fvdl 1163: { &vop_remove_desc, ext2fs_remove }, /* remove */
1.1 bouyer 1164: { &vop_link_desc, ext2fs_link }, /* link */
1.8 fvdl 1165: { &vop_rename_desc, ext2fs_rename }, /* rename */
1.1 bouyer 1166: { &vop_mkdir_desc, ext2fs_mkdir }, /* mkdir */
1167: { &vop_rmdir_desc, ext2fs_rmdir }, /* rmdir */
1.8 fvdl 1168: { &vop_symlink_desc, ext2fs_symlink }, /* symlink */
1169: { &vop_readdir_desc, ext2fs_readdir }, /* readdir */
1170: { &vop_readlink_desc, ext2fs_readlink }, /* readlink */
1.1 bouyer 1171: { &vop_abortop_desc, ufs_abortop }, /* abortop */
1.8 fvdl 1172: { &vop_inactive_desc, ext2fs_inactive }, /* inactive */
1173: { &vop_reclaim_desc, ext2fs_reclaim }, /* reclaim */
1.1 bouyer 1174: { &vop_lock_desc, ufs_lock }, /* lock */
1175: { &vop_unlock_desc, ufs_unlock }, /* unlock */
1176: { &vop_bmap_desc, ext2fs_bmap }, /* bmap */
1.8 fvdl 1177: { &vop_strategy_desc, ufs_strategy }, /* strategy */
1.1 bouyer 1178: { &vop_print_desc, ufs_print }, /* print */
1.8 fvdl 1179: { &vop_islocked_desc, ufs_islocked }, /* islocked */
1180: { &vop_pathconf_desc, ufs_pathconf }, /* pathconf */
1181: { &vop_advlock_desc, ext2fs_advlock }, /* advlock */
1.1 bouyer 1182: { &vop_bwrite_desc, vn_bwrite }, /* bwrite */
1.30 chs 1183: { &vop_getpages_desc, genfs_getpages }, /* getpages */
1184: { &vop_putpages_desc, genfs_putpages }, /* putpages */
1185: { NULL, NULL }
1.1 bouyer 1186: };
1.31 jdolecek 1187: const struct vnodeopv_desc ext2fs_vnodeop_opv_desc =
1.1 bouyer 1188: { &ext2fs_vnodeop_p, ext2fs_vnodeop_entries };
1189:
1.61 xtraeme 1190: int (**ext2fs_specop_p)(void *);
1.31 jdolecek 1191: const struct vnodeopv_entry_desc ext2fs_specop_entries[] = {
1.1 bouyer 1192: { &vop_default_desc, vn_default_error },
1193: { &vop_lookup_desc, spec_lookup }, /* lookup */
1194: { &vop_create_desc, spec_create }, /* create */
1195: { &vop_mknod_desc, spec_mknod }, /* mknod */
1196: { &vop_open_desc, spec_open }, /* open */
1197: { &vop_close_desc, ufsspec_close }, /* close */
1.8 fvdl 1198: { &vop_access_desc, ext2fs_access }, /* access */
1199: { &vop_getattr_desc, ext2fs_getattr }, /* getattr */
1200: { &vop_setattr_desc, ext2fs_setattr }, /* setattr */
1.1 bouyer 1201: { &vop_read_desc, ufsspec_read }, /* read */
1202: { &vop_write_desc, ufsspec_write }, /* write */
1.113 dholland 1203: { &vop_fallocate_desc, spec_fallocate }, /* fallocate */
1204: { &vop_fdiscard_desc, spec_fdiscard }, /* fdiscard */
1.1 bouyer 1205: { &vop_ioctl_desc, spec_ioctl }, /* ioctl */
1.21 wrstuden 1206: { &vop_fcntl_desc, ufs_fcntl }, /* fcntl */
1.1 bouyer 1207: { &vop_poll_desc, spec_poll }, /* poll */
1.42 jdolecek 1208: { &vop_kqfilter_desc, spec_kqfilter }, /* kqfilter */
1.8 fvdl 1209: { &vop_revoke_desc, spec_revoke }, /* revoke */
1.1 bouyer 1210: { &vop_mmap_desc, spec_mmap }, /* mmap */
1211: { &vop_fsync_desc, ext2fs_fsync }, /* fsync */
1212: { &vop_seek_desc, spec_seek }, /* seek */
1213: { &vop_remove_desc, spec_remove }, /* remove */
1214: { &vop_link_desc, spec_link }, /* link */
1215: { &vop_rename_desc, spec_rename }, /* rename */
1216: { &vop_mkdir_desc, spec_mkdir }, /* mkdir */
1217: { &vop_rmdir_desc, spec_rmdir }, /* rmdir */
1.8 fvdl 1218: { &vop_symlink_desc, spec_symlink }, /* symlink */
1219: { &vop_readdir_desc, spec_readdir }, /* readdir */
1220: { &vop_readlink_desc, spec_readlink }, /* readlink */
1221: { &vop_abortop_desc, spec_abortop }, /* abortop */
1222: { &vop_inactive_desc, ext2fs_inactive }, /* inactive */
1223: { &vop_reclaim_desc, ext2fs_reclaim }, /* reclaim */
1.1 bouyer 1224: { &vop_lock_desc, ufs_lock }, /* lock */
1225: { &vop_unlock_desc, ufs_unlock }, /* unlock */
1226: { &vop_bmap_desc, spec_bmap }, /* bmap */
1.8 fvdl 1227: { &vop_strategy_desc, spec_strategy }, /* strategy */
1.1 bouyer 1228: { &vop_print_desc, ufs_print }, /* print */
1.8 fvdl 1229: { &vop_islocked_desc, ufs_islocked }, /* islocked */
1230: { &vop_pathconf_desc, spec_pathconf }, /* pathconf */
1231: { &vop_advlock_desc, spec_advlock }, /* advlock */
1.1 bouyer 1232: { &vop_bwrite_desc, vn_bwrite }, /* bwrite */
1.35 chs 1233: { &vop_getpages_desc, spec_getpages }, /* getpages */
1234: { &vop_putpages_desc, spec_putpages }, /* putpages */
1.30 chs 1235: { NULL, NULL }
1.1 bouyer 1236: };
1.31 jdolecek 1237: const struct vnodeopv_desc ext2fs_specop_opv_desc =
1.1 bouyer 1238: { &ext2fs_specop_p, ext2fs_specop_entries };
1239:
1.61 xtraeme 1240: int (**ext2fs_fifoop_p)(void *);
1.31 jdolecek 1241: const struct vnodeopv_entry_desc ext2fs_fifoop_entries[] = {
1.1 bouyer 1242: { &vop_default_desc, vn_default_error },
1.92 pooka 1243: { &vop_lookup_desc, vn_fifo_bypass }, /* lookup */
1244: { &vop_create_desc, vn_fifo_bypass }, /* create */
1245: { &vop_mknod_desc, vn_fifo_bypass }, /* mknod */
1246: { &vop_open_desc, vn_fifo_bypass }, /* open */
1.1 bouyer 1247: { &vop_close_desc, ufsfifo_close }, /* close */
1.8 fvdl 1248: { &vop_access_desc, ext2fs_access }, /* access */
1249: { &vop_getattr_desc, ext2fs_getattr }, /* getattr */
1250: { &vop_setattr_desc, ext2fs_setattr }, /* setattr */
1.1 bouyer 1251: { &vop_read_desc, ufsfifo_read }, /* read */
1252: { &vop_write_desc, ufsfifo_write }, /* write */
1.113 dholland 1253: { &vop_fallocate_desc, vn_fifo_bypass }, /* fallocate */
1254: { &vop_fdiscard_desc, vn_fifo_bypass }, /* fdiscard */
1.92 pooka 1255: { &vop_ioctl_desc, vn_fifo_bypass }, /* ioctl */
1.21 wrstuden 1256: { &vop_fcntl_desc, ufs_fcntl }, /* fcntl */
1.92 pooka 1257: { &vop_poll_desc, vn_fifo_bypass }, /* poll */
1258: { &vop_kqfilter_desc, vn_fifo_bypass }, /* kqfilter */
1259: { &vop_revoke_desc, vn_fifo_bypass }, /* revoke */
1260: { &vop_mmap_desc, vn_fifo_bypass }, /* mmap */
1.1 bouyer 1261: { &vop_fsync_desc, ext2fs_fsync }, /* fsync */
1.92 pooka 1262: { &vop_seek_desc, vn_fifo_bypass }, /* seek */
1263: { &vop_remove_desc, vn_fifo_bypass }, /* remove */
1264: { &vop_link_desc, vn_fifo_bypass }, /* link */
1265: { &vop_rename_desc, vn_fifo_bypass }, /* rename */
1266: { &vop_mkdir_desc, vn_fifo_bypass }, /* mkdir */
1267: { &vop_rmdir_desc, vn_fifo_bypass }, /* rmdir */
1268: { &vop_symlink_desc, vn_fifo_bypass }, /* symlink */
1269: { &vop_readdir_desc, vn_fifo_bypass }, /* readdir */
1270: { &vop_readlink_desc, vn_fifo_bypass }, /* readlink */
1271: { &vop_abortop_desc, vn_fifo_bypass }, /* abortop */
1.8 fvdl 1272: { &vop_inactive_desc, ext2fs_inactive }, /* inactive */
1273: { &vop_reclaim_desc, ext2fs_reclaim }, /* reclaim */
1.1 bouyer 1274: { &vop_lock_desc, ufs_lock }, /* lock */
1275: { &vop_unlock_desc, ufs_unlock }, /* unlock */
1.92 pooka 1276: { &vop_bmap_desc, vn_fifo_bypass }, /* bmap */
1277: { &vop_strategy_desc, vn_fifo_bypass }, /* strategy */
1.1 bouyer 1278: { &vop_print_desc, ufs_print }, /* print */
1.8 fvdl 1279: { &vop_islocked_desc, ufs_islocked }, /* islocked */
1.92 pooka 1280: { &vop_pathconf_desc, vn_fifo_bypass }, /* pathconf */
1281: { &vop_advlock_desc, vn_fifo_bypass }, /* advlock */
1.1 bouyer 1282: { &vop_bwrite_desc, vn_bwrite }, /* bwrite */
1.92 pooka 1283: { &vop_putpages_desc, vn_fifo_bypass }, /* putpages */
1.30 chs 1284: { NULL, NULL }
1.1 bouyer 1285: };
1.31 jdolecek 1286: const struct vnodeopv_desc ext2fs_fifoop_opv_desc =
1.1 bouyer 1287: { &ext2fs_fifoop_p, ext2fs_fifoop_entries };
CVSweb <webmaster@jp.NetBSD.org>