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