#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/file.h>
#include <sys/buf.h>
#include <sys/proc.h>
#include <sys/conf.h>
#include <mach/machine/vm_types.h>
#include <sys/vnode.h>
#include <sys/malloc.h>
#include <sys/signalvar.h>
#include <sys/attr.h>
#include <sys/utfconv.h>
#include "hfs.h"
#include "hfs_dbg.h"
#include "hfs_catalog.h"
#include "hfs_attrlist.h"
#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"
struct directoryInfoSpec
{
u_long numFiles;
};
struct fileInfoSpec
{
off_t dataLogicalLength;
off_t dataPhysicalLength;
off_t resourceLogicalLength;
off_t resourcePhysicalLength;
};
struct searchinfospec
{
u_char name[kHFSPlusMaxFileNameBytes];
u_long nameLength;
char attributes; u_long nodeID;
u_long parentDirID;
struct timespec creationDate;
struct timespec modificationDate;
struct timespec changeDate;
struct timespec accessDate;
struct timespec lastBackupDate;
u_long finderInfo[8];
uid_t uid;
gid_t gid;
mode_t mask;
struct fileInfoSpec f;
struct directoryInfoSpec d;
};
typedef struct searchinfospec searchinfospec_t;
static void ResolveHardlink(ExtendedVCB *vcb, HFSPlusCatalogFile *recp);
static int UnpackSearchAttributeBlock(struct vnode *vp, struct attrlist *alist,
searchinfospec_t *searchInfo, void *attributeBuffer);
static int CheckCriteria( ExtendedVCB *vcb,
u_long searchBits,
struct attrlist *attrList,
CatalogRecord *rec,
CatalogKey *key,
searchinfospec_t *searchInfo1,
searchinfospec_t *searchInfo2,
Boolean lookForDup );
static int CheckAccess(ExtendedVCB *vcb, CatalogKey *key, struct proc *p);
static int InsertMatch(struct vnode *vp, struct uio *a_uio, CatalogRecord *rec,
CatalogKey *key, struct attrlist *returnAttrList,
void *attributesBuffer, void *variableBuffer,
u_long bufferSize, 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);
static Boolean CompareRange( u_long val, u_long low, u_long high )
{
return( (val >= low) && (val <= high) );
}
static Boolean CompareWideRange( u_int64_t val, u_int64_t low, u_int64_t high )
{
return( (val >= low) && (val <= high) );
}
#if 1 // Installer workaround (2940423)
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);
extern int resolvelink(struct hfsmount *hfsmp, u_long linkref,
struct HFSPlusCatalogFile *recp);
#define errSearchBufferFull 101
int
hfs_search( ap )
struct vop_searchfs_args *ap;
{
ExtendedVCB *vcb = VTOVCB(ap->a_vp);
FCB * catalogFCB;
searchinfospec_t searchInfo1;
searchinfospec_t searchInfo2;
void *attributesBuffer;
void *variableBuffer;
u_long fixedBlockSize;
u_long eachReturnBufferSize;
struct proc *p = current_proc();
int err = E_NONE;
int isHFSPlus;
int timerExpired = false;
int doQuickExit = false;
CatalogKey * myCurrentKeyPtr;
CatalogRecord * myCurrentDataPtr;
CatPosition * myCatPositionPtr;
BTScanState myBTScanState;
void *user_start = NULL;
int user_len;
*(ap->a_nummatches) = 0;
if (ap->a_options & ~SRCHFS_VALIDOPTIONSMASK)
return (EINVAL);
if (ap->a_uio->uio_resid <= 0)
return (EINVAL);
isHFSPlus = (vcb->vcbSigWord == kHFSPlusSigWord);
err = UnpackSearchAttributeBlock(ap->a_vp, ap->a_searchattrs,
&searchInfo1, ap->a_searchparams1);
if (err) return err;
err = UnpackSearchAttributeBlock(ap->a_vp, ap->a_searchattrs,
&searchInfo2, ap->a_searchparams2);
if (err) return err;
fixedBlockSize = sizeof(u_long) + hfs_attrblksize(ap->a_returnattrs);
eachReturnBufferSize = fixedBlockSize;
if ( ap->a_returnattrs->commonattr & ATTR_CMN_NAME )
eachReturnBufferSize += kHFSPlusMaxFileNameBytes + 1;
MALLOC( attributesBuffer, void *, eachReturnBufferSize, M_TEMP, M_WAITOK );
variableBuffer = (void*)((char*) attributesBuffer + fixedBlockSize);
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 ((err = vslock(user_start, user_len)) != 0) {
user_start = NULL;
goto ExitThisRoutine;
}
}
err = hfs_metafilelocking(VTOHFS(ap->a_vp), kHFSCatalogFileID, LK_SHARED, p);
if (err)
goto ExitThisRoutine;
catalogFCB = GetFileControlBlock(vcb->catalogRefNum);
myCurrentKeyPtr = NULL;
myCurrentDataPtr = NULL;
myCatPositionPtr = (CatPosition *)ap->a_searchstate;
if (ap->a_options & SRCHFS_START) {
(void) VOP_FSYNC(vcb->catalogRefNum, NOCRED, MNT_WAIT, p);
ap->a_options &= ~SRCHFS_START;
bzero( (caddr_t)myCatPositionPtr, sizeof( *myCatPositionPtr ) );
err = BTScanInitialize(catalogFCB, 0, 0, 0, kCatSearchBufferSize, &myBTScanState);
#if 1 // Installer workaround (2940423)
if ( err == E_NONE &&
(ap->a_searchattrs->commonattr & ATTR_CMN_NAME) != 0 &&
IsTargetName( &searchInfo1, isHFSPlus ) )
{
CatalogRecord rec;
BTreeIterator iterator;
FSBufferDescriptor btrec;
CatalogKey * keyp;
UInt16 reclen;
OSErr result;
bzero( (caddr_t)&iterator, sizeof( iterator ) );
keyp = (CatalogKey *) &iterator.key;
(void) BuildCatalogKeyUTF8(vcb, kRootDirID, "Library", kUndefinedStrLen, keyp, NULL);
btrec.bufferAddress = &rec;
btrec.itemCount = 1;
btrec.itemSize = sizeof( rec );
result = BTSearchRecord( catalogFCB, &iterator, &btrec, &reclen, &iterator );
if ( result == E_NONE ) {
if (CheckCriteria(vcb, ap->a_options, ap->a_searchattrs, &rec,
keyp, &searchInfo1, &searchInfo2, false) &&
CheckAccess(vcb, keyp, ap->a_uio->uio_procp)) {
result = InsertMatch(ap->a_vp, ap->a_uio, &rec,
keyp, ap->a_returnattrs,
attributesBuffer, variableBuffer,
eachReturnBufferSize, ap->a_nummatches);
if (result == E_NONE && *(ap->a_nummatches) >= ap->a_maxmatches)
doQuickExit = true;
}
}
}
#endif // Installer workaround
} else {
err = BTScanInitialize(catalogFCB, myCatPositionPtr->nextNode,
myCatPositionPtr->nextRecord,
myCatPositionPtr->recordsFound,
kCatSearchBufferSize,
&myBTScanState);
if (err == 0
&& myCatPositionPtr->writeCount != myBTScanState.btcb->writeCount) {
myCatPositionPtr->writeCount = myBTScanState.btcb->writeCount;
err = EBUSY;
}
}
(void) hfs_metafilelocking(VTOHFS(ap->a_vp), kHFSCatalogFileID, LK_RELEASE, p);
if (err)
goto ExitThisRoutine;
#if 1 // Installer workaround (2940423)
if ( doQuickExit )
goto QuickExit;
#endif // Installer workaround
for (;;) {
struct timeval myCurrentTime;
struct timeval myElapsedTime;
err = BTScanNextRecord(&myBTScanState, timerExpired,
(void **)&myCurrentKeyPtr, (void **)&myCurrentDataPtr,
NULL);
if (err)
break;
if (isHFSPlus)
ResolveHardlink(vcb, (HFSPlusCatalogFile *) myCurrentDataPtr);
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,
myCurrentKeyPtr, ap->a_returnattrs,
attributesBuffer, variableBuffer,
eachReturnBufferSize, ap->a_nummatches);
if (err) {
--myBTScanState.recordsFound;
--myBTScanState.recordNum;
break;
}
if (*(ap->a_nummatches) >= ap->a_maxmatches)
break;
}
myCurrentTime = time;
timersub(&myCurrentTime, &myBTScanState.startTime, &myElapsedTime);
if (myElapsedTime.tv_sec > 0
|| myElapsedTime.tv_usec >= kMaxMicroSecsInKernel) {
timerExpired = true;
}
}
QuickExit:
myCatPositionPtr->writeCount = myBTScanState.btcb->writeCount;
BTScanTerminate(&myBTScanState, &myCatPositionPtr->nextNode,
&myCatPositionPtr->nextRecord,
&myCatPositionPtr->recordsFound);
if ( err == E_NONE ) {
err = EAGAIN;
} else if ( err == errSearchBufferFull ) {
if ( *(ap->a_nummatches) > 0 )
err = EAGAIN;
else
err = ENOBUFS;
} else if ( err == btNotFound ) {
err = E_NONE;
} else if ( err == fsBTTimeOutErr ) {
err = EAGAIN;
}
ExitThisRoutine:
FREE( attributesBuffer, M_TEMP );
if (VTOHFS(ap->a_vp)->jnl && user_start) {
vsunlock(user_start, user_len, TRUE);
}
return (MacToVFSError(err));
}
static void
ResolveHardlink(ExtendedVCB *vcb, HFSPlusCatalogFile *recp)
{
if ((recp->recordType == kHFSPlusFileRecord)
&& (SWAP_BE32(recp->userInfo.fdType) == kHardLinkFileType)
&& (SWAP_BE32(recp->userInfo.fdCreator) == kHFSPlusCreator)
&& ((to_bsd_time(recp->createDate) == vcb->vcbCrDate) ||
(to_bsd_time(recp->createDate) == VCBTOHFS(vcb)->hfs_metadata_createdate))) {
(void) resolvelink(VCBTOHFS(vcb), recp->bsdInfo.special.iNodeNum, recp);
}
}
static Boolean
CompareMasked(const UInt32 *thisValue, const UInt32 *compareData,
const UInt32 *compareMask, UInt32 count)
{
Boolean matched;
UInt32 i;
matched = true;
for (i=0; i<count; i++) {
if (((*thisValue++ ^ *compareData++) & *compareMask++) != 0) {
matched = false;
break;
}
}
return matched;
}
static Boolean
ComparePartialUnicodeName (register ConstUniCharArrayPtr str, register ItemCount s_len,
register ConstUniCharArrayPtr find, register ItemCount f_len )
{
if (f_len == 0 || s_len == 0)
return FALSE;
do {
if (s_len-- < f_len)
return FALSE;
} while (FastUnicodeCompare(str++, f_len, find, f_len) != 0);
return TRUE;
}
static Boolean
ComparePartialPascalName ( register ConstStr31Param str, register ConstStr31Param find )
{
register u_char s_len = str[0];
register u_char f_len = find[0];
register u_char *tsp;
Str31 tmpstr;
if (f_len == 0 || s_len == 0)
return FALSE;
bcopy(str, tmpstr, s_len + 1);
tsp = &tmpstr[0];
while (s_len-- >= f_len) {
*tsp = f_len;
if (FastRelString(tsp++, find) == 0)
return TRUE;
}
return FALSE;
}
static int
CheckAccess(ExtendedVCB *theVCBPtr, CatalogKey *theKeyPtr, struct proc *theProcPtr)
{
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;
myResult = 0;
my_cat_desc.cd_nameptr = NULL;
my_cat_desc.cd_namelen = 0;
if ( theProcPtr->p_ucred->cr_uid == 0 ) {
myResult = 1;
goto ExitThisRoutine;
}
my_hfsmountPtr = VCBTOHFS( theVCBPtr );
isHFSPlus = ( theVCBPtr->vcbSigWord == kHFSPlusSigWord );
if ( isHFSPlus )
myNodeID = theKeyPtr->hfsPlus.parentID;
else
myNodeID = theKeyPtr->hfs.parentID;
while ( myNodeID >= kRootDirID ) {
myErr = hfs_metafilelocking( my_hfsmountPtr, kHFSCatalogFileID, LK_SHARED, theProcPtr );
if ( myErr )
goto ExitThisRoutine;
myErr = cat_idlookup( my_hfsmountPtr, myNodeID, &my_cat_desc, &my_cat_attr, NULL );
(void) hfs_metafilelocking( my_hfsmountPtr, kHFSCatalogFileID, LK_RELEASE, theProcPtr );
if ( myErr )
goto ExitThisRoutine;
myNodeID = my_cat_desc.cd_parentcnid;
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 )
goto ExitThisRoutine;
}
myResult = 1;
ExitThisRoutine:
cat_releasedesc( &my_cat_desc );
return ( myResult );
}
static int
CheckCriteria( ExtendedVCB *vcb,
u_long searchBits,
struct attrlist *attrList,
CatalogRecord *rec,
CatalogKey *key,
searchinfospec_t *searchInfo1,
searchinfospec_t *searchInfo2,
Boolean lookForDup )
{
Boolean matched, atleastone;
Boolean isHFSPlus;
attrgroup_t searchAttributes;
struct cat_attr c_attr = {0};
struct cat_fork datafork;
struct cat_fork rsrcfork;
isHFSPlus = (vcb->vcbSigWord == kHFSPlusSigWord);
switch (rec->recordType) {
case kHFSFolderRecord:
case kHFSPlusFolderRecord:
if ( (searchBits & SRCHFS_MATCHDIRS) == 0 ) {
matched = false;
goto TestDone;
}
break;
case kHFSFileRecord:
case kHFSPlusFileRecord:
if ( (searchBits & SRCHFS_MATCHFILES) == 0 ) {
matched = false;
goto TestDone;
}
break;
default:
return( false );
}
matched = true;
atleastone = false;
if ( attrList->commonattr & ATTR_CMN_NAME ) {
if (isHFSPlus) {
if ( searchBits & SRCHFS_MATCHPARTIALNAMES ) {
matched = ComparePartialUnicodeName(key->hfsPlus.nodeName.unicode,
key->hfsPlus.nodeName.length,
(UniChar*)searchInfo1->name,
searchInfo1->nameLength );
} else {
matched = (FastUnicodeCompare(key->hfsPlus.nodeName.unicode,
key->hfsPlus.nodeName.length,
(UniChar*)searchInfo1->name,
searchInfo1->nameLength ) == 0);
}
} else {
if ( searchBits & SRCHFS_MATCHPARTIALNAMES )
matched = ComparePartialPascalName(key->hfs.nodeName, (u_char*)searchInfo1->name);
else
matched = (FastRelString(key->hfs.nodeName, (u_char*)searchInfo1->name) == 0);
}
#if 1 // Installer workaround (2940423)
if ( lookForDup ) {
HFSCatalogNodeID parentID;
if (isHFSPlus)
parentID = key->hfsPlus.parentID;
else
parentID = key->hfs.parentID;
if ( matched && parentID == kRootDirID &&
IsTargetName( searchInfo1, isHFSPlus ) )
matched = false;
}
#endif // Installer workaround
if ( matched == false || (searchBits & ~SRCHFS_MATCHPARTIALNAMES) == 0 )
goto TestDone;
atleastone = true;
}
cat_convertattr(VCBTOHFS(vcb), rec, &c_attr, &datafork, &rsrcfork);
if (rec->recordType == kHFSFileRecord ||
rec->recordType == kHFSPlusFileRecord) {
if ((attrList->fileattr & ~ATTR_FILE_VALIDMASK) != 0) {
matched = false;
goto TestDone;
}
else if ((attrList->fileattr & ATTR_FILE_VALIDMASK) != 0) {
searchAttributes = attrList->fileattr;
if ( searchAttributes & ATTR_FILE_DATALENGTH ) {
matched = CompareWideRange(
datafork.cf_size,
searchInfo1->f.dataLogicalLength,
searchInfo2->f.dataLogicalLength);
if (matched == false) goto TestDone;
atleastone = true;
}
if ( searchAttributes & ATTR_FILE_DATAALLOCSIZE ) {
matched = CompareWideRange(
(u_int64_t)datafork.cf_blocks * (u_int64_t)vcb->blockSize,
searchInfo1->f.dataPhysicalLength,
searchInfo2->f.dataPhysicalLength);
if (matched == false) goto TestDone;
atleastone = true;
}
if ( searchAttributes & ATTR_FILE_RSRCLENGTH ) {
matched = CompareWideRange(
rsrcfork.cf_size,
searchInfo1->f.resourceLogicalLength,
searchInfo2->f.resourceLogicalLength);
if (matched == false) goto TestDone;
atleastone = true;
}
if ( searchAttributes & ATTR_FILE_RSRCALLOCSIZE ) {
matched = CompareWideRange(
(u_int64_t)rsrcfork.cf_blocks * (u_int64_t)vcb->blockSize,
searchInfo1->f.resourcePhysicalLength,
searchInfo2->f.resourcePhysicalLength);
if (matched == false) goto TestDone;
atleastone = true;
}
}
else {
atleastone = true;
}
}
else if (rec->recordType == kHFSFolderRecord ||
rec->recordType == kHFSPlusFolderRecord) {
if ((attrList->dirattr & ~ATTR_DIR_VALIDMASK) != 0) {
matched = false;
goto TestDone;
}
else if ((attrList->dirattr & ATTR_DIR_VALIDMASK) != 0) {
searchAttributes = attrList->dirattr;
if ( searchAttributes & ATTR_DIR_ENTRYCOUNT ) {
matched = CompareRange(c_attr.ca_entries,
searchInfo1->d.numFiles,
searchInfo2->d.numFiles );
if (matched == false) goto TestDone;
atleastone = true;
}
}
else {
atleastone = true;
}
}
searchAttributes = attrList->commonattr;
if ( (searchAttributes & ATTR_CMN_VALIDMASK) != 0 ) {
if ( searchAttributes & ATTR_CMN_OBJID ) {
matched = CompareRange(c_attr.ca_fileid,
searchInfo1->nodeID,
searchInfo2->nodeID );
if (matched == false) goto TestDone;
atleastone = true;
}
if ( searchAttributes & ATTR_CMN_PAROBJID ) {
HFSCatalogNodeID parentID;
if (isHFSPlus)
parentID = key->hfsPlus.parentID;
else
parentID = key->hfs.parentID;
matched = CompareRange(parentID, searchInfo1->parentDirID,
searchInfo2->parentDirID );
if (matched == false) goto TestDone;
atleastone = true;
}
if ( searchAttributes & ATTR_CMN_FNDRINFO ) {
UInt32 *thisValue;
thisValue = (UInt32 *) &c_attr.ca_finderinfo;
matched = CompareMasked(thisValue,
(UInt32 *)&searchInfo1->finderInfo,
(UInt32 *) &searchInfo2->finderInfo, 8);
if (matched == false) goto TestDone;
atleastone = true;
}
if ( searchAttributes & ATTR_CMN_CRTIME ) {
matched = CompareRange(c_attr.ca_itime,
searchInfo1->creationDate.tv_sec,
searchInfo2->creationDate.tv_sec);
if (matched == false) goto TestDone;
atleastone = true;
}
if ( searchAttributes & ATTR_CMN_MODTIME ) {
matched = CompareRange(c_attr.ca_mtime,
searchInfo1->modificationDate.tv_sec,
searchInfo2->modificationDate.tv_sec);
if (matched == false) goto TestDone;
atleastone = true;
}
if ( searchAttributes & ATTR_CMN_CHGTIME ) {
matched = CompareRange(c_attr.ca_ctime,
searchInfo1->changeDate.tv_sec,
searchInfo2->changeDate.tv_sec);
if (matched == false) goto TestDone;
atleastone = true;
}
if ( searchAttributes & ATTR_CMN_ACCTIME ) {
matched = CompareRange(c_attr.ca_atime,
searchInfo1->accessDate.tv_sec,
searchInfo2->accessDate.tv_sec);
if (matched == false) goto TestDone;
atleastone = true;
}
if ( searchAttributes & ATTR_CMN_BKUPTIME ) {
matched = CompareRange(c_attr.ca_btime,
searchInfo1->lastBackupDate.tv_sec,
searchInfo2->lastBackupDate.tv_sec);
if (matched == false) goto TestDone;
atleastone = true;
}
if ( searchAttributes & ATTR_CMN_OWNERID ) {
matched = CompareRange(c_attr.ca_uid,
searchInfo1->uid, searchInfo2->uid);
if (matched == false) goto TestDone;
atleastone = true;
}
if ( searchAttributes & ATTR_CMN_GRPID ) {
matched = CompareRange(c_attr.ca_gid,
searchInfo1->gid, searchInfo2->gid);
if (matched == false) goto TestDone;
atleastone = true;
}
if ( searchAttributes & ATTR_CMN_ACCESSMASK ) {
matched = CompareRange((u_long)c_attr.ca_mode,
(u_long)searchInfo1->mask,
(u_long)searchInfo2->mask);
if (matched == false) goto TestDone;
atleastone = true;
}
}
if (! atleastone)
matched = false;
TestDone:
if ( searchBits & SRCHFS_NEGATEPARAMS )
matched = !matched;
return( matched );
}
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 )
{
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;
struct attrblock attrblk;
struct cat_desc c_desc = {0};
struct cat_attr c_attr = {0};
struct cat_fork datafork;
struct cat_fork rsrcfork;
rovingAttributesBuffer = (char*)attributesBuffer + sizeof(u_long);
rovingVariableBuffer = variableBuffer;
cat_convertattr(VTOHFS(root_vp), rec, &c_attr, &datafork, &rsrcfork);
if ((privateDir != 0) && (c_attr.ca_fileid == privateDir)) {
err = 0;
goto exit;
}
if (VTOHFS(root_vp)->jnl &&
((c_attr.ca_fileid == VTOHFS(root_vp)->hfs_jnlfileid) ||
(c_attr.ca_fileid == VTOHFS(root_vp)->hfs_jnlinfoblkid))) {
err = 0;
goto exit;
}
if (returnAttrList->commonattr & ATTR_CMN_NAME) {
cat_convertkey(VTOHFS(root_vp), key, rec, &c_desc);
} else {
c_desc.cd_cnid = c_attr.ca_fileid;
if (isHFSPlus)
c_desc.cd_parentcnid = key->hfsPlus.parentID;
else
c_desc.cd_parentcnid = key->hfs.parentID;
}
if ((privateDir != 0) && (c_desc.cd_parentcnid == privateDir)) {
err = 0;
goto exit;
}
attrblk.ab_attrlist = returnAttrList;
attrblk.ab_attrbufpp = &rovingAttributesBuffer;
attrblk.ab_varbufpp = &rovingVariableBuffer;
attrblk.ab_flags = 0;
attrblk.ab_blocksize = 0;
hfs_packattrblk(&attrblk, VTOHFS(root_vp), NULL, &c_desc, &c_attr, &datafork, &rsrcfork);
packedBufferSize = (char*)rovingVariableBuffer - (char*)attributesBuffer;
if ( packedBufferSize > a_uio->uio_resid )
return( errSearchBufferFull );
(* nummatches)++;
*((u_long *)attributesBuffer) = packedBufferSize;
err = uiomove( (caddr_t)attributesBuffer, packedBufferSize, a_uio );
exit:
cat_releasedesc(&c_desc);
return( err );
}
static int
UnpackSearchAttributeBlock( struct vnode *vp, struct attrlist *alist, searchinfospec_t *searchInfo, void *attributeBuffer )
{
attrgroup_t a;
u_long bufferSize;
DBG_ASSERT(searchInfo != NULL);
bufferSize = *((u_long *)attributeBuffer);
if (bufferSize == 0)
return (EINVAL);
++((u_long *)attributeBuffer);
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;
if (len > sizeof(searchInfo->name))
return (EINVAL);
if (VTOVCB(vp)->vcbSigWord == kHFSPlusSigWord) {
size_t ucslen;
if (len > 0) {
if (utf8_decodestr(s, len-1, (UniChar*)searchInfo->name, &ucslen,
sizeof(searchInfo->name), ':', UTF_DECOMPOSED))
return (EINVAL);
searchInfo->nameLength = ucslen / sizeof(UniChar);
} else {
searchInfo->nameLength = 0;
}
++((attrreference_t *)attributeBuffer);
} else {
if (len > 0) {
if (utf8_to_hfs(VTOVCB(vp), len-1, s, (u_char*)searchInfo->name) != 0)
return (EINVAL);
searchInfo->nameLength = searchInfo->name[0];
} else {
searchInfo->name[0] = searchInfo->nameLength = 0;
}
++((attrreference_t *)attributeBuffer);
}
}
if ( a & ATTR_CMN_OBJID ) {
searchInfo->nodeID = ((fsobj_id_t *) attributeBuffer)->fid_objno;
++((fsobj_id_t *)attributeBuffer);
}
if ( a & ATTR_CMN_PAROBJID ) {
searchInfo->parentDirID = ((fsobj_id_t *) attributeBuffer)->fid_objno;
++((fsobj_id_t *)attributeBuffer);
}
if ( a & ATTR_CMN_CRTIME ) {
searchInfo->creationDate = *((struct timespec *)attributeBuffer);
++((struct timespec *)attributeBuffer);
}
if ( a & ATTR_CMN_MODTIME ) {
searchInfo->modificationDate = *((struct timespec *)attributeBuffer);
++((struct timespec *)attributeBuffer);
}
if ( a & ATTR_CMN_CHGTIME ) {
searchInfo->changeDate = *((struct timespec *)attributeBuffer);
++((struct timespec *)attributeBuffer);
}
if ( a & ATTR_CMN_ACCTIME ) {
searchInfo->accessDate = *((struct timespec *)attributeBuffer);
++((struct timespec *)attributeBuffer);
}
if ( a & ATTR_CMN_BKUPTIME ) {
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);
}
if ( a & ATTR_CMN_OWNERID ) {
searchInfo->uid = *((uid_t *)attributeBuffer);
++((uid_t *)attributeBuffer);
}
if ( a & ATTR_CMN_GRPID ) {
searchInfo->gid = *((gid_t *)attributeBuffer);
++((gid_t *)attributeBuffer);
}
if ( a & ATTR_CMN_ACCESSMASK ) {
searchInfo->mask = *((mode_t *)attributeBuffer);
++((mode_t *)attributeBuffer);
}
}
a = alist->dirattr;
if ( a != 0 ) {
if ( a & ATTR_DIR_ENTRYCOUNT ) {
searchInfo->d.numFiles = *((u_long *)attributeBuffer);
++((u_long *)attributeBuffer);
}
}
a = alist->fileattr;
if ( a != 0 ) {
if ( a & ATTR_FILE_DATALENGTH ) {
searchInfo->f.dataLogicalLength = *((off_t *)attributeBuffer);
++((off_t *)attributeBuffer);
}
if ( a & ATTR_FILE_DATAALLOCSIZE ) {
searchInfo->f.dataPhysicalLength = *((off_t *)attributeBuffer);
++((off_t *)attributeBuffer);
}
if ( a & ATTR_FILE_RSRCLENGTH ) {
searchInfo->f.resourceLogicalLength = *((off_t *)attributeBuffer);
++((off_t *)attributeBuffer);
}
if ( a & ATTR_FILE_RSRCALLOCSIZE ) {
searchInfo->f.resourcePhysicalLength = *((off_t *)attributeBuffer);
++((off_t *)attributeBuffer);
}
}
return (0);
}
#if 1 // Installer workaround (2940423)
static Boolean IsTargetName( searchinfospec_t * searchInfoPtr, Boolean isHFSPlus )
{
if ( searchInfoPtr->name == NULL )
return( false );
if (isHFSPlus) {
HFSUniStr255 myName = {
7,
{
'L','i','b','r','a','r','y'
}
};
if ( FastUnicodeCompare( myName.unicode, myName.length,
(UniChar*)searchInfoPtr->name,
searchInfoPtr->nameLength ) == 0 ) {
return( true );
}
} else {
u_char myName[32] = {
0x07,'L','i','b','r','a','r','y'
};
if ( FastRelString(myName, (u_char*)searchInfoPtr->name) == 0 ) {
return( true );
}
}
return( false );
}
#endif // Installer workaround