Line data Source code
1 : /* $OpenBSD: ufs_vnops.c,v 1.142 2018/06/21 14:17:23 visa Exp $ */
2 : /* $NetBSD: ufs_vnops.c,v 1.18 1996/05/11 18:28:04 mycroft Exp $ */
3 :
4 : /*
5 : * Copyright (c) 1982, 1986, 1989, 1993
6 : * The Regents of the University of California. All rights reserved.
7 : * (c) UNIX System Laboratories, Inc.
8 : * All or some portions of this file are derived from material licensed
9 : * to the University of California by American Telephone and Telegraph
10 : * Co. or Unix System Laboratories, Inc. and are reproduced herein with
11 : * the permission of UNIX System Laboratories, Inc.
12 : *
13 : * Redistribution and use in source and binary forms, with or without
14 : * modification, are permitted provided that the following conditions
15 : * are met:
16 : * 1. Redistributions of source code must retain the above copyright
17 : * notice, this list of conditions and the following disclaimer.
18 : * 2. Redistributions in binary form must reproduce the above copyright
19 : * notice, this list of conditions and the following disclaimer in the
20 : * documentation and/or other materials provided with the distribution.
21 : * 3. Neither the name of the University nor the names of its contributors
22 : * may be used to endorse or promote products derived from this software
23 : * without specific prior written permission.
24 : *
25 : * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
26 : * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27 : * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28 : * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
29 : * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30 : * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31 : * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32 : * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33 : * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34 : * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35 : * SUCH DAMAGE.
36 : *
37 : * @(#)ufs_vnops.c 8.14 (Berkeley) 10/26/94
38 : */
39 :
40 : #include <sys/param.h>
41 : #include <sys/systm.h>
42 : #include <sys/namei.h>
43 : #include <sys/resourcevar.h>
44 : #include <sys/kernel.h>
45 : #include <sys/fcntl.h>
46 : #include <sys/file.h>
47 : #include <sys/stat.h>
48 : #include <sys/buf.h>
49 : #include <sys/proc.h>
50 : #include <sys/mount.h>
51 : #include <sys/vnode.h>
52 : #include <sys/malloc.h>
53 : #include <sys/pool.h>
54 : #include <sys/dirent.h>
55 : #include <sys/lockf.h>
56 : #include <sys/event.h>
57 : #include <sys/poll.h>
58 : #include <sys/specdev.h>
59 : #include <sys/unistd.h>
60 :
61 : #include <miscfs/fifofs/fifo.h>
62 :
63 : #include <ufs/ufs/quota.h>
64 : #include <ufs/ufs/inode.h>
65 : #include <ufs/ufs/dir.h>
66 : #include <ufs/ufs/ufsmount.h>
67 : #include <ufs/ufs/ufs_extern.h>
68 : #ifdef UFS_DIRHASH
69 : #include <ufs/ufs/dirhash.h>
70 : #endif
71 : #include <ufs/ext2fs/ext2fs_extern.h>
72 :
73 : #include <uvm/uvm_extern.h>
74 :
75 : int ufs_chmod(struct vnode *, int, struct ucred *, struct proc *);
76 : int ufs_chown(struct vnode *, uid_t, gid_t, struct ucred *, struct proc *);
77 : int filt_ufsread(struct knote *, long);
78 : int filt_ufswrite(struct knote *, long);
79 : int filt_ufsvnode(struct knote *, long);
80 : void filt_ufsdetach(struct knote *);
81 :
82 : /*
83 : * A virgin directory (no blushing please).
84 : */
85 : static struct dirtemplate mastertemplate = {
86 : 0, 12, DT_DIR, 1, ".",
87 : 0, DIRBLKSIZ - 12, DT_DIR, 2, ".."
88 : };
89 : static struct odirtemplate omastertemplate = {
90 : 0, 12, 1, ".",
91 : 0, DIRBLKSIZ - 12, 2, ".."
92 : };
93 :
94 : /*
95 : * Update the times in the inode
96 : */
97 : void
98 0 : ufs_itimes(struct vnode *vp)
99 : {
100 : struct inode *ip;
101 0 : struct timespec ts;
102 :
103 0 : ip = VTOI(vp);
104 0 : if ((ip->i_flag & (IN_ACCESS | IN_CHANGE | IN_UPDATE)) == 0)
105 0 : return;
106 :
107 0 : if (vp->v_mount->mnt_flag & MNT_RDONLY)
108 : goto out;
109 :
110 : #ifdef EXT2FS
111 0 : if (IS_EXT2_VNODE(ip->i_vnode)) {
112 0 : EXT2FS_ITIMES(ip);
113 : goto out;
114 : }
115 : #endif
116 :
117 0 : if ((vp->v_type == VBLK || vp->v_type == VCHR) && !DOINGSOFTDEP(vp))
118 0 : ip->i_flag |= IN_LAZYMOD;
119 : else
120 0 : ip->i_flag |= IN_MODIFIED;
121 :
122 0 : getnanotime(&ts);
123 0 : if (ip->i_flag & IN_ACCESS) {
124 0 : DIP_ASSIGN(ip, atime, ts.tv_sec);
125 0 : DIP_ASSIGN(ip, atimensec, ts.tv_nsec);
126 : }
127 0 : if (ip->i_flag & IN_UPDATE) {
128 0 : DIP_ASSIGN(ip, mtime, ts.tv_sec);
129 0 : DIP_ASSIGN(ip, mtimensec, ts.tv_nsec);
130 : }
131 0 : if (ip->i_flag & IN_CHANGE) {
132 0 : DIP_ASSIGN(ip, ctime, ts.tv_sec);
133 0 : DIP_ASSIGN(ip, ctimensec, ts.tv_nsec);
134 0 : ip->i_modrev++;
135 0 : }
136 :
137 : out:
138 0 : ip->i_flag &= ~(IN_ACCESS | IN_CHANGE | IN_UPDATE);
139 0 : }
140 :
141 :
142 : /*
143 : * Create a regular file
144 : */
145 : int
146 0 : ufs_create(void *v)
147 : {
148 0 : struct vop_create_args *ap = v;
149 : int error;
150 :
151 : error =
152 0 : ufs_makeinode(MAKEIMODE(ap->a_vap->va_type, ap->a_vap->va_mode),
153 0 : ap->a_dvp, ap->a_vpp, ap->a_cnp);
154 0 : if (error == 0)
155 0 : VN_KNOTE(ap->a_dvp, NOTE_WRITE);
156 0 : return (error);
157 : }
158 :
159 : /*
160 : * Mknod vnode call
161 : */
162 : int
163 0 : ufs_mknod(void *v)
164 : {
165 0 : struct vop_mknod_args *ap = v;
166 0 : struct vattr *vap = ap->a_vap;
167 0 : struct vnode **vpp = ap->a_vpp;
168 : struct inode *ip;
169 : int error;
170 :
171 0 : if ((error =
172 0 : ufs_makeinode(MAKEIMODE(vap->va_type, vap->va_mode),
173 0 : ap->a_dvp, vpp, ap->a_cnp)) != 0)
174 0 : return (error);
175 0 : VN_KNOTE(ap->a_dvp, NOTE_WRITE);
176 0 : ip = VTOI(*vpp);
177 0 : ip->i_flag |= IN_ACCESS | IN_CHANGE | IN_UPDATE;
178 0 : if (vap->va_rdev != VNOVAL) {
179 : /*
180 : * Want to be able to use this to make badblock
181 : * inodes, so don't truncate the dev number.
182 : */
183 0 : DIP_ASSIGN(ip, rdev, vap->va_rdev);
184 : }
185 : /*
186 : * Remove inode so that it will be reloaded by VFS_VGET and
187 : * checked to see if it is an alias of an existing entry in
188 : * the inode cache.
189 : */
190 0 : vput(*vpp);
191 0 : (*vpp)->v_type = VNON;
192 0 : vgone(*vpp);
193 0 : *vpp = NULL;
194 0 : return (0);
195 0 : }
196 :
197 : /*
198 : * Open called.
199 : *
200 : * Nothing to do.
201 : */
202 : int
203 0 : ufs_open(void *v)
204 : {
205 0 : struct vop_open_args *ap = v;
206 0 : struct inode *ip = VTOI(ap->a_vp);
207 :
208 : /*
209 : * Files marked append-only must be opened for appending.
210 : */
211 0 : if ((DIP(ip, flags) & APPEND) &&
212 0 : (ap->a_mode & (FWRITE | O_APPEND)) == FWRITE)
213 0 : return (EPERM);
214 :
215 0 : if (ap->a_mode & O_TRUNC)
216 0 : ip->i_flag |= IN_CHANGE | IN_UPDATE;
217 :
218 0 : return (0);
219 0 : }
220 :
221 : /*
222 : * Close called.
223 : *
224 : * Update the times on the inode.
225 : */
226 : int
227 0 : ufs_close(void *v)
228 : {
229 0 : struct vop_close_args *ap = v;
230 0 : struct vnode *vp = ap->a_vp;
231 :
232 0 : if (vp->v_usecount > 1)
233 0 : ufs_itimes(vp);
234 0 : return (0);
235 : }
236 :
237 : int
238 0 : ufs_access(void *v)
239 : {
240 0 : struct vop_access_args *ap = v;
241 0 : struct vnode *vp = ap->a_vp;
242 0 : struct inode *ip = VTOI(vp);
243 0 : mode_t mode = ap->a_mode;
244 :
245 : /*
246 : * Disallow write attempts on read-only file systems;
247 : * unless the file is a socket, fifo, or a block or
248 : * character device resident on the file system.
249 : */
250 0 : if (mode & VWRITE) {
251 0 : switch (vp->v_type) {
252 : int error;
253 : case VDIR:
254 : case VLNK:
255 : case VREG:
256 0 : if (vp->v_mount->mnt_flag & MNT_RDONLY)
257 0 : return (EROFS);
258 :
259 0 : if ((error = getinoquota(ip)) != 0)
260 0 : return (error);
261 : break;
262 : case VBAD:
263 : case VBLK:
264 : case VCHR:
265 : case VSOCK:
266 : case VFIFO:
267 : case VNON:
268 : break;
269 :
270 : }
271 : }
272 :
273 : /* If immutable bit set, nobody gets to write it. */
274 0 : if ((mode & VWRITE) && (DIP(ip, flags) & IMMUTABLE))
275 0 : return (EPERM);
276 :
277 0 : if ((vp->v_mount->mnt_flag & MNT_NOPERM) &&
278 0 : (vp->v_flag & VROOT) == 0)
279 0 : return (0);
280 :
281 0 : return (vaccess(vp->v_type, DIP(ip, mode), DIP(ip, uid), DIP(ip, gid),
282 0 : mode, ap->a_cred));
283 0 : }
284 :
285 : int
286 0 : ufs_getattr(void *v)
287 : {
288 0 : struct vop_getattr_args *ap = v;
289 0 : struct vnode *vp = ap->a_vp;
290 0 : struct inode *ip = VTOI(vp);
291 0 : struct vattr *vap = ap->a_vap;
292 :
293 0 : ufs_itimes(vp);
294 :
295 : /*
296 : * Copy from inode table
297 : */
298 0 : vap->va_fsid = ip->i_dev;
299 0 : vap->va_fileid = ip->i_number;
300 0 : vap->va_mode = DIP(ip, mode) & ~IFMT;
301 0 : vap->va_nlink = ip->i_effnlink;
302 0 : vap->va_uid = DIP(ip, uid);
303 0 : vap->va_gid = DIP(ip, gid);
304 0 : vap->va_rdev = (dev_t) DIP(ip, rdev);
305 0 : vap->va_size = DIP(ip, size);
306 0 : vap->va_atime.tv_sec = DIP(ip, atime);
307 0 : vap->va_atime.tv_nsec = DIP(ip, atimensec);
308 0 : vap->va_mtime.tv_sec = DIP(ip, mtime);
309 0 : vap->va_mtime.tv_nsec = DIP(ip, mtimensec);
310 0 : vap->va_ctime.tv_sec = DIP(ip, ctime);
311 0 : vap->va_ctime.tv_nsec = DIP(ip, ctimensec);
312 0 : vap->va_flags = DIP(ip, flags);
313 0 : vap->va_gen = DIP(ip, gen);
314 : /* this doesn't belong here */
315 0 : if (vp->v_type == VBLK)
316 0 : vap->va_blocksize = BLKDEV_IOSIZE;
317 0 : else if (vp->v_type == VCHR)
318 0 : vap->va_blocksize = MAXBSIZE;
319 : else
320 0 : vap->va_blocksize = vp->v_mount->mnt_stat.f_iosize;
321 0 : vap->va_bytes = dbtob((u_quad_t) DIP(ip, blocks));
322 0 : vap->va_type = vp->v_type;
323 0 : vap->va_filerev = ip->i_modrev;
324 0 : return (0);
325 : }
326 :
327 : /*
328 : * Set attribute vnode op. called from several syscalls
329 : */
330 : int
331 0 : ufs_setattr(void *v)
332 : {
333 0 : struct vop_setattr_args *ap = v;
334 0 : struct vattr *vap = ap->a_vap;
335 0 : struct vnode *vp = ap->a_vp;
336 0 : struct inode *ip = VTOI(vp);
337 0 : struct ucred *cred = ap->a_cred;
338 0 : struct proc *p = ap->a_p;
339 : int error;
340 : long hint = NOTE_ATTRIB;
341 : u_quad_t oldsize;
342 :
343 : /*
344 : * Check for unsettable attributes.
345 : */
346 0 : if ((vap->va_type != VNON) || (vap->va_nlink != VNOVAL) ||
347 0 : (vap->va_fsid != VNOVAL) || (vap->va_fileid != VNOVAL) ||
348 0 : (vap->va_blocksize != VNOVAL) || (vap->va_rdev != VNOVAL) ||
349 0 : ((int)vap->va_bytes != VNOVAL) || (vap->va_gen != VNOVAL)) {
350 0 : return (EINVAL);
351 : }
352 0 : if (vap->va_flags != VNOVAL) {
353 0 : if (vp->v_mount->mnt_flag & MNT_RDONLY)
354 0 : return (EROFS);
355 0 : if (cred->cr_uid != DIP(ip, uid) &&
356 0 : (vp->v_mount->mnt_flag & MNT_NOPERM) == 0 &&
357 0 : (error = suser_ucred(cred)))
358 0 : return (error);
359 0 : if (cred->cr_uid == 0) {
360 0 : if ((DIP(ip, flags) & (SF_IMMUTABLE | SF_APPEND)) &&
361 0 : securelevel > 0)
362 0 : return (EPERM);
363 0 : DIP_ASSIGN(ip, flags, vap->va_flags);
364 : } else {
365 0 : if (DIP(ip, flags) & (SF_IMMUTABLE | SF_APPEND) ||
366 0 : (vap->va_flags & UF_SETTABLE) != vap->va_flags)
367 0 : return (EPERM);
368 0 : DIP_AND(ip, flags, SF_SETTABLE);
369 0 : DIP_OR(ip, flags, vap->va_flags & UF_SETTABLE);
370 : }
371 0 : ip->i_flag |= IN_CHANGE;
372 0 : if (vap->va_flags & (IMMUTABLE | APPEND))
373 0 : return (0);
374 : }
375 0 : if (DIP(ip, flags) & (IMMUTABLE | APPEND))
376 0 : return (EPERM);
377 : /*
378 : * Go through the fields and update if not VNOVAL.
379 : */
380 0 : if (vap->va_uid != (uid_t)VNOVAL || vap->va_gid != (gid_t)VNOVAL) {
381 0 : if (vp->v_mount->mnt_flag & MNT_RDONLY)
382 0 : return (EROFS);
383 0 : error = ufs_chown(vp, vap->va_uid, vap->va_gid, cred, p);
384 0 : if (error)
385 0 : return (error);
386 : }
387 0 : if (vap->va_size != VNOVAL) {
388 0 : oldsize = DIP(ip, size);
389 : /*
390 : * Disallow write attempts on read-only file systems;
391 : * unless the file is a socket, fifo, or a block or
392 : * character device resident on the file system.
393 : */
394 0 : switch (vp->v_type) {
395 : case VDIR:
396 0 : return (EISDIR);
397 : case VLNK:
398 : case VREG:
399 0 : if (vp->v_mount->mnt_flag & MNT_RDONLY)
400 0 : return (EROFS);
401 : break;
402 : default:
403 : break;
404 : }
405 0 : if ((error = UFS_TRUNCATE(ip, vap->va_size, 0, cred)) != 0)
406 0 : return (error);
407 0 : if (vap->va_size < oldsize)
408 0 : hint |= NOTE_TRUNCATE;
409 : }
410 0 : if ((vap->va_vaflags & VA_UTIMES_CHANGE) ||
411 0 : vap->va_atime.tv_nsec != VNOVAL ||
412 0 : vap->va_mtime.tv_nsec != VNOVAL) {
413 0 : if (vp->v_mount->mnt_flag & MNT_RDONLY)
414 0 : return (EROFS);
415 0 : if (cred->cr_uid != DIP(ip, uid) &&
416 0 : (vp->v_mount->mnt_flag & MNT_NOPERM) == 0 &&
417 0 : (error = suser_ucred(cred)) &&
418 0 : ((vap->va_vaflags & VA_UTIMES_NULL) == 0 ||
419 0 : (error = VOP_ACCESS(vp, VWRITE, cred, p))))
420 0 : return (error);
421 0 : if (vap->va_mtime.tv_nsec != VNOVAL)
422 0 : ip->i_flag |= IN_CHANGE | IN_UPDATE;
423 0 : else if (vap->va_vaflags & VA_UTIMES_CHANGE)
424 0 : ip->i_flag |= IN_CHANGE;
425 0 : if (vap->va_atime.tv_nsec != VNOVAL) {
426 0 : if (!(vp->v_mount->mnt_flag & MNT_NOATIME) ||
427 0 : (ip->i_flag & (IN_CHANGE | IN_UPDATE)))
428 0 : ip->i_flag |= IN_ACCESS;
429 : }
430 0 : ufs_itimes(vp);
431 0 : if (vap->va_mtime.tv_nsec != VNOVAL) {
432 0 : DIP_ASSIGN(ip, mtime, vap->va_mtime.tv_sec);
433 0 : DIP_ASSIGN(ip, mtimensec, vap->va_mtime.tv_nsec);
434 : }
435 0 : if (vap->va_atime.tv_nsec != VNOVAL) {
436 0 : DIP_ASSIGN(ip, atime, vap->va_atime.tv_sec);
437 0 : DIP_ASSIGN(ip, atimensec, vap->va_atime.tv_nsec);
438 : }
439 0 : error = UFS_UPDATE(ip, 0);
440 0 : if (error)
441 0 : return (error);
442 : }
443 : error = 0;
444 0 : if (vap->va_mode != (mode_t)VNOVAL) {
445 0 : if (vp->v_mount->mnt_flag & MNT_RDONLY)
446 0 : return (EROFS);
447 0 : error = ufs_chmod(vp, (int)vap->va_mode, cred, p);
448 0 : }
449 0 : VN_KNOTE(vp, hint);
450 0 : return (error);
451 0 : }
452 :
453 : /*
454 : * Change the mode on a file.
455 : * Inode must be locked before calling.
456 : */
457 : int
458 0 : ufs_chmod(struct vnode *vp, int mode, struct ucred *cred, struct proc *p)
459 : {
460 0 : struct inode *ip = VTOI(vp);
461 : int error;
462 :
463 0 : if (cred->cr_uid != DIP(ip, uid) &&
464 0 : (vp->v_mount->mnt_flag & MNT_NOPERM) == 0 &&
465 0 : (error = suser_ucred(cred)))
466 0 : return (error);
467 0 : if (cred->cr_uid &&
468 0 : (vp->v_mount->mnt_flag & MNT_NOPERM) == 0) {
469 0 : if (vp->v_type != VDIR && (mode & S_ISTXT))
470 0 : return (EFTYPE);
471 0 : if (!groupmember(DIP(ip, gid), cred) && (mode & ISGID))
472 0 : return (EPERM);
473 : }
474 0 : DIP_AND(ip, mode, ~ALLPERMS);
475 0 : DIP_OR(ip, mode, mode & ALLPERMS);
476 0 : ip->i_flag |= IN_CHANGE;
477 0 : if ((vp->v_flag & VTEXT) && (DIP(ip, mode) & S_ISTXT) == 0)
478 0 : (void) uvm_vnp_uncache(vp);
479 0 : return (0);
480 0 : }
481 :
482 : /*
483 : * Perform chown operation on inode ip;
484 : * inode must be locked prior to call.
485 : */
486 : int
487 0 : ufs_chown(struct vnode *vp, uid_t uid, gid_t gid, struct ucred *cred,
488 : struct proc *p)
489 : {
490 0 : struct inode *ip = VTOI(vp);
491 : uid_t ouid;
492 : gid_t ogid;
493 : int error = 0;
494 : daddr_t change;
495 : enum ufs_quota_flags quota_flags = 0;
496 :
497 0 : if (uid == (uid_t)VNOVAL)
498 0 : uid = DIP(ip, uid);
499 0 : if (gid == (gid_t)VNOVAL)
500 0 : gid = DIP(ip, gid);
501 : /*
502 : * If we don't own the file, are trying to change the owner
503 : * of the file, or are not a member of the target group,
504 : * the caller must be superuser or the call fails.
505 : */
506 0 : if ((cred->cr_uid != DIP(ip, uid) || uid != DIP(ip, uid) ||
507 0 : (gid != DIP(ip, gid) && !groupmember(gid, cred))) &&
508 0 : (vp->v_mount->mnt_flag & MNT_NOPERM) == 0 &&
509 0 : (error = suser_ucred(cred)))
510 0 : return (error);
511 0 : ogid = DIP(ip, gid);
512 0 : ouid = DIP(ip, uid);
513 0 : change = DIP(ip, blocks);
514 :
515 0 : if (ouid == uid)
516 0 : quota_flags |= UFS_QUOTA_NOUID;
517 :
518 0 : if (ogid == gid)
519 0 : quota_flags |= UFS_QUOTA_NOGID;
520 :
521 0 : if ((error = getinoquota(ip)) != 0)
522 0 : return (error);
523 0 : (void) ufs_quota_free_blocks2(ip, change, cred, quota_flags);
524 0 : (void) ufs_quota_free_inode2(ip, cred, quota_flags);
525 0 : (void) ufs_quota_delete(ip);
526 :
527 0 : DIP_ASSIGN(ip, gid, gid);
528 0 : DIP_ASSIGN(ip, uid, uid);
529 :
530 0 : if ((error = getinoquota(ip)) != 0)
531 : goto error;
532 :
533 0 : if ((error = ufs_quota_alloc_blocks2(ip, change, cred,
534 0 : quota_flags)) != 0)
535 : goto error;
536 :
537 0 : if ((error = ufs_quota_alloc_inode2(ip, cred ,
538 0 : quota_flags)) != 0) {
539 0 : (void)ufs_quota_free_blocks2(ip, change, cred,
540 : quota_flags);
541 0 : goto error;
542 : }
543 :
544 0 : if (getinoquota(ip))
545 0 : panic("chown: lost quota");
546 :
547 0 : if (ouid != uid || ogid != gid)
548 0 : ip->i_flag |= IN_CHANGE;
549 0 : if (ouid != uid && cred->cr_uid != 0 &&
550 0 : (vp->v_mount->mnt_flag & MNT_NOPERM) == 0)
551 0 : DIP_AND(ip, mode, ~ISUID);
552 0 : if (ogid != gid && cred->cr_uid != 0 &&
553 0 : (vp->v_mount->mnt_flag & MNT_NOPERM) == 0)
554 0 : DIP_AND(ip, mode, ~ISGID);
555 0 : return (0);
556 :
557 : error:
558 0 : (void) ufs_quota_delete(ip);
559 :
560 0 : DIP_ASSIGN(ip, gid, ogid);
561 0 : DIP_ASSIGN(ip, uid, ouid);
562 :
563 0 : if (getinoquota(ip) == 0) {
564 0 : (void) ufs_quota_alloc_blocks2(ip, change, cred,
565 0 : quota_flags | UFS_QUOTA_FORCE);
566 0 : (void) ufs_quota_alloc_inode2(ip, cred,
567 : quota_flags | UFS_QUOTA_FORCE);
568 0 : (void) getinoquota(ip);
569 0 : }
570 0 : return (error);
571 :
572 0 : }
573 :
574 : /* ARGSUSED */
575 : int
576 0 : ufs_ioctl(void *v)
577 : {
578 : #if 0
579 : struct vop_ioctl_args *ap = v;
580 : #endif
581 0 : return (ENOTTY);
582 : }
583 :
584 : int
585 0 : ufs_poll(void *v)
586 : {
587 0 : struct vop_poll_args *ap = v;
588 :
589 : /*
590 : * We should really check to see if I/O is possible.
591 : */
592 0 : return (ap->a_events & (POLLIN | POLLOUT | POLLRDNORM | POLLWRNORM));
593 : }
594 :
595 : int
596 0 : ufs_remove(void *v)
597 : {
598 0 : struct vop_remove_args *ap = v;
599 : struct inode *ip;
600 0 : struct vnode *vp = ap->a_vp;
601 0 : struct vnode *dvp = ap->a_dvp;
602 : int error;
603 :
604 0 : ip = VTOI(vp);
605 0 : if (vp->v_type == VDIR || (DIP(ip, flags) & (IMMUTABLE | APPEND)) ||
606 0 : (DIP(VTOI(dvp), flags) & APPEND)) {
607 : error = EPERM;
608 0 : goto out;
609 : }
610 0 : error = ufs_dirremove(dvp, ip, ap->a_cnp->cn_flags, 0);
611 0 : VN_KNOTE(vp, NOTE_DELETE);
612 0 : VN_KNOTE(dvp, NOTE_WRITE);
613 : out:
614 0 : if (dvp == vp)
615 0 : vrele(vp);
616 : else
617 0 : vput(vp);
618 0 : vput(dvp);
619 0 : return (error);
620 : }
621 :
622 : /*
623 : * link vnode call
624 : */
625 : int
626 0 : ufs_link(void *v)
627 : {
628 0 : struct vop_link_args *ap = v;
629 0 : struct vnode *dvp = ap->a_dvp;
630 0 : struct vnode *vp = ap->a_vp;
631 0 : struct componentname *cnp = ap->a_cnp;
632 : struct inode *ip;
633 0 : struct direct newdir;
634 : int error;
635 :
636 : #ifdef DIAGNOSTIC
637 0 : if ((cnp->cn_flags & HASBUF) == 0)
638 0 : panic("ufs_link: no name");
639 : #endif
640 0 : if (vp->v_type == VDIR) {
641 0 : VOP_ABORTOP(dvp, cnp);
642 : error = EPERM;
643 0 : goto out2;
644 : }
645 0 : if (dvp->v_mount != vp->v_mount) {
646 0 : VOP_ABORTOP(dvp, cnp);
647 : error = EXDEV;
648 0 : goto out2;
649 : }
650 0 : if (dvp != vp && (error = vn_lock(vp, LK_EXCLUSIVE))) {
651 0 : VOP_ABORTOP(dvp, cnp);
652 0 : goto out2;
653 : }
654 0 : ip = VTOI(vp);
655 0 : if ((nlink_t) DIP(ip, nlink) >= LINK_MAX) {
656 0 : VOP_ABORTOP(dvp, cnp);
657 : error = EMLINK;
658 0 : goto out1;
659 : }
660 0 : if (DIP(ip, flags) & (IMMUTABLE | APPEND)) {
661 0 : VOP_ABORTOP(dvp, cnp);
662 : error = EPERM;
663 0 : goto out1;
664 : }
665 0 : ip->i_effnlink++;
666 0 : DIP_ADD(ip, nlink, 1);
667 0 : ip->i_flag |= IN_CHANGE;
668 0 : if (DOINGSOFTDEP(vp))
669 0 : softdep_change_linkcnt(ip, 0);
670 0 : if ((error = UFS_UPDATE(ip, !DOINGSOFTDEP(vp))) == 0) {
671 0 : ufs_makedirentry(ip, cnp, &newdir);
672 0 : error = ufs_direnter(dvp, vp, &newdir, cnp, NULL);
673 0 : }
674 0 : if (error) {
675 0 : ip->i_effnlink--;
676 0 : DIP_ADD(ip, nlink, -1);
677 0 : ip->i_flag |= IN_CHANGE;
678 0 : if (DOINGSOFTDEP(vp))
679 0 : softdep_change_linkcnt(ip, 0);
680 : }
681 0 : pool_put(&namei_pool, cnp->cn_pnbuf);
682 0 : VN_KNOTE(vp, NOTE_LINK);
683 0 : VN_KNOTE(dvp, NOTE_WRITE);
684 : out1:
685 0 : if (dvp != vp)
686 0 : VOP_UNLOCK(vp);
687 : out2:
688 0 : vput(dvp);
689 0 : return (error);
690 0 : }
691 :
692 : /*
693 : * Rename system call.
694 : * rename("foo", "bar");
695 : * is essentially
696 : * unlink("bar");
697 : * link("foo", "bar");
698 : * unlink("foo");
699 : * but ``atomically''. Can't do full commit without saving state in the
700 : * inode on disk which isn't feasible at this time. Best we can do is
701 : * always guarantee the target exists.
702 : *
703 : * Basic algorithm is:
704 : *
705 : * 1) Bump link count on source while we're linking it to the
706 : * target. This also ensure the inode won't be deleted out
707 : * from underneath us while we work (it may be truncated by
708 : * a concurrent `trunc' or `open' for creation).
709 : * 2) Link source to destination. If destination already exists,
710 : * delete it first.
711 : * 3) Unlink source reference to inode if still around. If a
712 : * directory was moved and the parent of the destination
713 : * is different from the source, patch the ".." entry in the
714 : * directory.
715 : */
716 : int
717 0 : ufs_rename(void *v)
718 : {
719 0 : struct vop_rename_args *ap = v;
720 0 : struct vnode *tvp = ap->a_tvp;
721 0 : struct vnode *tdvp = ap->a_tdvp;
722 0 : struct vnode *fvp = ap->a_fvp;
723 0 : struct vnode *fdvp = ap->a_fdvp;
724 0 : struct componentname *tcnp = ap->a_tcnp;
725 0 : struct componentname *fcnp = ap->a_fcnp;
726 : struct inode *ip, *xp, *dp;
727 0 : struct direct newdir;
728 : int doingdirectory = 0, oldparent = 0, newparent = 0;
729 : int error = 0;
730 :
731 : #ifdef DIAGNOSTIC
732 0 : if ((tcnp->cn_flags & HASBUF) == 0 ||
733 0 : (fcnp->cn_flags & HASBUF) == 0)
734 0 : panic("ufs_rename: no name");
735 : #endif
736 : /*
737 : * Check for cross-device rename.
738 : */
739 0 : if ((fvp->v_mount != tdvp->v_mount) ||
740 0 : (tvp && (fvp->v_mount != tvp->v_mount))) {
741 0 : error = EXDEV;
742 : abortit:
743 0 : VOP_ABORTOP(tdvp, tcnp);
744 0 : if (tdvp == tvp)
745 0 : vrele(tdvp);
746 : else
747 0 : vput(tdvp);
748 0 : if (tvp)
749 0 : vput(tvp);
750 0 : VOP_ABORTOP(fdvp, fcnp);
751 0 : vrele(fdvp);
752 0 : vrele(fvp);
753 0 : return (error);
754 : }
755 :
756 0 : if (tvp && ((DIP(VTOI(tvp), flags) & (IMMUTABLE | APPEND)) ||
757 0 : (DIP(VTOI(tdvp), flags) & APPEND))) {
758 : error = EPERM;
759 0 : goto abortit;
760 : }
761 :
762 : /*
763 : * Check if just deleting a link name or if we've lost a race.
764 : * If another process completes the same rename after we've looked
765 : * up the source and have blocked looking up the target, then the
766 : * source and target inodes may be identical now although the
767 : * names were never linked.
768 : */
769 0 : if (fvp == tvp) {
770 0 : if (fvp->v_type == VDIR) {
771 : /*
772 : * Linked directories are impossible, so we must
773 : * have lost the race. Pretend that the rename
774 : * completed before the lookup.
775 : */
776 : error = ENOENT;
777 0 : goto abortit;
778 : }
779 :
780 : /* Release destination completely. */
781 0 : VOP_ABORTOP(tdvp, tcnp);
782 0 : vput(tdvp);
783 0 : vput(tvp);
784 :
785 : /*
786 : * Delete source. There is another race now that everything
787 : * is unlocked, but this doesn't cause any new complications.
788 : * relookup() may find a file that is unrelated to the
789 : * original one, or it may fail. Too bad.
790 : */
791 0 : vrele(fvp);
792 0 : fcnp->cn_flags &= ~MODMASK;
793 0 : fcnp->cn_flags |= LOCKPARENT | LOCKLEAF;
794 0 : if ((fcnp->cn_flags & SAVESTART) == 0)
795 0 : panic("ufs_rename: lost from startdir");
796 0 : fcnp->cn_nameiop = DELETE;
797 0 : if ((error = vfs_relookup(fdvp, &fvp, fcnp)) != 0)
798 0 : return (error); /* relookup did vrele() */
799 0 : vrele(fdvp);
800 0 : return (VOP_REMOVE(fdvp, fvp, fcnp));
801 : }
802 :
803 0 : if ((error = vn_lock(fvp, LK_EXCLUSIVE)) != 0)
804 : goto abortit;
805 :
806 : /* fvp, tdvp, tvp now locked */
807 0 : dp = VTOI(fdvp);
808 0 : ip = VTOI(fvp);
809 0 : if ((nlink_t) DIP(ip, nlink) >= LINK_MAX) {
810 0 : VOP_UNLOCK(fvp);
811 : error = EMLINK;
812 0 : goto abortit;
813 : }
814 0 : if ((DIP(ip, flags) & (IMMUTABLE | APPEND)) ||
815 0 : (DIP(dp, flags) & APPEND)) {
816 0 : VOP_UNLOCK(fvp);
817 : error = EPERM;
818 0 : goto abortit;
819 : }
820 0 : if ((DIP(ip, mode) & IFMT) == IFDIR) {
821 0 : error = VOP_ACCESS(fvp, VWRITE, tcnp->cn_cred, tcnp->cn_proc);
822 0 : if (!error && tvp)
823 0 : error = VOP_ACCESS(tvp, VWRITE, tcnp->cn_cred, tcnp->cn_proc);
824 0 : if (error) {
825 0 : VOP_UNLOCK(fvp);
826 : error = EACCES;
827 0 : goto abortit;
828 : }
829 : /*
830 : * Avoid ".", "..", and aliases of "." for obvious reasons.
831 : */
832 0 : if ((fcnp->cn_namelen == 1 && fcnp->cn_nameptr[0] == '.') ||
833 0 : dp == ip ||
834 0 : (fcnp->cn_flags & ISDOTDOT) ||
835 0 : (tcnp->cn_flags & ISDOTDOT) ||
836 0 : (ip->i_flag & IN_RENAME)) {
837 0 : VOP_UNLOCK(fvp);
838 : error = EINVAL;
839 0 : goto abortit;
840 : }
841 0 : ip->i_flag |= IN_RENAME;
842 0 : oldparent = dp->i_number;
843 : doingdirectory = 1;
844 0 : }
845 0 : VN_KNOTE(fdvp, NOTE_WRITE); /* XXX right place? */
846 :
847 : /*
848 : * When the target exists, both the directory
849 : * and target vnodes are returned locked.
850 : */
851 0 : dp = VTOI(tdvp);
852 : xp = NULL;
853 0 : if (tvp)
854 0 : xp = VTOI(tvp);
855 :
856 : /*
857 : * 1) Bump link count while we're moving stuff
858 : * around. If we crash somewhere before
859 : * completing our work, the link count
860 : * may be wrong, but correctable.
861 : */
862 0 : ip->i_effnlink++;
863 0 : DIP_ADD(ip, nlink, 1);
864 0 : ip->i_flag |= IN_CHANGE;
865 0 : if (DOINGSOFTDEP(fvp))
866 0 : softdep_change_linkcnt(ip, 0);
867 0 : if ((error = UFS_UPDATE(ip, !DOINGSOFTDEP(fvp))) != 0) {
868 0 : VOP_UNLOCK(fvp);
869 0 : goto bad;
870 : }
871 :
872 : /*
873 : * If ".." must be changed (ie the directory gets a new
874 : * parent) then the source directory must not be in the
875 : * directory hierarchy above the target, as this would
876 : * orphan everything below the source directory. Also
877 : * the user must have write permission in the source so
878 : * as to be able to change "..". We must repeat the call
879 : * to namei, as the parent directory is unlocked by the
880 : * call to checkpath().
881 : */
882 0 : error = VOP_ACCESS(fvp, VWRITE, tcnp->cn_cred, tcnp->cn_proc);
883 0 : VOP_UNLOCK(fvp);
884 :
885 : /* tdvp and tvp locked */
886 0 : if (oldparent != dp->i_number)
887 0 : newparent = dp->i_number;
888 0 : if (doingdirectory && newparent) {
889 0 : if (error) /* write access check above */
890 : goto bad;
891 0 : if (xp != NULL)
892 0 : vput(tvp);
893 : /*
894 : * Compensate for the reference ufs_checkpath() loses.
895 : */
896 0 : vref(tdvp);
897 : /* Only tdvp is locked */
898 0 : if ((error = ufs_checkpath(ip, dp, tcnp->cn_cred)) != 0) {
899 0 : vrele(tdvp);
900 0 : goto out;
901 : }
902 0 : if ((tcnp->cn_flags & SAVESTART) == 0)
903 0 : panic("ufs_rename: lost to startdir");
904 0 : if ((error = vfs_relookup(tdvp, &tvp, tcnp)) != 0)
905 : goto out;
906 0 : vrele(tdvp); /* relookup() acquired a reference */
907 0 : dp = VTOI(tdvp);
908 : xp = NULL;
909 0 : if (tvp)
910 0 : xp = VTOI(tvp);
911 : }
912 : /*
913 : * 2) If target doesn't exist, link the target
914 : * to the source and unlink the source.
915 : * Otherwise, rewrite the target directory
916 : * entry to reference the source inode and
917 : * expunge the original entry's existence.
918 : */
919 0 : if (xp == NULL) {
920 0 : if (dp->i_dev != ip->i_dev)
921 0 : panic("rename: EXDEV");
922 : /*
923 : * Account for ".." in new directory.
924 : * When source and destination have the same
925 : * parent we don't fool with the link count.
926 : */
927 0 : if (doingdirectory && newparent) {
928 0 : if ((nlink_t) DIP(dp, nlink) >= LINK_MAX) {
929 : error = EMLINK;
930 0 : goto bad;
931 : }
932 0 : dp->i_effnlink++;
933 0 : DIP_ADD(dp, nlink, 1);
934 0 : dp->i_flag |= IN_CHANGE;
935 0 : if (DOINGSOFTDEP(tdvp))
936 0 : softdep_change_linkcnt(dp, 0);
937 0 : if ((error = UFS_UPDATE(dp, !DOINGSOFTDEP(tdvp)))
938 0 : != 0) {
939 0 : dp->i_effnlink--;
940 0 : DIP_ADD(dp, nlink, -1);
941 0 : dp->i_flag |= IN_CHANGE;
942 0 : if (DOINGSOFTDEP(tdvp))
943 0 : softdep_change_linkcnt(dp, 0);
944 : goto bad;
945 : }
946 : }
947 0 : ufs_makedirentry(ip, tcnp, &newdir);
948 0 : if ((error = ufs_direnter(tdvp, NULL, &newdir, tcnp, NULL)) != 0) {
949 0 : if (doingdirectory && newparent) {
950 0 : dp->i_effnlink--;
951 0 : DIP_ADD(dp, nlink, -1);
952 0 : dp->i_flag |= IN_CHANGE;
953 0 : if (DOINGSOFTDEP(tdvp))
954 0 : softdep_change_linkcnt(dp, 0);
955 0 : (void)UFS_UPDATE(dp, 1);
956 0 : }
957 : goto bad;
958 : }
959 0 : VN_KNOTE(tdvp, NOTE_WRITE);
960 0 : vput(tdvp);
961 0 : } else {
962 0 : if (xp->i_dev != dp->i_dev || xp->i_dev != ip->i_dev)
963 0 : panic("rename: EXDEV");
964 : /*
965 : * Short circuit rename(foo, foo).
966 : */
967 0 : if (xp->i_number == ip->i_number)
968 0 : panic("ufs_rename: same file");
969 : /*
970 : * If the parent directory is "sticky", then the user must
971 : * own the parent directory, or the destination of the rename,
972 : * otherwise the destination may not be changed (except by
973 : * root). This implements append-only directories.
974 : */
975 0 : if ((DIP(dp, mode) & S_ISTXT) && tcnp->cn_cred->cr_uid != 0 &&
976 0 : tcnp->cn_cred->cr_uid != DIP(dp, uid) &&
977 0 : DIP(xp, uid )!= tcnp->cn_cred->cr_uid &&
978 0 : (tdvp->v_mount->mnt_flag & MNT_NOPERM) == 0) {
979 : error = EPERM;
980 0 : goto bad;
981 : }
982 : /*
983 : * Target must be empty if a directory and have no links
984 : * to it. Also, ensure source and target are compatible
985 : * (both directories, or both not directories).
986 : */
987 0 : if ((DIP(xp, mode) & IFMT) == IFDIR) {
988 0 : if (xp->i_effnlink > 2 ||
989 0 : !ufs_dirempty(xp, dp->i_number, tcnp->cn_cred)) {
990 : error = ENOTEMPTY;
991 0 : goto bad;
992 : }
993 0 : if (!doingdirectory) {
994 : error = ENOTDIR;
995 0 : goto bad;
996 : }
997 0 : cache_purge(tdvp);
998 0 : } else if (doingdirectory) {
999 : error = EISDIR;
1000 0 : goto bad;
1001 : }
1002 :
1003 0 : if ((error = ufs_dirrewrite(dp, xp, ip->i_number,
1004 0 : IFTODT(DIP(ip, mode)), (doingdirectory && newparent) ?
1005 0 : newparent : doingdirectory)) != 0)
1006 : goto bad;
1007 0 : if (doingdirectory) {
1008 0 : if (!newparent) {
1009 0 : dp->i_effnlink--;
1010 0 : if (DOINGSOFTDEP(tdvp))
1011 0 : softdep_change_linkcnt(dp, 0);
1012 : }
1013 0 : xp->i_effnlink--;
1014 0 : if (DOINGSOFTDEP(tvp))
1015 0 : softdep_change_linkcnt(xp, 0);
1016 : }
1017 0 : if (doingdirectory && !DOINGSOFTDEP(tvp)) {
1018 : /*
1019 : * Truncate inode. The only stuff left in the directory
1020 : * is "." and "..". The "." reference is inconsequential
1021 : * since we are quashing it. We have removed the "."
1022 : * reference and the reference in the parent directory,
1023 : * but there may be other hard links. The soft
1024 : * dependency code will arrange to do these operations
1025 : * after the parent directory entry has been deleted on
1026 : * disk, so when running with that code we avoid doing
1027 : * them now.
1028 : */
1029 0 : if (!newparent) {
1030 0 : DIP_ADD(dp, nlink, -1);
1031 0 : dp->i_flag |= IN_CHANGE;
1032 0 : }
1033 :
1034 0 : DIP_ADD(xp, nlink, -1);
1035 0 : xp->i_flag |= IN_CHANGE;
1036 0 : if ((error = UFS_TRUNCATE(VTOI(tvp), (off_t)0, IO_SYNC,
1037 0 : tcnp->cn_cred)) != 0)
1038 : goto bad;
1039 : }
1040 0 : VN_KNOTE(tdvp, NOTE_WRITE);
1041 0 : vput(tdvp);
1042 0 : VN_KNOTE(tvp, NOTE_DELETE);
1043 0 : vput(tvp);
1044 : xp = NULL;
1045 : }
1046 :
1047 : /*
1048 : * 3) Unlink the source.
1049 : */
1050 0 : fcnp->cn_flags &= ~MODMASK;
1051 0 : fcnp->cn_flags |= LOCKPARENT | LOCKLEAF;
1052 0 : if ((fcnp->cn_flags & SAVESTART) == 0)
1053 0 : panic("ufs_rename: lost from startdir");
1054 0 : if ((error = vfs_relookup(fdvp, &fvp, fcnp)) != 0) {
1055 0 : vrele(ap->a_fvp);
1056 0 : return (error);
1057 : }
1058 0 : vrele(fdvp);
1059 0 : if (fvp == NULL) {
1060 : /*
1061 : * From name has disappeared.
1062 : */
1063 0 : if (doingdirectory)
1064 0 : panic("ufs_rename: lost dir entry");
1065 0 : vrele(ap->a_fvp);
1066 0 : return (0);
1067 : }
1068 :
1069 0 : xp = VTOI(fvp);
1070 0 : dp = VTOI(fdvp);
1071 :
1072 : /*
1073 : * Ensure that the directory entry still exists and has not
1074 : * changed while the new name has been entered. If the source is
1075 : * a file then the entry may have been unlinked or renamed. In
1076 : * either case there is no further work to be done. If the source
1077 : * is a directory then it cannot have been rmdir'ed; the IN_RENAME
1078 : * flag ensures that it cannot be moved by another rename or removed
1079 : * by a rmdir.
1080 : */
1081 0 : if (xp != ip) {
1082 0 : if (doingdirectory)
1083 0 : panic("ufs_rename: lost dir entry");
1084 : } else {
1085 : /*
1086 : * If the source is a directory with a
1087 : * new parent, the link count of the old
1088 : * parent directory must be decremented
1089 : * and ".." set to point to the new parent.
1090 : */
1091 0 : if (doingdirectory && newparent) {
1092 0 : xp->i_offset = mastertemplate.dot_reclen;
1093 0 : ufs_dirrewrite(xp, dp, newparent, DT_DIR, 0);
1094 0 : cache_purge(fdvp);
1095 0 : }
1096 0 : error = ufs_dirremove(fdvp, xp, fcnp->cn_flags, 0);
1097 0 : xp->i_flag &= ~IN_RENAME;
1098 : }
1099 0 : VN_KNOTE(fvp, NOTE_RENAME);
1100 0 : if (dp)
1101 0 : vput(fdvp);
1102 0 : if (xp)
1103 0 : vput(fvp);
1104 0 : vrele(ap->a_fvp);
1105 0 : return (error);
1106 :
1107 : bad:
1108 0 : if (xp)
1109 0 : vput(ITOV(xp));
1110 0 : vput(ITOV(dp));
1111 : out:
1112 0 : vrele(fdvp);
1113 0 : if (doingdirectory)
1114 0 : ip->i_flag &= ~IN_RENAME;
1115 0 : if (vn_lock(fvp, LK_EXCLUSIVE) == 0) {
1116 0 : ip->i_effnlink--;
1117 0 : DIP_ADD(ip, nlink, -1);
1118 0 : ip->i_flag |= IN_CHANGE;
1119 0 : ip->i_flag &= ~IN_RENAME;
1120 0 : if (DOINGSOFTDEP(fvp))
1121 0 : softdep_change_linkcnt(ip, 0);
1122 0 : vput(fvp);
1123 0 : } else
1124 0 : vrele(fvp);
1125 0 : return (error);
1126 0 : }
1127 :
1128 : /*
1129 : * Mkdir system call
1130 : */
1131 : int
1132 0 : ufs_mkdir(void *v)
1133 : {
1134 0 : struct vop_mkdir_args *ap = v;
1135 0 : struct vnode *dvp = ap->a_dvp;
1136 0 : struct vattr *vap = ap->a_vap;
1137 0 : struct componentname *cnp = ap->a_cnp;
1138 : struct inode *ip, *dp;
1139 0 : struct vnode *tvp;
1140 0 : struct buf *bp;
1141 0 : struct direct newdir;
1142 0 : struct dirtemplate dirtemplate, *dtp;
1143 : int error, dmode, blkoff;
1144 :
1145 : #ifdef DIAGNOSTIC
1146 0 : if ((cnp->cn_flags & HASBUF) == 0)
1147 0 : panic("ufs_mkdir: no name");
1148 : #endif
1149 0 : dp = VTOI(dvp);
1150 0 : if ((nlink_t) DIP(dp, nlink) >= LINK_MAX) {
1151 : error = EMLINK;
1152 0 : goto out;
1153 : }
1154 0 : dmode = vap->va_mode & 0777;
1155 0 : dmode |= IFDIR;
1156 : /*
1157 : * Must simulate part of ufs_makeinode here to acquire the inode,
1158 : * but not have it entered in the parent directory. The entry is
1159 : * made later after writing "." and ".." entries.
1160 : */
1161 0 : if ((error = UFS_INODE_ALLOC(dp, dmode, cnp->cn_cred, &tvp)) != 0)
1162 : goto out;
1163 :
1164 0 : ip = VTOI(tvp);
1165 :
1166 0 : DIP_ASSIGN(ip, uid, cnp->cn_cred->cr_uid);
1167 0 : DIP_ASSIGN(ip, gid, DIP(dp, gid));
1168 :
1169 0 : if ((error = getinoquota(ip)) ||
1170 0 : (error = ufs_quota_alloc_inode(ip, cnp->cn_cred))) {
1171 0 : pool_put(&namei_pool, cnp->cn_pnbuf);
1172 0 : UFS_INODE_FREE(ip, ip->i_number, dmode);
1173 0 : vput(tvp);
1174 0 : vput(dvp);
1175 0 : return (error);
1176 : }
1177 :
1178 0 : ip->i_flag |= IN_ACCESS | IN_CHANGE | IN_UPDATE;
1179 0 : DIP_ASSIGN(ip, mode, dmode);
1180 0 : tvp->v_type = VDIR; /* Rest init'd in getnewvnode(). */
1181 0 : ip->i_effnlink = 2;
1182 0 : DIP_ASSIGN(ip, nlink, 2);
1183 0 : if (DOINGSOFTDEP(tvp))
1184 0 : softdep_change_linkcnt(ip, 0);
1185 :
1186 : /*
1187 : * Bump link count in parent directory to reflect work done below.
1188 : * Should be done before reference is create so cleanup is
1189 : * possible if we crash.
1190 : */
1191 0 : dp->i_effnlink++;
1192 0 : DIP_ADD(dp, nlink, 1);
1193 0 : dp->i_flag |= IN_CHANGE;
1194 0 : if (DOINGSOFTDEP(dvp))
1195 0 : softdep_change_linkcnt(dp, 0);
1196 0 : if ((error = UFS_UPDATE(dp, !DOINGSOFTDEP(dvp))) != 0)
1197 : goto bad;
1198 :
1199 : /*
1200 : * Initialize directory with "." and ".." from static template.
1201 : */
1202 0 : if (dp->i_ump->um_maxsymlinklen > 0)
1203 0 : dtp = &mastertemplate;
1204 : else
1205 : dtp = (struct dirtemplate *)&omastertemplate;
1206 0 : dirtemplate = *dtp;
1207 0 : dirtemplate.dot_ino = ip->i_number;
1208 0 : dirtemplate.dotdot_ino = dp->i_number;
1209 :
1210 0 : if ((error = UFS_BUF_ALLOC(ip, (off_t)0, DIRBLKSIZ, cnp->cn_cred,
1211 0 : B_CLRBUF, &bp)) != 0)
1212 : goto bad;
1213 0 : DIP_ASSIGN(ip, size, DIRBLKSIZ);
1214 0 : ip->i_flag |= IN_CHANGE | IN_UPDATE;
1215 0 : uvm_vnp_setsize(tvp, DIP(ip, size));
1216 0 : memcpy(bp->b_data, &dirtemplate, sizeof(dirtemplate));
1217 0 : if (DOINGSOFTDEP(tvp)) {
1218 : /*
1219 : * Ensure that the entire newly allocated block is a
1220 : * valid directory so that future growth within the
1221 : * block does not have to ensure that the block is
1222 : * written before the inode
1223 : */
1224 : blkoff = DIRBLKSIZ;
1225 0 : while (blkoff < bp->b_bcount) {
1226 : ((struct direct *)
1227 0 : (bp->b_data + blkoff))->d_reclen = DIRBLKSIZ;
1228 0 : blkoff += DIRBLKSIZ;
1229 : }
1230 : }
1231 0 : if ((error = UFS_UPDATE(ip, !DOINGSOFTDEP(tvp))) != 0) {
1232 0 : (void)VOP_BWRITE(bp);
1233 0 : goto bad;
1234 : }
1235 :
1236 : /*
1237 : * Directory set up, now install its entry in the parent directory.
1238 : *
1239 : * If we are not doing soft dependencies, then we must write out the
1240 : * buffer containing the new directory body before entering the new
1241 : * name in the parent. If we are doing soft dependencies, then the
1242 : * buffer containing the new directory body will be passed to and
1243 : * released in the soft dependency code after the code has attached
1244 : * an appropriate ordering dependency to the buffer which ensures that
1245 : * the buffer is written before the new name is written in the parent.
1246 : */
1247 0 : if (!DOINGSOFTDEP(dvp) && ((error = VOP_BWRITE(bp)) != 0))
1248 : goto bad;
1249 0 : ufs_makedirentry(ip, cnp, &newdir);
1250 0 : error = ufs_direnter(dvp, tvp, &newdir, cnp, bp);
1251 :
1252 : bad:
1253 0 : if (error == 0) {
1254 0 : VN_KNOTE(dvp, NOTE_WRITE | NOTE_LINK);
1255 0 : *ap->a_vpp = tvp;
1256 0 : } else {
1257 0 : dp->i_effnlink--;
1258 0 : DIP_ADD(dp, nlink, -1);
1259 0 : dp->i_flag |= IN_CHANGE;
1260 0 : if (DOINGSOFTDEP(dvp))
1261 0 : softdep_change_linkcnt(dp, 0);
1262 : /*
1263 : * No need to do an explicit VOP_TRUNCATE here, vrele will
1264 : * do this for us because we set the link count to 0.
1265 : */
1266 0 : ip->i_effnlink = 0;
1267 0 : DIP_ASSIGN(ip, nlink, 0);
1268 0 : ip->i_flag |= IN_CHANGE;
1269 0 : if (DOINGSOFTDEP(tvp))
1270 0 : softdep_change_linkcnt(ip, 0);
1271 0 : vput(tvp);
1272 : }
1273 : out:
1274 0 : pool_put(&namei_pool, cnp->cn_pnbuf);
1275 0 : vput(dvp);
1276 :
1277 0 : return (error);
1278 0 : }
1279 :
1280 : /*
1281 : * Rmdir system call.
1282 : */
1283 : int
1284 0 : ufs_rmdir(void *v)
1285 : {
1286 0 : struct vop_rmdir_args *ap = v;
1287 0 : struct vnode *vp = ap->a_vp;
1288 0 : struct vnode *dvp = ap->a_dvp;
1289 0 : struct componentname *cnp = ap->a_cnp;
1290 : struct inode *ip, *dp;
1291 : int error;
1292 :
1293 0 : ip = VTOI(vp);
1294 0 : dp = VTOI(dvp);
1295 : /*
1296 : * Do not remove a directory that is in the process of being renamed.
1297 : * Verify the directory is empty (and valid). Rmdir ".." will not be
1298 : * valid since ".." will contain a reference to the current directory
1299 : * and thus be non-empty.
1300 : */
1301 : error = 0;
1302 0 : if (ip->i_flag & IN_RENAME) {
1303 : error = EINVAL;
1304 0 : goto out;
1305 : }
1306 0 : if (ip->i_effnlink != 2 ||
1307 0 : !ufs_dirempty(ip, dp->i_number, cnp->cn_cred)) {
1308 : error = ENOTEMPTY;
1309 0 : goto out;
1310 : }
1311 0 : if ((DIP(dp, flags) & APPEND) ||
1312 0 : (DIP(ip, flags) & (IMMUTABLE | APPEND))) {
1313 : error = EPERM;
1314 0 : goto out;
1315 : }
1316 : /*
1317 : * Delete reference to directory before purging
1318 : * inode. If we crash in between, the directory
1319 : * will be reattached to lost+found,
1320 : */
1321 0 : dp->i_effnlink--;
1322 0 : ip->i_effnlink--;
1323 0 : if (DOINGSOFTDEP(vp)) {
1324 0 : softdep_change_linkcnt(dp, 0);
1325 0 : softdep_change_linkcnt(ip, 0);
1326 0 : }
1327 0 : if ((error = ufs_dirremove(dvp, ip, cnp->cn_flags, 1)) != 0) {
1328 0 : dp->i_effnlink++;
1329 0 : ip->i_effnlink++;
1330 0 : if (DOINGSOFTDEP(vp)) {
1331 0 : softdep_change_linkcnt(dp, 0);
1332 0 : softdep_change_linkcnt(ip, 0);
1333 0 : }
1334 : goto out;
1335 : }
1336 :
1337 0 : VN_KNOTE(dvp, NOTE_WRITE | NOTE_LINK);
1338 0 : cache_purge(dvp);
1339 : /*
1340 : * Truncate inode. The only stuff left in the directory is "." and
1341 : * "..". The "." reference is inconsequential since we are quashing
1342 : * it. The soft dependency code will arrange to do these operations
1343 : * after the parent directory entry has been deleted on disk, so
1344 : * when running with that code we avoid doing them now.
1345 : */
1346 0 : if (!DOINGSOFTDEP(vp)) {
1347 : int ioflag;
1348 :
1349 0 : DIP_ADD(dp, nlink, -1);
1350 0 : dp->i_flag |= IN_CHANGE;
1351 0 : DIP_ADD(ip, nlink, -1);
1352 0 : ip->i_flag |= IN_CHANGE;
1353 0 : ioflag = DOINGASYNC(vp) ? 0 : IO_SYNC;
1354 0 : error = UFS_TRUNCATE(ip, (off_t)0, ioflag, cnp->cn_cred);
1355 0 : }
1356 0 : cache_purge(vp);
1357 : #ifdef UFS_DIRHASH
1358 : /* Kill any active hash; i_effnlink == 0, so it will not come back. */
1359 0 : if (ip->i_dirhash != NULL)
1360 0 : ufsdirhash_free(ip);
1361 : #endif
1362 :
1363 : out:
1364 0 : VN_KNOTE(vp, NOTE_DELETE);
1365 0 : vput(dvp);
1366 0 : vput(vp);
1367 0 : return (error);
1368 : }
1369 :
1370 : /*
1371 : * symlink -- make a symbolic link
1372 : */
1373 : int
1374 0 : ufs_symlink(void *v)
1375 : {
1376 0 : struct vop_symlink_args *ap = v;
1377 0 : struct vnode *vp, **vpp = ap->a_vpp;
1378 : struct inode *ip;
1379 : int len, error;
1380 :
1381 0 : error = ufs_makeinode(IFLNK | ap->a_vap->va_mode, ap->a_dvp,
1382 0 : vpp, ap->a_cnp);
1383 0 : if (error) {
1384 0 : vput(ap->a_dvp);
1385 0 : return (error);
1386 : }
1387 0 : VN_KNOTE(ap->a_dvp, NOTE_WRITE);
1388 0 : vput(ap->a_dvp);
1389 0 : vp = *vpp;
1390 0 : ip = VTOI(vp);
1391 0 : len = strlen(ap->a_target);
1392 0 : if (len < ip->i_ump->um_maxsymlinklen) {
1393 0 : memcpy(SHORTLINK(ip), ap->a_target, len);
1394 0 : DIP_ASSIGN(ip, size, len);
1395 0 : ip->i_flag |= IN_CHANGE | IN_UPDATE;
1396 0 : } else
1397 0 : error = vn_rdwr(UIO_WRITE, vp, ap->a_target, len, (off_t)0,
1398 0 : UIO_SYSSPACE, IO_NODELOCKED, ap->a_cnp->cn_cred, NULL,
1399 0 : curproc);
1400 0 : vput(vp);
1401 0 : return (error);
1402 0 : }
1403 :
1404 : /*
1405 : * Vnode op for reading directories.
1406 : *
1407 : * This routine converts the on-disk struct direct entries to the
1408 : * struct dirent entries expected by userland and the rest of the kernel.
1409 : */
1410 : int
1411 0 : ufs_readdir(void *v)
1412 : {
1413 0 : struct vop_readdir_args *ap = v;
1414 0 : struct uio auio, *uio = ap->a_uio;
1415 0 : struct iovec aiov;
1416 0 : union {
1417 : struct dirent dn;
1418 : char __pad[roundup(sizeof(struct dirent), 8)];
1419 : } u;
1420 0 : off_t off = uio->uio_offset;
1421 : struct direct *dp;
1422 : char *edp;
1423 : caddr_t diskbuf;
1424 : size_t count, entries;
1425 : int bufsize, readcnt, error;
1426 : #if (BYTE_ORDER == LITTLE_ENDIAN)
1427 0 : int ofmt = VTOI(ap->a_vp)->i_ump->um_maxsymlinklen == 0;
1428 : #endif
1429 :
1430 0 : if (uio->uio_rw != UIO_READ)
1431 0 : return (EINVAL);
1432 :
1433 0 : count = uio->uio_resid;
1434 0 : entries = (uio->uio_offset + count) & (DIRBLKSIZ - 1);
1435 :
1436 : /* Make sure we don't return partial entries. */
1437 0 : if (count <= entries)
1438 0 : return (EINVAL);
1439 :
1440 : /*
1441 : * Convert and copy back the on-disk struct direct format to
1442 : * the user-space struct dirent format, one entry at a time
1443 : */
1444 :
1445 : /* read from disk, stopping on a block boundary, max 64kB */
1446 0 : readcnt = min(count, 64*1024) - entries;
1447 :
1448 0 : auio = *uio;
1449 0 : auio.uio_iov = &aiov;
1450 0 : auio.uio_iovcnt = 1;
1451 0 : auio.uio_resid = readcnt;
1452 0 : auio.uio_segflg = UIO_SYSSPACE;
1453 0 : aiov.iov_len = readcnt;
1454 : bufsize = readcnt;
1455 0 : diskbuf = malloc(bufsize, M_TEMP, M_WAITOK);
1456 0 : aiov.iov_base = diskbuf;
1457 0 : error = VOP_READ(ap->a_vp, &auio, 0, ap->a_cred);
1458 0 : readcnt -= auio.uio_resid;
1459 0 : dp = (struct direct *)diskbuf;
1460 0 : edp = &diskbuf[readcnt];
1461 :
1462 0 : memset(&u, 0, sizeof(u));
1463 :
1464 : /*
1465 : * While
1466 : * - we haven't failed to VOP_READ or uiomove()
1467 : * - there's space in the read buf for the head of an entry
1468 : * - that entry has a valid d_reclen, and
1469 : * - there's space for the *entire* entry
1470 : * then we're good to process this one.
1471 : */
1472 0 : while (error == 0 &&
1473 0 : (char *)dp + offsetof(struct direct, d_name) < edp &&
1474 0 : dp->d_reclen > offsetof(struct direct, d_name) &&
1475 0 : (char *)dp + dp->d_reclen <= edp) {
1476 0 : u.dn.d_reclen = roundup(dp->d_namlen+1 +
1477 : offsetof(struct dirent, d_name), 8);
1478 0 : if (u.dn.d_reclen > uio->uio_resid)
1479 : break;
1480 0 : off += dp->d_reclen;
1481 0 : u.dn.d_off = off;
1482 0 : u.dn.d_fileno = dp->d_ino;
1483 : #if (BYTE_ORDER == LITTLE_ENDIAN)
1484 0 : if (ofmt) {
1485 0 : u.dn.d_type = dp->d_namlen;
1486 0 : u.dn.d_namlen = dp->d_type;
1487 0 : } else
1488 : #endif
1489 : {
1490 0 : u.dn.d_type = dp->d_type;
1491 0 : u.dn.d_namlen = dp->d_namlen;
1492 : }
1493 0 : memcpy(u.dn.d_name, dp->d_name, u.dn.d_namlen);
1494 0 : memset(u.dn.d_name + u.dn.d_namlen, 0, u.dn.d_reclen
1495 : - u.dn.d_namlen - offsetof(struct dirent, d_name));
1496 :
1497 0 : error = uiomove(&u.dn, u.dn.d_reclen, uio);
1498 0 : dp = (struct direct *)((char *)dp + dp->d_reclen);
1499 : }
1500 :
1501 : /*
1502 : * If there was room for an entry in what we read but its
1503 : * d_reclen is bogus, fail
1504 : */
1505 0 : if ((char *)dp + offsetof(struct direct, d_name) < edp &&
1506 0 : dp->d_reclen <= offsetof(struct direct, d_name))
1507 0 : error = EIO;
1508 0 : free(diskbuf, M_TEMP, bufsize);
1509 :
1510 0 : uio->uio_offset = off;
1511 0 : *ap->a_eofflag = DIP(VTOI(ap->a_vp), size) <= off;
1512 :
1513 0 : return (error);
1514 0 : }
1515 :
1516 : /*
1517 : * Return target name of a symbolic link
1518 : */
1519 : int
1520 0 : ufs_readlink(void *v)
1521 : {
1522 0 : struct vop_readlink_args *ap = v;
1523 0 : struct vnode *vp = ap->a_vp;
1524 0 : struct inode *ip = VTOI(vp);
1525 : u_int64_t isize;
1526 :
1527 0 : isize = DIP(ip, size);
1528 0 : if (isize < ip->i_ump->um_maxsymlinklen ||
1529 0 : (ip->i_ump->um_maxsymlinklen == 0 && DIP(ip, blocks) == 0)) {
1530 0 : return (uiomove((char *)SHORTLINK(ip), isize, ap->a_uio));
1531 : }
1532 0 : return (VOP_READ(vp, ap->a_uio, 0, ap->a_cred));
1533 0 : }
1534 :
1535 : /*
1536 : * Lock an inode. If its already locked, set the WANT bit and sleep.
1537 : */
1538 : int
1539 0 : ufs_lock(void *v)
1540 : {
1541 0 : struct vop_lock_args *ap = v;
1542 0 : struct vnode *vp = ap->a_vp;
1543 :
1544 0 : return rrw_enter(&VTOI(vp)->i_lock, ap->a_flags & LK_RWFLAGS);
1545 : }
1546 :
1547 : /*
1548 : * Unlock an inode. If WANT bit is on, wakeup.
1549 : */
1550 : int
1551 0 : ufs_unlock(void *v)
1552 : {
1553 0 : struct vop_unlock_args *ap = v;
1554 0 : struct vnode *vp = ap->a_vp;
1555 :
1556 0 : rrw_exit(&VTOI(vp)->i_lock);
1557 0 : return 0;
1558 : }
1559 :
1560 : /*
1561 : * Check for a locked inode.
1562 : */
1563 : int
1564 0 : ufs_islocked(void *v)
1565 : {
1566 0 : struct vop_islocked_args *ap = v;
1567 :
1568 0 : return rrw_status(&VTOI(ap->a_vp)->i_lock);
1569 : }
1570 :
1571 : /*
1572 : * Calculate the logical to physical mapping if not done already,
1573 : * then call the device strategy routine.
1574 : */
1575 : int
1576 0 : ufs_strategy(void *v)
1577 : {
1578 0 : struct vop_strategy_args *ap = v;
1579 0 : struct buf *bp = ap->a_bp;
1580 0 : struct vnode *vp = bp->b_vp;
1581 : struct inode *ip;
1582 : int error;
1583 : int s;
1584 :
1585 0 : ip = VTOI(vp);
1586 0 : if (vp->v_type == VBLK || vp->v_type == VCHR)
1587 0 : panic("ufs_strategy: spec");
1588 0 : if (bp->b_blkno == bp->b_lblkno) {
1589 0 : error = VOP_BMAP(vp, bp->b_lblkno, NULL, &bp->b_blkno,
1590 : NULL);
1591 0 : if (error) {
1592 0 : bp->b_error = error;
1593 0 : bp->b_flags |= B_ERROR;
1594 0 : s = splbio();
1595 0 : biodone(bp);
1596 0 : splx(s);
1597 0 : return (error);
1598 : }
1599 0 : if (bp->b_blkno == -1)
1600 0 : clrbuf(bp);
1601 : }
1602 0 : if (bp->b_blkno == -1) {
1603 0 : s = splbio();
1604 0 : biodone(bp);
1605 0 : splx(s);
1606 0 : return (0);
1607 : }
1608 0 : vp = ip->i_devvp;
1609 0 : bp->b_dev = vp->v_rdev;
1610 0 : (vp->v_op->vop_strategy)(ap);
1611 0 : return (0);
1612 0 : }
1613 :
1614 : /*
1615 : * Print out the contents of an inode.
1616 : */
1617 : int
1618 0 : ufs_print(void *v)
1619 : {
1620 : #ifdef DIAGNOSTIC
1621 0 : struct vop_print_args *ap = v;
1622 :
1623 0 : struct vnode *vp = ap->a_vp;
1624 0 : struct inode *ip = VTOI(vp);
1625 :
1626 0 : printf("tag VT_UFS, ino %u, on dev %d, %d", ip->i_number,
1627 0 : major(ip->i_dev), minor(ip->i_dev));
1628 0 : printf(" flags 0x%x, effnlink %d, nlink %d\n",
1629 0 : ip->i_flag, ip->i_effnlink, DIP(ip, nlink));
1630 0 : printf("\tmode 0%o, owner %d, group %d, size %lld",
1631 0 : DIP(ip, mode), DIP(ip, uid), DIP(ip, gid), DIP(ip, size));
1632 :
1633 : #ifdef FIFO
1634 0 : if (vp->v_type == VFIFO)
1635 0 : fifo_printinfo(vp);
1636 : #endif /* FIFO */
1637 0 : printf("\n");
1638 :
1639 : #endif /* DIAGNOSTIC */
1640 :
1641 0 : return (0);
1642 : }
1643 :
1644 : /*
1645 : * Read wrapper for special devices.
1646 : */
1647 : int
1648 0 : ufsspec_read(void *v)
1649 : {
1650 0 : struct vop_read_args *ap = v;
1651 :
1652 : /*
1653 : * Set access flag.
1654 : */
1655 0 : VTOI(ap->a_vp)->i_flag |= IN_ACCESS;
1656 0 : return (spec_read(ap));
1657 : }
1658 :
1659 : /*
1660 : * Write wrapper for special devices.
1661 : */
1662 : int
1663 0 : ufsspec_write(void *v)
1664 : {
1665 0 : struct vop_write_args *ap = v;
1666 :
1667 : /*
1668 : * Set update and change flags.
1669 : */
1670 0 : VTOI(ap->a_vp)->i_flag |= IN_CHANGE | IN_UPDATE;
1671 0 : return (spec_write(ap));
1672 : }
1673 :
1674 : /*
1675 : * Close wrapper for special devices.
1676 : *
1677 : * Update the times on the inode then do device close.
1678 : */
1679 : int
1680 0 : ufsspec_close(void *v)
1681 : {
1682 0 : struct vop_close_args *ap = v;
1683 0 : struct vnode *vp = ap->a_vp;
1684 :
1685 0 : if (vp->v_usecount > 1)
1686 0 : ufs_itimes(vp);
1687 0 : return (spec_close(ap));
1688 : }
1689 :
1690 : #ifdef FIFO
1691 : /*
1692 : * Read wrapper for fifo's
1693 : */
1694 : int
1695 0 : ufsfifo_read(void *v)
1696 : {
1697 0 : struct vop_read_args *ap = v;
1698 :
1699 : /*
1700 : * Set access flag.
1701 : */
1702 0 : VTOI(ap->a_vp)->i_flag |= IN_ACCESS;
1703 0 : return (fifo_read(ap));
1704 : }
1705 :
1706 : /*
1707 : * Write wrapper for fifo's.
1708 : */
1709 : int
1710 0 : ufsfifo_write(void *v)
1711 : {
1712 0 : struct vop_write_args *ap = v;
1713 :
1714 : /*
1715 : * Set update and change flags.
1716 : */
1717 0 : VTOI(ap->a_vp)->i_flag |= IN_CHANGE | IN_UPDATE;
1718 0 : return (fifo_write(ap));
1719 : }
1720 :
1721 : /*
1722 : * Close wrapper for fifo's.
1723 : *
1724 : * Update the times on the inode then do device close.
1725 : */
1726 : int
1727 0 : ufsfifo_close(void *v)
1728 : {
1729 0 : struct vop_close_args *ap = v;
1730 0 : struct vnode *vp = ap->a_vp;
1731 :
1732 0 : if (vp->v_usecount > 1)
1733 0 : ufs_itimes(vp);
1734 0 : return (fifo_close(ap));
1735 : }
1736 : #endif /* FIFO */
1737 :
1738 : /*
1739 : * Return POSIX pathconf information applicable to ufs filesystems.
1740 : */
1741 : int
1742 0 : ufs_pathconf(void *v)
1743 : {
1744 0 : struct vop_pathconf_args *ap = v;
1745 : int error = 0;
1746 :
1747 0 : switch (ap->a_name) {
1748 : case _PC_LINK_MAX:
1749 0 : *ap->a_retval = LINK_MAX;
1750 0 : break;
1751 : case _PC_NAME_MAX:
1752 0 : *ap->a_retval = NAME_MAX;
1753 0 : break;
1754 : case _PC_CHOWN_RESTRICTED:
1755 0 : *ap->a_retval = 1;
1756 0 : break;
1757 : case _PC_NO_TRUNC:
1758 0 : *ap->a_retval = 1;
1759 0 : break;
1760 : case _PC_ALLOC_SIZE_MIN:
1761 0 : *ap->a_retval = ap->a_vp->v_mount->mnt_stat.f_bsize;
1762 0 : break;
1763 : case _PC_FILESIZEBITS:
1764 0 : *ap->a_retval = 64;
1765 0 : break;
1766 : case _PC_REC_INCR_XFER_SIZE:
1767 0 : *ap->a_retval = ap->a_vp->v_mount->mnt_stat.f_iosize;
1768 0 : break;
1769 : case _PC_REC_MAX_XFER_SIZE:
1770 0 : *ap->a_retval = -1; /* means ``unlimited'' */
1771 0 : break;
1772 : case _PC_REC_MIN_XFER_SIZE:
1773 0 : *ap->a_retval = ap->a_vp->v_mount->mnt_stat.f_iosize;
1774 0 : break;
1775 : case _PC_REC_XFER_ALIGN:
1776 0 : *ap->a_retval = PAGE_SIZE;
1777 0 : break;
1778 : case _PC_SYMLINK_MAX:
1779 0 : *ap->a_retval = MAXPATHLEN;
1780 0 : break;
1781 : case _PC_2_SYMLINKS:
1782 0 : *ap->a_retval = 1;
1783 0 : break;
1784 : case _PC_TIMESTAMP_RESOLUTION:
1785 0 : *ap->a_retval = 1;
1786 0 : break;
1787 : default:
1788 : error = EINVAL;
1789 0 : break;
1790 : }
1791 :
1792 0 : return (error);
1793 : }
1794 :
1795 : /*
1796 : * Advisory record locking support
1797 : */
1798 : int
1799 0 : ufs_advlock(void *v)
1800 : {
1801 0 : struct vop_advlock_args *ap = v;
1802 0 : struct inode *ip = VTOI(ap->a_vp);
1803 :
1804 0 : return (lf_advlock(&ip->i_lockf, DIP(ip, size), ap->a_id, ap->a_op,
1805 0 : ap->a_fl, ap->a_flags));
1806 : }
1807 :
1808 : /*
1809 : * Allocate a new inode.
1810 : */
1811 : int
1812 0 : ufs_makeinode(int mode, struct vnode *dvp, struct vnode **vpp,
1813 : struct componentname *cnp)
1814 : {
1815 : struct inode *ip, *pdir;
1816 0 : struct direct newdir;
1817 0 : struct vnode *tvp;
1818 : int error;
1819 :
1820 0 : pdir = VTOI(dvp);
1821 : #ifdef DIAGNOSTIC
1822 0 : if ((cnp->cn_flags & HASBUF) == 0)
1823 0 : panic("ufs_makeinode: no name");
1824 : #endif
1825 0 : *vpp = NULL;
1826 0 : if ((mode & IFMT) == 0)
1827 0 : mode |= IFREG;
1828 :
1829 0 : if ((error = UFS_INODE_ALLOC(pdir, mode, cnp->cn_cred, &tvp)) != 0) {
1830 0 : pool_put(&namei_pool, cnp->cn_pnbuf);
1831 0 : return (error);
1832 : }
1833 :
1834 0 : ip = VTOI(tvp);
1835 :
1836 0 : DIP_ASSIGN(ip, gid, DIP(pdir, gid));
1837 0 : DIP_ASSIGN(ip, uid, cnp->cn_cred->cr_uid);
1838 :
1839 0 : if ((error = getinoquota(ip)) ||
1840 0 : (error = ufs_quota_alloc_inode(ip, cnp->cn_cred))) {
1841 0 : pool_put(&namei_pool, cnp->cn_pnbuf);
1842 0 : UFS_INODE_FREE(ip, ip->i_number, mode);
1843 0 : vput(tvp);
1844 0 : return (error);
1845 : }
1846 :
1847 0 : ip->i_flag |= IN_ACCESS | IN_CHANGE | IN_UPDATE;
1848 0 : DIP_ASSIGN(ip, mode, mode);
1849 0 : tvp->v_type = IFTOVT(mode); /* Rest init'd in getnewvnode(). */
1850 0 : ip->i_effnlink = 1;
1851 0 : DIP_ASSIGN(ip, nlink, 1);
1852 0 : if (DOINGSOFTDEP(tvp))
1853 0 : softdep_change_linkcnt(ip, 0);
1854 0 : if ((DIP(ip, mode) & ISGID) &&
1855 0 : !groupmember(DIP(ip, gid), cnp->cn_cred) &&
1856 0 : (dvp->v_mount->mnt_flag & MNT_NOPERM) == 0 &&
1857 0 : suser_ucred(cnp->cn_cred))
1858 0 : DIP_AND(ip, mode, ~ISGID);
1859 :
1860 : /*
1861 : * Make sure inode goes to disk before directory entry.
1862 : */
1863 0 : if ((error = UFS_UPDATE(ip, !DOINGSOFTDEP(tvp))) != 0)
1864 : goto bad;
1865 :
1866 0 : ufs_makedirentry(ip, cnp, &newdir);
1867 0 : if ((error = ufs_direnter(dvp, tvp, &newdir, cnp, NULL)) != 0)
1868 : goto bad;
1869 :
1870 0 : if ((cnp->cn_flags & SAVESTART) == 0)
1871 0 : pool_put(&namei_pool, cnp->cn_pnbuf);
1872 0 : *vpp = tvp;
1873 0 : return (0);
1874 :
1875 : bad:
1876 : /*
1877 : * Write error occurred trying to update the inode
1878 : * or the directory so must deallocate the inode.
1879 : */
1880 0 : pool_put(&namei_pool, cnp->cn_pnbuf);
1881 0 : ip->i_effnlink = 0;
1882 0 : DIP_ASSIGN(ip, nlink, 0);
1883 0 : ip->i_flag |= IN_CHANGE;
1884 0 : if (DOINGSOFTDEP(tvp))
1885 0 : softdep_change_linkcnt(ip, 0);
1886 0 : tvp->v_type = VNON;
1887 0 : vput(tvp);
1888 :
1889 0 : return (error);
1890 0 : }
1891 :
1892 : struct filterops ufsread_filtops =
1893 : { 1, NULL, filt_ufsdetach, filt_ufsread };
1894 : struct filterops ufswrite_filtops =
1895 : { 1, NULL, filt_ufsdetach, filt_ufswrite };
1896 : struct filterops ufsvnode_filtops =
1897 : { 1, NULL, filt_ufsdetach, filt_ufsvnode };
1898 :
1899 : int
1900 0 : ufs_kqfilter(void *v)
1901 : {
1902 0 : struct vop_kqfilter_args *ap = v;
1903 0 : struct vnode *vp = ap->a_vp;
1904 0 : struct knote *kn = ap->a_kn;
1905 :
1906 0 : switch (kn->kn_filter) {
1907 : case EVFILT_READ:
1908 0 : kn->kn_fop = &ufsread_filtops;
1909 0 : break;
1910 : case EVFILT_WRITE:
1911 0 : kn->kn_fop = &ufswrite_filtops;
1912 0 : break;
1913 : case EVFILT_VNODE:
1914 0 : kn->kn_fop = &ufsvnode_filtops;
1915 0 : break;
1916 : default:
1917 0 : return (EINVAL);
1918 : }
1919 :
1920 0 : kn->kn_hook = (caddr_t)vp;
1921 :
1922 0 : SLIST_INSERT_HEAD(&vp->v_selectinfo.si_note, kn, kn_selnext);
1923 :
1924 0 : return (0);
1925 0 : }
1926 :
1927 : void
1928 0 : filt_ufsdetach(struct knote *kn)
1929 : {
1930 0 : struct vnode *vp = (struct vnode *)kn->kn_hook;
1931 :
1932 0 : SLIST_REMOVE(&vp->v_selectinfo.si_note, kn, knote, kn_selnext);
1933 0 : }
1934 :
1935 : int
1936 0 : filt_ufsread(struct knote *kn, long hint)
1937 : {
1938 0 : struct vnode *vp = (struct vnode *)kn->kn_hook;
1939 0 : struct inode *ip = VTOI(vp);
1940 :
1941 : /*
1942 : * filesystem is gone, so set the EOF flag and schedule
1943 : * the knote for deletion.
1944 : */
1945 0 : if (hint == NOTE_REVOKE) {
1946 0 : kn->kn_flags |= (EV_EOF | EV_ONESHOT);
1947 0 : return (1);
1948 : }
1949 :
1950 : #ifdef EXT2FS
1951 0 : if (IS_EXT2_VNODE(ip->i_vnode))
1952 0 : kn->kn_data = ext2fs_size(ip) - kn->kn_fp->f_offset;
1953 : else
1954 : #endif
1955 0 : kn->kn_data = DIP(ip, size) - kn->kn_fp->f_offset;
1956 0 : if (kn->kn_data == 0 && kn->kn_sfflags & NOTE_EOF) {
1957 0 : kn->kn_fflags |= NOTE_EOF;
1958 0 : return (1);
1959 : }
1960 :
1961 0 : return (kn->kn_data != 0);
1962 0 : }
1963 :
1964 : int
1965 0 : filt_ufswrite(struct knote *kn, long hint)
1966 : {
1967 : /*
1968 : * filesystem is gone, so set the EOF flag and schedule
1969 : * the knote for deletion.
1970 : */
1971 0 : if (hint == NOTE_REVOKE) {
1972 0 : kn->kn_flags |= (EV_EOF | EV_ONESHOT);
1973 0 : return (1);
1974 : }
1975 :
1976 0 : kn->kn_data = 0;
1977 0 : return (1);
1978 0 : }
1979 :
1980 : int
1981 0 : filt_ufsvnode(struct knote *kn, long hint)
1982 : {
1983 0 : if (kn->kn_sfflags & hint)
1984 0 : kn->kn_fflags |= hint;
1985 0 : if (hint == NOTE_REVOKE) {
1986 0 : kn->kn_flags |= EV_EOF;
1987 0 : return (1);
1988 : }
1989 0 : return (kn->kn_fflags != 0);
1990 0 : }
|