windows-nt/Source/XPSP1/NT/com/ole32/stg/docfile/funcs.cxx
2020-09-26 16:20:57 +08:00

736 lines
20 KiB
C++

//+--------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1992 - 1992.
//
// File: funcs.cxx
//
// Contents: Generic DocFile support functions
//
// Functions: ModeToTFlags
// CheckName
// VerifyPerms
//
// History: 22-Jan-92 DrewB Created
//
//---------------------------------------------------------------
#include <dfhead.cxx>
#pragma hdrstop
#include <df32.hxx>
//+--------------------------------------------------------------
//
// Function: ModeToDFlags, private
//
// Synopsis: Translates STGM flags to DF flags
//
// Arguments: [dwModeFlags]
//
// Returns: DF_*
//
// History: 04-Feb-92 DrewB Created
//
//---------------------------------------------------------------
DFLAGS ModeToDFlags(DWORD const dwModeFlags)
{
DFLAGS df;
olDebugOut((DEB_ITRACE, "In ModeToDFlags(%lX)\n", dwModeFlags));
if ((dwModeFlags & STGM_TRANSACTED) == 0)
df = DF_DIRECT;
else
df = DF_TRANSACTED;
if ((dwModeFlags & STGM_TRANSACTED) &&
(dwModeFlags & STGM_PRIORITY) == 0 &&
(dwModeFlags & STGM_DENY) != STGM_SHARE_DENY_WRITE &&
(dwModeFlags & STGM_DENY) != STGM_SHARE_EXCLUSIVE)
df |= DF_INDEPENDENT;
switch(dwModeFlags & STGM_RDWR)
{
case STGM_READ:
df |= DF_READ;
break;
case STGM_WRITE:
df |= DF_WRITE;
break;
case STGM_READWRITE:
df |= DF_READWRITE;
break;
default:
olAssert(FALSE);
break;
}
switch(dwModeFlags & STGM_DENY)
{
case STGM_SHARE_DENY_READ:
df |= DF_DENYREAD;
break;
case STGM_SHARE_DENY_WRITE:
df |= DF_DENYWRITE;
break;
case STGM_SHARE_EXCLUSIVE:
df |= DF_DENYALL;
break;
// Default is deny none
}
if (dwModeFlags & STGM_PRIORITY)
df |= DF_PRIORITY;
#ifdef USE_NOSNAPSHOT_ALWAYS
//This makes all transacted-writeable !deny-write instances no-snapshot,
// for testing.
if ((dwModeFlags & STGM_TRANSACTED) &&
!(df & DF_DENYWRITE) &&
(df & DF_WRITE))
{
df |= DF_NOSNAPSHOT;
df &= ~DF_INDEPENDENT;
}
#else
if (dwModeFlags & STGM_NOSNAPSHOT)
{
df |= DF_NOSNAPSHOT;
df &= ~DF_INDEPENDENT;
}
#endif //USE_NOSNAPSHOT_ALWAYS
#ifdef USE_NOSCRATCH_ALWAYS
//This makes everything NOSCRATCH, for testing.
if ((dwModeFlags & STGM_TRANSACTED) && (df & DF_WRITE))
df |= DF_NOSCRATCH;
#else
if (dwModeFlags & STGM_NOSCRATCH)
df |= DF_NOSCRATCH;
#endif
#if WIN32 == 300
if (dwModeFlags & STGM_EDIT_ACCESS_RIGHTS)
df |= DF_ACCESSCONTROL;
#endif
olDebugOut((DEB_ITRACE, "Out ModeToDFlags => %lX\n", df));
return df;
}
//+--------------------------------------------------------------
//
// Function: DFlagsToMode, private
//
// Synopsis: Converts the read/write/denials/transacted/priority
// to STGM flags
//
// Arguments: [df] - DFlags
//
// Returns: STGM flags
//
// History: 24-Jul-92 DrewB Created
//
//---------------------------------------------------------------
DWORD DFlagsToMode(DFLAGS const df)
{
DWORD dwMode = 0;
olDebugOut((DEB_ITRACE, "In DFlagsToMode(%X)\n", df));
if (P_READ(df))
if (P_WRITE(df))
dwMode = STGM_READWRITE;
else
dwMode = STGM_READ;
else if (P_WRITE(df))
dwMode = STGM_WRITE;
// Must have either read or write, so no else
if (P_DENYREAD(df))
if (P_DENYWRITE(df))
dwMode |= STGM_SHARE_EXCLUSIVE;
else
dwMode |= STGM_SHARE_DENY_READ;
else if (P_DENYWRITE(df))
dwMode |= STGM_SHARE_DENY_WRITE;
else
dwMode |= STGM_SHARE_DENY_NONE;
if (P_TRANSACTED(df))
dwMode |= STGM_TRANSACTED;
if (P_PRIORITY(df))
dwMode |= STGM_PRIORITY;
if (P_NOSCRATCH(df))
dwMode |= STGM_NOSCRATCH;
if (P_NOSNAPSHOT(df))
dwMode |= STGM_NOSNAPSHOT;
olDebugOut((DEB_ITRACE, "Out DFlagsToMode\n"));
return dwMode;
}
//+--------------------------------------------------------------
//
// Function: VerifyPerms, private
//
// Synopsis: Checks flags to see if they are valid
//
// Arguments: [grfMode] - Permissions
// [fRoot] - TRUE if checking root storage
//
// Returns: Appropriate status code
//
// Notes: This routine is called when opening a root storage
// or a subelement. When changing root permissions,
// use the fRoot flag to preserve compatibily for
// return codes when opening subelements
//
// History: 19-Mar-92 DrewB Created
//
//---------------------------------------------------------------
SCODE VerifyPerms(DWORD grfMode, BOOL fRoot)
{
SCODE sc = S_OK;
olDebugOut((DEB_ITRACE, "In VerifyPerms(%lX)\n", grfMode));
// Check for valid flags
if ((grfMode & STGM_RDWR) > STGM_READWRITE ||
(grfMode & STGM_DENY) > STGM_SHARE_DENY_NONE ||
(grfMode & ~(STGM_RDWR | STGM_DENY | STGM_DIRECT | STGM_TRANSACTED |
STGM_PRIORITY | STGM_CREATE | STGM_CONVERT | STGM_SIMPLE |
STGM_NOSCRATCH |
#ifndef DISABLE_NOSNAPSHOT
STGM_NOSNAPSHOT |
#endif
#if WIN32 >= 300
STGM_EDIT_ACCESS_RIGHTS |
#endif
#ifdef DIRECTWRITERLOCK
STGM_DIRECT_SWMR |
#endif
STGM_FAILIFTHERE | STGM_DELETEONRELEASE)))
olErr(EH_Err, STG_E_INVALIDFLAG);
// If priority is specified...
if (grfMode & STGM_PRIORITY)
{
// Make sure no priority-denied permissions are specified
if ((grfMode & STGM_RDWR) == STGM_WRITE ||
(grfMode & STGM_RDWR) == STGM_READWRITE ||
(grfMode & STGM_TRANSACTED))
olErr(EH_Err, STG_E_INVALIDFLAG);
}
// Check to make sure only one existence flag is specified
// FAILIFTHERE is zero so it can't be checked
if ((grfMode & (STGM_CREATE | STGM_CONVERT)) ==
(STGM_CREATE | STGM_CONVERT))
olErr(EH_Err, STG_E_INVALIDFLAG);
// If not transacted and not priority, you can either be
// read-only deny write or read-write deny all
if ((grfMode & (STGM_TRANSACTED | STGM_PRIORITY)) == 0)
{
if ((grfMode & STGM_RDWR) == STGM_READ)
{
// we're asking for read-only access
if ((grfMode & STGM_DENY) != STGM_SHARE_EXCLUSIVE &&
#ifdef DIRECTWRITERLOCK
(!fRoot ||
(grfMode & STGM_DIRECT_SWMR) == 0 ||
(grfMode & STGM_DENY) != STGM_SHARE_DENY_NONE) &&
#endif
(grfMode & STGM_DENY) != STGM_SHARE_DENY_WRITE)
{
// Can't allow others to have write access
olErr(EH_Err, STG_E_INVALIDFLAG);
}
}
else
{
// we're asking for write access
#ifdef DIRECTWRITERLOCK
if ((grfMode & STGM_DENY) != STGM_SHARE_EXCLUSIVE &&
(!fRoot ||
(grfMode & STGM_DIRECT_SWMR) == 0 ||
(grfMode & STGM_DENY) != STGM_SHARE_DENY_WRITE))
#else
if ((grfMode & STGM_DENY) != STGM_SHARE_EXCLUSIVE)
#endif
{
// Can't allow others to have any access
olErr(EH_Err, STG_E_INVALIDFLAG);
}
}
}
//If this is not a root open, we can't pass STGM_NOSCRATCH or
// STGM_NOSNAPSHOT
if (!fRoot && (grfMode & (STGM_NOSCRATCH | STGM_NOSNAPSHOT)))
{
olErr(EH_Err, STG_E_INVALIDFLAG);
}
if (grfMode & STGM_NOSCRATCH)
{
if (((grfMode & STGM_RDWR) == STGM_READ) ||
((grfMode & STGM_TRANSACTED) == 0))
{
olErr(EH_Err, STG_E_INVALIDFLAG);
}
}
if (grfMode & STGM_NOSNAPSHOT)
{
if (((grfMode & STGM_DENY) == STGM_SHARE_EXCLUSIVE) ||
((grfMode & STGM_DENY) == STGM_SHARE_DENY_WRITE) ||
((grfMode & STGM_TRANSACTED) == 0) ||
((grfMode & STGM_NOSCRATCH) != 0) ||
((grfMode & STGM_CREATE) != 0) ||
((grfMode & STGM_CONVERT) != 0))
{
olErr(EH_Err, STG_E_INVALIDFLAG);
}
}
olDebugOut((DEB_ITRACE, "Out VerifyPerms\n"));
// Fall through
EH_Err:
return sc;
}
//+---------------------------------------------------------------------------
//
// Member: ValidateNameW, public
//
// Synopsis: Validate that a name is valid and no longer than the
// size specified.
//
// Arguments: [pwcsName] -- Pointer to wide character string
// [cchMax] -- Maximum length for string
//
// Returns: Appropriate status code
//
// History: 23-Nov-98 PhilipLa Created
//
// Notes:
//
//----------------------------------------------------------------------------
SCODE ValidateNameW(LPCWSTR pwcsName, UINT cchMax)
{
SCODE sc = S_OK;
#if WIN32 == 200
if (IsBadReadPtrW(pwcsName, sizeof(WCHAR)))
sc = STG_E_INVALIDNAME;
#else
if (IsBadStringPtrW(pwcsName, cchMax))
sc = STG_E_INVALIDNAME;
#endif
else
{
__try
{
if ((UINT)lstrlenW(pwcsName) >= cchMax)
sc = STG_E_INVALIDNAME;
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
sc = STG_E_INVALIDNAME;
}
}
return sc;
}
//+--------------------------------------------------------------
//
// Function: CheckName, public
//
// Synopsis: Checks name for illegal characters and length
//
// Arguments: [pwcsName] - Name
//
// Returns: Appropriate status code
//
// History: 11-Feb-92 DrewB Created
// 04-Dec-95 SusiA Optimized
//
//---------------------------------------------------------------
SCODE CheckName(WCHAR const *pwcsName)
{
LPCWSTR pChar;
//Each character's position in the array is detrmined by its ascii numeric
//value. ":" is 58, so bit 58 of the array will be 1 if ":" is illegal.
//32bits per position in the array, so 58/32 is in Invalid[1].
//58%32 = 28th bit ( 0x04000000 ) in Invalid[1].
/* Invalid characters: : / ! \ */
static ULONG const Invalid[128/32] =
{0x00000000,0x04008002,0x10000000,0x00000000};
SCODE sc = STG_E_INVALIDNAME;
olDebugOut((DEB_ITRACE, "In CheckName(%ws)\n", pwcsName));
__try
{
for (pChar = (LPCWSTR)pwcsName;
pChar < (LPCWSTR) &pwcsName[CWCMAXPATHCOMPLEN];
pChar++)
{
if (*pChar == L'\0')
{
sc = S_OK;
break; // Success
}
// Test to see if this is an invalid character
if (*pChar < 128 &&
// All values above 128 are valid
(Invalid[*pChar / 32] & (1 << (*pChar % 32))) != 0)
// check to see if this character's bit is set
{
break; // Failure: invalid Char
}
}
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
}
olDebugOut((DEB_ITRACE, "Out CheckName\n"));
return sc;
}
//+--------------------------------------------------------------
//
// Function: ValidateSNB, private
//
// Synopsis: Validates SNB memory
//
// Arguments: [snb] - SNB
//
// Returns: Appropriate status code
//
// History: 10-Jun-92 DrewB Created
//
//---------------------------------------------------------------
SCODE ValidateSNB(SNBW snb)
{
SCODE sc;
olDebugOut((DEB_ITRACE, "In ValidateSNB(%p)\n", snb));
for (;;)
{
olChk(ValidatePtrBuffer(snb));
if (*snb == NULL)
break;
olChk(ValidateNameW(*snb, CWCMAXPATHCOMPLEN));
snb++;
}
olDebugOut((DEB_ITRACE, "Out ValidateSNB\n"));
return S_OK;
EH_Err:
return sc;
}
//+--------------------------------------------------------------
//
// Function: CopySStreamToSStream
//
// Synopsis: Copies the contents of a stream to another stream
//
// Arguments: [psstFrom] - Stream to copy from
// [psstTo] - Stream to copy to
//
// Returns: Appropriate status code
//
// History: 13-Sep-91 DrewB Created
//
// Notes: This function may fail due to out of memory. It
// may not be used by callers who must not fail due
// to out of memory.
//
//---------------------------------------------------------------
SCODE CopySStreamToSStream(PSStream *psstFrom, PSStream *psstTo)
{
BYTE *pbBuffer = NULL;
SCODE sc;
#ifdef LARGE_STREAMS
ULONGLONG cbSize = 0, cbPos;
ULONG cbRead, cbWritten;
#else
ULONG cbRead, cbWritten, cbSize, cbPos;
#endif
// We're allowed to fail due to out of memory
olMem(pbBuffer = (BYTE *) DfMemAlloc(STREAMBUFFERSIZE));
// Set destination size for contiguity
psstFrom->GetSize(&cbSize);
olChk(psstTo->SetSize(cbSize));
// Copy between streams
cbPos = 0;
for (;;)
{
olChk(psstFrom->ReadAt(cbPos, pbBuffer, STREAMBUFFERSIZE,
(ULONG STACKBASED *)&cbRead));
if (cbRead == 0) // EOF
break;
olChk(psstTo->WriteAt(cbPos, pbBuffer, cbRead,
(ULONG STACKBASED *)&cbWritten));
if (cbRead != cbWritten)
olErr(EH_Err, STG_E_WRITEFAULT);
cbPos += cbWritten;
}
EH_Err:
DfMemFree(pbBuffer);
return sc;
}
//+---------------------------------------------------------------------------
//
// Function: dfwcsnicmp, public
//
// Synopsis: wide character string compare that interoperates with what
// we did on 16-bit windows.
//
// Arguments: [wcsa] -- First string
// [wcsb] -- Second string
// [len] -- Length to compare to
//
// Returns: > 0 if wcsa > wcsb
// < 0 if wcsa < wcsb
// 0 is wcsa == wcsb
//
// History: 11-May-95 PhilipLa Created
// 22-Nov-95 SusiA Optimize comparisons
//
// Notes: This function is necessary because on 16-bit windows our
// wcsnicmp function converted everything to uppercase and
// compared the strings, whereas the 32-bit runtimes convert
// everything to lowercase and compare. This means that the
// sort order is different for string containing [\]^_`
//
//----------------------------------------------------------------------------
int dfwcsnicmp(const WCHAR *wcsa, const WCHAR *wcsb, size_t len)
{
if (!len)
return 0;
while (--len && *wcsa &&
( *wcsa == *wcsb ||
CharUpperW((LPWSTR)*wcsa) == CharUpperW((LPWSTR)*wcsb)))
{
wcsa++;
wcsb++;
}
return (int)(LONG_PTR)CharUpperW((LPWSTR)*wcsa) -
(int)(LONG_PTR)CharUpperW((LPWSTR)*wcsb);
}
//+--------------------------------------------------------------
//
// Function: NameInSNB, private
//
// Synopsis: Determines whether the given name is in the SNB
//
// Arguments: [dfn] - Name
// [snb] - SNB
//
// Returns: S_OK or S_FALSE
//
// History: 19-Mar-92 DrewB Created
//
//---------------------------------------------------------------
SCODE NameInSNB(CDfName const *dfn, SNBW snb)
{
SCODE sc = S_FALSE;
olDebugOut((DEB_ITRACE, "In NameInSNB(%ws, %p)\n", dfn, snb));
TRY
{
for (; *snb; snb++)
if ((lstrlenW(*snb)+1)*sizeof(WCHAR) == dfn->GetLength() &&
#ifdef CASE_SENSITIVE
memcmp(dfn->GetBuffer(), *snb, dfn->GetLength()) == 0)
#else
dfwcsnicmp((WCHAR *)dfn->GetBuffer(), (WCHAR *)*snb,
dfn->GetLength()/sizeof(WCHAR)) == 0)
#endif
{
sc = S_OK;
break;
}
}
CATCH(CException, e)
{
sc = e.GetErrorCode();
}
END_CATCH
olDebugOut((DEB_ITRACE, "Out NameInSNB\n"));
return sc;
}
//+---------------------------------------------------------------------------
//
// Function: Win32ErrorToScode, public
//
// Synopsis: Map a Win32 error into a corresponding scode, remapping
// into Facility_Storage if appropriate.
//
// Arguments: [dwErr] -- Win32 error to map
//
// Returns: Appropriate scode
//
// History: 22-Sep-93 PhilipLa Created
//
//----------------------------------------------------------------------------
SCODE Win32ErrorToScode(DWORD dwErr)
{
olAssert((dwErr != NO_ERROR) &&
aMsg("Win32ErrorToScode called on NO_ERROR"));
SCODE sc = STG_E_UNKNOWN;
switch (dwErr)
{
case ERROR_INVALID_FUNCTION:
sc = STG_E_INVALIDFUNCTION;
break;
case ERROR_FILE_NOT_FOUND:
sc = STG_E_FILENOTFOUND;
break;
case ERROR_PATH_NOT_FOUND:
sc = STG_E_PATHNOTFOUND;
break;
case ERROR_TOO_MANY_OPEN_FILES:
sc = STG_E_TOOMANYOPENFILES;
break;
case ERROR_ACCESS_DENIED:
case ERROR_NETWORK_ACCESS_DENIED:
sc = STG_E_ACCESSDENIED;
break;
case ERROR_INVALID_HANDLE:
sc = STG_E_INVALIDHANDLE;
break;
case ERROR_NOT_ENOUGH_MEMORY:
sc = STG_E_INSUFFICIENTMEMORY;
break;
case ERROR_NO_MORE_FILES:
sc = STG_E_NOMOREFILES;
break;
case ERROR_WRITE_PROTECT:
sc = STG_E_DISKISWRITEPROTECTED;
break;
case ERROR_SEEK:
sc = STG_E_SEEKERROR;
break;
case ERROR_WRITE_FAULT:
sc = STG_E_WRITEFAULT;
break;
case ERROR_READ_FAULT:
sc = STG_E_READFAULT;
break;
case ERROR_SHARING_VIOLATION:
sc = STG_E_SHAREVIOLATION;
break;
case ERROR_LOCK_VIOLATION:
sc = STG_E_LOCKVIOLATION;
break;
case ERROR_HANDLE_DISK_FULL:
case ERROR_DISK_FULL:
sc = STG_E_MEDIUMFULL;
break;
case ERROR_FILE_EXISTS:
case ERROR_ALREADY_EXISTS:
sc = STG_E_FILEALREADYEXISTS;
break;
case ERROR_INVALID_PARAMETER:
sc = STG_E_INVALIDPARAMETER;
break;
case ERROR_INVALID_NAME:
case ERROR_BAD_PATHNAME:
case ERROR_FILENAME_EXCED_RANGE:
sc = STG_E_INVALIDNAME;
break;
case ERROR_INVALID_FLAGS:
sc = STG_E_INVALIDFLAG;
break;
case ERROR_CANT_ACCESS_FILE:
sc= STG_E_DOCFILECORRUPT;
break;
default:
sc = WIN32_SCODE(dwErr);
break;
}
return sc;
}
//+---------------------------------------------------------------------------
//
// Function: IsValidStgInterface
//
// Synopsis: a copy of the old IsValidInterface() from COM
//
// Arguments: [pv] -- interface to validate
//
// Returns: Appropriate flag
//
// History: 08-May-2000 HenryLee Created
//
//----------------------------------------------------------------------------
BOOL IsValidStgInterface( void * pv )
{
ULONG_PTR * pVtbl;
BYTE * pFcn;
volatile BYTE bInstr;
__try {
pVtbl = *(ULONG_PTR **) pv; // beginning of vtable
#if DBG==1
for (int i=0 ; i<3; ++i) // loop through qi,addref,rel
#else
int i=1; // in retail, just do AddRef
#endif
{
pFcn = *(BYTE **) &pVtbl[i];
#if DBG==1
if (IsBadCodePtr((FARPROC)pFcn)) {
return FALSE;
}
#endif
bInstr = *(BYTE *) pFcn; // get 1st byte of 1st instruction
}
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
return FALSE;
}
return TRUE;
}