The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/bsd/hfs/hfs_attrlist.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

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

Cache object: 32fcd9db41dc4d08c1215c18d971c3aa


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.