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.
1685 lines
48 KiB
1685 lines
48 KiB
/*++
|
|
|
|
Copyright (c) 1995 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
string.c
|
|
|
|
Abstract:
|
|
|
|
This file implements file functions for fax.
|
|
|
|
Author:
|
|
|
|
Wesley Witt (wesw) 23-Jan-1995
|
|
|
|
Environment:
|
|
|
|
User Mode
|
|
|
|
--*/
|
|
|
|
#include <windows.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <tchar.h>
|
|
#include <Accctrl.h>
|
|
#include <Aclapi.h>
|
|
#include <Shellapi.h>
|
|
#include <strsafe.h>
|
|
|
|
#include "faxutil.h"
|
|
#include "faxreg.h"
|
|
#include "FaxUIConstants.h"
|
|
|
|
|
|
VOID
|
|
DeleteTempPreviewFiles (
|
|
LPTSTR lptstrDirectory,
|
|
BOOL bConsole
|
|
)
|
|
/*++
|
|
|
|
Routine name : DeleteTempPreviewFiles
|
|
|
|
Routine description:
|
|
|
|
Deletes all the temporary fax preview TIFF files from a given folder.
|
|
|
|
Deletes files: "<lptstrDirectory>\<PREVIEW_TIFF_PREFIX>*.<FAX_TIF_FILE_EXT>".
|
|
|
|
Author:
|
|
|
|
Eran Yariv (EranY), Apr, 2001
|
|
|
|
Arguments:
|
|
|
|
lptstrDirectory [in] - Folder.
|
|
Optional - if NULL, the current user's temp dir is used.
|
|
|
|
bConsole [in] - If TRUE, called from the client console. Otherwise, from the Fax Send Wizard.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
TCHAR szTempPath[MAX_PATH * 2];
|
|
TCHAR szSearch [MAX_PATH * 3];
|
|
WIN32_FIND_DATA W32FindData;
|
|
HANDLE hFind = INVALID_HANDLE_VALUE;
|
|
TCHAR* pLast = NULL;
|
|
|
|
HRESULT hRes;
|
|
|
|
DEBUG_FUNCTION_NAME(TEXT("DeleteTempPreviewFiles"));
|
|
|
|
if (!lptstrDirectory)
|
|
{
|
|
if (!GetTempPath( ARR_SIZE(szTempPath), szTempPath ))
|
|
{
|
|
DebugPrintEx(DEBUG_ERR,
|
|
TEXT("GetTempPath() failed. (ec = %lu)"),
|
|
GetLastError());
|
|
return;
|
|
}
|
|
lptstrDirectory = szTempPath;
|
|
}
|
|
|
|
//
|
|
// find last \ in path
|
|
//
|
|
pLast = _tcsrchr(lptstrDirectory,TEXT('\\'));
|
|
if(pLast && (*_tcsinc(pLast)) == '\0')
|
|
{
|
|
//
|
|
// the last character is a backslash, truncate it...
|
|
//
|
|
_tcsnset(pLast,'\0',1);
|
|
}
|
|
|
|
hRes = StringCchPrintf(
|
|
szSearch,
|
|
ARR_SIZE(szSearch),
|
|
TEXT("%s\\%s%08x*.%s"),
|
|
lptstrDirectory,
|
|
bConsole ? CONSOLE_PREVIEW_TIFF_PREFIX : WIZARD_PREVIEW_TIFF_PREFIX,
|
|
GetCurrentProcessId(),
|
|
FAX_TIF_FILE_EXT
|
|
);
|
|
if (FAILED(hRes))
|
|
{
|
|
DebugPrintEx(DEBUG_ERR,
|
|
TEXT("StringCchPrintf failed (ec=%lu)"),
|
|
HRESULT_CODE(hRes));
|
|
return;
|
|
}
|
|
|
|
hFind = FindFirstFile (szSearch, &W32FindData);
|
|
if (INVALID_HANDLE_VALUE == hFind)
|
|
{
|
|
DebugPrintEx(DEBUG_ERR, TEXT("FindFirstFile failed with %ld"), GetLastError ());
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Loop and delete all preview files
|
|
//
|
|
for (;;)
|
|
{
|
|
TCHAR szFile[MAX_PATH * 3];
|
|
|
|
//
|
|
// Compose full path to file
|
|
//
|
|
hRes = StringCchPrintf(
|
|
szFile,
|
|
ARR_SIZE(szFile),
|
|
TEXT("%s\\%s"),
|
|
lptstrDirectory,
|
|
W32FindData.cFileName
|
|
);
|
|
if ( SUCCEEDED(hRes) )
|
|
{
|
|
//
|
|
// Delete the currently found file
|
|
//
|
|
if (!DeleteFile (szFile))
|
|
{
|
|
DebugPrintEx(DEBUG_ERR, TEXT("DeleteFile(%s) failed with %ld"), szFile, GetLastError ());
|
|
}
|
|
else
|
|
{
|
|
DebugPrintEx(DEBUG_MSG, TEXT("%s deleted"), szFile);
|
|
}
|
|
}
|
|
//
|
|
// Find next file
|
|
//
|
|
if(!FindNextFile(hFind, &W32FindData))
|
|
{
|
|
if(ERROR_NO_MORE_FILES != GetLastError ())
|
|
{
|
|
DebugPrintEx(DEBUG_ERR, TEXT("FindNextFile failed with %ld"), GetLastError ());
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// End of files - no error
|
|
//
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
FindClose (hFind);
|
|
} // DeleteTempPreviewFiles
|
|
|
|
DWORDLONG
|
|
GenerateUniqueFileNameWithPrefix(
|
|
BOOL bUseProcessId,
|
|
LPTSTR lptstrDirectory,
|
|
LPTSTR lptstrPrefix,
|
|
LPTSTR lptstrExtension,
|
|
LPTSTR lptstrFileName,
|
|
DWORD dwFileNameSize
|
|
)
|
|
/*++
|
|
|
|
Routine name : GenerateUniqueFileNameWithPrefix
|
|
|
|
Routine description:
|
|
|
|
Generates a unique file name
|
|
|
|
Author:
|
|
|
|
Eran Yariv (EranY), Apr, 2001
|
|
|
|
Arguments:
|
|
|
|
bUseProcessId [in] - If TRUE, the process id is appended after the prefix
|
|
|
|
lptstrDirectory [in] - Directory where file should be created.
|
|
Optional - if NULL, the current user's temp dir is used.
|
|
|
|
lptstrPrefix [in] - File prefix.
|
|
Optional - if NULL, no prefix is used.
|
|
|
|
lptstrExtension [in] - File extension.
|
|
Optional - if NULL, FAX_TIF_FILE_EXT is used.
|
|
|
|
lptstrFileName [out] - File name.
|
|
|
|
dwFileNameSize [in] - Size of file name (in characters)
|
|
|
|
Return Value:
|
|
|
|
Unique file identifier.
|
|
Returns 0 in case of error (sets last error).
|
|
|
|
--*/
|
|
{
|
|
DWORD i;
|
|
TCHAR szTempPath[MAX_PATH * 2];
|
|
TCHAR szProcessId[20] = {0};
|
|
DWORDLONG dwlUniqueId = 0;
|
|
|
|
HRESULT hRes;
|
|
|
|
DEBUG_FUNCTION_NAME(TEXT("GenerateUniqueFileNameWithPrefix"));
|
|
|
|
if (!lptstrDirectory)
|
|
{
|
|
if (!GetTempPath( ARR_SIZE(szTempPath), szTempPath ))
|
|
{
|
|
DebugPrintEx(DEBUG_ERR,
|
|
TEXT("GetTempPath() failed. (ec = %lu)"),
|
|
GetLastError());
|
|
return 0;
|
|
}
|
|
lptstrDirectory = szTempPath;
|
|
}
|
|
|
|
TCHAR* pLast = NULL;
|
|
pLast = _tcsrchr(lptstrDirectory,TEXT('\\'));
|
|
if(pLast && (*_tcsinc(pLast)) == '\0')
|
|
{
|
|
//
|
|
// the last character is a backslash, truncate it...
|
|
//
|
|
_tcsnset(pLast,'\0',1);
|
|
}
|
|
|
|
if (!lptstrExtension)
|
|
{
|
|
lptstrExtension = FAX_TIF_FILE_EXT;
|
|
}
|
|
if (!lptstrPrefix)
|
|
{
|
|
lptstrPrefix = TEXT("");
|
|
}
|
|
if (bUseProcessId)
|
|
{
|
|
hRes = StringCchPrintf (szProcessId, ARR_SIZE(szProcessId), TEXT("%08x"), GetCurrentProcessId());
|
|
if (FAILED(hRes))
|
|
{
|
|
DebugPrintEx(DEBUG_ERR,
|
|
TEXT("StringCchPrintf failed (ec=%lu)"),
|
|
HRESULT_CODE(hRes));
|
|
SetLastError(HRESULT_CODE(hRes));
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
for (i=0; i<256; i++)
|
|
{
|
|
HANDLE hFile = INVALID_HANDLE_VALUE;
|
|
FILETIME FileTime;
|
|
SYSTEMTIME SystemTime;
|
|
|
|
GetSystemTime( &SystemTime ); // returns VOID
|
|
if (!SystemTimeToFileTime( &SystemTime, &FileTime ))
|
|
{
|
|
DebugPrintEx(DEBUG_ERR, TEXT("SystemTimeToFileTime() failed (ec: %ld)"), GetLastError());
|
|
return 0;
|
|
}
|
|
|
|
dwlUniqueId = MAKELONGLONG(FileTime.dwLowDateTime, FileTime.dwHighDateTime);
|
|
//
|
|
// dwlUniqueId holds the number of 100 nanosecond units since 1.1.1601.
|
|
// This occuipies most of the 64 bits.We we need some space to add extra
|
|
// information (job type for example) to the job id.
|
|
// Thus we give up the precision (1/10000000 of a second is too much for us anyhow)
|
|
// to free up 8 MSB bits.
|
|
// We shift right the time 8 bits to the right. This divides it by 256 which gives
|
|
// us time resolution better than 1/10000 of a sec which is more than enough.
|
|
//
|
|
dwlUniqueId = dwlUniqueId >> 8;
|
|
|
|
hRes = StringCchPrintf(
|
|
lptstrFileName,
|
|
dwFileNameSize,
|
|
TEXT("%s\\%s%s%I64X.%s"),
|
|
lptstrDirectory,
|
|
lptstrPrefix,
|
|
szProcessId,
|
|
dwlUniqueId,
|
|
lptstrExtension );
|
|
if (FAILED(hRes))
|
|
{
|
|
DebugPrintEx(DEBUG_ERR,
|
|
TEXT("StringCchPrintf failed (ec=%lu)"),
|
|
HRESULT_CODE(hRes));
|
|
|
|
SetLastError(HRESULT_CODE(hRes));
|
|
return 0;
|
|
}
|
|
|
|
hFile = SafeCreateFile(
|
|
lptstrFileName,
|
|
GENERIC_WRITE,
|
|
0,
|
|
NULL,
|
|
CREATE_NEW,
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
NULL);
|
|
|
|
if (hFile == INVALID_HANDLE_VALUE)
|
|
{
|
|
DWORD dwError = GetLastError();
|
|
|
|
if (dwError == ERROR_ALREADY_EXISTS || dwError == ERROR_FILE_EXISTS)
|
|
{
|
|
continue;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Real error
|
|
//
|
|
DebugPrintEx(DEBUG_ERR,
|
|
TEXT("CreateFile() for [%s] failed. (ec: %ld)"),
|
|
lptstrFileName,
|
|
GetLastError());
|
|
return 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Success
|
|
//
|
|
CloseHandle (hFile);
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (i == 256)
|
|
{
|
|
DebugPrintEx( DEBUG_ERR,
|
|
TEXT("Failed to generate a unique file name after %d attempts. \n")
|
|
TEXT("Last attempted UniqueIdValue value is: 0x%I64X \n")
|
|
TEXT("Last attempted file name is : [%s]"),
|
|
i,
|
|
dwlUniqueId,
|
|
lptstrFileName);
|
|
SetLastError( ERROR_TOO_MANY_OPEN_FILES );
|
|
return 0;
|
|
}
|
|
return dwlUniqueId;
|
|
} // GenerateUniqueFileNameWithPrefix
|
|
|
|
|
|
//*********************************************************************************
|
|
//* Name: GenerateUniqueFileName()
|
|
//* Author:
|
|
//* Date:
|
|
//*********************************************************************************
|
|
//* DESCRIPTION:
|
|
//* Generates a unique file in the queue directory.
|
|
//* returns a UNIQUE id for the file.
|
|
//* PARAMETERS:
|
|
//* [IN] LPTSTR Directory
|
|
//* The path where the file is to be created.
|
|
//* [OUT] LPTSTR Extension
|
|
//* The file extension that the generated file should have.
|
|
//* [IN] LPTSTR FileName
|
|
//* The buffer where the resulting file name (including path) will be
|
|
//* placed, must be MAX_PATH.
|
|
//* [IN] DWORD FileNameSize
|
|
//* The size of the file name buffer.
|
|
//* RETURN VALUE:
|
|
//* If successful the function returns A DWORDLONG with the unique id for the file.
|
|
//* On failure it returns 0.
|
|
//* REMARKS:
|
|
//* The generated unique id the 64 bit value of the system time.
|
|
//* The generated file name is a string containing the hex representation of
|
|
//* the 64 bit system time value.
|
|
//*********************************************************************************
|
|
DWORDLONG
|
|
GenerateUniqueFileName(
|
|
LPTSTR Directory,
|
|
LPTSTR Extension,
|
|
LPTSTR FileName,
|
|
DWORD FileNameSize
|
|
)
|
|
{
|
|
return GenerateUniqueFileNameWithPrefix (FALSE, Directory, NULL, Extension, FileName, FileNameSize);
|
|
} // GenerateUniqueFileName
|
|
|
|
|
|
|
|
BOOL
|
|
MapFileOpen(
|
|
LPCTSTR FileName,
|
|
BOOL ReadOnly,
|
|
DWORD ExtendBytes,
|
|
PFILE_MAPPING FileMapping
|
|
)
|
|
{
|
|
FileMapping->hFile = NULL;
|
|
FileMapping->hMap = NULL;
|
|
FileMapping->fPtr = NULL;
|
|
|
|
FileMapping->hFile = SafeCreateFile(
|
|
FileName,
|
|
ReadOnly ? GENERIC_READ : GENERIC_READ | GENERIC_WRITE,
|
|
ReadOnly ? FILE_SHARE_READ : 0,
|
|
NULL,
|
|
OPEN_EXISTING,
|
|
0,
|
|
NULL);
|
|
if (FileMapping->hFile == INVALID_HANDLE_VALUE)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
FileMapping->fSize = GetFileSize( FileMapping->hFile, NULL );
|
|
|
|
FileMapping->hMap = CreateFileMapping(
|
|
FileMapping->hFile,
|
|
NULL,
|
|
ReadOnly ? PAGE_READONLY : PAGE_READWRITE,
|
|
0,
|
|
FileMapping->fSize + ExtendBytes,
|
|
NULL
|
|
);
|
|
if (FileMapping->hMap == NULL)
|
|
{
|
|
CloseHandle( FileMapping->hFile );
|
|
return FALSE;
|
|
}
|
|
|
|
FileMapping->fPtr = (LPBYTE)MapViewOfFileEx(
|
|
FileMapping->hMap,
|
|
ReadOnly ? FILE_MAP_READ : FILE_MAP_WRITE,
|
|
0,
|
|
0,
|
|
0,
|
|
NULL
|
|
);
|
|
if (FileMapping->fPtr == NULL)
|
|
{
|
|
CloseHandle( FileMapping->hFile );
|
|
CloseHandle( FileMapping->hMap );
|
|
return FALSE;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
VOID
|
|
MapFileClose(
|
|
PFILE_MAPPING FileMapping,
|
|
DWORD TrimOffset
|
|
)
|
|
{
|
|
UnmapViewOfFile( FileMapping->fPtr );
|
|
CloseHandle( FileMapping->hMap );
|
|
if (TrimOffset) {
|
|
SetFilePointer( FileMapping->hFile, TrimOffset, NULL, FILE_BEGIN );
|
|
SetEndOfFile( FileMapping->hFile );
|
|
}
|
|
CloseHandle( FileMapping->hFile );
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// Function: MultiFileCopy
|
|
// Description: Copies multiple files from one directory to another.
|
|
// In case of failure, return FALSE without any clean-up.
|
|
// Validate that the path names and file names are not sum to be larger than MAX_PATH
|
|
// Args:
|
|
//
|
|
// dwNumberOfFiles : Number of file names to copy
|
|
// fileList : Array of strings: file names
|
|
// lpctstrSrcDirectory : Source directory (with or without '\' at the end
|
|
// lpctstrDestDirectory: Destination directory (with or without '\' at the end
|
|
//
|
|
// Author: AsafS
|
|
|
|
|
|
|
|
BOOL
|
|
MultiFileCopy(
|
|
DWORD dwNumberOfFiles,
|
|
LPCTSTR* fileList,
|
|
LPCTSTR lpctstrSrcDirectory,
|
|
LPCTSTR lpctstrDestDirerctory
|
|
)
|
|
{
|
|
DEBUG_FUNCTION_NAME(TEXT("MultiFileCopy"))
|
|
TCHAR szSrcPath [MAX_PATH];
|
|
TCHAR szDestPath[MAX_PATH];
|
|
|
|
HRESULT hRes;
|
|
|
|
DWORD dwLengthOfDestDirectory = _tcslen(lpctstrDestDirerctory);
|
|
DWORD dwLengthOfSrcDirectory = _tcslen(lpctstrSrcDirectory);
|
|
|
|
// Make sure that all the file name lengths are not too big
|
|
|
|
DWORD dwMaxPathLen = 1 + max((dwLengthOfDestDirectory),(dwLengthOfSrcDirectory));
|
|
DWORD dwBufferLen = (sizeof(szSrcPath)/sizeof(TCHAR)) - 1;
|
|
|
|
DWORD i=0;
|
|
Assert (dwNumberOfFiles);
|
|
for (i=0 ; i < dwNumberOfFiles ; i++)
|
|
{
|
|
if ( (_tcslen(fileList[i]) + dwMaxPathLen) > dwBufferLen )
|
|
{
|
|
DebugPrintEx(
|
|
DEBUG_ERR,
|
|
TEXT("The file/path names are too long")
|
|
);
|
|
SetLastError( ERROR_BUFFER_OVERFLOW );
|
|
return (FALSE);
|
|
}
|
|
}
|
|
|
|
hRes = StringCchCopy( szSrcPath,
|
|
ARR_SIZE(szSrcPath),
|
|
lpctstrSrcDirectory);
|
|
if (FAILED(hRes))
|
|
{
|
|
DebugPrintEx(DEBUG_ERR,
|
|
TEXT("StringCchCopy failed (ec=%lu)"),
|
|
HRESULT_CODE(hRes));
|
|
|
|
SetLastError( HRESULT_CODE(hRes) );
|
|
return (FALSE);
|
|
}
|
|
|
|
hRes = StringCchCopy( szDestPath,
|
|
ARR_SIZE(szDestPath),
|
|
lpctstrDestDirerctory);
|
|
if (FAILED(hRes))
|
|
{
|
|
DebugPrintEx(DEBUG_ERR,
|
|
TEXT("StringCchCopy failed (ec=%lu)"),
|
|
HRESULT_CODE(hRes));
|
|
|
|
SetLastError( HRESULT_CODE(hRes) );
|
|
return (FALSE);
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// Verify that directories end with '\\'.
|
|
//
|
|
TCHAR* pLast = NULL;
|
|
pLast = _tcsrchr(szSrcPath,TEXT('\\'));
|
|
if( !( pLast && (*_tcsinc(pLast)) == '\0' ) )
|
|
{
|
|
// the last character is not a backslash, add one...
|
|
hRes = StringCchCat(szSrcPath, ARR_SIZE(szSrcPath), TEXT("\\"));
|
|
if (FAILED(hRes))
|
|
{
|
|
DebugPrintEx(DEBUG_ERR,
|
|
TEXT("StringCchCat failed (ec=%lu)"),
|
|
HRESULT_CODE(hRes));
|
|
|
|
SetLastError( HRESULT_CODE(hRes) );
|
|
return (FALSE);
|
|
}
|
|
}
|
|
|
|
pLast = _tcsrchr(szDestPath,TEXT('\\'));
|
|
if( !( pLast && (*_tcsinc(pLast)) == '\0' ) )
|
|
{
|
|
// the last character is not a backslash, add one...
|
|
hRes = StringCchCat(szDestPath, ARR_SIZE(szDestPath), TEXT("\\"));
|
|
if (FAILED(hRes))
|
|
{
|
|
DebugPrintEx(DEBUG_ERR,
|
|
TEXT("StringCchCat failed (ec=%lu)"),
|
|
HRESULT_CODE(hRes));
|
|
|
|
SetLastError( HRESULT_CODE(hRes) );
|
|
return (FALSE);
|
|
}
|
|
}
|
|
|
|
// Do the copy now
|
|
|
|
for (i=0 ; i < dwNumberOfFiles ; i++)
|
|
{
|
|
TCHAR szSrcFile[MAX_PATH];
|
|
TCHAR szDestFile[MAX_PATH];
|
|
|
|
hRes = StringCchPrintf(
|
|
szSrcFile,
|
|
ARR_SIZE(szSrcFile),
|
|
TEXT("%s%s"),
|
|
szSrcPath,
|
|
fileList[i]
|
|
);
|
|
if (FAILED(hRes))
|
|
{
|
|
DebugPrintEx(DEBUG_ERR,
|
|
TEXT("StringCchPrintf failed (ec=%lu)"),
|
|
HRESULT_CODE(hRes));
|
|
|
|
SetLastError(HRESULT_CODE(hRes));
|
|
return FALSE;
|
|
}
|
|
|
|
hRes = StringCchPrintf(
|
|
szDestFile,
|
|
ARR_SIZE(szDestFile),
|
|
TEXT("%s%s"),
|
|
szDestPath,
|
|
fileList[i]
|
|
);
|
|
if (FAILED(hRes))
|
|
{
|
|
DebugPrintEx(DEBUG_ERR,
|
|
TEXT("StringCchPrintf failed (ec=%lu)"),
|
|
HRESULT_CODE(hRes));
|
|
|
|
SetLastError(HRESULT_CODE(hRes));
|
|
return FALSE;
|
|
}
|
|
|
|
if (!CopyFile(szSrcFile, szDestFile, FALSE))
|
|
{
|
|
DebugPrintEx(
|
|
DEBUG_ERR,
|
|
TEXT("CopyFile(%s, %s) failed: %d."),
|
|
szSrcFile,
|
|
szDestFile,
|
|
GetLastError()
|
|
);
|
|
return(FALSE);
|
|
}
|
|
|
|
DebugPrintEx(
|
|
DEBUG_MSG,
|
|
TEXT("CopyFile(%s, %s) succeeded."),
|
|
szSrcFile,
|
|
szDestFile
|
|
);
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
// Function: MultiFileDelete
|
|
// Description: Deletes multiple files from given directory.
|
|
// In case of failure, continue with the rest of the files and returns FALSE. Call to
|
|
// GetLastError() to get the reason for the last failure that occured
|
|
// If all DeleteFile calls were successful - return TRUE
|
|
// Validate that the path name and file names are not sum to be larger than MAX_PATH
|
|
// Args:
|
|
//
|
|
// dwNumberOfFiles : Number of file names to copy
|
|
// fileList : Array of strings: file names
|
|
// lpctstrFilesDirectory : Directory of the files (with or without '\' at the end
|
|
//
|
|
// Author: AsafS
|
|
|
|
|
|
|
|
BOOL
|
|
MultiFileDelete(
|
|
DWORD dwNumberOfFiles,
|
|
LPCTSTR* fileList,
|
|
LPCTSTR lpctstrFilesDirectory
|
|
)
|
|
{
|
|
DEBUG_FUNCTION_NAME(TEXT("MultiFileDelete"))
|
|
BOOL retVal = TRUE;
|
|
DWORD dwLastError = 0;
|
|
TCHAR szFullPath[MAX_PATH];
|
|
|
|
|
|
HRESULT hRes;
|
|
|
|
DWORD dwLengthOfDirectoryName = _tcslen(lpctstrFilesDirectory);
|
|
|
|
// Make sure that all the file name lengths are not too big
|
|
DWORD dwBufferLen = (sizeof(szFullPath)/sizeof(TCHAR)) - 1;
|
|
DWORD i;
|
|
Assert (dwNumberOfFiles);
|
|
for (i=0 ; i < dwNumberOfFiles ; i++)
|
|
{
|
|
if ( (_tcslen(fileList[i]) + dwLengthOfDirectoryName + 1) > dwBufferLen )
|
|
{
|
|
DebugPrintEx(
|
|
DEBUG_ERR,
|
|
TEXT("The file/path names are too long")
|
|
);
|
|
SetLastError( ERROR_BUFFER_OVERFLOW );
|
|
return (FALSE);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
hRes = StringCchCopy(szFullPath ,ARR_SIZE(szFullPath), lpctstrFilesDirectory);
|
|
if (FAILED(hRes))
|
|
{
|
|
DebugPrintEx(DEBUG_ERR,
|
|
TEXT("StringCchCopy failed (ec=%lu)"),
|
|
HRESULT_CODE(hRes));
|
|
|
|
SetLastError( HRESULT_CODE(hRes) );
|
|
return (FALSE);
|
|
}
|
|
|
|
|
|
dwLengthOfDirectoryName = _tcslen(lpctstrFilesDirectory);
|
|
|
|
//
|
|
// Verify that directory end with '\\' to the end of the path.
|
|
//
|
|
TCHAR* pLast = NULL;
|
|
pLast = _tcsrchr(szFullPath,TEXT('\\'));
|
|
if( !( pLast && (*_tcsinc(pLast)) == '\0' ) )
|
|
{
|
|
// the last character is not a backslash, add one...
|
|
hRes = StringCchCat(szFullPath, ARR_SIZE(szFullPath), TEXT("\\"));
|
|
if (FAILED(hRes))
|
|
{
|
|
DebugPrintEx(DEBUG_ERR,
|
|
TEXT("StringCchCat failed (ec=%lu)"),
|
|
HRESULT_CODE(hRes));
|
|
|
|
SetLastError( HRESULT_CODE(hRes) );
|
|
return (FALSE);
|
|
}
|
|
}
|
|
|
|
for(i=0 ; i < dwNumberOfFiles ; i++)
|
|
{
|
|
TCHAR szFileName[MAX_PATH];
|
|
|
|
hRes = StringCchPrintf(
|
|
szFileName,
|
|
ARR_SIZE(szFileName),
|
|
TEXT("%s%s"),
|
|
szFullPath,
|
|
fileList[i]
|
|
);
|
|
if (FAILED(hRes))
|
|
{
|
|
DebugPrintEx(DEBUG_ERR,
|
|
TEXT("StringCchPrintf failed (ec=%lu)"),
|
|
HRESULT_CODE(hRes));
|
|
|
|
SetLastError(HRESULT_CODE(hRes));
|
|
return FALSE;
|
|
}
|
|
|
|
if (!DeleteFile(szFileName))
|
|
{
|
|
dwLastError = GetLastError();
|
|
DebugPrintEx(
|
|
DEBUG_ERR,
|
|
TEXT("Delete (%s) failed: %d."),
|
|
szFileName,
|
|
dwLastError
|
|
);
|
|
retVal = FALSE; // Continue with the list
|
|
}
|
|
else
|
|
{
|
|
DebugPrintEx(
|
|
DEBUG_MSG,
|
|
TEXT("Delete (%s) succeeded."),
|
|
szFileName
|
|
);
|
|
}
|
|
}
|
|
|
|
if (!retVal) // In case there was a failure to delete any file
|
|
{
|
|
SetLastError(dwLastError);
|
|
DebugPrintEx(
|
|
DEBUG_ERR,
|
|
TEXT("Delete files from (%s) failed: %d."),
|
|
szFullPath,
|
|
dwLastError
|
|
);
|
|
|
|
}
|
|
|
|
return retVal;
|
|
}
|
|
|
|
|
|
BOOL
|
|
ValidateCoverpage(
|
|
IN LPCTSTR CoverPageName,
|
|
IN LPCTSTR ServerName,
|
|
IN BOOL ServerCoverpage,
|
|
OUT LPTSTR ResolvedName,
|
|
IN DWORD dwResolvedNameSize
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine tries to validate that that coverpage specified by the user actually exists where
|
|
they say it does, and that it is indeed a coverpage (or a resolvable link to one)
|
|
|
|
Please see the SDK for documentation on the rules for how server coverpages work, etc.
|
|
Arguments:
|
|
|
|
CoverpageName - contains name of coverpage
|
|
ServerName - name of the server, if any (can be null)
|
|
ServerCoverpage - indicates if this coverpage is on the server, or in the server location for
|
|
coverpages locally
|
|
ResolvedName - a pointer to buffer (should be MAX_PATH large at least) to receive the
|
|
resolved coverpage name.
|
|
dwResolvedNameSize - holds the size of ResolvedName buffer in TCAHRs
|
|
|
|
|
|
Return Value:
|
|
|
|
TRUE if coverpage can be used.
|
|
FALSE if the coverpage is invalid or cannot be used.
|
|
|
|
--*/
|
|
|
|
{
|
|
LPTSTR p;
|
|
DWORD ec = ERROR_SUCCESS;
|
|
TCHAR CpDir [MAX_PATH];
|
|
TCHAR tszExt[_MAX_EXT];
|
|
TCHAR tszFileName[_MAX_FNAME];
|
|
|
|
HRESULT hRes;
|
|
|
|
DEBUG_FUNCTION_NAME(TEXT("ValidateCoverpage"));
|
|
Assert (ResolvedName);
|
|
|
|
if (!CoverPageName)
|
|
{
|
|
ec = ERROR_INVALID_PARAMETER;
|
|
goto exit;
|
|
}
|
|
|
|
hRes = StringCchCopy(CpDir, ARR_SIZE(CpDir), CoverPageName);
|
|
if (FAILED(hRes))
|
|
{
|
|
DebugPrintEx(DEBUG_ERR,
|
|
TEXT("StringCchCopy failed (ec=%lu)"),
|
|
HRESULT_CODE(hRes));
|
|
|
|
ec = HRESULT_CODE(hRes);
|
|
goto exit;
|
|
}
|
|
|
|
if (TRUE == ServerCoverpage)
|
|
{
|
|
//
|
|
// If this is a server cover page, make sure we only have the file name
|
|
//
|
|
TCHAR tszFullFileName[MAX_PATH];
|
|
|
|
_tsplitpath(CpDir, NULL, NULL, tszFileName, tszExt);
|
|
hRes = StringCchCopy(tszFullFileName, ARR_SIZE(tszFullFileName), tszFileName);
|
|
if (FAILED(hRes))
|
|
{
|
|
//
|
|
// Can not happen. CpDir is MAX_PATH
|
|
//
|
|
Assert (FALSE);
|
|
}
|
|
|
|
hRes = StringCchCat(tszFullFileName, ARR_SIZE(tszFullFileName), tszExt);
|
|
if (FAILED(hRes))
|
|
{
|
|
//
|
|
// Can not happen. CpDir is MAX_PATH
|
|
//
|
|
Assert (FALSE);
|
|
}
|
|
|
|
if (0 != _tcsicmp(tszFullFileName, CpDir))
|
|
{
|
|
DebugPrintEx(
|
|
DEBUG_ERR,
|
|
TEXT("server coverpage does not contain file name only. cover page name: %s "),
|
|
CpDir);
|
|
ec = ERROR_INVALID_PARAMETER;
|
|
goto exit;
|
|
}
|
|
|
|
if (0 == _tcsicmp(tszExt, CP_SHORTCUT_EXT) )
|
|
{
|
|
DebugPrintEx(DEBUG_ERR,
|
|
_T("Server Based Cover Page File Name should not be a link : %s"),
|
|
CpDir);
|
|
ec = ERROR_INVALID_PARAMETER;
|
|
goto exit;
|
|
}
|
|
}
|
|
|
|
p = _tcschr(CpDir, FAX_PATH_SEPARATOR_CHR );
|
|
if (p)
|
|
{
|
|
//
|
|
// the coverpage file name contains a path so just use it.
|
|
//
|
|
if (GetFileAttributes( CpDir ) == 0xffffffff)
|
|
{
|
|
ec = ERROR_FILE_NOT_FOUND;
|
|
DebugPrintEx(DEBUG_ERR,
|
|
_T("GetFileAttributes failed for %ws. ec = %ld"),
|
|
CpDir,
|
|
ec);
|
|
goto exit;
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// the coverpage file name does not contain
|
|
// a path so we must construct a full path name
|
|
//
|
|
if (ServerCoverpage)
|
|
{
|
|
if (!ServerName || ServerName[0] == 0)
|
|
{
|
|
if (!GetServerCpDir( NULL, CpDir, sizeof(CpDir) / sizeof(CpDir[0]) ))
|
|
{
|
|
ec = GetLastError ();
|
|
DebugPrintEx(DEBUG_ERR,
|
|
_T("GetServerCpDir failed . ec = %ld"),
|
|
GetLastError());
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (!GetServerCpDir( ServerName, CpDir, sizeof(CpDir) / sizeof(CpDir[0]) ))
|
|
{
|
|
ec = GetLastError ();
|
|
DebugPrintEx(DEBUG_ERR,
|
|
_T("GetServerCpDir failed . ec = %ld"),
|
|
GetLastError());
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (!GetClientCpDir( CpDir, sizeof(CpDir) / sizeof(CpDir[0])))
|
|
{
|
|
ec = GetLastError ();
|
|
DebugPrintEx(DEBUG_ERR,
|
|
_T("GetClientCpDir failed . ec = %ld"),
|
|
GetLastError());
|
|
}
|
|
}
|
|
|
|
if (ERROR_SUCCESS != ec)
|
|
{
|
|
ec = ERROR_FILE_NOT_FOUND;
|
|
goto exit;
|
|
}
|
|
|
|
hRes = StringCchCat( CpDir, ARR_SIZE(CpDir), TEXT("\\") );
|
|
if (FAILED(hRes))
|
|
{
|
|
DebugPrintEx(DEBUG_ERR,
|
|
TEXT("StringCchCat failed (ec=%lu)"),
|
|
HRESULT_CODE(hRes));
|
|
|
|
ec = HRESULT_CODE(hRes);
|
|
goto exit;
|
|
}
|
|
|
|
hRes = StringCchCat( CpDir, ARR_SIZE(CpDir), CoverPageName );
|
|
if (FAILED(hRes))
|
|
{
|
|
DebugPrintEx(DEBUG_ERR,
|
|
TEXT("StringCchCat failed (ec=%lu)"),
|
|
HRESULT_CODE(hRes));
|
|
|
|
ec = HRESULT_CODE(hRes);
|
|
goto exit;
|
|
}
|
|
|
|
_tsplitpath(CpDir, NULL, NULL, NULL, tszExt);
|
|
if (!_tcslen(tszExt))
|
|
{
|
|
hRes = StringCchCat( CpDir, ARR_SIZE(CpDir), FAX_COVER_PAGE_FILENAME_EXT );
|
|
if (FAILED(hRes))
|
|
{
|
|
DebugPrintEx(DEBUG_ERR,
|
|
TEXT("StringCchCat failed (ec=%lu)"),
|
|
HRESULT_CODE(hRes));
|
|
|
|
ec = HRESULT_CODE(hRes);
|
|
goto exit;
|
|
}
|
|
}
|
|
|
|
if (GetFileAttributes( CpDir ) == 0xffffffff)
|
|
{
|
|
ec = ERROR_FILE_NOT_FOUND;
|
|
goto exit;
|
|
}
|
|
}
|
|
|
|
hRes = StringCchCopy( ResolvedName, dwResolvedNameSize, CpDir );
|
|
if (FAILED(hRes))
|
|
{
|
|
DebugPrintEx(DEBUG_ERR,
|
|
TEXT("StringCchCopy failed (ec=%lu)"),
|
|
HRESULT_CODE(hRes));
|
|
|
|
ec = HRESULT_CODE(hRes);
|
|
goto exit;
|
|
}
|
|
|
|
//
|
|
// Make sure it is not a device
|
|
// Try to open file
|
|
//
|
|
HANDLE hFile = SafeCreateFile (
|
|
ResolvedName,
|
|
GENERIC_READ,
|
|
FILE_SHARE_READ,
|
|
NULL,
|
|
OPEN_EXISTING,
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
NULL);
|
|
if ( INVALID_HANDLE_VALUE == hFile )
|
|
{
|
|
ec = GetLastError ();
|
|
DebugPrintEx(
|
|
DEBUG_ERR,
|
|
TEXT("Opening %s for read failed (ec: %ld)"),
|
|
ResolvedName,
|
|
ec);
|
|
goto exit;
|
|
}
|
|
|
|
if (!CloseHandle (hFile))
|
|
{
|
|
DebugPrintEx(
|
|
DEBUG_ERR,
|
|
TEXT("CloseHandle failed (ec: %ld)"),
|
|
GetLastError());
|
|
}
|
|
|
|
Assert (ERROR_SUCCESS == ec);
|
|
|
|
exit:
|
|
if (ERROR_SUCCESS != ec)
|
|
{
|
|
SetLastError(ec);
|
|
return FALSE;
|
|
}
|
|
return TRUE;
|
|
} // ValidateCoverpage
|
|
|
|
|
|
DWORD
|
|
ViewFile (
|
|
LPCTSTR lpctstrFile
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Launches the application associated with a given file to view it.
|
|
We first attempt to use the "open" verb.
|
|
If that fails, we try the NULL (default) verb.
|
|
|
|
Arguments:
|
|
|
|
lpctstrFile [in] - File name
|
|
|
|
Return Value:
|
|
|
|
Standard Win32 error code
|
|
|
|
--*/
|
|
{
|
|
DWORD dwRes = ERROR_SUCCESS;
|
|
SHELLEXECUTEINFO executeInfo = {0};
|
|
|
|
DEBUG_FUNCTION_NAME(TEXT("ViewFile"));
|
|
|
|
executeInfo.cbSize = sizeof(executeInfo);
|
|
executeInfo.fMask = SEE_MASK_FLAG_NO_UI | SEE_MASK_FLAG_DDEWAIT;
|
|
executeInfo.lpVerb = TEXT("open");
|
|
executeInfo.lpFile = lpctstrFile;
|
|
executeInfo.nShow = SW_SHOWNORMAL;
|
|
//
|
|
// Execute the associated application with the "open" verb
|
|
//
|
|
if(!ShellExecuteEx(&executeInfo))
|
|
{
|
|
DebugPrintEx(
|
|
DEBUG_ERR,
|
|
TEXT("ShellExecuteEx(open) failed (ec: %ld)"),
|
|
GetLastError());
|
|
//
|
|
// "open" verb is not supported. Try the NULL (default) verb.
|
|
//
|
|
executeInfo.lpVerb = NULL;
|
|
if(!ShellExecuteEx(&executeInfo))
|
|
{
|
|
dwRes = GetLastError();
|
|
DebugPrintEx(
|
|
DEBUG_ERR,
|
|
TEXT("ShellExecuteEx(NULL) failed (ec: %ld)"),
|
|
dwRes);
|
|
}
|
|
}
|
|
return dwRes;
|
|
} // ViewFile
|
|
|
|
#ifdef UNICODE
|
|
|
|
DWORD
|
|
CheckToSeeIfSameDir(
|
|
LPWSTR lpwstrDir1,
|
|
LPWSTR lpwstrDir2,
|
|
BOOL* pIsSameDir
|
|
)
|
|
{
|
|
/*++
|
|
|
|
Routine name : IsDiffrentDir
|
|
|
|
Routine description:
|
|
|
|
Checks if both paths point to the same directory. Note that the directory pointed by lpwstrDir1 must exist.
|
|
|
|
Author:
|
|
|
|
Oded Sacher (OdedS), Aug, 2000
|
|
|
|
Arguments:
|
|
|
|
lpwstrDir1 [in] - First path - the directory must exist.
|
|
lpwstrDir2 [in] - Second path - the directory does not have to exist
|
|
pIsSameDir [out] - Receives the answer to "IsSameDir?" Valid only if the function succeeds.
|
|
|
|
Return Value:
|
|
Win32 Erorr code
|
|
|
|
--*/
|
|
Assert (lpwstrDir1 && lpwstrDir2 && pIsSameDir);
|
|
DWORD ec = ERROR_SUCCESS;
|
|
WCHAR wszTestFile1[MAX_PATH];
|
|
WCHAR wszTestFile2[MAX_PATH * 2];
|
|
BOOL fFileCreated = FALSE;
|
|
HANDLE hFile1 = INVALID_HANDLE_VALUE;
|
|
HANDLE hFile2 = INVALID_HANDLE_VALUE;
|
|
LPWSTR lpwstrFileName = NULL;
|
|
DEBUG_FUNCTION_NAME(TEXT("CheckToSeeIfSameDir)"));
|
|
|
|
HRESULT hRes;
|
|
|
|
if (0 == _wcsicmp(lpwstrDir1, lpwstrDir2))
|
|
{
|
|
*pIsSameDir = TRUE;
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
//
|
|
// Create temporary files
|
|
//
|
|
if (!GetTempFileName (lpwstrDir1, L"TST", 0, wszTestFile1))
|
|
{
|
|
//
|
|
// Either the folder doesn't exist or we don't have access
|
|
//
|
|
ec = GetLastError ();
|
|
DebugPrintEx(
|
|
DEBUG_ERR,
|
|
TEXT("GetTempFileName failed with %ld"), ec);
|
|
goto exit;
|
|
}
|
|
|
|
//
|
|
// GetTempFileName created 0 bytes file, that we need to delete before exiting
|
|
//
|
|
fFileCreated = TRUE;
|
|
|
|
hFile1 = SafeCreateFile(
|
|
wszTestFile1,
|
|
0,
|
|
FILE_SHARE_READ|FILE_SHARE_WRITE,
|
|
NULL,
|
|
OPEN_EXISTING,
|
|
0,
|
|
NULL);
|
|
if (INVALID_HANDLE_VALUE == hFile1)
|
|
{
|
|
ec = GetLastError();
|
|
DebugPrintEx(DEBUG_ERR,
|
|
TEXT("CreateFile failed (ec: %ld)"),
|
|
ec);
|
|
goto exit;
|
|
}
|
|
|
|
lpwstrFileName = wcsrchr(wszTestFile1, L'\\');
|
|
Assert (lpwstrFileName);
|
|
|
|
hRes = StringCchCopy (wszTestFile2, ARR_SIZE(wszTestFile2), lpwstrDir2);
|
|
if (FAILED(hRes))
|
|
{
|
|
DebugPrintEx(DEBUG_ERR,
|
|
TEXT("StringCchCopy failed (ec=%lu)"),
|
|
HRESULT_CODE(hRes));
|
|
|
|
ec = HRESULT_CODE(hRes);
|
|
goto exit;
|
|
}
|
|
|
|
hRes = StringCchCat (wszTestFile2, ARR_SIZE(wszTestFile2), lpwstrFileName);
|
|
if (FAILED(hRes))
|
|
{
|
|
DebugPrintEx(DEBUG_ERR,
|
|
TEXT("StringCchCat failed (ec=%lu)"),
|
|
HRESULT_CODE(hRes));
|
|
|
|
ec = HRESULT_CODE(hRes);
|
|
goto exit;
|
|
}
|
|
|
|
hFile2 = SafeCreateFile(
|
|
wszTestFile2,
|
|
0,
|
|
FILE_SHARE_READ|FILE_SHARE_WRITE,
|
|
NULL,
|
|
OPEN_EXISTING,
|
|
0,
|
|
NULL);
|
|
if (INVALID_HANDLE_VALUE == hFile2)
|
|
{
|
|
//
|
|
// Check if failure is *NOT* because of access or availability
|
|
//
|
|
ec = GetLastError ();
|
|
if (ERROR_NOT_ENOUGH_MEMORY == ec ||
|
|
ERROR_OUTOFMEMORY == ec )
|
|
{
|
|
DebugPrintEx(DEBUG_ERR,
|
|
TEXT("CreateFile failed (ec: %ld)"),
|
|
ec);
|
|
goto exit;
|
|
}
|
|
|
|
//
|
|
// On any other failure we asssume that the paths are diffrent
|
|
//
|
|
*pIsSameDir = FALSE;
|
|
ec = ERROR_SUCCESS;
|
|
|
|
goto exit;
|
|
}
|
|
|
|
BY_HANDLE_FILE_INFORMATION hfi1;
|
|
BY_HANDLE_FILE_INFORMATION hfi2;
|
|
|
|
if (!GetFileInformationByHandle(hFile1, &hfi1))
|
|
{
|
|
ec = GetLastError();
|
|
DebugPrintEx(DEBUG_ERR,
|
|
TEXT("GetFileInformationByHandle failed (ec: %ld)"),
|
|
ec);
|
|
goto exit;
|
|
}
|
|
|
|
if (!GetFileInformationByHandle(hFile2, &hfi2))
|
|
{
|
|
ec = GetLastError();
|
|
DebugPrintEx(DEBUG_ERR,
|
|
TEXT("GetFileInformationByHandle failed (ec: %ld)"),
|
|
ec);
|
|
goto exit;
|
|
}
|
|
|
|
if ((hfi1.nFileIndexHigh == hfi2.nFileIndexHigh) &&
|
|
(hfi1.nFileIndexLow == hfi2.nFileIndexLow) &&
|
|
(hfi1.dwVolumeSerialNumber == hfi2.dwVolumeSerialNumber))
|
|
{
|
|
*pIsSameDir = TRUE;
|
|
}
|
|
else
|
|
{
|
|
*pIsSameDir = FALSE;
|
|
}
|
|
|
|
Assert (ERROR_SUCCESS == ec);
|
|
|
|
exit:
|
|
|
|
if (INVALID_HANDLE_VALUE != hFile1)
|
|
{
|
|
if (!CloseHandle(hFile1))
|
|
{
|
|
DebugPrintEx(DEBUG_ERR,
|
|
TEXT("CloseHandle failed (ec: %ld)"),
|
|
GetLastError());
|
|
}
|
|
}
|
|
|
|
if (INVALID_HANDLE_VALUE != hFile2)
|
|
{
|
|
if (!CloseHandle(hFile2))
|
|
{
|
|
DebugPrintEx(DEBUG_ERR,
|
|
TEXT("CloseHandle failed (ec: %ld)"),
|
|
GetLastError());
|
|
}
|
|
}
|
|
|
|
if (TRUE == fFileCreated)
|
|
{
|
|
if (!DeleteFile(wszTestFile1))
|
|
{
|
|
DebugPrintEx(DEBUG_ERR,
|
|
TEXT("DeleteFile failed. File: %s, (ec: %ld)"),
|
|
wszTestFile1,
|
|
GetLastError());
|
|
}
|
|
}
|
|
|
|
return ec;
|
|
}
|
|
#endif //UNICODE
|
|
|
|
|
|
typedef enum
|
|
{
|
|
SAFE_METAFILE_SEMANTICS_NONE = 0x00000000,
|
|
SAFE_METAFILE_SEMANTICS_TEMP = 0x00000001, // File is temporary. Should be deleted on close / reboot
|
|
SAFE_METAFILE_SEMANTICS_SENSITIVE = 0x00000002 // File contains sensitive information. Should not be indexed
|
|
} SAFE_METAFILE_SEMANTICS;
|
|
|
|
static
|
|
HANDLE
|
|
InternalSafeCreateFile(
|
|
LPCTSTR IN lpFileName, // File name
|
|
DWORD IN dwDesiredAccess, // Access mode
|
|
DWORD IN dwShareMode, // Share mode
|
|
LPSECURITY_ATTRIBUTES IN lpSecurityAttributes, // SD
|
|
DWORD IN dwCreationDisposition, // How to create
|
|
DWORD IN dwFlagsAndAttributes, // File attributes
|
|
HANDLE IN hTemplateFile, // Handle to template file
|
|
DWORD IN dwMetaFileSemantics // Meta file semantics
|
|
)
|
|
/*++
|
|
|
|
Routine name : InternalSafeCreateFile
|
|
|
|
Routine description:
|
|
|
|
This is a safe wrapper around the Win32 CreateFile API.
|
|
It only supports creating real files (as opposed to COM ports, named pipes, etc.).
|
|
|
|
It uses some widely-discussed mitigation techniques to guard agaist some well known security
|
|
issues in CreateFile().
|
|
|
|
Author:
|
|
|
|
Eran Yariv (EranY), Mar, 2002
|
|
|
|
Arguments:
|
|
|
|
lpFileName [in] - Refer to the CreateFile() documentation for parameter description.
|
|
dwDesiredAccess [in] - Refer to the CreateFile() documentation for parameter description.
|
|
dwShareMode [in] - Refer to the CreateFile() documentation for parameter description.
|
|
lpSecurityAttributes [in] - Refer to the CreateFile() documentation for parameter description.
|
|
dwCreationDisposition [in] - Refer to the CreateFile() documentation for parameter description.
|
|
dwFlagsAndAttributes [in] - Refer to the CreateFile() documentation for parameter description.
|
|
hTemplateFile [in] - Refer to the CreateFile() documentation for parameter description.
|
|
dwMetaFileSemantics [in] - Meta file semantics.
|
|
This parameter can be a combination of the following values:
|
|
|
|
SAFE_METAFILE_SEMANTICS_TEMP
|
|
The file is a temporary file.
|
|
The file will be created / opened using the FILE_FLAG_DELETE_ON_CLOSE flag.
|
|
When the last file handle is closed, the file will be automatically deleted.
|
|
|
|
In addition, the file is marked for deletion after reboot (Unicode-version only).
|
|
This will only work if the calling thread's user is a member of the local admins group.
|
|
If marking for deletion-post-reboot fails, the InternalSafeCreateFile function call still succeeds.
|
|
|
|
SAFE_METAFILE_SEMANTICS_SENSITIVE
|
|
The file contains sensitive information.
|
|
The current implementation of this function will mark the file with the
|
|
FILE_ATTRIBUTE_NOT_CONTENT_INDEXED flag.
|
|
|
|
Return Value:
|
|
|
|
If the function succeeds, the return value is an open handle to the specified file.
|
|
If the specified file exists before the function call and dwCreationDisposition is CREATE_ALWAYS or OPEN_ALWAYS,
|
|
a call to GetLastError returns ERROR_ALREADY_EXISTS (even though the function has succeeded).
|
|
If the file does not exist before the call, GetLastError returns zero.
|
|
|
|
If the function fails, the return value is INVALID_HANDLE_VALUE. To get extended error information, call GetLastError.
|
|
|
|
For more information see the "Return value" section in the CreateFile() documentation.
|
|
|
|
Remarks:
|
|
|
|
Please refer to the CreateFile() documentation.
|
|
|
|
--*/
|
|
{
|
|
HANDLE hFile;
|
|
DWORD dwFaxFlagsAndAttributes = SECURITY_SQOS_PRESENT | SECURITY_ANONYMOUS;
|
|
DWORD dwFaxShareMode = 0;
|
|
DEBUG_FUNCTION_NAME(TEXT("InternalSafeCreateFile"));
|
|
//
|
|
// Always use SECURITY_SQOS_PRESENT | SECURITY_ANONYMOUS in file flags and attributes.
|
|
// This prevents us from opening a user-supplied named pipe and allowing the other side
|
|
// of that pipe to impersonate the caller.
|
|
//
|
|
if (SAFE_METAFILE_SEMANTICS_SENSITIVE & dwMetaFileSemantics)
|
|
{
|
|
//
|
|
// File contains sensitive data. It should not be indexed.
|
|
//
|
|
dwFaxFlagsAndAttributes |= FILE_ATTRIBUTE_NOT_CONTENT_INDEXED;
|
|
}
|
|
if (SAFE_METAFILE_SEMANTICS_TEMP & dwMetaFileSemantics)
|
|
{
|
|
//
|
|
// File is temporary.
|
|
//
|
|
dwFaxFlagsAndAttributes |= FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_DELETE_ON_CLOSE;
|
|
#ifdef UNICODE
|
|
dwFaxShareMode = FILE_SHARE_DELETE;
|
|
#endif // UNICODE
|
|
}
|
|
|
|
hFile = CreateFile (lpFileName,
|
|
dwDesiredAccess,
|
|
dwShareMode | dwFaxShareMode,
|
|
lpSecurityAttributes,
|
|
dwCreationDisposition,
|
|
dwFlagsAndAttributes | dwFaxFlagsAndAttributes,
|
|
hTemplateFile);
|
|
if (INVALID_HANDLE_VALUE == hFile)
|
|
{
|
|
return hFile;
|
|
}
|
|
//
|
|
// Never allow using non-disk file (e.g. COM ports)
|
|
//
|
|
if (FILE_TYPE_DISK != GetFileType (hFile))
|
|
{
|
|
CloseHandle (hFile);
|
|
SetLastError (ERROR_UNSUPPORTED_TYPE);
|
|
return INVALID_HANDLE_VALUE;
|
|
}
|
|
#ifdef UNICODE
|
|
if (SAFE_METAFILE_SEMANTICS_TEMP & dwMetaFileSemantics)
|
|
{
|
|
//
|
|
// File is temporary.
|
|
// Mark it for delete after reboot.
|
|
// This can fail if we're not admins. That's why we're not checking return value from MoveFileEx.
|
|
//
|
|
MoveFileEx (lpFileName, NULL, MOVEFILE_DELAY_UNTIL_REBOOT);
|
|
}
|
|
#endif // UNICODE
|
|
return hFile;
|
|
} // InternalSafeCreateFile
|
|
|
|
HANDLE
|
|
SafeCreateFile(
|
|
LPCTSTR IN lpFileName, // File name
|
|
DWORD IN dwDesiredAccess, // Access mode
|
|
DWORD IN dwShareMode, // Share mode
|
|
LPSECURITY_ATTRIBUTES IN lpSecurityAttributes, // SD
|
|
DWORD IN dwCreationDisposition, // How to create
|
|
DWORD IN dwFlagsAndAttributes, // File attributes
|
|
HANDLE IN hTemplateFile // Handle to template file
|
|
)
|
|
{
|
|
return InternalSafeCreateFile (lpFileName,
|
|
dwDesiredAccess,
|
|
dwShareMode,
|
|
lpSecurityAttributes,
|
|
dwCreationDisposition,
|
|
dwFlagsAndAttributes,
|
|
hTemplateFile,
|
|
SAFE_METAFILE_SEMANTICS_SENSITIVE);
|
|
} // SafeCreateFile
|
|
|
|
HANDLE
|
|
SafeCreateTempFile(
|
|
LPCTSTR IN lpFileName, // File name
|
|
DWORD IN dwDesiredAccess, // Access mode
|
|
DWORD IN dwShareMode, // Share mode
|
|
LPSECURITY_ATTRIBUTES IN lpSecurityAttributes, // SD
|
|
DWORD IN dwCreationDisposition, // How to create
|
|
DWORD IN dwFlagsAndAttributes, // File attributes
|
|
HANDLE IN hTemplateFile // Handle to template file
|
|
)
|
|
{
|
|
return InternalSafeCreateFile (lpFileName,
|
|
dwDesiredAccess,
|
|
dwShareMode,
|
|
lpSecurityAttributes,
|
|
dwCreationDisposition,
|
|
dwFlagsAndAttributes,
|
|
hTemplateFile,
|
|
SAFE_METAFILE_SEMANTICS_SENSITIVE |
|
|
SAFE_METAFILE_SEMANTICS_TEMP);
|
|
} // SafeCreateTempFile
|
|
|
|
DWORD
|
|
IsValidFaxFolder(
|
|
LPCTSTR szFolder
|
|
)
|
|
/*++
|
|
|
|
Routine name : IsValidFaxFolder
|
|
|
|
Routine description:
|
|
|
|
Check if fax service has access right to a given folder.
|
|
The routine checks for these rights:
|
|
o Create file/Write file
|
|
o Enumerate files
|
|
o Delete file
|
|
|
|
Author:
|
|
|
|
Caliv Nir (t-nicali) Mar, 2002
|
|
|
|
Arguments:
|
|
|
|
lpwstrFolder [in] - the folder name.
|
|
|
|
|
|
Return Value:
|
|
|
|
Win32 error code. ERROR_SUCCESS if the folder can be used by fax service.
|
|
Otherwise, the Win32 error code to return to the caller.
|
|
|
|
--*/
|
|
{
|
|
TCHAR szTestFile[MAX_PATH]={0};
|
|
DWORD dwFileAtt;
|
|
LPTSTR szExpandedFolder = NULL;
|
|
|
|
HANDLE hFind = INVALID_HANDLE_VALUE;
|
|
WIN32_FIND_DATA FindFileData = {0};
|
|
|
|
BOOL bFileCreated = FALSE;
|
|
|
|
DWORD ec = ERROR_SUCCESS;
|
|
|
|
DEBUG_FUNCTION_NAME(TEXT("IsValidFaxFolder"));
|
|
|
|
szExpandedFolder = ExpandEnvironmentString( szFolder );
|
|
if (!szExpandedFolder)
|
|
{
|
|
ec = GetLastError();
|
|
DebugPrintEx( DEBUG_ERR,
|
|
TEXT("ExpandEnvironmentString failed (ec=%lu)."),
|
|
ec);
|
|
return ec;
|
|
}
|
|
|
|
//
|
|
// Check to see if the directory exist
|
|
//
|
|
dwFileAtt = GetFileAttributes( szExpandedFolder );
|
|
if (INVALID_FILE_ATTRIBUTES == dwFileAtt || !(dwFileAtt & FILE_ATTRIBUTE_DIRECTORY))
|
|
{
|
|
//
|
|
// The directory does not exists
|
|
//
|
|
ec = GetLastError ();
|
|
DebugPrintEx(
|
|
DEBUG_ERR,
|
|
TEXT("GetFileAttributes failed with %lu"), ec);
|
|
goto exit;
|
|
}
|
|
|
|
|
|
//
|
|
// Verify that we have access to this folder - Create a temporary file
|
|
//
|
|
if (!GetTempFileName (szExpandedFolder, TEXT("TST"), 0, szTestFile))
|
|
{
|
|
//
|
|
// Either the folder doesn't exist or we don't have access
|
|
//
|
|
ec = GetLastError ();
|
|
DebugPrintEx(
|
|
DEBUG_ERR,
|
|
TEXT("GetTempFileName failed with %ld"), ec);
|
|
goto exit;
|
|
}
|
|
|
|
bFileCreated = TRUE;
|
|
|
|
//
|
|
// Try to enumarate files in this folder
|
|
//
|
|
hFind = FindFirstFile(szTestFile, &FindFileData);
|
|
if (hFind == INVALID_HANDLE_VALUE)
|
|
{
|
|
//
|
|
// Couldn't enumerate folder
|
|
//
|
|
ec = GetLastError ();
|
|
DebugPrintEx(
|
|
DEBUG_ERR,
|
|
TEXT("FindFirstFile failed with %ld"), ec);
|
|
goto exit;
|
|
}
|
|
|
|
Assert(ec == ERROR_SUCCESS);
|
|
|
|
exit:
|
|
//
|
|
// Close find handle
|
|
//
|
|
if (hFind != INVALID_HANDLE_VALUE)
|
|
{
|
|
if(!FindClose(hFind))
|
|
{
|
|
DebugPrintEx(
|
|
DEBUG_ERR,
|
|
TEXT("FindClose failed with %ld"), GetLastError ());
|
|
}
|
|
}
|
|
|
|
if (bFileCreated)
|
|
{
|
|
//
|
|
// Delete the file
|
|
//
|
|
if (!DeleteFile(szTestFile))
|
|
{
|
|
/***********************************************************
|
|
/* Although it's a clean up code we propagate the error code
|
|
/* It may say that we lack the permission to delete this
|
|
/* file.
|
|
/***********************************************************/
|
|
ec = GetLastError ();
|
|
DebugPrintEx(
|
|
DEBUG_ERR,
|
|
TEXT("DeleteFile() failed with %ld"),ec);
|
|
}
|
|
}
|
|
MemFree(szExpandedFolder);
|
|
return ec;
|
|
} // IsValidFaxFolder
|