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