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