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.
553 lines
16 KiB
553 lines
16 KiB
/*++
|
|
|
|
Copyright (c) 1990 - 1996 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
Files.c
|
|
|
|
Abstract:
|
|
|
|
This module provides routines required to copy files associated with a
|
|
printer on printer connection
|
|
|
|
Author:
|
|
|
|
Muhunthan Sivapragasam (MuhuntS) 05-Dec-96
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include <precomp.h>
|
|
#include "clusspl.h"
|
|
|
|
HMODULE
|
|
SplLoadLibraryTheCopyFileModule(
|
|
HANDLE hPrinter,
|
|
LPWSTR pszModule
|
|
)
|
|
{
|
|
UINT uErrorMode;
|
|
DWORD dwLen;
|
|
WCHAR szPath[MAX_PATH];
|
|
PSPOOL pSpool = (PSPOOL)hPrinter;
|
|
HMODULE hModule;
|
|
PINIDRIVER pIniDriver;
|
|
|
|
uErrorMode = SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX);
|
|
|
|
//
|
|
// This should be fine because we will be using the process path. Unforunately
|
|
// the registry has been set up not to use a full path, so we can't change this
|
|
// and be sure of not breaking backward compatability.
|
|
//
|
|
hModule = LoadLibrary(pszModule);
|
|
|
|
//
|
|
// If the module could not be found in $Path look for it in the
|
|
// printer driver directory
|
|
//
|
|
if ( !hModule &&
|
|
GetLastError() == ERROR_MOD_NOT_FOUND &&
|
|
(dwLen = GetIniDriverAndDirForThisMachine(pSpool->pIniPrinter,
|
|
szPath,
|
|
&pIniDriver)) ) {
|
|
|
|
if (!BoolFromHResult(StringCchCopy(szPath+dwLen, COUNTOF(szPath) - dwLen, pszModule))) {
|
|
|
|
goto Cleanup;
|
|
}
|
|
|
|
hModule = LoadLibraryEx(szPath, NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
|
|
}
|
|
|
|
Cleanup:
|
|
(VOID)SetErrorMode(uErrorMode);
|
|
|
|
return hModule;
|
|
}
|
|
|
|
|
|
BOOL
|
|
GenerateDirectoryNamesForCopyFilesKey(
|
|
PSPOOL pSpool,
|
|
HKEY hKey,
|
|
LPWSTR *ppszSourceDir,
|
|
LPWSTR *ppszTargetDir,
|
|
DWORD cbMax
|
|
)
|
|
{
|
|
BOOL bRet = FALSE, bInCS = FALSE;
|
|
DWORD dwType, dwSize, dwSourceDirSize, dwTargetDirSize;
|
|
LPWSTR pszDir, ppszFiles, pszModule = NULL, pszPrinterName = NULL;
|
|
HMODULE hModule = NULL;
|
|
DWORD (*pfn)(LPWSTR pszPrinterName,
|
|
LPCWSTR pszDirectory,
|
|
LPBYTE pSplClientInfo,
|
|
DWORD dwLevel,
|
|
LPWSTR pszSourceDir,
|
|
LPDWORD pcchSourceDirSize,
|
|
LPWSTR pszTargetDir,
|
|
LPDWORD pcchTargetDirSize,
|
|
DWORD dwFlags
|
|
);
|
|
SPLCLIENT_INFO_1 SplClientInfo1;
|
|
|
|
//
|
|
// First find the keys we need from the registry
|
|
// "Directory", "Files" values are mandatory. "Module" is optional
|
|
//
|
|
pszDir = (LPWSTR) AllocSplMem(cbMax);
|
|
ppszFiles = (LPWSTR) AllocSplMem(cbMax);
|
|
pszModule = (LPWSTR) AllocSplMem(cbMax);
|
|
|
|
if ( !pszDir || !ppszFiles || !pszModule )
|
|
goto Cleanup;
|
|
|
|
if ( (dwSize = cbMax) &&
|
|
ERROR_SUCCESS == SplRegQueryValue(hKey,
|
|
L"Directory",
|
|
&dwType,
|
|
(LPBYTE)pszDir,
|
|
&dwSize,
|
|
pSpool->pIniSpooler) &&
|
|
dwType == REG_SZ &&
|
|
(dwSize = cbMax) &&
|
|
ERROR_SUCCESS == SplRegQueryValue(hKey,
|
|
L"Files",
|
|
&dwType,
|
|
(LPBYTE)ppszFiles,
|
|
&dwSize,
|
|
pSpool->pIniSpooler) &&
|
|
dwType == REG_MULTI_SZ ) {
|
|
|
|
dwSize = cbMax;
|
|
if ( ERROR_SUCCESS == SplRegQueryValue(hKey,
|
|
L"Module",
|
|
&dwType,
|
|
(LPBYTE)pszModule,
|
|
&dwSize,
|
|
pSpool->pIniSpooler) &&
|
|
dwType != REG_SZ ) {
|
|
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
goto Cleanup;
|
|
}
|
|
}
|
|
|
|
//
|
|
// If a module is given we need to call into to "correct" the path
|
|
// We will first try LoadLibrary on the module, if we can't find the module
|
|
// we will look in the driver directory for it
|
|
//
|
|
if ( pszModule && *pszModule ) {
|
|
|
|
if ( !(hModule = SplLoadLibraryTheCopyFileModule(pSpool, pszModule)) ||
|
|
!((FARPROC)pfn = GetProcAddress(hModule, "GenerateCopyFilePaths")) )
|
|
goto Cleanup;
|
|
}
|
|
|
|
|
|
dwTargetDirSize = MAX_PATH;
|
|
dwSourceDirSize = INTERNET_MAX_HOST_NAME_LENGTH + MAX_PATH;
|
|
*ppszSourceDir = (LPWSTR) AllocSplMem(dwSourceDirSize * sizeof(WCHAR));
|
|
*ppszTargetDir = (LPWSTR) AllocSplMem(dwTargetDirSize * sizeof(WCHAR));
|
|
|
|
if ( !*ppszSourceDir || !*ppszTargetDir )
|
|
goto Cleanup;
|
|
|
|
EnterSplSem();
|
|
bInCS = TRUE;
|
|
pszPrinterName = AllocSplStr(pSpool->pIniPrinter->pName);
|
|
|
|
//
|
|
// For source dir we will give full path the way the client will understand
|
|
// (ie. have correct prefix -- server nam, dns name etc).
|
|
// For target dir we will give a relative path off print$
|
|
//
|
|
if ( !pszPrinterName || wcslen(pszDir) >= dwTargetDirSize ||
|
|
wcslen(pSpool->pFullMachineName) +
|
|
wcslen(pSpool->pIniSpooler->pszDriversShare) +
|
|
wcslen(pszDir) + 2 >= dwSourceDirSize ) {
|
|
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
goto Cleanup;
|
|
|
|
}
|
|
|
|
StringCchPrintf(*ppszSourceDir, dwSourceDirSize,
|
|
L"%ws\\%ws\\%ws",
|
|
pSpool->pFullMachineName,
|
|
pSpool->pIniSpooler->pszDriversShare,
|
|
pszDir);
|
|
|
|
CopyMemory((LPBYTE)&SplClientInfo1, (LPBYTE)&pSpool->SplClientInfo1, sizeof(SPLCLIENT_INFO_1));
|
|
|
|
SplClientInfo1.pUserName = NULL;
|
|
SplClientInfo1.pMachineName = NULL;
|
|
|
|
LeaveSplSem();
|
|
bInCS = FALSE;
|
|
|
|
StringCchCopy(*ppszTargetDir, dwTargetDirSize, pszDir);
|
|
|
|
if ( hModule ) {
|
|
|
|
//
|
|
// On free builds we do not want spooler to crash
|
|
//
|
|
#if DBG
|
|
#else
|
|
try {
|
|
#endif
|
|
if ( ERROR_SUCCESS != pfn(pszPrinterName,
|
|
pszDir,
|
|
(LPBYTE)&SplClientInfo1,
|
|
1,
|
|
*ppszSourceDir,
|
|
&dwSourceDirSize,
|
|
*ppszTargetDir,
|
|
&dwTargetDirSize,
|
|
COPYFILE_FLAG_SERVER_SPOOLER) )
|
|
#if DBG
|
|
goto Cleanup;
|
|
#else
|
|
leave;
|
|
#endif
|
|
bRet = TRUE;
|
|
#if DBG
|
|
#else
|
|
} except(1) {
|
|
}
|
|
#endif
|
|
} else {
|
|
|
|
bRet = TRUE;
|
|
}
|
|
|
|
|
|
Cleanup:
|
|
if ( bInCS )
|
|
LeaveSplSem();
|
|
|
|
SplOutSem();
|
|
|
|
FreeSplStr(pszDir);
|
|
FreeSplStr(ppszFiles);
|
|
FreeSplStr(pszModule);
|
|
FreeSplStr(pszPrinterName);
|
|
|
|
if ( hModule )
|
|
FreeLibrary(hModule);
|
|
|
|
if ( !bRet ) {
|
|
|
|
FreeSplStr(*ppszSourceDir);
|
|
FreeSplStr(*ppszTargetDir);
|
|
*ppszSourceDir = *ppszTargetDir = NULL;
|
|
}
|
|
|
|
return bRet;
|
|
}
|
|
|
|
|
|
LPWSTR
|
|
BuildFilesCopiedAsAString(
|
|
PINTERNAL_DRV_FILE pInternalDriverFile,
|
|
DWORD dwCount
|
|
)
|
|
/*++
|
|
For files copied we log an event. This routine allocates memory and
|
|
generates the file list as a comma separated string
|
|
--*/
|
|
{
|
|
DWORD dwIndex;
|
|
SIZE_T Size;
|
|
LPWSTR pszRet, psz2;
|
|
LPCWSTR psz;
|
|
|
|
//
|
|
// Must have some files.
|
|
//
|
|
SPLASSERT( dwCount );
|
|
|
|
for ( dwIndex = 0, Size = 0 ; dwIndex < dwCount ; ++dwIndex ) {
|
|
|
|
//
|
|
// Find the file name part
|
|
//
|
|
psz = FindFileName(pInternalDriverFile[dwIndex]. pFileName);
|
|
|
|
if( psz ){
|
|
|
|
//
|
|
// Two characters for ", " separator. This also includes the
|
|
// terminating NULL sice we count this for all files, but only
|
|
// append ", " to the internal ones.
|
|
//
|
|
Size += wcslen(psz) + 2;
|
|
}
|
|
}
|
|
|
|
pszRet = AllocSplMem((DWORD)(Size * sizeof(WCHAR)));
|
|
|
|
if ( !pszRet )
|
|
return NULL;
|
|
|
|
for ( dwIndex = 0, psz2 = pszRet ; dwIndex < dwCount ; ++dwIndex ) {
|
|
|
|
//
|
|
// Find the file name part
|
|
//
|
|
psz = FindFileName(pInternalDriverFile[dwIndex].pFileName );
|
|
|
|
if( psz ){
|
|
|
|
StringCchCopyEx(psz2, Size, psz, &psz2, &Size, 0);
|
|
|
|
if ( dwIndex < dwCount - 1) {
|
|
|
|
StringCchCopyEx(psz2, Size, L", ", &psz2, &Size, 0);
|
|
}
|
|
}
|
|
}
|
|
|
|
return pszRet;
|
|
}
|
|
|
|
BOOL
|
|
SplCopyNumberOfFiles(
|
|
LPWSTR pszPrinterName,
|
|
LPWSTR *ppszSourceFileNames,
|
|
DWORD dwCount,
|
|
LPWSTR pszTargetDir,
|
|
LPBOOL pbFilesAddedOrUpdated
|
|
)
|
|
{
|
|
BOOL bRet=FALSE, bFilesMoved;
|
|
LPWSTR pszFiles;
|
|
DWORD dwIndex;
|
|
LPWSTR pszNewDir = NULL;
|
|
LPWSTR pszOldDir = NULL;
|
|
BOOL bFilesUpdated;
|
|
INTERNAL_DRV_FILE *pInternalDriverFiles = NULL;
|
|
BOOL bWaitForReboot = FALSE;
|
|
|
|
*pbFilesAddedOrUpdated = FALSE;
|
|
|
|
pInternalDriverFiles = (INTERNAL_DRV_FILE *) AllocSplMem(dwCount*sizeof(INTERNAL_DRV_FILE));
|
|
|
|
if ( !pInternalDriverFiles )
|
|
return FALSE;
|
|
|
|
for ( dwIndex = 0 ; dwIndex < dwCount ; ++dwIndex ) {
|
|
|
|
pInternalDriverFiles[dwIndex].pFileName = ppszSourceFileNames[dwIndex];
|
|
|
|
//
|
|
// This is "fine" because this ultimately comes from the server registry,
|
|
// so it is no worse than anything else in point and print. Which is a
|
|
// known filed issue.
|
|
//
|
|
pInternalDriverFiles[dwIndex].hFileHandle = CreateFile(ppszSourceFileNames[dwIndex],
|
|
GENERIC_READ,
|
|
FILE_SHARE_READ,
|
|
NULL,
|
|
OPEN_EXISTING,
|
|
FILE_FLAG_SEQUENTIAL_SCAN,
|
|
NULL);
|
|
|
|
if ( pInternalDriverFiles[dwIndex].hFileHandle == INVALID_HANDLE_VALUE )
|
|
goto Cleanup;
|
|
}
|
|
|
|
if ( !DirectoryExists(pszTargetDir) &&
|
|
!CreateDirectoryWithoutImpersonatingUser(pszTargetDir) )
|
|
goto Cleanup;
|
|
|
|
// Create the New Directory
|
|
|
|
if (!BoolFromStatus(StrCatAlloc(&pszNewDir, pszTargetDir, L"\\New", NULL))) {
|
|
goto Cleanup;
|
|
}
|
|
|
|
if (!DirectoryExists(pszNewDir) &&
|
|
!CreateDirectoryWithoutImpersonatingUser(pszNewDir)) {
|
|
|
|
// Failed to create New directory
|
|
goto Cleanup;
|
|
}
|
|
|
|
// Create the Old Directory
|
|
if (!BoolFromStatus(StrCatAlloc(&pszOldDir, pszTargetDir, L"\\Old", NULL))) {
|
|
goto Cleanup;
|
|
}
|
|
|
|
if (!DirectoryExists(pszOldDir) &&
|
|
!CreateDirectoryWithoutImpersonatingUser(pszOldDir)) {
|
|
|
|
// Failed to create Old directory
|
|
goto Cleanup;
|
|
}
|
|
|
|
|
|
EnterSplSem();
|
|
|
|
bFilesUpdated = FALSE;
|
|
|
|
for (dwIndex = 0 ; dwIndex < dwCount ; ++dwIndex) {
|
|
|
|
if (!(bRet = UpdateFile(NULL,
|
|
pInternalDriverFiles[dwIndex].hFileHandle,
|
|
pInternalDriverFiles[dwIndex].pFileName,
|
|
0,
|
|
pszTargetDir,
|
|
APD_COPY_NEW_FILES,
|
|
TRUE,
|
|
&bFilesUpdated,
|
|
&bFilesMoved,
|
|
TRUE,
|
|
FALSE))) {
|
|
|
|
//
|
|
// Files could not be copied correctly
|
|
//
|
|
break;
|
|
}
|
|
|
|
if (bFilesUpdated) {
|
|
*pbFilesAddedOrUpdated = TRUE;
|
|
}
|
|
}
|
|
|
|
if (bRet && *pbFilesAddedOrUpdated) {
|
|
|
|
bRet = MoveNewDriverRelatedFiles( pszNewDir,
|
|
pszTargetDir,
|
|
pszOldDir,
|
|
pInternalDriverFiles,
|
|
dwCount,
|
|
NULL,
|
|
NULL);
|
|
//
|
|
// Don't delete "New" directory if the files couldn't be moved in "Color" directory
|
|
//
|
|
bWaitForReboot = !bRet;
|
|
|
|
}
|
|
|
|
LeaveSplSem();
|
|
|
|
Cleanup:
|
|
|
|
if ( pszNewDir ) {
|
|
DeleteDirectoryRecursively(pszNewDir, bWaitForReboot);
|
|
FreeSplMem(pszNewDir);
|
|
}
|
|
|
|
if ( pszOldDir ) {
|
|
DeleteDirectoryRecursively(pszOldDir, FALSE);
|
|
FreeSplMem(pszOldDir);
|
|
}
|
|
|
|
if ( *pbFilesAddedOrUpdated &&
|
|
(pszFiles = BuildFilesCopiedAsAString(pInternalDriverFiles, dwCount)) ) {
|
|
|
|
SplLogEvent(pLocalIniSpooler,
|
|
LOG_WARNING,
|
|
MSG_FILES_COPIED,
|
|
FALSE,
|
|
pszFiles,
|
|
pszPrinterName,
|
|
NULL);
|
|
FreeSplMem(pszFiles);
|
|
}
|
|
|
|
if ( pInternalDriverFiles ) {
|
|
|
|
while ( dwIndex-- )
|
|
CloseHandle(pInternalDriverFiles[dwIndex].hFileHandle);
|
|
FreeSplMem(pInternalDriverFiles);
|
|
}
|
|
|
|
return bRet;
|
|
}
|
|
|
|
|
|
BOOL
|
|
SplCopyFileEvent(
|
|
HANDLE hPrinter,
|
|
LPWSTR pszKey,
|
|
DWORD dwCopyFileEvent
|
|
)
|
|
{
|
|
BOOL bRet = FALSE;
|
|
DWORD dwNeeded, dwType, dwLastError;
|
|
LPWSTR pszModule = NULL;
|
|
PSPOOL pSpool = (PSPOOL)hPrinter;
|
|
HMODULE hModule = NULL;
|
|
BOOL (*pfnSpoolerCopyFileEvent)(
|
|
LPWSTR pszPrinterName,
|
|
LPWSTR pszKey,
|
|
DWORD dwCopyFileEvent
|
|
);
|
|
|
|
SPLASSERT(pSpool->pIniSpooler->signature == ISP_SIGNATURE);
|
|
|
|
dwLastError = SplGetPrinterDataEx(hPrinter,
|
|
pszKey,
|
|
L"Module",
|
|
&dwType,
|
|
NULL,
|
|
0,
|
|
&dwNeeded);
|
|
|
|
//
|
|
// If there is no module name there is no callback needed
|
|
//
|
|
if ( dwLastError == ERROR_FILE_NOT_FOUND )
|
|
return TRUE;
|
|
|
|
if ( dwLastError != ERROR_SUCCESS ||
|
|
!(pszModule = (LPWSTR) AllocSplMem(dwNeeded)) ||
|
|
SplGetPrinterDataEx(hPrinter,
|
|
pszKey,
|
|
L"Module",
|
|
&dwType,
|
|
(LPBYTE)pszModule,
|
|
dwNeeded,
|
|
&dwNeeded) ||
|
|
dwType != REG_SZ ) {
|
|
|
|
goto Cleanup;
|
|
}
|
|
|
|
if ( !(hModule = SplLoadLibraryTheCopyFileModule(hPrinter,
|
|
pszModule)) ||
|
|
!((FARPROC)pfnSpoolerCopyFileEvent = GetProcAddress(hModule,
|
|
"SpoolerCopyFileEvent")) )
|
|
goto Cleanup;
|
|
|
|
#if DBG
|
|
#else
|
|
try {
|
|
#endif
|
|
bRet = pfnSpoolerCopyFileEvent(pSpool->pName,
|
|
pszKey,
|
|
dwCopyFileEvent);
|
|
|
|
#if DBG
|
|
#else
|
|
} except(1) {
|
|
}
|
|
#endif
|
|
|
|
Cleanup:
|
|
FreeSplStr(pszModule);
|
|
|
|
if ( hModule )
|
|
FreeLibrary(hModule);
|
|
|
|
return bRet;
|
|
}
|