X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/d7e50217d7adf6e52786a38bcaa4cd698cb9a79e..8f6c56a50524aa785f7e596d52dddfb331e18961:/bsd/hfs/hfs_search.c diff --git a/bsd/hfs/hfs_search.c b/bsd/hfs/hfs_search.c index 589e04431..76f385820 100644 --- a/bsd/hfs/hfs_search.c +++ b/bsd/hfs/hfs_search.c @@ -1,16 +1,19 @@ /* - * Copyright (c) 1997-2002 Apple Computer, Inc. All rights reserved. + * Copyright (c) 1997-2004 Apple Computer, Inc. All rights reserved. * - * @APPLE_LICENSE_HEADER_START@ - * - * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. + * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. + * compliance with the License. The rights granted to you under the License + * may not be used to create, or enable the creation or redistribution of, + * unlawful or unlicensed copies of an Apple operating system, or to + * circumvent, violate, or enable the circumvention or violation of, any + * terms of an Apple operating system software license agreement. + * + * Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this file. * * The Original Code and all software distributed under the License are * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER @@ -20,7 +23,7 @@ * Please see the License for the specific language governing rights and * limitations under the License. * - * @APPLE_LICENSE_HEADER_END@ + * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ * * @(#)hfs_search.c */ @@ -29,7 +32,6 @@ #include #include #include -#include #include #include #include @@ -38,6 +40,8 @@ #include #include #include +#include +#include #include "hfs.h" #include "hfs_dbg.h" @@ -46,16 +50,15 @@ #include "hfs_endian.h" #include "hfscommon/headers/FileMgrInternal.h" -#include "hfscommon/headers/CatalogPrivate.h" #include "hfscommon/headers/HFSUnicodeWrappers.h" #include "hfscommon/headers/BTreesPrivate.h" #include "hfscommon/headers/BTreeScanner.h" - +#include "hfscommon/headers/CatalogPrivate.h" /* Search criterea. */ struct directoryInfoSpec { - u_long numFiles; + u_int32_t numFiles; }; struct fileInfoSpec @@ -78,7 +81,7 @@ struct searchinfospec struct timespec changeDate; struct timespec accessDate; struct timespec lastBackupDate; - u_long finderInfo[8]; + uint8_t finderInfo[32]; uid_t uid; gid_t gid; mode_t mask; @@ -90,7 +93,7 @@ typedef struct searchinfospec searchinfospec_t; static void ResolveHardlink(ExtendedVCB *vcb, HFSPlusCatalogFile *recp); -static int UnpackSearchAttributeBlock(struct vnode *vp, struct attrlist *alist, +static int UnpackSearchAttributeBlock(struct hfsmount *hfsmp, struct attrlist *alist, searchinfospec_t *searchInfo, void *attributeBuffer); static int CheckCriteria( ExtendedVCB *vcb, @@ -102,12 +105,12 @@ static int CheckCriteria( ExtendedVCB *vcb, searchinfospec_t *searchInfo2, Boolean lookForDup ); -static int CheckAccess(ExtendedVCB *vcb, CatalogKey *key, struct proc *p); +static int CheckAccess(ExtendedVCB *vcb, u_long searchBits, CatalogKey *key, struct vfs_context *ctx); -static int InsertMatch(struct vnode *vp, struct uio *a_uio, CatalogRecord *rec, +static int InsertMatch(struct hfsmount *hfsmp, uio_t a_uio, CatalogRecord *rec, CatalogKey *key, struct attrlist *returnAttrList, void *attributesBuffer, void *variableBuffer, - u_long bufferSize, u_long * nummatches ); + u_long * nummatches ); static Boolean CompareRange(u_long val, u_long low, u_long high); static Boolean CompareWideRange(u_int64_t val, u_int64_t low, u_int64_t high); @@ -127,21 +130,8 @@ static Boolean CompareWideRange( u_int64_t val, u_int64_t low, u_int64_t high ) static Boolean IsTargetName( searchinfospec_t * searchInfoPtr, Boolean isHFSPlus ); #endif // Installer workaround -extern int cat_convertkey( - struct hfsmount *hfsmp, - CatalogKey *key, - CatalogRecord * recp, - struct cat_desc *descp); - -extern void cat_convertattr( - struct hfsmount *hfsmp, - CatalogRecord * recp, - struct cat_attr *attrp, - struct cat_fork *datafp, - struct cat_fork *rsrcfp); +__private_extern__ int hfs_vnop_search(struct vnop_searchfs_args *ap); -extern int resolvelink(struct hfsmount *hfsmp, u_long linkref, - struct HFSPlusCatalogFile *recp); /************************************************************************/ /* Entry for searchfs() */ @@ -152,18 +142,19 @@ extern int resolvelink(struct hfsmount *hfsmp, u_long linkref, # #% searchfs vp L L L # -vop_searchfs { +vnop_searchfs { IN struct vnode *vp; IN off_t length; IN int flags; - IN struct ucred *cred; + IN kauth_cred_t cred; IN struct proc *p; }; */ +__private_extern__ int -hfs_search( ap ) - struct vop_searchfs_args *ap; /* +hfs_vnop_search(ap) + struct vnop_searchfs_args *ap; /* struct vnodeop_desc *a_desc; struct vnode *a_vp; void *a_searchparams1; @@ -177,9 +168,11 @@ hfs_search( ap ) u_long a_options; struct uio *a_uio; struct searchstate *a_searchstate; + vfs_context_t a_context; */ { ExtendedVCB *vcb = VTOVCB(ap->a_vp); + struct hfsmount *hfsmp; FCB * catalogFCB; searchinfospec_t searchInfo1; searchinfospec_t searchInfo2; @@ -187,7 +180,7 @@ hfs_search( ap ) void *variableBuffer; u_long fixedBlockSize; u_long eachReturnBufferSize; - struct proc *p = current_proc(); + struct proc *p = proc_self(); int err = E_NONE; int isHFSPlus; int timerExpired = false; @@ -196,8 +189,10 @@ hfs_search( ap ) CatalogRecord * myCurrentDataPtr; CatPosition * myCatPositionPtr; BTScanState myBTScanState; - void *user_start = NULL; - int user_len; + user_addr_t user_start = 0; + user_size_t user_len = 0; + int32_t searchTime; + int lockflags; /* XXX Parameter check a_searchattrs? */ @@ -206,20 +201,44 @@ hfs_search( ap ) if (ap->a_options & ~SRCHFS_VALIDOPTIONSMASK) return (EINVAL); - if (ap->a_uio->uio_resid <= 0) + /* SRCHFS_SKIPLINKS requires root access. + * This option cannot be used with either + * the ATTR_CMN_NAME or ATTR_CMN_PAROBJID + * attributes. + */ + if (ap->a_options & SRCHFS_SKIPLINKS) { + attrgroup_t attrs; + + attrs = ap->a_searchattrs->commonattr | ap->a_returnattrs->commonattr; + if (attrs & (ATTR_CMN_NAME | ATTR_CMN_PAROBJID)) + return (EINVAL); + if ((err = vfs_context_suser(ap->a_context))) + return (err); + } + + if (uio_resid(ap->a_uio) <= 0) return (EINVAL); isHFSPlus = (vcb->vcbSigWord == kHFSPlusSigWord); + hfsmp = VTOHFS(ap->a_vp); + + searchTime = kMaxMicroSecsInKernel; + if (ap->a_timelimit->tv_sec == 0 && + ap->a_timelimit->tv_usec > 0 && + ap->a_timelimit->tv_usec < kMaxMicroSecsInKernel) { + searchTime = ap->a_timelimit->tv_usec; + } /* UnPack the search boundries, searchInfo1, searchInfo2 */ - err = UnpackSearchAttributeBlock(ap->a_vp, ap->a_searchattrs, + err = UnpackSearchAttributeBlock(hfsmp, ap->a_searchattrs, &searchInfo1, ap->a_searchparams1); if (err) return err; - err = UnpackSearchAttributeBlock(ap->a_vp, ap->a_searchattrs, + err = UnpackSearchAttributeBlock(hfsmp, ap->a_searchattrs, &searchInfo2, ap->a_searchparams2); if (err) return err; - fixedBlockSize = sizeof(u_long) + hfs_attrblksize(ap->a_returnattrs); /* u_long for length longword */ + fixedBlockSize = sizeof(uint32_t) + hfs_attrblksize(ap->a_returnattrs); /* uint32_t for length word */ + eachReturnBufferSize = fixedBlockSize; if ( ap->a_returnattrs->commonattr & ATTR_CMN_NAME ) /* XXX should be more robust! */ @@ -232,20 +251,17 @@ hfs_search( ap ) // while holding the shared catalog file lock. see the comment // in hfs_readdir() for more details. // - if (VTOHFS(ap->a_vp)->jnl && ap->a_uio->uio_segflg == UIO_USERSPACE) { - user_start = ap->a_uio->uio_iov->iov_base; - user_len = ap->a_uio->uio_iov->iov_len; + if (hfsmp->jnl && uio_isuserspace(ap->a_uio)) { + user_start = uio_curriovbase(ap->a_uio); + user_len = uio_curriovlen(ap->a_uio); if ((err = vslock(user_start, user_len)) != 0) { - user_start = NULL; + user_start = 0; goto ExitThisRoutine; } } - /* Lock catalog b-tree */ - err = hfs_metafilelocking(VTOHFS(ap->a_vp), kHFSCatalogFileID, LK_SHARED, p); - if (err) - goto ExitThisRoutine; + lockflags = hfs_systemfile_lock(hfsmp, SFL_CATALOG, HFS_SHARED_LOCK); catalogFCB = GetFileControlBlock(vcb->catalogRefNum); myCurrentKeyPtr = NULL; @@ -255,7 +271,13 @@ hfs_search( ap ) if (ap->a_options & SRCHFS_START) { /* Starting a new search. */ /* Make sure the on-disk Catalog file is current */ - (void) VOP_FSYNC(vcb->catalogRefNum, NOCRED, MNT_WAIT, p); + (void) hfs_fsync(vcb->catalogRefNum, MNT_WAIT, 0, p); + if (hfsmp->jnl) { + hfs_systemfile_unlock(hfsmp, lockflags); + journal_flush(hfsmp->jnl); + lockflags = hfs_systemfile_lock(hfsmp, SFL_CATALOG, HFS_SHARED_LOCK); + } + ap->a_options &= ~SRCHFS_START; bzero( (caddr_t)myCatPositionPtr, sizeof( *myCatPositionPtr ) ); err = BTScanInitialize(catalogFCB, 0, 0, 0, kCatSearchBufferSize, &myBTScanState); @@ -287,17 +309,20 @@ hfs_search( ap ) result = BTSearchRecord( catalogFCB, &iterator, &btrec, &reclen, &iterator ); if ( result == E_NONE ) { + // need to unlock since CheckAccess assumes no lock held + hfs_systemfile_unlock(hfsmp, lockflags); if (CheckCriteria(vcb, ap->a_options, ap->a_searchattrs, &rec, keyp, &searchInfo1, &searchInfo2, false) && - CheckAccess(vcb, keyp, ap->a_uio->uio_procp)) { + CheckAccess(vcb, ap->a_options, keyp, ap->a_context)) { - result = InsertMatch(ap->a_vp, ap->a_uio, &rec, + result = InsertMatch(hfsmp, ap->a_uio, &rec, keyp, ap->a_returnattrs, attributesBuffer, variableBuffer, - eachReturnBufferSize, ap->a_nummatches); + ap->a_nummatches); if (result == E_NONE && *(ap->a_nummatches) >= ap->a_maxmatches) doQuickExit = true; } + lockflags = hfs_systemfile_lock(hfsmp, SFL_CATALOG, HFS_SHARED_LOCK); } } #endif // Installer workaround @@ -315,9 +340,8 @@ hfs_search( ap ) err = EBUSY; /* catChangedErr */ } } + hfs_systemfile_unlock(hfsmp, lockflags); - /* Unlock catalog b-tree */ - (void) hfs_metafilelocking(VTOHFS(ap->a_vp), kHFSCatalogFileID, LK_RELEASE, p); if (err) goto ExitThisRoutine; #if 1 // Installer workaround (2940423) @@ -340,16 +364,17 @@ hfs_search( ap ) break; /* Resolve any hardlinks */ - if (isHFSPlus) + if (isHFSPlus && (ap->a_options & SRCHFS_SKIPLINKS) == 0) { + lockflags = hfs_systemfile_lock(hfsmp, SFL_CATALOG, HFS_SHARED_LOCK); ResolveHardlink(vcb, (HFSPlusCatalogFile *) myCurrentDataPtr); - + hfs_systemfile_unlock(hfsmp, lockflags); + } if (CheckCriteria( vcb, ap->a_options, ap->a_searchattrs, myCurrentDataPtr, myCurrentKeyPtr, &searchInfo1, &searchInfo2, true ) - && CheckAccess(vcb, myCurrentKeyPtr, ap->a_uio->uio_procp)) { - err = InsertMatch(ap->a_vp, ap->a_uio, myCurrentDataPtr, + && CheckAccess(vcb, ap->a_options, myCurrentKeyPtr, ap->a_context)) { + err = InsertMatch(hfsmp, ap->a_uio, myCurrentDataPtr, myCurrentKeyPtr, ap->a_returnattrs, - attributesBuffer, variableBuffer, - eachReturnBufferSize, ap->a_nummatches); + attributesBuffer, variableBuffer, ap->a_nummatches); if (err) { /* * The last match didn't fit so come back @@ -369,11 +394,11 @@ hfs_search( ap ) * The idea here is to throttle the amount of time we * spend in the kernel. */ - myCurrentTime = time; + microuptime(&myCurrentTime); timersub(&myCurrentTime, &myBTScanState.startTime, &myElapsedTime); /* Note: assumes kMaxMicroSecsInKernel is less than 1,000,000 */ if (myElapsedTime.tv_sec > 0 - || myElapsedTime.tv_usec >= kMaxMicroSecsInKernel) { + || myElapsedTime.tv_usec >= searchTime) { timerExpired = true; } } @@ -400,9 +425,9 @@ QuickExit: } ExitThisRoutine: - FREE( attributesBuffer, M_TEMP ); + FREE( attributesBuffer, M_TEMP ); - if (VTOHFS(ap->a_vp)->jnl && user_start) { + if (hfsmp->jnl && user_start) { vsunlock(user_start, user_len, TRUE); } @@ -418,7 +443,12 @@ ResolveHardlink(ExtendedVCB *vcb, HFSPlusCatalogFile *recp) && (SWAP_BE32(recp->userInfo.fdCreator) == kHFSPlusCreator) && ((to_bsd_time(recp->createDate) == vcb->vcbCrDate) || (to_bsd_time(recp->createDate) == VCBTOHFS(vcb)->hfs_metadata_createdate))) { + cnid_t saved_cnid; + + /* Export link's cnid (a unique value) instead of inode's cnid */ + saved_cnid = recp->fileID; (void) resolvelink(VCBTOHFS(vcb), recp->bsdInfo.special.iNodeNum, recp); + recp->fileID = saved_cnid; } } @@ -484,32 +514,53 @@ ComparePartialPascalName ( register ConstStr31Param str, register ConstStr31Para } +// +// Determine if a name is "inappropriate" where the definition +// of "inappropriate" is up to higher level execs. Currently +// that's limited to /System. +// +static int +is_inappropriate_name(char *name, int len) +{ + const char *bad_names[] = { "System" }; + int bad_len[] = { 6 }; + int i; + + for(i=0; i < (int) (sizeof(bad_names) / sizeof(bad_names[0])); i++) { + if (len == bad_len[i] && strcmp(name, bad_names[i]) == 0) { + return 1; + } + } + + // if we get here, no name matched + return 0; +} + + + /* * Check to see if caller has access rights to this item */ static int -CheckAccess(ExtendedVCB *theVCBPtr, CatalogKey *theKeyPtr, struct proc *theProcPtr) +CheckAccess(ExtendedVCB *theVCBPtr, u_long searchBits, CatalogKey *theKeyPtr, struct vfs_context *ctx) { - Boolean isHFSPlus; - int myErr; - int myResult; + Boolean isHFSPlus; + int myErr; + int myResult; HFSCatalogNodeID myNodeID; - unsigned long myPerms; - hfsmount_t * my_hfsmountPtr; - struct cat_desc my_cat_desc; - struct cat_attr my_cat_attr; - + hfsmount_t * hfsmp; + struct FndrDirInfo *finfop; + struct vnode * vp = NULL; + myResult = 0; /* default to "no access" */ - my_cat_desc.cd_nameptr = NULL; - my_cat_desc.cd_namelen = 0; - if ( theProcPtr->p_ucred->cr_uid == 0 ) { + if (!vfs_context_suser(ctx)) { myResult = 1; /* allow access */ goto ExitThisRoutine; /* root always has access */ } - my_hfsmountPtr = VCBTOHFS( theVCBPtr ); + hfsmp = VCBTOHFS( theVCBPtr ); isHFSPlus = ( theVCBPtr->vcbSigWord == kHFSPlusSigWord ); if ( isHFSPlus ) myNodeID = theKeyPtr->hfsPlus.parentID; @@ -517,30 +568,60 @@ CheckAccess(ExtendedVCB *theVCBPtr, CatalogKey *theKeyPtr, struct proc *theProcP myNodeID = theKeyPtr->hfs.parentID; while ( myNodeID >= kRootDirID ) { + cnode_t * cp; + /* now go get catalog data for this directory */ - myErr = hfs_metafilelocking( my_hfsmountPtr, kHFSCatalogFileID, LK_SHARED, theProcPtr ); - if ( myErr ) - goto ExitThisRoutine; /* no access */ - - myErr = cat_idlookup( my_hfsmountPtr, myNodeID, &my_cat_desc, &my_cat_attr, NULL ); - (void) hfs_metafilelocking( my_hfsmountPtr, kHFSCatalogFileID, LK_RELEASE, theProcPtr ); - if ( myErr ) + myErr = hfs_vget(hfsmp, myNodeID, &vp, 0); + if ( myErr ) { goto ExitThisRoutine; /* no access */ + } - myNodeID = my_cat_desc.cd_parentcnid; /* move up the hierarchy */ - myPerms = DerivePermissionSummary(my_cat_attr.ca_uid, my_cat_attr.ca_gid, - my_cat_attr.ca_mode, my_hfsmountPtr->hfs_mp, - theProcPtr->p_ucred, theProcPtr ); - cat_releasedesc( &my_cat_desc ); - - if ( (myPerms & X_OK) == 0 ) + cp = VTOC(vp); + finfop = (struct FndrDirInfo *)&cp->c_attr.ca_finderinfo[0]; + + if ( searchBits & SRCHFS_SKIPPACKAGES ) { + if ( (SWAP_BE16(finfop->frFlags) & kHasBundle) + || (cp->c_desc.cd_nameptr != NULL + && is_package_name(cp->c_desc.cd_nameptr, cp->c_desc.cd_namelen)) ) { + myResult = 0; + goto ExitThisRoutine; + } + } + + if ( searchBits & SRCHFS_SKIPINAPPROPRIATE ) { + if ( cp->c_parentcnid == kRootDirID && cp->c_desc.cd_nameptr != NULL && + is_inappropriate_name(cp->c_desc.cd_nameptr, cp->c_desc.cd_namelen) ) { + myResult = 0; + goto ExitThisRoutine; + } + } + + if ( (searchBits & SRCHFS_SKIPINVISIBLE) && + (SWAP_BE16(finfop->frFlags) & kIsInvisible) ) { + myResult = 0; + goto ExitThisRoutine; + } + + myNodeID = cp->c_parentcnid; /* move up the hierarchy */ + hfs_unlock(VTOC(vp)); + if (vp->v_type == VDIR) { + myErr = vnode_authorize(vp, NULL, (KAUTH_VNODE_SEARCH | KAUTH_VNODE_LIST_DIRECTORY), ctx); + } else { + myErr = vnode_authorize(vp, NULL, (KAUTH_VNODE_SEARCH), ctx); + } + vnode_put(vp); + vp = NULL; + if ( myErr ) { goto ExitThisRoutine; /* no access */ + } } - myResult = 1; /* allow access */ ExitThisRoutine: - cat_releasedesc( &my_cat_desc ); + if ( vp != NULL ) { + hfs_unlock(VTOC(vp)); + vnode_put(vp); + } return ( myResult ); } @@ -558,10 +639,11 @@ CheckCriteria( ExtendedVCB *vcb, Boolean matched, atleastone; Boolean isHFSPlus; attrgroup_t searchAttributes; - struct cat_attr c_attr = {0}; + struct cat_attr c_attr; struct cat_fork datafork; struct cat_fork rsrcfork; + bzero(&c_attr, sizeof(c_attr)); isHFSPlus = (vcb->vcbSigWord == kHFSPlusSigWord); switch (rec->recordType) { @@ -574,7 +656,29 @@ CheckCriteria( ExtendedVCB *vcb, break; case kHFSFileRecord: + if ( (searchBits & SRCHFS_MATCHFILES) == 0 ) { /* If we are NOT searching files */ + matched = false; + goto TestDone; + } + break; + case kHFSPlusFileRecord: + /* Check if hardlink links should be skipped. */ + if (searchBits & SRCHFS_SKIPLINKS) { + cnid_t parid = key->hfsPlus.parentID; + HFSPlusCatalogFile *filep = (HFSPlusCatalogFile *)rec; + + if ((SWAP_BE32(filep->userInfo.fdType) == kHardLinkFileType) && + (SWAP_BE32(filep->userInfo.fdCreator) == kHFSPlusCreator)) { + return (false); /* skip over link records */ + } else if ((parid == VCBTOHFS(vcb)->hfs_privdir_desc.cd_cnid) && + (filep->bsdInfo.special.linkCount == 0)) { + return (false); /* skip over unlinked files */ + } + } else if (key->hfsPlus.parentID == VCBTOHFS(vcb)->hfs_privdir_desc.cd_cnid) { + return (false); /* skip over private files */ + } + if ( (searchBits & SRCHFS_MATCHFILES) == 0 ) { /* If we are NOT searching files */ matched = false; goto TestDone; @@ -636,6 +740,42 @@ CheckCriteria( ExtendedVCB *vcb, /* Convert catalog record into cat_attr format. */ cat_convertattr(VCBTOHFS(vcb), rec, &c_attr, &datafork, &rsrcfork); + if (searchBits & SRCHFS_SKIPINVISIBLE) { + int flags; + + switch (rec->recordType) { + case kHFSFolderRecord: + case kHFSPlusFolderRecord: { + struct FndrDirInfo *finder_info; + + finder_info = (struct FndrDirInfo *)&c_attr.ca_finderinfo[0]; + flags = SWAP_BE16(finder_info->frFlags); + break; + } + + case kHFSFileRecord: + case kHFSPlusFileRecord: { + struct FndrFileInfo *finder_info; + + finder_info = (struct FndrFileInfo *)&c_attr.ca_finderinfo[0]; + flags = SWAP_BE16(finder_info->fdFlags); + break; + } + + default: { + flags = kIsInvisible; + break; + } + } + + if (flags & kIsInvisible) { + matched = false; + goto TestDone; + } + } + + + /* Now that we have a record worth searching, see if it matches the search attributes */ if (rec->recordType == kHFSFileRecord || rec->recordType == kHFSPlusFileRecord) { @@ -824,9 +964,9 @@ CheckCriteria( ExtendedVCB *vcb, /* mode */ if ( searchAttributes & ATTR_CMN_ACCESSMASK ) { - matched = CompareRange((u_long)c_attr.ca_mode, - (u_long)searchInfo1->mask, - (u_long)searchInfo2->mask); + matched = CompareRange((uint32_t)c_attr.ca_mode, + (uint32_t)searchInfo1->mask, + (uint32_t)searchInfo2->mask); if (matched == false) goto TestDone; atleastone = true; } @@ -852,28 +992,28 @@ TestDone: * Adds another record to the packed array for output */ static int -InsertMatch( struct vnode *root_vp, struct uio *a_uio, CatalogRecord *rec, - CatalogKey *key, struct attrlist *returnAttrList, void *attributesBuffer, - void *variableBuffer, u_long bufferSize, u_long * nummatches ) +InsertMatch(struct hfsmount *hfsmp, uio_t a_uio, CatalogRecord *rec, + CatalogKey *key, struct attrlist *returnAttrList, + void *attributesBuffer, void *variableBuffer, u_long * nummatches) { int err; void *rovingAttributesBuffer; void *rovingVariableBuffer; u_long packedBufferSize; - ExtendedVCB *vcb = VTOVCB(root_vp); - Boolean isHFSPlus = vcb->vcbSigWord == kHFSPlusSigWord; - u_long privateDir = VTOHFS(root_vp)->hfs_private_metadata_dir; + u_long privateDir = hfsmp->hfs_privdir_desc.cd_cnid; struct attrblock attrblk; - struct cat_desc c_desc = {0}; - struct cat_attr c_attr = {0}; + struct cat_desc c_desc; + struct cat_attr c_attr; struct cat_fork datafork; struct cat_fork rsrcfork; + bzero(&c_desc, sizeof(c_desc)); + bzero(&c_attr, sizeof(c_attr)); rovingAttributesBuffer = (char*)attributesBuffer + sizeof(u_long); /* Reserve space for length field */ rovingVariableBuffer = variableBuffer; /* Convert catalog record into cat_attr format. */ - cat_convertattr(VTOHFS(root_vp), rec, &c_attr, &datafork, &rsrcfork); + cat_convertattr(hfsmp, rec, &c_attr, &datafork, &rsrcfork); /* hide our private meta data directory */ if ((privateDir != 0) && (c_attr.ca_fileid == privateDir)) { @@ -882,27 +1022,21 @@ InsertMatch( struct vnode *root_vp, struct uio *a_uio, CatalogRecord *rec, } /* Hide the private journal files */ - if (VTOHFS(root_vp)->jnl && - ((c_attr.ca_fileid == VTOHFS(root_vp)->hfs_jnlfileid) || - (c_attr.ca_fileid == VTOHFS(root_vp)->hfs_jnlinfoblkid))) { + if (hfsmp->jnl && + ((c_attr.ca_fileid == hfsmp->hfs_jnlfileid) || + (c_attr.ca_fileid == hfsmp->hfs_jnlinfoblkid))) { err = 0; goto exit; } if (returnAttrList->commonattr & ATTR_CMN_NAME) { - cat_convertkey(VTOHFS(root_vp), key, rec, &c_desc); + cat_convertkey(hfsmp, key, rec, &c_desc); } else { c_desc.cd_cnid = c_attr.ca_fileid; - if (isHFSPlus) - c_desc.cd_parentcnid = key->hfsPlus.parentID; - else + if (hfsmp->hfs_flags & HFS_STANDARD) c_desc.cd_parentcnid = key->hfs.parentID; - } - - /* hide open files that have been deleted */ - if ((privateDir != 0) && (c_desc.cd_parentcnid == privateDir)) { - err = 0; - goto exit; + else + c_desc.cd_parentcnid = key->hfsPlus.parentID; } attrblk.ab_attrlist = returnAttrList; @@ -911,11 +1045,11 @@ InsertMatch( struct vnode *root_vp, struct uio *a_uio, CatalogRecord *rec, attrblk.ab_flags = 0; attrblk.ab_blocksize = 0; - hfs_packattrblk(&attrblk, VTOHFS(root_vp), NULL, &c_desc, &c_attr, &datafork, &rsrcfork); + hfs_packattrblk(&attrblk, hfsmp, NULL, &c_desc, &c_attr, &datafork, &rsrcfork, current_proc()); packedBufferSize = (char*)rovingVariableBuffer - (char*)attributesBuffer; - if ( packedBufferSize > a_uio->uio_resid ) + if ( packedBufferSize > uio_resid(a_uio) ) return( errSearchBufferFull ); (* nummatches)++; @@ -931,18 +1065,21 @@ exit: static int -UnpackSearchAttributeBlock( struct vnode *vp, struct attrlist *alist, searchinfospec_t *searchInfo, void *attributeBuffer ) +UnpackSearchAttributeBlock( struct hfsmount *hfsmp, struct attrlist *alist, searchinfospec_t *searchInfo, void *attributeBuffer ) { attrgroup_t a; u_long bufferSize; + boolean_t is_64_bit; DBG_ASSERT(searchInfo != NULL); + + is_64_bit = proc_is64bit(current_proc()); - bufferSize = *((u_long *)attributeBuffer); + bufferSize = *((uint32_t *)attributeBuffer); if (bufferSize == 0) return (EINVAL); /* XXX -DJB is a buffer size of zero ever valid for searchfs? */ - ++((u_long *)attributeBuffer); /* advance past the size */ + ++((uint32_t *)attributeBuffer); /* advance past the size */ /* * UnPack common attributes @@ -950,39 +1087,41 @@ UnpackSearchAttributeBlock( struct vnode *vp, struct attrlist *alist, searchinfo a = alist->commonattr; if ( a != 0 ) { if ( a & ATTR_CMN_NAME ) { - char *s = (char*) attributeBuffer + ((attrreference_t *) attributeBuffer)->attr_dataoffset; - size_t len = ((attrreference_t *) attributeBuffer)->attr_length; + char *s; + u_int32_t len; + + s = (char*) attributeBuffer + ((attrreference_t *) attributeBuffer)->attr_dataoffset; + len = ((attrreference_t *) attributeBuffer)->attr_length; if (len > sizeof(searchInfo->name)) return (EINVAL); - if (VTOVCB(vp)->vcbSigWord == kHFSPlusSigWord) { - size_t ucslen; - /* Convert name to Unicode to match HFS Plus B-Tree names */ + if (hfsmp->hfs_flags & HFS_STANDARD) { + /* Convert name to pascal string to match HFS B-Tree names */ if (len > 0) { - if (utf8_decodestr(s, len-1, (UniChar*)searchInfo->name, &ucslen, - sizeof(searchInfo->name), ':', UTF_DECOMPOSED)) + if (utf8_to_hfs(HFSTOVCB(hfsmp), len-1, s, (u_char*)searchInfo->name) != 0) return (EINVAL); - searchInfo->nameLength = ucslen / sizeof(UniChar); + searchInfo->nameLength = searchInfo->name[0]; } else { - searchInfo->nameLength = 0; + searchInfo->name[0] = searchInfo->nameLength = 0; } - ++((attrreference_t *)attributeBuffer); - + ++((attrreference_t *)attributeBuffer); } else { - /* Convert name to pascal string to match HFS B-Tree names */ + size_t ucslen; + /* Convert name to Unicode to match HFS Plus B-Tree names */ if (len > 0) { - if (utf8_to_hfs(VTOVCB(vp), len-1, s, (u_char*)searchInfo->name) != 0) + if (utf8_decodestr(s, len-1, (UniChar*)searchInfo->name, &ucslen, + sizeof(searchInfo->name), ':', UTF_DECOMPOSED)) return (EINVAL); - searchInfo->nameLength = searchInfo->name[0]; + searchInfo->nameLength = ucslen / sizeof(UniChar); } else { - searchInfo->name[0] = searchInfo->nameLength = 0; + searchInfo->nameLength = 0; } - ++((attrreference_t *)attributeBuffer); + ++((attrreference_t *)attributeBuffer); } } if ( a & ATTR_CMN_OBJID ) { @@ -994,32 +1133,73 @@ UnpackSearchAttributeBlock( struct vnode *vp, struct attrlist *alist, searchinfo ++((fsobj_id_t *)attributeBuffer); } if ( a & ATTR_CMN_CRTIME ) { - searchInfo->creationDate = *((struct timespec *)attributeBuffer); - ++((struct timespec *)attributeBuffer); + if (is_64_bit) { + struct user_timespec tmp; + tmp = *((struct user_timespec *)attributeBuffer); + searchInfo->creationDate.tv_sec = (time_t)tmp.tv_sec; + searchInfo->creationDate.tv_nsec = tmp.tv_nsec; + ++((struct user_timespec *)attributeBuffer); + } + else { + searchInfo->creationDate = *((struct timespec *)attributeBuffer); + ++((struct timespec *)attributeBuffer); + } } if ( a & ATTR_CMN_MODTIME ) { - searchInfo->modificationDate = *((struct timespec *)attributeBuffer); - ++((struct timespec *)attributeBuffer); + if (is_64_bit) { + struct user_timespec tmp; + tmp = *((struct user_timespec *)attributeBuffer); + searchInfo->modificationDate.tv_sec = (time_t)tmp.tv_sec; + searchInfo->modificationDate.tv_nsec = tmp.tv_nsec; + ++((struct user_timespec *)attributeBuffer); + } + else { + searchInfo->modificationDate = *((struct timespec *)attributeBuffer); + ++((struct timespec *)attributeBuffer); + } } if ( a & ATTR_CMN_CHGTIME ) { - searchInfo->changeDate = *((struct timespec *)attributeBuffer); - ++((struct timespec *)attributeBuffer); + if (is_64_bit) { + struct user_timespec tmp; + tmp = *((struct user_timespec *)attributeBuffer); + searchInfo->changeDate.tv_sec = (time_t)tmp.tv_sec; + searchInfo->changeDate.tv_nsec = tmp.tv_nsec; + ++((struct user_timespec *)attributeBuffer); + } + else { + searchInfo->changeDate = *((struct timespec *)attributeBuffer); + ++((struct timespec *)attributeBuffer); + } } if ( a & ATTR_CMN_ACCTIME ) { - searchInfo->accessDate = *((struct timespec *)attributeBuffer); - ++((struct timespec *)attributeBuffer); + if (is_64_bit) { + struct user_timespec tmp; + tmp = *((struct user_timespec *)attributeBuffer); + searchInfo->accessDate.tv_sec = (time_t)tmp.tv_sec; + searchInfo->accessDate.tv_nsec = tmp.tv_nsec; + ++((struct user_timespec *)attributeBuffer); + } + else { + searchInfo->accessDate = *((struct timespec *)attributeBuffer); + ++((struct timespec *)attributeBuffer); + } } if ( a & ATTR_CMN_BKUPTIME ) { - searchInfo->lastBackupDate = *((struct timespec *)attributeBuffer); - ++((struct timespec *)attributeBuffer); + if (is_64_bit) { + struct user_timespec tmp; + tmp = *((struct user_timespec *)attributeBuffer); + searchInfo->lastBackupDate.tv_sec = (time_t)tmp.tv_sec; + searchInfo->lastBackupDate.tv_nsec = tmp.tv_nsec; + ++((struct user_timespec *)attributeBuffer); + } + else { + searchInfo->lastBackupDate = *((struct timespec *)attributeBuffer); + ++((struct timespec *)attributeBuffer); + } } if ( a & ATTR_CMN_FNDRINFO ) { - bcopy( attributeBuffer, searchInfo->finderInfo, sizeof(u_long) * 8 ); - (u_long *)attributeBuffer += 8; - } - if ( a & ATTR_CMN_BKUPTIME ) { - searchInfo->lastBackupDate = *((struct timespec *)attributeBuffer); - ++((struct timespec *)attributeBuffer); + bcopy( attributeBuffer, searchInfo->finderInfo, sizeof(searchInfo->finderInfo) ); + (uint8_t *)attributeBuffer += 32; } if ( a & ATTR_CMN_OWNERID ) { searchInfo->uid = *((uid_t *)attributeBuffer); @@ -1038,8 +1218,8 @@ UnpackSearchAttributeBlock( struct vnode *vp, struct attrlist *alist, searchinfo a = alist->dirattr; if ( a != 0 ) { if ( a & ATTR_DIR_ENTRYCOUNT ) { - searchInfo->d.numFiles = *((u_long *)attributeBuffer); - ++((u_long *)attributeBuffer); + searchInfo->d.numFiles = *((u_int32_t *)attributeBuffer); + ++((u_int32_t *)attributeBuffer); } }