1 /*        $NetBSD: hfs_vnops.c,v 1.40 2022/08/06 18:26:42 andvar Exp $          */
2 
3 /*-
4  * Copyright (c) 2005, 2007 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD Foundation
8  * by Yevgeny Binder and Dieter Baron.
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 /*
33  * Copyright (c) 1992, 1993
34  *        The Regents of the University of California.  All rights reserved.
35  *
36  * This code is derived from software donated to Berkeley by
37  * Jan-Simon Pendry.
38  *
39  * Redistribution and use in source and binary forms, with or without
40  * modification, are permitted provided that the following conditions
41  * are met:
42  * 1. Redistributions of source code must retain the above copyright
43  *    notice, this list of conditions and the following disclaimer.
44  * 2. Redistributions in binary form must reproduce the above copyright
45  *    notice, this list of conditions and the following disclaimer in the
46  *    documentation and/or other materials provided with the distribution.
47  * 3. Neither the name of the University nor the names of its contributors
48  *    may be used to endorse or promote products derived from this software
49  *    without specific prior written permission.
50  *
51  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
52  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
53  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
54  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
55  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
56  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
57  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
58  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
59  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
60  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
61  * SUCH DAMAGE.
62  */
63 
64 /*
65  * Copyright (c) 1982, 1986, 1989, 1993, 1995
66  *        The Regents of the University of California.  All rights reserved.
67  * (c) UNIX System Laboratories, Inc.
68  * All or some portions of this file are derived from material licensed
69  * to the University of California by American Telephone and Telegraph
70  * Co. or Unix System Laboratories, Inc. and are reproduced herein with
71  * the permission of UNIX System Laboratories, Inc.
72  *
73  * Redistribution and use in source and binary forms, with or without
74  * modification, are permitted provided that the following conditions
75  * are met:
76  * 1. Redistributions of source code must retain the above copyright
77  *    notice, this list of conditions and the following disclaimer.
78  * 2. Redistributions in binary form must reproduce the above copyright
79  *    notice, this list of conditions and the following disclaimer in the
80  *    documentation and/or other materials provided with the distribution.
81  * 3. Neither the name of the University nor the names of its contributors
82  *    may be used to endorse or promote products derived from this software
83  *    without specific prior written permission.
84  *
85  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
86  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
87  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
88  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
89  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
90  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
91  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
92  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
93  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
94  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
95  * SUCH DAMAGE.
96  */
97 
98 
99 /*
100  * Apple HFS+ filesystem
101  */
102 
103 #include <sys/cdefs.h>
104 __KERNEL_RCSID(0, "$NetBSD: hfs_vnops.c,v 1.40 2022/08/06 18:26:42 andvar Exp $");
105 
106 #ifdef _KERNEL_OPT
107 #include "opt_ipsec.h"
108 #endif
109 
110 #include <sys/param.h>
111 #include <sys/systm.h>
112 #include <sys/kernel.h>
113 #include <sys/vmmeter.h>
114 #include <sys/time.h>
115 #include <sys/proc.h>
116 #include <sys/vnode.h>
117 #include <sys/malloc.h>
118 #include <sys/pool.h>
119 #include <sys/file.h>
120 #include <sys/stat.h>
121 #include <sys/mount.h>
122 #include <sys/namei.h>
123 #include <sys/buf.h>
124 #include <sys/dirent.h>
125 #include <sys/msgbuf.h>
126 
127 #include <miscfs/fifofs/fifo.h>
128 #include <miscfs/specfs/specdev.h>
129 
130 #include <fs/hfs/hfs.h>
131 #include <fs/hfs/unicode.h>
132 
133 #include <miscfs/genfs/genfs.h>
134 
135 int       hfs_vop_parsepath(void *);
136 int       hfs_vop_lookup(void *);
137 int       hfs_vop_open(void *);
138 int       hfs_vop_close(void *);
139 int       hfs_vop_access(void *);
140 int       hfs_vop_getattr(void *);
141 int       hfs_vop_setattr(void *);
142 int       hfs_vop_bmap(void *);
143 int       hfs_vop_read(void *);
144 int       hfs_vop_readdir(void *);
145 int       hfs_vop_readlink(void *);
146 int       hfs_vop_reclaim(void *);
147 int       hfs_vop_print(void *);
148 
149 #ifdef HFS_DEBUG
150 #define DPRINTF(a) printf a
151 #else
152 #define DPRINTF(a)
153 #endif
154 
155 
156 int (**hfs_vnodeop_p) (void *);
157 const struct vnodeopv_entry_desc hfs_vnodeop_entries[] = {
158           { &vop_default_desc, vn_default_error },
159           { &vop_parsepath_desc, genfs_parsepath },         /* parsepath */
160           { &vop_lookup_desc, hfs_vop_lookup },             /* lookup */
161           { &vop_create_desc, genfs_eopnotsupp },           /* create */
162           { &vop_whiteout_desc, genfs_eopnotsupp },         /* whiteout */
163           { &vop_mknod_desc, genfs_eopnotsupp },            /* mknod */
164           { &vop_open_desc, hfs_vop_open },                 /* open */
165           { &vop_close_desc, hfs_vop_close },               /* close */
166           { &vop_access_desc, hfs_vop_access },             /* access */
167           { &vop_accessx_desc, genfs_accessx },             /* accessx */
168           { &vop_getattr_desc, hfs_vop_getattr },           /* getattr */
169           { &vop_setattr_desc, hfs_vop_setattr },           /* setattr */
170           { &vop_read_desc, hfs_vop_read },                 /* read */
171           { &vop_write_desc, genfs_eopnotsupp },            /* write */
172           { &vop_fallocate_desc, genfs_eopnotsupp },        /* fallocate */
173           { &vop_fdiscard_desc, genfs_eopnotsupp },         /* fdiscard */
174           { &vop_ioctl_desc, genfs_eopnotsupp },            /* ioctl */
175           { &vop_fcntl_desc, genfs_fcntl },                 /* fcntl */
176           { &vop_poll_desc, genfs_eopnotsupp },             /* poll */
177           { &vop_kqfilter_desc, genfs_kqfilter },           /* kqfilter */
178           { &vop_revoke_desc, genfs_eopnotsupp },           /* revoke */
179           { &vop_mmap_desc, genfs_mmap },                             /* mmap */
180           { &vop_fsync_desc, genfs_nullop },                /* fsync */
181           { &vop_seek_desc, genfs_seek },                             /* seek */
182           { &vop_remove_desc, genfs_eopnotsupp },           /* remove */
183           { &vop_link_desc, genfs_eopnotsupp },             /* link */
184           { &vop_rename_desc, genfs_eopnotsupp },           /* rename */
185           { &vop_mkdir_desc, genfs_eopnotsupp },            /* mkdir */
186           { &vop_rmdir_desc, genfs_eopnotsupp },            /* rmdir */
187           { &vop_symlink_desc, genfs_eopnotsupp },          /* symlink */
188           { &vop_readdir_desc, hfs_vop_readdir },           /* readdir */
189           { &vop_readlink_desc, hfs_vop_readlink },         /* readlink */
190           { &vop_abortop_desc, genfs_abortop },             /* abortop */
191           { &vop_inactive_desc, genfs_eopnotsupp },         /* inactive */
192           { &vop_reclaim_desc, hfs_vop_reclaim },           /* reclaim */
193           { &vop_lock_desc, genfs_lock },                             /* lock */
194           { &vop_unlock_desc, genfs_unlock },               /* unlock */
195           { &vop_bmap_desc, hfs_vop_bmap },                 /* bmap */
196           { &vop_strategy_desc, genfs_eopnotsupp },         /* strategy */
197           { &vop_print_desc, hfs_vop_print },               /* print */
198           { &vop_islocked_desc, genfs_islocked },           /* islocked */
199           { &vop_pathconf_desc, genfs_eopnotsupp },         /* pathconf */
200           { &vop_advlock_desc, genfs_eopnotsupp },          /* advlock */
201           { &vop_bwrite_desc, genfs_eopnotsupp },           /* bwrite */
202           { &vop_getpages_desc, genfs_getpages },           /* getpages */
203           { &vop_putpages_desc, genfs_putpages },           /* putpages */
204           { &vop_openextattr_desc, genfs_eopnotsupp },      /* openextattr */
205           { &vop_closeextattr_desc, genfs_eopnotsupp },     /* closeextattr */
206           { &vop_getextattr_desc, genfs_eopnotsupp },       /* getextattr */
207           { &vop_setextattr_desc, genfs_eopnotsupp },       /* setextattr */
208           { &vop_listextattr_desc, genfs_eopnotsupp },      /* listextattr */
209           { &vop_deleteextattr_desc, genfs_eopnotsupp },    /* deleteextattr */
210           { NULL, NULL }
211 };
212 const struct vnodeopv_desc hfs_vnodeop_opv_desc =
213           { &hfs_vnodeop_p, hfs_vnodeop_entries };
214 
215 int (**hfs_specop_p) (void *);
216 const struct vnodeopv_entry_desc hfs_specop_entries[] = {
217           { &vop_default_desc, vn_default_error },
218           GENFS_SPECOP_ENTRIES,
219           { &vop_close_desc, spec_close },                  /* close */
220           { &vop_access_desc, hfs_vop_access },             /* access */
221           { &vop_accessx_desc, genfs_accessx },             /* accessx */
222           { &vop_getattr_desc, hfs_vop_getattr },           /* getattr */
223           { &vop_setattr_desc, hfs_vop_setattr },           /* setattr */
224           { &vop_read_desc, spec_read },                              /* read */
225           { &vop_write_desc, spec_write },                  /* write */
226           { &vop_fcntl_desc, genfs_fcntl },                 /* fcntl */
227           { &vop_fsync_desc, spec_fsync },                  /* fsync */
228           { &vop_inactive_desc, genfs_eopnotsupp },         /* inactive */
229           { &vop_reclaim_desc, hfs_vop_reclaim },           /* reclaim */
230           { &vop_lock_desc, genfs_lock },                             /* lock */
231           { &vop_unlock_desc, genfs_unlock },               /* unlock */
232           { &vop_print_desc, hfs_vop_print },               /* print */
233           { &vop_islocked_desc, genfs_islocked },           /* islocked */
234           { &vop_bwrite_desc, vn_bwrite },                  /* bwrite */
235 #if 0
236           { &vop_openextattr_desc, hfs_openextattr },       /* openextattr */
237           { &vop_closeextattr_desc, hfs_closeextattr },     /* closeextattr */
238           { &vop_getextattr_desc, hfs_getextattr },         /* getextattr */
239           { &vop_setextattr_desc, hfs_setextattr },         /* setextattr */
240           { &vop_listextattr_desc, hfs_listextattr },       /* listextattr */
241           { &vop_deleteextattr_desc, hfs_deleteextattr },   /* deleteextattr */
242 #endif
243           { NULL, NULL }
244 };
245 const struct vnodeopv_desc hfs_specop_opv_desc =
246           { &hfs_specop_p, hfs_specop_entries };
247 
248 int (**hfs_fifoop_p) (void *);
249 const struct vnodeopv_entry_desc hfs_fifoop_entries[] = {
250           { &vop_default_desc, vn_default_error },
251           GENFS_FIFOOP_ENTRIES,
252           { &vop_close_desc, vn_fifo_bypass },              /* close */
253           { &vop_access_desc, hfs_vop_access },             /* access */
254           { &vop_accessx_desc, genfs_accessx },             /* accessx */
255           { &vop_getattr_desc, hfs_vop_getattr },           /* getattr */
256           { &vop_setattr_desc, hfs_vop_setattr },           /* setattr */
257           { &vop_read_desc, vn_fifo_bypass },               /* read */
258           { &vop_write_desc, vn_fifo_bypass },              /* write */
259           { &vop_fcntl_desc, genfs_fcntl },                 /* fcntl */
260           { &vop_fsync_desc, vn_fifo_bypass },              /* fsync */
261           { &vop_inactive_desc, genfs_eopnotsupp },         /* inactive */
262           { &vop_reclaim_desc, hfs_vop_reclaim },           /* reclaim */
263           { &vop_lock_desc, genfs_lock },                             /* lock */
264           { &vop_unlock_desc, genfs_unlock },               /* unlock */
265           { &vop_strategy_desc, vn_fifo_bypass },           /* strategy */
266           { &vop_print_desc, hfs_vop_print },               /* print */
267           { &vop_islocked_desc, genfs_islocked },           /* islocked */
268           { &vop_bwrite_desc, vn_bwrite },                  /* bwrite */
269 #if 0
270           { &vop_openextattr_desc, hfs_openextattr },       /* openextattr */
271           { &vop_closeextattr_desc, hfs_closeextattr },     /* closeextattr */
272           { &vop_getextattr_desc, hfs_getextattr },         /* getextattr */
273           { &vop_setextattr_desc, hfs_setextattr },         /* setextattr */
274           { &vop_listextattr_desc, hfs_listextattr },       /* listextattr */
275           { &vop_deleteextattr_desc, hfs_deleteextattr },   /* deleteextattr */
276 #endif
277           { NULL, NULL }
278 };
279 const struct vnodeopv_desc hfs_fifoop_opv_desc =
280           { &hfs_fifoop_p, hfs_fifoop_entries };
281 
282 int
hfs_vop_parsepath(void * v)283 hfs_vop_parsepath(void *v)
284 {
285           struct vop_parsepath_args /* {
286                     struct vnode *a_dvp;
287                     const char *a_name;
288                     size_t *a_retval;
289           } */ *ap = v;
290           size_t len;
291           int error;
292 
293           error = genfs_parsepath(v);
294           if (error) {
295                     return error;
296           }
297 
298           len = *ap->a_retval;
299           if (!strcmp(ap->a_name + len, "/rsrc")) {
300                     *ap->a_retval += 5;
301           }
302           return 0;
303 }
304 
305 int
hfs_vop_lookup(void * v)306 hfs_vop_lookup(void *v)
307 {
308           struct vop_lookup_v2_args /* {
309                     struct vnode * a_dvp;
310                     struct vnode ** a_vpp;
311                     struct componentname * a_cnp;
312           } */ *ap = v;
313           struct componentname *cnp;
314           struct hfsnode *dp; /* hfsnode for directory being searched */
315           kauth_cred_t cred;
316           struct vnode **vpp;           /* resultant vnode */
317           struct vnode *tdp;            /* returned by VFS_VGET */
318           struct vnode *vdp;            /* vnode for directory being searched */
319           hfs_catalog_key_t key;        /* hfs+ catalog search key for requested child */
320           hfs_catalog_keyed_record_t rec; /* catalog record of requested child */
321           size_t namelen;
322           int use_resource_fork = 0;
323           unichar_t* unicn;             /* name of component, in Unicode */
324           const char *pname;
325           int error;
326           int flags;
327           int result;                             /* result of libhfs operations */
328 
329           DPRINTF(("VOP = hfs_vop_lookup()\n"));
330 
331           cnp = ap->a_cnp;
332           cred = cnp->cn_cred;
333           vdp = ap->a_dvp;
334           dp = VTOH(vdp);
335           error = 0;
336           pname = cnp->cn_nameptr;
337           result = 0;
338           unicn = NULL;
339           vpp = ap->a_vpp;
340           *vpp = NULL;
341 
342           flags = cnp->cn_flags;
343 
344 
345           /*
346            * Check accessibility of directory.
347            */
348           if ((error = VOP_ACCESS(vdp, VEXEC, cred)) != 0)
349                     return error;
350 
351           if ((flags & ISLASTCN) && (vdp->v_mount->mnt_flag & MNT_RDONLY) &&
352               (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME))
353                     return EROFS;
354 
355           /*
356            * We now have a segment name to search for, and a directory to search.
357            *
358            * Before tediously performing a linear scan of the directory,
359            * check the name cache to see if the directory/name pair
360            * we are looking for is known already.
361            */
362 /* XXX Cache disabled until we can make sure it works. */
363 #if 0
364           if ((error = cache_lookup(vdp, vpp, cnp)) >= 0)
365                     return error;
366 #endif
367 
368 
369 #if 0
370           if (cnp->cn_namelen == 1 && *pname == '.') {
371                     *vpp = vdp;
372                     vref(vdp);
373                     return 0;
374           }
375 #endif
376 
377           if (flags & ISDOTDOT) {
378                     DPRINTF(("DOTDOT "));
379                     error = hfs_vget_internal(vdp->v_mount, dp->h_parent,
380                         HFS_RSRCFORK, &tdp);
381                     if (error != 0)
382                               goto error;
383                     *vpp = tdp;
384 #if 0
385           } else if (dp->h_rec.u.cnid == rec.file.u.cnid) {
386 #endif
387           } else if (cnp->cn_namelen == 1 && pname[0] == '.') {
388                     DPRINTF(("DOT "));
389                     vref(vdp);          /* we want ourself, ie "." */
390                     *vpp = vdp;
391           } else {
392                     hfs_callback_args cbargs;
393                     uint8_t len, ni;
394 
395                     hfslib_init_cbargs(&cbargs);
396 
397                     namelen = cnp->cn_namelen;
398                     if (namelen > 5 &&
399                         !strcmp(cnp->cn_nameptr + namelen - 5, "/rsrc")) {
400                               namelen -= 5;
401                               use_resource_fork = 1;
402                     }
403 
404                     /* XXX: when decomposing, string could grow
405                        and we have to handle overflow */
406                     unicn = malloc(namelen * sizeof(unicn[0]), M_TEMP, M_WAITOK);
407                     len = utf8_to_utf16(unicn, namelen,
408                         cnp->cn_nameptr, namelen, 0, NULL);
409                     for (ni = 0; ni < len; ni++)
410                               if (unicn[ni] == (unichar_t)':')
411                                         unicn[ni] = (unichar_t)'/';
412                     /* XXX: check conversion errors? */
413                     if (hfslib_make_catalog_key(VTOH(vdp)->h_rec.u.cnid, len, unicn,
414                         &key) == 0) {
415                               DPRINTF(("ERROR in hfslib_make_catalog_key\n"));
416                               error = EINVAL;
417                               goto error;
418                     }
419 
420                     result = hfslib_find_catalog_record_with_key(&dp->h_hmp->hm_vol,
421                         &key, &rec, &cbargs);
422                     if (result > 0) {
423                               error = EINVAL;
424                               goto error;
425                     }
426                     if (result < 0) {
427                               if (cnp->cn_nameiop == CREATE)
428                                         error = EROFS;
429                               else
430                                         error = ENOENT;
431                               goto error;
432                     }
433 
434                     if (rec.file.user_info.file_type == HFS_HARD_LINK_FILE_TYPE
435                         && rec.file.user_info.file_creator == HFS_HFSLUS_CREATOR) {
436                               if (hfslib_get_hardlink(&dp->h_hmp->hm_vol,
437                                   rec.file.bsd.special.inode_num,
438                                   &rec, &cbargs) != 0) {
439                                         error = EINVAL;
440                                         goto error;
441                               }
442                     }
443 
444                     if (rec.type == HFS_REC_FILE
445                         && use_resource_fork
446                         && rec.file.rsrc_fork.logical_size > 0) {
447                         /* advance namei next pointer to end of string */
448                               error = hfs_vget_internal(vdp->v_mount, rec.file.cnid,
449                                   HFS_RSRCFORK, &tdp);
450                     } else
451                               error = hfs_vget_internal(vdp->v_mount, rec.file.cnid,
452                                   HFS_DATAFORK, &tdp);
453                     if (error != 0)
454                               goto error;
455                     *vpp = tdp;
456           }
457           DPRINTF(("\n"));
458           /*
459            * Insert name into cache if appropriate.
460            */
461 /* XXX Cache disabled until we can make sure it works. */
462 #if 0
463           cache_enter(vdp, *vpp, cnp);
464 #endif
465 
466           error = 0;
467 
468           /* FALLTHROUGH */
469 error:
470           if (unicn != NULL)
471                     free(unicn, M_TEMP);
472 
473           return error;
474 }
475 
476 int
hfs_vop_open(void * v)477 hfs_vop_open(void *v)
478 {
479 #if 0
480           struct vop_open_args /* {
481                     struct vnode *a_vp;
482                     int a_mode;
483                     kauth_cred_t a_cred;
484           } */ *ap = v;
485           struct hfsnode *hn = VTOH(ap->a_vp);
486 #endif
487           DPRINTF(("VOP = hfs_vop_open()\n"));
488 
489           /*
490            * XXX This is a good place to read and cache the file's extents to
491            * XXX avoid doing it upon every read/write. Must however keep the
492            * XXX cache in sync when the file grows/shrinks. (So would that go
493            * XXX in vop_truncate?)
494            */
495 
496           return 0;
497 }
498 
499 int
hfs_vop_close(void * v)500 hfs_vop_close(void *v)
501 {
502 #if 0
503           struct vop_close_args /* {
504                     struct vnode *a_vp;
505                     int a_fflag;
506                     kauth_cred_t a_cred;
507           } */ *ap = v;
508           struct hfsnode *hn = VTOH(ap->a_vp);
509 #endif
510           DPRINTF(("VOP = hfs_vop_close()\n"));
511 
512           /* Release extents cache here. */
513 
514           return 0;
515 }
516 
517 static int
hfs_check_possible(struct vnode * vp,accmode_t accmode)518 hfs_check_possible(struct vnode *vp, accmode_t accmode)
519 {
520 
521           /*
522            * Disallow writes on files, directories, and symlinks
523            * since we have no write support yet.
524            */
525 
526           if (accmode & VWRITE) {
527                     switch (vp->v_type) {
528                     case VDIR:
529                     case VLNK:
530                     case VREG:
531                               return EROFS;
532                     default:
533                               break;
534                     }
535           }
536 
537           return 0;
538 }
539 
540 static int
hfs_check_permitted(vnode_t * vp,struct vattr * va,accmode_t accmode,kauth_cred_t cred)541 hfs_check_permitted(vnode_t *vp, struct vattr *va, accmode_t accmode,
542     kauth_cred_t cred)
543 {
544 
545           return kauth_authorize_vnode(cred, KAUTH_ACCESS_ACTION(accmode,
546               va->va_type, va->va_mode), vp, NULL,  genfs_can_access(vp, cred,
547               va->va_uid, va->va_gid, va->va_mode, NULL, accmode));
548 }
549 
550 int
hfs_vop_access(void * v)551 hfs_vop_access(void *v)
552 {
553           struct vop_access_args /* {
554                     struct vnode *a_vp;
555                     int a_accmode;
556                     kauth_cred_t a_cred;
557           } */ *ap = v;
558           struct vattr va;
559           int error;
560 
561           DPRINTF(("VOP = hfs_vop_access()\n"));
562 
563           error = hfs_check_possible(ap->a_vp, ap->a_accmode);
564           if (error)
565                     return error;
566 
567           if ((error = VOP_GETATTR(ap->a_vp, &va, ap->a_cred)) != 0)
568                     return error;
569 
570           error = hfs_check_permitted(ap->a_vp, &va, ap->a_accmode, ap->a_cred);
571 
572           return error;
573 }
574 
575 int
hfs_vop_getattr(void * v)576 hfs_vop_getattr(void *v)
577 {
578           struct vop_getattr_args /* {
579                     struct vnode        *a_vp;
580                     struct vattr        *a_vap;
581                     struct ucred        *a_cred;
582           } */ *ap = v;
583           struct vnode        *vp;
584           struct hfsnode      *hp;
585           struct vattr        *vap;
586           hfs_bsd_data_t *bsd;
587           hfs_fork_t     *fork;
588 
589           DPRINTF(("VOP = hfs_vop_getattr()\n"));
590 
591           vp = ap->a_vp;
592           hp = VTOH(vp);
593           vap = ap->a_vap;
594 
595           vattr_null(vap);
596 
597           /*
598            * XXX Cannot trust permissions/modes/flags stored in an HFS+ catalog
599            * XXX record those values are not set on files created under Mac OS 9.
600            */
601           vap->va_type = ap->a_vp->v_type;
602           if (hp->h_rec.u.rec_type == HFS_REC_FILE) {
603                     hfs_file_record_t *f = &hp->h_rec.file;
604                     if (hp->h_fork == HFS_RSRCFORK)
605                               fork = &f->rsrc_fork;
606                     else
607                               fork = &f->data_fork;
608                     vap->va_fileid = f->cnid;
609                     bsd = &f->bsd;
610                     vap->va_bytes = fork->total_blocks * HFS_BLOCKSIZE(vp);
611                     vap->va_size = fork->logical_size;
612                     hfs_time_to_timespec(f->date_created, &vap->va_ctime);
613                     hfs_time_to_timespec(f->date_content_mod, &vap->va_mtime);
614                     hfs_time_to_timespec(f->date_accessed, &vap->va_atime);
615                     vap->va_nlink = 1;
616           } else if (hp->h_rec.u.rec_type == HFS_REC_FLDR) {
617                     hfs_folder_record_t *f = &hp->h_rec.folder;
618                     vap->va_fileid = hp->h_rec.folder.cnid;
619                     bsd = &f->bsd;
620                     vap->va_size = 512; /* XXX Temporary */
621                     vap->va_bytes = 512; /* XXX Temporary */
622                     hfs_time_to_timespec(f->date_created, &vap->va_ctime);
623                     hfs_time_to_timespec(f->date_content_mod,&vap->va_mtime);
624                     hfs_time_to_timespec(f->date_accessed, &vap->va_atime);
625                     vap->va_nlink = 2; /* XXX */
626           } else {
627                     DPRINTF(("hfs+: hfs_vop_getattr(): invalid record type %i",
628                         hp->h_rec.u.rec_type));
629                     return EINVAL;
630           }
631 
632           if ((bsd->file_mode & S_IFMT) == 0) {
633                     /* no bsd permissions recorded, use default values */
634                     if (hp->h_rec.u.rec_type == HFS_REC_FILE)
635                               vap->va_mode = (S_IFREG | HFS_DEFAULT_FILE_MODE);
636                     else
637                               vap->va_mode = (S_IFDIR | HFS_DEFAULT_DIR_MODE);
638                     vap->va_uid = HFS_DEFAULT_UID;
639                     vap->va_gid = HFS_DEFAULT_GID;
640           } else {
641                     vap->va_mode = bsd->file_mode;
642                     vap->va_uid = bsd->owner_id;
643                     vap->va_gid = bsd->group_id;
644                     if ((vap->va_mode & S_IFMT) == S_IFCHR
645                         || (vap->va_mode & S_IFMT) == S_IFBLK) {
646                               vap->va_rdev
647                                   = HFS_CONVERT_RDEV(bsd->special.raw_device);
648                     }
649                     else if (bsd->special.link_count != 0) {
650                         /* XXX: only if in metadata directory */
651                         vap->va_nlink = bsd->special.link_count;
652                     }
653           }
654 
655           vap->va_fsid = hp->h_dev;
656           vap->va_blocksize = hp->h_hmp->hm_vol.vh.block_size;
657           vap->va_gen = 1;
658           vap->va_flags = 0;
659 
660           return 0;
661 }
662 
663 int
hfs_vop_setattr(void * v)664 hfs_vop_setattr(void *v)
665 {
666           struct vop_setattr_args /* {
667                     struct vnode        *a_vp;
668                     struct vattr        *a_vap;
669                     kauth_cred_t        a_cred;
670           } */ *ap = v;
671           struct vattr        *vap;
672           struct vnode        *vp;
673 
674           vap = ap->a_vap;
675           vp = ap->a_vp;
676 
677           /*
678            * Check for unsettable attributes.
679            */
680           if ((vap->va_type != VNON) || (vap->va_nlink != VNOVAL) ||
681               (vap->va_fsid != VNOVAL) || (vap->va_fileid != VNOVAL) ||
682               (vap->va_blocksize != VNOVAL) || (vap->va_rdev != VNOVAL) ||
683               ((int)vap->va_bytes != VNOVAL) || (vap->va_gen != VNOVAL)) {
684                     return EINVAL;
685           }
686 
687           /* XXX: needs revisiting for write support */
688           if (vap->va_flags != VNOVAL
689               || vap->va_uid != (uid_t)VNOVAL || vap->va_gid != (gid_t)VNOVAL
690               || vap->va_atime.tv_sec != VNOVAL || vap->va_mtime.tv_sec != VNOVAL
691               || vap->va_birthtime.tv_sec != VNOVAL) {
692                     return EROFS;
693           }
694 
695           if (vap->va_size != VNOVAL) {
696                     /*
697                      * Disallow write attempts on read-only file systems;
698                      * unless the file is a socket, fifo, or a block or
699                      * character device resident on the file system.
700                      */
701                     switch (vp->v_type) {
702                     case VDIR:
703                               return EISDIR;
704                     case VCHR:
705                     case VBLK:
706                     case VFIFO:
707                               break;
708                     case VREG:
709                               return EROFS;
710                     default:
711                               return EOPNOTSUPP;
712                     }
713           }
714 
715           return 0;
716 }
717 
718 int
hfs_vop_bmap(void * v)719 hfs_vop_bmap(void *v)
720 {
721           struct vop_bmap_args /* {
722                     struct vnode *a_vp;
723                     daddr_t  a_bn;
724                     struct vnode **a_vpp;
725                     daddr_t *a_bnp;
726                     int *a_runp;
727           } */ *ap = v;
728           struct vnode *vp;
729           struct hfsnode *hp;
730           daddr_t lblkno;
731           hfs_callback_args cbargs;
732           hfs_libcb_argsread argsread;
733           hfs_extent_descriptor_t *extents;
734           uint16_t numextents, i;
735           int bshift;
736 
737           vp = ap->a_vp;
738           hp = VTOH(vp);
739           lblkno = ap->a_bn;
740           bshift = vp->v_mount->mnt_fs_bshift;
741 
742           /*
743            * Check for underlying vnode requests and ensure that logical
744            * to physical mapping is requested.
745            */
746           if (ap->a_vpp != NULL)
747                     *ap->a_vpp = hp->h_devvp;
748           if (ap->a_bnp == NULL)
749                     return 0;
750 
751           hfslib_init_cbargs(&cbargs);
752           argsread.cred = NULL;
753           argsread.l = NULL;
754           cbargs.read = &argsread;
755 
756           numextents = hfslib_get_file_extents(&hp->h_hmp->hm_vol,
757               hp->h_rec.u.cnid, hp->h_fork, &extents, &cbargs);
758 
759           /* XXX: is this correct for 0-length files? */
760           if (numextents == 0)
761                     return EBADF;
762 
763           for (i = 0; i < numextents; i++) {
764                     if (lblkno < extents[i].block_count)
765                               break;
766                     lblkno -= extents[i].block_count;
767           }
768 
769           if (i == numextents) {
770                     /* XXX: block number past EOF */
771                     i--;
772                     lblkno += extents[i].block_count;
773           }
774 
775           *ap->a_bnp = ((extents[i].start_block + lblkno) << (bshift-DEV_BSHIFT))
776               + (hp->h_hmp->hm_vol.offset >> DEV_BSHIFT);
777 
778           if (ap->a_runp) {
779                     int nblk;
780 
781                     nblk = extents[i].block_count - lblkno - 1;
782                     if (nblk <= 0)
783                               *ap->a_runp = 0;
784                     else if (nblk > MAXBSIZE >> bshift)
785                               *ap->a_runp = (MAXBSIZE >> bshift) - 1;
786                     else
787                               *ap->a_runp = nblk;
788           }
789 
790           free(extents, M_TEMP);
791 
792           return 0;
793 }
794 
795 int
hfs_vop_read(void * v)796 hfs_vop_read(void *v)
797 {
798           struct vop_read_args /* {
799                     struct vnode *a_vp;
800                     struct uio *a_uio;
801                     int a_ioflag;
802                     kauth_cred_t a_cred;
803           } */ *ap = v;
804           struct vnode *vp;
805           struct hfsnode *hp;
806           struct uio *uio;
807           uint64_t fsize; /* logical size of file */
808           int advice;
809           int error;
810 
811           vp = ap->a_vp;
812           hp = VTOH(vp);
813           uio = ap->a_uio;
814           if (hp->h_fork == HFS_RSRCFORK)
815                     fsize = hp->h_rec.file.rsrc_fork.logical_size;
816           else
817                     fsize = hp->h_rec.file.data_fork.logical_size;
818           error = 0;
819           advice = IO_ADV_DECODE(ap->a_ioflag);
820 
821           if (uio->uio_offset < 0)
822                     return EINVAL;
823 
824           if (uio->uio_resid == 0 || uio->uio_offset >= fsize)
825                     return 0;
826 
827           if (vp->v_type != VREG && vp->v_type != VLNK)
828                     return EINVAL;
829 
830           error = 0;
831           while (uio->uio_resid > 0 && error == 0) {
832                     vsize_t len;
833 
834                     len = MIN(uio->uio_resid, fsize - uio->uio_offset);
835                     if (len == 0)
836                               break;
837 
838                     error = ubc_uiomove(&vp->v_uobj, uio, len, advice,
839                         UBC_READ | UBC_PARTIALOK | UBC_VNODE_FLAGS(vp));
840           }
841 
842           return error;
843 }
844 
845 int
hfs_vop_readdir(void * v)846 hfs_vop_readdir(void *v)
847 {
848           struct vop_readdir_args /* {
849                     struct vnode *a_vp;
850                     struct uio *a_uio;
851                     kauth_cred_t a_cred;
852                     int *a_eofflag;
853                     off_t **a_cookies;
854                     int a_*ncookies;
855           } */ *ap = v;
856 
857           DPRINTF(("VOP = hfs_vop_readdir()\n"));
858 
859           struct dirent curent; /* the dirent entry we are constructing */
860           struct hfsnode *hp;
861           hfs_catalog_keyed_record_t *children;
862           hfs_unistr255_t *childnames;
863           hfs_callback_args cbargs;
864           hfs_libcb_argsread argsread;
865           struct uio *uio;
866           off_t bufoff; /* offset in buffer relative to start of dirents */
867           uint32_t numchildren;
868           uint32_t curchild; /* index of child we are stuffing into dirent */
869           size_t namlen, ni;
870           int error;
871           int i; /* dummy variable */
872 
873           bufoff = 0;
874           children = NULL;
875           error = 0;
876           numchildren = 0;
877           hp = VTOH(ap->a_vp);
878           uio = ap->a_uio;
879 
880           if (uio->uio_offset < 0)
881                     return EINVAL;
882           if (ap->a_eofflag != NULL)
883                     *ap->a_eofflag = 0;
884 
885 /* XXX Inform that we don't support NFS, for now. */
886 #if 0
887           if(ap->a_eofflag != NULL || ap->a_cookies != NULL ||
888               ap->a_ncookies != NULL)
889                     return EOPNOTSUPP;
890 #endif
891           DPRINTF(("READDIR uio: offset=%td, resid=%zu\n",
892               uio->uio_offset, uio->uio_resid));
893           hfslib_init_cbargs(&cbargs);
894           argsread.cred = ap->a_cred;
895           argsread.l = NULL;
896           cbargs.read = &argsread;
897 
898           /* XXX Should we cache this? */
899           if (hfslib_get_directory_contents(&hp->h_hmp->hm_vol, hp->h_rec.u.cnid,
900               &children, &childnames, &numchildren, &cbargs) != 0) {
901                     DPRINTF(("ENOENT\n"));
902                     error = ENOENT;
903                     goto error;
904           }
905 
906           DPRINTF(("numchildren = %u\n", numchildren));
907           for (curchild = 0; curchild < numchildren && uio->uio_resid > 0;
908               curchild++) {
909                     namlen = utf16_to_utf8(curent.d_name, NAME_MAX,
910                         childnames[curchild].unicode, childnames[curchild].length,
911                         0, NULL);
912                     /* XXX: check conversion errors? */
913                     if (namlen > NAME_MAX) {
914                               /* XXX: how to handle name too long? */
915                               continue;
916                     }
917                     for (ni = 0; ni < namlen; ni++)
918                               if (curent.d_name[ni] == '/')
919                                         curent.d_name[ni] = ':';
920                     curent.d_namlen = namlen;
921                     curent.d_reclen = _DIRENT_SIZE(&curent);
922 
923                     /* Skip to desired dirent. */
924                     bufoff += curent.d_reclen;
925                     if (bufoff - curent.d_reclen < uio->uio_offset)
926                               continue;
927 
928                     /* Make sure we don't return partial entries. */
929                     if (uio->uio_resid < curent.d_reclen) {
930                               DPRINTF(("PARTIAL ENTRY\n"));
931                               if (ap->a_eofflag != NULL)
932                                         *ap->a_eofflag = 1;
933                               break;
934                     }
935 
936                     curent.d_fileno = children[curchild].file.cnid;
937                     switch (hfs_catalog_keyed_record_vtype(children+curchild)) {
938                     case VREG:
939                               curent.d_type = DT_REG;
940                               break;
941                     case VDIR:
942                               curent.d_type = DT_DIR;
943                               break;
944                     case VBLK:
945                               curent.d_type = DT_BLK;
946                               break;
947                     case VCHR:
948                               curent.d_type = DT_CHR;
949                               break;
950                     case VLNK:
951                               curent.d_type = DT_LNK;
952                               break;
953                     case VSOCK:
954                               curent.d_type = DT_SOCK;
955                               break;
956                     case VFIFO:
957                               curent.d_type = DT_FIFO;
958                               break;
959                     default:
960                               curent.d_type = DT_UNKNOWN;
961                               break;
962                     }
963                     DPRINTF(("curchildname = %s\t\t", curchildname));
964                     /* pad curent.d_name to aligned byte boundary */
965                     for (i = curent.d_namlen;
966                         i < curent.d_reclen - _DIRENT_NAMEOFF(&curent); i++)
967                               curent.d_name[i] = 0;
968 
969                     DPRINTF(("curent.d_name = %s\n", curent.d_name));
970 
971                     if ((error = uiomove(&curent, curent.d_reclen, uio)) != 0)
972                               goto error;
973           }
974 
975           /* FALLTHROUGH */
976 
977 error:
978           if (numchildren > 0) {
979                     if (children != NULL)
980                               free(children, M_TEMP);
981                     if (childnames != NULL)
982                               free(childnames, M_TEMP);
983           }
984 
985           if (error) {
986                     DPRINTF(("ERROR = %i\n", error));
987           }
988 
989           return error;
990 }
991 
992 int
hfs_vop_readlink(void * v)993 hfs_vop_readlink(void *v) {
994           struct vop_readlink_args /* {
995                     struct vnode *a_vp;
996                     struct uio *a_uio;
997                     kauth_cred_t a_cred;
998           } */ *ap = v;
999 
1000           return VOP_READ(ap->a_vp, ap->a_uio, 0, ap->a_cred);
1001 }
1002 
1003 int
hfs_vop_reclaim(void * v)1004 hfs_vop_reclaim(void *v)
1005 {
1006           struct vop_reclaim_v2_args /* {
1007                     struct vnode *a_vp;
1008           } */ *ap = v;
1009           struct vnode *vp;
1010           struct hfsnode *hp;
1011 
1012           VOP_UNLOCK(ap->a_vp);
1013 
1014           DPRINTF(("VOP = hfs_vop_reclaim()\n"));
1015 
1016           vp = ap->a_vp;
1017           hp = VTOH(vp);
1018 
1019           /* Decrement the reference count to the volume's device. */
1020           if (hp->h_devvp) {
1021                     vrele(hp->h_devvp);
1022                     hp->h_devvp = 0;
1023           }
1024 
1025           genfs_node_destroy(vp);
1026           pool_put(&hfs_node_pool, hp);
1027           vp->v_data = NULL;
1028 
1029           return 0;
1030 }
1031 
1032 int
hfs_vop_print(void * v)1033 hfs_vop_print(void *v)
1034 {
1035           struct vop_print_args /* {
1036                     struct vnode        *a_vp;
1037           } */ *ap = v;
1038           struct vnode        *vp;
1039           struct hfsnode      *hp;
1040 
1041           DPRINTF(("VOP = hfs_vop_print()\n"));
1042 
1043           vp = ap->a_vp;
1044           hp = VTOH(vp);
1045 
1046           printf("dummy = %X\n", (unsigned)hp->dummy);
1047           printf("\n");
1048 
1049           return 0;
1050 }
1051