darwin-xnu/bsd/hfs/hfs_attrlist.c
<<
>>
Prefs
   1/*
   2 * Copyright (c) 2000-2005 Apple Computer, Inc. All rights reserved.
   3 *
   4 * @APPLE_LICENSE_HEADER_START@
   5 * 
   6 * The contents of this file constitute Original Code as defined in and
   7 * are subject to the Apple Public Source License Version 1.1 (the
   8 * "License").  You may not use this file except in compliance with the
   9 * License.  Please obtain a copy of the License at
  10 * http://www.apple.com/publicsource and read it before using this file.
  11 * 
  12 * This Original Code and all software distributed under the License are
  13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
  14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
  15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
  16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
  17 * License for the specific language governing rights and limitations
  18 * under the License.
  19 * 
  20 * @APPLE_LICENSE_HEADER_END@
  21 */
  22
  23/*
  24 * hfs_attrlist.c - HFS attribute list processing
  25 *
  26 * Copyright (c) 1998-2002, Apple Computer, Inc.  All Rights Reserved.
  27 */
  28
  29#include <sys/param.h>
  30#include <sys/systm.h>
  31#include <sys/kernel.h>
  32#include <sys/malloc.h>
  33#include <sys/attr.h>
  34#include <sys/stat.h>
  35#include <sys/unistd.h>
  36#include <sys/mount_internal.h>
  37#include <sys/kauth.h>
  38
  39#include <kern/locks.h>
  40
  41#include "hfs.h"
  42#include "hfs_cnode.h"
  43#include "hfs_mount.h"
  44#include "hfs_dbg.h"
  45#include "hfs_attrlist.h"
  46
  47
  48
  49/* Routines that are shared by hfs_setattr: */
  50extern int hfs_write_access(struct vnode *vp, kauth_cred_t cred,
  51                        struct proc *p, Boolean considerFlags);
  52
  53extern int hfs_chflags(struct vnode *vp, uint32_t flags, kauth_cred_t cred,
  54                        struct proc *p);
  55
  56extern int hfs_chmod(struct vnode *vp, int mode, kauth_cred_t cred,
  57                        struct proc *p);
  58
  59extern int hfs_chown(struct vnode *vp, uid_t uid, gid_t gid, kauth_cred_t cred,
  60                        struct proc *p);
  61
  62__private_extern__ int hfs_vnop_readdirattr(struct vnop_readdirattr_args *ap);
  63
  64__private_extern__ int hfs_vnop_setattrlist(struct vnop_setattrlist_args  *ap);
  65
  66__private_extern__ int hfs_vnop_getattrlist(struct vnop_getattrlist_args *ap);
  67
  68/* Packing routines: */
  69
  70
  71static void packvolcommonattr(struct attrblock *abp, struct hfsmount *hfsmp,
  72                        struct vnode *vp, struct proc *p);
  73
  74static void packvolattr(struct attrblock *abp, struct hfsmount *hfsmp,
  75                        struct vnode *vp);
  76
  77static void packcommonattr(struct attrblock *abp, struct hfsmount *hfsmp,
  78                        struct vnode *vp, struct cat_desc * cdp,
  79                        struct cat_attr * cap, struct proc *p);
  80
  81static void packfileattr(struct attrblock *abp, struct hfsmount *hfsmp,
  82                        struct cat_attr *cattrp, struct cat_fork *datafork,
  83                        struct cat_fork *rsrcfork);
  84
  85static void packdirattr(struct attrblock *abp, struct hfsmount *hfsmp,
  86                        struct vnode *vp, struct cat_desc * descp,
  87                        struct cat_attr * cattrp);
  88
  89
  90#if 0
  91static int unpackattrblk(struct attrblock *abp, struct vnode *vp);
  92
  93static void unpackcommonattr(struct attrblock *abp, struct vnode *vp);
  94
  95static int unpackvolattr(struct attrblock *abp, struct hfsmount *hfsmp,
  96                        struct vnode *root_vp);
  97
  98
  99/*
 100 * Get a list of attributes.
 101 */
 102__private_extern__
 103int
 104hfs_vnop_getattrlist(ap)
 105        struct vnop_getattrlist_args /* {
 106                struct vnode *a_vp;
 107                struct attrlist *a_alist
 108                struct uio *a_uio;
 109                int a_options;
 110                vfs_context_t a_context;
 111        } */ *ap;
 112{
 113        struct vnode *vp = ap->a_vp;
 114        struct cnode *cp;
 115        struct hfsmount *hfsmp;
 116        struct attrlist *alist = ap->a_alist;
 117        proc_t p = vfs_context_proc(ap->a_context);
 118        int fixedblocksize;
 119        int attrblocksize;
 120        int attrbufsize;
 121        void *attrbufptr = NULL;
 122        void *attrptr;
 123        void *varptr;
 124        struct attrblock attrblk;
 125        struct cat_fork *datafp = NULL;
 126        struct cat_fork *rsrcfp = NULL;
 127        struct cat_fork rsrcfork;
 128        int lockflags;
 129        int error = 0;
 130
 131        if ((alist->bitmapcount != ATTR_BIT_MAP_COUNT) ||
 132            ((alist->commonattr & ~ATTR_CMN_VALIDMASK) != 0) ||
 133            ((alist->volattr & ~ATTR_VOL_VALIDMASK) != 0) ||
 134            ((alist->dirattr & ~ATTR_DIR_VALIDMASK) != 0) ||
 135            ((alist->fileattr & ~ATTR_FILE_VALIDMASK) != 0)) {
 136                return (EINVAL);
 137        }
 138
 139        /*
 140         * Requesting volume information requires setting the
 141         * ATTR_VOL_INFO bit. Also, volume info requests are
 142         * mutually exclusive with all other info requests.
 143         */
 144        if ((alist->volattr != 0) &&
 145            (((alist->volattr & ATTR_VOL_INFO) == 0) ||
 146             (alist->dirattr != 0) || (alist->fileattr != 0))) {
 147                return (EINVAL);
 148        }
 149
 150        /* Reject requests for unsupported options for now: */
 151        if ((alist->commonattr & (ATTR_CMN_NAMEDATTRCOUNT | ATTR_CMN_NAMEDATTRLIST)) ||
 152            (alist->fileattr & (ATTR_FILE_FILETYPE | ATTR_FILE_FORKCOUNT | ATTR_FILE_FORKLIST))) {
 153                return (EINVAL);
 154        }
 155
 156        if ((error = hfs_lock(VTOC(vp), HFS_EXCLUSIVE_LOCK)))
 157                return (error);
 158        cp = VTOC(vp);
 159        hfsmp = VTOHFS(vp);
 160
 161        /* Requesting volume information requires root vnode */ 
 162        if ((alist->volattr) && cp->c_fileid != kHFSRootFolderID) {
 163                error = EINVAL;
 164                goto exit;
 165        }
 166        /* Asking for data fork attributes from the rsrc fork is not supported */
 167        if (VNODE_IS_RSRC(vp) && (alist->fileattr & ATTR_DATAFORK_MASK)) {
 168                error = EINVAL;
 169                goto exit;
 170        }
 171        /* This file no longer exists! */
 172        if (cp->c_flag & (C_NOEXISTS | C_DELETED)) {
 173                error = ENOENT;
 174                goto exit;
 175        }
 176        /* This file doesn't have a name! */
 177        if ((cp->c_desc.cd_namelen == 0) && (alist->commonattr & ATTR_CMN_NAME)) {
 178                error = ENOENT;
 179                goto exit;
 180        }
 181
 182        /* Update cnode times if needed */
 183        hfs_touchtimes(hfsmp, cp);
 184
 185        /*
 186         * If a File ID (ATTR_CMN_OBJPERMANENTID) is requested on
 187         * an HFS volume we must be sure to create the thread
 188         * record before returning it. (yikes)
 189         */
 190        if (vnode_isreg(vp) &&
 191            (alist->commonattr & ATTR_CMN_OBJPERMANENTID) &&
 192            (VTOVCB(vp)->vcbSigWord != kHFSPlusSigWord)) {
 193
 194                cat_cookie_t cookie;
 195
 196                if (hfsmp->hfs_flags & HFS_READ_ONLY) {
 197                        error = EROFS;
 198                        goto exit;
 199                }
 200                if ((error = hfs_write_access(vp, vfs_context_ucred(ap->a_context),
 201                                              p, false)) != 0) {
 202                        goto exit;
 203                }
 204                /*
 205                 * Reserve some space in the Catalog file.
 206                 */
 207                bzero(&cookie, sizeof(cookie));
 208                error = cat_preflight(hfsmp, CAT_CREATE, &cookie, p);
 209                if (error) {
 210                        goto exit;
 211                }
 212
 213                lockflags = hfs_systemfile_lock(hfsmp, SFL_CATALOG, HFS_EXCLUSIVE_LOCK);
 214
 215                error = cat_insertfilethread(hfsmp, &cp->c_desc);
 216
 217                hfs_systemfile_unlock(hfsmp, lockflags);
 218
 219                cat_postflight(hfsmp, &cookie, p);
 220
 221                if (error)
 222                        goto exit;
 223        }
 224        bzero(&rsrcfork, sizeof(rsrcfork));
 225        /* Establish known fork data */
 226        if (cp->c_datafork != NULL) {
 227                datafp = &cp->c_datafork->ff_data;
 228                if ((cp->c_rsrcfork == NULL) &&
 229                    (cp->c_blocks == datafp->cf_blocks))
 230                        rsrcfp = &rsrcfork;     /* rsrc fork is empty */
 231        }
 232        if (cp->c_rsrcfork != NULL)
 233                rsrcfp = &cp->c_rsrcfork->ff_data;
 234        
 235        /*
 236         * When resource fork data is requested and its not available
 237         * in the cnode and the fork is not empty then it needs to be
 238         * fetched from the catalog.
 239         */
 240        if ((alist->fileattr & ATTR_RSRCFORK_MASK) && (rsrcfp == NULL)) {
 241
 242                lockflags = hfs_systemfile_lock(hfsmp, SFL_CATALOG, HFS_SHARED_LOCK);
 243
 244                /* Get resource fork data */
 245                error = cat_lookup(hfsmp, &cp->c_desc, 1,
 246                                (struct cat_desc *)0, (struct cat_attr *)0, &rsrcfork, NULL);
 247
 248                hfs_systemfile_unlock(hfsmp, lockflags);
 249
 250                if (error)
 251                        goto exit;
 252
 253                rsrcfp = &rsrcfork;
 254        }
 255
 256        fixedblocksize = hfs_attrblksize(alist);
 257        attrblocksize = fixedblocksize + (sizeof(uint32_t));  /* uint32_t for length word */
 258        if (alist->commonattr & ATTR_CMN_NAME)
 259                attrblocksize += kHFSPlusMaxFileNameBytes + 1;
 260        if (alist->volattr & ATTR_VOL_MOUNTPOINT)
 261                attrblocksize += PATH_MAX;
 262        if (alist->volattr & ATTR_VOL_NAME)
 263                attrblocksize += kHFSPlusMaxFileNameBytes + 1;
 264#if 0
 265        if (alist->commonattr & ATTR_CMN_NAMEDATTRLIST)
 266                attrblocksize += 0;
 267        if (alist->fileattr & ATTR_FILE_FORKLIST)
 268                attrblocksize += 0;
 269#endif
 270        attrbufsize = MIN(uio_resid(ap->a_uio), attrblocksize);
 271        MALLOC(attrbufptr, void *, attrblocksize, M_TEMP, M_WAITOK);
 272        attrptr = attrbufptr;
 273        *((uint32_t *)attrptr) = 0;  /* Set buffer length in case of errors */
 274        ++((uint32_t *)attrptr);     /* Reserve space for length field */
 275        varptr = ((char *)attrptr) + fixedblocksize;
 276
 277        attrblk.ab_attrlist = alist;
 278        attrblk.ab_attrbufpp = &attrptr;
 279        attrblk.ab_varbufpp = &varptr;
 280        attrblk.ab_flags = 0;
 281        attrblk.ab_blocksize = attrblocksize;
 282
 283        hfs_packattrblk(&attrblk, hfsmp, vp, &cp->c_desc, &cp->c_attr,
 284                        datafp, rsrcfp, p);
 285
 286        /* Don't copy out more data than was generated */
 287        attrbufsize = MIN((u_int)attrbufsize, (u_int)varptr - (u_int)attrbufptr);
 288         /* Set actual buffer length for return to caller */
 289        *((uint32_t *)attrbufptr) = attrbufsize;
 290        error = uiomove((caddr_t)attrbufptr, attrbufsize, ap->a_uio);
 291exit:
 292        if (attrbufptr)
 293                FREE(attrbufptr, M_TEMP);
 294        hfs_unlock(cp);
 295        return (error);
 296}
 297
 298
 299/*
 300 * Set a list of attributes.
 301 */
 302__private_extern__
 303int
 304hfs_vnop_setattrlist(ap)
 305        struct vnop_setattrlist_args /* {
 306                struct vnode *a_vp;
 307                struct attrlist *a_alist
 308                struct uio *a_uio;
 309                int a_options;
 310                vfs_context_t a_context;
 311        } */ *ap;
 312{
 313        struct vnode *vp = ap->a_vp;
 314        struct cnode *cp;
 315        struct hfsmount * hfsmp;
 316        struct attrlist *alist = ap->a_alist;
 317        kauth_cred_t cred = vfs_context_ucred(ap->a_context);
 318        struct proc *p = vfs_context_proc(ap->a_context);
 319        int attrblocksize;
 320        void *attrbufptr = NULL;
 321        void *attrptr;
 322        void *varptr = NULL;
 323        struct attrblock attrblk;
 324        uid_t saved_uid;
 325        gid_t saved_gid;
 326        mode_t saved_mode;
 327        uint32_t saved_flags;
 328        int error = 0;
 329
 330        hfsmp = VTOHFS(vp);
 331
 332        if (hfsmp->hfs_flags & HFS_READ_ONLY)
 333                return (EROFS);
 334        if ((alist->bitmapcount != ATTR_BIT_MAP_COUNT)     ||
 335            ((alist->commonattr & ~ATTR_CMN_SETMASK) != 0) ||
 336            ((alist->volattr & ~ATTR_VOL_SETMASK) != 0)    ||
 337            ((alist->dirattr & ~ATTR_DIR_SETMASK) != 0)    ||
 338            ((alist->fileattr & ~ATTR_FILE_SETMASK) != 0)) {
 339                return (EINVAL);
 340        }
 341        if ((error = hfs_lock(VTOC(vp), HFS_EXCLUSIVE_LOCK)))
 342                return (error);
 343        cp = VTOC(vp);
 344
 345        /* 
 346         * When setting volume attributes make sure
 347         * that ATTR_VOL_INFO is set and that all
 348         * the attributes are valid.
 349         */
 350        if ((alist->volattr != 0) &&
 351            (((alist->volattr & ATTR_VOL_INFO) == 0) ||
 352            (alist->commonattr & ~ATTR_CMN_VOLSETMASK) ||
 353            (cp->c_fileid != kHFSRootFolderID))) {
 354                if ((alist->volattr & ATTR_VOL_INFO) == 0)
 355                        printf("hfs_setattrlist: you forgot to set ATTR_VOL_INFO bit!\n");
 356                else
 357                        printf("hfs_setattrlist: you cannot set bits 0x%08X!\n",
 358                                alist->commonattr & ~ATTR_CMN_VOLSETMASK);
 359                error = EINVAL;
 360                goto ErrorExit;
 361        }
 362        if (cp->c_flag & (C_NOEXISTS | C_DELETED)) {
 363                error = ENOENT;
 364                goto ErrorExit;
 365        }
 366        // XXXdbg - don't allow modifying the journal or journal_info_block
 367        if (hfsmp->jnl && cp->c_datafork) {
 368                struct HFSPlusExtentDescriptor *extd;
 369                
 370                extd = &cp->c_datafork->ff_extents[0];
 371                if (extd->startBlock == HFSTOVCB(hfsmp)->vcbJinfoBlock || extd->startBlock == hfsmp->jnl_start) {
 372                        error = EPERM;
 373                        goto ErrorExit;
 374                }
 375        }
 376
 377        /*
 378         * Ownership of a file is required in one of two classes of calls:
 379         *
 380         * (a) When setting any ownership-requiring attribute other
 381         *     than ATTR_CMN_FLAGS, or
 382         * (b) When setting ATTR_CMN_FLAGS on a volume that's not
 383         *     plain HFS (for which no real per-object ownership
 384         *     information is stored)
 385         */
 386        if ((alist->commonattr & (ATTR_OWNERSHIP_SETMASK & ~ATTR_CMN_FLAGS)) ||
 387            ((alist->commonattr & ATTR_CMN_FLAGS) &&
 388             (VTOVCB(vp)->vcbSigWord != kHFSSigWord))) {
 389                /*
 390                 * NOTE: The following isn't ENTIRELY complete: even if
 391                 * you're the superuser you cannot change the flags as
 392                 * long as SF_IMMUTABLE or SF_APPEND is set and the
 393                 * securelevel > 0.  This is verified in hfs_chflags
 394                 * which gets invoked to do the actual flags field
 395                 * change so this check is sufficient for now.
 396                 */
 397                if ((error = hfs_owner_rights(hfsmp, cp->c_uid, cred, p, true)) != 0)
 398                        goto ErrorExit;
 399        }
 400        /*
 401         * For any other attributes, check to see if the user has
 402         * write access to the cnode in question [unlike vn_access,
 403         * ignore IMMUTABLE here]:
 404         */ 
 405        if (((alist->commonattr & ~ATTR_OWNERSHIP_SETMASK) != 0) ||
 406            (alist->volattr != 0) || (alist->dirattr != 0) ||
 407            (alist->fileattr != 0)) {
 408                if ((error = hfs_write_access(vp, cred, p, false)) != 0)
 409                        goto ErrorExit;
 410        }
 411
 412        /*
 413         * Allocate the buffer now to minimize the time we might
 414         * be blocked holding the catalog lock.
 415         */
 416        // LP64todo - fix this
 417        attrblocksize = uio_resid(ap->a_uio);
 418        if (attrblocksize < hfs_attrblksize(alist)) {
 419                error = EINVAL;
 420                goto ErrorExit;
 421        }
 422
 423        MALLOC(attrbufptr, void *, attrblocksize, M_TEMP, M_WAITOK);
 424
 425        error = uiomove((caddr_t)attrbufptr, attrblocksize, ap->a_uio);
 426        if (error)
 427                goto ErrorExit;
 428
 429        /* Save original state so changes can be detected. */
 430        saved_uid = cp->c_uid;
 431        saved_gid = cp->c_gid;
 432        saved_mode = cp->c_mode;
 433        saved_flags = cp->c_flags;
 434
 435        attrptr = attrbufptr;
 436        attrblk.ab_attrlist = alist;
 437        attrblk.ab_attrbufpp = &attrptr;
 438        attrblk.ab_varbufpp = &varptr;
 439        attrblk.ab_flags = 0;
 440        attrblk.ab_blocksize = attrblocksize;
 441        error = unpackattrblk(&attrblk, vp);
 442        if (error)
 443                goto ErrorExit;
 444
 445        /* If unpacking changed the owner/group then call hfs_chown() */
 446        if ((saved_uid != cp->c_uid) || (saved_gid != cp->c_gid)) {
 447                uid_t uid;
 448                gid_t gid;
 449                
 450                uid = cp->c_uid;
 451                cp->c_uid = saved_uid;
 452                gid = cp->c_gid;
 453                cp->c_gid = saved_gid;
 454                if ((error = hfs_chown(vp, uid, gid, cred, p)))
 455                        goto ErrorExit;
 456        }
 457        /* If unpacking changed the mode then call hfs_chmod() */
 458        if (saved_mode != cp->c_mode) {
 459                mode_t mode;
 460
 461                mode = cp->c_mode;
 462                cp->c_mode = saved_mode;
 463                if ((error = hfs_chmod(vp, mode, cred, p)))
 464                        goto ErrorExit;
 465        }
 466        /* If unpacking changed the flags then call hfs_chflags() */
 467        if (saved_flags !=cp->c_flags) {
 468                uint32_t flags;
 469
 470                flags = cp->c_flags;
 471                cp->c_flags = saved_flags;
 472                if ((error = hfs_chflags(vp, flags, cred, p)))
 473                        goto ErrorExit;
 474        }
 475        /*
 476         * If any cnode attributes changed then do an update.
 477         */
 478        if (alist->volattr == 0) {
 479                cp->c_flag |= C_MODIFIED;
 480                if ((error = hfs_update(vp, TRUE))) {
 481                        goto ErrorExit;
 482                }
 483        }
 484        /* Volume Rename */
 485        if (alist->volattr & ATTR_VOL_NAME) {
 486                ExtendedVCB *vcb = VTOVCB(vp);
 487        
 488                if (vcb->vcbVN[0] == 0) {
 489                        /*
 490                         * Ignore attempts to rename a volume to a zero-length name:
 491                         * restore the original name from the cnode.
 492                         */
 493                        copystr(cp->c_desc.cd_nameptr, vcb->vcbVN, sizeof(vcb->vcbVN), NULL);
 494                } else {
 495                        struct cat_desc to_desc;
 496                        struct cat_desc todir_desc;
 497                        struct cat_desc new_desc;
 498                        cat_cookie_t cookie;
 499                        int catreserve = 0;
 500                        int catlocked = 0;
 501                        int started_tr = 0;
 502                        int lockflags;
 503
 504                        bzero(&to_desc, sizeof(to_desc));
 505                        bzero(&todir_desc, sizeof(todir_desc));
 506                        bzero(&new_desc, sizeof(new_desc));
 507                        bzero(&cookie, sizeof(cookie));
 508
 509                        todir_desc.cd_parentcnid = kHFSRootParentID;
 510                        todir_desc.cd_cnid = kHFSRootFolderID;
 511                        todir_desc.cd_flags = CD_ISDIR;
 512
 513                        to_desc.cd_nameptr = vcb->vcbVN;
 514                        to_desc.cd_namelen = strlen(vcb->vcbVN);
 515                        to_desc.cd_parentcnid = kHFSRootParentID;
 516                        to_desc.cd_cnid = cp->c_cnid;
 517                        to_desc.cd_flags = CD_ISDIR;
 518
 519                        if ((error = hfs_start_transaction(hfsmp) != 0)) {
 520                            goto rename_out;
 521                        }
 522                        started_tr = 1;
 523
 524                        /*
 525                         * Reserve some space in the Catalog file.
 526                         */
 527                        error = cat_preflight(hfsmp, CAT_RENAME, &cookie, p);
 528                        if (error) {
 529                                goto rename_out;
 530                        }
 531                        catreserve = 1;
 532
 533                        lockflags = hfs_systemfile_lock(hfsmp, SFL_CATALOG, HFS_EXCLUSIVE_LOCK);
 534                        catlocked = 1;
 535
 536                        error = cat_rename(hfsmp, &cp->c_desc, &todir_desc, &to_desc, &new_desc);
 537rename_out:                     
 538                        if (catlocked) {
 539                                hfs_systemfile_unlock(hfsmp, lockflags);
 540                        }
 541                        if (catreserve) {
 542                                cat_postflight(hfsmp, &cookie, p);
 543                        }
 544                        (void) hfs_flushvolumeheader(hfsmp, MNT_WAIT, 0);
 545                        if (started_tr) {
 546                            hfs_end_transaction(hfsmp);
 547                        }
 548                        
 549                        if (error) {
 550                                /* Restore the old name in the VCB */
 551                                copystr(cp->c_desc.cd_nameptr, vcb->vcbVN, sizeof(vcb->vcbVN), NULL);
 552                                vcb->vcbFlags |= 0xFF00;
 553                                goto ErrorExit;
 554                        }
 555                        /* Release old allocated name buffer */
 556                        if (cp->c_desc.cd_flags & CD_HASBUF) {
 557                                char *name = cp->c_desc.cd_nameptr;
 558                
 559                                cp->c_desc.cd_nameptr = 0;
 560                                cp->c_desc.cd_namelen = 0;
 561                                cp->c_desc.cd_flags &= ~CD_HASBUF;
 562                                vfs_removename(name);
 563                        }                       
 564                        /* Update cnode's catalog descriptor */
 565                        replace_desc(cp, &new_desc);
 566                        vcb->volumeNameEncodingHint = new_desc.cd_encoding;
 567                        cp->c_touch_chgtime = TRUE;
 568                }
 569        }
 570
 571        /*
 572         * When the volume name changes or the volume's finder info
 573         * changes then force them to disk immediately.
 574         */
 575        if ((alist->volattr & ATTR_VOL_INFO) &&
 576            ((alist->volattr & ATTR_VOL_NAME) ||
 577             (alist->commonattr & ATTR_CMN_FNDRINFO))) {
 578                (void) hfs_flushvolumeheader(hfsmp, MNT_WAIT, 0);
 579        }
 580ErrorExit:
 581        if (attrbufptr)
 582                FREE(attrbufptr, M_TEMP);
 583
 584        hfs_unlock(cp);
 585        return (error);
 586}
 587#endif
 588
 589/*
 590 * readdirattr operation will return attributes for the items in the
 591 * directory specified. 
 592 *
 593 * It does not do . and .. entries. The problem is if you are at the root of the
 594 * hfs directory and go to .. you could be crossing a mountpoint into a
 595 * different (ufs) file system. The attributes that apply for it may not 
 596 * apply for the file system you are doing the readdirattr on. To make life 
 597 * simpler, this call will only return entries in its directory, hfs like.
 598 * TO DO LATER: 
 599 * 1. more than one for uiovcnt support.
 600 * 2. put knohint (hints) in state for next call in
 601 * 3. credentials checking when rest of hfs does it.
 602 * 4. Do return permissions concatenation ???
 603 */
 604
 605/*                      
 606#
 607#% readdirattr  vp      L L L
 608#
 609vnop_readdirattr {
 610        IN struct vnode *vp;
 611        IN struct attrlist *alist;
 612        INOUT struct uio *uio;
 613        IN u_long maxcount:
 614        IN u_long options;
 615        OUT u_long *newstate;
 616        OUT int *eofflag;
 617        OUT u_long *actualCount;
 618        OUT u_long **cookies;
 619        IN kauth_cred_t cred;
 620};
 621*/
 622__private_extern__
 623int
 624hfs_vnop_readdirattr(ap)
 625        struct vnop_readdirattr_args /* {
 626                struct vnode *a_vp;
 627                struct attrlist *a_alist;
 628                struct uio *a_uio;
 629                u_long a_maxcount;
 630                u_long a_options;
 631                u_long *a_newstate;
 632                int *a_eofflag;
 633                u_long *a_actualcount;
 634                vfs_context_t a_context;
 635        } */ *ap;
 636{
 637        struct vnode *dvp = ap->a_vp;
 638        struct cnode *dcp;
 639        struct hfsmount * hfsmp;
 640        struct attrlist *alist = ap->a_alist;
 641        uio_t uio = ap->a_uio;
 642        int maxcount = ap->a_maxcount;
 643        struct proc *p = vfs_context_proc(ap->a_context);
 644        uint32_t fixedblocksize;
 645        uint32_t maxattrblocksize;
 646        uint32_t currattrbufsize;
 647        void *attrbufptr = NULL;
 648        void *attrptr;
 649        void *varptr;
 650        struct attrblock attrblk;
 651        int error = 0;
 652        int depleted = 0;
 653        int index;
 654        int i, dir_entries;
 655        struct cat_desc *lastdescp = NULL;
 656        struct cat_entrylist *ce_list = NULL;
 657        directoryhint_t *dirhint = NULL;
 658        unsigned int tag;
 659        int shared_cnode_lock = 0;
 660
 661        *(ap->a_actualcount) = 0;
 662        *(ap->a_eofflag) = 0;
 663
 664        /* Check for invalid options and buffer space. */
 665        if (((ap->a_options & ~(FSOPT_NOINMEMUPDATE | FSOPT_NOFOLLOW)) != 0)
 666        ||  (uio_resid(uio) <= 0) || (uio_iovcnt(uio) > 1) || (maxcount <= 0))
 667                return (EINVAL);
 668
 669        /* This call doesn't take volume attributes. */
 670        if ((alist->bitmapcount != ATTR_BIT_MAP_COUNT) ||
 671            ((alist->commonattr & ~ATTR_CMN_VALIDMASK) != 0) ||
 672            (alist->volattr  != 0) ||
 673            ((alist->dirattr & ~ATTR_DIR_VALIDMASK) != 0) ||
 674            ((alist->fileattr & ~ATTR_FILE_VALIDMASK) != 0)) 
 675                return (EINVAL);
 676
 677        if ((error = hfs_lock(VTOC(dvp), HFS_EXCLUSIVE_LOCK)))
 678                return (error);
 679        dcp = VTOC(dvp);
 680        hfsmp = VTOHFS(dvp);
 681
 682        /* Reject requests for unsupported options. */
 683        if ((alist->commonattr & (ATTR_CMN_NAMEDATTRCOUNT | ATTR_CMN_NAMEDATTRLIST |
 684             ATTR_CMN_OBJPERMANENTID)) ||
 685            (alist->fileattr & (ATTR_FILE_FILETYPE | ATTR_FILE_FORKCOUNT |
 686             ATTR_FILE_FORKLIST | ATTR_FILE_DATAEXTENTS | ATTR_FILE_RSRCEXTENTS))) {
 687                printf("readdirattr: unsupported attributes! (%s)\n", dcp->c_desc.cd_nameptr);
 688                error = EINVAL;
 689                goto exit;
 690        }
 691
 692        dir_entries = dcp->c_entries;
 693        if (dcp->c_attr.ca_fileid == kHFSRootFolderID && hfsmp->jnl) {
 694                dir_entries -= 3;
 695        }
 696
 697        /* Convert uio_offset into a directory index. */
 698        index = uio_offset(uio) & HFS_INDEX_MASK;
 699        tag = uio_offset(uio) & ~HFS_INDEX_MASK;
 700        if ((index + 1) > dir_entries) {
 701                *(ap->a_eofflag) = 1;
 702                error = 0;
 703                goto exit;
 704        }
 705
 706        /* Get a buffer to hold packed attributes. */
 707        fixedblocksize = (sizeof(uint32_t) + hfs_attrblksize(alist)); /* 4 bytes for length */
 708        maxattrblocksize = fixedblocksize;
 709        if (alist->commonattr & ATTR_CMN_NAME) 
 710                maxattrblocksize += kHFSPlusMaxFileNameBytes + 1;
 711        MALLOC(attrbufptr, void *, maxattrblocksize, M_TEMP, M_WAITOK);
 712        attrptr = attrbufptr;
 713        varptr = (char *)attrbufptr + fixedblocksize;  /* Point to variable-length storage */
 714
 715        /* Initialize a catalog entry list. */
 716        MALLOC(ce_list, struct cat_entrylist *, sizeof(*ce_list), M_TEMP, M_WAITOK);
 717        bzero(ce_list, sizeof(*ce_list));
 718        ce_list->maxentries = MAXCATENTRIES;
 719
 720        /* Get a directory hint (cnode must be locked exclusive) */     
 721        dirhint = hfs_getdirhint(dcp, ((index - 1) & HFS_INDEX_MASK) | tag);
 722
 723        /* Hide tag from catalog layer. */
 724        dirhint->dh_index &= HFS_INDEX_MASK;
 725        if (dirhint->dh_index == HFS_INDEX_MASK) {
 726                dirhint->dh_index = -1;
 727        }
 728
 729        /*
 730         * An ATTR_CMN_USERACCESS attribute request can result in a
 731         * call to kauth_cred_ismember_gid().  So when requesting
 732         * this attribute we downgrade our exclusive lock on dcp to
 733         * a shared lock in case kauth_cred_ismember_gid generates
 734         * an indirect call back into the file system.
 735         */
 736        if (alist->commonattr & ATTR_CMN_USERACCESS) {
 737                lck_rw_lock_exclusive_to_shared(&dcp->c_rwlock);
 738                dcp->c_lockowner = HFS_SHARED_OWNER;
 739                shared_cnode_lock = 1;
 740        }
 741        /*
 742         * Obtain a list of catalog entries and pack their attributes until
 743         * the output buffer is full or maxcount entries have been packed.
 744         */
 745        while (!depleted) {
 746                int maxentries;
 747                int lockflags;
 748
 749                /* Constrain our list size. */
 750                maxentries = uio_resid(uio) / (fixedblocksize + HFS_AVERAGE_NAME_SIZE);
 751                maxentries = min(maxentries, dcp->c_entries - index);
 752                maxentries = min(maxentries, maxcount);
 753                ce_list->maxentries = min(maxentries, ce_list->maxentries);
 754                lastdescp = NULL;
 755
 756                lockflags = hfs_systemfile_lock(hfsmp, SFL_CATALOG, HFS_SHARED_LOCK);
 757                 
 758                error = cat_getentriesattr(hfsmp, dirhint, ce_list);
 759                /* Don't forget to release the descriptors later! */
 760
 761                hfs_systemfile_unlock(hfsmp, lockflags);
 762 
 763                if (error == ENOENT) {
 764                        *(ap->a_eofflag) = TRUE;
 765                        error = 0;
 766                        depleted = 1;
 767                }
 768                if (error)
 769                        break;
 770 
 771                /* Process the catalog entries. */
 772                for (i = 0; i < (int)ce_list->realentries; ++i) {
 773                        struct cnode *cp = NULL;
 774                        struct vnode *vp = NULL;
 775                        struct cat_desc * cdescp;
 776                        struct cat_attr * cattrp;
 777                        struct cat_fork c_datafork;
 778                        struct cat_fork c_rsrcfork;
 779
 780                        bzero(&c_datafork, sizeof(c_datafork));
 781                        bzero(&c_rsrcfork, sizeof(c_rsrcfork));
 782                        cdescp = &ce_list->entry[i].ce_desc;
 783                        cattrp = &ce_list->entry[i].ce_attr;
 784                        c_datafork.cf_size   = ce_list->entry[i].ce_datasize;
 785                        c_datafork.cf_blocks = ce_list->entry[i].ce_datablks;
 786                        c_rsrcfork.cf_size   = ce_list->entry[i].ce_rsrcsize;
 787                        c_rsrcfork.cf_blocks = ce_list->entry[i].ce_rsrcblks;
 788                        /*
 789                         * Get in memory cnode data (if any).
 790                         */
 791                        if (!(ap->a_options & FSOPT_NOINMEMUPDATE)) {
 792                                vp = hfs_chash_getvnode(dcp->c_dev, cattrp->ca_fileid, 0, 0);
 793
 794                                if (vp != NULL) {
 795                                        cp = VTOC(vp);
 796                                        /* Only use cnode's decriptor for non-hardlinks */
 797                                        if (!(cp->c_flag & C_HARDLINK))
 798                                                cdescp = &cp->c_desc;
 799                                        cattrp = &cp->c_attr;
 800                                        if (cp->c_datafork) {
 801                                                c_datafork.cf_size   = cp->c_datafork->ff_size;
 802                                                c_datafork.cf_blocks = cp->c_datafork->ff_blocks;
 803                                        }
 804                                        if (cp->c_rsrcfork) {
 805                                                c_rsrcfork.cf_size   = cp->c_rsrcfork->ff_size;
 806                                                c_rsrcfork.cf_blocks = cp->c_rsrcfork->ff_blocks;
 807                                        }
 808                                }
 809                        }
 810                        *((uint32_t *)attrptr)++ = 0; /* move it past length */
 811                        attrblk.ab_attrlist = alist;
 812                        attrblk.ab_attrbufpp = &attrptr;
 813                        attrblk.ab_varbufpp = &varptr;
 814                        attrblk.ab_flags = 0;
 815                        attrblk.ab_blocksize = maxattrblocksize;
 816
 817                        /* Pack catalog entries into attribute buffer. */
 818                        hfs_packattrblk(&attrblk, hfsmp, vp, cdescp, cattrp,
 819                                        &c_datafork, &c_rsrcfork, p);
 820                        currattrbufsize = ((char *)varptr - (char *)attrbufptr);
 821                
 822                        /* All done with cnode. */
 823                        if (vp != NULL) {
 824                                hfs_unlock(VTOC(vp));
 825                                vnode_put(vp);
 826                                vp = NULL;
 827                                cp = NULL;
 828                        }
 829
 830                        /* Make sure there's enough buffer space remaining. */
 831                        // LP64todo - fix this!
 832                        if (uio_resid(uio) < 0 || currattrbufsize > (uint32_t)uio_resid(uio)) {
 833                                depleted = 1;
 834                                break;
 835                        } else {
 836                                *((uint32_t *)attrbufptr) = currattrbufsize;
 837                                error = uiomove((caddr_t)attrbufptr, currattrbufsize, ap->a_uio);
 838                                if (error != E_NONE) {
 839                                        depleted = 1;
 840                                        break;
 841                                }
 842                                attrptr = attrbufptr;
 843                                varptr = (char *)attrbufptr + fixedblocksize;  /* Point to variable-length storage */
 844                                /* Save the last valid catalog entry */
 845                                lastdescp = &ce_list->entry[i].ce_desc;
 846                                index++;
 847                                *ap->a_actualcount += 1;
 848
 849                                /* Termination checks */
 850                                if ((--maxcount <= 0) ||
 851                                        // LP64todo - fix this!
 852                                        uio_resid(uio) < 0 ||
 853                                    ((uint32_t)uio_resid(uio) < (fixedblocksize + HFS_AVERAGE_NAME_SIZE)) ||
 854                                    (index >= dir_entries)) {
 855                                        depleted = 1;
 856                                        break;
 857                                }
 858                        }
 859                } /* for each catalog entry */
 860
 861                /* If there are more entries then save the last name. */
 862                if (index < dir_entries
 863                &&  !(*(ap->a_eofflag))
 864                &&  lastdescp != NULL) {
 865
 866                        /* Remember last entry */
 867                        if (dirhint->dh_desc.cd_nameptr != NULL) {
 868                                vfs_removename(dirhint->dh_desc.cd_nameptr);
 869                        }
 870                        dirhint->dh_desc.cd_namelen = lastdescp->cd_namelen;
 871                        dirhint->dh_desc.cd_nameptr =
 872                                vfs_addname(lastdescp->cd_nameptr, lastdescp->cd_namelen, 0, 0);
 873                        dirhint->dh_index = index - 1;
 874                        dirhint->dh_desc.cd_cnid = lastdescp->cd_cnid;
 875                        dirhint->dh_desc.cd_hint = lastdescp->cd_hint;
 876                        dirhint->dh_desc.cd_encoding = lastdescp->cd_encoding;
 877                }
 878                        
 879                /* All done with the catalog descriptors. */
 880                for (i = 0; i < (int)ce_list->realentries; ++i)
 881                        cat_releasedesc(&ce_list->entry[i].ce_desc);
 882                ce_list->realentries = 0;
 883
 884        } /* while not depleted */
 885
 886        *ap->a_newstate = dcp->c_mtime;
 887
 888        /* Make sure dcp is locked exclusive before changing c_dirhinttag. */
 889        if (shared_cnode_lock) {
 890                lck_rw_lock_shared_to_exclusive(&dcp->c_rwlock);
 891                dcp->c_lockowner = current_thread();
 892                shared_cnode_lock = 0;
 893        }
 894
 895        /* Convert directory index back into a uio_offset. */
 896        while (tag == 0) tag = (++dcp->c_dirhinttag) << HFS_INDEX_BITS; 
 897        uio_setoffset(uio, index | tag);
 898        dirhint->dh_index |= tag;
 899
 900exit:
 901        /* Drop directory hint on error or if there are no more entries */
 902        if (dirhint && (error || index >= dir_entries)) {
 903                if (shared_cnode_lock) {
 904                        lck_rw_lock_shared_to_exclusive(&dcp->c_rwlock);
 905                        dcp->c_lockowner = current_thread();
 906                }
 907                hfs_reldirhint(dcp, dirhint);
 908        }
 909        if (attrbufptr)
 910                FREE(attrbufptr, M_TEMP);
 911        if (ce_list)
 912                FREE(ce_list, M_TEMP);
 913                
 914        hfs_unlock(dcp);
 915        return (error);
 916}
 917
 918
 919/*==================== Attribute list support routines ====================*/
 920
 921/*
 922 * Pack cnode attributes into an attribute block.
 923 */
 924 __private_extern__
 925void
 926hfs_packattrblk(struct attrblock *abp,
 927                struct hfsmount *hfsmp,
 928                struct vnode *vp,
 929                struct cat_desc *descp,
 930                struct cat_attr *attrp,
 931                struct cat_fork *datafork,
 932                struct cat_fork *rsrcfork,
 933                struct proc *p)
 934{
 935        struct attrlist *attrlistp = abp->ab_attrlist;
 936
 937        if (attrlistp->volattr) {
 938                if (attrlistp->commonattr)
 939                        packvolcommonattr(abp, hfsmp, vp, p);
 940
 941                if (attrlistp->volattr & ~ATTR_VOL_INFO)
 942                        packvolattr(abp, hfsmp, vp);
 943        } else {
 944                if (attrlistp->commonattr)
 945                        packcommonattr(abp, hfsmp, vp, descp, attrp, p);
 946        
 947                if (attrlistp->dirattr && S_ISDIR(attrp->ca_mode))
 948                        packdirattr(abp, hfsmp, vp, descp,attrp);
 949        
 950                if (attrlistp->fileattr && !S_ISDIR(attrp->ca_mode))
 951                        packfileattr(abp, hfsmp, attrp, datafork, rsrcfork);
 952        }
 953}
 954
 955
 956static char*
 957mountpointname(struct mount *mp)
 958{
 959        size_t namelength = strlen(mp->mnt_vfsstat.f_mntonname);
 960        int foundchars = 0;
 961        char *c;
 962        
 963        if (namelength == 0)
 964                return (NULL);
 965        
 966        /*
 967         * Look backwards through the name string, looking for
 968         * the first slash encountered (which must precede the
 969         * last part of the pathname).
 970         */
 971        for (c = mp->mnt_vfsstat.f_mntonname + namelength - 1;
 972             namelength > 0; --c, --namelength) {
 973                if (*c != '/') {
 974                        foundchars = 1;
 975                } else if (foundchars) {
 976                        return (c + 1);
 977                }
 978        }
 979        
 980        return (mp->mnt_vfsstat.f_mntonname);
 981}
 982
 983
 984static void
 985packnameattr(
 986        struct attrblock *abp,
 987        struct vnode *vp,
 988        char *name,
 989        int namelen)
 990{
 991        void *varbufptr;
 992        struct attrreference * attr_refptr;
 993        char *mpname;
 994        size_t mpnamelen;
 995        uint32_t attrlength;
 996        char empty = 0;
 997        
 998        /* A cnode's name may be incorrect for the root of a mounted
 999         * filesystem (it can be mounted on a different directory name
1000         * than the name of the volume, such as "blah-1").  So for the
1001         * root directory, it's best to return the last element of the
1002         location where the volume's mounted:
1003         */
1004        if ((vp != NULL) && vnode_isvroot(vp) &&
1005            (mpname = mountpointname(vnode_mount(vp)))) {
1006                mpnamelen = strlen(mpname);
1007                
1008                /* Trim off any trailing slashes: */
1009                while ((mpnamelen > 0) && (mpname[mpnamelen-1] == '/'))
1010                        --mpnamelen;
1011
1012                /* If there's anything left, use it instead of the volume's name */
1013                if (mpnamelen > 0) {
1014                        name = mpname;
1015                        namelen = mpnamelen;
1016                }
1017        }
1018        if (name == NULL) {
1019                name = &empty;
1020                namelen = 0;
1021        }
1022
1023        varbufptr = *abp->ab_varbufpp;
1024        attr_refptr = (struct attrreference *)(*abp->ab_attrbufpp);
1025
1026        attrlength = namelen + 1;
1027        attr_refptr->attr_dataoffset = (char *)varbufptr - (char *)attr_refptr;
1028        attr_refptr->attr_length = attrlength;
1029        (void) strncpy((unsigned char *)varbufptr, name, attrlength);
1030        /*
1031         * Advance beyond the space just allocated and
1032         * round up to the next 4-byte boundary:
1033         */
1034        (char *)(varbufptr) += attrlength + ((4 - (attrlength & 3)) & 3);
1035        ++attr_refptr;
1036
1037        *abp->ab_attrbufpp = attr_refptr;
1038        *abp->ab_varbufpp = varbufptr;
1039}
1040
1041/*
1042 * Pack common volume attributes.
1043 */
1044static void
1045packvolcommonattr(struct attrblock *abp, struct hfsmount *hfsmp, struct vnode *vp, struct proc *p)
1046{
1047        attrgroup_t attr;
1048        void *attrbufptr = *abp->ab_attrbufpp;
1049        void *varbufptr = *abp->ab_varbufpp;
1050        struct cnode *cp = VTOC(vp);
1051        struct mount *mp = VTOVFS(vp);
1052        ExtendedVCB *vcb = HFSTOVCB(hfsmp);
1053        u_int32_t attrlength;
1054        boolean_t is_64_bit = proc_is64bit(p);
1055
1056        attr = abp->ab_attrlist->commonattr;
1057
1058        if (ATTR_CMN_NAME & attr) {
1059                packnameattr(abp, vp, cp->c_desc.cd_nameptr, cp->c_desc.cd_namelen);
1060                attrbufptr = *abp->ab_attrbufpp;
1061                varbufptr = *abp->ab_varbufpp;
1062        }
1063        if (ATTR_CMN_DEVID & attr) {
1064                *((dev_t *)attrbufptr)++ = hfsmp->hfs_raw_dev;
1065        }
1066        if (ATTR_CMN_FSID & attr) {
1067                fsid_t fsid;
1068                
1069                fsid.val[0] = (long)hfsmp->hfs_raw_dev;
1070                fsid.val[1] = (long)vfs_typenum(mp);
1071                *((fsid_t *)attrbufptr) = fsid;
1072                ++((fsid_t *)attrbufptr);
1073        }
1074        if (ATTR_CMN_OBJTYPE & attr) {
1075                *((fsobj_type_t *)attrbufptr)++ = 0;
1076        }
1077        if (ATTR_CMN_OBJTAG & attr) {
1078                *((fsobj_tag_t *)attrbufptr)++ = VT_HFS;
1079        }
1080        if (ATTR_CMN_OBJID & attr)      {
1081                ((fsobj_id_t *)attrbufptr)->fid_objno = 0;
1082                ((fsobj_id_t *)attrbufptr)->fid_generation = 0;
1083                ++((fsobj_id_t *)attrbufptr);
1084        }
1085        if (ATTR_CMN_OBJPERMANENTID & attr) {
1086                ((fsobj_id_t *)attrbufptr)->fid_objno = 0;
1087                ((fsobj_id_t *)attrbufptr)->fid_generation = 0;
1088                ++((fsobj_id_t *)attrbufptr);
1089        }
1090        if (ATTR_CMN_PAROBJID & attr) {
1091                ((fsobj_id_t *)attrbufptr)->fid_objno = 0;
1092                ((fsobj_id_t *)attrbufptr)->fid_generation = 0;
1093                ++((fsobj_id_t *)attrbufptr);
1094        }
1095        if (ATTR_CMN_SCRIPT & attr) {
1096                uint32_t encoding;
1097 
1098                if (vcb->vcbSigWord == kHFSPlusSigWord)
1099                        encoding = vcb->volumeNameEncodingHint;
1100                else
1101                        encoding = hfsmp->hfs_encoding;
1102                *((text_encoding_t *)attrbufptr)++ = encoding;
1103        }
1104        if (ATTR_CMN_CRTIME & attr) {
1105            if (is_64_bit) {
1106            ((struct user_timespec *)attrbufptr)->tv_sec = vcb->vcbCrDate;
1107            ((struct user_timespec *)attrbufptr)->tv_nsec = 0;
1108            ++((struct user_timespec *)attrbufptr);
1109            }
1110            else {
1111            ((struct timespec *)attrbufptr)->tv_sec = vcb->vcbCrDate;
1112            ((struct timespec *)attrbufptr)->tv_nsec = 0;
1113            ++((struct timespec *)attrbufptr);
1114            }
1115        }
1116        if (ATTR_CMN_MODTIME & attr) {
1117            if (is_64_bit) {
1118            ((struct user_timespec *)attrbufptr)->tv_sec = vcb->vcbLsMod;
1119            ((struct user_timespec *)attrbufptr)->tv_nsec = 0;
1120            ++((struct user_timespec *)attrbufptr);
1121            }
1122            else {
1123            ((struct timespec *)attrbufptr)->tv_sec = vcb->vcbLsMod;
1124            ((struct timespec *)attrbufptr)->tv_nsec = 0;
1125            ++((struct timespec *)attrbufptr);
1126            }
1127        }
1128        if (ATTR_CMN_CHGTIME & attr) {
1129            if (is_64_bit) {
1130            ((struct user_timespec *)attrbufptr)->tv_sec = vcb->vcbLsMod;
1131            ((struct user_timespec *)attrbufptr)->tv_nsec = 0;
1132            ++((struct user_timespec *)attrbufptr);
1133            }
1134            else {
1135            ((struct timespec *)attrbufptr)->tv_sec = vcb->vcbLsMod;
1136            ((struct timespec *)attrbufptr)->tv_nsec = 0;
1137            ++((struct timespec *)attrbufptr);
1138            }
1139        }
1140        if (ATTR_CMN_ACCTIME & attr) {
1141            if (is_64_bit) {
1142            ((struct user_timespec *)attrbufptr)->tv_sec = vcb->vcbLsMod;
1143            ((struct user_timespec *)attrbufptr)->tv_nsec = 0;
1144            ++((struct user_timespec *)attrbufptr);
1145            }
1146            else {
1147            ((struct timespec *)attrbufptr)->tv_sec = vcb->vcbLsMod;
1148            ((struct timespec *)attrbufptr)->tv_nsec = 0;
1149            ++((struct timespec *)attrbufptr);
1150            }
1151        }
1152        if (ATTR_CMN_BKUPTIME & attr) {
1153            if (is_64_bit) {
1154            ((struct user_timespec *)attrbufptr)->tv_sec = vcb->vcbVolBkUp;
1155            ((struct user_timespec *)attrbufptr)->tv_nsec = 0;
1156            ++((struct user_timespec *)attrbufptr);
1157            }
1158            else {
1159            ((struct timespec *)attrbufptr)->tv_sec = vcb->vcbVolBkUp;
1160            ((struct timespec *)attrbufptr)->tv_nsec = 0;
1161            ++((struct timespec *)attrbufptr);
1162            }
1163        }
1164        if (ATTR_CMN_FNDRINFO & attr) {
1165                bcopy (&vcb->vcbFndrInfo, attrbufptr, sizeof(vcb->vcbFndrInfo));
1166                (char *)attrbufptr += sizeof(vcb->vcbFndrInfo);
1167        }
1168        if (ATTR_CMN_OWNERID & attr) {
1169                if (cp->c_uid == UNKNOWNUID)
1170                        *((uid_t *)attrbufptr)++ = kauth_cred_getuid(proc_ucred(p));
1171                else
1172                        *((uid_t *)attrbufptr)++ = cp->c_uid;
1173        }
1174        if (ATTR_CMN_GRPID & attr) {
1175                *((gid_t *)attrbufptr)++ = cp->c_gid;
1176        }
1177
1178        if (ATTR_CMN_ACCESSMASK & attr) {
1179                /*
1180                 * [2856576]  Since we are dynamically changing the owner, also
1181                 * effectively turn off the set-user-id and set-group-id bits,
1182                 * just like chmod(2) would when changing ownership.  This prevents
1183                 * a security hole where set-user-id programs run as whoever is
1184                 * logged on (or root if nobody is logged in yet!)
1185                 */
1186                *((uint32_t *)attrbufptr)++ =
1187                        (cp->c_uid == UNKNOWNUID) ? cp->c_mode & ~(S_ISUID | S_ISGID) : cp->c_mode;
1188        }
1189        if (ATTR_CMN_NAMEDATTRCOUNT & attr) {
1190                *((uint32_t *)attrbufptr)++ = 0;        /* XXX PPD TBC */
1191        }
1192        if (ATTR_CMN_NAMEDATTRLIST & attr) {
1193                attrlength = 0;
1194                ((struct attrreference *)attrbufptr)->attr_dataoffset = 0;
1195                ((struct attrreference *)attrbufptr)->attr_length = attrlength;
1196                /*
1197                 * Advance beyond the space just allocated and
1198                 * round up to the next 4-byte boundary:
1199                 */
1200                (char *)varbufptr += attrlength + ((4 - (attrlength & 3)) & 3);
1201                ++((struct attrreference *)attrbufptr);
1202        }
1203        if (ATTR_CMN_FLAGS & attr) {
1204                *((uint32_t *)attrbufptr)++ = cp->c_flags;
1205        }
1206        if (ATTR_CMN_USERACCESS & attr) {
1207                *((uint32_t *)attrbufptr)++ =
1208                        DerivePermissionSummary(cp->c_uid, cp->c_gid, cp->c_mode,
1209                                VTOVFS(vp), kauth_cred_get(), proc_self());
1210        }
1211
1212        *abp->ab_attrbufpp = attrbufptr;
1213        *abp->ab_varbufpp = varbufptr;
1214}
1215
1216
1217static void
1218packvolattr(struct attrblock *abp, struct hfsmount *hfsmp, struct vnode *vp)
1219{
1220        attrgroup_t attr;
1221        void *attrbufptr = *abp->ab_attrbufpp;
1222        void *varbufptr = *abp->ab_varbufpp;
1223        struct cnode *cp = VTOC(vp);
1224        struct mount *mp = VTOVFS(vp);
1225        ExtendedVCB *vcb = HFSTOVCB(hfsmp);
1226        uint32_t attrlength;
1227
1228        attr = abp->ab_attrlist->volattr;
1229
1230        if (ATTR_VOL_FSTYPE & attr) {
1231                *((uint32_t *)attrbufptr)++ = (uint32_t)vfs_typenum(mp);
1232        }
1233        if (ATTR_VOL_SIGNATURE & attr) {
1234                *((uint32_t *)attrbufptr)++ = (uint32_t)vcb->vcbSigWord;
1235        }
1236        if (ATTR_VOL_SIZE & attr) {
1237                *((off_t *)attrbufptr)++ =
1238                                (off_t)vcb->totalBlocks * (off_t)vcb->blockSize;
1239        }
1240        if (ATTR_VOL_SPACEFREE & attr) {
1241                *((off_t *)attrbufptr)++ = (off_t)hfs_freeblks(hfsmp, 0) *
1242                                           (off_t)vcb->blockSize;
1243        }
1244        if (ATTR_VOL_SPACEAVAIL & attr) {
1245                *((off_t *)attrbufptr)++ = (off_t)hfs_freeblks(hfsmp, 1) *
1246                                           (off_t)vcb->blockSize;
1247        }
1248        if (ATTR_VOL_MINALLOCATION & attr) {
1249                *((off_t *)attrbufptr)++ = (off_t)vcb->blockSize;
1250        }
1251        if (ATTR_VOL_ALLOCATIONCLUMP & attr) {
1252                *((off_t *)attrbufptr)++ = (off_t)(vcb->vcbClpSiz);
1253        }
1254        if (ATTR_VOL_IOBLOCKSIZE & attr) {
1255        *((uint32_t *)attrbufptr)++ = hfsmp->hfs_logBlockSize;
1256        }
1257        if (ATTR_VOL_OBJCOUNT & attr) {
1258                *((uint32_t *)attrbufptr)++ = 
1259                    (uint32_t)vcb->vcbFilCnt + (uint32_t)vcb->vcbDirCnt;
1260        }
1261        if (ATTR_VOL_FILECOUNT & attr) {
1262                *((uint32_t *)attrbufptr)++ = (uint32_t)vcb->vcbFilCnt;
1263        }
1264        if (ATTR_VOL_DIRCOUNT & attr) {
1265                *((uint32_t *)attrbufptr)++ = (uint32_t)vcb->vcbDirCnt;
1266        }
1267        if (ATTR_VOL_MAXOBJCOUNT & attr) {
1268                *((uint32_t *)attrbufptr)++ = 0xFFFFFFFF;
1269        }
1270        if (ATTR_VOL_MOUNTPOINT & attr) {
1271                ((struct attrreference *)attrbufptr)->attr_dataoffset =
1272                                (char *)varbufptr - (char *)attrbufptr;
1273                ((struct attrreference *)attrbufptr)->attr_length =
1274                                strlen(mp->mnt_vfsstat.f_mntonname) + 1;
1275                attrlength = ((struct attrreference *)attrbufptr)->attr_length;
1276                /* round up to the next 4-byte boundary: */
1277                attrlength = attrlength + ((4 - (attrlength & 3)) & 3);
1278                (void) bcopy(mp->mnt_vfsstat.f_mntonname, varbufptr, attrlength);
1279                        
1280                /* Advance beyond the space just allocated: */
1281                (char *)varbufptr += attrlength;
1282                ++((struct attrreference *)attrbufptr);
1283        }
1284        if (ATTR_VOL_NAME & attr) {
1285                ((struct attrreference *)attrbufptr)->attr_dataoffset =
1286                                (char *)varbufptr - (char *)attrbufptr;
1287                ((struct attrreference *)attrbufptr)->attr_length =
1288                                cp->c_desc.cd_namelen + 1;
1289                attrlength = ((struct attrreference *)attrbufptr)->attr_length;
1290                /* round up to the next 4-byte boundary: */
1291                attrlength = attrlength + ((4 - (attrlength & 3)) & 3);
1292                /* XXX this could read off the end of cd_nameptr! */
1293                bcopy(cp->c_desc.cd_nameptr, varbufptr, attrlength);
1294
1295                /* Advance beyond the space just allocated: */
1296                (char *)varbufptr += attrlength;
1297                ++((struct attrreference *)attrbufptr);
1298        }
1299    if (ATTR_VOL_MOUNTFLAGS & attr) {
1300        *((uint32_t *)attrbufptr)++ = (uint32_t)vfs_flags(mp);
1301    }
1302        if (ATTR_VOL_MOUNTEDDEVICE & attr) {
1303                ((struct attrreference *)attrbufptr)->attr_dataoffset =
1304                                (char *)varbufptr - (char *)attrbufptr;
1305                ((struct attrreference *)attrbufptr)->attr_length =
1306                                strlen(mp->mnt_vfsstat.f_mntfromname) + 1;
1307                attrlength = ((struct attrreference *)attrbufptr)->attr_length;
1308                /* round up to the next 4-byte boundary: */
1309                attrlength = attrlength + ((4 - (attrlength & 3)) & 3);
1310                (void) bcopy(mp->mnt_vfsstat.f_mntfromname, varbufptr, attrlength);
1311                        
1312                /* Advance beyond the space just allocated: */
1313                (char *)varbufptr += attrlength;
1314                ++((struct attrreference *)attrbufptr);
1315        }
1316        if (ATTR_VOL_ENCODINGSUSED & attr) {
1317                *((unsigned long long *)attrbufptr)++ =
1318                                (unsigned long long)vcb->encodingsBitmap;
1319        }
1320        if (ATTR_VOL_CAPABILITIES & attr) {
1321                vol_capabilities_attr_t *vcapattrptr;
1322        
1323                vcapattrptr = (vol_capabilities_attr_t *)attrbufptr;
1324
1325                if (vcb->vcbSigWord == kHFSPlusSigWord) {
1326                        u_int32_t journal_active_cap;
1327                        u_int32_t case_sensitive;
1328                        
1329                        if (hfsmp->jnl)
1330                                journal_active_cap = VOL_CAP_FMT_JOURNAL_ACTIVE;
1331                        else
1332                                journal_active_cap = 0;
1333
1334                        if (hfsmp->hfs_flags & HFS_CASE_SENSITIVE)
1335                                case_sensitive = VOL_CAP_FMT_CASE_SENSITIVE;
1336                        else
1337                                case_sensitive = 0;
1338                        
1339                        vcapattrptr->capabilities[VOL_CAPABILITIES_FORMAT] =
1340                                        VOL_CAP_FMT_PERSISTENTOBJECTIDS |
1341                                        VOL_CAP_FMT_SYMBOLICLINKS |
1342                                        VOL_CAP_FMT_HARDLINKS |
1343                                        VOL_CAP_FMT_JOURNAL |
1344                                        journal_active_cap |
1345                                        case_sensitive |
1346                                        VOL_CAP_FMT_CASE_PRESERVING |
1347                                        VOL_CAP_FMT_FAST_STATFS | 
1348                                        VOL_CAP_FMT_2TB_FILESIZE;
1349                } else { /* Plain HFS */
1350                        vcapattrptr->capabilities[VOL_CAPABILITIES_FORMAT] =
1351                                        VOL_CAP_FMT_PERSISTENTOBJECTIDS |
1352                                        VOL_CAP_FMT_CASE_PRESERVING |
1353                                        VOL_CAP_FMT_FAST_STATFS ;
1354                }
1355                vcapattrptr->capabilities[VOL_CAPABILITIES_INTERFACES] =
1356                                        VOL_CAP_INT_SEARCHFS |
1357                                        VOL_CAP_INT_ATTRLIST |
1358                                        VOL_CAP_INT_NFSEXPORT |
1359                                        VOL_CAP_INT_READDIRATTR |
1360                                        VOL_CAP_INT_EXCHANGEDATA |
1361                                        VOL_CAP_INT_ALLOCATE |
1362                                        VOL_CAP_INT_VOL_RENAME |
1363                                        VOL_CAP_INT_ADVLOCK |
1364                                        VOL_CAP_INT_FLOCK ;
1365                vcapattrptr->capabilities[VOL_CAPABILITIES_RESERVED1] = 0;
1366                vcapattrptr->capabilities[VOL_CAPABILITIES_RESERVED2] = 0;
1367
1368                vcapattrptr->valid[VOL_CAPABILITIES_FORMAT] =
1369                                        VOL_CAP_FMT_PERSISTENTOBJECTIDS |
1370                                        VOL_CAP_FMT_SYMBOLICLINKS |
1371                                        VOL_CAP_FMT_HARDLINKS |
1372                                        VOL_CAP_FMT_JOURNAL |
1373                                        VOL_CAP_FMT_JOURNAL_ACTIVE |
1374                                        VOL_CAP_FMT_NO_ROOT_TIMES |
1375                                        VOL_CAP_FMT_SPARSE_FILES |
1376                                        VOL_CAP_FMT_ZERO_RUNS |
1377                                        VOL_CAP_FMT_CASE_SENSITIVE |
1378                                        VOL_CAP_FMT_CASE_PRESERVING |
1379                                        VOL_CAP_FMT_FAST_STATFS |
1380                                        VOL_CAP_FMT_2TB_FILESIZE;
1381                vcapattrptr->valid[VOL_CAPABILITIES_INTERFACES] =
1382                                        VOL_CAP_INT_SEARCHFS |
1383                                        VOL_CAP_INT_ATTRLIST |
1384                                        VOL_CAP_INT_NFSEXPORT |
1385                                        VOL_CAP_INT_READDIRATTR |
1386                                        VOL_CAP_INT_EXCHANGEDATA |
1387                                        VOL_CAP_INT_COPYFILE |
1388                                        VOL_CAP_INT_ALLOCATE |
1389                                        VOL_CAP_INT_VOL_RENAME |
1390                                        VOL_CAP_INT_ADVLOCK |
1391                                        VOL_CAP_INT_FLOCK ;
1392                vcapattrptr->valid[VOL_CAPABILITIES_RESERVED1] = 0;
1393                vcapattrptr->valid[VOL_CAPABILITIES_RESERVED2] = 0;
1394
1395                ++((vol_capabilities_attr_t *)attrbufptr);
1396        }
1397        if (ATTR_VOL_ATTRIBUTES & attr) {
1398                vol_attributes_attr_t *volattrattrp;
1399                
1400                volattrattrp = (vol_attributes_attr_t *)attrbufptr;
1401                volattrattrp->validattr.commonattr = ATTR_CMN_VALIDMASK;
1402                volattrattrp->validattr.volattr = ATTR_VOL_VALIDMASK;
1403                volattrattrp->validattr.dirattr = ATTR_DIR_VALIDMASK;
1404                volattrattrp->validattr.fileattr = ATTR_FILE_VALIDMASK;
1405                volattrattrp->validattr.forkattr = ATTR_FORK_VALIDMASK;
1406
1407                volattrattrp->nativeattr.commonattr = ATTR_CMN_VALIDMASK;
1408                volattrattrp->nativeattr.volattr = ATTR_VOL_VALIDMASK;
1409                volattrattrp->nativeattr.dirattr = ATTR_DIR_VALIDMASK;
1410                volattrattrp->nativeattr.fileattr = ATTR_FILE_VALIDMASK;
1411                volattrattrp->nativeattr.forkattr = ATTR_FORK_VALIDMASK;
1412                ++((vol_attributes_attr_t *)attrbufptr);
1413        }
1414        
1415        *abp->ab_attrbufpp = attrbufptr;
1416        *abp->ab_varbufpp = varbufptr;
1417}
1418
1419
1420static void
1421packcommonattr(
1422        struct attrblock *abp,
1423        struct hfsmount *hfsmp,
1424        struct vnode *vp,
1425        struct cat_desc * cdp,
1426        struct cat_attr * cap,
1427        struct proc *p)
1428{
1429        attrgroup_t attr = abp->ab_attrlist->commonattr;
1430        struct mount *mp = HFSTOVFS(hfsmp);
1431        void *attrbufptr = *abp->ab_attrbufpp;
1432        void *varbufptr = *abp->ab_varbufpp;
1433        uint32_t attrlength = 0;
1434        boolean_t is_64_bit = proc_is64bit(p);
1435        
1436        if (ATTR_CMN_NAME & attr) {
1437                packnameattr(abp, vp, cdp->cd_nameptr, cdp->cd_namelen);
1438                attrbufptr = *abp->ab_attrbufpp;
1439                varbufptr = *abp->ab_varbufpp;
1440        }
1441        if (ATTR_CMN_DEVID & attr) {
1442                *((dev_t *)attrbufptr)++ = hfsmp->hfs_raw_dev;
1443        }
1444        if (ATTR_CMN_FSID & attr) {
1445                fsid_t fsid;
1446                
1447                fsid.val[0] = (long)hfsmp->hfs_raw_dev;
1448                fsid.val[1] = (long)vfs_typenum(mp);
1449                *((fsid_t *)attrbufptr) = fsid;
1450                ++((fsid_t *)attrbufptr);
1451        }
1452        if (ATTR_CMN_OBJTYPE & attr) {
1453                *((fsobj_type_t *)attrbufptr)++ = IFTOVT(cap->ca_mode);
1454        }
1455        if (ATTR_CMN_OBJTAG & attr) {
1456                *((fsobj_tag_t *)attrbufptr)++ = VT_HFS;
1457        }
1458        /*
1459         * Exporting file IDs from HFS Plus:
1460         *
1461         * For "normal" files the c_fileid is the same value as the
1462         * c_cnid.  But for hard link files, they are different - the
1463         * c_cnid belongs to the active directory entry (ie the link)
1464         * and the c_fileid is for the actual inode (ie the data file).
1465         *
1466         * The stat call (getattr) will always return the c_fileid
1467         * and Carbon APIs, which are hardlink-ignorant, will always
1468         * receive the c_cnid (from getattrlist).
1469         */
1470    if (ATTR_CMN_OBJID & attr) {
1471                ((fsobj_id_t *)attrbufptr)->fid_objno = cdp->cd_cnid;
1472                ((fsobj_id_t *)attrbufptr)->fid_generation = 0;
1473                ++((fsobj_id_t *)attrbufptr);
1474        }
1475        if (ATTR_CMN_OBJPERMANENTID & attr) {
1476                ((fsobj_id_t *)attrbufptr)->fid_objno = cdp->cd_cnid;
1477                ((fsobj_id_t *)attrbufptr)->fid_generation = 0;
1478                ++((fsobj_id_t *)attrbufptr);
1479        }
1480        if (ATTR_CMN_PAROBJID & attr) {
1481                ((fsobj_id_t *)attrbufptr)->fid_objno = cdp->cd_parentcnid;
1482                ((fsobj_id_t *)attrbufptr)->fid_generation = 0;
1483                ++((fsobj_id_t *)attrbufptr);
1484        }
1485        if (ATTR_CMN_SCRIPT & attr) {
1486                *((text_encoding_t *)attrbufptr)++ = cdp->cd_encoding;
1487        }
1488        if (ATTR_CMN_CRTIME & attr) {
1489            if (is_64_bit) {
1490            ((struct user_timespec *)attrbufptr)->tv_sec = cap->ca_itime;
1491            ((struct user_timespec *)attrbufptr)->tv_nsec = 0;
1492            ++((struct user_timespec *)attrbufptr);
1493            }
1494            else {
1495            ((struct timespec *)attrbufptr)->tv_sec = cap->ca_itime;
1496            ((struct timespec *)attrbufptr)->tv_nsec = 0;
1497            ++((struct timespec *)attrbufptr);
1498            }
1499        }
1500        if (ATTR_CMN_MODTIME & attr) {
1501            if (is_64_bit) {
1502             ((struct user_timespec *)attrbufptr)->tv_sec = cap->ca_mtime;
1503             ((struct user_timespec *)attrbufptr)->tv_nsec = 0;
1504             ++((struct user_timespec *)attrbufptr);
1505            }
1506            else {
1507            ((struct timespec *)attrbufptr)->tv_sec = cap->ca_mtime;
1508            ((struct timespec *)attrbufptr)->tv_nsec = 0;
1509            ++((struct timespec *)attrbufptr);
1510            }
1511        }
1512        if (ATTR_CMN_CHGTIME & attr) {
1513            if (is_64_bit) {
1514            ((struct user_timespec *)attrbufptr)->tv_sec = cap->ca_ctime;
1515            ((struct user_timespec *)attrbufptr)->tv_nsec = 0;
1516            ++((struct user_timespec *)attrbufptr);
1517            }
1518            else {
1519            ((struct timespec *)attrbufptr)->tv_sec = cap->ca_ctime;
1520            ((struct timespec *)attrbufptr)->tv_nsec = 0;
1521            ++((struct timespec *)attrbufptr);
1522            }
1523        }
1524        if (ATTR_CMN_ACCTIME & attr) {
1525            if (is_64_bit) {
1526            ((struct user_timespec *)attrbufptr)->tv_sec = cap->ca_atime;
1527            ((struct user_timespec *)attrbufptr)->tv_nsec = 0;
1528            ++((struct user_timespec *)attrbufptr);
1529            }
1530            else {
1531            ((struct timespec *)attrbufptr)->tv_sec = cap->ca_atime;
1532            ((struct timespec *)attrbufptr)->tv_nsec = 0;
1533            ++((struct timespec *)attrbufptr);
1534            }
1535        }
1536        if (ATTR_CMN_BKUPTIME & attr) {
1537            if (is_64_bit) {
1538            ((struct user_timespec *)attrbufptr)->tv_sec = cap->ca_btime;
1539            ((struct user_timespec *)attrbufptr)->tv_nsec = 0;
1540            ++((struct user_timespec *)attrbufptr);
1541            }
1542            else {
1543            ((struct timespec *)attrbufptr)->tv_sec = cap->ca_btime;
1544            ((struct timespec *)attrbufptr)->tv_nsec = 0;
1545            ++((struct timespec *)attrbufptr);
1546            }
1547        }
1548        if (ATTR_CMN_FNDRINFO & attr) {
1549                bcopy(&cap->ca_finderinfo, attrbufptr, sizeof(u_int8_t) * 32);
1550                (char *)attrbufptr += sizeof(u_int8_t) * 32;
1551        }
1552        if (ATTR_CMN_OWNERID & attr) {
1553                *((uid_t *)attrbufptr)++ =
1554                        (cap->ca_uid == UNKNOWNUID) ? kauth_cred_getuid(proc_ucred(p)) : cap->ca_uid;
1555        }
1556        if (ATTR_CMN_GRPID & attr) {
1557                *((gid_t *)attrbufptr)++ = cap->ca_gid;
1558        }
1559        if (ATTR_CMN_ACCESSMASK & attr) {
1560                /*
1561                 * [2856576]  Since we are dynamically changing the owner, also
1562                 * effectively turn off the set-user-id and set-group-id bits,
1563                 * just like chmod(2) would when changing ownership.  This prevents
1564                 * a security hole where set-user-id programs run as whoever is
1565                 * logged on (or root if nobody is logged in yet!)
1566                 */
1567                *((uint32_t *)attrbufptr)++ =
1568                        (cap->ca_uid == UNKNOWNUID) ? cap->ca_mode & ~(S_ISUID | S_ISGID) : cap->ca_mode;
1569        }
1570        if (ATTR_CMN_NAMEDATTRCOUNT & attr) {
1571                *((uint32_t *)attrbufptr)++ = 0;
1572        }
1573        if (ATTR_CMN_NAMEDATTRLIST & attr) {
1574                attrlength = 0;
1575                ((struct attrreference *)attrbufptr)->attr_dataoffset = 0;
1576                ((struct attrreference *)attrbufptr)->attr_length = attrlength;
1577                /*
1578                 * Advance beyond the space just allocated and
1579                 * round up to the next 4-byte boundary:
1580                 */
1581                (char *)varbufptr += attrlength + ((4 - (attrlength & 3)) & 3);
1582                ++((struct attrreference *)attrbufptr);
1583        }
1584        if (ATTR_CMN_FLAGS & attr) {
1585                *((uint32_t *)attrbufptr)++ = cap->ca_flags;
1586        }
1587        if (ATTR_CMN_USERACCESS & attr) {
1588                *((uint32_t *)attrbufptr)++ =
1589                        DerivePermissionSummary(cap->ca_uid, cap->ca_gid,
1590                                cap->ca_mode, mp, proc_ucred(current_proc()),
1591                                current_proc());
1592        }
1593        
1594        *abp->ab_attrbufpp = attrbufptr;
1595        *abp->ab_varbufpp = varbufptr;
1596}
1597
1598static void
1599packdirattr(
1600        struct attrblock *abp,
1601        struct hfsmount *hfsmp,
1602        struct vnode *vp,
1603        struct cat_desc * descp,
1604        struct cat_attr * cattrp)
1605{
1606        attrgroup_t attr = abp->ab_attrlist->dirattr;
1607        void *attrbufptr = *abp->ab_attrbufpp;
1608        
1609        if (ATTR_DIR_LINKCOUNT & attr)
1610                *((uint32_t *)attrbufptr)++ = cattrp->ca_nlink;
1611        if (ATTR_DIR_ENTRYCOUNT & attr) {
1612                uint32_t entries = cattrp->ca_entries;
1613
1614                if (descp->cd_parentcnid == kHFSRootParentID) {
1615                        if (hfsmp->hfs_privdir_desc.cd_cnid != 0)
1616                                --entries;          /* hide private dir */
1617                        if (hfsmp->jnl)
1618                                entries -= 2;   /* hide the journal files */
1619                }
1620
1621                *((uint32_t *)attrbufptr)++ = entries;
1622        }
1623        if (ATTR_DIR_MOUNTSTATUS & attr) {
1624                if (vp != NULL && vnode_mountedhere(vp) != NULL)
1625                        *((uint32_t *)attrbufptr)++ = DIR_MNTSTATUS_MNTPOINT;
1626                else
1627                        *((uint32_t *)attrbufptr)++ = 0;
1628        }
1629        *abp->ab_attrbufpp = attrbufptr;
1630}
1631
1632static void
1633packfileattr(
1634        struct attrblock *abp,
1635        struct hfsmount *hfsmp,
1636        struct cat_attr *cattrp,
1637        struct cat_fork *datafork,
1638        struct cat_fork *rsrcfork)
1639{
1640        attrgroup_t attr = abp->ab_attrlist->fileattr;
1641        void *attrbufptr = *abp->ab_attrbufpp;
1642        void *varbufptr = *abp->ab_varbufpp;
1643        uint32_t attrlength;
1644        uint32_t allocblksize;
1645
1646        allocblksize = HFSTOVCB(hfsmp)->blockSize;
1647
1648        if (ATTR_FILE_LINKCOUNT & attr) {
1649                *((uint32_t *)attrbufptr)++ = cattrp->ca_nlink;
1650        }
1651        if (ATTR_FILE_TOTALSIZE & attr) {
1652                *((off_t *)attrbufptr)++ = datafork->cf_size + rsrcfork->cf_size;
1653        }
1654        if (ATTR_FILE_ALLOCSIZE & attr) {
1655                *((off_t *)attrbufptr)++ =
1656                        (off_t)cattrp->ca_blocks * (off_t)allocblksize;
1657        }
1658        if (ATTR_FILE_IOBLOCKSIZE & attr) {
1659                *((uint32_t *)attrbufptr)++ = hfsmp->hfs_logBlockSize;
1660        }
1661        if (ATTR_FILE_CLUMPSIZE & attr) {
1662                *((uint32_t *)attrbufptr)++ = HFSTOVCB(hfsmp)->vcbClpSiz;
1663        }
1664        if (ATTR_FILE_DEVTYPE & attr) {
1665                if (S_ISBLK(cattrp->ca_mode) || S_ISCHR(cattrp->ca_mode))
1666                        *((uint32_t *)attrbufptr)++ = (uint32_t)cattrp->ca_rdev;
1667                else
1668                        *((uint32_t *)attrbufptr)++ = 0;
1669        }
1670        if (ATTR_FILE_FILETYPE & attr) {
1671                *((uint32_t *)attrbufptr)++ = 0;
1672        }
1673        if (ATTR_FILE_FORKCOUNT & attr) {
1674                *((uint32_t *)attrbufptr)++ = 2;
1675        }
1676        if (ATTR_FILE_FORKLIST & attr) {
1677                attrlength = 0;
1678                ((struct attrreference *)attrbufptr)->attr_dataoffset = 0;
1679                ((struct attrreference *)attrbufptr)->attr_length = attrlength; 
1680                /*
1681                 * Advance beyond the space just allocated and
1682                 * round up to the next 4-byte boundary:
1683                 */
1684                (char *)varbufptr += attrlength + ((4 - (attrlength & 3)) & 3);
1685                ++((struct attrreference *)attrbufptr);
1686        }
1687        if (ATTR_FILE_DATALENGTH & attr) {
1688                *((off_t *)attrbufptr)++ = datafork->cf_size;
1689        }
1690        if (ATTR_FILE_DATAALLOCSIZE & attr) {
1691                *((off_t *)attrbufptr)++ =
1692                        (off_t)datafork->cf_blocks * (off_t)allocblksize;
1693        }
1694        if (ATTR_FILE_DATAEXTENTS & attr) {
1695                bcopy(&datafork->cf_extents, attrbufptr, sizeof(extentrecord));
1696                (char *)attrbufptr += sizeof(extentrecord);
1697        }
1698        if (ATTR_FILE_RSRCLENGTH & attr) {
1699                *((off_t *)attrbufptr)++ = rsrcfork->cf_size;
1700        }
1701        if (ATTR_FILE_RSRCALLOCSIZE & attr) {
1702                *((off_t *)attrbufptr)++ =
1703                        (off_t)rsrcfork->cf_blocks * (off_t)allocblksize;
1704        }
1705        if (ATTR_FILE_RSRCEXTENTS & attr) {
1706                bcopy(&rsrcfork->cf_extents, attrbufptr, sizeof(extentrecord));
1707                (char *)attrbufptr += sizeof(extentrecord);
1708        }
1709        *abp->ab_attrbufpp = attrbufptr;
1710        *abp->ab_varbufpp = varbufptr;
1711}
1712
1713#if 0
1714static int
1715unpackattrblk(struct attrblock *abp, struct vnode *vp)
1716{
1717        struct attrlist *attrlistp = abp->ab_attrlist;
1718        int error;
1719
1720        if (attrlistp->volattr) {
1721                error = unpackvolattr(abp, VTOHFS(vp), vp);
1722                if (error)
1723                        return (error);
1724        } else if (attrlistp->commonattr) {
1725                unpackcommonattr(abp, vp);
1726        }
1727        return (0);
1728}
1729
1730
1731static void
1732unpackcommonattr(
1733        struct attrblock *abp,
1734        struct vnode *vp)
1735{
1736        attrgroup_t attr = abp->ab_attrlist->commonattr;
1737        void *attrbufptr = *abp->ab_attrbufpp;
1738        struct cnode *cp = VTOC(vp);
1739        boolean_t is_64_bit = proc_is64bit(current_proc());
1740
1741        if (ATTR_CMN_SCRIPT & attr) {
1742                cp->c_encoding = (u_int32_t)*((text_encoding_t *)attrbufptr)++;
1743                hfs_setencodingbits(VTOHFS(vp), cp->c_encoding);
1744        }
1745        if (ATTR_CMN_CRTIME & attr) {
1746            if (is_64_bit) {
1747            cp->c_itime = ((struct user_timespec *)attrbufptr)->tv_sec;
1748            ++((struct user_timespec *)attrbufptr);
1749            }
1750            else {
1751            cp->c_itime = ((struct timespec *)attrbufptr)->tv_sec;
1752            ++((struct timespec *)attrbufptr);
1753            }
1754        }
1755        if (ATTR_CMN_MODTIME & attr) {
1756                cp->c_mtime = ((struct timespec *)attrbufptr)->tv_sec;
1757                ++((struct timespec *)attrbufptr);
1758                cp->c_touch_modtime = FALSE;
1759        }
1760        if (ATTR_CMN_CHGTIME & attr) {
1761                cp->c_ctime = ((struct timespec *)attrbufptr)->tv_sec;
1762                ++((struct timespec *)attrbufptr);
1763                cp->c_touch_chgtime = FALSE;
1764        }
1765        if (ATTR_CMN_ACCTIME & attr) {
1766                cp->c_atime = ((struct timespec *)attrbufptr)->tv_sec;
1767                ++((struct timespec *)attrbufptr);
1768                cp->c_touch_acctime = FALSE;
1769        }
1770        if (ATTR_CMN_BKUPTIME & attr) {
1771                cp->c_btime = ((struct timespec *)attrbufptr)->tv_sec;
1772                ++((struct timespec *)attrbufptr);
1773        }
1774        if (ATTR_CMN_FNDRINFO & attr) {
1775                bcopy(attrbufptr, &cp->c_attr.ca_finderinfo,
1776                        sizeof(cp->c_attr.ca_finderinfo));
1777                (char *)attrbufptr += sizeof(cp->c_attr.ca_finderinfo);
1778        }
1779        if (ATTR_CMN_OWNERID & attr) {
1780                if (VTOVCB(vp)->vcbSigWord == kHFSPlusSigWord) {
1781                        u_int32_t uid = (u_int32_t)*((uid_t *)attrbufptr)++;
1782                        if (uid != (uid_t)VNOVAL)
1783                                cp->c_uid = uid;
1784                } else {
1785                        ((uid_t *)attrbufptr)++;
1786                }
1787        }
1788        if (ATTR_CMN_GRPID & attr) {
1789                u_int32_t gid = (u_int32_t)*((gid_t *)attrbufptr)++;
1790                if (VTOVCB(vp)->vcbSigWord == kHFSPlusSigWord) {
1791                    if (gid != (gid_t)VNOVAL)
1792                        cp->c_gid = gid;
1793                }
1794        }
1795        if (ATTR_CMN_ACCESSMASK & attr) {
1796                u_int16_t mode = (u_int16_t)*((uint32_t *)attrbufptr)++;
1797                if (VTOVCB(vp)->vcbSigWord == kHFSPlusSigWord) {
1798                        if (mode != (mode_t)VNOVAL) {
1799                                cp->c_mode &= ~ALLPERMS;
1800                                cp->c_mode |= (mode & ALLPERMS);
1801                        }
1802                }
1803        }
1804        if (ATTR_CMN_FLAGS & attr) {
1805                uint32_t flags = *((uint32_t *)attrbufptr)++;
1806                /*
1807                 * Flags are settable only on HFS+ volumes.  A special
1808                 * exception is made for the IMMUTABLE flags
1809                 * (SF_IMMUTABLE and UF_IMMUTABLE), which can be set on
1810                 * HFS volumes as well:
1811                 */
1812                if ((VTOVCB(vp)->vcbSigWord == kHFSPlusSigWord) ||
1813                    ((VTOVCB(vp)->vcbSigWord == kHFSSigWord) &&
1814                     ((flags & ~IMMUTABLE) == 0))) {
1815                        if (flags != (uint32_t)VNOVAL) {
1816                                cp->c_flags = flags;
1817                        }
1818                }
1819        }
1820        *abp->ab_attrbufpp = attrbufptr;
1821}
1822
1823
1824static int
1825unpackvolattr(
1826        struct attrblock *abp,
1827        struct hfsmount *hfsmp,
1828        struct vnode *root_vp)
1829{
1830        void *attrbufptr = *abp->ab_attrbufpp;
1831        attrgroup_t attr;
1832        int error = 0;
1833        boolean_t is_64_bit = proc_is64bit(current_proc());
1834
1835        HFS_MOUNT_LOCK(hfsmp, TRUE);
1836
1837        attr = abp->ab_attrlist->commonattr;
1838        if (attr == 0)
1839                goto volattr;
1840
1841        if (ATTR_CMN_SCRIPT & attr) {
1842                hfsmp->volumeNameEncodingHint =
1843                                (u_int32_t)*(((text_encoding_t *)attrbufptr)++);
1844        }
1845        if (ATTR_CMN_CRTIME & attr) {
1846            if (is_64_bit) {
1847            hfsmp->vcbCrDate = ((struct user_timespec *)attrbufptr)->tv_sec;
1848            ++((struct user_timespec *)attrbufptr);
1849            }
1850            else {
1851            hfsmp->vcbCrDate = ((struct timespec *)attrbufptr)->tv_sec;
1852            ++((struct timespec *)attrbufptr);
1853            }
1854                
1855                /* The volume's create date comes from the root directory */
1856                VTOC(root_vp)->c_itime = hfsmp->vcbCrDate;
1857                VTOC(root_vp)->c_flag |= C_MODIFIED;
1858                /*
1859                 * XXX Should we also do a relative change to the
1860                 * the volume header's create date in local time?
1861                 */
1862        }
1863        if (ATTR_CMN_MODTIME & attr) {
1864                hfsmp->vcbLsMod = ((struct timespec *)attrbufptr)->tv_sec;
1865                ++((struct timespec *)attrbufptr);
1866        }
1867        if (ATTR_CMN_BKUPTIME & attr) {
1868                hfsmp->vcbVolBkUp = ((struct timespec *)attrbufptr)->tv_sec;
1869                ++((struct timespec *)attrbufptr);
1870        }
1871        if (ATTR_CMN_FNDRINFO & attr) {
1872                bcopy(attrbufptr, &hfsmp->vcbFndrInfo, sizeof(hfsmp->vcbFndrInfo));
1873                (char *)attrbufptr += sizeof(hfsmp->vcbFndrInfo);
1874        }
1875
1876volattr:        
1877        attr = abp->ab_attrlist->volattr & ~ATTR_VOL_INFO;
1878        /*
1879         * XXX - no validation is done on the name!
1880         * It could be empty or garbage (bad UTF-8).
1881         */
1882        if (ATTR_VOL_NAME & attr) {
1883                attrreference_t * attr_refp = (attrreference_t *) attrbufptr;
1884                
1885                error = copystr(((char *)attrbufptr) + attr_refp->attr_dataoffset,
1886                                hfsmp->vcbVN, MIN(attr_refp->attr_length, sizeof(hfsmp->vcbVN)),
1887                                NULL);
1888                if (error == 0)
1889                        (char *)attrbufptr += sizeof(struct attrreference);
1890        }
1891        *abp->ab_attrbufpp = attrbufptr;
1892
1893        hfsmp->vcbFlags |= 0xFF00;
1894        HFS_MOUNT_UNLOCK(hfsmp, TRUE);
1895
1896        return (error);
1897}
1898#endif
1899
1900/*
1901 * Calculate the total size of an attribute block.
1902 */
1903 __private_extern__
1904int
1905hfs_attrblksize(struct attrlist *attrlist)
1906{
1907        int size;
1908        attrgroup_t a;
1909        int sizeof_timespec;
1910        boolean_t is_64_bit = proc_is64bit(current_proc());
1911        
1912    if (is_64_bit) 
1913        sizeof_timespec = sizeof(struct user_timespec);
1914    else
1915        sizeof_timespec = sizeof(struct timespec);
1916
1917#if ((ATTR_CMN_NAME | ATTR_CMN_DEVID | ATTR_CMN_FSID | ATTR_CMN_OBJTYPE |  \
1918      ATTR_CMN_OBJTAG | ATTR_CMN_OBJID | ATTR_CMN_OBJPERMANENTID |         \
1919      ATTR_CMN_PAROBJID | ATTR_CMN_SCRIPT | ATTR_CMN_CRTIME |              \
1920      ATTR_CMN_MODTIME | ATTR_CMN_CHGTIME | ATTR_CMN_ACCTIME |             \
1921      ATTR_CMN_BKUPTIME | ATTR_CMN_FNDRINFO | ATTR_CMN_OWNERID |           \
1922      ATTR_CMN_GRPID | ATTR_CMN_ACCESSMASK | ATTR_CMN_NAMEDATTRCOUNT |     \
1923      ATTR_CMN_NAMEDATTRLIST | ATTR_CMN_FLAGS | ATTR_CMN_USERACCESS)       \
1924      != ATTR_CMN_VALIDMASK)
1925#error  hfs_attrblksize: Missing bits in common mask computation!
1926#endif
1927        DBG_ASSERT((attrlist->commonattr & ~ATTR_CMN_VALIDMASK) == 0);
1928
1929#if ((ATTR_VOL_FSTYPE | ATTR_VOL_SIGNATURE | ATTR_VOL_SIZE |                \
1930      ATTR_VOL_SPACEFREE | ATTR_VOL_SPACEAVAIL | ATTR_VOL_MINALLOCATION |   \
1931      ATTR_VOL_ALLOCATIONCLUMP | ATTR_VOL_IOBLOCKSIZE |                     \
1932      ATTR_VOL_OBJCOUNT | ATTR_VOL_FILECOUNT | ATTR_VOL_DIRCOUNT |          \
1933      ATTR_VOL_MAXOBJCOUNT | ATTR_VOL_MOUNTPOINT | ATTR_VOL_NAME |          \
1934      ATTR_VOL_MOUNTFLAGS | ATTR_VOL_INFO | ATTR_VOL_MOUNTEDDEVICE |        \
1935      ATTR_VOL_ENCODINGSUSED | ATTR_VOL_CAPABILITIES | ATTR_VOL_ATTRIBUTES) \
1936      != ATTR_VOL_VALIDMASK)
1937#error  hfs_attrblksize: Missing bits in volume mask computation!
1938#endif
1939        DBG_ASSERT((attrlist->volattr & ~ATTR_VOL_VALIDMASK) == 0);
1940
1941#if ((ATTR_DIR_LINKCOUNT | ATTR_DIR_ENTRYCOUNT | ATTR_DIR_MOUNTSTATUS)  \
1942      != ATTR_DIR_VALIDMASK)
1943#error  hfs_attrblksize: Missing bits in directory mask computation!
1944#endif
1945        DBG_ASSERT((attrlist->dirattr & ~ATTR_DIR_VALIDMASK) == 0);
1946
1947#if ((ATTR_FILE_LINKCOUNT | ATTR_FILE_TOTALSIZE | ATTR_FILE_ALLOCSIZE |        \
1948      ATTR_FILE_IOBLOCKSIZE | ATTR_FILE_CLUMPSIZE | ATTR_FILE_DEVTYPE |        \
1949      ATTR_FILE_FILETYPE | ATTR_FILE_FORKCOUNT | ATTR_FILE_FORKLIST |          \
1950      ATTR_FILE_DATALENGTH | ATTR_FILE_DATAALLOCSIZE | ATTR_FILE_DATAEXTENTS | \
1951      ATTR_FILE_RSRCLENGTH | ATTR_FILE_RSRCALLOCSIZE | ATTR_FILE_RSRCEXTENTS)  \
1952      != ATTR_FILE_VALIDMASK)
1953#error  hfs_attrblksize: Missing bits in file mask computation!
1954#endif
1955        DBG_ASSERT((attrlist->fileattr & ~ATTR_FILE_VALIDMASK) == 0);
1956
1957#if ((ATTR_FORK_TOTALSIZE | ATTR_FORK_ALLOCSIZE) != ATTR_FORK_VALIDMASK)
1958#error  hfs_attrblksize: Missing bits in fork mask computation!
1959#endif
1960        DBG_ASSERT((attrlist->forkattr & ~ATTR_FORK_VALIDMASK) == 0);
1961
1962        size = 0;
1963        
1964        if ((a = attrlist->commonattr) != 0) {
1965        if (a & ATTR_CMN_NAME) size += sizeof(struct attrreference);
1966                if (a & ATTR_CMN_DEVID) size += sizeof(dev_t);
1967                if (a & ATTR_CMN_FSID) size += sizeof(fsid_t);
1968                if (a & ATTR_CMN_OBJTYPE) size += sizeof(fsobj_type_t);
1969                if (a & ATTR_CMN_OBJTAG) size += sizeof(fsobj_tag_t);
1970                if (a & ATTR_CMN_OBJID) size += sizeof(fsobj_id_t);
1971                if (a & ATTR_CMN_OBJPERMANENTID) size += sizeof(fsobj_id_t);
1972                if (a & ATTR_CMN_PAROBJID) size += sizeof(fsobj_id_t);
1973                if (a & ATTR_CMN_SCRIPT) size += sizeof(text_encoding_t);
1974        if (a & ATTR_CMN_CRTIME) size += sizeof_timespec;
1975        if (a & ATTR_CMN_MODTIME) size += sizeof_timespec;
1976        if (a & ATTR_CMN_CHGTIME) size += sizeof_timespec;
1977        if (a & ATTR_CMN_ACCTIME) size += sizeof_timespec;
1978        if (a & ATTR_CMN_BKUPTIME) size += sizeof_timespec;
1979                if (a & ATTR_CMN_FNDRINFO) size += 32 * sizeof(u_int8_t);
1980                if (a & ATTR_CMN_OWNERID) size += sizeof(uid_t);
1981                if (a & ATTR_CMN_GRPID) size += sizeof(gid_t);
1982                if (a & ATTR_CMN_ACCESSMASK) size += sizeof(uint32_t);
1983                if (a & ATTR_CMN_NAMEDATTRCOUNT) size += sizeof(uint32_t);
1984                if (a & ATTR_CMN_NAMEDATTRLIST) size += sizeof(struct attrreference);
1985                if (a & ATTR_CMN_FLAGS) size += sizeof(uint32_t);
1986                if (a & ATTR_CMN_USERACCESS) size += sizeof(uint32_t);
1987        };
1988        if ((a = attrlist->volattr) != 0) {
1989                if (a & ATTR_VOL_FSTYPE) size += sizeof(uint32_t);
1990                if (a & ATTR_VOL_SIGNATURE) size += sizeof(uint32_t);
1991                if (a & ATTR_VOL_SIZE) size += sizeof(off_t);
1992                if (a & ATTR_VOL_SPACEFREE) size += sizeof(off_t);
1993                if (a & ATTR_VOL_SPACEAVAIL) size += sizeof(off_t);
1994                if (a & ATTR_VOL_MINALLOCATION) size += sizeof(off_t);
1995                if (a & ATTR_VOL_ALLOCATIONCLUMP) size += sizeof(off_t);
1996                if (a & ATTR_VOL_IOBLOCKSIZE) size += sizeof(uint32_t);
1997                if (a & ATTR_VOL_OBJCOUNT) size += sizeof(uint32_t);
1998                if (a & ATTR_VOL_FILECOUNT) size += sizeof(uint32_t);
1999                if (a & ATTR_VOL_DIRCOUNT) size += sizeof(uint32_t);
2000                if (a & ATTR_VOL_MAXOBJCOUNT) size += sizeof(uint32_t);
2001                if (a & ATTR_VOL_MOUNTPOINT) size += sizeof(struct attrreference);
2002                if (a & ATTR_VOL_NAME) size += sizeof(struct attrreference);
2003                if (a & ATTR_VOL_MOUNTFLAGS) size += sizeof(uint32_t);
2004                if (a & ATTR_VOL_MOUNTEDDEVICE) size += sizeof(struct attrreference);
2005                if (a & ATTR_VOL_ENCODINGSUSED) size += sizeof(unsigned long long);
2006                if (a & ATTR_VOL_CAPABILITIES) size += sizeof(vol_capabilities_attr_t);
2007                if (a & ATTR_VOL_ATTRIBUTES) size += sizeof(vol_attributes_attr_t);
2008        };
2009        if ((a = attrlist->dirattr) != 0) {
2010                if (a & ATTR_DIR_LINKCOUNT) size += sizeof(uint32_t);
2011                if (a & ATTR_DIR_ENTRYCOUNT) size += sizeof(uint32_t);
2012                if (a & ATTR_DIR_MOUNTSTATUS) size += sizeof(uint32_t);
2013        };
2014        if ((a = attrlist->fileattr) != 0) {
2015                if (a & ATTR_FILE_LINKCOUNT) size += sizeof(uint32_t);
2016                if (a & ATTR_FILE_TOTALSIZE) size += sizeof(off_t);
2017                if (a & ATTR_FILE_ALLOCSIZE) size += sizeof(off_t);
2018                if (a & ATTR_FILE_IOBLOCKSIZE) size += sizeof(uint32_t);
2019                if (a & ATTR_FILE_CLUMPSIZE) size += sizeof(uint32_t);
2020                if (a & ATTR_FILE_DEVTYPE) size += sizeof(uint32_t);
2021                if (a & ATTR_FILE_FILETYPE) size += sizeof(uint32_t);
2022                if (a & ATTR_FILE_FORKCOUNT) size += sizeof(uint32_t);
2023                if (a & ATTR_FILE_FORKLIST) size += sizeof(struct attrreference);
2024                if (a & ATTR_FILE_DATALENGTH) size += sizeof(off_t);
2025                if (a & ATTR_FILE_DATAALLOCSIZE) size += sizeof(off_t);
2026                if (a & ATTR_FILE_DATAEXTENTS) size += sizeof(extentrecord);
2027                if (a & ATTR_FILE_RSRCLENGTH) size += sizeof(off_t);
2028                if (a & ATTR_FILE_RSRCALLOCSIZE) size += sizeof(off_t);
2029                if (a & ATTR_FILE_RSRCEXTENTS) size += sizeof(extentrecord);
2030        };
2031        if ((a = attrlist->forkattr) != 0) {
2032                if (a & ATTR_FORK_TOTALSIZE) size += sizeof(off_t);
2033                if (a & ATTR_FORK_ALLOCSIZE) size += sizeof(off_t);
2034        };
2035
2036        return size;
2037}
2038
2039
2040__private_extern__
2041unsigned long
2042DerivePermissionSummary(uid_t obj_uid, gid_t obj_gid, mode_t obj_mode,
2043                struct mount *mp, kauth_cred_t cred, struct proc *p)
2044{
2045        unsigned long permissions;
2046
2047        if (obj_uid == UNKNOWNUID)
2048                obj_uid = kauth_cred_getuid(proc_ucred(p));
2049
2050        /* User id 0 (root) always gets access. */
2051        if (!suser(cred, NULL)) {
2052                permissions = R_OK | W_OK | X_OK;
2053                goto Exit;
2054        };
2055
2056        /* Otherwise, check the owner. */
2057        if (hfs_owner_rights(VFSTOHFS(mp), obj_uid, cred, p, false) == 0) {
2058                permissions = ((unsigned long)obj_mode & S_IRWXU) >> 6;
2059                goto Exit;
2060        }
2061
2062        /* Otherwise, check the groups. */
2063        if (! (((unsigned int)vfs_flags(mp)) & MNT_UNKNOWNPERMISSIONS)) {
2064                int is_member;
2065
2066                if (kauth_cred_ismember_gid(cred, obj_gid, &is_member) == 0 && is_member) {
2067                        permissions = ((unsigned long)obj_mode & S_IRWXG) >> 3;
2068                        goto Exit;
2069                }
2070        }
2071
2072        /* Otherwise, settle for 'others' access. */
2073        permissions = (unsigned long)obj_mode & S_IRWXO;
2074
2075Exit:
2076        return (permissions);    
2077}
2078
2079
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.