]> git.saurik.com Git - apple/xnu.git/blame - bsd/ufs/ufs/ufs_vnops.c
xnu-344.49.tar.gz
[apple/xnu.git] / bsd / ufs / ufs / ufs_vnops.c
CommitLineData
1c79356b
A
1/*
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
43866e37 6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
1c79356b 7 *
43866e37
A
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * file.
14 *
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
1c79356b
A
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
43866e37
A
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
1c79356b
A
22 *
23 * @APPLE_LICENSE_HEADER_END@
24 */
25/* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */
26/*
27 * Copyright (c) 1982, 1986, 1989, 1993, 1995
28 * The Regents of the University of California. All rights reserved.
29 * (c) UNIX System Laboratories, Inc.
30 * All or some portions of this file are derived from material licensed
31 * to the University of California by American Telephone and Telegraph
32 * Co. or Unix System Laboratories, Inc. and are reproduced herein with
33 * the permission of UNIX System Laboratories, Inc.
34 *
35 * Redistribution and use in source and binary forms, with or without
36 * modification, are permitted provided that the following conditions
37 * are met:
38 * 1. Redistributions of source code must retain the above copyright
39 * notice, this list of conditions and the following disclaimer.
40 * 2. Redistributions in binary form must reproduce the above copyright
41 * notice, this list of conditions and the following disclaimer in the
42 * documentation and/or other materials provided with the distribution.
43 * 3. All advertising materials mentioning features or use of this software
44 * must display the following acknowledgement:
45 * This product includes software developed by the University of
46 * California, Berkeley and its contributors.
47 * 4. Neither the name of the University nor the names of its contributors
48 * may be used to endorse or promote products derived from this software
49 * without specific prior written permission.
50 *
51 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
52 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
53 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
54 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
55 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
56 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
57 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
58 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
59 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
60 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
61 * SUCH DAMAGE.
62 *
63 * @(#)ufs_vnops.c 8.27 (Berkeley) 5/27/95
64 */
65
66#include <rev_endian_fs.h>
67#include <sys/param.h>
68#include <sys/systm.h>
69#include <sys/namei.h>
70#include <sys/resourcevar.h>
71#include <sys/kernel.h>
72#include <sys/file.h>
73#include <sys/stat.h>
74#include <sys/buf.h>
75#include <sys/proc.h>
76#include <sys/conf.h>
77#include <sys/mount.h>
78#include <sys/vnode.h>
79#include <sys/malloc.h>
80#include <sys/dirent.h>
81#include <sys/fcntl.h>
82#include <sys/ubc.h>
9bccf70c 83#include <sys/quota.h>
1c79356b
A
84
85#include <kern/thread.h>
86#include <sys/vm.h>
87
88#include <miscfs/specfs/specdev.h>
89
90#include <ufs/ufs/lockf.h>
91#include <ufs/ufs/quota.h>
92#include <ufs/ufs/inode.h>
93#include <ufs/ufs/dir.h>
94#include <ufs/ufs/ufsmount.h>
95#include <ufs/ufs/ufs_extern.h>
96
97#if REV_ENDIAN_FS
98#include <ufs/ufs/ufs_byte_order.h>
99#include <architecture/byte_order.h>
100#endif /* REV_ENDIAN_FS */
101
102static int ufs_chmod __P((struct vnode *, int, struct ucred *, struct proc *));
103static int ufs_chown
104 __P((struct vnode *, uid_t, gid_t, struct ucred *, struct proc *));
105
106union _qcvt {
107 int64_t qcvt;
108 int32_t val[2];
109};
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 */
126int
127ufs_create(ap)
128 struct vop_create_args /* {
129 struct vnode *a_dvp;
130 struct vnode **a_vpp;
131 struct componentname *a_cnp;
132 struct vattr *a_vap;
133 } */ *ap;
134{
135 int error;
136
137 if (error =
138 ufs_makeinode(MAKEIMODE(ap->a_vap->va_type, ap->a_vap->va_mode),
139 ap->a_dvp, ap->a_vpp, ap->a_cnp))
140 return (error);
141 return (0);
142}
143
144/*
145 * Mknod vnode call
146 */
147/* ARGSUSED */
148int
149ufs_mknod(ap)
150 struct vop_mknod_args /* {
151 struct vnode *a_dvp;
152 struct vnode **a_vpp;
153 struct componentname *a_cnp;
154 struct vattr *a_vap;
155 } */ *ap;
156{
157 struct vattr *vap = ap->a_vap;
158 struct vnode **vpp = ap->a_vpp;
159 struct inode *ip;
160 int error;
161
162 if (error =
163 ufs_makeinode(MAKEIMODE(vap->va_type, vap->va_mode),
164 ap->a_dvp, vpp, ap->a_cnp))
165 return (error);
166 ip = VTOI(*vpp);
167 ip->i_flag |= IN_ACCESS | IN_CHANGE | IN_UPDATE;
168 if (vap->va_rdev != VNOVAL) {
169 /*
170 * Want to be able to use this to make badblock
171 * inodes, so don't truncate the dev number.
172 */
173 ip->i_rdev = vap->va_rdev;
174 }
175 /*
176 * Remove inode so that it will be reloaded by VFS_VGET and
177 * checked to see if it is an alias of an existing entry in
178 * the inode cache.
179 */
180 vput(*vpp);
181 (*vpp)->v_type = VNON;
182 vgone(*vpp);
183 *vpp = 0;
184 return (0);
185}
186
187/*
188 * Open called.
189 *
190 * Nothing to do.
191 */
192/* ARGSUSED */
193int
194ufs_open(ap)
195 struct vop_open_args /* {
196 struct vnode *a_vp;
197 int a_mode;
198 struct ucred *a_cred;
199 struct proc *a_p;
200 } */ *ap;
201{
202
203 /*
204 * Files marked append-only must be opened for appending.
205 */
206 if ((VTOI(ap->a_vp)->i_flags & APPEND) &&
207 (ap->a_mode & (FWRITE | O_APPEND)) == FWRITE)
208 return (EPERM);
209 return (0);
210}
211
212/*
213 * Close called.
214 *
215 * Update the times on the inode.
216 */
217/* ARGSUSED */
218int
219ufs_close(ap)
220 struct vop_close_args /* {
221 struct vnode *a_vp;
222 int a_fflag;
223 struct ucred *a_cred;
224 struct proc *a_p;
225 } */ *ap;
226{
227 register struct vnode *vp = ap->a_vp;
228 register struct inode *ip = VTOI(vp);
229
230 simple_lock(&vp->v_interlock);
9bccf70c
A
231 if ((!UBCISVALID(vp) && vp->v_usecount > 1)
232 || (UBCISVALID(vp) && ubc_isinuse(vp, 1)))
1c79356b
A
233 ITIMES(ip, &time, &time);
234 simple_unlock(&vp->v_interlock);
235
236 if (!VOP_ISLOCKED(vp)) {
237 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, ap->a_p);
238
239 cluster_push(vp);
240
241 VOP_UNLOCK(vp, 0, ap->a_p);
242 }
243 return (0);
244}
245
246int
247ufs_access(ap)
248 struct vop_access_args /* {
249 struct vnode *a_vp;
250 int a_mode;
251 struct ucred *a_cred;
252 struct proc *a_p;
253 } */ *ap;
254{
255 struct vnode *vp = ap->a_vp;
256 struct inode *ip = VTOI(vp);
257 struct ucred *cred = ap->a_cred;
258 mode_t mask, mode = ap->a_mode;
259 register gid_t *gp;
260 int i, error;
261
262 /*
263 * Disallow write attempts on read-only file systems;
264 * unless the file is a socket, fifo, or a block or
265 * character device resident on the file system.
266 */
267 if (mode & VWRITE) {
268 switch (vp->v_type) {
269 case VDIR:
270 case VLNK:
271 case VREG:
272 if (vp->v_mount->mnt_flag & MNT_RDONLY)
273 return (EROFS);
274#if QUOTA
275 if (error = getinoquota(ip))
276 return (error);
277#endif
278 break;
279 }
280 }
281
282 /* If immutable bit set, nobody gets to write it. */
283 if ((mode & VWRITE) && (ip->i_flags & IMMUTABLE))
284 return (EPERM);
285
286 /* Otherwise, user id 0 always gets access. */
287 if (cred->cr_uid == 0)
288 return (0);
289
290 mask = 0;
291
292 /* Otherwise, check the owner. */
293 if (cred->cr_uid == ip->i_uid) {
294 if (mode & VEXEC)
295 mask |= S_IXUSR;
296 if (mode & VREAD)
297 mask |= S_IRUSR;
298 if (mode & VWRITE)
299 mask |= S_IWUSR;
300 return ((ip->i_mode & mask) == mask ? 0 : EACCES);
301 }
302
303 /* Otherwise, check the groups. */
304 for (i = 0, gp = cred->cr_groups; i < cred->cr_ngroups; i++, gp++)
305 if (ip->i_gid == *gp) {
306 if (mode & VEXEC)
307 mask |= S_IXGRP;
308 if (mode & VREAD)
309 mask |= S_IRGRP;
310 if (mode & VWRITE)
311 mask |= S_IWGRP;
312 return ((ip->i_mode & mask) == mask ? 0 : EACCES);
313 }
314
315 /* Otherwise, check everyone else. */
316 if (mode & VEXEC)
317 mask |= S_IXOTH;
318 if (mode & VREAD)
319 mask |= S_IROTH;
320 if (mode & VWRITE)
321 mask |= S_IWOTH;
322 return ((ip->i_mode & mask) == mask ? 0 : EACCES);
323}
324
325/* ARGSUSED */
326int
327ufs_getattr(ap)
328 struct vop_getattr_args /* {
329 struct vnode *a_vp;
330 struct vattr *a_vap;
331 struct ucred *a_cred;
332 struct proc *a_p;
333 } */ *ap;
334{
335 register struct vnode *vp = ap->a_vp;
336 register struct inode *ip = VTOI(vp);
337 register struct vattr *vap = ap->a_vap;
338 int devBlockSize=0;
339
340 ITIMES(ip, &time, &time);
341 /*
342 * Copy from inode table
343 */
344 vap->va_fsid = ip->i_dev;
345 vap->va_fileid = ip->i_number;
346 vap->va_mode = ip->i_mode & ~IFMT;
347 vap->va_nlink = ip->i_nlink;
348 vap->va_uid = ip->i_uid;
349 vap->va_gid = ip->i_gid;
350 vap->va_rdev = (dev_t)ip->i_rdev;
351 vap->va_size = ip->i_din.di_size;
352 vap->va_atime.tv_sec = ip->i_atime;
353 vap->va_atime.tv_nsec = ip->i_atimensec;
354 vap->va_mtime.tv_sec = ip->i_mtime;
355 vap->va_mtime.tv_nsec = ip->i_mtimensec;
356 vap->va_ctime.tv_sec = ip->i_ctime;
357 vap->va_ctime.tv_nsec = ip->i_ctimensec;
358 vap->va_flags = ip->i_flags;
359 vap->va_gen = ip->i_gen;
360 /* this doesn't belong here */
361 if (vp->v_type == VBLK)
362 vap->va_blocksize = BLKDEV_IOSIZE;
363 else if (vp->v_type == VCHR)
364 vap->va_blocksize = MAXPHYSIO;
365 else
366 vap->va_blocksize = vp->v_mount->mnt_stat.f_iosize;
367 VOP_DEVBLOCKSIZE(ip->i_devvp, &devBlockSize);
368 vap->va_bytes = dbtob((u_quad_t)ip->i_blocks, devBlockSize);
369 vap->va_type = vp->v_type;
370 vap->va_filerev = ip->i_modrev;
371 return (0);
372}
373
374/*
375 * Set attribute vnode op. called from several syscalls
376 */
377int
378ufs_setattr(ap)
379 struct vop_setattr_args /* {
380 struct vnode *a_vp;
381 struct vattr *a_vap;
382 struct ucred *a_cred;
383 struct proc *a_p;
384 } */ *ap;
385{
386 struct vattr *vap = ap->a_vap;
387 struct vnode *vp = ap->a_vp;
388 struct inode *ip = VTOI(vp);
389 struct ucred *cred = ap->a_cred;
390 struct proc *p = ap->a_p;
391 struct timeval atimeval, mtimeval;
392 int error;
393
394 /*
395 * Check for unsettable attributes.
396 */
397 if ((vap->va_type != VNON) || (vap->va_nlink != VNOVAL) ||
398 (vap->va_fsid != VNOVAL) || (vap->va_fileid != VNOVAL) ||
399 (vap->va_blocksize != VNOVAL) || (vap->va_rdev != VNOVAL) ||
400 ((int)vap->va_bytes != VNOVAL) || (vap->va_gen != VNOVAL)) {
401 return (EINVAL);
402 }
403 if (vap->va_flags != VNOVAL) {
404 if (vp->v_mount->mnt_flag & MNT_RDONLY)
405 return (EROFS);
406 if (cred->cr_uid != ip->i_uid &&
407 (error = suser(cred, &p->p_acflag)))
408 return (error);
409 if (cred->cr_uid == 0) {
410 if ((ip->i_flags & (SF_IMMUTABLE | SF_APPEND)) &&
411 securelevel > 0)
412 return (EPERM);
413 ip->i_flags = vap->va_flags;
414 } else {
415 if (ip->i_flags & (SF_IMMUTABLE | SF_APPEND) ||
416 (vap->va_flags & UF_SETTABLE) != vap->va_flags)
417 return (EPERM);
418 ip->i_flags &= SF_SETTABLE;
419 ip->i_flags |= (vap->va_flags & UF_SETTABLE);
420 }
421 ip->i_flag |= IN_CHANGE;
422 if (vap->va_flags & (IMMUTABLE | APPEND))
423 return (0);
424 }
425 if (ip->i_flags & (IMMUTABLE | APPEND))
426 return (EPERM);
427 /*
428 * Go through the fields and update iff not VNOVAL.
429 */
430 if (vap->va_uid != (uid_t)VNOVAL || vap->va_gid != (gid_t)VNOVAL) {
431 if (vp->v_mount->mnt_flag & MNT_RDONLY)
432 return (EROFS);
433 if (error = ufs_chown(vp, vap->va_uid, vap->va_gid, cred, p))
434 return (error);
435 }
436 if (vap->va_size != VNOVAL) {
437 /*
438 * Disallow write attempts on read-only file systems;
439 * unless the file is a socket, fifo, or a block or
440 * character device resident on the file system.
441 */
442 switch (vp->v_type) {
443 case VDIR:
444 return (EISDIR);
445 case VLNK:
446 case VREG:
447 if (vp->v_mount->mnt_flag & MNT_RDONLY)
448 return (EROFS);
449 break;
450 }
451 if (error = VOP_TRUNCATE(vp, vap->va_size, 0, cred, p))
452 return (error);
453 }
454 ip = VTOI(vp);
455 if (vap->va_atime.tv_sec != VNOVAL || vap->va_mtime.tv_sec != VNOVAL) {
456 if (vp->v_mount->mnt_flag & MNT_RDONLY)
457 return (EROFS);
458 if (cred->cr_uid != ip->i_uid &&
459 (error = suser(cred, &p->p_acflag)) &&
460 ((vap->va_vaflags & VA_UTIMES_NULL) == 0 ||
461 (error = VOP_ACCESS(vp, VWRITE, cred, p))))
462 return (error);
463 if (vap->va_atime.tv_sec != VNOVAL)
464 ip->i_flag |= IN_ACCESS;
465 if (vap->va_mtime.tv_sec != VNOVAL)
466 ip->i_flag |= IN_CHANGE | IN_UPDATE;
467 atimeval.tv_sec = vap->va_atime.tv_sec;
468 atimeval.tv_usec = vap->va_atime.tv_nsec / 1000;
469 mtimeval.tv_sec = vap->va_mtime.tv_sec;
470 mtimeval.tv_usec = vap->va_mtime.tv_nsec / 1000;
471 if (error = VOP_UPDATE(vp, &atimeval, &mtimeval, 1))
472 return (error);
473 }
474 error = 0;
475 if (vap->va_mode != (mode_t)VNOVAL) {
476 if (vp->v_mount->mnt_flag & MNT_RDONLY)
477 return (EROFS);
478 error = ufs_chmod(vp, (int)vap->va_mode, cred, p);
479 }
480 return (error);
481}
482
483/*
484 * Change the mode on a file.
485 * Inode must be locked before calling.
486 */
487static int
488ufs_chmod(vp, mode, cred, p)
489 register struct vnode *vp;
490 register int mode;
491 register struct ucred *cred;
492 struct proc *p;
493{
494 register struct inode *ip = VTOI(vp);
495 int error;
496
497 if (cred->cr_uid != ip->i_uid &&
498 (error = suser(cred, &p->p_acflag)))
499 return (error);
500 if (cred->cr_uid) {
501 if (vp->v_type != VDIR && (mode & S_ISTXT))
502 return (EFTYPE);
503 if (!groupmember(ip->i_gid, cred) && (mode & ISGID))
504 return (EPERM);
505 }
506 ip->i_mode &= ~ALLPERMS;
507 ip->i_mode |= (mode & ALLPERMS);
508 ip->i_flag |= IN_CHANGE;
509 return (0);
510}
511
512/*
513 * Perform chown operation on inode ip;
514 * inode must be locked prior to call.
515 */
516static int
517ufs_chown(vp, uid, gid, cred, p)
518 register struct vnode *vp;
519 uid_t uid;
520 gid_t gid;
521 struct ucred *cred;
522 struct proc *p;
523{
524 register struct inode *ip = VTOI(vp);
525 uid_t ouid;
526 gid_t ogid;
527 int error = 0;
528#if QUOTA
529 register int i;
9bccf70c
A
530 int64_t change; /* in bytes */
531 int devBlockSize=0;
532#endif /* QUOTA */
1c79356b
A
533
534 if (uid == (uid_t)VNOVAL)
535 uid = ip->i_uid;
536 if (gid == (gid_t)VNOVAL)
537 gid = ip->i_gid;
538 /*
539 * If we don't own the file, are trying to change the owner
540 * of the file, or are not a member of the target group,
541 * the caller must be superuser or the call fails.
542 */
543 if ((cred->cr_uid != ip->i_uid || uid != ip->i_uid ||
544 (gid != ip->i_gid && !groupmember((gid_t)gid, cred))) &&
545 (error = suser(cred, &p->p_acflag)))
546 return (error);
547 ogid = ip->i_gid;
548 ouid = ip->i_uid;
549#if QUOTA
550 if (error = getinoquota(ip))
551 return (error);
552 if (ouid == uid) {
553 dqrele(vp, ip->i_dquot[USRQUOTA]);
554 ip->i_dquot[USRQUOTA] = NODQUOT;
555 }
556 if (ogid == gid) {
557 dqrele(vp, ip->i_dquot[GRPQUOTA]);
558 ip->i_dquot[GRPQUOTA] = NODQUOT;
559 }
9bccf70c
A
560 VOP_DEVBLOCKSIZE(ip->i_devvp, &devBlockSize);
561 change = dbtob((int64_t)ip->i_blocks, devBlockSize);
1c79356b
A
562 (void) chkdq(ip, -change, cred, CHOWN);
563 (void) chkiq(ip, -1, cred, CHOWN);
564 for (i = 0; i < MAXQUOTAS; i++) {
565 dqrele(vp, ip->i_dquot[i]);
566 ip->i_dquot[i] = NODQUOT;
567 }
568#endif
569 ip->i_gid = gid;
570 ip->i_uid = uid;
571#if QUOTA
572 if ((error = getinoquota(ip)) == 0) {
573 if (ouid == uid) {
574 dqrele(vp, ip->i_dquot[USRQUOTA]);
575 ip->i_dquot[USRQUOTA] = NODQUOT;
576 }
577 if (ogid == gid) {
578 dqrele(vp, ip->i_dquot[GRPQUOTA]);
579 ip->i_dquot[GRPQUOTA] = NODQUOT;
580 }
581 if ((error = chkdq(ip, change, cred, CHOWN)) == 0) {
582 if ((error = chkiq(ip, 1, cred, CHOWN)) == 0)
583 goto good;
584 else
585 (void) chkdq(ip, -change, cred, CHOWN|FORCE);
586 }
587 for (i = 0; i < MAXQUOTAS; i++) {
588 dqrele(vp, ip->i_dquot[i]);
589 ip->i_dquot[i] = NODQUOT;
590 }
591 }
592 ip->i_gid = ogid;
593 ip->i_uid = ouid;
594 if (getinoquota(ip) == 0) {
595 if (ouid == uid) {
596 dqrele(vp, ip->i_dquot[USRQUOTA]);
597 ip->i_dquot[USRQUOTA] = NODQUOT;
598 }
599 if (ogid == gid) {
600 dqrele(vp, ip->i_dquot[GRPQUOTA]);
601 ip->i_dquot[GRPQUOTA] = NODQUOT;
602 }
603 (void) chkdq(ip, change, cred, FORCE|CHOWN);
604 (void) chkiq(ip, 1, cred, FORCE|CHOWN);
605 (void) getinoquota(ip);
606 }
607 return (error);
608good:
609 if (getinoquota(ip))
610 panic("chown: lost quota");
611#endif /* QUOTA */
612 if (ouid != uid || ogid != gid)
613 ip->i_flag |= IN_CHANGE;
614 if (ouid != uid && cred->cr_uid != 0)
615 ip->i_mode &= ~ISUID;
616 if (ogid != gid && cred->cr_uid != 0)
617 ip->i_mode &= ~ISGID;
618 return (0);
619}
620
621/* ARGSUSED */
622int
623ufs_ioctl(ap)
624 struct vop_ioctl_args /* {
625 struct vnode *a_vp;
626 int a_command;
627 caddr_t a_data;
628 int a_fflag;
629 struct ucred *a_cred;
630 struct proc *a_p;
631 } */ *ap;
632{
633
634 switch (ap->a_command) {
635
636 case 1:
637 { register struct inode *ip;
638 register struct vnode *vp;
639 register struct fs *fs;
640 register struct radvisory *ra;
641 int devBlockSize = 0;
642 int error;
643
644 vp = ap->a_vp;
645
646 VOP_LEASE(vp, ap->a_p, ap->a_cred, LEASE_READ);
647 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, ap->a_p);
648
649 ra = (struct radvisory *)(ap->a_data);
650 ip = VTOI(vp);
651 fs = ip->i_fs;
652
653 if ((u_int64_t)ra->ra_offset >= ip->i_size) {
654 VOP_UNLOCK(vp, 0, ap->a_p);
655 return (EFBIG);
656 }
657 VOP_DEVBLOCKSIZE(ip->i_devvp, &devBlockSize);
658
659 error = advisory_read(vp, ip->i_size, ra->ra_offset, ra->ra_count, devBlockSize);
660 VOP_UNLOCK(vp, 0, ap->a_p);
661 return (error);
662 }
663 default:
664 return (ENOTTY);
665 }
666}
667
668/* ARGSUSED */
669int
670ufs_select(ap)
671 struct vop_select_args /* {
672 struct vnode *a_vp;
673 int a_which;
674 int a_fflags;
675 struct ucred *a_cred;
0b4e3aa0 676 void *a_wql;
1c79356b
A
677 struct proc *a_p;
678 } */ *ap;
679{
680
681 /*
682 * We should really check to see if I/O is possible.
683 */
684 return (1);
685}
686
687/*
688 * Mmap a file
689 *
690 * NB Currently unsupported.
691 */
692/* ARGSUSED */
693int
694ufs_mmap(ap)
695 struct vop_mmap_args /* {
696 struct vnode *a_vp;
697 int a_fflags;
698 struct ucred *a_cred;
699 struct proc *a_p;
700 } */ *ap;
701{
702
703 return (EINVAL);
704}
705
706/*
707 * Seek on a file
708 *
709 * Nothing to do, so just return.
710 */
711/* ARGSUSED */
712int
713ufs_seek(ap)
714 struct vop_seek_args /* {
715 struct vnode *a_vp;
716 off_t a_oldoff;
717 off_t a_newoff;
718 struct ucred *a_cred;
719 } */ *ap;
720{
721
722 return (0);
723}
724
725int
726ufs_remove(ap)
727 struct vop_remove_args /* {
728 struct vnode *a_dvp;
729 struct vnode *a_vp;
730 struct componentname *a_cnp;
731 } */ *ap;
732{
733 struct inode *ip;
734 struct vnode *vp = ap->a_vp;
735 struct vnode *dvp = ap->a_dvp;
736 int error;
737
738 ip = VTOI(vp);
739 if ((ip->i_flags & (IMMUTABLE | APPEND)) ||
740 (VTOI(dvp)->i_flags & APPEND)) {
741 error = EPERM;
742 goto out;
743 }
9bccf70c
A
744
745 if (ap->a_cnp->cn_flags & NODELETEBUSY) {
746 /* Caller requested Carbon delete semantics */
747 if ((!UBCISVALID(vp) && vp->v_usecount > 1)
748 || (UBCISVALID(vp) && ubc_isinuse(vp, 1))) {
749 error = EBUSY;
750 goto out;
751 }
1c79356b 752 }
9bccf70c 753
1c79356b
A
754 if ((error = ufs_dirremove(dvp, ap->a_cnp)) == 0) {
755 ip->i_nlink--;
756 ip->i_flag |= IN_CHANGE;
757 }
758
0b4e3aa0
A
759 if (dvp != vp)
760 VOP_UNLOCK(vp, 0, ap->a_cnp->cn_proc);
1c79356b 761
0b4e3aa0
A
762 (void) ubc_uncache(vp);
763
764 vrele(vp);
765 vput(dvp);
1c79356b
A
766
767 return (error);
768
769out:
770 if (dvp == vp)
771 vrele(vp);
772 else
773 vput(vp);
774 vput(dvp);
775 return (error);
776}
777
778/*
779 * link vnode call
780 */
781int
782ufs_link(ap)
783 struct vop_link_args /* {
784 struct vnode *a_vp;
785 struct vnode *a_tdvp;
786 struct componentname *a_cnp;
787 } */ *ap;
788{
789 struct vnode *vp = ap->a_vp;
790 struct vnode *tdvp = ap->a_tdvp;
791 struct componentname *cnp = ap->a_cnp;
792 struct proc *p = cnp->cn_proc;
793 struct inode *ip;
794 struct timeval tv;
795 int error;
796
797#if DIAGNOSTIC
798 if ((cnp->cn_flags & HASBUF) == 0)
799 panic("ufs_link: no name");
800#endif
801 if (tdvp->v_mount != vp->v_mount) {
802 VOP_ABORTOP(tdvp, cnp);
803 error = EXDEV;
804 goto out2;
805 }
806 if (tdvp != vp && (error = vn_lock(vp, LK_EXCLUSIVE, p))) {
807 VOP_ABORTOP(tdvp, cnp);
808 goto out2;
809 }
810 ip = VTOI(vp);
811 if ((nlink_t)ip->i_nlink >= LINK_MAX) {
812 VOP_ABORTOP(tdvp, cnp);
813 error = EMLINK;
814 goto out1;
815 }
816 if (ip->i_flags & (IMMUTABLE | APPEND)) {
817 VOP_ABORTOP(tdvp, cnp);
818 error = EPERM;
819 goto out1;
820 }
821 ip->i_nlink++;
822 ip->i_flag |= IN_CHANGE;
823 tv = time;
824 error = VOP_UPDATE(vp, &tv, &tv, 1);
825 if (!error)
826 error = ufs_direnter(ip, tdvp, cnp);
827 if (error) {
828 ip->i_nlink--;
829 ip->i_flag |= IN_CHANGE;
830 }
831 FREE_ZONE(cnp->cn_pnbuf, cnp->cn_pnlen, M_NAMEI);
832out1:
833 if (tdvp != vp)
834 VOP_UNLOCK(vp, 0, p);
835out2:
836 vput(tdvp);
837 return (error);
838}
839
840/*
841 * whiteout vnode call
842 */
843int
844ufs_whiteout(ap)
845 struct vop_whiteout_args /* {
846 struct vnode *a_dvp;
847 struct componentname *a_cnp;
848 int a_flags;
849 } */ *ap;
850{
851 struct vnode *dvp = ap->a_dvp;
852 struct componentname *cnp = ap->a_cnp;
853 struct direct newdir;
854 int error;
855
856 switch (ap->a_flags) {
857 case LOOKUP:
858 /* 4.4 format directories support whiteout operations */
859 if (dvp->v_mount->mnt_maxsymlinklen > 0)
860 return (0);
861 return (EOPNOTSUPP);
862
863 case CREATE:
864 /* create a new directory whiteout */
865#if DIAGNOSTIC
866 if ((cnp->cn_flags & SAVENAME) == 0)
867 panic("ufs_whiteout: missing name");
868 if (dvp->v_mount->mnt_maxsymlinklen <= 0)
869 panic("ufs_whiteout: old format filesystem");
870#endif
871
872 newdir.d_ino = WINO;
873 newdir.d_namlen = cnp->cn_namelen;
874 bcopy(cnp->cn_nameptr, newdir.d_name, (unsigned)cnp->cn_namelen + 1);
875 newdir.d_type = DT_WHT;
876 error = ufs_direnter2(dvp, &newdir, cnp->cn_cred, cnp->cn_proc);
877 break;
878
879 case DELETE:
880 /* remove an existing directory whiteout */
881#if DIAGNOSTIC
882 if (dvp->v_mount->mnt_maxsymlinklen <= 0)
883 panic("ufs_whiteout: old format filesystem");
884#endif
885
886 cnp->cn_flags &= ~DOWHITEOUT;
887 error = ufs_dirremove(dvp, cnp);
888 break;
889 }
890 if (cnp->cn_flags & HASBUF) {
891 FREE_ZONE(cnp->cn_pnbuf, cnp->cn_pnlen, M_NAMEI);
892 cnp->cn_flags &= ~HASBUF;
893 }
894 return (error);
895}
896
897
898/*
899 * Rename system call.
900 * rename("foo", "bar");
901 * is essentially
902 * unlink("bar");
903 * link("foo", "bar");
904 * unlink("foo");
905 * but ``atomically''. Can't do full commit without saving state in the
906 * inode on disk which isn't feasible at this time. Best we can do is
907 * always guarantee the target exists.
908 *
909 * Basic algorithm is:
910 *
911 * 1) Bump link count on source while we're linking it to the
912 * target. This also ensure the inode won't be deleted out
913 * from underneath us while we work (it may be truncated by
914 * a concurrent `trunc' or `open' for creation).
915 * 2) Link source to destination. If destination already exists,
916 * delete it first.
917 * 3) Unlink source reference to inode if still around. If a
918 * directory was moved and the parent of the destination
919 * is different from the source, patch the ".." entry in the
920 * directory.
921 */
922int
923ufs_rename(ap)
924 struct vop_rename_args /* {
925 struct vnode *a_fdvp;
926 struct vnode *a_fvp;
927 struct componentname *a_fcnp;
928 struct vnode *a_tdvp;
929 struct vnode *a_tvp;
930 struct componentname *a_tcnp;
931 } */ *ap;
932{
933 struct vnode *tvp = ap->a_tvp;
934 register struct vnode *tdvp = ap->a_tdvp;
935 struct vnode *fvp = ap->a_fvp;
936 struct vnode *fdvp = ap->a_fdvp;
937 struct componentname *tcnp = ap->a_tcnp;
938 struct componentname *fcnp = ap->a_fcnp;
939 struct proc *p = fcnp->cn_proc;
940 struct inode *ip, *xp, *dp;
941 struct dirtemplate dirbuf;
942 struct timeval tv;
943 int doingdirectory = 0, oldparent = 0, newparent = 0;
944 int error = 0;
945 u_char namlen;
946
947#if DIAGNOSTIC
948 if ((tcnp->cn_flags & HASBUF) == 0 ||
949 (fcnp->cn_flags & HASBUF) == 0)
950 panic("ufs_rename: no name");
951#endif
952 /*
953 * Check for cross-device rename.
954 */
955 if ((fvp->v_mount != tdvp->v_mount) ||
956 (tvp && (fvp->v_mount != tvp->v_mount))) {
957 error = EXDEV;
958abortit:
959 VOP_ABORTOP(tdvp, tcnp); /* XXX, why not in NFS? */
960 if (tdvp == tvp)
961 vrele(tdvp);
962 else
963 vput(tdvp);
964 if (tvp)
965 vput(tvp);
966 VOP_ABORTOP(fdvp, fcnp); /* XXX, why not in NFS? */
967 vrele(fdvp);
968 vrele(fvp);
969 return (error);
970 }
971
972 /*
973 * Check if just deleting a link name.
974 */
975 if (tvp && ((VTOI(tvp)->i_flags & (IMMUTABLE | APPEND)) ||
976 (VTOI(tdvp)->i_flags & APPEND))) {
977 error = EPERM;
978 goto abortit;
979 }
980 if (fvp == tvp) {
981 if (fvp->v_type == VDIR) {
982 error = EINVAL;
983 goto abortit;
984 }
985
986 /* Release destination completely. */
987 VOP_ABORTOP(tdvp, tcnp);
988 vput(tdvp);
989 vput(tvp);
990
991 /* Delete source. */
992 vrele(fdvp);
993 vrele(fvp);
994 fcnp->cn_flags &= ~MODMASK;
995 fcnp->cn_flags |= LOCKPARENT | LOCKLEAF;
996 if ((fcnp->cn_flags & SAVESTART) == 0)
997 panic("ufs_rename: lost from startdir");
998 fcnp->cn_nameiop = DELETE;
999 (void) relookup(fdvp, &fvp, fcnp);
1000 return (VOP_REMOVE(fdvp, fvp, fcnp));
1001 }
1002 if (error = vn_lock(fvp, LK_EXCLUSIVE, p))
1003 goto abortit;
1004 dp = VTOI(fdvp);
1005 ip = VTOI(fvp);
1006 if ((ip->i_flags & (IMMUTABLE | APPEND)) || (dp->i_flags & APPEND)) {
1007 VOP_UNLOCK(fvp, 0, p);
1008 error = EPERM;
1009 goto abortit;
1010 }
1011 if ((ip->i_mode & IFMT) == IFDIR) {
1012 /*
1013 * Avoid ".", "..", and aliases of "." for obvious reasons.
1014 */
1015 if ((fcnp->cn_namelen == 1 && fcnp->cn_nameptr[0] == '.') ||
1016 dp == ip || (fcnp->cn_flags&ISDOTDOT) ||
1017 (ip->i_flag & IN_RENAME)) {
1018 VOP_UNLOCK(fvp, 0, p);
1019 error = EINVAL;
1020 goto abortit;
1021 }
1022 ip->i_flag |= IN_RENAME;
1023 oldparent = dp->i_number;
1024 doingdirectory++;
1025 }
1026 vrele(fdvp);
1027
1028 /*
1029 * When the target exists, both the directory
1030 * and target vnodes are returned locked.
1031 */
1032 dp = VTOI(tdvp);
1033 xp = NULL;
1034 if (tvp)
1035 xp = VTOI(tvp);
1036
1037 /*
1038 * 1) Bump link count while we're moving stuff
1039 * around. If we crash somewhere before
1040 * completing our work, the link count
1041 * may be wrong, but correctable.
1042 */
1043 ip->i_nlink++;
1044 ip->i_flag |= IN_CHANGE;
1045 tv = time;
1046 if (error = VOP_UPDATE(fvp, &tv, &tv, 1)) {
1047 VOP_UNLOCK(fvp, 0, p);
1048 goto bad;
1049 }
1050
1051 /*
1052 * If ".." must be changed (ie the directory gets a new
1053 * parent) then the source directory must not be in the
1054 * directory heirarchy above the target, as this would
1055 * orphan everything below the source directory. Also
1056 * the user must have write permission in the source so
1057 * as to be able to change "..". We must repeat the call
1058 * to namei, as the parent directory is unlocked by the
1059 * call to checkpath().
1060 */
1061 error = VOP_ACCESS(fvp, VWRITE, tcnp->cn_cred, tcnp->cn_proc);
1062 VOP_UNLOCK(fvp, 0, p);
1063 if (oldparent != dp->i_number)
1064 newparent = dp->i_number;
1065 if (doingdirectory && newparent) {
1066 if (error) /* write access check above */
1067 goto bad;
1068 if (xp != NULL)
1069 vput(tvp);
1070 if (error = ufs_checkpath(ip, dp, tcnp->cn_cred))
1071 goto out;
1072 if ((tcnp->cn_flags & SAVESTART) == 0)
1073 panic("ufs_rename: lost to startdir");
1074 if (error = relookup(tdvp, &tvp, tcnp))
1075 goto out;
1076 dp = VTOI(tdvp);
1077 xp = NULL;
1078 if (tvp)
1079 xp = VTOI(tvp);
1080 }
1081 /*
1082 * 2) If target doesn't exist, link the target
1083 * to the source and unlink the source.
1084 * Otherwise, rewrite the target directory
1085 * entry to reference the source inode and
1086 * expunge the original entry's existence.
1087 */
1088 if (xp == NULL) {
1089 if (dp->i_dev != ip->i_dev)
1090 panic("rename: EXDEV");
1091 /*
1092 * Account for ".." in new directory.
1093 * When source and destination have the same
1094 * parent we don't fool with the link count.
1095 */
1096 if (doingdirectory && newparent) {
1097 if ((nlink_t)dp->i_nlink >= LINK_MAX) {
1098 error = EMLINK;
1099 goto bad;
1100 }
1101 dp->i_nlink++;
1102 dp->i_flag |= IN_CHANGE;
1103 if (error = VOP_UPDATE(tdvp, &tv, &tv, 1))
1104 goto bad;
1105 }
1106 if (error = ufs_direnter(ip, tdvp, tcnp)) {
1107 if (doingdirectory && newparent) {
1108 dp->i_nlink--;
1109 dp->i_flag |= IN_CHANGE;
1110 (void)VOP_UPDATE(tdvp, &tv, &tv, 1);
1111 }
1112 goto bad;
1113 }
1114 vput(tdvp);
1115 } else {
1116 if (xp->i_dev != dp->i_dev || xp->i_dev != ip->i_dev)
1117 panic("rename: EXDEV");
1118 /*
1119 * Short circuit rename(foo, foo).
1120 */
1121 if (xp->i_number == ip->i_number)
1122 panic("rename: same file");
1123 /*
1124 * If the parent directory is "sticky", then the user must
1125 * own the parent directory, or the destination of the rename,
1126 * otherwise the destination may not be changed (except by
1127 * root). This implements append-only directories.
1128 */
1129 if ((dp->i_mode & S_ISTXT) && tcnp->cn_cred->cr_uid != 0 &&
1130 tcnp->cn_cred->cr_uid != dp->i_uid &&
1131 xp->i_uid != tcnp->cn_cred->cr_uid) {
1132 error = EPERM;
1133 goto bad;
1134 }
1135 /*
1136 * Target must be empty if a directory and have no links
1137 * to it. Also, ensure source and target are compatible
1138 * (both directories, or both not directories).
1139 */
1140 if ((xp->i_mode&IFMT) == IFDIR) {
1141 if (!ufs_dirempty(xp, dp->i_number, tcnp->cn_cred) ||
1142 xp->i_nlink > 2) {
1143 error = ENOTEMPTY;
1144 goto bad;
1145 }
1146 if (!doingdirectory) {
1147 error = ENOTDIR;
1148 goto bad;
1149 }
1150 cache_purge(tdvp);
1151 } else if (doingdirectory) {
1152 error = EISDIR;
1153 goto bad;
1154 }
1155 if (error = ufs_dirrewrite(dp, ip, tcnp))
1156 goto bad;
1157 /*
1158 * If the target directory is in the same
1159 * directory as the source directory,
1160 * decrement the link count on the parent
1161 * of the target directory.
1162 */
1163 if (doingdirectory && !newparent) {
1164 dp->i_nlink--;
1165 dp->i_flag |= IN_CHANGE;
1166 }
1167 vput(tdvp);
1168 /*
1169 * Adjust the link count of the target to
1170 * reflect the dirrewrite above. If this is
1171 * a directory it is empty and there are
1172 * no links to it, so we can squash the inode and
1173 * any space associated with it. We disallowed
1174 * renaming over top of a directory with links to
1175 * it above, as the remaining link would point to
1176 * a directory without "." or ".." entries.
1177 */
1178 xp->i_nlink--;
1179 if (doingdirectory) {
1180 if (--xp->i_nlink != 0)
1181 panic("rename: linked directory");
1182 error = VOP_TRUNCATE(tvp, (off_t)0, IO_SYNC,
1183 tcnp->cn_cred, tcnp->cn_proc);
1184 }
1185 xp->i_flag |= IN_CHANGE;
1186 vput(tvp);
1187 xp = NULL;
1188 }
1189
1190 /*
1191 * 3) Unlink the source.
1192 */
1193 fcnp->cn_flags &= ~MODMASK;
1194 fcnp->cn_flags |= LOCKPARENT | LOCKLEAF;
1195 if ((fcnp->cn_flags & SAVESTART) == 0)
1196 panic("ufs_rename: lost from startdir");
1197 (void) relookup(fdvp, &fvp, fcnp);
1198 if (fvp != NULL) {
1199 xp = VTOI(fvp);
1200 dp = VTOI(fdvp);
1201 } else {
1202 /*
1203 * From name has disappeared.
1204 */
1205 if (doingdirectory)
1206 panic("rename: lost dir entry");
1207 vrele(ap->a_fvp);
1208 return (0);
1209 }
1210 /*
1211 * Ensure that the directory entry still exists and has not
1212 * changed while the new name has been entered. If the source is
1213 * a file then the entry may have been unlinked or renamed. In
1214 * either case there is no further work to be done. If the source
1215 * is a directory then it cannot have been rmdir'ed; its link
1216 * count of three would cause a rmdir to fail with ENOTEMPTY.
1217 * The IRENAME flag ensures that it cannot be moved by another
1218 * rename.
1219 */
1220 if (xp != ip) {
1221 if (doingdirectory)
1222 panic("rename: lost dir entry");
1223 } else {
1224 /*
1225 * If the source is a directory with a
1226 * new parent, the link count of the old
1227 * parent directory must be decremented
1228 * and ".." set to point to the new parent.
1229 */
1230 if (doingdirectory && newparent) {
1231 dp->i_nlink--;
1232 dp->i_flag |= IN_CHANGE;
1233 error = vn_rdwr(UIO_READ, fvp, (caddr_t)&dirbuf,
1234 sizeof (struct dirtemplate), (off_t)0,
1235 UIO_SYSSPACE, IO_NODELOCKED,
1236 tcnp->cn_cred, (int *)0, (struct proc *)0);
1237 if (error == 0) {
1238# if (BYTE_ORDER == LITTLE_ENDIAN)
1239 if (fvp->v_mount->mnt_maxsymlinklen <= 0)
1240 namlen = dirbuf.dotdot_type;
1241 else
1242 namlen = dirbuf.dotdot_namlen;
1243# else
1244 namlen = dirbuf.dotdot_namlen;
1245# endif
1246 if (namlen != 2 ||
1247 dirbuf.dotdot_name[0] != '.' ||
1248 dirbuf.dotdot_name[1] != '.') {
1249 ufs_dirbad(xp, (doff_t)12,
1250 "rename: mangled dir");
1251 } else {
1252 dirbuf.dotdot_ino = newparent;
1253 (void) vn_rdwr(UIO_WRITE, fvp,
1254 (caddr_t)&dirbuf,
1255 sizeof (struct dirtemplate),
1256 (off_t)0, UIO_SYSSPACE,
1257 IO_NODELOCKED|IO_SYNC,
1258 tcnp->cn_cred, (int *)0,
1259 (struct proc *)0);
1260 cache_purge(fdvp);
1261 }
1262 }
1263 }
1264 error = ufs_dirremove(fdvp, fcnp);
1265 if (!error) {
1266 xp->i_nlink--;
1267 xp->i_flag |= IN_CHANGE;
1268 }
1269 xp->i_flag &= ~IN_RENAME;
1270 }
1271 if (dp)
1272 vput(fdvp);
1273 if (xp)
1274 vput(fvp);
1275 vrele(ap->a_fvp);
1276 return (error);
1277
1278bad:
1279 if (xp)
1280 vput(ITOV(xp));
1281 vput(ITOV(dp));
1282out:
1283 if (doingdirectory)
1284 ip->i_flag &= ~IN_RENAME;
1285 if (vn_lock(fvp, LK_EXCLUSIVE, p) == 0) {
1286 ip->i_nlink--;
1287 ip->i_flag |= IN_CHANGE;
1288 vput(fvp);
1289 } else
1290 vrele(fvp);
1291 return (error);
1292}
1293
1294/*
1295 * A virgin directory (no blushing please).
1296 */
1297static struct dirtemplate mastertemplate = {
1298 0, 12, DT_DIR, 1, ".",
1299 0, DIRBLKSIZ - 12, DT_DIR, 2, ".."
1300};
1301static struct odirtemplate omastertemplate = {
1302 0, 12, 1, ".",
1303 0, DIRBLKSIZ - 12, 2, ".."
1304};
1305
1306/*
1307 * Mkdir system call
1308 */
1309int
1310ufs_mkdir(ap)
1311 struct vop_mkdir_args /* {
1312 struct vnode *a_dvp;
1313 struct vnode **a_vpp;
1314 struct componentname *a_cnp;
1315 struct vattr *a_vap;
1316 } */ *ap;
1317{
1318 register struct vnode *dvp = ap->a_dvp;
1319 register struct vattr *vap = ap->a_vap;
1320 register struct componentname *cnp = ap->a_cnp;
1321 register struct inode *ip, *dp;
1322 struct vnode *tvp;
1323 struct dirtemplate dirtemplate, *dtp;
1324 struct timeval tv;
1325 int error, dmode;
1326
1327#if DIAGNOSTIC
1328 if ((cnp->cn_flags & HASBUF) == 0)
1329 panic("ufs_mkdir: no name");
1330#endif
1331 dp = VTOI(dvp);
1332 if ((nlink_t)dp->i_nlink >= LINK_MAX) {
1333 error = EMLINK;
1334 goto out;
1335 }
1336 dmode = vap->va_mode & 0777;
1337 dmode |= IFDIR;
1338 /*
1339 * Must simulate part of ufs_makeinode here to acquire the inode,
1340 * but not have it entered in the parent directory. The entry is
1341 * made later after writing "." and ".." entries.
1342 */
1343 if (error = VOP_VALLOC(dvp, dmode, cnp->cn_cred, &tvp))
1344 goto out;
1345 ip = VTOI(tvp);
1346 ip->i_uid = cnp->cn_cred->cr_uid;
1347 ip->i_gid = dp->i_gid;
1348#if QUOTA
1349 if ((error = getinoquota(ip)) ||
1350 (error = chkiq(ip, 1, cnp->cn_cred, 0))) {
1351 _FREE_ZONE(cnp->cn_pnbuf, cnp->cn_pnlen, M_NAMEI);
1352 VOP_VFREE(tvp, ip->i_number, dmode);
1353 vput(tvp);
1354 vput(dvp);
1355 return (error);
1356 }
1357#endif
1358 ip->i_flag |= IN_ACCESS | IN_CHANGE | IN_UPDATE;
1359 ip->i_mode = dmode;
1360 tvp->v_type = VDIR; /* Rest init'd in getnewvnode(). */
1361 ip->i_nlink = 2;
1362 if (cnp->cn_flags & ISWHITEOUT)
1363 ip->i_flags |= UF_OPAQUE;
1364 tv = time;
1365 error = VOP_UPDATE(tvp, &tv, &tv, 1);
1366
1367 /*
1368 * Bump link count in parent directory
1369 * to reflect work done below. Should
1370 * be done before reference is created
1371 * so reparation is possible if we crash.
1372 */
1373 dp->i_nlink++;
1374 dp->i_flag |= IN_CHANGE;
1375 if (error = VOP_UPDATE(dvp, &tv, &tv, 1))
1376 goto bad;
1377
1378 /* Initialize directory with "." and ".." from static template. */
1379 if (dvp->v_mount->mnt_maxsymlinklen > 0)
1380 dtp = &mastertemplate;
1381 else
1382 dtp = (struct dirtemplate *)&omastertemplate;
1383 dirtemplate = *dtp;
1384 dirtemplate.dot_ino = ip->i_number;
1385 dirtemplate.dotdot_ino = dp->i_number;
1386 error = vn_rdwr(UIO_WRITE, tvp, (caddr_t)&dirtemplate,
1387 sizeof (dirtemplate), (off_t)0, UIO_SYSSPACE,
1388 IO_NODELOCKED|IO_SYNC, cnp->cn_cred, (int *)0, (struct proc *)0);
1389 if (error) {
1390 dp->i_nlink--;
1391 dp->i_flag |= IN_CHANGE;
1392 goto bad;
1393 }
1394 if (DIRBLKSIZ > VFSTOUFS(dvp->v_mount)->um_mountp->mnt_stat.f_bsize)
1395 panic("ufs_mkdir: blksize"); /* XXX should grow with balloc() */
1396 else {
1397 ip->i_size = DIRBLKSIZ;
1398 ip->i_flag |= IN_CHANGE;
1399 }
1400
1401 /* Directory set up, now install it's entry in the parent directory. */
1402 if (error = ufs_direnter(ip, dvp, cnp)) {
1403 dp->i_nlink--;
1404 dp->i_flag |= IN_CHANGE;
1405 }
1406bad:
1407 /*
1408 * No need to do an explicit VOP_TRUNCATE here, vrele will do this
1409 * for us because we set the link count to 0.
1410 */
1411 if (error) {
1412 ip->i_nlink = 0;
1413 ip->i_flag |= IN_CHANGE;
1414 vput(tvp);
1415 } else
1416 *ap->a_vpp = tvp;
1417out:
1418 FREE_ZONE(cnp->cn_pnbuf, cnp->cn_pnlen, M_NAMEI);
1419 vput(dvp);
1420 return (error);
1421}
1422
1423/*
1424 * Rmdir system call.
1425 */
1426int
1427ufs_rmdir(ap)
1428 struct vop_rmdir_args /* {
1429 struct vnode *a_dvp;
1430 struct vnode *a_vp;
1431 struct componentname *a_cnp;
1432 } */ *ap;
1433{
1434 struct vnode *vp = ap->a_vp;
1435 struct vnode *dvp = ap->a_dvp;
1436 struct componentname *cnp = ap->a_cnp;
1437 struct inode *ip, *dp;
1438 int error;
1439
1440 ip = VTOI(vp);
1441 dp = VTOI(dvp);
1442 /*
1443 * No rmdir "." please.
1444 */
1445 if (dp == ip) {
1446 vrele(dvp);
1447 vput(vp);
1448 return (EINVAL);
1449 }
1450 /*
1451 * Verify the directory is empty (and valid).
1452 * (Rmdir ".." won't be valid since
1453 * ".." will contain a reference to
1454 * the current directory and thus be
1455 * non-empty.)
1456 */
1457 error = 0;
1458 if (ip->i_nlink != 2 ||
1459 !ufs_dirempty(ip, dp->i_number, cnp->cn_cred)) {
1460 error = ENOTEMPTY;
1461 goto out;
1462 }
1463 if ((dp->i_flags & APPEND) || (ip->i_flags & (IMMUTABLE | APPEND))) {
1464 error = EPERM;
1465 goto out;
1466 }
1467 /*
1468 * Delete reference to directory before purging
1469 * inode. If we crash in between, the directory
1470 * will be reattached to lost+found,
1471 */
1472 if (error = ufs_dirremove(dvp, cnp))
1473 goto out;
1474 dp->i_nlink--;
1475 dp->i_flag |= IN_CHANGE;
1476 cache_purge(dvp);
1477 vput(dvp);
1478 dvp = NULL;
1479 /*
1480 * Truncate inode. The only stuff left
1481 * in the directory is "." and "..". The
1482 * "." reference is inconsequential since
1483 * we're quashing it. The ".." reference
1484 * has already been adjusted above. We've
1485 * removed the "." reference and the reference
1486 * in the parent directory, but there may be
1487 * other hard links so decrement by 2 and
1488 * worry about them later.
1489 */
1490 ip->i_nlink -= 2;
1491 error = VOP_TRUNCATE(vp, (off_t)0, IO_SYNC, cnp->cn_cred,
1492 cnp->cn_proc);
1493 cache_purge(ITOV(ip));
1494out:
1495 if (dvp)
1496 vput(dvp);
1497 vput(vp);
1498 return (error);
1499}
1500
1501/*
1502 * symlink -- make a symbolic link
1503 */
1504int
1505ufs_symlink(ap)
1506 struct vop_symlink_args /* {
1507 struct vnode *a_dvp;
1508 struct vnode **a_vpp;
1509 struct componentname *a_cnp;
1510 struct vattr *a_vap;
1511 char *a_target;
1512 } */ *ap;
1513{
1514 register struct vnode *vp, **vpp = ap->a_vpp;
1515 register struct inode *ip;
1516 int len, error;
1517
1518 if (error = ufs_makeinode(IFLNK | ap->a_vap->va_mode, ap->a_dvp,
1519 vpp, ap->a_cnp))
1520 return (error);
1521 vp = *vpp;
1522 len = strlen(ap->a_target);
1523 if (len < vp->v_mount->mnt_maxsymlinklen) {
1524 ip = VTOI(vp);
1525 bcopy(ap->a_target, (char *)ip->i_shortlink, len);
1526 ip->i_size = len;
1527 ip->i_flag |= IN_CHANGE | IN_UPDATE;
1528 } else
1529 error = vn_rdwr(UIO_WRITE, vp, ap->a_target, len, (off_t)0,
1530 UIO_SYSSPACE, IO_NODELOCKED, ap->a_cnp->cn_cred, (int *)0,
1531 (struct proc *)0);
1532 vput(vp);
1533 return (error);
1534}
1535
1536/*
1537 * Vnode op for reading directories.
1538 *
1539 * The routine below assumes that the on-disk format of a directory
1540 * is the same as that defined by <sys/dirent.h>. If the on-disk
1541 * format changes, then it will be necessary to do a conversion
1542 * from the on-disk format that read returns to the format defined
1543 * by <sys/dirent.h>.
1544 */
1545int
1546ufs_readdir(ap)
1547 struct vop_readdir_args /* {
1548 struct vnode *a_vp;
1549 struct uio *a_uio;
1550 struct ucred *a_cred;
1551 int *a_eofflag;
1552 int *ncookies;
1553 u_long **a_cookies;
1554 } */ *ap;
1555{
1556 register struct uio *uio = ap->a_uio;
1557 int error;
1558 size_t count, lost;
1559 off_t off = uio->uio_offset;
1560
1561 count = uio->uio_resid;
1562 /* Make sure we don't return partial entries. */
1563 count -= (uio->uio_offset + count) & (DIRBLKSIZ -1);
1564 if (count <= 0)
1565 return (EINVAL);
1566 lost = uio->uio_resid - count;
1567 uio->uio_resid = count;
1568 uio->uio_iov->iov_len = count;
1569# if (BYTE_ORDER == LITTLE_ENDIAN)
1570 if (ap->a_vp->v_mount->mnt_maxsymlinklen > 0) {
1571 error = VOP_READ(ap->a_vp, uio, 0, ap->a_cred);
1572 } else {
1573 struct dirent *dp, *edp;
1574 struct uio auio;
1575 struct iovec aiov;
1576 caddr_t dirbuf;
1577 int readcnt;
1578 u_char tmp;
1579
1580 auio = *uio;
1581 auio.uio_iov = &aiov;
1582 auio.uio_iovcnt = 1;
1583 auio.uio_segflg = UIO_SYSSPACE;
1584 aiov.iov_len = count;
1585 MALLOC(dirbuf, caddr_t, count, M_TEMP, M_WAITOK);
1586 aiov.iov_base = dirbuf;
1587 error = VOP_READ(ap->a_vp, &auio, 0, ap->a_cred);
1588 if (error == 0) {
1589 readcnt = count - auio.uio_resid;
1590 edp = (struct dirent *)&dirbuf[readcnt];
1591 for (dp = (struct dirent *)dirbuf; dp < edp; ) {
1592 tmp = dp->d_namlen;
1593 dp->d_namlen = dp->d_type;
1594 dp->d_type = tmp;
1595 if (dp->d_reclen > 0) {
1596 dp = (struct dirent *)
1597 ((char *)dp + dp->d_reclen);
1598 } else {
1599 error = EIO;
1600 break;
1601 }
1602 }
1603 if (dp >= edp)
1604 error = uiomove(dirbuf, readcnt, uio);
1605 }
1606 FREE(dirbuf, M_TEMP);
1607 }
1608# else
1609 error = VOP_READ(ap->a_vp, uio, 0, ap->a_cred);
1610# endif
1611 if (!error && ap->a_ncookies != NULL) {
1612 struct dirent* dpStart;
1613 struct dirent* dpEnd;
1614 struct dirent* dp;
1615 int ncookies;
1616 u_long *cookies;
1617 u_long *cookiep;
1618
1619 /*
1620 * Only the NFS server uses cookies, and it loads the
1621 * directory block into system space, so we can just look at
1622 * it directly.
1623 */
1624 if (uio->uio_segflg != UIO_SYSSPACE || uio->uio_iovcnt != 1)
1625 panic("ufs_readdir: unexpected uio from NFS server");
1626 dpStart = (struct dirent *)
1627 (uio->uio_iov->iov_base - (uio->uio_offset - off));
1628 dpEnd = (struct dirent *) uio->uio_iov->iov_base;
1629 for (dp = dpStart, ncookies = 0;
1630 dp < dpEnd && dp->d_reclen != 0;
1631 dp = (struct dirent *)((caddr_t)dp + dp->d_reclen))
1632 ncookies++;
1633 MALLOC(cookies, u_long *, ncookies * sizeof(u_long), M_TEMP,
1634 M_WAITOK);
1635 for (dp = dpStart, cookiep = cookies;
1636 dp < dpEnd;
1637 dp = (struct dirent *)((caddr_t) dp + dp->d_reclen)) {
1638 off += dp->d_reclen;
1639 *cookiep++ = (u_long) off;
1640 }
1641 *ap->a_ncookies = ncookies;
1642 *ap->a_cookies = cookies;
1643 }
1644 uio->uio_resid += lost;
1645 if (ap->a_eofflag)
1646 *ap->a_eofflag = VTOI(ap->a_vp)->i_size <= uio->uio_offset;
1647 return (error);
1648}
1649
1650/*
1651 * Return target name of a symbolic link
1652 */
1653int
1654ufs_readlink(ap)
1655 struct vop_readlink_args /* {
1656 struct vnode *a_vp;
1657 struct uio *a_uio;
1658 struct ucred *a_cred;
1659 } */ *ap;
1660{
1661 register struct vnode *vp = ap->a_vp;
1662 register struct inode *ip = VTOI(vp);
1663 int isize;
1664
1665 isize = ip->i_size;
1666 if (isize < vp->v_mount->mnt_maxsymlinklen) {
1667 uiomove((char *)ip->i_shortlink, isize, ap->a_uio);
1668 return (0);
1669 }
1670 return (VOP_READ(vp, ap->a_uio, 0, ap->a_cred));
1671}
1672
1673/*
1674 * Ufs abort op, called after namei() when a CREATE/DELETE isn't actually
1675 * done. If a buffer has been saved in anticipation of a CREATE, delete it.
1676 */
1677/* ARGSUSED */
1678int
1679ufs_abortop(ap)
1680 struct vop_abortop_args /* {
1681 struct vnode *a_dvp;
1682 struct componentname *a_cnp;
1683 } */ *ap;
1684{
1685 if ((ap->a_cnp->cn_flags & (HASBUF | SAVESTART)) == HASBUF)
1686 FREE_ZONE(ap->a_cnp->cn_pnbuf, ap->a_cnp->cn_pnlen, M_NAMEI);
1687 return (0);
1688}
1689
1690/*
1691 * Lock an inode. If its already locked, set the WANT bit and sleep.
1692 */
1693int
1694ufs_lock(ap)
1695 struct vop_lock_args /* {
1696 struct vnode *a_vp;
1697 int a_flags;
1698 struct proc *a_p;
1699 } */ *ap;
1700{
1701 struct vnode *vp = ap->a_vp;
1702
1703 if (VTOI(vp) == (struct inode *)NULL)
1704 panic("inode in vnode is null\n");
1705 return (lockmgr(&VTOI(vp)->i_lock, ap->a_flags, &vp->v_interlock,
1706 ap->a_p));
1707}
1708
1709/*
1710 * Unlock an inode.
1711 */
1712int
1713ufs_unlock(ap)
1714 struct vop_unlock_args /* {
1715 struct vnode *a_vp;
1716 int a_flags;
1717 struct proc *a_p;
1718 } */ *ap;
1719{
1720 struct vnode *vp = ap->a_vp;
1721
1722 return (lockmgr(&VTOI(vp)->i_lock, ap->a_flags | LK_RELEASE,
1723 &vp->v_interlock, ap->a_p));
1724}
1725
1726/*
1727 * Check for a locked inode.
1728 */
1729int
1730ufs_islocked(ap)
1731 struct vop_islocked_args /* {
1732 struct vnode *a_vp;
1733 } */ *ap;
1734{
1735
1736 return (lockstatus(&VTOI(ap->a_vp)->i_lock));
1737}
1738
1739/*
1740 * Calculate the logical to physical mapping if not done already,
1741 * then call the device strategy routine.
1742 */
1743int
1744ufs_strategy(ap)
1745 struct vop_strategy_args /* {
1746 struct buf *a_bp;
1747 } */ *ap;
1748{
1749 register struct buf *bp = ap->a_bp;
1750 register struct vnode *vp = bp->b_vp;
1751 register struct inode *ip;
1752 int error;
1753
1754 ip = VTOI(vp);
1755 if ( !(bp->b_flags & B_VECTORLIST)) {
1756 if (vp->v_type == VBLK || vp->v_type == VCHR)
1757 panic("ufs_strategy: spec");
1758
1759
1760 if (bp->b_flags & B_PAGELIST) {
1761 /*
1762 * if we have a page list associated with this bp,
1763 * then go through cluste_bp since it knows how to
1764 * deal with a page request that might span non-contiguous
1765 * physical blocks on the disk...
1766 */
1767#if 1
1768 if (bp->b_blkno == bp->b_lblkno) {
1769 if (error = VOP_BMAP(vp, bp->b_lblkno, NULL,
1770 &bp->b_blkno, NULL)) {
1771 bp->b_error = error;
1772 bp->b_flags |= B_ERROR;
1773 biodone(bp);
1774 return (error);
1775 }
1776 }
1777#endif /* 1 */
1778 error = cluster_bp(bp);
1779 vp = ip->i_devvp;
1780 bp->b_dev = vp->v_rdev;
1781
1782 return (error);
1783 }
1784
1785 if (bp->b_blkno == bp->b_lblkno) {
1786 if (error =
1787 VOP_BMAP(vp, bp->b_lblkno, NULL, &bp->b_blkno, NULL)) {
1788 bp->b_error = error;
1789 bp->b_flags |= B_ERROR;
1790 biodone(bp);
1791 return (error);
1792 }
1793 if ((long)bp->b_blkno == -1)
1794 clrbuf(bp);
1795 }
1796 if ((long)bp->b_blkno == -1) {
1797 biodone(bp);
1798 return (0);
1799 }
1800
1801 }
1802
1803 vp = ip->i_devvp;
1804 bp->b_dev = vp->v_rdev;
1805 VOCALL (vp->v_op, VOFFSET(vop_strategy), ap);
1806 return (0);
1807}
1808
1809/*
1810 * Print out the contents of an inode.
1811 */
1812int
1813ufs_print(ap)
1814 struct vop_print_args /* {
1815 struct vnode *a_vp;
1816 } */ *ap;
1817{
1818 register struct vnode *vp = ap->a_vp;
1819 register struct inode *ip = VTOI(vp);
1820
1821 printf("tag VT_UFS, ino %d, on dev %d, %d", ip->i_number,
1822 major(ip->i_dev), minor(ip->i_dev));
1823#if FIFO
1824 if (vp->v_type == VFIFO)
1825 fifo_printinfo(vp);
1826#endif /* FIFO */
1827 lockmgr_printinfo(&ip->i_lock);
1828 printf("\n");
1829 return (0);
1830}
1831
1832/*
1833 * Read wrapper for special devices.
1834 */
1835int
1836ufsspec_read(ap)
1837 struct vop_read_args /* {
1838 struct vnode *a_vp;
1839 struct uio *a_uio;
1840 int a_ioflag;
1841 struct ucred *a_cred;
1842 } */ *ap;
1843{
1844
1845 /*
1846 * Set access flag.
1847 */
1848 VTOI(ap->a_vp)->i_flag |= IN_ACCESS;
1849 return (VOCALL (spec_vnodeop_p, VOFFSET(vop_read), ap));
1850}
1851
1852/*
1853 * Write wrapper for special devices.
1854 */
1855int
1856ufsspec_write(ap)
1857 struct vop_write_args /* {
1858 struct vnode *a_vp;
1859 struct uio *a_uio;
1860 int a_ioflag;
1861 struct ucred *a_cred;
1862 } */ *ap;
1863{
1864
1865 /*
1866 * Set update and change flags.
1867 */
1868 VTOI(ap->a_vp)->i_flag |= IN_CHANGE | IN_UPDATE;
1869 return (VOCALL (spec_vnodeop_p, VOFFSET(vop_write), ap));
1870}
1871
1872/*
1873 * Close wrapper for special devices.
1874 *
1875 * Update the times on the inode then do device close.
1876 */
1877int
1878ufsspec_close(ap)
1879 struct vop_close_args /* {
1880 struct vnode *a_vp;
1881 int a_fflag;
1882 struct ucred *a_cred;
1883 struct proc *a_p;
1884 } */ *ap;
1885{
1886 struct vnode *vp = ap->a_vp;
1887 struct inode *ip = VTOI(vp);
1888
1889 simple_lock(&vp->v_interlock);
1890 if (ap->a_vp->v_usecount > 1)
1891 ITIMES(ip, &time, &time);
1892 simple_unlock(&vp->v_interlock);
1893 return (VOCALL (spec_vnodeop_p, VOFFSET(vop_close), ap));
1894}
1895
1896#if FIFO
1897/*
1898 * Read wrapper for fifo's
1899 */
1900int
1901ufsfifo_read(ap)
1902 struct vop_read_args /* {
1903 struct vnode *a_vp;
1904 struct uio *a_uio;
1905 int a_ioflag;
1906 struct ucred *a_cred;
1907 } */ *ap;
1908{
1909 extern int (**fifo_vnodeop_p)(void *);
1910
1911 /*
1912 * Set access flag.
1913 */
1914 VTOI(ap->a_vp)->i_flag |= IN_ACCESS;
1915 return (VOCALL (fifo_vnodeop_p, VOFFSET(vop_read), ap));
1916}
1917
1918/*
1919 * Write wrapper for fifo's.
1920 */
1921int
1922ufsfifo_write(ap)
1923 struct vop_write_args /* {
1924 struct vnode *a_vp;
1925 struct uio *a_uio;
1926 int a_ioflag;
1927 struct ucred *a_cred;
1928 } */ *ap;
1929{
1930 extern int (**fifo_vnodeop_p)(void *);
1931
1932 /*
1933 * Set update and change flags.
1934 */
1935 VTOI(ap->a_vp)->i_flag |= IN_CHANGE | IN_UPDATE;
1936 return (VOCALL (fifo_vnodeop_p, VOFFSET(vop_write), ap));
1937}
1938
1939/*
1940 * Close wrapper for fifo's.
1941 *
1942 * Update the times on the inode then do device close.
1943 */
1944ufsfifo_close(ap)
1945 struct vop_close_args /* {
1946 struct vnode *a_vp;
1947 int a_fflag;
1948 struct ucred *a_cred;
1949 struct proc *a_p;
1950 } */ *ap;
1951{
1952 extern int (**fifo_vnodeop_p)(void *);
1953 struct vnode *vp = ap->a_vp;
1954 struct inode *ip = VTOI(vp);
1955
1956 simple_lock(&vp->v_interlock);
1957 if (ap->a_vp->v_usecount > 1)
1958 ITIMES(ip, &time, &time);
1959 simple_unlock(&vp->v_interlock);
1960 return (VOCALL (fifo_vnodeop_p, VOFFSET(vop_close), ap));
1961}
1962#endif /* FIFO */
1963
1964/*
1965 * Return POSIX pathconf information applicable to ufs filesystems.
1966 */
1967ufs_pathconf(ap)
1968 struct vop_pathconf_args /* {
1969 struct vnode *a_vp;
1970 int a_name;
1971 int *a_retval;
1972 } */ *ap;
1973{
1974
1975 switch (ap->a_name) {
1976 case _PC_LINK_MAX:
1977 *ap->a_retval = LINK_MAX;
1978 return (0);
1979 case _PC_NAME_MAX:
1980 *ap->a_retval = NAME_MAX;
1981 return (0);
1982 case _PC_PATH_MAX:
1983 *ap->a_retval = PATH_MAX;
1984 return (0);
1985 case _PC_PIPE_BUF:
1986 *ap->a_retval = PIPE_BUF;
1987 return (0);
1988 case _PC_CHOWN_RESTRICTED:
1989 *ap->a_retval = 1;
1990 return (0);
1991 case _PC_NO_TRUNC:
1992 *ap->a_retval = 1;
1993 return (0);
1994 default:
1995 return (EINVAL);
1996 }
1997 /* NOTREACHED */
1998}
1999
2000/*
2001 * Advisory record locking support
2002 */
2003int
2004ufs_advlock(ap)
2005 struct vop_advlock_args /* {
2006 struct vnode *a_vp;
2007 caddr_t a_id;
2008 int a_op;
2009 struct flock *a_fl;
2010 int a_flags;
2011 } */ *ap;
2012{
2013 register struct inode *ip = VTOI(ap->a_vp);
2014 register struct flock *fl = ap->a_fl;
2015 register struct lockf *lock;
2016 off_t start, end;
2017 int error;
2018
2019 /*
2020 * Avoid the common case of unlocking when inode has no locks.
2021 */
2022 if (ip->i_lockf == (struct lockf *)0) {
2023 if (ap->a_op != F_SETLK) {
2024 fl->l_type = F_UNLCK;
2025 return (0);
2026 }
2027 }
2028 /*
2029 * Convert the flock structure into a start and end.
2030 */
2031 switch (fl->l_whence) {
2032
2033 case SEEK_SET:
2034 case SEEK_CUR:
2035 /*
2036 * Caller is responsible for adding any necessary offset
2037 * when SEEK_CUR is used.
2038 */
2039 start = fl->l_start;
2040 break;
2041
2042 case SEEK_END:
2043 start = ip->i_size + fl->l_start;
2044 break;
2045
2046 default:
2047 return (EINVAL);
2048 }
2049 if (start < 0)
2050 return (EINVAL);
2051 if (fl->l_len == 0)
2052 end = -1;
2053 else
2054 end = start + fl->l_len - 1;
2055 /*
2056 * Create the lockf structure
2057 */
2058 MALLOC(lock, struct lockf *, sizeof *lock, M_LOCKF, M_WAITOK);
2059 lock->lf_start = start;
2060 lock->lf_end = end;
2061 lock->lf_id = ap->a_id;
2062 lock->lf_inode = ip;
2063 lock->lf_type = fl->l_type;
2064 lock->lf_next = (struct lockf *)0;
2065 TAILQ_INIT(&lock->lf_blkhd);
2066 lock->lf_flags = ap->a_flags;
2067 /*
2068 * Do the requested operation.
2069 */
2070 switch(ap->a_op) {
2071 case F_SETLK:
2072 return (lf_setlock(lock));
2073
2074 case F_UNLCK:
2075 error = lf_clearlock(lock);
2076 FREE(lock, M_LOCKF);
2077 return (error);
2078
2079 case F_GETLK:
2080 error = lf_getlock(lock, fl);
2081 FREE(lock, M_LOCKF);
2082 return (error);
2083
2084 default:
2085 _FREE(lock, M_LOCKF);
2086 return (EINVAL);
2087 }
2088 /* NOTREACHED */
2089}
2090
2091/*
2092 * Initialize the vnode associated with a new inode, handle aliased
2093 * vnodes.
2094 */
2095int
2096ufs_vinit(mntp, specops, fifoops, vpp)
2097 struct mount *mntp;
2098 int (**specops)();
2099 int (**fifoops)();
2100 struct vnode **vpp;
2101{
2102 struct proc *p = current_proc(); /* XXX */
2103 struct inode *ip;
2104 struct vnode *vp, *nvp;
2105
2106 vp = *vpp;
2107 ip = VTOI(vp);
2108 switch(vp->v_type = IFTOVT(ip->i_mode)) {
2109 case VCHR:
2110 case VBLK:
2111 vp->v_op = specops;
2112 if (nvp = checkalias(vp, ip->i_rdev, mntp)) {
2113 /*
2114 * Discard unneeded vnode, but save its inode.
2115 * Note that the lock is carried over in the inode
2116 * to the replacement vnode.
2117 */
2118 nvp->v_data = vp->v_data;
2119 vp->v_data = NULL;
2120 vp->v_op = spec_vnodeop_p;
2121 vrele(vp);
2122 vgone(vp);
2123 /*
2124 * Reinitialize aliased inode.
2125 */
2126 vp = nvp;
2127 ip->i_vnode = vp;
2128 }
2129 break;
2130 case VFIFO:
2131#if FIFO
2132 vp->v_op = fifoops;
2133 break;
2134#else
2135 return (EOPNOTSUPP);
2136#endif
2137 case VREG:
2138#if 0
2139 ubc_info_init(vp);
2140#endif /* 0 */
2141 break;
2142 default:
2143 break;
2144 }
2145 if (ip->i_number == ROOTINO)
2146 vp->v_flag |= VROOT;
2147 /*
2148 * Initialize modrev times
2149 */
2150 SETHIGH(ip->i_modrev, time.tv_sec);
2151 SETLOW(ip->i_modrev, time.tv_usec * 4294);
2152 *vpp = vp;
2153 return (0);
2154}
2155
2156/*
2157 * Allocate a new inode.
2158 */
2159int
2160ufs_makeinode(mode, dvp, vpp, cnp)
2161 int mode;
2162 struct vnode *dvp;
2163 struct vnode **vpp;
2164 struct componentname *cnp;
2165{
2166 register struct inode *ip, *pdir;
2167 struct timeval tv;
2168 struct vnode *tvp;
2169 int error;
2170
2171 pdir = VTOI(dvp);
2172#if DIAGNOSTIC
2173 if ((cnp->cn_flags & HASBUF) == 0)
2174 panic("ufs_makeinode: no name");
2175#endif
2176 *vpp = NULL;
2177 if ((mode & IFMT) == 0)
2178 mode |= IFREG;
2179
2180 if (error = VOP_VALLOC(dvp, mode, cnp->cn_cred, &tvp)) {
2181 _FREE_ZONE(cnp->cn_pnbuf, cnp->cn_pnlen, M_NAMEI);
2182 vput(dvp);
2183 return (error);
2184 }
2185 ip = VTOI(tvp);
2186 ip->i_gid = pdir->i_gid;
2187 if ((mode & IFMT) == IFLNK)
2188 ip->i_uid = pdir->i_uid;
2189 else
2190 ip->i_uid = cnp->cn_cred->cr_uid;
2191#if QUOTA
2192 if ((error = getinoquota(ip)) ||
2193 (error = chkiq(ip, 1, cnp->cn_cred, 0))) {
2194 _FREE_ZONE(cnp->cn_pnbuf, cnp->cn_pnlen, M_NAMEI);
2195 VOP_VFREE(tvp, ip->i_number, mode);
2196 vput(tvp);
2197 vput(dvp);
2198 return (error);
2199 }
2200#endif
2201 ip->i_flag |= IN_ACCESS | IN_CHANGE | IN_UPDATE;
2202 ip->i_mode = mode;
2203 tvp->v_type = IFTOVT(mode); /* Rest init'd in getnewvnode(). */
2204 ip->i_nlink = 1;
2205 if ((ip->i_mode & ISGID) && !groupmember(ip->i_gid, cnp->cn_cred) &&
2206 suser(cnp->cn_cred, NULL))
2207 ip->i_mode &= ~ISGID;
2208
2209 if (cnp->cn_flags & ISWHITEOUT)
2210 ip->i_flags |= UF_OPAQUE;
2211
2212 /*
2213 * initialize UBC before calling VOP_UPDATE and ufs_direnter
2214 * Not doing so introduces probelms in handling error from
2215 * those calls.
2216 * It results in a "vget: stolen ubc_info" panic due to attempt
2217 * to shutdown uninitialized UBC.
2218 */
2219 if (UBCINFOMISSING(tvp) || UBCINFORECLAIMED(tvp))
2220 ubc_info_init(tvp);
2221
2222 /*
2223 * Make sure inode goes to disk before directory entry.
2224 */
2225 tv = time;
2226 if (error = VOP_UPDATE(tvp, &tv, &tv, 1))
2227 goto bad;
2228 if (error = ufs_direnter(ip, dvp, cnp))
2229 goto bad;
2230 if ((cnp->cn_flags & SAVESTART) == 0)
2231 FREE_ZONE(cnp->cn_pnbuf, cnp->cn_pnlen, M_NAMEI);
2232 vput(dvp);
2233
2234 *vpp = tvp;
2235 return (0);
2236
2237bad:
2238 /*
2239 * Write error occurred trying to update the inode
2240 * or the directory so must deallocate the inode.
2241 */
2242 _FREE_ZONE(cnp->cn_pnbuf, cnp->cn_pnlen, M_NAMEI);
2243 vput(dvp);
2244 ip->i_nlink = 0;
2245 ip->i_flag |= IN_CHANGE;
2246 vput(tvp);
2247 return (error);
2248}
2249