mirror of https://github.com/lianthony/NT4.0
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.
409 lines
11 KiB
409 lines
11 KiB
/*++
|
|
|
|
Copyright (c) 1992-1993 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
CopyTree.c
|
|
|
|
Abstract:
|
|
|
|
ReplCopyTree() does a recursive file/directory copy.
|
|
|
|
Author:
|
|
|
|
John Rogers (JohnRo) 25-Mar-1992
|
|
|
|
Environment:
|
|
|
|
User mode only. Uses Win32 APIs.
|
|
Requires ANSI C extensions: slash-slash comments, long external names.
|
|
Tab size is set to 4.
|
|
|
|
Revision History:
|
|
|
|
25-Mar-1992 JohnRo
|
|
Created.
|
|
26-Mar-1992 JohnRo
|
|
Removed assumption about using the current directory.
|
|
New ReplFind routines interface.
|
|
27-Mar-1992 JohnRo
|
|
Create dest directories. Copy single file if asked to.
|
|
11-Aug-1992 JohnRo
|
|
RAID 3288: repl svc should preserve ACLs on copy.
|
|
25-Feb-1993 JohnRo
|
|
RAID 12237: replicator tree depth exceeded.
|
|
Improve thread documentation.
|
|
Use NetpKdPrint() where possible.
|
|
Use PREFIX_ equates.
|
|
22-Apr-1993 JohnRo
|
|
RAID 7157: replicator does not stop while in recursive tree copy.
|
|
Make sure attributes, EAs, etc. are updated for each directory.
|
|
Added error logging.
|
|
Random cleanup.
|
|
Prepare for >32 bits someday.
|
|
|
|
--*/
|
|
|
|
|
|
#include <windows.h> // IN, LPTSTR, etc.
|
|
#include <lmcons.h> // NET_API_STATUS, PATHLEN, etc.
|
|
|
|
#include <client.h> // ReplCopyTree().
|
|
#include <filefind.h> // REPL_WIN32_FIND_DATA.
|
|
#include <lmerrlog.h> // NELOG_ equates.
|
|
#include <netdebug.h> // NetpKdPrint(), FORMAT_ equates, etc.
|
|
#include <prefix.h> // PREFIX_ equates.
|
|
#include <repldefs.h> // IF_DEBUG(), STAR_DOT_STAR, etc.
|
|
#include <replgbl.h> // ReplGlobal variables.
|
|
#include <tstr.h> // STRLEN(), TCHAR_EOS, etc.
|
|
|
|
|
|
DBGSTATIC NET_API_STATUS
|
|
ReplCopyRestOfTree(
|
|
IN LPTSTR SourcePath,
|
|
IN LPTSTR DestPath
|
|
);
|
|
|
|
|
|
NET_API_STATUS
|
|
ReplCopyTree(
|
|
IN LPTSTR SourcePath,
|
|
IN LPTSTR DestPath
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Front-end for ReplCopyRestOfTree(). See ReplCopyRestOfTree().
|
|
|
|
Arguments:
|
|
|
|
See ReplCopyRestOfTree().
|
|
|
|
Return Value:
|
|
|
|
NET_API_STATUS - NO_ERROR (copy complete).
|
|
- ERROR_OPERATION_ABORTED (service is stopping).
|
|
- other errors.
|
|
|
|
Threads:
|
|
|
|
Used by client and syncer threads.
|
|
|
|
--*/
|
|
|
|
{
|
|
NET_API_STATUS ApiStatus;
|
|
DWORD Attributes;
|
|
TCHAR FullSourceBuffer[PATHLEN+1];
|
|
TCHAR FullDestBuffer[PATHLEN+1];
|
|
|
|
NetpAssert( SourcePath != NULL );
|
|
NetpAssert( (*SourcePath) != TCHAR_EOS );
|
|
NetpAssert( STRLEN(SourcePath) <= PATHLEN );
|
|
NetpAssert( DestPath != NULL );
|
|
NetpAssert( (*DestPath) != TCHAR_EOS );
|
|
NetpAssert( STRLEN(DestPath) <= PATHLEN );
|
|
|
|
Attributes = GetFileAttributes( SourcePath );
|
|
|
|
if ( Attributes == (DWORD) -1 ) {
|
|
|
|
//
|
|
// Source doesn't exist, bad syntax, or something along those lines.
|
|
//
|
|
ApiStatus = (NET_API_STATUS) GetLastError();
|
|
NetpAssert( ApiStatus != NO_ERROR );
|
|
|
|
// Log this!
|
|
ReplErrorLog(
|
|
NULL, // local (no server name)
|
|
NELOG_ReplUpdateError, // log code
|
|
ApiStatus,
|
|
DestPath,
|
|
SourcePath );
|
|
|
|
// BUGBUG: Log on remote server too if we got UNC name.
|
|
|
|
} else {
|
|
if ((Attributes & FILE_ATTRIBUTE_DIRECTORY) == 0) {
|
|
|
|
//
|
|
// Simple case: just a single file.
|
|
// ReplCopyFile() will copy data, attributes, everything!
|
|
//
|
|
ApiStatus = ReplCopyFile(
|
|
SourcePath,
|
|
DestPath,
|
|
FALSE ); // Don't fail if exists.
|
|
|
|
// (Error already logged by ReplCopyFile.)
|
|
|
|
} else {
|
|
|
|
//
|
|
// It's a directory tree.
|
|
// Set up large buffers and call the worker to handle this.
|
|
//
|
|
(void) STRCPY( FullSourceBuffer, SourcePath );
|
|
(void) STRCPY( FullDestBuffer, DestPath );
|
|
|
|
ApiStatus = ReplCopyRestOfTree(
|
|
FullSourceBuffer,
|
|
FullDestBuffer );
|
|
|
|
// (Error already logged by ReplCopyRestOfTree.)
|
|
|
|
}
|
|
}
|
|
|
|
IF_DEBUG( SYNC ) {
|
|
NetpKdPrint(( PREFIX_REPL_CLIENT
|
|
"ReplCopyTree: tree copy of " FORMAT_LPTSTR " to "
|
|
FORMAT_LPTSTR " gave status " FORMAT_API_STATUS ".\n",
|
|
SourcePath, DestPath, ApiStatus ));
|
|
}
|
|
|
|
// No need to log error here, as it has already been done.
|
|
|
|
return (ApiStatus);
|
|
|
|
} // ReplCopyTree.
|
|
|
|
|
|
DBGSTATIC NET_API_STATUS
|
|
ReplCopyRestOfTree(
|
|
IN LPTSTR SourcePath,
|
|
IN LPTSTR DestPath
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Scans recursivly thru an entire sub-tree copying files and directories.
|
|
|
|
Uses a depth-first algorithm.
|
|
|
|
Arguments:
|
|
|
|
BUGBUG
|
|
Note - path of dir to be scanned. Must be alloc'ed as TCHAR[PATHLEN+1], as
|
|
this routine uses the space at the end for temporary stuff.
|
|
|
|
Return Value:
|
|
|
|
NET_API_STATUS
|
|
|
|
Threads:
|
|
|
|
Used by client and syncer threads.
|
|
|
|
--*/
|
|
|
|
{
|
|
NET_API_STATUS ApiStatus;
|
|
DWORD DestAttributes;
|
|
DWORD DestPathIndex;
|
|
REPL_WIN32_FIND_DATA SearchBuf;
|
|
LPREPL_FIND_HANDLE SearchHandle = INVALID_REPL_HANDLE;
|
|
DWORD SourcePathIndex;
|
|
|
|
#define UNEXPECTED( apiName ) \
|
|
{ \
|
|
NetpKdPrint(( PREFIX_REPL_CLIENT \
|
|
"ReplCopyRestOfTree: Unexpected status from " \
|
|
apiName " (" FORMAT_DWORD ").\n", ApiStatus )); \
|
|
}
|
|
|
|
SourcePathIndex = STRLEN(SourcePath);
|
|
NetpAssert( SourcePathIndex < PATHLEN );
|
|
DestPathIndex = STRLEN(DestPath);
|
|
NetpAssert( DestPathIndex < PATHLEN );
|
|
|
|
//
|
|
// Prevent trashing a file with this directory.
|
|
//
|
|
|
|
DestAttributes = GetFileAttributes( DestPath );
|
|
|
|
if ((DestAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0) {
|
|
|
|
ApiStatus = ERROR_ALREADY_EXISTS;
|
|
NetpKdPrint(( PREFIX_REPL_CLIENT
|
|
"ReplCopyRestOfTree: *ERROR* "
|
|
"Copying dir to file - invalid.\n" ));
|
|
goto Cleanup;
|
|
}
|
|
|
|
IF_DEBUG( MAJOR ) {
|
|
if (DestAttributes == (DWORD)-1) {
|
|
NetpKdPrint(( PREFIX_REPL_CLIENT
|
|
"ReplCopyRestOfTree: Creating directory "
|
|
FORMAT_LPTSTR "...\n", DestPath ));
|
|
} else {
|
|
NetpKdPrint(( PREFIX_REPL_CLIENT
|
|
"ReplCopyRestOfTree: Updating directory "
|
|
FORMAT_LPTSTR "...\n", DestPath ));
|
|
}
|
|
}
|
|
|
|
//
|
|
// Make sure dest directory exists, with right attributes, EAs, etc.
|
|
//
|
|
|
|
ApiStatus = ReplCopyDirectoryItself(
|
|
SourcePath, // place to copy security, timestamp, etc from.
|
|
DestPath, // Name of the new directory.
|
|
FALSE); // Don't fail if it already exists.
|
|
|
|
if (ApiStatus != NO_ERROR) {
|
|
UNEXPECTED( "ReplCopyDirectoryItself" );
|
|
goto Cleanup;
|
|
}
|
|
|
|
|
|
//
|
|
// Setup to scan this directory for files and directories.
|
|
//
|
|
(void) STRCAT( SourcePath, SLASH );
|
|
(void) STRCAT( SourcePath, STAR_DOT_STAR );
|
|
IF_DEBUG( SYNC ) {
|
|
NetpKdPrint(( PREFIX_REPL_CLIENT
|
|
"ReplCopyRestOfTree: Processing source " FORMAT_LPTSTR
|
|
", dest " FORMAT_LPTSTR ".\n", SourcePath, DestPath ));
|
|
}
|
|
|
|
SearchHandle = ReplFindFirstFile( SourcePath, &SearchBuf);
|
|
SourcePath[SourcePathIndex] = TCHAR_EOS;
|
|
|
|
if (SearchHandle == INVALID_REPL_HANDLE) {
|
|
|
|
ApiStatus = (NET_API_STATUS) GetLastError();
|
|
UNEXPECTED( "ReplFindFirstFile" );
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// Loop for each files and directory in this directory.
|
|
//
|
|
do {
|
|
//
|
|
// Quit if service is stopping.
|
|
//
|
|
|
|
if (ReplGlobalIsServiceStopping) {
|
|
ApiStatus = ERROR_OPERATION_ABORTED;
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// Ignore REPL.INI, USERLOCK.*, ., .., and so on.
|
|
//
|
|
|
|
if ( ReplIgnoreDirOrFileName( SearchBuf.fdFound.cFileName ) ) {
|
|
continue; // Skip to next one.
|
|
}
|
|
|
|
// Append "\".
|
|
SourcePath[SourcePathIndex] = TCHAR_BACKSLASH;
|
|
DestPath[DestPathIndex] = TCHAR_BACKSLASH;
|
|
|
|
// Append sub-dir or file name name.
|
|
(void) STRCPY(
|
|
SourcePath + SourcePathIndex + 1,
|
|
SearchBuf.fdFound.cFileName);
|
|
NetpAssert( STRLEN( SourcePath ) <= PATHLEN );
|
|
|
|
(void) STRCPY(
|
|
DestPath + DestPathIndex + 1,
|
|
SearchBuf.fdFound.cFileName);
|
|
NetpAssert( STRLEN( DestPath ) <= PATHLEN );
|
|
|
|
if (SearchBuf.fdFound.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
|
|
|
|
//
|
|
// Recursively copy this subdirectory.
|
|
//
|
|
|
|
ApiStatus = ReplCopyRestOfTree( SourcePath, DestPath );
|
|
if (ApiStatus != NO_ERROR) {
|
|
UNEXPECTED( "ReplCopyRestOfTree" );
|
|
goto Cleanup;
|
|
}
|
|
|
|
} else {
|
|
|
|
IF_DEBUG( SYNC ) {
|
|
NetpKdPrint(( PREFIX_REPL_CLIENT
|
|
"ReplCopyRestOfTree: Copying file "
|
|
FORMAT_LPTSTR " to " FORMAT_LPTSTR ".\n",
|
|
SourcePath, DestPath ));
|
|
}
|
|
|
|
//
|
|
// Copy this individual file; don't fail if it already exists.
|
|
// ReplCopyFile() will copy data, attributes, everything.
|
|
//
|
|
|
|
ApiStatus = ReplCopyFile(SourcePath, DestPath, FALSE);
|
|
if (ApiStatus != NO_ERROR) {
|
|
UNEXPECTED( "ReplCopyFile" );
|
|
goto Cleanup;
|
|
}
|
|
|
|
}
|
|
|
|
// Reset path names for next pass through the loop.
|
|
SourcePath[SourcePathIndex] = TCHAR_EOS;
|
|
DestPath[DestPathIndex] = TCHAR_EOS;
|
|
|
|
|
|
} while (ReplFindNextFile(SearchHandle, &SearchBuf));
|
|
|
|
ApiStatus = NO_ERROR;
|
|
|
|
Cleanup:
|
|
IF_DEBUG( SYNC ) {
|
|
NetpKdPrint(( PREFIX_REPL_CLIENT
|
|
"ReplCopyRestOfTree() is done, stat="
|
|
FORMAT_API_STATUS ".\n", ApiStatus ));
|
|
}
|
|
|
|
if (SearchHandle != INVALID_REPL_HANDLE) {
|
|
if( !ReplFindClose(SearchHandle) ) {
|
|
|
|
ApiStatus = (NET_API_STATUS) GetLastError();
|
|
UNEXPECTED( "ReplFindClose" );
|
|
NetpAssert( ApiStatus != NO_ERROR );
|
|
|
|
}
|
|
}
|
|
|
|
//
|
|
// Log error.
|
|
//
|
|
if (ApiStatus != NO_ERROR) {
|
|
|
|
// Log this locally.
|
|
ReplErrorLog(
|
|
NULL, // local (no server name)
|
|
NELOG_ReplUpdateError, // log code
|
|
ApiStatus,
|
|
DestPath,
|
|
SourcePath );
|
|
|
|
// BUGBUG: Log error on remote server too, if we got UNC name.
|
|
}
|
|
|
|
//
|
|
// Reset path names, now that we've logged them.
|
|
//
|
|
SourcePath[SourcePathIndex] = TCHAR_EOS;
|
|
DestPath[DestPathIndex] = TCHAR_EOS;
|
|
|
|
return (ApiStatus);
|
|
|
|
} // ReplCopyRestOfTree
|