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