1 /*        $NetBSD: sysvbfs_vnops.c,v 1.69 2022/07/31 13:08:18 mlelstv Exp $     */
2 
3 /*-
4  * Copyright (c) 2004 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD Foundation
8  * by UCHIYAMA Yasushi.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29  * POSSIBILITY OF SUCH DAMAGE.
30  */
31 
32 #include <sys/cdefs.h>
33 __KERNEL_RCSID(0, "$NetBSD: sysvbfs_vnops.c,v 1.69 2022/07/31 13:08:18 mlelstv Exp $");
34 
35 #include <sys/param.h>
36 #include <sys/kernel.h>
37 #include <sys/resource.h>
38 #include <sys/vnode.h>
39 #include <sys/namei.h>
40 #include <sys/dirent.h>
41 #include <sys/malloc.h>
42 #include <sys/lockf.h>
43 #include <sys/unistd.h>
44 #include <sys/fcntl.h>
45 #include <sys/kauth.h>
46 #include <sys/buf.h>
47 
48 #include <miscfs/genfs/genfs.h>
49 
50 #include <fs/sysvbfs/sysvbfs.h>
51 #include <fs/sysvbfs/bfs.h>
52 
53 #ifdef SYSVBFS_VNOPS_DEBUG
54 #define   DPRINTF(fmt, args...)         printf(fmt, ##args)
55 #else
56 #define   DPRINTF(arg...)               ((void)0)
57 #endif
58 #define   ROUND_SECTOR(x)               (((x) + 511) & ~511)
59 
60 MALLOC_JUSTDEFINE(M_SYSVBFS_VNODE, "sysvbfs vnode", "sysvbfs vnode structures");
61 MALLOC_DECLARE(M_BFS);
62 
63 static void sysvbfs_file_setsize(struct vnode *, size_t);
64 
65 int
sysvbfs_lookup(void * arg)66 sysvbfs_lookup(void *arg)
67 {
68           struct vop_lookup_v2_args /* {
69                     struct vnode *a_dvp;
70                     struct vnode **a_vpp;
71                     struct componentname *a_cnp;
72           } */ *a = arg;
73           struct vnode *v = a->a_dvp;
74           struct sysvbfs_node *bnode = v->v_data;
75           struct bfs *bfs = bnode->bmp->bfs;      /* my filesystem */
76           struct vnode *vpp = NULL;
77           struct bfs_dirent *dirent = NULL;
78           struct componentname *cnp = a->a_cnp;
79           int nameiop = cnp->cn_nameiop;
80           const char *name = cnp->cn_nameptr;
81           int namelen = cnp->cn_namelen;
82           int error;
83 
84           DPRINTF("%s: %s op=%d %d\n", __func__, name, nameiop,
85               cnp->cn_flags);
86 
87           *a->a_vpp = NULL;
88 
89           KASSERT((cnp->cn_flags & ISDOTDOT) == 0);
90 
91           if ((error = VOP_ACCESS(a->a_dvp, VEXEC, cnp->cn_cred)) != 0) {
92                     return error;       /* directory permission. */
93           }
94 
95           /* Deny last component write operation on a read-only mount */
96           if ((cnp->cn_flags & ISLASTCN) && (v->v_mount->mnt_flag & MNT_RDONLY) &&
97               (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME))
98                     return EROFS;
99 
100           if (namelen == 1 && name[0] == '.') {   /* "." */
101                     vref(v);
102                     *a->a_vpp = v;
103           } else {                                /* Regular file */
104                     if (!bfs_dirent_lookup_by_name(bfs, cnp->cn_nameptr,
105                         &dirent)) {
106                               if (nameiop != CREATE && nameiop != RENAME) {
107                                         DPRINTF("%s: no such a file. (1)\n",
108                                             __func__);
109                                         return ENOENT;
110                               }
111                               if ((error = VOP_ACCESS(v, VWRITE, cnp->cn_cred)) != 0)
112                                         return error;
113                               return EJUSTRETURN;
114                     }
115 
116                     /* Allocate v-node */
117                     error = sysvbfs_vget(v->v_mount, dirent->inode,
118                         LK_EXCLUSIVE, &vpp);
119                     if (error != 0) {
120                               DPRINTF("%s: can't get vnode.\n", __func__);
121                               return error;
122                     }
123                     VOP_UNLOCK(vpp);
124                     *a->a_vpp = vpp;
125           }
126 
127           return 0;
128 }
129 
130 int
sysvbfs_create(void * arg)131 sysvbfs_create(void *arg)
132 {
133           struct vop_create_v3_args /* {
134                     struct vnode *a_dvp;
135                     struct vnode **a_vpp;
136                     struct componentname *a_cnp;
137                     struct vattr *a_vap;
138           } */ *a = arg;
139           struct sysvbfs_node *bnode = a->a_dvp->v_data;
140           struct sysvbfs_mount *bmp = bnode->bmp;
141           struct bfs *bfs = bmp->bfs;
142           struct mount *mp = bmp->mountp;
143           struct bfs_dirent *dirent;
144           struct bfs_fileattr attr;
145           struct vattr *va = a->a_vap;
146           kauth_cred_t cr = a->a_cnp->cn_cred;
147           int err = 0;
148 
149           DPRINTF("%s: %s\n", __func__, a->a_cnp->cn_nameptr);
150           KDASSERT(a->a_vap->va_type == VREG);
151           attr.uid = kauth_cred_geteuid(cr);
152           attr.gid = kauth_cred_getegid(cr);
153           attr.mode = va->va_mode;
154 
155           if ((err = bfs_file_create(bfs, a->a_cnp->cn_nameptr, 0, 0, &attr))
156               != 0) {
157                     DPRINTF("%s: bfs_file_create failed.\n", __func__);
158                     return err;
159           }
160 
161           if (!bfs_dirent_lookup_by_name(bfs, a->a_cnp->cn_nameptr, &dirent))
162                     panic("no dirent for created file.");
163 
164           err = sysvbfs_vget(mp, dirent->inode, LK_EXCLUSIVE, a->a_vpp);
165           if (err != 0) {
166                     DPRINTF("%s: sysvbfs_vget failed.\n", __func__);
167                     return err;
168           }
169           bnode = (*a->a_vpp)->v_data;
170           bnode->update_ctime = true;
171           bnode->update_mtime = true;
172           bnode->update_atime = true;
173           VOP_UNLOCK(*a->a_vpp);
174 
175           return err;
176 }
177 
178 int
sysvbfs_open(void * arg)179 sysvbfs_open(void *arg)
180 {
181           struct vop_open_args /* {
182                     struct vnode *a_vp;
183                     int  a_mode;
184                     kauth_cred_t a_cred;
185           } */ *a = arg;
186           struct vnode *v = a->a_vp;
187           struct sysvbfs_node *bnode = v->v_data;
188           struct bfs_inode *inode = bnode->inode;
189 
190           DPRINTF("%s:\n", __func__);
191           KDASSERT(v->v_type == VREG || v->v_type == VDIR);
192 
193           bnode->update_atime = true;
194           if ((a->a_mode & FWRITE) && !(a->a_mode & O_APPEND)) {
195                     bnode->size = 0;
196           } else {
197                     bnode->size = bfs_file_size(inode);
198           }
199           bnode->data_block = inode->start_sector;
200 
201           return 0;
202 }
203 
204 int
sysvbfs_close(void * arg)205 sysvbfs_close(void *arg)
206 {
207           struct vop_close_args /* {
208                     struct vnodeop_desc *a_desc;
209                     struct vnode *a_vp;
210                     int  a_fflag;
211                     kauth_cred_t a_cred;
212           } */ *a = arg;
213           struct vnode *v = a->a_vp;
214           struct sysvbfs_node *bnode = v->v_data;
215           struct bfs_fileattr attr;
216 
217           DPRINTF("%s:\n", __func__);
218 
219           if (v->v_mount->mnt_flag & MNT_RDONLY)
220                     goto out;
221 
222           uvm_vnp_setsize(v, bnode->size);
223 
224           memset(&attr, 0xff, sizeof attr);       /* Set VNOVAL all */
225           if (bnode->update_atime)
226                     attr.atime = time_second;
227           if (bnode->update_ctime)
228                     attr.ctime = time_second;
229           if (bnode->update_mtime)
230                     attr.mtime = time_second;
231           bfs_inode_set_attr(bnode->bmp->bfs, bnode->inode, &attr);
232 
233           VOP_FSYNC(a->a_vp, a->a_cred, FSYNC_WAIT, 0, 0);
234 
235  out:
236           return 0;
237 }
238 
239 static int
sysvbfs_check_possible(struct vnode * vp,struct sysvbfs_node * bnode,mode_t mode)240 sysvbfs_check_possible(struct vnode *vp, struct sysvbfs_node *bnode,
241     mode_t mode)
242 {
243 
244           if ((mode & VWRITE) && (vp->v_mount->mnt_flag & MNT_RDONLY))
245                     return EROFS;
246 
247           return 0;
248 }
249 
250 static int
sysvbfs_check_permitted(struct vnode * vp,struct sysvbfs_node * bnode,accmode_t accmode,kauth_cred_t cred)251 sysvbfs_check_permitted(struct vnode *vp, struct sysvbfs_node *bnode,
252     accmode_t accmode, kauth_cred_t cred)
253 {
254           struct bfs_fileattr *attr = &bnode->inode->attr;
255 
256           return kauth_authorize_vnode(cred, KAUTH_ACCESS_ACTION(accmode,
257               vp->v_type, attr->mode), vp, NULL, genfs_can_access(vp, cred,
258               attr->uid, attr->gid, attr->mode, NULL, accmode));
259 }
260 
261 int
sysvbfs_access(void * arg)262 sysvbfs_access(void *arg)
263 {
264           struct vop_access_args /* {
265                     struct vnode        *a_vp;
266                     accmode_t a_accmode;
267                     kauth_cred_t        a_cred;
268           } */ *ap = arg;
269           struct vnode *vp = ap->a_vp;
270           struct sysvbfs_node *bnode = vp->v_data;
271           int error;
272 
273           DPRINTF("%s:\n", __func__);
274 
275           error = sysvbfs_check_possible(vp, bnode, ap->a_accmode);
276           if (error)
277                     return error;
278 
279           error = sysvbfs_check_permitted(vp, bnode, ap->a_accmode, ap->a_cred);
280 
281           return error;
282 }
283 
284 int
sysvbfs_getattr(void * v)285 sysvbfs_getattr(void *v)
286 {
287           struct vop_getattr_args /* {
288                     struct vnode *a_vp;
289                     struct vattr *a_vap;
290                     kauth_cred_t a_cred;
291           } */ *ap = v;
292           struct vnode *vp = ap->a_vp;
293           struct sysvbfs_node *bnode = vp->v_data;
294           struct bfs_inode *inode = bnode->inode;
295           struct bfs_fileattr *attr = &inode->attr;
296           struct sysvbfs_mount *bmp = bnode->bmp;
297           struct vattr *vap = ap->a_vap;
298 
299           DPRINTF("%s:\n", __func__);
300 
301           vap->va_type = vp->v_type;
302           vap->va_mode = attr->mode;
303           vap->va_nlink = attr->nlink;
304           vap->va_uid = attr->uid;
305           vap->va_gid = attr->gid;
306           vap->va_fsid = bmp->devvp->v_rdev;
307           vap->va_fileid = inode->number;
308           vap->va_size = bfs_file_size(inode);
309           vap->va_blocksize = BFS_BSIZE;
310           vap->va_atime.tv_sec = attr->atime;
311           vap->va_mtime.tv_sec = attr->mtime;
312           vap->va_ctime.tv_sec = attr->ctime;
313           vap->va_birthtime.tv_sec = 0;
314           vap->va_gen = 1;
315           vap->va_flags = 0;
316           vap->va_rdev = 0;   /* No device file */
317           vap->va_bytes = vap->va_size;
318           vap->va_filerev = 0;
319           vap->va_vaflags = 0;
320 
321           return 0;
322 }
323 
324 int
sysvbfs_setattr(void * arg)325 sysvbfs_setattr(void *arg)
326 {
327           struct vop_setattr_args /* {
328                     struct vnode *a_vp;
329                     struct vattr *a_vap;
330                     kauth_cred_t a_cred;
331                     struct proc *p;
332           } */ *ap = arg;
333           struct vnode *vp = ap->a_vp;
334           struct vattr *vap = ap->a_vap;
335           struct sysvbfs_node *bnode = vp->v_data;
336           struct bfs_inode *inode = bnode->inode;
337           struct bfs_fileattr *attr = &inode->attr;
338           struct bfs *bfs = bnode->bmp->bfs;
339           kauth_cred_t cred = ap->a_cred;
340           int error;
341 
342           DPRINTF("%s:\n", __func__);
343           if (vp->v_mount->mnt_flag & MNT_RDONLY)
344                     return EROFS;
345 
346           if ((vap->va_type != VNON) || (vap->va_nlink != VNOVAL) ||
347               (vap->va_fsid != VNOVAL) || (vap->va_fileid != VNOVAL) ||
348               (vap->va_blocksize != VNOVAL) || (vap->va_rdev != VNOVAL) ||
349               ((int)vap->va_bytes != VNOVAL) || (vap->va_gen != VNOVAL))
350                     return EINVAL;
351 
352           if (vap->va_flags != VNOVAL)
353                     return EOPNOTSUPP;
354 
355           if (vap->va_uid != (uid_t)VNOVAL || vap->va_gid != (gid_t)VNOVAL) {
356                     uid_t uid =
357                         (vap->va_uid != (uid_t)VNOVAL) ? vap->va_uid : attr->uid;
358                     gid_t gid =
359                         (vap->va_gid != (gid_t)VNOVAL) ? vap->va_gid : attr->gid;
360                     error = kauth_authorize_vnode(cred,
361                         KAUTH_VNODE_CHANGE_OWNERSHIP, vp, NULL,
362                         genfs_can_chown(vp, cred, attr->uid, attr->gid, uid, gid));
363                     if (error)
364                               return error;
365                     attr->uid = uid;
366                     attr->gid = gid;
367           }
368 
369           if (vap->va_size != VNOVAL)
370                     switch (vp->v_type) {
371                     case VDIR:
372                               return EISDIR;
373                     case VCHR:
374                     case VBLK:
375                     case VFIFO:
376                               break;
377                     case VREG:
378                               if (vp->v_mount->mnt_flag & MNT_RDONLY)
379                                         return EROFS;
380                               sysvbfs_file_setsize(vp, vap->va_size);
381                               break;
382                     default:
383                               return EOPNOTSUPP;
384                     }
385 
386           if (vap->va_mode != (mode_t)VNOVAL) {
387                     mode_t mode = vap->va_mode;
388                     error = kauth_authorize_vnode(cred, KAUTH_VNODE_WRITE_SECURITY,
389                         vp, NULL, genfs_can_chmod(vp, cred, attr->uid,
390                         attr->gid, mode));
391                     if (error)
392                               return error;
393                     attr->mode = mode;
394           }
395 
396           if ((vap->va_atime.tv_sec != VNOVAL) ||
397               (vap->va_mtime.tv_sec != VNOVAL) ||
398               (vap->va_ctime.tv_sec != VNOVAL)) {
399                     error = kauth_authorize_vnode(cred, KAUTH_VNODE_WRITE_TIMES, vp,
400                         NULL, genfs_can_chtimes(vp, cred, attr->uid,
401                               vap->va_vaflags));
402                     if (error)
403                               return error;
404 
405                     if (vap->va_atime.tv_sec != VNOVAL)
406                               attr->atime = vap->va_atime.tv_sec;
407                     if (vap->va_mtime.tv_sec != VNOVAL)
408                               attr->mtime = vap->va_mtime.tv_sec;
409                     if (vap->va_ctime.tv_sec != VNOVAL)
410                               attr->ctime = vap->va_ctime.tv_sec;
411           }
412 
413           bfs_inode_set_attr(bfs, inode, attr);
414 
415           return 0;
416 }
417 
418 int
sysvbfs_read(void * arg)419 sysvbfs_read(void *arg)
420 {
421           struct vop_read_args /* {
422                     struct vnode *a_vp;
423                     struct uio *a_uio;
424                     int a_ioflag;
425                     kauth_cred_t a_cred;
426           } */ *a = arg;
427           struct vnode *v = a->a_vp;
428           struct uio *uio = a->a_uio;
429           struct sysvbfs_node *bnode = v->v_data;
430           struct bfs_inode *inode = bnode->inode;
431           vsize_t sz, filesz = bfs_file_size(inode);
432           int err, uerr;
433           const int advice = IO_ADV_DECODE(a->a_ioflag);
434 
435           DPRINTF("%s: type=%d\n", __func__, v->v_type);
436           switch (v->v_type) {
437           case VREG:
438                     break;
439           case VDIR:
440                     return EISDIR;
441           default:
442                     return EINVAL;
443           }
444 
445           err = 0;
446           while (uio->uio_resid > 0) {
447                     if ((sz = MIN(filesz - uio->uio_offset, uio->uio_resid)) == 0)
448                               break;
449 
450                     err = ubc_uiomove(&v->v_uobj, uio, sz, advice,
451                         UBC_READ | UBC_PARTIALOK | UBC_VNODE_FLAGS(v));
452                     if (err)
453                               break;
454                     DPRINTF("%s: read %ldbyte\n", __func__, sz);
455           }
456 
457           uerr = sysvbfs_update(v, NULL, NULL, UPDATE_WAIT);
458           if (err == 0)
459                     err = uerr;
460 
461           return err;
462 }
463 
464 int
sysvbfs_write(void * arg)465 sysvbfs_write(void *arg)
466 {
467           struct vop_write_args /* {
468                     struct vnode *a_vp;
469                     struct uio *a_uio;
470                     int  a_ioflag;
471                     kauth_cred_t a_cred;
472           } */ *a = arg;
473           struct vnode *v = a->a_vp;
474           struct uio *uio = a->a_uio;
475           int advice = IO_ADV_DECODE(a->a_ioflag);
476           struct sysvbfs_node *bnode = v->v_data;
477           vsize_t sz;
478           int err = 0;
479 
480           if (a->a_vp->v_type != VREG)
481                     return EISDIR;
482 
483           if (a->a_ioflag & IO_APPEND)
484                     uio->uio_offset = bnode->size;
485 
486           if (uio->uio_resid == 0)
487                     return 0;
488 
489           if (bnode->size < uio->uio_offset + uio->uio_resid) {
490                     sysvbfs_file_setsize(v, uio->uio_offset + uio->uio_resid);
491           }
492 
493           while (uio->uio_resid > 0) {
494                     sz = uio->uio_resid;
495                     err = ubc_uiomove(&v->v_uobj, uio, sz, advice,
496                         UBC_WRITE | UBC_VNODE_FLAGS(v));
497                     if (err)
498                               break;
499                     DPRINTF("%s: write %ldbyte\n", __func__, sz);
500           }
501           if (err)
502                     sysvbfs_file_setsize(v, bnode->size - uio->uio_resid);
503 
504           return err;
505 }
506 
507 int
sysvbfs_remove(void * arg)508 sysvbfs_remove(void *arg)
509 {
510           struct vop_remove_v3_args /* {
511                     struct vnodeop_desc *a_desc;
512                     struct vnode * a_dvp;
513                     struct vnode * a_vp;
514                     struct componentname * a_cnp;
515                     nlink_t ctx_vp_new_nlink;
516           } */ *ap = arg;
517           struct vnode *vp = ap->a_vp;
518           struct vnode *dvp = ap->a_dvp;
519           struct sysvbfs_node *bnode = vp->v_data;
520           struct sysvbfs_mount *bmp = bnode->bmp;
521           struct bfs *bfs = bmp->bfs;
522           int err;
523 
524           DPRINTF("%s: delete %s\n", __func__, ap->a_cnp->cn_nameptr);
525 
526           if (vp->v_type == VDIR) {
527                     vrele(vp);
528                     return EPERM;
529           }
530 
531           if ((err = bfs_file_delete(bfs, ap->a_cnp->cn_nameptr, true)) != 0)
532                     DPRINTF("%s: bfs_file_delete failed.\n", __func__);
533 
534           if (dvp == vp)
535                     vrele(vp);
536           else
537                     vput(vp);
538 
539           if (err == 0) {
540                     bnode->removed = 1;
541           }
542 
543           return err;
544 }
545 
546 int
sysvbfs_rename(void * arg)547 sysvbfs_rename(void *arg)
548 {
549           struct vop_rename_args /* {
550                     struct vnode *a_fdvp;         from parent-directory v-node
551                     struct vnode *a_fvp;          from file v-node
552                     struct componentname *a_fcnp;
553                     struct vnode *a_tdvp;         to parent-directory
554                     struct vnode *a_tvp;          to file v-node
555                     struct componentname *a_tcnp;
556           } */ *ap = arg;
557           struct vnode *fvp = ap->a_fvp;
558           struct vnode *fdvp = ap->a_fdvp;
559           struct vnode *tvp = ap->a_tvp;
560           struct vnode *tdvp = ap->a_tdvp;
561           struct sysvbfs_node *bnode = fvp->v_data;
562           struct bfs *bfs = bnode->bmp->bfs;
563           const char *from_name = ap->a_fcnp->cn_nameptr;
564           const char *to_name = ap->a_tcnp->cn_nameptr;
565           int error;
566 
567           DPRINTF("%s: %s->%s\n", __func__, from_name, to_name);
568           if ((fvp->v_mount != tdvp->v_mount) ||
569               (tvp && (fvp->v_mount != tvp->v_mount))) {
570                     error = EXDEV;
571                     printf("cross-device link\n");
572                     goto out;
573           }
574 
575           KDASSERT(fvp->v_type == VREG);
576           KDASSERT(tvp == NULL ? true : tvp->v_type == VREG);
577           KASSERT(tdvp == fdvp);
578 
579           /*
580            * Make sure the source hasn't been removed between lookup
581            * and target directory lock.
582            */
583           if (bnode->removed) {
584                     error = ENOENT;
585                     goto out;
586           }
587 
588           /*
589            * Remove the target if it exists.
590            */
591           if (tvp != NULL) {
592                     error = bfs_file_delete(bfs, to_name, true);
593                     if (error)
594                               goto out;
595           }
596           error = bfs_file_rename(bfs, from_name, to_name);
597  out:
598           /* tdvp == tvp probably can't happen with this fs, but safety first */
599           if (tdvp == tvp)
600                     vrele(tdvp);
601           else
602                     vput(tdvp);
603           if (tvp)
604                     vput(tvp);
605 
606           vrele(fdvp);
607           vrele(fvp);
608 
609           return 0;
610 }
611 
612 int
sysvbfs_readdir(void * v)613 sysvbfs_readdir(void *v)
614 {
615           struct vop_readdir_args /* {
616                     struct vnode *a_vp;
617                     struct uio *a_uio;
618                     kauth_cred_t a_cred;
619                     int *a_eofflag;
620                     off_t **a_cookies;
621                     int *a_ncookies;
622           } */ *ap = v;
623           struct uio *uio = ap->a_uio;
624           struct vnode *vp = ap->a_vp;
625           struct sysvbfs_node *bnode = vp->v_data;
626           struct bfs *bfs = bnode->bmp->bfs;
627           struct dirent *dp;
628           struct bfs_dirent *file;
629           int i, n, error;
630 
631           DPRINTF("%s: offset=%" PRId64 " residue=%zu\n", __func__,
632               uio->uio_offset, uio->uio_resid);
633 
634           KDASSERT(vp->v_type == VDIR);
635 
636           if (uio->uio_offset < 0)
637                     return EINVAL;
638 
639           dp = malloc(sizeof(struct dirent), M_BFS, M_WAITOK | M_ZERO);
640 
641           i = uio->uio_offset / sizeof(struct dirent);
642           n = uio->uio_resid / sizeof(struct dirent);
643           if ((i + n) > bfs->n_dirent)
644                     n = bfs->n_dirent - i;
645 
646           DPRINTF("%s 1: %d %d %d\n", __func__, i, n, bfs->n_dirent);
647           for (file = &bfs->dirent[i]; n > 0; file++, i++) {
648                     if (i == bfs->max_dirent) {
649                               DPRINTF("%s: file system inconsistent.\n",
650                                   __func__);
651                               break;
652                     }
653                     if (file->inode == 0)
654                               continue;
655 
656                     /* ok, we have a live one here */
657                     n--;
658                     memset(dp, 0, sizeof(struct dirent));
659                     dp->d_fileno = file->inode;
660                     dp->d_type = file->inode == BFS_ROOT_INODE ? DT_DIR : DT_REG;
661                     dp->d_namlen = strlen(file->name);
662                     strncpy(dp->d_name, file->name, BFS_FILENAME_MAXLEN);
663                     dp->d_reclen = sizeof(struct dirent);
664                     if ((error = uiomove(dp, dp->d_reclen, uio)) != 0) {
665                               DPRINTF("%s: uiomove failed.\n", __func__);
666                               free(dp, M_BFS);
667                               return error;
668                     }
669           }
670           DPRINTF("%s 2: %d %d %d\n", __func__, i, n, bfs->n_dirent);
671           *ap->a_eofflag = (i == bfs->n_dirent);
672 
673           free(dp, M_BFS);
674           return 0;
675 }
676 
677 int
sysvbfs_inactive(void * arg)678 sysvbfs_inactive(void *arg)
679 {
680           struct vop_inactive_v2_args /* {
681                     struct vnode *a_vp;
682                     bool *a_recycle;
683           } */ *a = arg;
684           struct vnode *v = a->a_vp;
685           struct sysvbfs_node *bnode = v->v_data;
686 
687           DPRINTF("%s:\n", __func__);
688           if (bnode->removed)
689                     *a->a_recycle = true;
690           else
691                     *a->a_recycle = false;
692 
693           return 0;
694 }
695 
696 int
sysvbfs_reclaim(void * v)697 sysvbfs_reclaim(void *v)
698 {
699           extern struct pool sysvbfs_node_pool;
700           struct vop_reclaim_v2_args /* {
701                     struct vnode *a_vp;
702           } */ *ap = v;
703           struct vnode *vp = ap->a_vp;
704           struct sysvbfs_node *bnode = vp->v_data;
705           struct bfs *bfs = bnode->bmp->bfs;
706 
707           VOP_UNLOCK(vp);
708 
709           DPRINTF("%s:\n", __func__);
710 
711           if (bnode->removed) {
712                     if (bfs_inode_delete(bfs, bnode->inode->number) != 0)
713                               DPRINTF("%s: delete inode failed\n", __func__);
714           }
715           genfs_node_destroy(vp);
716           pool_put(&sysvbfs_node_pool, bnode);
717           vp->v_data = NULL;
718 
719           return 0;
720 }
721 
722 int
sysvbfs_bmap(void * arg)723 sysvbfs_bmap(void *arg)
724 {
725           struct vop_bmap_args /* {
726                     struct vnode *a_vp;
727                     daddr_t  a_bn;
728                     struct vnode **a_vpp;
729                     daddr_t *a_bnp;
730                     int *a_runp;
731           } */ *a = arg;
732           struct vnode *v = a->a_vp;
733           struct sysvbfs_node *bnode = v->v_data;
734           struct sysvbfs_mount *bmp = bnode->bmp;
735           struct bfs_inode *inode = bnode->inode;
736           daddr_t blk;
737 
738           DPRINTF("%s:\n", __func__);
739           /* BFS algorithm is contiguous allocation */
740           blk = inode->start_sector + a->a_bn;
741 
742           if (blk * BFS_BSIZE > bmp->bfs->data_end)
743                     return ENOSPC;
744 
745           *a->a_vpp = bmp->devvp;
746           *a->a_runp = 0;
747           DPRINTF("%s: %d + %" PRId64 "\n", __func__, inode->start_sector,
748               a->a_bn);
749 
750           *a->a_bnp = blk;
751 
752 
753           return 0;
754 }
755 
756 int
sysvbfs_strategy(void * arg)757 sysvbfs_strategy(void *arg)
758 {
759           struct vop_strategy_args /* {
760                     struct vnode *a_vp;
761                     struct buf *a_bp;
762           } */ *a = arg;
763           struct buf *b = a->a_bp;
764           struct vnode *v = a->a_vp;
765           struct sysvbfs_node *bnode = v->v_data;
766           struct sysvbfs_mount *bmp = bnode->bmp;
767           int error;
768 
769           DPRINTF("%s:\n", __func__);
770           KDASSERT(v->v_type == VREG);
771           if (b->b_blkno == b->b_lblkno) {
772                     error = VOP_BMAP(v, b->b_lblkno, NULL, &b->b_blkno, NULL);
773                     if (error) {
774                               b->b_error = error;
775                               biodone(b);
776                               return error;
777                     }
778                     if ((long)b->b_blkno == -1)
779                               clrbuf(b);
780           }
781           if ((long)b->b_blkno == -1) {
782                     biodone(b);
783                     return 0;
784           }
785 
786           return VOP_STRATEGY(bmp->devvp, b);
787 }
788 
789 int
sysvbfs_print(void * v)790 sysvbfs_print(void *v)
791 {
792           struct vop_print_args /* {
793                     struct vnode *a_vp;
794           } */ *ap = v;
795           struct sysvbfs_node *bnode = ap->a_vp->v_data;
796 
797           DPRINTF("%s:\n", __func__);
798           bfs_dump(bnode->bmp->bfs);
799 
800           return 0;
801 }
802 
803 int
sysvbfs_advlock(void * v)804 sysvbfs_advlock(void *v)
805 {
806           struct vop_advlock_args /* {
807                     struct vnode *a_vp;
808                     void *a_id;
809                     int a_op;
810                     struct flock *a_fl;
811                     int a_flags;
812           } */ *ap = v;
813           struct sysvbfs_node *bnode = ap->a_vp->v_data;
814 
815           DPRINTF("%s: op=%d\n", __func__, ap->a_op);
816 
817           return lf_advlock(ap, &bnode->lockf, bfs_file_size(bnode->inode));
818 }
819 
820 int
sysvbfs_pathconf(void * v)821 sysvbfs_pathconf(void *v)
822 {
823           struct vop_pathconf_args /* {
824                     struct vnode *a_vp;
825                     int a_name;
826                     register_t *a_retval;
827           } */ *ap = v;
828 
829           DPRINTF("%s:\n", __func__);
830 
831           switch (ap->a_name) {
832           case _PC_LINK_MAX:
833                     *ap->a_retval = 1;
834                     return 0;
835           case _PC_NAME_MAX:
836                     *ap->a_retval = BFS_FILENAME_MAXLEN;
837                     return 0;
838           case _PC_PATH_MAX:
839                     *ap->a_retval = BFS_FILENAME_MAXLEN;
840                     return 0;
841           case _PC_CHOWN_RESTRICTED:
842                     *ap->a_retval = 1;
843                     return 0;
844           case _PC_NO_TRUNC:
845                     *ap->a_retval = 0;
846                     return 0;
847           case _PC_SYNC_IO:
848                     *ap->a_retval = 1;
849                     return 0;
850           case _PC_FILESIZEBITS:
851                     *ap->a_retval = 32;
852                     return 0;
853           default:
854                     return genfs_pathconf(ap);
855           }
856 }
857 
858 int
sysvbfs_fsync(void * v)859 sysvbfs_fsync(void *v)
860 {
861           struct vop_fsync_args /* {
862                     struct vnode *a_vp;
863                     kauth_cred_t a_cred;
864                     int a_flags;
865                     off_t offlo;
866                     off_t offhi;
867           } */ *ap = v;
868           struct vnode *vp = ap->a_vp;
869           int error, wait;
870 
871           if (ap->a_flags & FSYNC_CACHE) {
872                     return EOPNOTSUPP;
873           }
874 
875           wait = (ap->a_flags & FSYNC_WAIT) != 0;
876           error = vflushbuf(vp, ap->a_flags);
877           if (error == 0 && (ap->a_flags & FSYNC_DATAONLY) == 0)
878                     error = sysvbfs_update(vp, NULL, NULL, wait ? UPDATE_WAIT : 0);
879 
880           return error;
881 }
882 
883 int
sysvbfs_update(struct vnode * vp,const struct timespec * acc,const struct timespec * mod,int flags)884 sysvbfs_update(struct vnode *vp, const struct timespec *acc,
885     const struct timespec *mod, int flags)
886 {
887           struct sysvbfs_node *bnode = vp->v_data;
888           struct bfs_fileattr attr;
889 
890           if (vp->v_mount->mnt_flag & MNT_RDONLY)
891                     return 0;
892 
893           DPRINTF("%s:\n", __func__);
894           memset(&attr, 0xff, sizeof attr);       /* Set VNOVAL all */
895           if (bnode->update_atime) {
896                     attr.atime = acc ? acc->tv_sec : time_second;
897                     bnode->update_atime = false;
898           }
899           if (bnode->update_ctime) {
900                     attr.ctime = time_second;
901                     bnode->update_ctime = false;
902           }
903           if (bnode->update_mtime) {
904                     attr.mtime = mod ? mod->tv_sec : time_second;
905                     bnode->update_mtime = false;
906           }
907           bfs_inode_set_attr(bnode->bmp->bfs, bnode->inode, &attr);
908 
909           return 0;
910 }
911 
912 static void
sysvbfs_file_setsize(struct vnode * v,size_t size)913 sysvbfs_file_setsize(struct vnode *v, size_t size)
914 {
915           struct sysvbfs_node *bnode = v->v_data;
916           struct bfs_inode *inode = bnode->inode;
917 
918           bnode->size = size;
919           uvm_vnp_setsize(v, bnode->size);
920           inode->end_sector = bnode->data_block +
921               (ROUND_SECTOR(bnode->size) >> DEV_BSHIFT) - 1;
922           inode->eof_offset_byte = bnode->data_block * DEV_BSIZE +
923               bnode->size - 1;
924           bnode->update_mtime = true;
925 }
926