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