]> git.saurik.com Git - apple/xnu.git/blame_incremental - bsd/ufs/ufs/ufs_vnops.c
xnu-1228.15.4.tar.gz
[apple/xnu.git] / bsd / ufs / ufs / ufs_vnops.c
... / ...
CommitLineData
1/*
2 * Copyright (c) 2000-2007 Apple Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28/* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */
29/*
30 * Copyright (c) 1982, 1986, 1989, 1993, 1995
31 * The Regents of the University of California. All rights reserved.
32 * (c) UNIX System Laboratories, Inc.
33 * All or some portions of this file are derived from material licensed
34 * to the University of California by American Telephone and Telegraph
35 * Co. or Unix System Laboratories, Inc. and are reproduced herein with
36 * the permission of UNIX System Laboratories, Inc.
37 *
38 * Redistribution and use in source and binary forms, with or without
39 * modification, are permitted provided that the following conditions
40 * are met:
41 * 1. Redistributions of source code must retain the above copyright
42 * notice, this list of conditions and the following disclaimer.
43 * 2. Redistributions in binary form must reproduce the above copyright
44 * notice, this list of conditions and the following disclaimer in the
45 * documentation and/or other materials provided with the distribution.
46 * 3. All advertising materials mentioning features or use of this software
47 * must display the following acknowledgement:
48 * This product includes software developed by the University of
49 * California, Berkeley and its contributors.
50 * 4. Neither the name of the University nor the names of its contributors
51 * may be used to endorse or promote products derived from this software
52 * without specific prior written permission.
53 *
54 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
55 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
56 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
57 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
58 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
59 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
60 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
61 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
62 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
63 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
64 * SUCH DAMAGE.
65 *
66 * @(#)ufs_vnops.c 8.27 (Berkeley) 5/27/95
67 */
68
69#include <rev_endian_fs.h>
70#include <sys/param.h>
71#include <sys/systm.h>
72#include <sys/namei.h>
73#include <sys/resourcevar.h>
74#include <sys/kernel.h>
75#include <sys/file_internal.h>
76#include <sys/stat.h>
77#include <sys/buf.h>
78#include <sys/proc.h>
79#include <sys/kauth.h>
80#include <sys/conf.h>
81#include <sys/mount_internal.h>
82#include <sys/vnode_internal.h>
83#include <sys/malloc.h>
84#include <sys/dirent.h>
85#include <sys/fcntl.h>
86#include <sys/ubc.h>
87#include <sys/quota.h>
88#include <sys/uio_internal.h>
89
90#include <kern/thread.h>
91#include <sys/vm.h>
92
93#include <miscfs/specfs/specdev.h>
94
95#include <ufs/ufs/quota.h>
96#include <ufs/ufs/inode.h>
97#include <ufs/ufs/dir.h>
98#include <ufs/ufs/ufsmount.h>
99#include <ufs/ufs/ufs_extern.h>
100
101#if REV_ENDIAN_FS
102#include <ufs/ufs/ufs_byte_order.h>
103#endif /* REV_ENDIAN_FS */
104
105
106static int ufs_chmod(struct vnode *, int, kauth_cred_t, struct proc *);
107static int ufs_chown(struct vnode *, uid_t, gid_t, kauth_cred_t,
108 struct proc *);
109static int filt_ufsread(struct knote *kn, long hint);
110static int filt_ufswrite(struct knote *kn, long hint);
111static int filt_ufsvnode(struct knote *kn, long hint);
112static void filt_ufsdetach(struct knote *kn);
113
114#if FIFO
115extern void fifo_printinfo(struct vnode *vp);
116#endif /* FIFO */
117extern int ufs_direnter2(struct vnode *dvp, struct direct *dirp,
118 vfs_context_t ctx);
119
120static int ufs_readdirext(vnode_t vp, uio_t uio, int *eofflag, int *numdirent,
121 vfs_context_t context);
122
123/*
124 * Create a regular file
125 */
126int
127ufs_create(ap)
128 struct vnop_create_args /* {
129 struct vnode *a_dvp;
130 struct vnode **a_vpp;
131 struct componentname *a_cnp;
132 struct vnode_vattr *a_vap;
133 vfs_context_t a_context;
134 } */ *ap;
135{
136 int error;
137
138 if ( (error = ufs_makeinode(ap->a_vap, ap->a_dvp, ap->a_vpp, ap->a_cnp)) )
139 return (error);
140 VN_KNOTE(ap->a_dvp, NOTE_WRITE);
141 return (0);
142}
143
144/*
145 * Mknod vnode call
146 */
147int
148ufs_mknod(ap)
149 struct vnop_mknod_args /* {
150 struct vnode *a_dvp;
151 struct vnode **a_vpp;
152 struct componentname *a_cnp;
153 struct vnode_attr *a_vap;
154 vfs_context_t a_context;
155 } */ *ap;
156{
157 struct vnode_attr *vap = ap->a_vap;
158 struct vnode **vpp = ap->a_vpp;
159 struct vnode *dvp = ap->a_dvp;
160 struct vnode *tvp;
161 struct inode *ip;
162 struct componentname *cnp = ap->a_cnp;
163 int error;
164
165 /* use relookup to force correct directory hints */
166 cnp->cn_flags &= ~MODMASK;
167 cnp->cn_flags |= (WANTPARENT | NOCACHE);
168 cnp->cn_nameiop = CREATE;
169
170 (void) relookup(dvp, &tvp, cnp);
171
172 /* get rid of reference relookup returned */
173 if (tvp)
174 vnode_put(tvp);
175
176 if ( (error =
177 ufs_makeinode(ap->a_vap, ap->a_dvp, vpp, ap->a_cnp)) )
178 return (error);
179 VN_KNOTE(ap->a_dvp, NOTE_WRITE);
180 ip = VTOI(*vpp);
181 ip->i_flag |= IN_ACCESS | IN_CHANGE | IN_UPDATE;
182 if (vap->va_rdev != VNOVAL) {
183 /*
184 * Want to be able to use this to make badblock
185 * inodes, so don't truncate the dev number.
186 */
187 ip->i_rdev = vap->va_rdev;
188 }
189 return (0);
190}
191
192/*
193 * Open called.
194 *
195 * Nothing to do.
196 */
197int
198ufs_open(ap)
199 struct vnop_open_args /* {
200 struct vnode *a_vp;
201 int a_mode;
202 vfs_context_t a_context;
203 } */ *ap;
204{
205
206 /*
207 * Files marked append-only must be opened for appending.
208 */
209 if ((VTOI(ap->a_vp)->i_flags & APPEND) &&
210 (ap->a_mode & (FWRITE | O_APPEND)) == FWRITE)
211 return (EPERM);
212 return (0);
213}
214
215/*
216 * Close called.
217 *
218 * Update the times on the inode.
219 */
220int
221ufs_close(ap)
222 struct vnop_close_args /* {
223 struct vnode *a_vp;
224 int a_fflag;
225 vfs_context_t a_context;
226 } */ *ap;
227{
228 register struct vnode *vp = ap->a_vp;
229 register struct inode *ip = VTOI(vp);
230 struct timeval tv;
231
232 if (vnode_isinuse(vp, 1)) {
233 microtime(&tv);
234 ITIMES(ip, &tv, &tv);
235 }
236
237 cluster_push(vp, IO_CLOSE);
238
239 return (0);
240}
241
242int
243ufs_getattr(ap)
244 struct vnop_getattr_args /* {
245 struct vnode *a_vp;
246 struct vnode_attr *a_vap;
247 vfs_context_t a_context;
248 } */ *ap;
249{
250 register struct vnode *vp = ap->a_vp;
251 register struct inode *ip = VTOI(vp);
252 register struct vnode_attr *vap = ap->a_vap;
253 int devBlockSize=0;
254 struct timeval tv;
255
256 microtime(&tv);
257
258 ITIMES(ip, &tv, &tv);
259 /*
260 * Copy from inode table
261 */
262 VATTR_RETURN(vap, va_fsid, ip->i_dev);
263 VATTR_RETURN(vap, va_fileid, ip->i_number);
264 VATTR_RETURN(vap, va_mode, ip->i_mode & ~IFMT);
265 VATTR_RETURN(vap, va_nlink, ip->i_nlink);
266 VATTR_RETURN(vap, va_uid, ip->i_uid);
267 VATTR_RETURN(vap, va_gid, ip->i_gid);
268 VATTR_RETURN(vap, va_rdev, (dev_t)ip->i_rdev);
269 VATTR_RETURN(vap, va_data_size, ip->i_din.di_size);
270 vap->va_access_time.tv_sec = ip->i_atime;
271 vap->va_access_time.tv_nsec = ip->i_atimensec;
272 VATTR_SET_SUPPORTED(vap, va_access_time);
273 vap->va_modify_time.tv_sec = ip->i_mtime;
274 vap->va_modify_time.tv_nsec = ip->i_mtimensec;
275 VATTR_SET_SUPPORTED(vap, va_modify_time);
276 vap->va_change_time.tv_sec = ip->i_ctime;
277 vap->va_change_time.tv_nsec = ip->i_ctimensec;
278 VATTR_SET_SUPPORTED(vap, va_change_time);
279 VATTR_RETURN(vap, va_flags, ip->i_flags);
280 VATTR_RETURN(vap, va_gen, ip->i_gen);
281 if (vp->v_type == VBLK)
282 VATTR_RETURN(vap, va_iosize, BLKDEV_IOSIZE);
283 else if (vp->v_type == VCHR)
284 VATTR_RETURN(vap, va_iosize, MAXPHYSIO);
285 else
286 VATTR_RETURN(vap, va_iosize, vp->v_mount->mnt_vfsstat.f_iosize);
287 devBlockSize = vfs_devblocksize(vnode_mount(vp));
288 VATTR_RETURN(vap, va_data_alloc, dbtob((u_quad_t)ip->i_blocks, devBlockSize));
289 VATTR_RETURN(vap, va_type, vp->v_type);
290 VATTR_RETURN(vap, va_filerev, ip->i_modrev);
291 return (0);
292}
293
294/*
295 * Set attribute vnode op. called from several syscalls
296 */
297int
298ufs_setattr(ap)
299 struct vnop_setattr_args /* {
300 struct vnode *a_vp;
301 struct vnode_attr *a_vap;
302 struct proc *a_p;
303 vfs_context_t a_context;
304 } */ *ap;
305{
306 struct vnode_attr *vap = ap->a_vap;
307 struct vnode *vp = ap->a_vp;
308 struct inode *ip = VTOI(vp);
309 kauth_cred_t cred = vfs_context_ucred(ap->a_context);
310 struct proc *p = vfs_context_proc(ap->a_context);
311 struct timeval atimeval, mtimeval;
312 int error;
313 uid_t nuid;
314 gid_t ngid;
315
316 /*
317 * Go through the fields and update iff set.
318 */
319 if (VATTR_IS_ACTIVE(vap, va_flags)) {
320 ip->i_flags = vap->va_flags;
321 ip->i_flag |= IN_CHANGE;
322 }
323 VATTR_SET_SUPPORTED(vap, va_flags);
324
325 nuid = VATTR_IS_ACTIVE(vap, va_uid) ? vap->va_uid : (uid_t)VNOVAL;
326 ngid = VATTR_IS_ACTIVE(vap, va_gid) ? vap->va_gid : (gid_t)VNOVAL;
327 if (nuid != (uid_t)VNOVAL || ngid != (gid_t)VNOVAL) {
328 if ( (error = ufs_chown(vp, nuid, ngid, cred, p)) )
329 return (error);
330 }
331 VATTR_SET_SUPPORTED(vap, va_uid);
332 VATTR_SET_SUPPORTED(vap, va_gid);
333
334 if (VATTR_IS_ACTIVE(vap, va_data_size)) {
335 if ( (error = ffs_truncate_internal(vp, vap->va_data_size, vap->va_vaflags & 0xffff, cred)) )
336 return (error);
337 }
338 VATTR_SET_SUPPORTED(vap, va_data_size);
339
340 ip = VTOI(vp);
341 if (VATTR_IS_ACTIVE(vap, va_access_time) || VATTR_IS_ACTIVE(vap, va_modify_time)) {
342 if (VATTR_IS_ACTIVE(vap, va_access_time))
343 ip->i_flag |= IN_ACCESS;
344 if (VATTR_IS_ACTIVE(vap, va_modify_time))
345 ip->i_flag |= IN_CHANGE | IN_UPDATE;
346 atimeval.tv_sec = vap->va_access_time.tv_sec;
347 atimeval.tv_usec = vap->va_access_time.tv_nsec / 1000;
348 mtimeval.tv_sec = vap->va_modify_time.tv_sec;
349 mtimeval.tv_usec = vap->va_modify_time.tv_nsec / 1000;
350 if ( (error = ffs_update(vp, &atimeval, &mtimeval, 1)) )
351 return (error);
352 }
353 VATTR_SET_SUPPORTED(vap, va_access_time);
354 VATTR_SET_SUPPORTED(vap, va_modify_time);
355
356 if (VATTR_IS_ACTIVE(vap, va_mode)) {
357 if ((error = ufs_chmod(vp, (int)vap->va_mode, cred, p)))
358 return (error);
359 }
360 VATTR_SET_SUPPORTED(vap, va_mode);
361
362 VN_KNOTE(vp, NOTE_ATTRIB);
363
364 return (0);
365}
366
367/*
368 * Change the mode on a file.
369 * Inode must be locked before calling.
370 */
371static int
372ufs_chmod(struct vnode *vp, int mode, kauth_cred_t cred, struct proc *p)
373{
374 register struct inode *ip = VTOI(vp);
375
376 ip->i_mode &= ~ALLPERMS;
377 ip->i_mode |= (mode & ALLPERMS);
378 ip->i_flag |= IN_CHANGE;
379 return (0);
380}
381
382/*
383 * Perform chown operation on inode ip;
384 * inode must be locked prior to call.
385 */
386static int
387ufs_chown(struct vnode *vp, uid_t uid, gid_t gid, kauth_cred_t cred,
388 struct proc *p)
389{
390 register struct inode *ip = VTOI(vp);
391 uid_t ouid;
392 gid_t ogid;
393 int error = 0;
394 int is_member;
395#if QUOTA
396 register int i;
397 int64_t change; /* in bytes */
398 int devBlockSize=0;
399#endif /* QUOTA */
400
401 if (uid == (uid_t)VNOVAL)
402 uid = ip->i_uid;
403 if (gid == (gid_t)VNOVAL)
404 gid = ip->i_gid;
405 ogid = ip->i_gid;
406 ouid = ip->i_uid;
407#if QUOTA
408 if ( (error = getinoquota(ip)) )
409 return (error);
410 if (ouid == uid) {
411 dqrele(ip->i_dquot[USRQUOTA]);
412 ip->i_dquot[USRQUOTA] = NODQUOT;
413 }
414 if (ogid == gid) {
415 dqrele(ip->i_dquot[GRPQUOTA]);
416 ip->i_dquot[GRPQUOTA] = NODQUOT;
417 }
418 devBlockSize = vfs_devblocksize(vnode_mount(vp));
419
420 change = dbtob((int64_t)ip->i_blocks, devBlockSize);
421 (void) chkdq(ip, -change, cred, CHOWN);
422 (void) chkiq(ip, -1, cred, CHOWN);
423 for (i = 0; i < MAXQUOTAS; i++) {
424 dqrele(ip->i_dquot[i]);
425 ip->i_dquot[i] = NODQUOT;
426 }
427#endif
428 ip->i_gid = gid;
429 ip->i_uid = uid;
430#if QUOTA
431 if ((error = getinoquota(ip)) == 0) {
432 if (ouid == uid) {
433 dqrele(ip->i_dquot[USRQUOTA]);
434 ip->i_dquot[USRQUOTA] = NODQUOT;
435 }
436 if (ogid == gid) {
437 dqrele(ip->i_dquot[GRPQUOTA]);
438 ip->i_dquot[GRPQUOTA] = NODQUOT;
439 }
440 if ((error = chkdq(ip, change, cred, CHOWN)) == 0) {
441 if ((error = chkiq(ip, 1, cred, CHOWN)) == 0)
442 goto good;
443 else
444 (void) chkdq(ip, -change, cred, CHOWN|FORCE);
445 }
446 for (i = 0; i < MAXQUOTAS; i++) {
447 dqrele(ip->i_dquot[i]);
448 ip->i_dquot[i] = NODQUOT;
449 }
450 }
451 ip->i_gid = ogid;
452 ip->i_uid = ouid;
453 if (getinoquota(ip) == 0) {
454 if (ouid == uid) {
455 dqrele(ip->i_dquot[USRQUOTA]);
456 ip->i_dquot[USRQUOTA] = NODQUOT;
457 }
458 if (ogid == gid) {
459 dqrele(ip->i_dquot[GRPQUOTA]);
460 ip->i_dquot[GRPQUOTA] = NODQUOT;
461 }
462 (void) chkdq(ip, change, cred, FORCE|CHOWN);
463 (void) chkiq(ip, 1, cred, FORCE|CHOWN);
464 (void) getinoquota(ip);
465 }
466 return (error);
467good:
468 if (getinoquota(ip))
469 panic("chown: lost quota");
470#endif /* QUOTA */
471 if (ouid != uid || ogid != gid)
472 ip->i_flag |= IN_CHANGE;
473 return (0);
474}
475
476int
477ufs_ioctl(ap)
478 struct vnop_ioctl_args /* {
479 struct vnode *a_vp;
480 int a_command;
481 caddr_t a_data;
482 int a_fflag;
483 vfs_context_t a_context;
484 } */ *ap;
485{
486
487 switch (ap->a_command) {
488
489 case 1:
490 { register struct inode *ip;
491 register struct vnode *vp;
492 register struct fs *fs;
493 register struct radvisory *ra;
494 int devBlockSize = 0;
495 int error;
496
497 vp = ap->a_vp;
498
499 ra = (struct radvisory *)(ap->a_data);
500 ip = VTOI(vp);
501 fs = ip->i_fs;
502
503 if ((u_int64_t)ra->ra_offset >= ip->i_size) {
504 return (EFBIG);
505 }
506 devBlockSize = vfs_devblocksize(vnode_mount(vp));
507
508 error = advisory_read(vp, ip->i_size, ra->ra_offset, ra->ra_count);
509
510 return (error);
511 }
512 default:
513 return (ENOTTY);
514 }
515}
516
517int
518ufs_select(__unused struct vnop_select_args *ap)
519{
520 /*
521 * We should really check to see if I/O is possible.
522 */
523 return (1);
524}
525
526/*
527 * Mmap a file
528 *
529 * NB Currently unsupported.
530 */
531int
532ufs_mmap(__unused struct vnop_mmap_args *ap)
533{
534 return (EINVAL);
535}
536
537int
538ufs_remove(ap)
539 struct vnop_remove_args /* {
540 struct vnode *a_dvp;
541 struct vnode *a_vp;
542 struct componentname *a_cnp;
543 int *a_flags;
544 vfs_context_t a_context;
545 } */ *ap;
546{
547 return(ufs_remove_internal(ap->a_dvp, ap->a_vp, ap->a_cnp, ap->a_flags));
548}
549
550
551int
552ufs_remove_internal(vnode_t dvp, vnode_t vp, struct componentname *cnp, int flags)
553{
554 struct inode *ip;
555 struct vnode *tvp;
556 int error;
557
558 if (flags & VNODE_REMOVE_NODELETEBUSY) {
559 /* Caller requested Carbon delete semantics */
560 if (vnode_isinuse(vp, 0)) {
561 error = EBUSY;
562 goto out;
563 }
564 }
565 cnp->cn_flags &= ~MODMASK;
566 cnp->cn_flags |= (WANTPARENT | NOCACHE);
567 cnp->cn_nameiop = DELETE;
568
569 (void) relookup(dvp, &tvp, cnp);
570
571 if (tvp == NULL)
572 return (ENOENT);
573 if (tvp != vp) {
574 /*
575 * The file has already gone away. Somewhat annoying, but that's
576 * life in a threaded world. We need to release the reference we
577 * got, and then return ENOENT.
578 */
579 vnode_put(tvp);
580 return ENOENT;
581 }
582 /*
583 * get rid of reference relookup returned
584 */
585 vnode_put(tvp);
586
587
588 ip = VTOI(vp);
589
590 if ((error = ufs_dirremove(dvp, cnp)) == 0) {
591 ip->i_nlink--;
592 ip->i_flag |= IN_CHANGE;
593 VN_KNOTE(vp, NOTE_DELETE);
594 VN_KNOTE(dvp, NOTE_WRITE);
595 }
596out:
597 return (error);
598}
599
600/*
601 * link vnode call
602 */
603int
604ufs_link(ap)
605 struct vnop_link_args /* {
606 struct vnode *a_vp;
607 struct vnode *a_tdvp;
608 struct componentname *a_cnp;
609 vfs_context_t a_context;
610 } */ *ap;
611{
612 struct vnode *vp = ap->a_vp;
613 struct vnode *tdvp = ap->a_tdvp;
614 struct componentname *cnp = ap->a_cnp;
615 vfs_context_t ctx = cnp->cn_context;
616 struct proc *p = vfs_context_proc(ctx);
617 struct inode *ip;
618 struct timeval tv;
619 int error;
620
621 ip = VTOI(vp);
622
623 if ((nlink_t)ip->i_nlink >= LINK_MAX) {
624 error = EMLINK;
625 goto out1;
626 }
627 ip->i_nlink++;
628 ip->i_flag |= IN_CHANGE;
629 microtime(&tv);
630 error = ffs_update(vp, &tv, &tv, 1);
631 if (!error)
632 error = ufs_direnter(ip, tdvp, cnp);
633 if (error) {
634 ip->i_nlink--;
635 ip->i_flag |= IN_CHANGE;
636 }
637 VN_KNOTE(vp, NOTE_LINK);
638 VN_KNOTE(tdvp, NOTE_WRITE);
639out1:
640 return (error);
641}
642
643/*
644 * whiteout vnode call
645 */
646
647int
648ufs_whiteout(ap)
649 struct vnop_whiteout_args /* {
650 struct vnode *a_dvp;
651 struct componentname *a_cnp;
652 int a_flags;
653 vfs_context_t a_context;
654 } */ *ap;
655{
656 struct vnode *dvp = ap->a_dvp;
657 struct componentname *cnp = ap->a_cnp;
658 struct direct newdir;
659 int error = 0;
660
661 switch (ap->a_flags) {
662 case LOOKUP:
663 /* 4.4 format directories support whiteout operations */
664 if (dvp->v_mount->mnt_maxsymlinklen > 0)
665 return (0);
666 return (ENOTSUP);
667
668 case CREATE:
669 /* create a new directory whiteout */
670#if DIAGNOSTIC
671 if (dvp->v_mount->mnt_maxsymlinklen <= 0)
672 panic("ufs_whiteout: old format filesystem");
673#endif
674
675 newdir.d_ino = WINO;
676 newdir.d_namlen = cnp->cn_namelen;
677 bcopy(cnp->cn_nameptr, newdir.d_name, (unsigned)cnp->cn_namelen + 1);
678 newdir.d_type = DT_WHT;
679 error = ufs_direnter2(dvp, &newdir, cnp->cn_context);
680 break;
681
682 case DELETE:
683 /* remove an existing directory whiteout */
684#if DIAGNOSTIC
685 if (dvp->v_mount->mnt_maxsymlinklen <= 0)
686 panic("ufs_whiteout: old format filesystem");
687#endif
688
689 cnp->cn_flags &= ~DOWHITEOUT;
690 error = ufs_dirremove(dvp, cnp);
691 break;
692 }
693 return (error);
694}
695
696
697/*
698 * Rename system call.
699 * rename("foo", "bar");
700 * is essentially
701 * unlink("bar");
702 * link("foo", "bar");
703 * unlink("foo");
704 * but ``atomically''. Can't do full commit without saving state in the
705 * inode on disk which isn't feasible at this time. Best we can do is
706 * always guarantee the target exists.
707 *
708 * Basic algorithm is:
709 *
710 * 1) Bump link count on source while we're linking it to the
711 * target. This also ensure the inode won't be deleted out
712 * from underneath us while we work (it may be truncated by
713 * a concurrent `trunc' or `open' for creation).
714 * 2) Link source to destination. If destination already exists,
715 * delete it first.
716 * 3) Unlink source reference to inode if still around. If a
717 * directory was moved and the parent of the destination
718 * is different from the source, patch the ".." entry in the
719 * directory.
720 */
721int
722ufs_rename(ap)
723 struct vnop_rename_args /* {
724 struct vnode *a_fdvp;
725 struct vnode *a_fvp;
726 struct componentname *a_fcnp;
727 struct vnode *a_tdvp;
728 struct vnode *a_tvp;
729 struct componentname *a_tcnp;
730 vfs_context_t a_context;
731 } */ *ap;
732{
733 struct vnode *tvp = ap->a_tvp;
734 register struct vnode *tdvp = ap->a_tdvp;
735 struct vnode *fvp = ap->a_fvp;
736 struct vnode *fdvp = ap->a_fdvp;
737 struct componentname *tcnp = ap->a_tcnp;
738 struct componentname *fcnp = ap->a_fcnp;
739 vfs_context_t ctx = fcnp->cn_context;
740 struct proc *p = vfs_context_proc(ctx);
741 struct inode *ip, *xp, *dp;
742 struct dirtemplate dirbuf;
743 struct timeval tv;
744 ino_t doingdirectory = 0, oldparent = 0, newparent = 0;
745 int error = 0, ioflag;
746 u_char namlen;
747 struct vnode *rl_vp = NULL;
748
749
750 /*
751 * Check if just deleting a link name or if we've lost a race.
752 * If another process completes the same rename after we've looked
753 * up the source and have blocked looking up the target, then the
754 * source and target inodes may be identical now although the
755 * names were never linked.
756 */
757 if (fvp == tvp) {
758 if (fvp->v_type == VDIR) {
759 /*
760 * Linked directories are impossible, so we must
761 * have lost the race. Pretend that the rename
762 * completed before the lookup.
763 */
764#ifdef UFS_RENAME_DEBUG
765 printf("ufs_rename: fvp == tvp for directories\n");
766#endif
767 error = ENOENT;
768 goto abortit;
769 }
770
771 /*
772 * don't need to check in here for permissions, must already have been granted
773 * ufs_remove_internal now does the relookup
774 */
775 error = ufs_remove_internal(fdvp, fvp, fcnp, 0);
776
777 return (error);
778 }
779 /*
780 * because the vnode_authorization code may have looked up in this directory
781 * between the original lookup and the actual call to VNOP_RENAME, we need
782 * to reset the directory hints... since we haven't dropped the FSNODELOCK
783 * on tdvp since this whole thing started, we expect relookup to return
784 * tvp (which may be NULL)
785 */
786 tcnp->cn_flags &= ~MODMASK;
787 tcnp->cn_flags |= (WANTPARENT | NOCACHE);
788
789 if ( (error = relookup(tdvp, &rl_vp, tcnp)) )
790 panic("ufs_rename: relookup on target returned error");
791 if (rl_vp != tvp) {
792 /*
793 * Don't panic. The only way this state will be reached is if
794 * another rename has taken effect. In that case, it's safe
795 * to restart this rename and let things sort themselves out.
796 */
797 if (rl_vp)
798 vnode_put(rl_vp);
799 error = ERESTART;
800 goto abortit;
801 }
802 if (rl_vp) {
803 vnode_put(rl_vp);
804 rl_vp = NULL;
805 }
806 dp = VTOI(fdvp);
807 ip = VTOI(fvp);
808
809 if ((ip->i_mode & IFMT) == IFDIR) {
810 if (ip->i_flag & IN_RENAME) {
811 error = EINVAL;
812 goto abortit;
813 }
814 ip->i_flag |= IN_RENAME;
815 oldparent = dp->i_number;
816 doingdirectory++;
817 }
818 VN_KNOTE(fdvp, NOTE_WRITE); /* XXX right place? */
819
820 /*
821 * When the target exists, both the directory
822 * and target vnodes are returned locked.
823 */
824 dp = VTOI(tdvp);
825 xp = NULL;
826 if (tvp)
827 xp = VTOI(tvp);
828
829 /*
830 * 1) Bump link count while we're moving stuff
831 * around. If we crash somewhere before
832 * completing our work, the link count
833 * may be wrong, but correctable.
834 */
835 ip->i_nlink++;
836 ip->i_flag |= IN_CHANGE;
837 microtime(&tv);
838 if ( (error = ffs_update(fvp, &tv, &tv, 1)) ) {
839 goto bad;
840 }
841
842 /*
843 * If ".." must be changed (ie the directory gets a new
844 * parent) then the source directory must not be in the
845 * directory heirarchy above the target, as this would
846 * orphan everything below the source directory. Also
847 * the user must have write permission in the source so
848 * as to be able to change "..". We must repeat the call
849 * to namei, as the parent directory is unlocked by the
850 * call to checkpath().
851 */
852
853 if (oldparent != dp->i_number)
854 newparent = dp->i_number;
855
856 if (doingdirectory && newparent) {
857 if (error) /* write access check above */
858 goto bad;
859
860 if ( (error = ufs_checkpath(ip, dp, vfs_context_ucred(tcnp->cn_context))) )
861 goto bad;
862
863 if ( (error = relookup(tdvp, &tvp, tcnp)) )
864 goto bad;
865 rl_vp = tvp;
866
867 dp = VTOI(tdvp);
868 if (tvp)
869 xp = VTOI(tvp);
870 else
871 xp = NULL;
872 }
873 /*
874 * 2) If target doesn't exist, link the target
875 * to the source and unlink the source.
876 * Otherwise, rewrite the target directory
877 * entry to reference the source inode and
878 * expunge the original entry's existence.
879 */
880 if (xp == NULL) {
881 if (dp->i_dev != ip->i_dev)
882 panic("rename: EXDEV");
883 /*
884 * Account for ".." in new directory.
885 * When source and destination have the same
886 * parent we don't fool with the link count.
887 */
888 if (doingdirectory && newparent) {
889 if ((nlink_t)dp->i_nlink >= LINK_MAX) {
890 error = EMLINK;
891 goto bad;
892 }
893 dp->i_nlink++;
894 dp->i_flag |= IN_CHANGE;
895 if ( (error = ffs_update(tdvp, &tv, &tv, 1)) )
896 goto bad;
897 }
898 if ( (error = ufs_direnter(ip, tdvp, tcnp)) ) {
899 if (doingdirectory && newparent) {
900 dp->i_nlink--;
901 dp->i_flag |= IN_CHANGE;
902 (void)ffs_update(tdvp, &tv, &tv, 1);
903 }
904 goto bad;
905 }
906 VN_KNOTE(tdvp, NOTE_WRITE);
907 } else {
908 if (xp->i_dev != dp->i_dev || xp->i_dev != ip->i_dev)
909 panic("rename: EXDEV");
910 /*
911 * Short circuit rename(foo, foo).
912 */
913 if (xp->i_number == ip->i_number)
914 panic("rename: same file");
915 /*
916 * Target must be empty if a directory and have no links
917 * to it. Also, ensure source and target are compatible
918 * (both directories, or both not directories).
919 */
920 if ((xp->i_mode&IFMT) == IFDIR) {
921 if (!ufs_dirempty(xp, dp->i_number, vfs_context_ucred(tcnp->cn_context)) ||
922 xp->i_nlink > 2) {
923 error = ENOTEMPTY;
924 goto bad;
925 }
926 if (!doingdirectory) {
927 error = ENOTDIR;
928 goto bad;
929 }
930 cache_purge(tdvp);
931 } else if (doingdirectory) {
932 error = EISDIR;
933 goto bad;
934 }
935 if ( (error = ufs_dirrewrite(dp, ip, tcnp)) )
936 goto bad;
937 /*
938 * If the target directory is in the same
939 * directory as the source directory,
940 * decrement the link count on the parent
941 * of the target directory.
942 */
943 if (doingdirectory && !newparent) {
944 dp->i_nlink--;
945 dp->i_flag |= IN_CHANGE;
946 }
947 VN_KNOTE(tdvp, NOTE_WRITE);
948 /*
949 * Adjust the link count of the target to
950 * reflect the dirrewrite above. If this is
951 * a directory it is empty and there are
952 * no links to it, so we can squash the inode and
953 * any space associated with it. We disallowed
954 * renaming over top of a directory with links to
955 * it above, as the remaining link would point to
956 * a directory without "." or ".." entries.
957 */
958 xp->i_nlink--;
959 if (doingdirectory) {
960 if (--xp->i_nlink != 0)
961 panic("rename: linked directory");
962 ioflag = ((tvp)->v_mount->mnt_flag & MNT_ASYNC) ?
963 0 : IO_SYNC;
964 error = ffs_truncate_internal(tvp, (off_t)0, ioflag, vfs_context_ucred(tcnp->cn_context));
965 }
966 xp->i_flag |= IN_CHANGE;
967 VN_KNOTE(tvp, NOTE_DELETE);
968 xp = NULL;
969 }
970 if (rl_vp)
971 vnode_put(rl_vp);
972 rl_vp = NULL;
973
974 /*
975 * 3) Unlink the source.
976 */
977 fcnp->cn_flags &= ~MODMASK;
978 fcnp->cn_flags |= (WANTPARENT | NOCACHE);
979
980 (void) relookup(fdvp, &fvp, fcnp);
981
982 if (fvp != NULL) {
983 xp = VTOI(fvp);
984 dp = VTOI(fdvp);
985 rl_vp = fvp;
986 } else {
987 /*
988 * From name has disappeared.
989 */
990 if (doingdirectory)
991 panic("rename: lost dir entry");
992
993 return (0);
994 }
995 /*
996 * Ensure that the directory entry still exists and has not
997 * changed while the new name has been entered. If the source is
998 * a file then the entry may have been unlinked or renamed. In
999 * either case there is no further work to be done. If the source
1000 * is a directory then it cannot have been rmdir'ed; its link
1001 * count of three would cause a rmdir to fail with ENOTEMPTY.
1002 * The IN_RENAME flag ensures that it cannot be moved by another
1003 * rename.
1004 */
1005 if (xp != ip) {
1006 if (doingdirectory)
1007 panic("rename: lost dir entry");
1008 } else {
1009 /*
1010 * If the source is a directory with a
1011 * new parent, the link count of the old
1012 * parent directory must be decremented
1013 * and ".." set to point to the new parent.
1014 */
1015 if (doingdirectory && newparent) {
1016 dp->i_nlink--;
1017 dp->i_flag |= IN_CHANGE;
1018 error = vn_rdwr(UIO_READ, fvp, (caddr_t)&dirbuf,
1019 sizeof (struct dirtemplate), (off_t)0,
1020 UIO_SYSSPACE32, IO_NODELOCKED,
1021 vfs_context_ucred(tcnp->cn_context), (int *)0, (struct proc *)0);
1022 if (error == 0) {
1023# if (BYTE_ORDER == LITTLE_ENDIAN)
1024 if (fvp->v_mount->mnt_maxsymlinklen <= 0)
1025 namlen = dirbuf.dotdot_type;
1026 else
1027 namlen = dirbuf.dotdot_namlen;
1028# else
1029 namlen = dirbuf.dotdot_namlen;
1030# endif
1031 if (namlen != 2 ||
1032 dirbuf.dotdot_name[0] != '.' ||
1033 dirbuf.dotdot_name[1] != '.') {
1034 ufs_dirbad(xp, (doff_t)12,
1035 "rename: mangled dir");
1036 } else {
1037 dirbuf.dotdot_ino = newparent;
1038 (void) vn_rdwr(UIO_WRITE, fvp,
1039 (caddr_t)&dirbuf,
1040 sizeof (struct dirtemplate),
1041 (off_t)0, UIO_SYSSPACE32,
1042 IO_NODELOCKED|IO_SYNC,
1043 vfs_context_ucred(tcnp->cn_context), (int *)0,
1044 (struct proc *)0);
1045 cache_purge(fdvp);
1046 }
1047 }
1048 }
1049 error = ufs_dirremove(fdvp, fcnp);
1050 if (!error) {
1051 xp->i_nlink--;
1052 xp->i_flag |= IN_CHANGE;
1053 }
1054 xp->i_flag &= ~IN_RENAME;
1055 }
1056 VN_KNOTE(fvp, NOTE_RENAME);
1057
1058 if (rl_vp)
1059 vnode_put(rl_vp);
1060
1061 return (error);
1062
1063bad:
1064 if (rl_vp)
1065 vnode_put(rl_vp);
1066
1067 if (doingdirectory)
1068 ip->i_flag &= ~IN_RENAME;
1069
1070 ip->i_nlink--;
1071 ip->i_flag |= IN_CHANGE;
1072 ip->i_flag &= ~IN_RENAME;
1073
1074abortit:
1075 return (error);
1076}
1077
1078/*
1079 * A virgin directory (no blushing please).
1080 */
1081static struct dirtemplate mastertemplate = {
1082 0, 12, DT_DIR, 1, ".",
1083 0, DIRBLKSIZ - 12, DT_DIR, 2, ".."
1084};
1085static struct odirtemplate omastertemplate = {
1086 0, 12, 1, ".",
1087 0, DIRBLKSIZ - 12, 2, ".."
1088};
1089
1090/*
1091 * Mkdir system call
1092 */
1093int
1094ufs_mkdir(ap)
1095 struct vnop_mkdir_args /* {
1096 struct vnode *a_dvp;
1097 struct vnode **a_vpp;
1098 struct componentname *a_cnp;
1099 struct vnode_attr *a_vap;
1100 vfs_context_t a_context;
1101 } */ *ap;
1102{
1103 register struct vnode *dvp = ap->a_dvp;
1104 register struct vnode_attr *vap = ap->a_vap;
1105 register struct componentname *cnp = ap->a_cnp;
1106 register struct inode *ip, *dp;
1107 struct vnode *tvp;
1108 struct dirtemplate dirtemplate, *dtp;
1109 struct timeval tv;
1110 int error, dmode;
1111
1112 /* use relookup to force correct directory hints */
1113 cnp->cn_flags &= ~MODMASK;
1114 cnp->cn_flags |= (WANTPARENT | NOCACHE);
1115 cnp->cn_nameiop = CREATE;
1116
1117 (void) relookup(dvp, &tvp, cnp);
1118
1119 /* get rid of reference relookup returned */
1120 if (tvp)
1121 vnode_put(tvp);
1122
1123 dp = VTOI(dvp);
1124 if ((nlink_t)dp->i_nlink >= LINK_MAX) {
1125 error = EMLINK;
1126 goto out;
1127 }
1128 dmode = vap->va_mode & 0777;
1129 dmode |= IFDIR;
1130
1131 /*
1132 * Must simulate part of ufs_makeinode here to acquire the inode,
1133 * but not have it entered in the parent directory. The entry is
1134 * made later after writing "." and ".." entries.
1135 */
1136 if ( (error = ffs_valloc(dvp, (mode_t)dmode, vfs_context_ucred(cnp->cn_context), &tvp)) )
1137 goto out;
1138 ip = VTOI(tvp);
1139 ip->i_uid = ap->a_vap->va_uid;
1140 ip->i_gid = ap->a_vap->va_gid;
1141 VATTR_SET_SUPPORTED(ap->a_vap, va_mode);
1142 VATTR_SET_SUPPORTED(ap->a_vap, va_uid);
1143 VATTR_SET_SUPPORTED(ap->a_vap, va_gid);
1144#if QUOTA
1145 if ((error = getinoquota(ip)) ||
1146 (error = chkiq(ip, 1, vfs_context_ucred(cnp->cn_context), 0))) {
1147 ffs_vfree(tvp, ip->i_number, dmode);
1148 vnode_put(tvp);
1149 return (error);
1150 }
1151#endif
1152 ip->i_flag |= IN_ACCESS | IN_CHANGE | IN_UPDATE;
1153 ip->i_mode = dmode;
1154 ip->i_nlink = 2;
1155 if (cnp->cn_flags & ISWHITEOUT)
1156 ip->i_flags |= UF_OPAQUE;
1157 microtime(&tv);
1158 error = ffs_update(tvp, &tv, &tv, 1);
1159
1160 /*
1161 * Bump link count in parent directory
1162 * to reflect work done below. Should
1163 * be done before reference is created
1164 * so reparation is possible if we crash.
1165 */
1166 dp->i_nlink++;
1167 dp->i_flag |= IN_CHANGE;
1168 if ( (error = ffs_update(dvp, &tv, &tv, 1)) )
1169 goto bad;
1170
1171 /* Initialize directory with "." and ".." from static template. */
1172 if (dvp->v_mount->mnt_maxsymlinklen > 0)
1173 dtp = &mastertemplate;
1174 else
1175 dtp = (struct dirtemplate *)&omastertemplate;
1176 dirtemplate = *dtp;
1177 dirtemplate.dot_ino = ip->i_number;
1178 dirtemplate.dotdot_ino = dp->i_number;
1179 error = vn_rdwr(UIO_WRITE, tvp, (caddr_t)&dirtemplate,
1180 sizeof (dirtemplate), (off_t)0, UIO_SYSSPACE32,
1181 IO_NODELOCKED|IO_SYNC, vfs_context_ucred(cnp->cn_context), (int *)0, (struct proc *)0);
1182 if (error) {
1183 dp->i_nlink--;
1184 dp->i_flag |= IN_CHANGE;
1185 goto bad;
1186 }
1187 if (DIRBLKSIZ > VFSTOUFS(dvp->v_mount)->um_mountp->mnt_vfsstat.f_bsize)
1188 panic("ufs_mkdir: blksize"); /* XXX should grow with balloc() */
1189 else {
1190 ip->i_size = DIRBLKSIZ;
1191 ip->i_flag |= IN_CHANGE;
1192 }
1193
1194 /* Directory set up, now install it's entry in the parent directory. */
1195 if ( (error = ufs_direnter(ip, dvp, cnp)) ) {
1196 dp->i_nlink--;
1197 dp->i_flag |= IN_CHANGE;
1198 }
1199bad:
1200 /*
1201 * No need to do an explicit vnop_truncate here, vnode_put will do it
1202 * for us because we set the link count to 0.
1203 */
1204 if (error) {
1205 ip->i_nlink = 0;
1206 ip->i_flag |= IN_CHANGE;
1207 /*
1208 * since we're not returning tvp due to the error,
1209 * we're responsible for releasing it here
1210 */
1211 vnode_put(tvp);
1212 } else {
1213 VN_KNOTE(dvp, NOTE_WRITE | NOTE_LINK);
1214 *ap->a_vpp = tvp;
1215 };
1216out:
1217 return (error);
1218}
1219
1220/*
1221 * Rmdir system call.
1222 */
1223int
1224ufs_rmdir(ap)
1225 struct vnop_rmdir_args /* {
1226 struct vnode *a_dvp;
1227 struct vnode *a_vp;
1228 struct componentname *a_cnp;
1229 vfs_context_t a_context;
1230 } */ *ap;
1231{
1232 struct vnode *vp = ap->a_vp;
1233 struct vnode *dvp = ap->a_dvp;
1234 struct vnode *tvp;
1235 struct componentname *cnp = ap->a_cnp;
1236 struct inode *ip, *dp;
1237 int error, ioflag;
1238
1239
1240 ip = VTOI(vp);
1241 dp = VTOI(dvp);
1242 /*
1243 * No rmdir "." please.
1244 */
1245 if (dp == ip)
1246 return (EINVAL);
1247
1248
1249 cnp->cn_flags &= ~MODMASK;
1250 cnp->cn_flags |= (WANTPARENT | NOCACHE);
1251
1252 (void) relookup(dvp, &tvp, cnp);
1253
1254 if (tvp == NULL)
1255 return (ENOENT);
1256 if (tvp != vp)
1257 panic("ufs_rmdir: relookup returned a different vp");
1258 /*
1259 * get rid of reference relookup returned
1260 */
1261 vnode_put(tvp);
1262
1263
1264 /*
1265 * Verify the directory is empty (and valid).
1266 * (Rmdir ".." won't be valid since
1267 * ".." will contain a reference to
1268 * the current directory and thus be
1269 * non-empty.)
1270 */
1271 error = 0;
1272 if (ip->i_nlink != 2 ||
1273 !ufs_dirempty(ip, dp->i_number, vfs_context_ucred(cnp->cn_context))) {
1274 error = ENOTEMPTY;
1275 goto out;
1276 }
1277 /*
1278 * Delete reference to directory before purging
1279 * inode. If we crash in between, the directory
1280 * will be reattached to lost+found,
1281 */
1282 if ( (error = ufs_dirremove(dvp, cnp)) )
1283 goto out;
1284 VN_KNOTE(dvp, NOTE_WRITE | NOTE_LINK);
1285 dp->i_nlink--;
1286 dp->i_flag |= IN_CHANGE;
1287 cache_purge(dvp);
1288 /*
1289 * Truncate inode. The only stuff left
1290 * in the directory is "." and "..". The
1291 * "." reference is inconsequential since
1292 * we're quashing it. The ".." reference
1293 * has already been adjusted above. We've
1294 * removed the "." reference and the reference
1295 * in the parent directory, but there may be
1296 * other hard links so decrement by 2 and
1297 * worry about them later.
1298 */
1299 ip->i_nlink -= 2;
1300 ioflag = ((vp)->v_mount->mnt_flag & MNT_ASYNC) ? 0 : IO_SYNC;
1301 error = ffs_truncate_internal(vp, (off_t)0, ioflag, vfs_context_ucred(cnp->cn_context));
1302 cache_purge(ITOV(ip));
1303out:
1304 VN_KNOTE(vp, NOTE_DELETE);
1305 return (error);
1306}
1307
1308/*
1309 * symlink -- make a symbolic link
1310 */
1311int
1312ufs_symlink(ap)
1313 struct vnop_symlink_args /* {
1314 struct vnode *a_dvp;
1315 struct vnode **a_vpp;
1316 struct componentname *a_cnp;
1317 struct vnode_attr *a_vap;
1318 char *a_target;
1319 vfs_context_t a_context;
1320 } */ *ap;
1321{
1322 register struct vnode *vp, **vpp = ap->a_vpp;
1323 register struct inode *ip;
1324 int len, error;
1325
1326 if ( (error = ufs_makeinode(ap->a_vap, ap->a_dvp, vpp, ap->a_cnp)) )
1327 return (error);
1328 VN_KNOTE(ap->a_dvp, NOTE_WRITE);
1329 vp = *vpp;
1330 len = strlen(ap->a_target);
1331 if (len < vp->v_mount->mnt_maxsymlinklen) {
1332 ip = VTOI(vp);
1333 bcopy(ap->a_target, (char *)ip->i_shortlink, len);
1334 ip->i_size = len;
1335 ip->i_flag |= IN_CHANGE | IN_UPDATE;
1336 } else
1337 error = vn_rdwr(UIO_WRITE, vp, ap->a_target, len, (off_t)0,
1338 UIO_SYSSPACE32, IO_NODELOCKED, vfs_context_ucred(ap->a_cnp->cn_context), (int *)0,
1339 (struct proc *)0);
1340 return (error);
1341}
1342
1343/*
1344 * Vnode op for reading directories.
1345 *
1346 * The routine below assumes that the on-disk format of a directory
1347 * is the same as that defined by <sys/dirent.h>. If the on-disk
1348 * format changes, then it will be necessary to do a conversion
1349 * from the on-disk format that read returns to the format defined
1350 * by <sys/dirent.h>.
1351 */
1352int
1353ufs_readdir(ap)
1354 struct vnop_readdir_args /* {
1355 struct vnode *a_vp;
1356 struct uio *a_uio;
1357 int a_flags;
1358 int *a_eofflag;
1359 int *a_numdirent;
1360 vfs_context_t a_context;
1361 } */ *ap;
1362{
1363 struct uio *uio = ap->a_uio;
1364 int error;
1365 size_t count, lost;
1366
1367 if (ap->a_flags & VNODE_READDIR_EXTENDED) {
1368 return ufs_readdirext(ap->a_vp, uio, ap->a_eofflag,
1369 ap->a_numdirent, ap->a_context);
1370 }
1371
1372 // LP64todo - fix this
1373 count = uio_resid(uio);
1374 /* Make sure we don't return partial entries. */
1375 count -= (uio->uio_offset + count) & (DIRBLKSIZ -1);
1376 if (count <= 0)
1377 return (EINVAL);
1378 // LP64todo - fix this
1379 lost = uio_resid(uio) - count;
1380 uio_setresid(uio, count);
1381 uio_iov_len_set(uio, count);
1382# if (BYTE_ORDER == LITTLE_ENDIAN)
1383 if (ap->a_vp->v_mount->mnt_maxsymlinklen > 0) {
1384 error = ffs_read_internal(ap->a_vp, uio, 0);
1385 } else {
1386 struct dirent *dp, *edp;
1387 struct uio auio;
1388 struct iovec_32 aiov;
1389 caddr_t dirbuf;
1390 int readcnt;
1391 u_char tmp;
1392
1393 auio = *uio;
1394 auio.uio_iovs.iov32p = &aiov;
1395 auio.uio_iovcnt = 1;
1396#if 1 /* LP64todo - can't use new segment flags until the drivers are ready */
1397 auio.uio_segflg = UIO_SYSSPACE;
1398#else
1399 auio.uio_segflg = UIO_SYSSPACE32;
1400#endif
1401 aiov.iov_len = count;
1402 MALLOC(dirbuf, caddr_t, count, M_TEMP, M_WAITOK);
1403 aiov.iov_base = (uintptr_t)dirbuf;
1404 error = ffs_read_internal(ap->a_vp, &auio, 0);
1405 if (error == 0) {
1406 // LP64todo - fix this
1407 readcnt = count - uio_resid(&auio);
1408 edp = (struct dirent *)&dirbuf[readcnt];
1409 for (dp = (struct dirent *)dirbuf; dp < edp; ) {
1410 tmp = dp->d_namlen;
1411 dp->d_namlen = dp->d_type;
1412 dp->d_type = tmp;
1413 if (dp->d_reclen > 0) {
1414 dp = (struct dirent *)
1415 ((char *)dp + dp->d_reclen);
1416 } else {
1417 error = EIO;
1418 break;
1419 }
1420 }
1421 if (dp >= edp)
1422 error = uiomove(dirbuf, readcnt, uio);
1423 }
1424 FREE(dirbuf, M_TEMP);
1425 }
1426# else
1427 error = ffs_read_internal(ap->a_vp, uio, 0);
1428# endif
1429
1430 uio_setresid(uio, (uio_resid(uio) + lost));
1431 if (ap->a_eofflag)
1432 *ap->a_eofflag = (off_t)VTOI(ap->a_vp)->i_size <= uio->uio_offset;
1433 return (error);
1434}
1435
1436
1437/*
1438 * ufs_readdirext reads directory entries into the buffer pointed
1439 * to by uio, in a filesystem independent format. Up to uio_resid
1440 * bytes of data can be transferred. The data in the buffer is a
1441 * series of packed direntry structures where each one contains the
1442 * following entries:
1443 *
1444 * d_reclen: length of record
1445 * d_ino: file number of entry
1446 * d_seekoff: seek offset (used by NFS server, aka cookie)
1447 * d_type: file type
1448 * d_namlen: length of string in d_name
1449 * d_name: null terminated file name
1450 *
1451 * The current position (uio_offset) refers to the next block of
1452 * entries. The offset will only be set to a value previously
1453 * returned by ufs_readdirext or zero. This offset does not have
1454 * to match the number of bytes returned (in uio_resid).
1455 */
1456#define EXT_DIRENT_LEN(namlen) \
1457 ((sizeof(struct direntry) + (namlen) - (MAXPATHLEN-1) + 3) & ~3)
1458
1459static int
1460ufs_readdirext(vnode_t vp, uio_t uio, int *eofflag, int *numdirent,
1461 __unused vfs_context_t context)
1462{
1463 int error;
1464 size_t count, lost;
1465 off_t off = uio->uio_offset;
1466 struct dirent *dp, *edp;
1467 struct uio auio;
1468 struct iovec_32 aiov;
1469 caddr_t dirbuf;
1470 struct direntry *xdp;
1471 int nentries = 0;
1472
1473 // LP64todo - fix this
1474 count = uio_resid(uio);
1475 /* Make sure we don't return partial entries. */
1476 count -= (uio->uio_offset + count) & (DIRBLKSIZ -1);
1477 if (count <= 0)
1478 return (EINVAL);
1479 // LP64todo - fix this
1480 lost = uio_resid(uio) - count;
1481 uio_setresid(uio, count);
1482 uio_iov_len_set(uio, count);
1483
1484 auio = *uio;
1485 auio.uio_iovs.iov32p = &aiov;
1486 auio.uio_iovcnt = 1;
1487 /* LP64todo - can't use new segment flags until the drivers are ready */
1488 auio.uio_segflg = UIO_SYSSPACE;
1489 aiov.iov_len = count;
1490 MALLOC(dirbuf, caddr_t, count, M_TEMP, M_WAITOK);
1491 aiov.iov_base = (uintptr_t)dirbuf;
1492
1493 MALLOC(xdp, struct direntry *, sizeof(struct direntry), M_TEMP, M_WAITOK);
1494
1495 error = ffs_read_internal(vp, &auio, 0);
1496 if (error)
1497 goto out;
1498
1499 // LP64todo - fix this
1500 edp = (struct dirent *)&dirbuf[count - uio_resid(&auio)];
1501 for (dp = (struct dirent *)dirbuf; dp < edp; ) {
1502
1503#if (BYTE_ORDER == LITTLE_ENDIAN)
1504 u_char tmp;
1505
1506 /*
1507 * We only need to swap the d_namlen and
1508 * d_type fields for older versions of UFS,
1509 * which we check by looking at the mnt_maxsymlinklen
1510 * field.
1511 */
1512 if (vp->v_mount->mnt_maxsymlinklen <= 0) {
1513 tmp = dp->d_namlen;
1514 dp->d_namlen = dp->d_type;
1515 dp->d_type = tmp;
1516 }
1517#endif
1518
1519 xdp->d_reclen = EXT_DIRENT_LEN(dp->d_namlen);
1520 if (xdp->d_reclen > uio_resid(uio)) {
1521 break; /* user buffer is full */
1522 }
1523 xdp->d_ino = dp->d_ino;
1524 xdp->d_namlen = dp->d_namlen;
1525 xdp->d_type = dp->d_type;
1526
1527 bcopy(dp->d_name, xdp->d_name, dp->d_namlen + 1);
1528 off += dp->d_reclen;
1529 xdp->d_seekoff = off;
1530 error = uiomove((caddr_t)xdp, xdp->d_reclen, uio);
1531 if (error) {
1532 off -= dp->d_reclen;
1533 break; /* unexpected this error is */
1534 }
1535 nentries++;
1536
1537 if (dp->d_reclen > 0) {
1538 dp = (struct dirent *)
1539 ((char *)dp + dp->d_reclen);
1540 } else {
1541 error = EIO;
1542 break;
1543 }
1544 }
1545out:
1546 FREE(dirbuf, M_TEMP);
1547 FREE(xdp, M_TEMP);
1548
1549 /* Use the on-disk dirent offset */
1550 uio_setoffset(uio, off);
1551 *numdirent = nentries;
1552 uio_setresid(uio, (uio_resid(uio) + lost));
1553 if (eofflag)
1554 *eofflag = (off_t)VTOI(vp)->i_size <= uio->uio_offset;
1555 return (error);
1556}
1557
1558
1559/*
1560 * Return target name of a symbolic link
1561 */
1562int
1563ufs_readlink(ap)
1564 struct vnop_readlink_args /* {
1565 struct vnode *a_vp;
1566 struct uio *a_uio;
1567 vfs_context_t a_context;
1568 } */ *ap;
1569{
1570 register struct vnode *vp = ap->a_vp;
1571 register struct inode *ip = VTOI(vp);
1572 int isize;
1573
1574 isize = ip->i_size;
1575 if (isize < vp->v_mount->mnt_maxsymlinklen) {
1576 uiomove((char *)ip->i_shortlink, isize, ap->a_uio);
1577 return (0);
1578 }
1579 return (ffs_read_internal(vp, ap->a_uio, 0));
1580}
1581
1582/*
1583 * prepare and issue the I/O
1584 */
1585errno_t
1586ufs_strategy(ap)
1587 struct vnop_strategy_args /* {
1588 struct buf *a_bp;
1589 } */ *ap;
1590{
1591 buf_t bp = ap->a_bp;
1592 vnode_t vp = buf_vnode(bp);
1593 struct inode *ip = VTOI(vp);
1594
1595 return (buf_strategy(ip->i_devvp, ap));
1596}
1597
1598/*
1599 * Read wrapper for special devices.
1600 */
1601int
1602ufsspec_read(ap)
1603 struct vnop_read_args /* {
1604 struct vnode *a_vp;
1605 struct uio *a_uio;
1606 int a_ioflag;
1607 vfs_context_t a_context;
1608 } */ *ap;
1609{
1610
1611 /*
1612 * Set access flag.
1613 */
1614 VTOI(ap->a_vp)->i_flag |= IN_ACCESS;
1615 return (VOCALL (spec_vnodeop_p, VOFFSET(vnop_read), ap));
1616}
1617
1618/*
1619 * Write wrapper for special devices.
1620 */
1621int
1622ufsspec_write(
1623 struct vnop_write_args /* {
1624 struct vnode *a_vp;
1625 struct uio *a_uio;
1626 int a_ioflag;
1627 kauth_cred_t a_cred;
1628 } */ *ap)
1629{
1630
1631 /*
1632 * Set update and change flags.
1633 */
1634 VTOI(ap->a_vp)->i_flag |= IN_CHANGE | IN_UPDATE;
1635 return (VOCALL (spec_vnodeop_p, VOFFSET(vnop_write), ap));
1636}
1637
1638/*
1639 * Close wrapper for special devices.
1640 *
1641 * Update the times on the inode then do device close.
1642 */
1643int
1644ufsspec_close(ap)
1645 struct vnop_close_args /* {
1646 struct vnode *a_vp;
1647 int a_fflag;
1648 vfs_context_t a_context;
1649 } */ *ap;
1650{
1651 struct vnode *vp = ap->a_vp;
1652 struct inode *ip = VTOI(vp);
1653 struct timeval tv;
1654
1655 if (ap->a_vp->v_usecount > 1) {
1656 microtime(&tv);
1657 ITIMES(ip, &tv, &tv);
1658 }
1659 return (VOCALL (spec_vnodeop_p, VOFFSET(vnop_close), ap));
1660}
1661
1662#if FIFO
1663/*
1664 * Read wrapper for fifo's
1665 */
1666int
1667ufsfifo_read(ap)
1668 struct vnop_read_args /* {
1669 struct vnode *a_vp;
1670 struct uio *a_uio;
1671 int a_ioflag;
1672 vfs_context_t a_context;
1673 } */ *ap;
1674{
1675 extern int (**fifo_vnodeop_p)(void *);
1676
1677 /*
1678 * Set access flag.
1679 */
1680 VTOI(ap->a_vp)->i_flag |= IN_ACCESS;
1681 return (VOCALL (fifo_vnodeop_p, VOFFSET(vnop_read), ap));
1682}
1683
1684/*
1685 * Write wrapper for fifo's.
1686 */
1687int
1688ufsfifo_write(
1689 struct vnop_write_args /* {
1690 struct vnode *a_vp;
1691 struct uio *a_uio;
1692 int a_ioflag;
1693 kauth_cred_t a_cred;
1694 } */ *ap)
1695{
1696 extern int (**fifo_vnodeop_p)(void *);
1697
1698 /*
1699 * Set update and change flags.
1700 */
1701 VTOI(ap->a_vp)->i_flag |= IN_CHANGE | IN_UPDATE;
1702 return (VOCALL (fifo_vnodeop_p, VOFFSET(vnop_write), ap));
1703}
1704
1705/*
1706 * Close wrapper for fifo's.
1707 *
1708 * Update the times on the inode then do device close.
1709 */
1710int
1711ufsfifo_close(ap)
1712 struct vnop_close_args /* {
1713 struct vnode *a_vp;
1714 int a_fflag;
1715 vfs_context_t a_context;
1716 } */ *ap;
1717{
1718 extern int (**fifo_vnodeop_p)(void *);
1719 struct vnode *vp = ap->a_vp;
1720 struct inode *ip = VTOI(vp);
1721 struct timeval tv;
1722
1723 if (ap->a_vp->v_usecount > 1) {
1724 microtime(&tv);
1725 ITIMES(ip, &tv, &tv);
1726 }
1727 return (VOCALL (fifo_vnodeop_p, VOFFSET(vnop_close), ap));
1728}
1729
1730/*
1731 * kqfilt_add wrapper for fifos.
1732 *
1733 * Fall through to ufs kqfilt_add routines if needed
1734 */
1735int
1736ufsfifo_kqfilt_add(ap)
1737 struct vnop_kqfilt_add_args *ap;
1738{
1739 extern int (**fifo_vnodeop_p)(void *);
1740 int error;
1741
1742 error = VOCALL(fifo_vnodeop_p, VOFFSET(vnop_kqfilt_add), ap);
1743 if (error)
1744 error = ufs_kqfilt_add(ap);
1745 return (error);
1746}
1747
1748#if 0
1749/*
1750 * kqfilt_remove wrapper for fifos.
1751 *
1752 * Fall through to ufs kqfilt_remove routines if needed
1753 */
1754int
1755ufsfifo_kqfilt_remove(ap)
1756 struct vnop_kqfilt_remove_args *ap;
1757{
1758 extern int (**fifo_vnodeop_p)(void *);
1759 int error;
1760
1761 error = VOCALL(fifo_vnodeop_p, VOFFSET(vnop_kqfilt_remove), ap);
1762 if (error)
1763 error = ufs_kqfilt_remove(ap);
1764 return (error);
1765}
1766#endif
1767
1768#endif /* FIFO */
1769
1770
1771static struct filterops ufsread_filtops =
1772 { 1, NULL, filt_ufsdetach, filt_ufsread };
1773static struct filterops ufswrite_filtops =
1774 { 1, NULL, filt_ufsdetach, filt_ufswrite };
1775static struct filterops ufsvnode_filtops =
1776 { 1, NULL, filt_ufsdetach, filt_ufsvnode };
1777
1778/*
1779 #
1780 #% kqfilt_add vp L L L
1781 #
1782 vnop_kqfilt_add
1783 IN struct vnode *vp;
1784 IN struct knote *kn;
1785 IN vfs_context_t context;
1786 */
1787int
1788ufs_kqfilt_add(ap)
1789 struct vnop_kqfilt_add_args /* {
1790 struct vnode *a_vp;
1791 struct knote *a_kn;
1792 vfs_context_t a_context;
1793 } */ *ap;
1794{
1795 struct vnode *vp = ap->a_vp;
1796 struct knote *kn = ap->a_kn;
1797
1798 switch (kn->kn_filter) {
1799 case EVFILT_READ:
1800 kn->kn_fop = &ufsread_filtops;
1801 break;
1802 case EVFILT_WRITE:
1803 kn->kn_fop = &ufswrite_filtops;
1804 break;
1805 case EVFILT_VNODE:
1806 kn->kn_fop = &ufsvnode_filtops;
1807 break;
1808 default:
1809 return (1);
1810 }
1811
1812 kn->kn_hook = (caddr_t)vp;
1813 kn->kn_hookid = vnode_vid(vp);
1814
1815 KNOTE_ATTACH(&VTOI(vp)->i_knotes, kn);
1816
1817 return (0);
1818}
1819
1820static void
1821filt_ufsdetach(struct knote *kn)
1822{
1823 struct vnode *vp;
1824 int result;
1825 struct proc *p = current_proc();
1826
1827 vp = (struct vnode *)kn->kn_hook;
1828
1829 if (vnode_getwithvid(vp, kn->kn_hookid))
1830 return;
1831
1832 result = KNOTE_DETACH(&VTOI(vp)->i_knotes, kn);
1833 vnode_put(vp);
1834}
1835
1836static int
1837filt_ufsread(struct knote *kn, long hint)
1838{
1839 struct vnode *vp = (struct vnode *)kn->kn_hook;
1840 struct inode *ip;
1841 int dropvp = 0;
1842 int result;
1843
1844 if (hint == 0) {
1845 if ((vnode_getwithvid(vp, kn->kn_hookid) != 0)) {
1846 hint = NOTE_REVOKE;
1847 } else
1848 dropvp = 1;
1849 }
1850 if (hint == NOTE_REVOKE) {
1851 /*
1852 * filesystem is gone, so set the EOF flag and schedule
1853 * the knote for deletion.
1854 */
1855 kn->kn_flags |= (EV_EOF | EV_ONESHOT);
1856 return (1);
1857 }
1858
1859 /* poll(2) semantics dictate always returning true */
1860 if (kn->kn_flags & EV_POLL) {
1861 kn->kn_data = 1;
1862 result = 1;
1863 } else {
1864 off_t amount;
1865
1866 ip = VTOI(vp);
1867 amount = ip->i_size - kn->kn_fp->f_fglob->fg_offset;
1868 if (amount > (off_t)INTPTR_MAX)
1869 kn->kn_data = INTPTR_MAX;
1870 else if (amount < (off_t)INTPTR_MIN)
1871 kn->kn_data = INTPTR_MIN;
1872 else
1873 kn->kn_data = (intptr_t)amount;
1874 result = (kn->kn_data != 0);
1875 }
1876
1877 if (dropvp)
1878 vnode_put(vp);
1879
1880 return (result);
1881}
1882
1883static int
1884filt_ufswrite(struct knote *kn, long hint)
1885{
1886
1887 int dropvp = 0;
1888 int result;
1889
1890 if (hint == 0) {
1891 if ((vnode_getwithvid(kn->kn_hook, kn->kn_hookid) != 0)) {
1892 hint = NOTE_REVOKE;
1893 } else
1894 vnode_put(kn->kn_hook);
1895 }
1896 if (hint == NOTE_REVOKE) {
1897 /*
1898 * filesystem is gone, so set the EOF flag and schedule
1899 * the knote for deletion.
1900 */
1901 kn->kn_data = 0;
1902 kn->kn_flags |= (EV_EOF | EV_ONESHOT);
1903 return (1);
1904 }
1905 kn->kn_data = 0;
1906 return (1);
1907}
1908
1909static int
1910filt_ufsvnode(struct knote *kn, long hint)
1911{
1912
1913 if (hint == 0) {
1914 if ((vnode_getwithvid(kn->kn_hook, kn->kn_hookid) != 0)) {
1915 hint = NOTE_REVOKE;
1916 } else
1917 vnode_put(kn->kn_hook);
1918 }
1919 if (kn->kn_sfflags & hint)
1920 kn->kn_fflags |= hint;
1921 if ((hint == NOTE_REVOKE)) {
1922 kn->kn_flags |= (EV_EOF | EV_ONESHOT);
1923 return (1);
1924 }
1925
1926 return (kn->kn_fflags != 0);
1927}
1928
1929/*
1930 * Return POSIX pathconf information applicable to ufs filesystems.
1931 */
1932int
1933ufs_pathconf(ap)
1934 struct vnop_pathconf_args /* {
1935 struct vnode *a_vp;
1936 int a_name;
1937 int *a_retval;
1938 vfs_context_t a_context;
1939 } */ *ap;
1940{
1941
1942 switch (ap->a_name) {
1943 case _PC_LINK_MAX:
1944 *ap->a_retval = LINK_MAX;
1945 return (0);
1946 case _PC_NAME_MAX:
1947 *ap->a_retval = NAME_MAX;
1948 return (0);
1949 case _PC_PATH_MAX:
1950 *ap->a_retval = PATH_MAX;
1951 return (0);
1952 case _PC_PIPE_BUF:
1953 *ap->a_retval = PIPE_BUF;
1954 return (0);
1955 case _PC_CHOWN_RESTRICTED:
1956 *ap->a_retval = 200112; /* _POSIX_CHOWN_RESTRICTED */
1957 return (0);
1958 case _PC_NO_TRUNC:
1959 *ap->a_retval = 200112; /* _POSIX_NO_TRUNC */
1960 return (0);
1961 case _PC_FILESIZEBITS:
1962 *ap->a_retval = 34;
1963 return (0);
1964
1965 default:
1966 return (EINVAL);
1967 }
1968 /* NOTREACHED */
1969}
1970
1971/*
1972 * Allocate a new inode.
1973 */
1974int
1975ufs_makeinode(vap, dvp, vpp, cnp)
1976 struct vnode_attr *vap;
1977 struct vnode *dvp;
1978 struct vnode **vpp;
1979 struct componentname *cnp;
1980{
1981 register struct inode *ip, *pdir;
1982 struct timeval tv;
1983 struct vnode *tvp;
1984 int error;
1985 int is_member;
1986 int mode;
1987
1988 mode = MAKEIMODE(vap->va_type, vap->va_mode);
1989 pdir = VTOI(dvp);
1990 *vpp = NULL;
1991 if ((mode & IFMT) == 0)
1992 mode |= IFREG;
1993
1994 if ( (error = ffs_valloc(dvp, (mode_t)mode, vfs_context_ucred(cnp->cn_context), &tvp)) )
1995 return (error);
1996
1997 ip = VTOI(tvp);
1998 ip->i_gid = vap->va_gid;
1999 ip->i_uid = vap->va_uid;
2000 VATTR_SET_SUPPORTED(vap, va_mode);
2001 VATTR_SET_SUPPORTED(vap, va_uid);
2002 VATTR_SET_SUPPORTED(vap, va_gid);
2003#if QUOTA
2004 if ((error = getinoquota(ip)) ||
2005 (error = chkiq(ip, 1, vfs_context_ucred(cnp->cn_context), 0))) {
2006 ffs_vfree(tvp, ip->i_number, mode);
2007 vnode_put(tvp);
2008 return (error);
2009 }
2010#endif
2011 ip->i_flag |= IN_ACCESS | IN_CHANGE | IN_UPDATE;
2012 ip->i_mode = mode;
2013 ip->i_nlink = 1;
2014
2015 if (cnp->cn_flags & ISWHITEOUT)
2016 ip->i_flags |= UF_OPAQUE;
2017
2018 /*
2019 * Make sure inode goes to disk before directory entry.
2020 */
2021 microtime(&tv);
2022 if ( (error = ffs_update(tvp, &tv, &tv, 1)) )
2023 goto bad;
2024 if ( (error = ufs_direnter(ip, dvp, cnp)) )
2025 goto bad;
2026
2027 *vpp = tvp;
2028 return (0);
2029
2030bad:
2031 /*
2032 * Write error occurred trying to update the inode
2033 * or the directory so must deallocate the inode.
2034 */
2035 ip->i_nlink = 0;
2036 ip->i_flag |= IN_CHANGE;
2037 vnode_put(tvp);
2038
2039 return (error);
2040}
2041