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