Leaked source code of windows server 2003
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.
 
 
 
 
 
 

1009 lines
29 KiB

//+---------------------------------------------------------------------------
//
// Microsoft Windows NT Security
// Copyright (C) Microsoft Corporation, 1997 - 1999
//
// File: updcat.cpp
//
// Contents: Update Catalog Entry
//
// History: 02-Sep-98 kirtd Created
//
//----------------------------------------------------------------------------
#include <windows.h>
#include <assert.h>
#include "wincrypt.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <memory.h>
#include <time.h>
#include <mscat.h>
#include <mssip.h>
#include <sipguids.h>
#include <wintrust.h>
// Prototypes
// BOOL AddFileToCatalog (IN HANDLE hCatalog, IN LPWSTR pwszFileName);
BOOL RemoveHashFromCatalog(IN LPWSTR pwszCatalogFile, IN LPSTR pszHash);
BOOL AddFileOrAuthAttrToCatalog(IN HANDLE hCatalog, IN LPWSTR pwszFileName,
IN DWORD dwAttrFlags, IN LPWSTR pwszAttrName,
IN LPWSTR pwszAttrValue);
BOOL CheckFileSize(IN LPWSTR pFileName, IN ULONG size);
extern "C" BOOL MsCatConstructHashTag (IN DWORD cbDigest, IN LPBYTE pbDigest, OUT LPWSTR* ppwszHashTag);
extern "C" VOID MsCatFreeHashTag (IN LPWSTR pwszHashTag);
#define AddFileToCatalog(cat, file) AddFileOrAuthAttrToCatalog(cat, file, 0, NULL, NULL)
#define PWSZ_SPATTR L"SpAttr"
#define PSZ_SPATTR_OPTION "-SpAttr:"
ULONG sizeLimit = 0;
//+---------------------------------------------------------------------------
//
// Function: Usage
//
// Synopsis: prints the usage statement
//
//----------------------------------------------------------------------------
static void Usage(void)
{
printf("Usage: updcat <Catalog File> [-s <Size>] [-a <FileName>]\n");
printf("Usage: updcat <Catalog File> [-d <Hash>]\n");
printf("Usage: updcat <Catalog File> [-s <Size>] [-r <Hash> <FileName>]\n");
printf("Usage: updcat <Catalog File> [-attr <FileName> <Name> <Value>]\n");
printf(" -a, add the file by hash to the catalog\n");
printf(" -d, delete the hash from the catalog\n");
printf(" -r, replace the hash in the catalog with the hash of the file\n");
printf(" -s, fail if the file is smaller than this size (in bytes)\n");
printf(" -attr, add an ASCII attribute to a file's catalog entry\n");
printf(" -SpAttr:, replace the current (or add new) SpAttr in the catalog\n");
}
//+---------------------------------------------------------------------------
//
// Function: main
//
// Synopsis: main program entry point
//
//----------------------------------------------------------------------------
int _cdecl main(int argc, char * argv[])
{
BOOL fResult = TRUE;
LPSTR pszCatalogFile = NULL;
LPWSTR pwszCatalogFile = NULL;
LPSTR pszFileName = NULL;
LPSTR pszHash = NULL;
LPWSTR pwszFileName = NULL;
LPSTR pszAttrName = NULL;
LPWSTR pwszAttrName = NULL;
LPSTR pszAttrValue = NULL;
LPWSTR pwszAttrValue = NULL;
BOOL fAddEntry = FALSE;
DWORD cch = 0;
HANDLE hCatalog = NULL;
BOOL fOptionChosen = FALSE;
LPWSTR pwszSpAttr = NULL;
CRYPTCATATTRIBUTE *pCatAttr = NULL;
if ( argc < 2 )
{
Usage();
return( 1 );
}
argv++;
argc--;
printf( "command line: %s\n", GetCommandLineA() );
pszCatalogFile = argv[0];
cch = strlen( pszCatalogFile );
while ( --argc > 0 )
{
if ( **++argv == '-' )
{
switch( argv[0][1] )
{
case 'a':
case 'A':
if ( argc < 2 )
{
Usage();
return( 1 );
}
pszFileName = argv[1];
fAddEntry = TRUE;
if (_strcmpi(&argv[0][1], "attr") == 0)
{
if ( argc < 4 )
{
Usage();
return( 1 );
}
pszAttrName = argv[2];
pszAttrValue = argv[3];
}
break;
case 'd':
case 'D':
if ( argc < 2 )
{
Usage();
return( 1 );
}
pszHash = argv[1];
break;
case 'r':
case 'R':
if ( argc < 3 )
{
Usage();
return( 1 );
}
pszHash = argv[1];
fAddEntry = TRUE;
pszFileName = argv[2];
break;
case 'S':
if (memcmp(&(argv[0][0]), (void *) PSZ_SPATTR_OPTION, strlen(PSZ_SPATTR_OPTION)) == 0)
{
DWORD dwNumChars;
dwNumChars = MultiByteToWideChar(
CP_ACP,
0,
&(argv[0][strlen(PSZ_SPATTR_OPTION)]),
-1,
NULL,
0
);
if (dwNumChars == 0)
{
printf( "Error calling MultiByteToWideChar on %s\n", &(argv[0][strlen(PSZ_SPATTR_OPTION)]));
return -1;
}
pwszSpAttr = new WCHAR [ dwNumChars ];
if (pwszSpAttr == NULL)
{
printf("Out of memory error\n");
return -1;
}
if ( MultiByteToWideChar(
CP_ACP,
0,
&(argv[0][strlen(PSZ_SPATTR_OPTION)]),
-1,
pwszSpAttr,
dwNumChars
) == 0 )
{
delete pwszSpAttr;
printf( "Error calling MultiByteToWideChar on %s\n", &(argv[0][strlen(PSZ_SPATTR_OPTION)]));
return -1;
}
}
else
{
Usage();
return -1;
}
break;
case 's':
if ((argc < 2) || (argv[0][2] != '\0'))
{
Usage();
return -1;
}
sizeLimit = strtol(*(argv+1), NULL, 10);
if (errno || (sizeLimit == 0))
{
printf ("Invalid size specified with -s option: %s\n",*(argv+1));
Usage();
return -1;
}
break;
default:
Usage();
return -1;
}
fOptionChosen = TRUE;
argc -= 1;
argv++;
}
}
pwszCatalogFile = new WCHAR [ cch + 1 ];
if ( pwszCatalogFile != NULL )
{
if ( MultiByteToWideChar(
CP_ACP,
0,
pszCatalogFile,
-1,
pwszCatalogFile,
cch + 1
) == 0 )
{
delete pwszCatalogFile;
return( 1 );
}
}
if (!fOptionChosen)
{
Usage();
delete pwszCatalogFile;
return -1;
}
if (pszFileName != NULL)
{
cch = strlen( pszFileName );
pwszFileName = new WCHAR [ cch + 1 ];
if ( pwszFileName != NULL )
{
if ( MultiByteToWideChar(
CP_ACP,
0,
pszFileName,
-1,
pwszFileName,
cch + 1
) == 0 )
{
delete pwszCatalogFile;
delete pwszFileName;
return( 1 );
}
}
}
if (pszAttrName != NULL)
{
cch = strlen( pszAttrName );
pwszAttrName = new WCHAR [ cch + 1 ];
if ( pwszAttrName != NULL )
{
if ( MultiByteToWideChar(
CP_ACP,
0,
pszAttrName,
-1,
pwszAttrName,
cch + 1
) == 0 )
{
printf("Error converting AttrName to wchar\n");
delete pwszCatalogFile;
delete pwszFileName;
delete pwszAttrName;
return( 1 );
}
}
}
if (pszAttrValue != NULL)
{
cch = strlen( pszAttrValue );
pwszAttrValue = new WCHAR [ cch + 1 ];
if ( pwszAttrValue != NULL )
{
if ( MultiByteToWideChar(
CP_ACP,
0,
pszAttrValue,
-1,
pwszAttrValue,
cch + 1
) == 0 )
{
printf("Error converting AttrValue to wchar\n");
delete pwszCatalogFile;
delete pwszFileName;
delete pwszAttrName;
delete pwszAttrValue;
return( 1 );
}
}
}
if ( pszHash != NULL )
{
fResult = RemoveHashFromCatalog(pwszCatalogFile, pszHash);
if ( fResult == FALSE )
{
printf("Error removing <%s> from catalog <%s>\n", pszHash, pszCatalogFile);
}
}
//
// If there haven't been any errors, and we are adding a hash
//
if (( fResult == TRUE ) && ( fAddEntry == TRUE ))
{
hCatalog = CryptCATOpen(
pwszCatalogFile,
CRYPTCAT_OPEN_ALWAYS,
NULL,
0x00000001,
0x00010001
);
if ( hCatalog == NULL )
{
fResult = FALSE;
}
else
{
// If we're adding an attribute
if (pwszAttrName && pwszAttrValue)
{
fResult = AddFileOrAuthAttrToCatalog( hCatalog, pwszFileName,
0x10010001, pwszAttrName,
pwszAttrValue );
CryptCATClose( hCatalog );
if ( fResult == FALSE )
{
printf("Error adding Attribute <%s> to catalog <%s>\n",
pszAttrName, pszCatalogFile);
}
}
else
// If we're only adding the file by hash
{
fResult = AddFileToCatalog( hCatalog, pwszFileName );
CryptCATClose( hCatalog );
if ( fResult == FALSE )
{
printf("Error adding <%s> to catalog <%s>\n",
pszFileName, pszCatalogFile);
}
}
}
}
if ( pwszSpAttr != NULL )
{
hCatalog = CryptCATOpen(
pwszCatalogFile,
CRYPTCAT_OPEN_ALWAYS,
NULL,
0x00000001,
0x00010001
);
if ( hCatalog == NULL )
{
fResult = FALSE;
goto Return;
}
//
// Check to see if it already has an SpAttr
//
pCatAttr = CryptCATGetCatAttrInfo(hCatalog, PWSZ_SPATTR);
if ( pCatAttr == NULL )
{
if (NULL == CryptCATPutCatAttrInfo(
hCatalog,
PWSZ_SPATTR,
0x10010001,
(wcslen(pwszSpAttr) + 1) * sizeof(WCHAR),
(BYTE *) pwszSpAttr))
{
printf("Error adding SpAttr to catalog <%s>\n", pszCatalogFile);
fResult = FALSE;
goto Return;
}
}
else
{
if (NULL == CryptCATPutCatAttrInfo(
hCatalog,
PWSZ_SPATTR,
0x10040001,
(wcslen(pwszSpAttr) + 1) * sizeof(WCHAR),
(BYTE *) pwszSpAttr))
{
if (GetLastError() == ERROR_INVALID_PARAMETER)
{
printf("The SpAttr modification failed, it is likely due to an old wintrust.dll\n");
}
else
{
printf("Error changing SpAttr in catalog <%s>\n", pszCatalogFile);
}
fResult = FALSE;
goto Return;
}
}
CryptCATPersistStore(hCatalog);
CryptCATClose( hCatalog );
}
Return:
return( !fResult );
}
typedef BOOL (WINAPI *PFN_CRYPTSIP_RETRIEVE_SUBJECT_GUID_FOR_CATALOG_FILE) (
IN LPCWSTR FileName,
IN HANDLE hFileIn,
OUT GUID *pgSubject
);
//+---------------------------------------------------------------------------
//
// Function: AddFileOrAuthAttrToCatalog
//
// Synopsis: add a file as an entry to the catalog. The tag will be the
// hash
// additionally, you can add an authenticated attribute.
//
//----------------------------------------------------------------------------
BOOL AddFileOrAuthAttrToCatalog (IN HANDLE hCatalog,
IN LPWSTR pwszFileName,
IN DWORD dwAttrFlags,
IN LPWSTR pwszAttrName,
IN LPWSTR pwszAttrValue)
{
BOOL fResult;
GUID FlatSubject = CRYPT_SUBJTYPE_FLAT_IMAGE;
GUID SubjectType;
SIP_SUBJECTINFO SubjectInfo;
SIP_DISPATCH_INFO DispatchInfo;
DWORD cbIndirectData;
SIP_INDIRECT_DATA* pIndirectData = NULL;
CRYPTCATSTORE* pCatStore = CryptCATStoreFromHandle( hCatalog );
CRYPTCATMEMBER* pMember;
CRYPTCATATTRIBUTE* pAttr;
LPWSTR pwszHashTag = NULL;
HMODULE hMod = NULL;
PFN_CRYPTSIP_RETRIEVE_SUBJECT_GUID_FOR_CATALOG_FILE pSIPFunc = NULL;
memset( &SubjectInfo, 0, sizeof( SubjectInfo ) );
memset( &DispatchInfo, 0, sizeof( DispatchInfo ) );
if (sizeLimit)
{
// Check that we do not add the hash for a file whose
// size if less than the specified lower limit
if ( !CheckFileSize(pwszFileName, sizeLimit) )
{
printf ("Error: %S is smaller than the specified minimum size (%d)\n",
pwszFileName, sizeLimit);
return FALSE;
}
}
//
// NOTE!!!!!
//
// Try to use the function that only retrieves SIPs for hashing files
// that are to be included in catalog files. This function is new and
// only exists post win2k, so if it isn't there, then fall back to the
// win2k function... which should be OK since Win2k didn't SHIP
// with any SIPs that caused problems (although SIPs could be installed on
// a win2k system after the fact that do cause problems)
//
if (NULL != (hMod = LoadLibrary("crypt32.dll")))
{
pSIPFunc = (PFN_CRYPTSIP_RETRIEVE_SUBJECT_GUID_FOR_CATALOG_FILE)
GetProcAddress(hMod, "CryptSIPRetrieveSubjectGuidForCatalogFile");
if (pSIPFunc != NULL)
{
if ( pSIPFunc(pwszFileName, NULL, &SubjectType) == FALSE )
{
memcpy( &SubjectType, &FlatSubject, sizeof( GUID ) );
}
}
}
if (pSIPFunc == NULL)
{
//
// Fall back to old SIP resolver
//
if ( CryptSIPRetrieveSubjectGuid(
pwszFileName,
NULL,
&SubjectType
) == FALSE )
{
memcpy( &SubjectType, &FlatSubject, sizeof( GUID ) );
}
}
if (hMod != NULL)
{
FreeLibrary(hMod);
}
if ( CryptSIPLoad( &SubjectType, 0, &DispatchInfo ) == FALSE )
{
return( FALSE );
}
// Some of this subject info stuff should be configurable but
// since the CDF API does not allow it, we won't worry about it
// yet.
SubjectInfo.cbSize = sizeof( SubjectInfo );
SubjectInfo.hProv = pCatStore->hProv;
SubjectInfo.DigestAlgorithm.pszObjId = (char *)CertAlgIdToOID( CALG_SHA1 );
SubjectInfo.dwFlags = SPC_INC_PE_RESOURCES_FLAG |
SPC_INC_PE_IMPORT_ADDR_TABLE_FLAG |
MSSIP_FLAGS_PROHIBIT_RESIZE_ON_CREATE;
SubjectInfo.dwEncodingType = pCatStore->dwEncodingType;
SubjectInfo.pgSubjectType = &SubjectType;
SubjectInfo.pwsFileName = pwszFileName;
fResult = DispatchInfo.pfCreate( &SubjectInfo, &cbIndirectData, NULL );
if ( fResult == TRUE )
{
pIndirectData = (SIP_INDIRECT_DATA *)new BYTE [ cbIndirectData ];
if ( pIndirectData != NULL )
{
fResult = DispatchInfo.pfCreate(
&SubjectInfo,
&cbIndirectData,
pIndirectData
);
}
else
{
SetLastError( E_OUTOFMEMORY );
fResult = FALSE;
}
}
if ( fResult == TRUE )
{
fResult = MsCatConstructHashTag(
pIndirectData->Digest.cbData,
pIndirectData->Digest.pbData,
&pwszHashTag
);
}
if ( fResult == FALSE )
{
goto Return;
}
if (pwszAttrName && pwszAttrValue)
{
// We're adding an Attribute
if (dwAttrFlags != 0x10010001)
{
printf("Error: Unsupported flag specified\n");
fResult = FALSE;
goto Return;
}
// Find the member in the catalog.
pMember = CryptCATGetMemberInfo(hCatalog, pwszHashTag);
if (pMember == NULL)
{
// Catalog member was not found. Adding it...
pMember = CryptCATPutMemberInfo(
hCatalog,
pwszFileName,
pwszHashTag,
&SubjectType,
SubjectInfo.dwIntVersion,
cbIndirectData,
(LPBYTE)pIndirectData
);
}
if (pMember == NULL)
{
printf("Error: Could not find file hash, and could not add it.\n");
fResult = FALSE;
}
else
{
if (pAttr = CryptCATGetAttrInfo(hCatalog, pMember, pwszAttrName))
{
if (wcscmp(pwszAttrValue, LPCWSTR(pAttr->pbValue)) == 0)
{
printf("Attribute already exists with the same value\n");
fResult = FALSE;
}
else
{
pAttr->cbValue = (wcslen(pwszAttrValue) + 1) * sizeof(WCHAR);
delete(pAttr->pbValue);
pAttr->pbValue = (BYTE *)pwszAttrValue;
pAttr->pbValue = new BYTE[pAttr->cbValue];
if (pAttr->pbValue)
{
memcpy(pAttr->pbValue, pwszAttrValue, pAttr->cbValue);
fResult = CryptCATPersistStore(hCatalog);
}
else
{
pAttr->cbValue = 0;
fResult = FALSE;
}
}
}
else
{
pAttr = CryptCATPutAttrInfo(hCatalog,
pMember,
pwszAttrName,
dwAttrFlags,
(wcslen(pwszAttrValue) + 1) * sizeof(WCHAR),
(BYTE *)pwszAttrValue);
if (pAttr != NULL)
{
fResult = CryptCATPersistStore(hCatalog);
}
else
{
fResult = FALSE;
}
}
}
}
else
{
// We're just adding a catalog member
// Does this member already exist?
pMember = CryptCATGetMemberInfo(hCatalog, pwszHashTag);
if (pMember == NULL)
{
// it does not exist in the catalog yet. Add it.
pMember = CryptCATPutMemberInfo(
hCatalog,
pwszFileName,
pwszHashTag,
&SubjectType,
SubjectInfo.dwIntVersion,
cbIndirectData,
(LPBYTE)pIndirectData
);
if ( pMember != NULL )
{
fResult = CryptCATPersistStore( hCatalog );
}
else
{
fResult = FALSE;
}
}
else
{
// It already exists in the catalog.
printf("This file's hash is already present in the catalog.\n");
fResult = FALSE;
}
}
Return:
if ( pwszHashTag != NULL )
{
MsCatFreeHashTag( pwszHashTag );
}
delete (LPBYTE)pIndirectData;
return( fResult );
}
//+---------------------------------------------------------------------------
//
// Function: RemoveHashFromCatalog
//
// Synopsis: removes a hash entry from the catalog.
//
//----------------------------------------------------------------------------
BOOL
RemoveHashFromCatalog(IN LPWSTR pwszCatalogFile, IN LPSTR pszHash)
{
BOOL fRet = TRUE;
LPSTR pChar = NULL;
int i, j;
DWORD dwContentType;
PCTL_CONTEXT pCTLContext = NULL;
CTL_CONTEXT CTLContext;
CTL_INFO CTLInfo;
DWORD cbEncodedCTL = 0;
BYTE *pbEncodedCTL = NULL;
DWORD cbWritten = 0;
HANDLE hFile = INVALID_HANDLE_VALUE;
DWORD cch = 0;
LPWSTR pwszHash = NULL;
BOOL fHashFound = FALSE;
CMSG_SIGNED_ENCODE_INFO signedInfo;
memset(&signedInfo, 0, sizeof(signedInfo));
signedInfo.cbSize = sizeof(signedInfo);
CTLInfo.rgCTLEntry = NULL;
cch = strlen( pszHash );
pwszHash = new WCHAR [ cch + 1 ];
if ( pwszHash == NULL )
{
goto ErrorReturn;
}
if ( MultiByteToWideChar(
CP_ACP,
0,
pszHash,
-1,
pwszHash,
cch + 1
) == 0 )
{
goto ErrorReturn;
}
//
// Get rid of all the ' ' chars
//
i = 0;
j = 0;
for (i=0; i<(int)wcslen(pwszHash); i++)
{
if (pwszHash[i] != ' ')
{
pwszHash[j++] = pwszHash[i];
}
}
pwszHash[j] = '\0';
//
// Open the cat file as a CTL
//
if (!CryptQueryObject(
CERT_QUERY_OBJECT_FILE,
pwszCatalogFile,
CERT_QUERY_CONTENT_FLAG_CTL,
CERT_QUERY_FORMAT_FLAG_BINARY,
0, //flags
NULL,
&dwContentType,
NULL,
NULL,
NULL,
(const void **) &pCTLContext))
{
goto ErrorReturn;
}
if (dwContentType != CERT_QUERY_CONTENT_CTL)
{
goto ErrorReturn;
}
//
// Create another CTL context just like pCTLContext
//
CTLInfo = *(pCTLContext->pCtlInfo);
CTLInfo.rgCTLEntry = (PCTL_ENTRY) new CTL_ENTRY[pCTLContext->pCtlInfo->cCTLEntry];
if (CTLInfo.rgCTLEntry == NULL)
{
goto ErrorReturn;
}
//
// Loop through all the ctl entries and remove the entry
// that corresponds to the hash given
//
CTLInfo.cCTLEntry = 0;
for (i=0; i<(int)pCTLContext->pCtlInfo->cCTLEntry; i++)
{
if (wcscmp(
(LPWSTR) pCTLContext->pCtlInfo->rgCTLEntry[i].SubjectIdentifier.pbData,
pwszHash) != 0)
{
CTLInfo.rgCTLEntry[CTLInfo.cCTLEntry++] = pCTLContext->pCtlInfo->rgCTLEntry[i];
}
else
{
fHashFound = TRUE;
}
}
if (!fHashFound)
{
printf("<%S> not found in <%S>\n", pwszHash, pwszCatalogFile);
goto ErrorReturn;
}
//
// now save the CTL which is exactly the same as the previous one,
// except it doesn't doesn't have the hash being removed, back to
// the original filename
//
if (!CryptMsgEncodeAndSignCTL(
X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
&CTLInfo,
&signedInfo,
0,
NULL,
&cbEncodedCTL))
{
goto ErrorReturn;
}
if (NULL == (pbEncodedCTL = new BYTE[cbEncodedCTL]))
{
goto ErrorReturn;
}
if (!CryptMsgEncodeAndSignCTL(
X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
&CTLInfo,
&signedInfo,
0,
pbEncodedCTL,
&cbEncodedCTL))
{
goto ErrorReturn;
}
if (INVALID_HANDLE_VALUE == (hFile = CreateFileW(
pwszCatalogFile,
GENERIC_READ | GENERIC_WRITE,
0,
NULL,
CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
NULL)))
{
goto ErrorReturn;
}
if (!WriteFile(
hFile,
pbEncodedCTL,
cbEncodedCTL,
&cbWritten,
NULL))
{
printf("WriteFile of <%S> failed with %x\n", pwszCatalogFile, GetLastError());
goto ErrorReturn;
}
if (cbWritten != cbEncodedCTL)
{
goto ErrorReturn;
}
CloseHandle(hFile);
hFile = INVALID_HANDLE_VALUE;
CommonReturn:
if (pwszHash != NULL)
{
delete (pwszHash);
}
if (pCTLContext != NULL)
{
CertFreeCTLContext(pCTLContext);
}
if (CTLInfo.rgCTLEntry != NULL)
{
delete (CTLInfo.rgCTLEntry);
}
if (pbEncodedCTL != NULL)
{
delete (pbEncodedCTL);
}
if (hFile != INVALID_HANDLE_VALUE)
{
if (!CloseHandle(hFile))
{
fRet = FALSE;
}
}
return fRet;
ErrorReturn:
fRet = FALSE;
goto CommonReturn;
}
//+---------------------------------------------------------------------------
//
// Function: CheckFileSize
//
// Synopsis: Checks that a file meets the minumum size requirement.
//
//----------------------------------------------------------------------------
BOOL
CheckFileSize (LPWSTR fileName, ULONG sizeLimit)
{
HANDLE hFile;
LARGE_INTEGER sizeFile = {0};
// Attempt to open the specified file
hFile = CreateFileW( fileName,
GENERIC_READ,
FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
FILE_FLAG_SEQUENTIAL_SCAN,
NULL );
if (INVALID_HANDLE_VALUE == hFile)
{
printf("Error opening %S (%lu)\n", fileName, GetLastError() );
return FALSE;
}
// Get the file size
if (!GetFileSizeEx(hFile, &sizeFile))
{
printf("Error determining size of %S (%lu)\n", fileName, GetLastError());
return FALSE;
}
if ((!sizeFile.HighPart) && (sizeFile.LowPart < sizeLimit))
{
// File is too small
return FALSE;
}
// Success. File is not too small.
return TRUE;
}