You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1492 lines
40 KiB
1492 lines
40 KiB
/*
|
|
|
|
Copyright (c) 1992 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
fdparm.c
|
|
|
|
Abstract:
|
|
|
|
This module contains the routines for handling file parameters.
|
|
|
|
Author:
|
|
|
|
Jameel Hyder (microsoft!jameelh)
|
|
|
|
|
|
Revision History:
|
|
25 Apr 1992 Initial Version
|
|
|
|
Notes: Tab stop: 4
|
|
--*/
|
|
|
|
#define _FDPARM_LOCALS
|
|
#define FILENUM FILE_FDPARM
|
|
|
|
#include <seposix.h>
|
|
#include <afp.h>
|
|
#include <fdparm.h>
|
|
#include <pathmap.h>
|
|
#include <afpinfo.h>
|
|
#include <client.h>
|
|
#include <access.h>
|
|
|
|
#ifdef ALLOC_PRAGMA
|
|
#pragma alloc_text( PAGE, AfpGetFileDirParmsReplyLength)
|
|
#pragma alloc_text( PAGE, AfpPackFileDirParms)
|
|
#pragma alloc_text( PAGE, AfpUnpackFileDirParms)
|
|
#pragma alloc_text( PAGE, AfpUnpackCatSearchSpecs)
|
|
#pragma alloc_text( PAGE, AfpSetFileDirParms)
|
|
#pragma alloc_text( PAGE, AfpQuerySecurityIdsAndRights)
|
|
#pragma alloc_text( PAGE, AfpConvertNTAttrToAfpAttr)
|
|
#pragma alloc_text( PAGE, AfpConvertAfpAttrToNTAttr)
|
|
#pragma alloc_text( PAGE, AfpNormalizeAfpAttr)
|
|
#pragma alloc_text( PAGE, AfpMapFDBitmapOpenAccess)
|
|
#pragma alloc_text( PAGE, AfpCheckForInhibit)
|
|
#pragma alloc_text( PAGE, AfpIsCatSearchMatch)
|
|
#endif
|
|
|
|
|
|
/*** AfpGetFileDirParmsReplyLength
|
|
*
|
|
* Compute the size of buffer required to copy the file parameters based
|
|
* on the bitmap.
|
|
*/
|
|
USHORT
|
|
AfpGetFileDirParmsReplyLength(
|
|
IN PFILEDIRPARM pFDParm,
|
|
IN DWORD Bitmap
|
|
)
|
|
{
|
|
LONG i;
|
|
USHORT Size = 0;
|
|
static BYTE Bitmap2Size[14] =
|
|
{
|
|
sizeof(USHORT), // Attributes
|
|
sizeof(DWORD), // Parent DirId
|
|
sizeof(DWORD), // Create Date
|
|
sizeof(DWORD), // Mod. Date
|
|
sizeof(DWORD), // Backup Date
|
|
sizeof(FINDERINFO),
|
|
sizeof(USHORT) + sizeof(BYTE), // Long Name
|
|
sizeof(USHORT) + sizeof(BYTE), // Short Name
|
|
sizeof(DWORD), // DirId/FileNum
|
|
sizeof(DWORD), // DataForkLength/Offspring Count
|
|
sizeof(DWORD), // RescForkLength/Owner Id
|
|
sizeof(DWORD), // Group Id
|
|
sizeof(DWORD), // Access Rights
|
|
sizeof(PRODOSINFO) // ProDos Info
|
|
};
|
|
|
|
PAGED_CODE( );
|
|
|
|
ASSERT ((Bitmap & ~DIR_BITMAP_MASK) == 0);
|
|
|
|
if (Bitmap & FD_BITMAP_LONGNAME)
|
|
Size += pFDParm->_fdp_LongName.Length;
|
|
|
|
if (Bitmap & FD_BITMAP_SHORTNAME)
|
|
Size += pFDParm->_fdp_ShortName.Length;
|
|
|
|
if (IsDir(pFDParm) && (Bitmap & DIR_BITMAP_OFFSPRINGS))
|
|
Size -= sizeof(USHORT);
|
|
|
|
for (i = 0; Bitmap; i++)
|
|
{
|
|
if (Bitmap & 1)
|
|
Size += (USHORT)Bitmap2Size[i];
|
|
Bitmap >>= 1;
|
|
}
|
|
return Size;
|
|
}
|
|
|
|
|
|
|
|
/*** AfpPackFileDirParms
|
|
*
|
|
* Pack file or directory parameters into the reply buffer in on-the-wire
|
|
* format.
|
|
*/
|
|
VOID
|
|
AfpPackFileDirParms(
|
|
IN PFILEDIRPARM pFDParm,
|
|
IN DWORD Bitmap,
|
|
IN PBYTE pReplyBuf
|
|
)
|
|
{
|
|
LONG Offset = 0;
|
|
LONG LongNameOff, ShortNameOff;
|
|
|
|
PAGED_CODE( );
|
|
|
|
if (Bitmap & FD_BITMAP_ATTR)
|
|
{
|
|
PUTSHORT2SHORT(pReplyBuf + Offset, pFDParm->_fdp_Attr);
|
|
Offset += sizeof(USHORT);
|
|
}
|
|
if (Bitmap & FD_BITMAP_PARENT_DIRID)
|
|
{
|
|
PUTDWORD2DWORD(pReplyBuf + Offset, pFDParm->_fdp_ParentId);
|
|
Offset += sizeof(DWORD);
|
|
}
|
|
if (Bitmap & FD_BITMAP_CREATETIME)
|
|
{
|
|
PUTDWORD2DWORD(pReplyBuf + Offset, pFDParm->_fdp_CreateTime);
|
|
Offset += sizeof(DWORD);
|
|
}
|
|
if (Bitmap & FD_BITMAP_MODIFIEDTIME)
|
|
{
|
|
PUTDWORD2DWORD(pReplyBuf + Offset, pFDParm->_fdp_ModifiedTime);
|
|
Offset += sizeof(DWORD);
|
|
}
|
|
if (Bitmap & FD_BITMAP_BACKUPTIME)
|
|
{
|
|
PUTDWORD2DWORD(pReplyBuf + Offset, pFDParm->_fdp_BackupTime);
|
|
Offset += sizeof(DWORD);
|
|
}
|
|
if (Bitmap & FD_BITMAP_FINDERINFO)
|
|
{
|
|
if ((Bitmap & FD_BITMAP_ATTR) && (pFDParm->_fdp_Attr & FD_BITMAP_ATTR_INVISIBLE))
|
|
pFDParm->_fdp_FinderInfo.fd_Attr1 |= FINDER_FLAG_INVISIBLE;
|
|
|
|
RtlCopyMemory(pReplyBuf + Offset, (PBYTE)&pFDParm->_fdp_FinderInfo,
|
|
sizeof(FINDERINFO));
|
|
Offset += sizeof(FINDERINFO);
|
|
}
|
|
|
|
// Note the offset where the pointers to names will go. We'll have to
|
|
// Fill it up later.
|
|
if (Bitmap & FD_BITMAP_LONGNAME)
|
|
{
|
|
LongNameOff = Offset;
|
|
Offset += sizeof(USHORT);
|
|
}
|
|
if (Bitmap & FD_BITMAP_SHORTNAME)
|
|
{
|
|
ShortNameOff = Offset;
|
|
Offset += sizeof(USHORT);
|
|
}
|
|
|
|
// FileNum for files and DirId for Directories are in the same place
|
|
if (Bitmap & FILE_BITMAP_FILENUM)
|
|
{
|
|
PUTDWORD2DWORD(pReplyBuf + Offset, pFDParm->_fdp_AfpId);
|
|
Offset += sizeof(DWORD);
|
|
}
|
|
|
|
if (IsDir(pFDParm))
|
|
{
|
|
// Directory parameters
|
|
if (Bitmap & DIR_BITMAP_OFFSPRINGS)
|
|
{
|
|
DWORD OffSpring;
|
|
|
|
OffSpring = pFDParm->_fdp_FileCount + pFDParm->_fdp_DirCount;
|
|
PUTDWORD2SHORT(pReplyBuf + Offset, OffSpring);
|
|
Offset += sizeof(USHORT);
|
|
}
|
|
|
|
if (Bitmap & DIR_BITMAP_OWNERID)
|
|
{
|
|
PUTDWORD2DWORD(pReplyBuf + Offset, pFDParm->_fdp_OwnerId);
|
|
Offset += sizeof(DWORD);
|
|
}
|
|
|
|
if (Bitmap & DIR_BITMAP_GROUPID)
|
|
{
|
|
PUTDWORD2DWORD(pReplyBuf + Offset, pFDParm->_fdp_GroupId);
|
|
Offset += sizeof(DWORD);
|
|
}
|
|
|
|
if (Bitmap & DIR_BITMAP_ACCESSRIGHTS)
|
|
{
|
|
DWORD AccessInfo;
|
|
|
|
AccessInfo = (pFDParm->_fdp_OwnerRights << OWNER_RIGHTS_SHIFT) +
|
|
(pFDParm->_fdp_GroupRights << GROUP_RIGHTS_SHIFT) +
|
|
(pFDParm->_fdp_WorldRights << WORLD_RIGHTS_SHIFT) +
|
|
(pFDParm->_fdp_UserRights << USER_RIGHTS_SHIFT);
|
|
|
|
PUTDWORD2DWORD(pReplyBuf + Offset, AccessInfo & ~OWNER_BITS_ALL);
|
|
Offset += sizeof(DWORD);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (Bitmap & FILE_BITMAP_DATALEN)
|
|
{
|
|
PUTDWORD2DWORD(pReplyBuf + Offset, pFDParm->_fdp_DataForkLen);
|
|
Offset += sizeof(DWORD);
|
|
}
|
|
|
|
// Resc Length for files and Owner Id for Directories are in the same place
|
|
if (Bitmap & FILE_BITMAP_RESCLEN)
|
|
{
|
|
PUTDWORD2DWORD(pReplyBuf + Offset, pFDParm->_fdp_RescForkLen);
|
|
Offset += sizeof(DWORD);
|
|
}
|
|
}
|
|
|
|
if (Bitmap & FD_BITMAP_PRODOSINFO)
|
|
{
|
|
RtlCopyMemory(pReplyBuf + Offset, (PBYTE)&pFDParm->_fdp_ProDosInfo,
|
|
sizeof(PRODOSINFO));
|
|
Offset += sizeof(PRODOSINFO);
|
|
}
|
|
if (Bitmap & FD_BITMAP_LONGNAME)
|
|
{
|
|
ASSERT(pFDParm->_fdp_LongName.Length <= AFP_LONGNAME_LEN);
|
|
|
|
PUTDWORD2SHORT(pReplyBuf + LongNameOff, Offset);
|
|
PUTSHORT2BYTE(pReplyBuf + Offset, pFDParm->_fdp_LongName.Length);
|
|
RtlCopyMemory(pReplyBuf + Offset + sizeof(BYTE),
|
|
pFDParm->_fdp_LongName.Buffer,
|
|
pFDParm->_fdp_LongName.Length);
|
|
|
|
Offset += pFDParm->_fdp_LongName.Length + sizeof(BYTE);
|
|
}
|
|
if (Bitmap & FD_BITMAP_SHORTNAME)
|
|
{
|
|
ASSERT(pFDParm->_fdp_ShortName.Length <= AFP_SHORTNAME_LEN);
|
|
|
|
PUTDWORD2SHORT(pReplyBuf + ShortNameOff, Offset);
|
|
PUTSHORT2BYTE(pReplyBuf + Offset, pFDParm->_fdp_ShortName.Length);
|
|
RtlCopyMemory(pReplyBuf + Offset + sizeof(BYTE),
|
|
pFDParm->_fdp_ShortName.Buffer,
|
|
pFDParm->_fdp_ShortName.Length);
|
|
Offset += pFDParm->_fdp_ShortName.Length + sizeof(BYTE);
|
|
}
|
|
if (Offset & 1)
|
|
*(pReplyBuf + Offset) = 0;
|
|
}
|
|
|
|
|
|
|
|
/*** AfpUnpackFileDirParms
|
|
*
|
|
* Unpack the information from the on-the-wire format to the FileDirParm
|
|
* structure. Only the fields that can be set are looked at. The bitmaps
|
|
* are validated by the caller.
|
|
*
|
|
* OPTIMIZATION: The finder is notorious for setting things needlessly.
|
|
* We figure out if what is being set is same as what it
|
|
* is currently and if it is just clear that bit.
|
|
*/
|
|
AFPSTATUS
|
|
AfpUnpackFileDirParms(
|
|
IN PBYTE pBuffer,
|
|
IN LONG Length,
|
|
IN PDWORD pBitmap,
|
|
OUT PFILEDIRPARM pFDParm
|
|
)
|
|
{
|
|
DWORD Bitmap = *pBitmap;
|
|
AFPTIME ModTime;
|
|
USHORT Offset = 0;
|
|
BOOLEAN SetModTime = False;
|
|
AFPSTATUS Status = AFP_ERR_NONE;
|
|
|
|
PAGED_CODE( );
|
|
|
|
do
|
|
{
|
|
if ((LONG)AfpGetFileDirParmsReplyLength(pFDParm, *pBitmap) > Length)
|
|
{
|
|
DBGPRINT(DBG_COMP_AFPAPI_FD, DBG_LEVEL_FATAL,
|
|
("UnpackFileDirParms: Buffer not large enough!\n"));
|
|
DBGBRK(DBG_LEVEL_FATAL);
|
|
Status = AFP_ERR_PARAM;
|
|
break;
|
|
}
|
|
|
|
if (Bitmap & FD_BITMAP_ATTR)
|
|
{
|
|
USHORT OldAttr, NewAttr;
|
|
USHORT Set;
|
|
|
|
GETSHORT2SHORT(&NewAttr, pBuffer+Offset);
|
|
// keep track of if client wants to set bits or clear bits
|
|
Set = (NewAttr & FD_BITMAP_ATTR_SET);
|
|
// take off the 'set' bit to isolate the requested bits
|
|
NewAttr &= ~FD_BITMAP_ATTR_SET;
|
|
// the current effective settings of attributes
|
|
OldAttr = (pFDParm->_fdp_Attr & ~FD_BITMAP_ATTR_SET);
|
|
|
|
if ((NewAttr != 0) &&
|
|
(((Set != 0) && ((OldAttr ^ NewAttr) != 0)) ||
|
|
((Set == 0) && ((OldAttr & NewAttr) != 0))))
|
|
{
|
|
// becomes the new resultant AFP attributes after setting
|
|
pFDParm->_fdp_EffectiveAttr = (Set != 0) ?
|
|
(pFDParm->_fdp_Attr | NewAttr) :
|
|
(pFDParm->_fdp_Attr & ~NewAttr);
|
|
|
|
// changing a directory's inhibit and invisible attributes from
|
|
// their current settings can only be done by the dir owner
|
|
if (IsDir(pFDParm) &&
|
|
((pFDParm->_fdp_EffectiveAttr & DIR_BITMAP_ATTR_CHG_X_OWNER_ONLY) ^
|
|
(pFDParm->_fdp_Attr & DIR_BITMAP_ATTR_CHG_X_OWNER_ONLY)) &&
|
|
!(pFDParm->_fdp_UserRights & DIR_ACCESS_OWNER))
|
|
{
|
|
Status = AFP_ERR_ACCESS_DENIED;
|
|
break;
|
|
}
|
|
|
|
// becomes attribute bits requested to be set/cleared
|
|
pFDParm->_fdp_Attr = (NewAttr | Set);
|
|
}
|
|
else *pBitmap &= ~FD_BITMAP_ATTR;
|
|
Offset += sizeof(USHORT);
|
|
}
|
|
if (Bitmap & FD_BITMAP_CREATETIME)
|
|
{
|
|
AFPTIME CreateTime;
|
|
|
|
GETDWORD2DWORD(&CreateTime, pBuffer+Offset);
|
|
if (CreateTime == pFDParm->_fdp_CreateTime)
|
|
*pBitmap &= ~FD_BITMAP_CREATETIME;
|
|
else pFDParm->_fdp_CreateTime = CreateTime;
|
|
Offset += sizeof(DWORD);
|
|
}
|
|
if (Bitmap & FD_BITMAP_MODIFIEDTIME)
|
|
{
|
|
GETDWORD2DWORD(&ModTime, pBuffer+Offset);
|
|
if (ModTime == pFDParm->_fdp_ModifiedTime)
|
|
{
|
|
*pBitmap &= ~FD_BITMAP_MODIFIEDTIME;
|
|
SetModTime = True;
|
|
}
|
|
else
|
|
{
|
|
pFDParm->_fdp_ModifiedTime = ModTime;
|
|
}
|
|
Offset += sizeof(DWORD);
|
|
}
|
|
if (Bitmap & FD_BITMAP_BACKUPTIME)
|
|
{
|
|
AFPTIME BackupTime;
|
|
|
|
GETDWORD2DWORD(&BackupTime, pBuffer+Offset);
|
|
if (BackupTime == pFDParm->_fdp_BackupTime)
|
|
*pBitmap &= ~FD_BITMAP_BACKUPTIME;
|
|
else pFDParm->_fdp_BackupTime = BackupTime;
|
|
Offset += sizeof(DWORD);
|
|
}
|
|
if (Bitmap & FD_BITMAP_FINDERINFO)
|
|
{
|
|
int i, rlo = -1, rhi = -1; // Range of bytes that are different
|
|
PBYTE pSrc, pDst;
|
|
|
|
pSrc = pBuffer + Offset;
|
|
pDst = (PBYTE)(&pFDParm->_fdp_FinderInfo);
|
|
for (i = 0; i < sizeof(FINDERINFO); i++)
|
|
{
|
|
if (*pSrc++ != *pDst++)
|
|
{
|
|
if (rlo == -1)
|
|
rlo = i;
|
|
else rhi = i;
|
|
}
|
|
}
|
|
|
|
if ((rlo != -1) && (rhi == -1))
|
|
rhi = rlo;
|
|
|
|
// Optimization: if nothing has changed, avoid a copy
|
|
if (rlo == -1)
|
|
{
|
|
*pBitmap &= ~FD_BITMAP_FINDERINFO;
|
|
}
|
|
else
|
|
{
|
|
RtlCopyMemory((PBYTE)&pFDParm->_fdp_FinderInfo,
|
|
pBuffer+Offset,
|
|
sizeof(FINDERINFO));
|
|
}
|
|
Offset += sizeof(FINDERINFO);
|
|
}
|
|
|
|
if (IsDir(pFDParm) &&
|
|
(Bitmap & (DIR_BITMAP_OWNERID |
|
|
DIR_BITMAP_GROUPID |
|
|
DIR_BITMAP_ACCESSRIGHTS)))
|
|
{
|
|
if (Bitmap & DIR_BITMAP_OWNERID)
|
|
{
|
|
DWORD OwnerId;
|
|
|
|
GETDWORD2DWORD(&OwnerId, pBuffer+Offset);
|
|
if (pFDParm->_fdp_OwnerId == OwnerId)
|
|
Bitmap &= ~DIR_BITMAP_OWNERID;
|
|
else pFDParm->_fdp_OwnerId = OwnerId;
|
|
Offset += sizeof(DWORD);
|
|
}
|
|
if (Bitmap & DIR_BITMAP_GROUPID)
|
|
{
|
|
DWORD GroupId;
|
|
|
|
GETDWORD2DWORD(&GroupId, pBuffer+Offset);
|
|
if (pFDParm->_fdp_GroupId == GroupId)
|
|
Bitmap &= ~DIR_BITMAP_GROUPID;
|
|
else pFDParm->_fdp_GroupId = GroupId;
|
|
Offset += sizeof(DWORD);
|
|
}
|
|
if (Bitmap & DIR_BITMAP_ACCESSRIGHTS)
|
|
{
|
|
DWORD AccessInfo;
|
|
|
|
GETDWORD2DWORD(&AccessInfo, pBuffer+Offset);
|
|
|
|
pFDParm->_fdp_OwnerRights =
|
|
(BYTE)((AccessInfo >> OWNER_RIGHTS_SHIFT) & DIR_ACCESS_ALL);
|
|
pFDParm->_fdp_GroupRights =
|
|
(BYTE)((AccessInfo >> GROUP_RIGHTS_SHIFT) & DIR_ACCESS_ALL);
|
|
pFDParm->_fdp_WorldRights =
|
|
(BYTE)((AccessInfo >> WORLD_RIGHTS_SHIFT) & DIR_ACCESS_ALL);
|
|
Offset += sizeof(DWORD);
|
|
}
|
|
if (Bitmap & (DIR_BITMAP_OWNERID | DIR_BITMAP_GROUPID))
|
|
Bitmap |= DIR_BITMAP_ACCESSRIGHTS;
|
|
}
|
|
|
|
if (Bitmap & FD_BITMAP_PRODOSINFO)
|
|
{
|
|
int i;
|
|
PBYTE pSrc, pDst;
|
|
|
|
pSrc = pBuffer + Offset;
|
|
pDst = (PBYTE)(&pFDParm->_fdp_ProDosInfo);
|
|
for (i = 0; i < sizeof(PRODOSINFO); i++)
|
|
if (*pSrc++ != *pDst++)
|
|
break;
|
|
if (i == sizeof(PRODOSINFO))
|
|
*pBitmap &= ~FD_BITMAP_PRODOSINFO;
|
|
else RtlCopyMemory((PBYTE)&pFDParm->_fdp_ProDosInfo,
|
|
pBuffer+Offset,
|
|
sizeof(PRODOSINFO));
|
|
// Offset += sizeof(PRODOSINFO);
|
|
}
|
|
} while (False);
|
|
|
|
// If anything is being set and modified time was dropped because it was identical
|
|
// to what is already on, set the bitmap so that it is restored after the change.
|
|
if (SetModTime && *pBitmap)
|
|
{
|
|
*pBitmap |= FD_BITMAP_MODIFIEDTIME;
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
/*** AfpSetFileDirParms
|
|
*
|
|
* This is the worker for AfpGetFileDirParms/AfpSetFileParms/AfpSetDirParms.
|
|
* This is callable only in the worker's context.
|
|
*
|
|
* LOCKS: vds_IdDbAccessLock (SWMR, Exclusive);
|
|
*/
|
|
AFPSTATUS
|
|
AfpSetFileDirParms(
|
|
IN PVOLDESC pVolDesc,
|
|
IN PPATHMAPENTITY pPME,
|
|
IN DWORD Bitmap,
|
|
IN PFILEDIRPARM pFDParm
|
|
)
|
|
{
|
|
AFPSTATUS Status = AFP_ERR_NONE;
|
|
BOOLEAN CleanupLock = False, SetROAttr = False;
|
|
PDFENTRY pDfEntry = NULL;
|
|
|
|
PAGED_CODE( );
|
|
|
|
do
|
|
{
|
|
ASSERT(IS_VOLUME_NTFS(pVolDesc));
|
|
|
|
// NOTE: should we take the SWMR while we set permissions?
|
|
if (IsDir(pFDParm))
|
|
{
|
|
if (Bitmap & (DIR_BITMAP_OWNERID |
|
|
DIR_BITMAP_GROUPID |
|
|
DIR_BITMAP_ACCESSRIGHTS))
|
|
{
|
|
|
|
Status = AfpSetAfpPermissions(pPME->pme_Handle.fsh_FileHandle,
|
|
Bitmap,
|
|
pFDParm);
|
|
if (!NT_SUCCESS(Status))
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (Bitmap & (FD_BITMAP_FINDERINFO |
|
|
FD_BITMAP_PRODOSINFO |
|
|
FD_BITMAP_ATTR |
|
|
FD_BITMAP_BACKUPTIME |
|
|
DIR_BITMAP_ACCESSRIGHTS |
|
|
DIR_BITMAP_OWNERID |
|
|
DIR_BITMAP_GROUPID |
|
|
FD_BITMAP_CREATETIME |
|
|
FD_BITMAP_MODIFIEDTIME |
|
|
FD_BITMAP_ATTR))
|
|
{
|
|
AfpSwmrAcquireExclusive(&pVolDesc->vds_IdDbAccessLock);
|
|
CleanupLock = True;
|
|
}
|
|
|
|
if (Bitmap & (FD_BITMAP_FINDERINFO |
|
|
FD_BITMAP_PRODOSINFO |
|
|
FD_BITMAP_ATTR |
|
|
FD_BITMAP_BACKUPTIME |
|
|
DIR_BITMAP_ACCESSRIGHTS))
|
|
{
|
|
|
|
// Will update the cached AfpInfo as well as the stream
|
|
Status = AfpSetAfpInfo(&pPME->pme_Handle,
|
|
Bitmap,
|
|
pFDParm,
|
|
pVolDesc,
|
|
&pDfEntry);
|
|
|
|
if (Status != AFP_ERR_NONE)
|
|
break;
|
|
}
|
|
|
|
if (Bitmap & (FD_BITMAP_CREATETIME |
|
|
FD_BITMAP_MODIFIEDTIME |
|
|
FD_BITMAP_ATTR |
|
|
DIR_BITMAP_ACCESSRIGHTS |
|
|
DIR_BITMAP_OWNERID |
|
|
DIR_BITMAP_GROUPID))
|
|
{
|
|
DWORD SetNtAttr = 0, ClrNtAttr = 0;
|
|
|
|
// need to update the cached times too. If we didn't get the
|
|
// pDfEntry back from setting some other AfpInfo, look it up now
|
|
if (pDfEntry == NULL)
|
|
{
|
|
pDfEntry = AfpFindDfEntryById(pVolDesc,
|
|
pFDParm->_fdp_AfpId,
|
|
IsDir(pFDParm) ? DFE_DIR : DFE_FILE);
|
|
if (pDfEntry == NULL)
|
|
{
|
|
Status = AFP_ERR_OBJECT_NOT_FOUND;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (Bitmap & FD_BITMAP_ATTR)
|
|
{
|
|
if (pFDParm->_fdp_Attr & FD_BITMAP_ATTR_SET)
|
|
SetNtAttr = AfpConvertAfpAttrToNTAttr(pFDParm->_fdp_Attr);
|
|
else
|
|
ClrNtAttr = AfpConvertAfpAttrToNTAttr(pFDParm->_fdp_Attr);
|
|
|
|
if (pFDParm->_fdp_Attr & (FD_BITMAP_ATTR_RENAMEINH |
|
|
FD_BITMAP_ATTR_DELETEINH))
|
|
{
|
|
SetROAttr = True;
|
|
}
|
|
|
|
if ((SetNtAttr == 0) && (ClrNtAttr == 0))
|
|
{
|
|
// Since there is no attribute being set/cleared that
|
|
// corresponds to any NT attribute, we can clear the
|
|
// ATTR bitmap since we've already set the Mac specific
|
|
// stuff in the DFE and Afpinfo.
|
|
Bitmap &= ~FD_BITMAP_ATTR;
|
|
}
|
|
}
|
|
|
|
if (Bitmap & (FD_BITMAP_CREATETIME |
|
|
FD_BITMAP_MODIFIEDTIME |
|
|
FD_BITMAP_ATTR))
|
|
{
|
|
ASSERT(pPME->pme_FullPath.Buffer != NULL);
|
|
Status = AfpIoSetTimesnAttr(&pPME->pme_Handle,
|
|
((Bitmap & FD_BITMAP_CREATETIME) != 0) ?
|
|
(PAFPTIME)&pFDParm->_fdp_CreateTime : NULL,
|
|
(((Bitmap & FD_BITMAP_MODIFIEDTIME) != 0) || (SetROAttr)) ?
|
|
(PAFPTIME)&pFDParm->_fdp_ModifiedTime : NULL,
|
|
SetNtAttr, ClrNtAttr,
|
|
pVolDesc,
|
|
&pPME->pme_FullPath);
|
|
}
|
|
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
break;
|
|
|
|
if (Bitmap & FD_BITMAP_CREATETIME)
|
|
{
|
|
pDfEntry->dfe_CreateTime =
|
|
(AFPTIME)pFDParm->_fdp_CreateTime;
|
|
}
|
|
|
|
if (Bitmap & FD_BITMAP_MODIFIEDTIME)
|
|
{
|
|
AfpConvertTimeFromMacFormat(pFDParm->_fdp_ModifiedTime,
|
|
&pDfEntry->dfe_LastModTime);
|
|
}
|
|
else if (IsDir(pFDParm) &&
|
|
((Bitmap & (DIR_BITMAP_OWNERID |
|
|
DIR_BITMAP_GROUPID |
|
|
DIR_BITMAP_ACCESSRIGHTS)) ||
|
|
SetROAttr))
|
|
{
|
|
ASSERT(VALID_DFE(pDfEntry));
|
|
// Setting permissions on a dir or changing its RO attribute
|
|
// should update the modified time on the dir (as observed
|
|
// on Appleshare 4.0)
|
|
AfpIoChangeNTModTime(&pPME->pme_Handle,
|
|
&pDfEntry->dfe_LastModTime);
|
|
}
|
|
|
|
if (Bitmap & FD_BITMAP_ATTR)
|
|
{
|
|
if (pFDParm->_fdp_Attr & FD_BITMAP_ATTR_SET)
|
|
pDfEntry->dfe_NtAttr |= (USHORT)SetNtAttr;
|
|
else pDfEntry->dfe_NtAttr &= ~((USHORT)ClrNtAttr);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
AfpVolumeSetModifiedTime(pVolDesc);
|
|
} while (False);
|
|
|
|
if (CleanupLock)
|
|
{
|
|
AfpSwmrRelease(&pVolDesc->vds_IdDbAccessLock);
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
/*** AfpQuerySecurityIdsAndRights
|
|
*
|
|
* Find the owner id and primary group id for this entity. Map the corres.
|
|
* SIDs to their posix ids. Determine also the access rights for owner,
|
|
* group, world and this user. The access rights are divided into the
|
|
* following:
|
|
*
|
|
* Owner's rights
|
|
* Primary group's rights
|
|
* World rights
|
|
* This user's rights
|
|
*
|
|
* The handle to the directory should be opened with READ_CONTROL
|
|
* See Files vs. See Folders resolution for Owner/Group/World is already done.
|
|
*/
|
|
LOCAL AFPSTATUS
|
|
AfpQuerySecurityIdsAndRights(
|
|
IN PSDA pSda,
|
|
IN PFILESYSHANDLE pFSHandle,
|
|
IN DWORD Bitmap,
|
|
IN OUT PFILEDIRPARM pFDParm
|
|
)
|
|
{
|
|
NTSTATUS Status;
|
|
BYTE ORights, GRights, WRights;
|
|
|
|
PAGED_CODE( );
|
|
|
|
// Save contents of the AfpInfo stream access bits
|
|
ORights = pFDParm->_fdp_OwnerRights | DIR_ACCESS_WRITE;
|
|
GRights = pFDParm->_fdp_GroupRights | DIR_ACCESS_WRITE;
|
|
WRights = pFDParm->_fdp_WorldRights | DIR_ACCESS_WRITE;
|
|
|
|
// Initialize to no rights for everybody
|
|
pFDParm->_fdp_Rights = 0;
|
|
|
|
// Get the OwnerId and GroupId for this directory.
|
|
// Determine the Owner/Group and World rights for this directory
|
|
// Determine if this user is a member of the directory's group
|
|
Status = AfpGetAfpPermissions(pSda,
|
|
pFSHandle->fsh_FileHandle,
|
|
pFDParm);
|
|
if (!NT_SUCCESS(Status))
|
|
return Status;
|
|
|
|
// Modify owner/group/world rights for the SeeFiles/SeeFolder weirdness
|
|
// Also if the ACLs say we have READ & SEARCH access but AfpInfo stream
|
|
// says we don't, then ignore AfpInfo stream
|
|
if ((pFDParm->_fdp_OwnerRights & (DIR_ACCESS_READ | DIR_ACCESS_SEARCH)) &&
|
|
!(ORights & (DIR_ACCESS_READ | DIR_ACCESS_SEARCH)))
|
|
ORights |= (DIR_ACCESS_READ | DIR_ACCESS_SEARCH);
|
|
pFDParm->_fdp_OwnerRights &= ORights;
|
|
|
|
if ((pFDParm->_fdp_GroupRights & (DIR_ACCESS_READ | DIR_ACCESS_SEARCH)) &&
|
|
!(GRights & (DIR_ACCESS_READ | DIR_ACCESS_SEARCH)))
|
|
GRights |= (DIR_ACCESS_READ | DIR_ACCESS_SEARCH);
|
|
pFDParm->_fdp_GroupRights &= GRights;
|
|
|
|
if ((pFDParm->_fdp_WorldRights & (DIR_ACCESS_READ | DIR_ACCESS_SEARCH)) &&
|
|
!(WRights & (DIR_ACCESS_READ | DIR_ACCESS_SEARCH)))
|
|
WRights |= (DIR_ACCESS_READ | DIR_ACCESS_SEARCH);
|
|
pFDParm->_fdp_WorldRights &= WRights;
|
|
|
|
// One last bit of munging. Owner & Group can be the same and they both
|
|
// could be everyone !! Coalese that.
|
|
if (pFDParm->_fdp_OwnerId == SE_WORLD_POSIX_ID)
|
|
{
|
|
pFDParm->_fdp_WorldRights |= (pFDParm->_fdp_OwnerRights & ~DIR_ACCESS_OWNER);
|
|
pFDParm->_fdp_OwnerRights |= pFDParm->_fdp_WorldRights;
|
|
}
|
|
|
|
if (pFDParm->_fdp_GroupId == SE_WORLD_POSIX_ID)
|
|
{
|
|
pFDParm->_fdp_WorldRights |= pFDParm->_fdp_GroupRights;
|
|
pFDParm->_fdp_GroupRights |= pFDParm->_fdp_WorldRights;
|
|
}
|
|
|
|
if (pFDParm->_fdp_GroupId == pFDParm->_fdp_OwnerId)
|
|
{
|
|
pFDParm->_fdp_OwnerRights |= pFDParm->_fdp_GroupRights;
|
|
pFDParm->_fdp_GroupRights |= (pFDParm->_fdp_OwnerRights & ~DIR_ACCESS_OWNER);
|
|
}
|
|
|
|
// Modify User rights for the SeeFiles/SeeFolder weirdness by determining
|
|
// if the user is owner/group or world
|
|
if (pFDParm->_fdp_UserRights & (DIR_ACCESS_READ | DIR_ACCESS_SEARCH))
|
|
{
|
|
BYTE URights = (pFDParm->_fdp_UserRights & (DIR_ACCESS_WRITE | DIR_ACCESS_OWNER));
|
|
|
|
if ((pFDParm->_fdp_WorldRights & (DIR_ACCESS_READ | DIR_ACCESS_SEARCH))
|
|
!= (DIR_ACCESS_READ | DIR_ACCESS_SEARCH))
|
|
{
|
|
pFDParm->_fdp_UserRights = pFDParm->_fdp_WorldRights;
|
|
if (pFDParm->_fdp_UserIsOwner)
|
|
{
|
|
pFDParm->_fdp_UserRights |= pFDParm->_fdp_OwnerRights;
|
|
}
|
|
if (pFDParm->_fdp_UserIsMemberOfDirGroup)
|
|
{
|
|
pFDParm->_fdp_UserRights |= pFDParm->_fdp_GroupRights;
|
|
}
|
|
if ((pFDParm->_fdp_UserRights & (DIR_ACCESS_READ | DIR_ACCESS_SEARCH)) == 0)
|
|
pFDParm->_fdp_UserRights |= (DIR_ACCESS_READ | DIR_ACCESS_SEARCH);
|
|
pFDParm->_fdp_UserRights &= ~DIR_ACCESS_WRITE;
|
|
pFDParm->_fdp_UserRights |= URights;
|
|
}
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
/*** AfpConvertNTAttrToAfpAttr
|
|
*
|
|
* Map NT Attributes to the AFP equivalents.
|
|
*/
|
|
USHORT
|
|
AfpConvertNTAttrToAfpAttr(
|
|
IN DWORD Attr
|
|
)
|
|
{
|
|
USHORT AfpAttr = FD_BITMAP_ATTR_SET;
|
|
|
|
PAGED_CODE( );
|
|
|
|
if (Attr & FILE_ATTRIBUTE_READONLY)
|
|
{
|
|
AfpAttr |= FD_BITMAP_ATTR_RENAMEINH | FD_BITMAP_ATTR_DELETEINH;
|
|
if (!(Attr & FILE_ATTRIBUTE_DIRECTORY))
|
|
AfpAttr |= FILE_BITMAP_ATTR_WRITEINH;
|
|
}
|
|
|
|
if (Attr & FILE_ATTRIBUTE_HIDDEN)
|
|
AfpAttr |= FD_BITMAP_ATTR_INVISIBLE;
|
|
|
|
if (Attr & FILE_ATTRIBUTE_SYSTEM)
|
|
AfpAttr |= FD_BITMAP_ATTR_SYSTEM;
|
|
|
|
if (Attr & FILE_ATTRIBUTE_ARCHIVE)
|
|
{
|
|
AfpAttr |= FD_BITMAP_ATTR_BACKUPNEED;
|
|
}
|
|
|
|
return AfpAttr;
|
|
}
|
|
|
|
|
|
/*** AfpConvertAfpAttrToNTAttr
|
|
*
|
|
* Map AFP Attributes to the NT equivalents.
|
|
*/
|
|
DWORD
|
|
AfpConvertAfpAttrToNTAttr(
|
|
IN USHORT Attr
|
|
)
|
|
{
|
|
DWORD NtAttr = 0;
|
|
|
|
PAGED_CODE( );
|
|
|
|
if (Attr & (FD_BITMAP_ATTR_RENAMEINH |
|
|
FD_BITMAP_ATTR_DELETEINH |
|
|
FILE_BITMAP_ATTR_WRITEINH))
|
|
NtAttr |= FILE_ATTRIBUTE_READONLY;
|
|
|
|
if (Attr & FD_BITMAP_ATTR_INVISIBLE)
|
|
NtAttr |= FILE_ATTRIBUTE_HIDDEN;
|
|
|
|
if (Attr & FD_BITMAP_ATTR_SYSTEM)
|
|
NtAttr |= FILE_ATTRIBUTE_SYSTEM;
|
|
|
|
if (Attr & FD_BITMAP_ATTR_BACKUPNEED)
|
|
{
|
|
NtAttr |= FILE_ATTRIBUTE_ARCHIVE;
|
|
}
|
|
|
|
return NtAttr;
|
|
}
|
|
|
|
|
|
/*** AfpNormalizeAfpAttr
|
|
*
|
|
* Normalize the various inhibit bits in afp attributes vs. the RO bit on the
|
|
* disk.
|
|
*/
|
|
VOID
|
|
AfpNormalizeAfpAttr(
|
|
IN OUT PFILEDIRPARM pFDParm,
|
|
IN DWORD NtAttr
|
|
)
|
|
{
|
|
USHORT AfpAttr;
|
|
|
|
PAGED_CODE( );
|
|
|
|
AfpAttr = AfpConvertNTAttrToAfpAttr(NtAttr);
|
|
|
|
/*
|
|
* The Attributes fall into two classes, the ones that are on
|
|
* on the filesystem and the others maintained in the AfpInfo
|
|
* stream. We need to coalesce these two sets. The RO bit on
|
|
* the disk corres. to the three inhibit bits. Fine grain
|
|
* control is possible.
|
|
*
|
|
* The other set of bits that are in the exclusive realm of
|
|
* the AfpInfo stream are the RAlreadyOpen and DAlreadyOpen
|
|
* bits and the multi-user bit.
|
|
*/
|
|
if (((pFDParm->_fdp_Attr & FD_BITMAP_ATTR_NT_RO) == 0) ^
|
|
((AfpAttr & FD_BITMAP_ATTR_NT_RO) == 0))
|
|
{
|
|
if ((AfpAttr & FD_BITMAP_ATTR_NT_RO) == 0)
|
|
pFDParm->_fdp_Attr &= ~FD_BITMAP_ATTR_NT_RO;
|
|
else pFDParm->_fdp_Attr |= FD_BITMAP_ATTR_NT_RO;
|
|
}
|
|
|
|
pFDParm->_fdp_Attr &= (AfpAttr |
|
|
(FILE_BITMAP_ATTR_MULTIUSER |
|
|
FILE_BITMAP_ATTR_DATAOPEN |
|
|
FILE_BITMAP_ATTR_RESCOPEN |
|
|
FD_BITMAP_ATTR_SET));
|
|
pFDParm->_fdp_Attr |= (AfpAttr & (FD_BITMAP_ATTR_BACKUPNEED |
|
|
FD_BITMAP_ATTR_SYSTEM |
|
|
FD_BITMAP_ATTR_INVISIBLE));
|
|
|
|
}
|
|
|
|
|
|
/***AfpMapFDBitmapOpenAccess
|
|
*
|
|
* Map the FD_INTERNAL_BITMAP_OPENACCESS_xxx bits to the appropriate
|
|
* FILEIO_ACCESS_xxx values. The returned OpenAccess is used by the
|
|
* pathmap code to open the data stream of a file/dir (under impersonation
|
|
* for NTFS) for use in the AFP APIs.
|
|
*
|
|
*/
|
|
DWORD
|
|
AfpMapFDBitmapOpenAccess(
|
|
IN DWORD Bitmap,
|
|
IN BOOLEAN IsDir
|
|
)
|
|
{
|
|
DWORD OpenAccess = FILEIO_ACCESS_NONE;
|
|
|
|
PAGED_CODE( );
|
|
|
|
do
|
|
{
|
|
if (!(Bitmap & FD_INTERNAL_BITMAP_OPENACCESS_ALL))
|
|
{
|
|
break;
|
|
}
|
|
if (Bitmap & FD_INTERNAL_BITMAP_OPENACCESS_READCTRL)
|
|
{
|
|
// For GetFileDirParms we don't know if it was a file or dir they
|
|
// are asking for, so we had to OR the file and dir bitmaps together
|
|
// before pathmapping.
|
|
if (IsDir)
|
|
OpenAccess = (FILEIO_ACCESS_NONE |
|
|
READ_CONTROL |
|
|
SYNCHRONIZE);
|
|
break;
|
|
}
|
|
// Used by AfpAdmwDirectoryGetInfo
|
|
if (Bitmap & FD_INTERNAL_BITMAP_OPENACCESS_ADMINGET)
|
|
{
|
|
OpenAccess = (FILE_READ_ATTRIBUTES |
|
|
READ_CONTROL |
|
|
SYNCHRONIZE);
|
|
break;
|
|
}
|
|
if (Bitmap & FD_INTERNAL_BITMAP_OPENACCESS_ADMINSET)
|
|
{
|
|
OpenAccess = (FILE_READ_ATTRIBUTES |
|
|
READ_CONTROL |
|
|
SYNCHRONIZE |
|
|
FILE_WRITE_ATTRIBUTES |
|
|
WRITE_DAC |
|
|
WRITE_OWNER);
|
|
break;
|
|
}
|
|
if (Bitmap & FD_INTERNAL_BITMAP_OPENACCESS_RW_ATTR)
|
|
{
|
|
OpenAccess |= (FILEIO_ACCESS_NONE | FILE_WRITE_ATTRIBUTES);
|
|
}
|
|
if (Bitmap & FD_INTERNAL_BITMAP_OPENACCESS_RWCTRL)
|
|
{
|
|
OpenAccess |= (FILEIO_ACCESS_NONE |
|
|
READ_CONTROL |
|
|
WRITE_DAC |
|
|
WRITE_OWNER |
|
|
SYNCHRONIZE);
|
|
break;
|
|
}
|
|
if (Bitmap & FD_INTERNAL_BITMAP_OPENACCESS_READ)
|
|
{
|
|
OpenAccess |= FILEIO_ACCESS_READ;
|
|
}
|
|
if (Bitmap & FD_INTERNAL_BITMAP_OPENACCESS_WRITE)
|
|
{
|
|
OpenAccess |= FILEIO_ACCESS_WRITE;
|
|
}
|
|
if (Bitmap & FD_INTERNAL_BITMAP_OPENACCESS_DELETE)
|
|
{
|
|
OpenAccess |= FILEIO_ACCESS_DELETE;
|
|
}
|
|
} while (False);
|
|
|
|
return OpenAccess;
|
|
}
|
|
|
|
|
|
/*** AfpCheckForInhibit
|
|
*
|
|
* This routine checks for the setting of the Afp RenameInhibit, DeleteInhibit
|
|
* or WriteInhibit attributes. It first queries for the host File/Dir
|
|
* attributes to find out the setting of the ReadOnly attribute, then checks
|
|
* that against the Afp InhibitBit of interest. AFP_ERR_NONE is returned if
|
|
* the InhibitBit is not set, else AFP_ERR_OBJECT_LOCKED is returned.
|
|
* The input handle must be a handle to the $DATA stream of the file/dir open
|
|
* in server's context. The host attributes are returned in pNTAttr if the
|
|
* error code is not AFP_ERR_MISC.
|
|
*
|
|
*/
|
|
AFPSTATUS
|
|
AfpCheckForInhibit(
|
|
IN PFILESYSHANDLE hData, // handle to DATA stream in server context
|
|
IN DWORD InhibitBit,
|
|
IN DWORD AfpAttr,
|
|
OUT PDWORD pNTAttr
|
|
)
|
|
{
|
|
AFPSTATUS Status = STATUS_SUCCESS;
|
|
|
|
PAGED_CODE();
|
|
|
|
do
|
|
{
|
|
if (!NT_SUCCESS(AfpIoQueryTimesnAttr(hData, NULL, NULL, pNTAttr)))
|
|
{
|
|
Status = AFP_ERR_MISC;
|
|
break;
|
|
}
|
|
|
|
if (!(*pNTAttr & FILE_ATTRIBUTE_READONLY))
|
|
{
|
|
Status = AFP_ERR_NONE;
|
|
break;
|
|
}
|
|
if (!(AfpAttr & FD_BITMAP_ATTR_NT_RO) || (AfpAttr & InhibitBit))
|
|
{
|
|
// The file/dir is ReadOnly, but NONE of the AFP Inhibit bits are
|
|
// set, so we assume the PC has set the RO bit; or, the requested
|
|
// inhibit bit IS set.
|
|
Status = AFP_ERR_OBJECT_LOCKED;
|
|
break;
|
|
}
|
|
} while (False);
|
|
|
|
return Status;
|
|
}
|
|
|
|
/*** AfpUnpackCatSearchSpecs
|
|
*
|
|
* Unpack the information from the on-the-wire format to the FileDirParm
|
|
* structures for Specification 1 and 2. Specification 1 contains the
|
|
* CatSearch criteria for lower bounds and values. Specification 2
|
|
* contains the CatSearch criteria for upper bounds and masks. The parameters
|
|
* are packed in the same order that the bits are set in the request bitmap.
|
|
* These are read into FILEDIRPARM structures.
|
|
*
|
|
* The fields in Specification 1 and Specification 2 have different uses:
|
|
*
|
|
* - In the name field, Specification 1 holds the target string and
|
|
* Specification 2 must always have a nil name field.
|
|
*
|
|
* - In all date and length fields, Specification 1 holds the lowest value
|
|
* in the target range and Specification 2 holds the highest value in the
|
|
* target range.
|
|
*
|
|
* - In file attributes and Finder Info fields, Specification 1 holds the
|
|
* target value, and Specification 2 holds the bitwise mask that specifies
|
|
* which bits in that field in Specification 1 are relevant to the current
|
|
* search.
|
|
*
|
|
*/
|
|
AFPSTATUS
|
|
AfpUnpackCatSearchSpecs(
|
|
IN PBYTE pBuffer, // Pointer to beginning of Spec data
|
|
IN USHORT BufLength, // Length of Spec1 + Spec2 data
|
|
IN DWORD Bitmap,
|
|
OUT PFILEDIRPARM pFDParm1,
|
|
OUT PFILEDIRPARM pFDParm2,
|
|
OUT PUNICODE_STRING pMatchString
|
|
)
|
|
{
|
|
PCATSEARCHSPEC pSpec1, pSpec2;
|
|
PBYTE pBuffer1, pBuffer2, pEndOfBuffer;
|
|
USHORT Offset = 0, MinSpecLength1, MinSpecLength2;
|
|
AFPSTATUS Status = AFP_ERR_NONE;
|
|
BOOLEAN NoNullString = False;
|
|
|
|
PAGED_CODE( );
|
|
|
|
pSpec1 = (PCATSEARCHSPEC) pBuffer;
|
|
pSpec2 = (PCATSEARCHSPEC) ((PBYTE)pBuffer + sizeof(CATSEARCHSPEC) +
|
|
pSpec1->__StructLength);
|
|
|
|
// Point to data after the specification length and filler byte
|
|
|
|
pBuffer1 = (PBYTE)pSpec1 + sizeof(CATSEARCHSPEC);
|
|
pBuffer2 = (PBYTE)pSpec2 + sizeof(CATSEARCHSPEC);
|
|
|
|
do
|
|
{
|
|
//
|
|
// Make sure pSpec2 is at least pointing into the buffer we have, and
|
|
// that its length is within the buffer as well.
|
|
//
|
|
pEndOfBuffer = pBuffer + BufLength;
|
|
|
|
if (((PBYTE)pSpec2 >= pEndOfBuffer) ||
|
|
((PBYTE)pSpec2+pSpec2->__StructLength+sizeof(CATSEARCHSPEC)
|
|
> pEndOfBuffer))
|
|
{
|
|
DBGPRINT(DBG_COMP_AFPAPI_FD, DBG_LEVEL_ERR,
|
|
("UnpackCatSearchParms: Buffer not large enough!\n"));
|
|
Status = AFP_ERR_PARAM;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Validate that input buffer is long enough to hold all the info the
|
|
// bitmap says it does. Note we cannot yet account for the length of
|
|
// a longname string's characters if there was one specified.
|
|
//
|
|
MinSpecLength1 = MinSpecLength2 = sizeof(CATSEARCHSPEC) +
|
|
AfpGetFileDirParmsReplyLength(pFDParm1, Bitmap);
|
|
|
|
//
|
|
// HACK: In order to support LLPT, if the catsearch is
|
|
// asking to match filename, we should allow the Spec2 name to
|
|
// be missing from the buffer (as opposed to being the null string),
|
|
// but still expect the offset to the name.
|
|
//
|
|
// We also need to support system 7.1 who sends a zero length spec2
|
|
// if the Bitmap == FD_BITMAP_LONGNAME.
|
|
//
|
|
// Real Appleshare handles both these cases with no error.
|
|
//
|
|
|
|
if (Bitmap & FD_BITMAP_LONGNAME)
|
|
{
|
|
if (pSpec2->__StructLength == (MinSpecLength2-sizeof(CATSEARCHSPEC)-sizeof(BYTE)) )
|
|
{
|
|
MinSpecLength2 -= sizeof(BYTE);
|
|
NoNullString = True;
|
|
}
|
|
else if ((Bitmap == FD_BITMAP_LONGNAME) && (pSpec2->__StructLength == 0))
|
|
{
|
|
MinSpecLength2 -= sizeof(USHORT) + sizeof(BYTE);
|
|
NoNullString = True;
|
|
}
|
|
}
|
|
|
|
if ( ((MinSpecLength1 + MinSpecLength2) > BufLength) ||
|
|
(pSpec1->__StructLength < (MinSpecLength1-sizeof(CATSEARCHSPEC))) ||
|
|
(pSpec2->__StructLength < (MinSpecLength2-sizeof(CATSEARCHSPEC))) )
|
|
{
|
|
DBGPRINT(DBG_COMP_AFPAPI_FD, DBG_LEVEL_ERR,
|
|
("UnpackCatSearchParms: Buffer not large enough!\n"));
|
|
Status = AFP_ERR_PARAM;
|
|
break;
|
|
}
|
|
|
|
if (Bitmap & FD_BITMAP_ATTR)
|
|
{
|
|
|
|
GETSHORT2SHORT(&pFDParm1->_fdp_Attr, pBuffer1+Offset);
|
|
GETSHORT2SHORT(&pFDParm2->_fdp_Attr, pBuffer2+Offset);
|
|
if ((pFDParm2->_fdp_Attr & ~FD_BITMAP_ATTR_NT_RO) ||
|
|
(pFDParm2->_fdp_Attr == 0))
|
|
{
|
|
Status = AFP_ERR_PARAM;
|
|
break;
|
|
}
|
|
Offset += sizeof(USHORT);
|
|
}
|
|
if (Bitmap & FD_BITMAP_PARENT_DIRID)
|
|
{
|
|
GETDWORD2DWORD(&pFDParm1->_fdp_ParentId, pBuffer1+Offset);
|
|
GETDWORD2DWORD(&pFDParm2->_fdp_ParentId, pBuffer2+Offset);
|
|
if (pFDParm1->_fdp_ParentId < AFP_ID_ROOT)
|
|
{
|
|
Status = AFP_ERR_PARAM;
|
|
break;
|
|
}
|
|
Offset += sizeof(DWORD);
|
|
}
|
|
if (Bitmap & FD_BITMAP_CREATETIME)
|
|
{
|
|
GETDWORD2DWORD(&pFDParm1->_fdp_CreateTime, pBuffer1+Offset);
|
|
GETDWORD2DWORD(&pFDParm2->_fdp_CreateTime, pBuffer2+Offset);
|
|
Offset += sizeof(DWORD);
|
|
}
|
|
if (Bitmap & FD_BITMAP_MODIFIEDTIME)
|
|
{
|
|
GETDWORD2DWORD(&pFDParm1->_fdp_ModifiedTime, pBuffer1+Offset);
|
|
GETDWORD2DWORD(&pFDParm2->_fdp_ModifiedTime, pBuffer2+Offset);
|
|
Offset += sizeof(DWORD);
|
|
}
|
|
if (Bitmap & FD_BITMAP_BACKUPTIME)
|
|
{
|
|
GETDWORD2DWORD(&pFDParm1->_fdp_BackupTime, pBuffer1+Offset);
|
|
GETDWORD2DWORD(&pFDParm2->_fdp_BackupTime, pBuffer2+Offset);
|
|
Offset += sizeof(DWORD);
|
|
}
|
|
if (Bitmap & FD_BITMAP_FINDERINFO)
|
|
{
|
|
RtlCopyMemory((PBYTE)&pFDParm1->_fdp_FinderInfo,
|
|
pBuffer1+Offset,
|
|
sizeof(FINDERINFO));
|
|
|
|
RtlCopyMemory((PBYTE)&pFDParm2->_fdp_FinderInfo,
|
|
pBuffer2+Offset,
|
|
sizeof(FINDERINFO));
|
|
|
|
Offset += sizeof(FINDERINFO);
|
|
}
|
|
if (Bitmap & FD_BITMAP_LONGNAME)
|
|
{
|
|
DWORD NameOffset1, NameOffset2;
|
|
|
|
//
|
|
// Get the parm relative offset to the start of the pascal string
|
|
//
|
|
|
|
GETSHORT2DWORD(&NameOffset1, pBuffer1+Offset);
|
|
if ((Bitmap == FD_BITMAP_LONGNAME) && (pSpec2->__StructLength == 0))
|
|
{
|
|
// HACK for system 7.1
|
|
NameOffset2 = NameOffset1;
|
|
pBuffer2 = NULL;
|
|
}
|
|
else
|
|
GETSHORT2DWORD(&NameOffset2, pBuffer2+Offset);
|
|
|
|
if ((NameOffset1 != NameOffset2) ||
|
|
(pBuffer1 + NameOffset1 >= (PBYTE)pSpec2) ||
|
|
(pBuffer2 + NameOffset2 > pEndOfBuffer))
|
|
{
|
|
Status = AFP_ERR_PARAM;
|
|
break;
|
|
}
|
|
Offset += sizeof(USHORT);
|
|
|
|
//
|
|
// Get the pascal string length
|
|
//
|
|
|
|
GETBYTE2SHORT(&pFDParm1->_fdp_LongName.Length, pBuffer1+NameOffset1);
|
|
|
|
// HACK: In order to support LLPT and system 7.1, if the catsearch is
|
|
// asking to match filename, we should allow the Spec2 name to
|
|
// be missing from the buffer (as opposed to being the null string).
|
|
// Real Appleshare handles this case with no error.
|
|
if (NoNullString)
|
|
pFDParm2->_fdp_LongName.Length = 0;
|
|
else
|
|
GETBYTE2SHORT(&pFDParm2->_fdp_LongName.Length, pBuffer2+NameOffset1);
|
|
|
|
if ((pFDParm1->_fdp_LongName.Length > AFP_LONGNAME_LEN) ||
|
|
(pFDParm2->_fdp_LongName.Length != 0) ||
|
|
(pBuffer1+NameOffset1+sizeof(BYTE)+pFDParm1->_fdp_LongName.Length > (PBYTE)pSpec2))
|
|
{
|
|
// Specification 2 must always have a nil name field. Also
|
|
// ensure that Specification 1 does not have a bogus string
|
|
// length.
|
|
Status = AFP_ERR_PARAM;
|
|
break;
|
|
}
|
|
RtlCopyMemory(pFDParm1->_fdp_LongName.Buffer,
|
|
pBuffer1+NameOffset1+sizeof(BYTE),
|
|
pFDParm1->_fdp_LongName.Length);
|
|
AfpConvertStringToMungedUnicode(&pFDParm1->_fdp_LongName, pMatchString);
|
|
}
|
|
// OFFSPRINGS bit for directories, DATALEN bit for files are the same
|
|
if (Bitmap & DIR_BITMAP_OFFSPRINGS)
|
|
{
|
|
ASSERT(pFDParm1->_fdp_Flags != (DFE_FLAGS_FILE_WITH_ID | DFE_FLAGS_DIR));
|
|
if (IsDir(pFDParm1))
|
|
{
|
|
// We have to combine total offspring count into the
|
|
// FileCount field here since the API does not separate
|
|
// them into separate file and dir offspring counts
|
|
GETSHORT2DWORD(&pFDParm1->_fdp_FileCount, pBuffer1+Offset);
|
|
GETSHORT2DWORD(&pFDParm2->_fdp_FileCount, pBuffer2+Offset);
|
|
Offset += sizeof(USHORT);
|
|
}
|
|
else
|
|
{
|
|
GETDWORD2DWORD(&pFDParm1->_fdp_DataForkLen, pBuffer1+Offset);
|
|
GETDWORD2DWORD(&pFDParm2->_fdp_DataForkLen, pBuffer2+Offset);
|
|
Offset += sizeof(DWORD);
|
|
}
|
|
}
|
|
if (Bitmap & FILE_BITMAP_RESCLEN)
|
|
{
|
|
ASSERT(pFDParm1->_fdp_Flags == DFE_FLAGS_FILE_WITH_ID);
|
|
GETDWORD2DWORD(&pFDParm1->_fdp_RescForkLen, pBuffer1+Offset);
|
|
GETDWORD2DWORD(&pFDParm2->_fdp_RescForkLen, pBuffer2+Offset);
|
|
Offset += sizeof(DWORD);
|
|
}
|
|
|
|
} while (False);
|
|
|
|
return Status;
|
|
}
|
|
|
|
/*** AfpIsCatSearchMatch
|
|
*
|
|
* Given a DFE and a set of search criteria, see if this item should be
|
|
* returned as a match in the catalog search.
|
|
*
|
|
*
|
|
* LOCKS_ASSUMED: vds_IdDbAccessLock (SWMR, Exclusive)
|
|
*/
|
|
SHORT
|
|
AfpIsCatSearchMatch(
|
|
IN PDFENTRY pDFE,
|
|
IN DWORD Bitmap, // Search criteria
|
|
IN DWORD ReplyBitmap, // Info to return
|
|
IN PFILEDIRPARM pFDParm1,
|
|
IN PFILEDIRPARM pFDParm2,
|
|
IN PUNICODE_STRING pMatchName OPTIONAL
|
|
)
|
|
{
|
|
BOOLEAN IsMatch = True;
|
|
SHORT Length = 0;
|
|
|
|
PAGED_CODE();
|
|
|
|
do
|
|
{
|
|
|
|
if (Bitmap & FD_BITMAP_ATTR)
|
|
{
|
|
FILEDIRPARM fdp;
|
|
|
|
fdp._fdp_Attr = pDFE->dfe_AfpAttr;
|
|
AfpNormalizeAfpAttr(&fdp, pDFE->dfe_NtAttr);
|
|
|
|
if ((fdp._fdp_Attr & pFDParm2->_fdp_Attr) != pFDParm1->_fdp_Attr)
|
|
|
|
{
|
|
IsMatch = False;
|
|
break;
|
|
}
|
|
}
|
|
if (Bitmap & FD_BITMAP_PARENT_DIRID)
|
|
{
|
|
if ((pDFE->dfe_Parent->dfe_AfpId < pFDParm1->_fdp_ParentId) ||
|
|
(pDFE->dfe_Parent->dfe_AfpId > pFDParm2->_fdp_ParentId))
|
|
{
|
|
IsMatch = False;
|
|
break;
|
|
}
|
|
}
|
|
if (Bitmap & FD_BITMAP_CREATETIME)
|
|
{
|
|
if (((AFPTIME)pDFE->dfe_CreateTime < (AFPTIME)pFDParm1->_fdp_CreateTime) ||
|
|
((AFPTIME)pDFE->dfe_CreateTime > (AFPTIME)pFDParm2->_fdp_CreateTime))
|
|
{
|
|
IsMatch = False;
|
|
break;
|
|
}
|
|
}
|
|
if (Bitmap & FD_BITMAP_MODIFIEDTIME)
|
|
{
|
|
AFPTIME ModTime;
|
|
|
|
ModTime = AfpConvertTimeToMacFormat(&pDFE->dfe_LastModTime);
|
|
if ((ModTime < pFDParm1->_fdp_ModifiedTime) ||
|
|
(ModTime > pFDParm2->_fdp_ModifiedTime))
|
|
{
|
|
IsMatch = False;
|
|
break;
|
|
}
|
|
}
|
|
if (Bitmap & FD_BITMAP_BACKUPTIME)
|
|
{
|
|
if ((pDFE->dfe_BackupTime < pFDParm1->_fdp_BackupTime) ||
|
|
(pDFE->dfe_BackupTime > pFDParm2->_fdp_BackupTime))
|
|
{
|
|
IsMatch = False;
|
|
break;
|
|
}
|
|
}
|
|
if (Bitmap & FD_BITMAP_FINDERINFO)
|
|
{
|
|
int i;
|
|
PBYTE pF, p1, p2;
|
|
FINDERINFO FinderInfo;
|
|
|
|
// NOTE: why doesn't dfe_FinderInfo.Attr1 correctly reflect the
|
|
// Nt Hidden attribute in the first place?
|
|
FinderInfo = pDFE->dfe_FinderInfo;
|
|
if (pDFE->dfe_NtAttr & FILE_ATTRIBUTE_HIDDEN)
|
|
FinderInfo.fd_Attr1 |= FINDER_FLAG_INVISIBLE;
|
|
|
|
pF = (PBYTE) &FinderInfo;
|
|
p1 = (PBYTE) &pFDParm1->_fdp_FinderInfo;
|
|
p2 = (PBYTE) &pFDParm2->_fdp_FinderInfo;
|
|
|
|
for (i = 0; i < sizeof(FINDERINFO); i++)
|
|
{
|
|
if ((*pF++ & *p2++) != *p1++)
|
|
{
|
|
IsMatch = False;
|
|
break; // out of for loop
|
|
}
|
|
}
|
|
|
|
if (IsMatch == False)
|
|
break; // out of while loop
|
|
}
|
|
if (Bitmap & FD_BITMAP_LONGNAME)
|
|
{
|
|
ASSERT(ARGUMENT_PRESENT(pMatchName));
|
|
|
|
if (pFDParm2->_fdp_fPartialName)
|
|
{
|
|
// Name must contain substring
|
|
if (!AfpIsProperSubstring(&pDFE->dfe_UnicodeName, pMatchName))
|
|
{
|
|
IsMatch = False;
|
|
break;
|
|
}
|
|
}
|
|
else if (!EQUAL_UNICODE_STRING(&pDFE->dfe_UnicodeName, pMatchName, True))
|
|
{
|
|
// Whole name must match
|
|
IsMatch = False;
|
|
break;
|
|
}
|
|
}
|
|
if (Bitmap & FILE_BITMAP_DATALEN)
|
|
{
|
|
// This bit is also used as DIR_BITMAP_OFFSPRINGS for directories
|
|
if (IsDir(pFDParm1))
|
|
{
|
|
DWORD count;
|
|
|
|
ASSERT(DFE_IS_DIRECTORY(pDFE) && DFE_CHILDREN_ARE_PRESENT(pDFE));
|
|
|
|
count = pDFE->dfe_DirOffspring + pDFE->dfe_FileOffspring;
|
|
|
|
// In this case, _fdp_FileCount holds total # of files and dirs
|
|
if ((count < pFDParm1->_fdp_FileCount) ||
|
|
(count > pFDParm2->_fdp_FileCount))
|
|
{
|
|
IsMatch = False;
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ASSERT(DFE_IS_FILE(pDFE));
|
|
|
|
if ((pDFE->dfe_DataLen < pFDParm1->_fdp_DataForkLen) ||
|
|
(pDFE->dfe_DataLen > pFDParm2->_fdp_DataForkLen))
|
|
{
|
|
IsMatch = False;
|
|
break;
|
|
}
|
|
}
|
|
|
|
}
|
|
if (Bitmap & FILE_BITMAP_RESCLEN)
|
|
{
|
|
ASSERT(DFE_IS_FILE(pDFE));
|
|
|
|
if ((pDFE->dfe_RescLen < pFDParm1->_fdp_RescForkLen) ||
|
|
(pDFE->dfe_RescLen > pFDParm2->_fdp_RescForkLen))
|
|
{
|
|
IsMatch = False;
|
|
break;
|
|
}
|
|
}
|
|
|
|
} while (False);
|
|
|
|
if (IsMatch)
|
|
{
|
|
Length = 2 * sizeof(BYTE); // Struct Length plus File/Dir Flag
|
|
if (ReplyBitmap & FD_BITMAP_PARENT_DIRID)
|
|
{
|
|
Length += sizeof(DWORD);
|
|
}
|
|
if (ReplyBitmap & FD_BITMAP_LONGNAME)
|
|
{
|
|
// Offset to string + pascal string length + characters
|
|
#ifdef DBCS
|
|
// FiX #11992 SFM: As a result of search, I get incorrect file information.
|
|
// 1996.09.26 V-HIDEKK
|
|
{
|
|
ANSI_STRING AName;
|
|
BYTE NameBuf[AFP_LONGNAME_LEN+1];
|
|
|
|
AfpInitAnsiStringWithNonNullTerm(&AName, sizeof(NameBuf), NameBuf);
|
|
AfpConvertMungedUnicodeToAnsi(&pDFE->dfe_UnicodeName, &AName);
|
|
Length += sizeof(USHORT) + sizeof(BYTE) + AName.Length;
|
|
}
|
|
#else
|
|
Length += sizeof(USHORT) + sizeof(BYTE) + pDFE->dfe_UnicodeName.Length/sizeof(WCHAR);
|
|
#endif
|
|
}
|
|
Length = EVENALIGN(Length);
|
|
}
|
|
|
|
return Length;
|
|
}
|
|
|
|
|