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