1242 lines
30 KiB
C
1242 lines
30 KiB
C
//*************************************************************
|
|
//
|
|
// Functions to copy the profile directory
|
|
//
|
|
// Microsoft Confidential
|
|
// Copyright (c) Microsoft Corporation 1995
|
|
// All rights reserved
|
|
//
|
|
//*************************************************************
|
|
|
|
#include "uenv.h"
|
|
|
|
//
|
|
// Local function proto-types
|
|
//
|
|
|
|
BOOL RecurseDirectory (LPTSTR lpSrcDir, LPTSTR lpDestDir, DWORD dwFlags,
|
|
LPFILEINFO *llSrcDirs, LPFILEINFO *llSrcFiles);
|
|
BOOL AddFileInfoNode (LPFILEINFO *lpFileInfo, LPTSTR lpSrcFile,
|
|
LPTSTR lpDestFile, LPFILETIME ftFileTime,
|
|
DWORD dwFileSize, DWORD dwFileAttribs);
|
|
BOOL FreeFileInfoList (LPFILEINFO lpFileInfo);
|
|
BOOL SyncItems (LPFILEINFO lpSrcItems, LPFILEINFO lpDestItems, BOOL bFile);
|
|
void CopyFileFunc (LPTHREADINFO lpThreadInfo);
|
|
|
|
//*************************************************************
|
|
//
|
|
// CopyProfileDirectory()
|
|
//
|
|
// Purpose: Copies the profile directory from the source
|
|
// to the destination
|
|
//
|
|
//
|
|
// Parameters: LPTSTR lpSourceDir - Source directory
|
|
// LPTSTR lpDestDir - Destination directory
|
|
// DWORD dwFlags - Flags
|
|
//
|
|
//
|
|
// Return: (BOOL) TRUE if successful
|
|
// FALSE if an error occurs
|
|
//
|
|
//
|
|
// Comments:
|
|
//
|
|
//
|
|
// History: Date Author Comment
|
|
// 5/24/95 ericflo Created
|
|
//
|
|
//*************************************************************
|
|
|
|
BOOL CopyProfileDirectory (LPCTSTR lpSourceDir, LPCTSTR lpDestinationDir,
|
|
DWORD dwFlags)
|
|
{
|
|
LPTSTR lpSrcDir = NULL, lpDestDir = NULL;
|
|
LPTSTR lpSrcEnd, lpDestEnd;
|
|
LPFILEINFO lpSrcFiles = NULL, lpDestFiles = NULL;
|
|
LPFILEINFO lpSrcDirs = NULL, lpDestDirs = NULL;
|
|
LPFILEINFO lpTemp;
|
|
CRITICAL_SECTION Crit;
|
|
THREADINFO ThreadInfo;
|
|
DWORD dwThreadId;
|
|
HANDLE hThreads[NUM_COPY_THREADS];
|
|
DWORD dwThreadCount = 0;
|
|
HANDLE hFile;
|
|
WIN32_FIND_DATA fd;
|
|
BOOL bResult = FALSE;
|
|
BOOL bSynchronize = FALSE;
|
|
UINT uiResult;
|
|
UINT i;
|
|
|
|
|
|
//
|
|
// Verbose output
|
|
//
|
|
|
|
DebugMsg((DM_VERBOSE, TEXT("CopyProfileDirectory: Entering, lpSourceDir = <%s>, lpDestinationDir = <%s>, dwFlags = 0x%x"),
|
|
lpSourceDir, lpDestinationDir, dwFlags));
|
|
|
|
|
|
//
|
|
// Validate parameters
|
|
//
|
|
|
|
if (!lpSourceDir || !lpDestinationDir) {
|
|
DebugMsg((DM_WARNING, TEXT("CopyProfileDirectory: received NULL pointer")));
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Is this a full sync copy (delete extra files / directories in dest).
|
|
//
|
|
|
|
if (dwFlags & CPD_SYNCHRONIZE) {
|
|
bSynchronize = TRUE;
|
|
}
|
|
|
|
|
|
//
|
|
// Test / Create the destination directory
|
|
//
|
|
|
|
if (!CreateNestedDirectory(lpDestinationDir, NULL)) {
|
|
DebugMsg((DM_WARNING, TEXT("CopyProfileDirectory: Failed to create the destination directory. Error = %d"),
|
|
GetLastError()));
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
//
|
|
// Create and set up the directory buffers
|
|
//
|
|
|
|
lpSrcDir = LocalAlloc(LPTR, (2 * MAX_PATH) * sizeof(TCHAR));
|
|
lpDestDir = LocalAlloc(LPTR, (2 * MAX_PATH) * sizeof(TCHAR));
|
|
|
|
if (!lpSrcDir || !lpDestDir) {
|
|
DebugMsg((DM_WARNING, TEXT("CopyProfileDirectory: Failed to allocate memory for working directories")));
|
|
goto Exit;
|
|
}
|
|
|
|
|
|
lstrcpy (lpSrcDir, lpSourceDir);
|
|
lstrcpy (lpDestDir, lpDestinationDir);
|
|
|
|
|
|
//
|
|
// Setup ending pointers
|
|
//
|
|
|
|
lpSrcEnd = CheckSlash (lpSrcDir);
|
|
lpDestEnd = CheckSlash (lpDestDir);
|
|
|
|
|
|
|
|
//
|
|
// Step 1: Loop through the shell folders gathering info
|
|
//
|
|
|
|
if (dwFlags & CPD_USESPECIALFOLDERS) {
|
|
|
|
//
|
|
// If the caller wants to use the special folders
|
|
// only, then loop through all of the known special
|
|
// folders only coping those directories and files.
|
|
//
|
|
// Notes:
|
|
// 1) no files in the root will be copied
|
|
// 2) This does work for internation profiles
|
|
// since the directories names will be in one
|
|
// language and userenv.dll will be in another
|
|
// 3) Setup is the only known component using this
|
|
// flag (to upgrade Win95 machines).
|
|
//
|
|
|
|
for (i=0; i < NUM_TIER1_FOLDERS; i++) {
|
|
|
|
//
|
|
// Setup the source and dest pointers
|
|
//
|
|
|
|
lstrcpy (lpSrcEnd, c_ShellFolders[i].lpFolderLocation);
|
|
lstrcpy (lpDestEnd, c_ShellFolders[i].lpFolderLocation);
|
|
|
|
|
|
//
|
|
// Test if the directory exists
|
|
//
|
|
|
|
hFile = FindFirstFile(lpSrcDir, &fd);
|
|
|
|
if (hFile != INVALID_HANDLE_VALUE) {
|
|
|
|
|
|
FindClose (hFile);
|
|
|
|
|
|
//
|
|
// Add to the list of directories
|
|
//
|
|
|
|
if (!AddFileInfoNode (&lpSrcDirs, lpSrcDir, lpDestDir, NULL, 0, fd.dwFileAttributes)) {
|
|
DebugMsg((DM_WARNING, TEXT("CopyProfileDirectory: AddFileInfoNode failed")));
|
|
goto Exit;
|
|
}
|
|
|
|
|
|
//
|
|
// Recurse the source directory
|
|
//
|
|
|
|
bResult = RecurseDirectory(lpSrcDir, lpDestDir, dwFlags,
|
|
&lpSrcDirs, &lpSrcFiles);
|
|
|
|
if (!bResult) {
|
|
DebugMsg((DM_VERBOSE, TEXT("CopyProfileDirectory: RecurseDirectory returned FALSE")));
|
|
}
|
|
|
|
|
|
if (bSynchronize) {
|
|
|
|
//
|
|
// Recurse the destination directory
|
|
//
|
|
|
|
bResult = RecurseDirectory(lpDestDir, lpSrcDir, dwFlags,
|
|
&lpDestDirs, &lpDestFiles);
|
|
|
|
if (!bResult) {
|
|
DebugMsg((DM_VERBOSE, TEXT("CopyProfileDirectory: RecurseDirectory returned FALSE")));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
|
|
//
|
|
// This version will copy every file / directory found
|
|
// in the profile directory except for ntuser.* files
|
|
// which will be handled below.
|
|
//
|
|
|
|
//
|
|
// Setup the source and dest pointers
|
|
//
|
|
|
|
lstrcpy (lpSrcEnd, c_szStarDotStar);
|
|
|
|
|
|
//
|
|
// Look for files/directories
|
|
//
|
|
|
|
hFile = FindFirstFile(lpSrcDir, &fd);
|
|
|
|
if (hFile == INVALID_HANDLE_VALUE) {
|
|
goto Exit;
|
|
}
|
|
|
|
|
|
do {
|
|
|
|
//
|
|
// Append the file / directory name to the working buffers
|
|
//
|
|
|
|
lstrcpy (lpSrcEnd, fd.cFileName);
|
|
lstrcpy (lpDestEnd, fd.cFileName);
|
|
|
|
|
|
if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
|
|
|
|
|
|
//
|
|
// Check for "." and ".."
|
|
//
|
|
|
|
if (!lstrcmpi(fd.cFileName, c_szDot)) {
|
|
continue;
|
|
}
|
|
|
|
if (!lstrcmpi(fd.cFileName, c_szDotDot)) {
|
|
continue;
|
|
}
|
|
|
|
|
|
//
|
|
// Add to the list of directories
|
|
//
|
|
|
|
if (!AddFileInfoNode (&lpSrcDirs, lpSrcDir, lpDestDir, NULL, 0, fd.dwFileAttributes)) {
|
|
DebugMsg((DM_WARNING, TEXT("CopyProfileDirectory: AddFileInfoNode failed")));
|
|
FindClose (hFile);
|
|
goto Exit;
|
|
}
|
|
|
|
|
|
//
|
|
// Recurse the source directory
|
|
//
|
|
|
|
bResult = RecurseDirectory(lpSrcDir, lpDestDir, dwFlags,
|
|
&lpSrcDirs, &lpSrcFiles);
|
|
|
|
if (!bResult) {
|
|
DebugMsg((DM_VERBOSE, TEXT("CopyProfileDirectory: RecurseDirectory returned FALSE")));
|
|
}
|
|
|
|
|
|
if (bSynchronize) {
|
|
|
|
//
|
|
// Recurse the destination directory
|
|
//
|
|
|
|
bResult = RecurseDirectory(lpDestDir, lpSrcDir, dwFlags,
|
|
&lpDestDirs, &lpDestFiles);
|
|
|
|
if (!bResult) {
|
|
DebugMsg((DM_VERBOSE, TEXT("CopyProfileDirectory: RecurseDirectory returned FALSE")));
|
|
}
|
|
}
|
|
} else {
|
|
|
|
//
|
|
// If the filename found starts with "ntuser", then ignore
|
|
// it because the hive will be copied below (if appropriate).
|
|
//
|
|
|
|
if (lstrlen(fd.cFileName) >= 6) {
|
|
if (CompareString (LOCALE_SYSTEM_DEFAULT, NORM_IGNORECASE,
|
|
fd.cFileName, 6,
|
|
TEXT("ntuser"), 6) == 2) {
|
|
continue;
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// We found a file. Add it to the list.
|
|
//
|
|
|
|
if (!AddFileInfoNode (&lpSrcFiles, lpSrcDir, lpDestDir,
|
|
&fd.ftLastWriteTime, fd.nFileSizeLow,
|
|
fd.dwFileAttributes)) {
|
|
DebugMsg((DM_WARNING, TEXT("CopyProfileDirctory: AddFileInfoNode failed")));
|
|
FindClose (hFile);
|
|
goto Exit;
|
|
}
|
|
|
|
}
|
|
|
|
//
|
|
// Find the next entry
|
|
//
|
|
|
|
} while (FindNextFile(hFile, &fd));
|
|
|
|
FindClose (hFile);
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// Step 2: Create all the directories
|
|
//
|
|
|
|
lpTemp = lpSrcDirs;
|
|
|
|
while (lpTemp) {
|
|
|
|
uiResult = CreateNestedDirectory(lpTemp->szDest, NULL);
|
|
|
|
if (!uiResult) {
|
|
DebugMsg((DM_WARNING, TEXT("CopyProfileDirectory: Failed to create the destination directory <%s>. Error = %d"),
|
|
lpTemp->szDest, GetLastError()));
|
|
goto Exit;
|
|
}
|
|
|
|
|
|
if (uiResult == ERROR_ALREADY_EXISTS) {
|
|
lpTemp->dwFlags |= FI_DIREXISTED;
|
|
|
|
} else {
|
|
|
|
//
|
|
// We created the directory. Set the attributes and security
|
|
//
|
|
|
|
SetFileAttributes (lpTemp->szDest, lpTemp->dwFileAttribs);
|
|
|
|
}
|
|
|
|
|
|
lpTemp = lpTemp->pNext;
|
|
}
|
|
|
|
|
|
//
|
|
// Step 3: Copy the files
|
|
//
|
|
|
|
if (dwFlags & CPD_SLOWCOPY) {
|
|
|
|
//
|
|
// Copy the files one at a time...
|
|
//
|
|
|
|
lpTemp = lpSrcFiles;
|
|
|
|
while (lpTemp) {
|
|
|
|
if (!ReconcileFile (lpTemp->szSrc, lpTemp->szDest, dwFlags,
|
|
&lpTemp->ftSrc)) {
|
|
DebugMsg((DM_WARNING, TEXT("CopyProfileDirectory: Failed to create the destination directory <%s>. Error = %d"),
|
|
lpTemp->szDest, GetLastError()));
|
|
goto Exit;
|
|
}
|
|
|
|
lpTemp = lpTemp->pNext;
|
|
}
|
|
|
|
} else {
|
|
|
|
if (lpSrcFiles) {
|
|
|
|
HANDLE hThreadToken;
|
|
|
|
|
|
if (!OpenThreadToken (GetCurrentThread(), TOKEN_IMPERSONATE,
|
|
TRUE, &hThreadToken)) {
|
|
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_IMPERSONATE,
|
|
&hThreadToken)) {
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// Multi-threaded copy
|
|
//
|
|
|
|
InitializeCriticalSection (&Crit);
|
|
|
|
ThreadInfo.dwFlags = dwFlags;
|
|
ThreadInfo.lpCrit = &Crit;
|
|
ThreadInfo.lpSrcFiles = lpSrcFiles;
|
|
|
|
//
|
|
// Create the file copy threads
|
|
//
|
|
|
|
for (i = 0; i < NUM_COPY_THREADS; i++) {
|
|
if (hThreads[dwThreadCount] = CreateThread (NULL,
|
|
0,
|
|
(LPTHREAD_START_ROUTINE) CopyFileFunc,
|
|
(LPVOID) &ThreadInfo,
|
|
CREATE_SUSPENDED,
|
|
&dwThreadId)) {
|
|
|
|
SetThreadToken(&hThreads[dwThreadCount], hThreadToken);
|
|
ResumeThread (hThreads[dwThreadCount]);
|
|
dwThreadCount++;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Wait for the threads to finish
|
|
//
|
|
|
|
if (WaitForMultipleObjects (dwThreadCount, hThreads, TRUE, INFINITE) == WAIT_FAILED) {
|
|
for (i = 0; i < dwThreadCount; i++) {
|
|
TerminateThread (hThreads[i], 1);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Clean up
|
|
//
|
|
|
|
CloseHandle (hThreadToken);
|
|
|
|
for (i = 0; i < dwThreadCount; i++) {
|
|
CloseHandle (hThreads[i]);
|
|
}
|
|
|
|
DeleteCriticalSection (&Crit);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// Step 4: Copy the actual hive and log file
|
|
//
|
|
|
|
if (!(dwFlags & CPD_IGNOREHIVE)) {
|
|
|
|
|
|
//
|
|
// Search for all user hives
|
|
//
|
|
|
|
if (dwFlags & CPD_WIN95HIVE) {
|
|
|
|
lstrcpy (lpSrcEnd, c_szUserStar);
|
|
|
|
} else {
|
|
|
|
lstrcpy (lpSrcEnd, c_szNTUserStar);
|
|
|
|
}
|
|
|
|
|
|
//
|
|
// Enumerate
|
|
//
|
|
|
|
hFile = FindFirstFile(lpSrcDir, &fd);
|
|
|
|
if (hFile == INVALID_HANDLE_VALUE) {
|
|
DebugMsg((DM_WARNING, TEXT("CopyProfileDirectory: FindFirstFile failed to find a hive!. Error = %d"),
|
|
GetLastError()));
|
|
goto Exit;
|
|
}
|
|
|
|
|
|
do {
|
|
|
|
//
|
|
// Setup the filename
|
|
//
|
|
|
|
lstrcpy (lpSrcEnd, fd.cFileName);
|
|
lstrcpy (lpDestEnd, fd.cFileName);
|
|
|
|
|
|
//
|
|
// Copy the hive
|
|
//
|
|
|
|
if (!ReconcileFile(lpSrcDir, lpDestDir, dwFlags, NULL)) {
|
|
DebugMsg((DM_WARNING, TEXT("CopyProfileDirectory: ReconcileFile failed with error = %d"),
|
|
GetLastError()));
|
|
if (!(dwFlags & CPD_IGNORECOPYERRORS)) {
|
|
FindClose(hFile);
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// Find the next entry
|
|
//
|
|
|
|
} while (FindNextFile(hFile, &fd));
|
|
|
|
|
|
FindClose(hFile);
|
|
}
|
|
|
|
//
|
|
// Step 5: Synchronize the directories and files if appropriate
|
|
//
|
|
|
|
if (bSynchronize) {
|
|
|
|
//
|
|
// Files first...
|
|
//
|
|
|
|
SyncItems (lpSrcFiles, lpDestFiles, TRUE);
|
|
|
|
//
|
|
// Now the directories...
|
|
//
|
|
|
|
SyncItems (lpSrcDirs, lpDestDirs, FALSE);
|
|
}
|
|
|
|
|
|
//
|
|
// Success
|
|
//
|
|
|
|
bResult = TRUE;
|
|
|
|
|
|
Exit:
|
|
|
|
|
|
//
|
|
// Free the memory allocated above
|
|
//
|
|
|
|
if (lpSrcDir) {
|
|
LocalFree(lpSrcDir);
|
|
}
|
|
|
|
if (lpDestDir) {
|
|
LocalFree(lpDestDir);
|
|
}
|
|
|
|
if (lpSrcFiles) {
|
|
FreeFileInfoList(lpSrcFiles);
|
|
}
|
|
|
|
if (lpDestFiles) {
|
|
FreeFileInfoList(lpDestFiles);
|
|
}
|
|
|
|
if (lpSrcDirs) {
|
|
FreeFileInfoList(lpSrcDirs);
|
|
}
|
|
|
|
if (lpDestDirs) {
|
|
FreeFileInfoList(lpDestDirs);
|
|
}
|
|
|
|
//
|
|
// Verbose output
|
|
//
|
|
|
|
DebugMsg((DM_VERBOSE, TEXT("CopyProfileDirectory: Leaving with a return value of %d"), bResult));
|
|
|
|
return bResult;
|
|
}
|
|
|
|
//*************************************************************
|
|
//
|
|
// RecurseDirectory()
|
|
//
|
|
// Purpose: Recurses through the subdirectory coping files.
|
|
//
|
|
// Parameters: lpSrcDir - Source directory working buffer
|
|
// lpDestDir - Destination directory working buffer
|
|
// dwFlags - dwFlags
|
|
// llSrcDirs - Link list of directories
|
|
// llSrcFiles - Link list of files
|
|
//
|
|
// Return: TRUE if successful
|
|
// FALSE if an error occurs
|
|
//
|
|
// Comments: 1) The source and dest directories will already have
|
|
// the trailing backslash when entering this function.
|
|
// 2) The current working directory is the source directory.
|
|
//
|
|
// History: Date Author Comment
|
|
// 5/25/95 ericflo Created
|
|
//
|
|
//*************************************************************
|
|
|
|
BOOL RecurseDirectory (LPTSTR lpSrcDir, LPTSTR lpDestDir, DWORD dwFlags,
|
|
LPFILEINFO *llSrcDirs, LPFILEINFO *llSrcFiles)
|
|
{
|
|
HANDLE hFile = INVALID_HANDLE_VALUE;
|
|
WIN32_FIND_DATA fd;
|
|
LPTSTR lpSrcEnd, lpDestEnd;
|
|
BOOL bResult = TRUE;
|
|
|
|
|
|
//
|
|
// Setup the ending pointers
|
|
//
|
|
|
|
lpSrcEnd = CheckSlash (lpSrcDir);
|
|
lpDestEnd = CheckSlash (lpDestDir);
|
|
|
|
|
|
//
|
|
// Append *.* to the source directory
|
|
//
|
|
|
|
lstrcpy(lpSrcEnd, c_szStarDotStar);
|
|
|
|
|
|
|
|
//
|
|
// Search through the source directory
|
|
//
|
|
|
|
hFile = FindFirstFile(lpSrcDir, &fd);
|
|
|
|
if (hFile == INVALID_HANDLE_VALUE) {
|
|
|
|
if ( (GetLastError() == ERROR_FILE_NOT_FOUND) ||
|
|
(GetLastError() == ERROR_PATH_NOT_FOUND) ) {
|
|
|
|
//
|
|
// bResult is already initialized to TRUE, so
|
|
// just fall through.
|
|
//
|
|
|
|
} else {
|
|
DebugMsg((DM_WARNING, TEXT("RecurseDirectory: FindFirstFile failed. Error = %d"),
|
|
GetLastError()));
|
|
|
|
bResult = FALSE;
|
|
}
|
|
|
|
goto RecurseDir_Exit;
|
|
}
|
|
|
|
|
|
do {
|
|
|
|
//
|
|
// Append the file / directory name to the working buffers
|
|
//
|
|
|
|
lstrcpy (lpSrcEnd, fd.cFileName);
|
|
lstrcpy (lpDestEnd, fd.cFileName);
|
|
|
|
|
|
if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
|
|
|
|
//
|
|
// Check for "." and ".."
|
|
//
|
|
|
|
if (!lstrcmpi(fd.cFileName, c_szDot)) {
|
|
continue;
|
|
}
|
|
|
|
if (!lstrcmpi(fd.cFileName, c_szDotDot)) {
|
|
continue;
|
|
}
|
|
|
|
|
|
//
|
|
// Found a directory.
|
|
//
|
|
// 1) Change into that subdirectory on the source drive.
|
|
// 2) Recurse down that tree.
|
|
// 3) Back up one level.
|
|
//
|
|
|
|
//
|
|
// Add to the list of directories
|
|
//
|
|
|
|
if (!AddFileInfoNode (llSrcDirs, lpSrcDir, lpDestDir, NULL, 0, fd.dwFileAttributes)) {
|
|
DebugMsg((DM_WARNING, TEXT("RecurseDirectory: AddFileInfoNode failed")));
|
|
goto RecurseDir_Exit;
|
|
}
|
|
|
|
|
|
//
|
|
// Recurse the subdirectory
|
|
//
|
|
|
|
if (!RecurseDirectory(lpSrcDir, lpDestDir, dwFlags,
|
|
llSrcDirs, llSrcFiles)) {
|
|
DebugMsg((DM_VERBOSE, TEXT("RecurseDirectory: RecurseDirectory returned FALSE")));
|
|
bResult = FALSE;
|
|
goto RecurseDir_Exit;
|
|
}
|
|
|
|
} else {
|
|
|
|
//
|
|
// We found a file. Add it to the list.
|
|
//
|
|
|
|
if (!AddFileInfoNode (llSrcFiles, lpSrcDir, lpDestDir,
|
|
&fd.ftLastWriteTime, fd.nFileSizeLow,
|
|
fd.dwFileAttributes)) {
|
|
DebugMsg((DM_WARNING, TEXT("RecurseDirectory: AddFileInfoNode failed")));
|
|
goto RecurseDir_Exit;
|
|
}
|
|
|
|
}
|
|
|
|
|
|
//
|
|
// Find the next entry
|
|
//
|
|
|
|
} while (FindNextFile(hFile, &fd));
|
|
|
|
|
|
RecurseDir_Exit:
|
|
|
|
//
|
|
// Remove the file / directory name appended above
|
|
//
|
|
|
|
*lpSrcEnd = TEXT('\0');
|
|
*lpDestEnd = TEXT('\0');
|
|
|
|
|
|
//
|
|
// Close the search handle
|
|
//
|
|
|
|
if (hFile != INVALID_HANDLE_VALUE) {
|
|
FindClose(hFile);
|
|
}
|
|
|
|
return bResult;
|
|
}
|
|
|
|
//*************************************************************
|
|
//
|
|
// ReconcileFile()
|
|
//
|
|
// Purpose: Compares the source and destination file.
|
|
// If the source is newer, then it is copied
|
|
// over the destination.
|
|
//
|
|
// Parameters: lpSrcFile - source filename
|
|
// lpDestFile - destination filename
|
|
// dwFlags - flags
|
|
// ftSrcTime - Src file time (can be NULL)
|
|
//
|
|
//
|
|
// Return: TRUE if successful
|
|
// FALSE if an error occurs
|
|
//
|
|
// Comments:
|
|
//
|
|
// History: Date Author Comment
|
|
// 5/25/95 ericflo Created
|
|
//
|
|
//*************************************************************
|
|
|
|
BOOL ReconcileFile (LPTSTR lpSrcFile, LPTSTR lpDestFile,
|
|
DWORD dwFlags, LPFILETIME ftSrcTime)
|
|
{
|
|
HANDLE hFile;
|
|
FILETIME ftWriteSrc, ftWriteDest;
|
|
BOOL bCopyFile = FALSE;
|
|
|
|
|
|
|
|
//
|
|
// If the flags have CPD_FORCECOPY, then skip to the
|
|
// copy file call without checking the timestamps.
|
|
//
|
|
|
|
if (!(dwFlags & CPD_FORCECOPY)) {
|
|
|
|
|
|
//
|
|
// If we were given a source file time, use that
|
|
//
|
|
|
|
if (ftSrcTime) {
|
|
ftWriteSrc.dwLowDateTime = ftSrcTime->dwLowDateTime;
|
|
ftWriteSrc.dwHighDateTime = ftSrcTime->dwHighDateTime;
|
|
|
|
} else {
|
|
|
|
|
|
//
|
|
// Attempt to open the source file
|
|
//
|
|
|
|
hFile = CreateFile(lpSrcFile,
|
|
GENERIC_READ,
|
|
FILE_SHARE_READ,
|
|
NULL,
|
|
OPEN_EXISTING,
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
NULL);
|
|
|
|
if (hFile == INVALID_HANDLE_VALUE) {
|
|
DebugMsg((DM_WARNING, TEXT("ReconcileFile: CreateFile on the source failed with error = %d"),
|
|
GetLastError()));
|
|
return FALSE;
|
|
}
|
|
|
|
if (!GetFileTime(hFile, NULL, NULL, &ftWriteSrc)) {
|
|
DebugMsg((DM_WARNING, TEXT("ReconcileFile: GetFileTime on the source failed with error = %d"),
|
|
GetLastError()));
|
|
CloseHandle(hFile);
|
|
return FALSE;
|
|
}
|
|
|
|
CloseHandle(hFile);
|
|
}
|
|
|
|
|
|
//
|
|
// Attempt to open the destination file
|
|
//
|
|
|
|
hFile = CreateFile(lpDestFile,
|
|
GENERIC_READ,
|
|
FILE_SHARE_READ,
|
|
NULL,
|
|
OPEN_EXISTING,
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
NULL);
|
|
|
|
if (hFile == INVALID_HANDLE_VALUE) {
|
|
DWORD dwError;
|
|
|
|
//
|
|
// CreateFile failed to open the destination
|
|
// file. If the last error is file not found
|
|
// then we automaticly will copy the file.
|
|
//
|
|
|
|
dwError = GetLastError();
|
|
|
|
if (dwError == ERROR_FILE_NOT_FOUND) {
|
|
|
|
bCopyFile = TRUE;
|
|
|
|
} else {
|
|
|
|
//
|
|
// CreateFile failed with some other error
|
|
//
|
|
|
|
DebugMsg((DM_WARNING, TEXT("ReconcileFile: CreateFile on the destination failed with error = %d"),
|
|
dwError));
|
|
return FALSE;
|
|
}
|
|
|
|
} else {
|
|
|
|
//
|
|
// The destination file exists. Query for the
|
|
// last write time.
|
|
//
|
|
|
|
if (!GetFileTime(hFile, NULL, NULL, &ftWriteDest)) {
|
|
DebugMsg((DM_WARNING, TEXT("ReconcileFile: GetFileTime on the destination failed with error = %d"),
|
|
GetLastError()));
|
|
CloseHandle(hFile);
|
|
return FALSE;
|
|
}
|
|
|
|
CloseHandle(hFile);
|
|
}
|
|
|
|
} else {
|
|
|
|
//
|
|
// The CPD_FORCECOPY flag is turned on, set bCopyFile to TRUE.
|
|
//
|
|
|
|
bCopyFile = TRUE;
|
|
}
|
|
|
|
|
|
//
|
|
// If bCopyFile is still false, then we need to compare
|
|
// the last write time stamps.
|
|
//
|
|
|
|
if (!bCopyFile) {
|
|
LONG lResult;
|
|
|
|
//
|
|
// If the source is later than the destination
|
|
// we need to copy the file.
|
|
//
|
|
|
|
lResult = CompareFileTime(&ftWriteSrc, &ftWriteDest);
|
|
|
|
if (lResult == 1) {
|
|
bCopyFile = TRUE;
|
|
}
|
|
|
|
if ( (dwFlags & CPD_COPYIFDIFFERENT) && (lResult == -1) ) {
|
|
bCopyFile = TRUE;
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// Copy the file if appropriate
|
|
//
|
|
|
|
if (bCopyFile) {
|
|
|
|
SetFileAttributes (lpDestFile, FILE_ATTRIBUTE_NORMAL);
|
|
if (!CopyFile(lpSrcFile, lpDestFile, FALSE)) {
|
|
DebugMsg((DM_WARNING, TEXT("ReconcileFile: %s ==> %s [FAILED!!!]"),
|
|
lpSrcFile, lpDestFile));
|
|
|
|
DebugMsg((DM_WARNING, TEXT("ReconcileFile: CopyFile failed with error = %d"),
|
|
GetLastError()));
|
|
|
|
if (!(dwFlags & CPD_IGNORECOPYERRORS)) {
|
|
return FALSE;
|
|
}
|
|
} else {
|
|
DebugMsg((DM_VERBOSE, TEXT("ReconcileFile: %s ==> %s [OK]"),
|
|
lpSrcFile, lpDestFile));
|
|
}
|
|
}
|
|
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
//*************************************************************
|
|
//
|
|
// AddFileInfoNode()
|
|
//
|
|
// Purpose: Adds a node to the linklist of files
|
|
//
|
|
// Parameters: lpFileInfo - Link list to add to
|
|
// lpSrcFile - Source filename
|
|
// lpDestFile - Destination filename
|
|
// ftFileTime - Source time stamp
|
|
// dwFileSize - Size of the file
|
|
// dwFileAttribs - File attributes
|
|
//
|
|
// Return: TRUE if successful
|
|
// FALSE if an error occurs
|
|
//
|
|
// Comments:
|
|
//
|
|
// History: Date Author Comment
|
|
// 9/28/95 ericflo Created
|
|
//
|
|
//*************************************************************
|
|
|
|
BOOL AddFileInfoNode (LPFILEINFO *lpFileInfo, LPTSTR lpSrcFile,
|
|
LPTSTR lpDestFile, LPFILETIME ftFileTime,
|
|
DWORD dwFileSize, DWORD dwFileAttribs)
|
|
{
|
|
LPFILEINFO lpNode;
|
|
|
|
|
|
lpNode = (LPFILEINFO) LocalAlloc(LPTR, sizeof(FILEINFO));
|
|
|
|
if (!lpNode) {
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
lstrcpy (lpNode->szSrc, lpSrcFile);
|
|
lstrcpy (lpNode->szDest, lpDestFile);
|
|
|
|
if (ftFileTime) {
|
|
lpNode->ftSrc.dwLowDateTime = ftFileTime->dwLowDateTime;
|
|
lpNode->ftSrc.dwHighDateTime = ftFileTime->dwHighDateTime;
|
|
}
|
|
|
|
lpNode->dwFileSize = dwFileSize;
|
|
lpNode->dwFileAttribs = (dwFileAttribs & ~FILE_ATTRIBUTE_DIRECTORY);
|
|
|
|
lpNode->pNext = *lpFileInfo;
|
|
|
|
*lpFileInfo = lpNode;
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
//*************************************************************
|
|
//
|
|
// FreeFileInfoList()
|
|
//
|
|
// Purpose: Free's a file info link list
|
|
//
|
|
// Parameters: lpFileInfo - List to be freed
|
|
//
|
|
// Return: TRUE if successful
|
|
// FALSE if an error occurs
|
|
//
|
|
// Comments:
|
|
//
|
|
// History: Date Author Comment
|
|
// 9/28/95 ericflo Created
|
|
//
|
|
//*************************************************************
|
|
|
|
BOOL FreeFileInfoList (LPFILEINFO lpFileInfo)
|
|
{
|
|
LPFILEINFO lpNext;
|
|
|
|
|
|
if (!lpFileInfo) {
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
lpNext = lpFileInfo->pNext;
|
|
|
|
while (lpFileInfo) {
|
|
LocalFree (lpFileInfo);
|
|
lpFileInfo = lpNext;
|
|
|
|
if (lpFileInfo) {
|
|
lpNext = lpFileInfo->pNext;
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
//*************************************************************
|
|
//
|
|
// SyncItems()
|
|
//
|
|
// Purpose: Removes unnecessary items from the destination
|
|
// directory tree
|
|
//
|
|
// Parameters: lpSrcItems - Link list of source items
|
|
// lpDestItems - Link list of dest items
|
|
// bFile - File or directory list
|
|
//
|
|
// Return: TRUE if successful
|
|
// FALSE if an error occurs
|
|
// Comments:
|
|
//
|
|
// History: Date Author Comment
|
|
// 9/28/95 ericflo Created
|
|
//
|
|
//*************************************************************
|
|
|
|
BOOL SyncItems (LPFILEINFO lpSrcItems, LPFILEINFO lpDestItems,
|
|
BOOL bFile)
|
|
{
|
|
LPFILEINFO lpTempSrc, lpTempDest;
|
|
|
|
|
|
//
|
|
// Check for NULL pointers
|
|
//
|
|
|
|
if (!lpSrcItems || !lpDestItems) {
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
//
|
|
// Loop through everyitem in lpDestItems to see if it
|
|
// is in lpSrcItems. If not, delete it.
|
|
//
|
|
|
|
lpTempDest = lpDestItems;
|
|
|
|
while (lpTempDest) {
|
|
|
|
lpTempSrc = lpSrcItems;
|
|
|
|
while (lpTempSrc) {
|
|
|
|
if (lstrcmpi(lpTempDest->szSrc, lpTempSrc->szDest) == 0) {
|
|
break;
|
|
}
|
|
|
|
lpTempSrc = lpTempSrc->pNext;
|
|
}
|
|
|
|
//
|
|
// If lpTempSrc is NULL, then delete the extra file/directory
|
|
//
|
|
|
|
if (!lpTempSrc) {
|
|
|
|
DebugMsg((DM_VERBOSE, TEXT("SyncItems: removing <%s>"),
|
|
lpTempDest->szSrc));
|
|
|
|
|
|
if (bFile) {
|
|
SetFileAttributes(lpTempDest->szSrc, FILE_ATTRIBUTE_NORMAL);
|
|
if (!DeleteFile (lpTempDest->szSrc)) {
|
|
DebugMsg((DM_WARNING, TEXT("SyncItems: Failed to delete <%s>. Error = %d."),
|
|
lpTempDest->szSrc, GetLastError()));
|
|
}
|
|
|
|
} else {
|
|
SetFileAttributes(lpTempDest->szSrc, FILE_ATTRIBUTE_NORMAL);
|
|
if (!RemoveDirectory (lpTempDest->szSrc)) {
|
|
DebugMsg((DM_WARNING, TEXT("SyncItems: Failed to remove <%s>. Error = %d"),
|
|
lpTempDest->szSrc, GetLastError()));
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
lpTempDest = lpTempDest->pNext;
|
|
}
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
//*************************************************************
|
|
//
|
|
// CopyFileFunc()
|
|
//
|
|
// Purpose: Copies files
|
|
//
|
|
// Parameters: lpThreadInfo - Thread information
|
|
//
|
|
// Return: void
|
|
//
|
|
// Comments:
|
|
//
|
|
// History: Date Author Comment
|
|
// 2/23/96 ericflo Created
|
|
//
|
|
//*************************************************************
|
|
|
|
void CopyFileFunc (LPTHREADINFO lpThreadInfo)
|
|
{
|
|
HANDLE hInstDll;
|
|
LPFILEINFO lpSrcFile;
|
|
BOOL bRetVal = TRUE;
|
|
|
|
|
|
hInstDll = LoadLibrary (TEXT("userenv.dll"));
|
|
|
|
|
|
while (TRUE) {
|
|
|
|
//
|
|
// Query for the next file to copy
|
|
//
|
|
|
|
EnterCriticalSection(lpThreadInfo->lpCrit);
|
|
|
|
lpSrcFile = lpThreadInfo->lpSrcFiles;
|
|
|
|
if (lpSrcFile) {
|
|
lpThreadInfo->lpSrcFiles = lpThreadInfo->lpSrcFiles->pNext;
|
|
}
|
|
|
|
LeaveCriticalSection(lpThreadInfo->lpCrit);
|
|
|
|
|
|
//
|
|
// If NULL, then we're finished.
|
|
//
|
|
|
|
if (!lpSrcFile) {
|
|
break;
|
|
}
|
|
|
|
|
|
//
|
|
// Copy the file
|
|
//
|
|
|
|
if (!ReconcileFile (lpSrcFile->szSrc, lpSrcFile->szDest,
|
|
lpThreadInfo->dwFlags, &lpSrcFile->ftSrc)) {
|
|
bRetVal = FALSE;
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// Clean up
|
|
//
|
|
|
|
if (hInstDll) {
|
|
FreeLibraryAndExitThread(hInstDll, bRetVal);
|
|
} else {
|
|
ExitThread (bRetVal);
|
|
}
|
|
}
|