diff options
Diffstat (limited to 'private/net/svcdlls/repl/common')
47 files changed, 9923 insertions, 0 deletions
diff --git a/private/net/svcdlls/repl/common/abspath.c b/private/net/svcdlls/repl/common/abspath.c new file mode 100644 index 000000000..6f73022d0 --- /dev/null +++ b/private/net/svcdlls/repl/common/abspath.c @@ -0,0 +1,86 @@ +/*++ + +Copyright (c) 1992 Microsoft Corporation + +Module Name: + + AbsPath.c + +Abstract: + + This file contains ReplCheckAbsPathSyntax(). + +Author: + + John Rogers (JohnRo) 27-Jan-1992 + +Environment: + + User Mode - Win32 + Portable to any flat, 32-bit environment. (Uses Win32 typedefs.) + Requires ANSI C extensions: slash-slash comments, long external names. + +Revision History: + + 27-Jan-1992 JohnRo + Created as part of replconf stuff.. + 21-Feb-1992 JohnRo + Extracted this code for slightly more general use. + 19-Mar-1992 JohnRo + Richard Firth fixed a canon bug, which I was unintentionally + depending on here. + 20-Mar-1992 JohnRo + Include header file with my prototype, just to be on the safe side. + 17-Aug-1992 JohnRo + RAID 3174: NetReplSetInfo (and repl registry) allow bad paths. + +--*/ + + +// These must be included first: + +#include <windef.h> // MAX_PATH, etc. +#include <lmcons.h> // LAN Manager common definitions + +// These can be in any order: + +#include <icanon.h> // I_NetPathCanonicalize(), ITYPE_ equates. +#include <repldefs.h> // My prototype. +#include <winerror.h> // ERROR_, NO_ERROR equates. + + + + +NET_API_STATUS +ReplCheckAbsPathSyntax ( + IN LPTSTR AbsPath + ) +{ + DWORD ActualType = 0; // 0 means we don't know yet. + NET_API_STATUS ApiStatus; + TCHAR CanonBuf[MAX_PATH]; + + ApiStatus = I_NetPathCanonicalize( + NULL, + AbsPath, + CanonBuf, + sizeof(CanonBuf), + NULL, + &ActualType, + 0); + + // + // Check the type of the input. + // + + if (ApiStatus != NO_ERROR) { + return (ApiStatus); + } else if (ActualType == ITYPE_PATH_ABSD) { // abs path with drive. + return (NO_ERROR); + } else { + return (ERROR_INVALID_DATA); + } + + /*NOTREACHED*/ + +} // ReplCheckAbsPathSyntax diff --git a/private/net/svcdlls/repl/common/allowrol.c b/private/net/svcdlls/repl/common/allowrol.c new file mode 100644 index 000000000..fa6bc12ae --- /dev/null +++ b/private/net/svcdlls/repl/common/allowrol.c @@ -0,0 +1,130 @@ +/*++ + +Copyright (c) 1992-1993 Microsoft Corporation + +Module Name: + + AllowRol.c + +Abstract: + + Just contains ReplConfigIsRoleAllowed(). + +Author: + + John Rogers (JohnRo) 07-Aug-1992 + +Revision History: + + 07-Aug-1992 JohnRo + Created for RAID 2252: repl should prevent export on Windows/NT. + 01-Dec-1992 JohnRo + RAID 3844: remote NetReplSetInfo uses local machine type. + 06-Apr-1993 JohnRo + RAID 1938: Replicator un-ACLs files when not given enough permission. + 30-Apr-1993 JohnRo + Use NetpKdPrint() where possible. + +--*/ + + +// These must be included first: + +#include <nt.h> // NT_PRODUCT_TYPE, etc. +#include <ntrtl.h> +#include <nturtl.h> +#include <windows.h> // BOOL, etc. +#include <lmcons.h> // NET_API_STATUS. + +// These may be included in any order: + +#include <netdebug.h> // NetpAssert(), NetpKdPrint(), FORMAT_ equates. +#include <netlibnt.h> // NetpGetProductType(). +#include <prefix.h> // PREFIX_ equates. +#include <replconf.h> // My prototype. +#include <repldefs.h> // ReplRoleIncludesExport(), ReplRoleIsValid(), etc. +#include <winerror.h> // ERROR_ and NO_ERROR equates. + + +// +// Return this value if we aren't sure whether or not to allow the role. +// +#define DEFAULT_ROLE_ALLOWED TRUE + + +BOOL +ReplConfigIsRoleAllowed( + IN LPTSTR UncServerName OPTIONAL, + IN DWORD Role + ) + +/*++ + +Routine Description: + + Indicates whether the given role is allowed based on the current product + type. Callable whether or not service is started. + +Arguments: + + Role - the desired replicator role. + +Return Value: + + TRUE iff Role is valid and Role is consistent with the current product type. + +--*/ + +{ + NET_API_STATUS ApiStatus; + NT_PRODUCT_TYPE ProductType; + + if ( !ReplIsRoleValid( Role ) ) { + return (FALSE); + } + + // + // Ask NT what type of system we're running on. + // + ApiStatus = NetpGetProductType( + UncServerName, + &ProductType ); + + if (ApiStatus != NO_ERROR) { + + NetpKdPrint(( PREFIX_REPL "ReplConfigIsRoleAllowed: unexpected failure " + "of NetpGetProductType(); assuming default.\n" )); + + return (DEFAULT_ROLE_ALLOWED); + } + + // + // Decide what to do based on the product type we got back. + // + if ((ProductType == NtProductLanManNt) + || (ProductType == NtProductServer) ) { + + return (TRUE); // All roles are valid with NT AS. + + } else if (ProductType == NtProductWinNt) { + + if (ReplRoleIncludesExport( Role ) ) { + return (FALSE); + } else { + NetpAssert( Role == REPL_ROLE_IMPORT ); + return (TRUE); // Import is allowed on all product types. + } + + /*NOTREACHED*/ + + } else { + NetpKdPrint(( PREFIX_REPL "ReplConfigIsRoleAllowed: unexpected product " + "type " FORMAT_DWORD "\n", ProductType )); + NetpAssert( FALSE ); // Unexpected product type. + + return (DEFAULT_ROLE_ALLOWED); + } + + /*NOTREACHED*/ + +} diff --git a/private/net/svcdlls/repl/common/chnglock.c b/private/net/svcdlls/repl/common/chnglock.c new file mode 100644 index 000000000..b559578b1 --- /dev/null +++ b/private/net/svcdlls/repl/common/chnglock.c @@ -0,0 +1,131 @@ +/*++ + +Copyright (c) 1992 Microsoft Corporation + +Module Name: + + ChngLock.c + +Abstract: + + This file contains: + + ReplIncrLockFields + ReplDecrLockFields + +Author: + + John Rogers (JohnRo) 07-Jan-1992 + +Environment: + + Runs under Windows NT. + Requires ANSI C extensions: slash-slash comments, long external names. + +Revision History: + + 07-Jan-1992 JohnRo + Created. + 18-Feb-1992 JohnRo + Extracted these bits of code from server for use by DLL stubs too. + 22-Feb-1992 JohnRo + Made changes suggested by PC-LINT. + 26-Feb-1992 JohnRo + Check lock fields for validity. + +--*/ + + +// These must be included first: + +#include <windef.h> // IN, VOID, LPTSTR, etc. +#include <lmcons.h> // NET_API_STATUS. + +// These can be in any order: + +#include <lmrepl.h> // REPL_UNLOCK_ equates. +#include <netdebug.h> // NetpAssert(), etc. +#include <repldefs.h> // My prototypes, etc. +#include <replp.h> // NetpReplTimeNow(). +#include <winerror.h> // ERROR_ and NO_ERROR equates. + + +NET_API_STATUS +ReplIncrLockFields ( + IN OUT LPDWORD LockCountPtr, + IN OUT LPDWORD LockTimePtr + ) + +{ + NetpAssert( LockCountPtr != NULL ); + NetpAssert( LockTimePtr != NULL ); + + NetpAssert( ReplAreLockFieldsValid( *LockCountPtr, *LockTimePtr ) ); + + if ( *LockCountPtr == 0) { + + *LockCountPtr = 1; + *LockTimePtr = NetpReplTimeNow(); + + } else { + + // Not first time. + ++ (*LockCountPtr); + + NetpAssert( (*LockCountPtr) > 0 ); + NetpAssert( (*LockTimePtr) > 0 ); + + } + + NetpAssert( ReplAreLockFieldsValid( *LockCountPtr, *LockTimePtr ) ); + + return (NO_ERROR); + +} // ReplIncrLockFields + + +NET_API_STATUS +ReplDecrLockFields ( + IN OUT LPDWORD LockCountPtr, + IN OUT LPDWORD LockTimePtr, + IN DWORD UnlockForce + ) + +{ + NET_API_STATUS ApiStatus; + + NetpAssert( LockCountPtr != NULL ); + NetpAssert( LockTimePtr != NULL ); + + NetpAssert( ReplAreLockFieldsValid( *LockCountPtr, *LockTimePtr ) ); + + if ( !ReplIsForceLevelValid( UnlockForce ) ) { + return (ERROR_INVALID_PARAMETER); + } + + if ((*LockCountPtr) == 0) { // not locked now. + + ApiStatus = ERROR_INVALID_PARAMETER; + + } else { + + if (UnlockForce == REPL_UNLOCK_NOFORCE) { + --(*LockCountPtr); + } else { + (*LockCountPtr) = 0; + } + + if ((*LockCountPtr) == 0) { // not locked any more. + + *LockTimePtr = 0; + + } + + ApiStatus = NO_ERROR; + } + + NetpAssert( ReplAreLockFieldsValid( *LockCountPtr, *LockTimePtr ) ); + + return (ApiStatus); + +} // ReplDecrLockFields diff --git a/private/net/svcdlls/repl/common/chngnot.c b/private/net/svcdlls/repl/common/chngnot.c new file mode 100644 index 000000000..31ddc8339 --- /dev/null +++ b/private/net/svcdlls/repl/common/chngnot.c @@ -0,0 +1,424 @@ +/*++ + +Copyright (c) 1991-1993 Microsoft Corporation + +Module Name: + + ChngNot.c + +Abstract: + + This is a package of change notify routines: + + ReplSetupChangeNotify + ReplEnableChangeNotify + ReplGetChangeNotifyStatus + ReplExtractChangeNotifyFirstDir + ReplCloseChangeNotify + +Author: + + John Rogers (JohnRo) 28-Nov-1992 + +Environment: + + NT only. + Requires ANSI C extensions: slash-slash comments, long external names. + +Revision History: + + 28-Nov-1992 JohnRo + Repl should use filesystem change notify. (Created these routines + from MadanA's test code in ReplTest/Watch.c) + 08-Dec-1992 JohnRo + Made changes suggested by PC-LINT 5.0 + 14-Jan-1993 JohnRo + RAID 7053: locked trees added to pulse msg. (Actually fix all + kinds of remote lock handling.) + 26-Feb-1993 JohnRo + RAID 13126: Fix repl memory leak. + Made changes suggested by PC-LINT 5.0 + Corrected copyright dates. + 30-Apr-1993 JohnRo + Use NetpKdPrint() where possible. + +--*/ + + + +// These must be included first: + +#include <nt.h> // NT definitions +#include <ntrtl.h> // NT runtime library definitions (needed by nturtl.h) +#include <nturtl.h> // RtlDosPathNameToNtPathName_U(). +#include <windef.h> // LPVOID, etc. +#include <lmcons.h> // NET_API_STATUS. + +// These may be included in any order: + +#include <chngnot.h> // My prototypes, REPL_CHANGE_NOTIFY_HANDLE, etc. +#include <netdebug.h> // DBGSTATIC, NetpKdPrint(), FORMAT_ equates, etc. +#include <netlib.h> // NetpMemoryAllocate(), etc. +#include <netlibnt.h> // NetpNtStatusToApiStatus(). +#include <prefix.h> // PREFIX_ equates. +#include <repldefs.h> // IF_DEBUG(). +#include <tstr.h> // TCHAR_EOS. +#include <winerror.h> // NO_ERROR, ERROR_ equates. + + +// Arbitrary amount for buffer which will be filled-in. +// BUGBUG: We don't even use this buffer yet! +#define BUFFER_SIZE (1024 * 10) + + +// +// Define which kinds of changes we want to actually get notified about. +// We don't use access time in checksum, so skip FILE_NOTIFY_CHANGE_LAST_ACCESS. +// Ditto for the creation time (FILE_NOTIFY_CHANGE_CREATION). +// BUGBUG: we copy security info but don't checksum it yet! +// + +#define MY_CHANGE_NOTIFY_FILTER \ + ( \ + FILE_NOTIFY_CHANGE_FILE_NAME | \ + FILE_NOTIFY_CHANGE_DIR_NAME | \ + FILE_NOTIFY_CHANGE_ATTRIBUTES | \ + FILE_NOTIFY_CHANGE_SIZE | \ + FILE_NOTIFY_CHANGE_LAST_WRITE | \ + FILE_NOTIFY_CHANGE_EA | \ + FILE_NOTIFY_CHANGE_SECURITY \ + ) + + +DBGSTATIC BOOL +ReplIsChangeNotifyHandleValid( + IN LPREPL_CHANGE_NOTIFY_HANDLE ReplHandle + ) +{ + if (ReplHandle == NULL) { + return (FALSE); + } else if ( (ReplHandle->WaitableHandle) == (LPVOID) NULL ) { + return (FALSE); + } else if ( (ReplHandle->Buffer) == NULL ) { + return (FALSE); + } else if ( (ReplHandle->BufferSize) == 0 ) { + return (FALSE); + } + // BUGBUG: Check ReplHandle->NextElementInBuffer too. + // BUGBUG: Check ReplHandle->BufferBytesValid too. + return (TRUE); +} + + +NET_API_STATUS +ReplSetupChangeNotify( + IN LPTSTR AbsPath, + OUT LPREPL_CHANGE_NOTIFY_HANDLE *ReplHandle + ) +{ + NET_API_STATUS ApiStatus; + UNICODE_STRING DirName; + NTSTATUS NtStatus; + OBJECT_ATTRIBUTES ObjectAttributes; + BOOL PathAllocated = FALSE; + LPREPL_CHANGE_NOTIFY_HANDLE ReplStruct = NULL; + + + // + // Check for caller's errors. + // + + NetpAssert( AbsPath != NULL ); + NetpAssert( (*AbsPath) != TCHAR_EOS ); + NetpAssert( ReplHandle != NULL ); + + // + // Allocate repl "handle" (structure). + // + + ReplStruct = NetpMemoryAllocate( sizeof( REPL_CHANGE_NOTIFY_HANDLE ) ); + if (ReplStruct == NULL) { + ApiStatus = ERROR_NOT_ENOUGH_MEMORY; + goto Cleanup; + } + + // + // Fill-in fields in repl struct, so we don't confuse cleanup code. + // + + ReplStruct->Buffer = NULL; + ReplStruct->BufferSize = 0; + ReplStruct->WaitableHandle = NULL; + + // + // Allocate change buffer. + // + + ReplStruct->Buffer = NetpMemoryAllocate( BUFFER_SIZE ); + if (ReplStruct->Buffer == NULL) { + ApiStatus = ERROR_NOT_ENOUGH_MEMORY; + goto Cleanup; + } + ReplStruct->BufferSize = BUFFER_SIZE; + + // + // Arrange NT-style stuff so we can open the directory. + // + + if (! RtlDosPathNameToNtPathName_U( + AbsPath, + &DirName, + NULL, + NULL + )) { + ApiStatus = ERROR_INVALID_PARAMETER; + NetpKdPrint(( PREFIX_REPL "ReplSetupChangeNotify: " + "Could not convert DOS path to NT path; returning " + FORMAT_API_STATUS ".\n", ApiStatus )); + goto Cleanup; + } + PathAllocated = TRUE; + + InitializeObjectAttributes( + &ObjectAttributes, + &DirName, + OBJ_CASE_INSENSITIVE, + NULL, + NULL + ); + + // + // Open the diretory. + // + + NtStatus = NtOpenFile( + &(ReplStruct->WaitableHandle), + SYNCHRONIZE | FILE_LIST_DIRECTORY, + &ObjectAttributes, + &(ReplStruct->IoStatusBlock), + FILE_SHARE_READ | FILE_SHARE_WRITE, + FILE_DIRECTORY_FILE + ); + + if (NT_SUCCESS(NtStatus)) { + NtStatus = ReplStruct->IoStatusBlock.Status; + } + + if (! NT_SUCCESS(NtStatus)) { + ApiStatus = NetpNtStatusToApiStatus( NtStatus ); + NetpKdPrint(( PREFIX_REPL "ReplSetupChangeNotify: " + "NtOpenFile " FORMAT_LPTSTR " failed: " FORMAT_NTSTATUS + "; returning " FORMAT_API_STATUS ".\n", + AbsPath, NtStatus, ApiStatus )); + ReplStruct->WaitableHandle = NULL; // BUGBUG: not necessary? + goto Cleanup; + } + + IF_DEBUG( CHNGNOT ) { + NetpKdPrint(( PREFIX_REPL "ReplSetupChangeNotify: " + "Succeeded in opening dir.\n" )); + } + + ApiStatus = NO_ERROR; + +Cleanup: + if (ApiStatus != NO_ERROR) { + if (ReplStruct->Buffer != NULL) { + NetpMemoryFree( ReplStruct->Buffer ); + } + if (ReplStruct != NULL) { + NetpMemoryFree( ReplStruct ); + } + *ReplHandle = NULL; + } else { + NetpAssert( ReplStruct != NULL ); + *ReplHandle = ReplStruct; + + NetpAssert( ReplIsChangeNotifyHandleValid( *ReplHandle ) ); + } + + IF_DEBUG( CHNGNOT ) { + NetpKdPrint(( PREFIX_REPL "ReplSetupChangeNotify: " + "returning " FORMAT_API_STATUS ".\n", ApiStatus )); + } + + if (PathAllocated) { + (VOID) RtlFreeHeap( RtlProcessHeap(), 0, DirName.Buffer ); + } + + + return (ApiStatus); + +} // ReplSetupChangeNotify + + +NET_API_STATUS +ReplEnableChangeNotify( + IN OUT LPREPL_CHANGE_NOTIFY_HANDLE ReplHandle + ) +{ + NET_API_STATUS ApiStatus; + NTSTATUS NtStatus; + + // + // Now tell the system that we're going to watch for changes. + // + + NtStatus = NtNotifyChangeDirectoryFile( + ReplHandle->WaitableHandle, + NULL, // No event, wait on handle + NULL, // No APC routine + NULL, // No APC context + &(ReplHandle->IoStatusBlock), + ReplHandle->Buffer, + BUFFER_SIZE, + MY_CHANGE_NOTIFY_FILTER, + (BOOLEAN) TRUE // Watch for change in the entire tree + ); + + + if ( !NT_SUCCESS( NtStatus ) ) { + ApiStatus = NetpNtStatusToApiStatus( NtStatus ); + + NetpKdPrint(( PREFIX_REPL "ReplEnableChangeNotify: " + "NtNotifyChangeDirectoryFile failed " FORMAT_NTSTATUS + "; returning " FORMAT_API_STATUS "\n", + NtStatus, ApiStatus )); + NetpAssert( ApiStatus != NO_ERROR ) + goto Cleanup; + } + + ApiStatus = NO_ERROR; + +Cleanup: + IF_DEBUG( CHNGNOT ) { + NetpKdPrint(( PREFIX_REPL "ReplEnableChangeNotify: " + "returning " FORMAT_API_STATUS ".\n", ApiStatus )); + } + + return (ApiStatus); + +} // ReplEnableChangeNotify + + +NET_API_STATUS +ReplGetChangeNotifyStatus( + IN LPREPL_CHANGE_NOTIFY_HANDLE ReplHandle + ) +{ + NET_API_STATUS ApiStatus; + NTSTATUS NtStatus; + + NetpAssert( ReplIsChangeNotifyHandleValid( ReplHandle ) ); + + // BUGBUG: What status do we get if buffer overflowed? + + NtStatus = ReplHandle->IoStatusBlock.Status; + + ApiStatus = NetpNtStatusToApiStatus( NtStatus ); + + ReplHandle->BufferBytesValid = ReplHandle->IoStatusBlock.Information; + NetpAssert( ReplIsChangeNotifyHandleValid( ReplHandle ) ); + + IF_DEBUG( CHNGNOT ) { + NetpKdPrint(( PREFIX_REPL "ReplGetChangeNotifyStatus: " + "NT status is " FORMAT_NTSTATUS ", " + "num bytes valid is " FORMAT_DWORD ", " + "returning " FORMAT_API_STATUS ".\n", + NtStatus, ReplHandle->BufferBytesValid, ApiStatus )); + } + + return (ApiStatus); + +} // ReplGetChangeNotifyStatus + + +NET_API_STATUS +ReplExtractChangeNotifyFirstDir( + IN OUT LPREPL_CHANGE_NOTIFY_HANDLE ReplHandle, + IN BOOL FirstTime, + OUT LPTSTR FirstLevelDirName + ) +{ + LPVOID BufferValidEnd; + DWORD CharsLeft; + LPTSTR InCharPtr, OutCharPtr; + PFILE_NOTIFY_INFORMATION EntryPtr; + + NetpAssert( ReplIsChangeNotifyHandleValid( ReplHandle ) ); + + if (FirstTime) { + ReplHandle->NextElementInBuffer = ReplHandle->Buffer; + } + EntryPtr = ReplHandle->NextElementInBuffer; + + BufferValidEnd = + ((LPBYTE)(ReplHandle->Buffer)) + + (ReplHandle->BufferBytesValid); + if ( BufferValidEnd >= ReplHandle->NextElementInBuffer ) { + return (ERROR_NO_MORE_ITEMS); + } + + NetpAssert( EntryPtr->FileNameLength > 0 ); + NetpAssert( (EntryPtr->FileNameLength % sizeof(WCHAR)) == 0 ); + + NetpAssert( sizeof(WCHAR) == sizeof(TCHAR) ); + InCharPtr = (LPTSTR) (LPVOID) (EntryPtr->FileName); + OutCharPtr = FirstLevelDirName; + CharsLeft = (EntryPtr->FileNameLength) / sizeof(WCHAR); + + /*lint -save -e716 */ // disable warnings for while(TRUE) + while (TRUE) { + if (CharsLeft == 0) { + break; + } else if ( IS_PATH_SEPARATOR( *InCharPtr ) ) { + break; + } + + *OutCharPtr = *InCharPtr; + + --CharsLeft; + ++InCharPtr; + ++OutCharPtr; + } + /*lint -restore */ // re-enable warnings for while(TRUE) + + *OutCharPtr = TCHAR_EOS; + + IF_DEBUG( CHNGNOT ) { + NetpKdPrint(( PREFIX_REPL + "ReplExtractChangeNotifyFirstDir: first level dir is '" + FORMAT_LPTSTR "'\n", FirstLevelDirName )); + } + + ReplHandle->NextElementInBuffer = + ((LPBYTE)EntryPtr) + + EntryPtr->NextEntryOffset; + + NetpAssert( ReplIsChangeNotifyHandleValid( ReplHandle ) ); + + return (NO_ERROR); + +} // ReplExtractChangeNotifyFirstDir + + +NET_API_STATUS +ReplCloseChangeNotify( + IN OUT LPREPL_CHANGE_NOTIFY_HANDLE ReplHandle + ) +{ + NetpAssert( ReplIsChangeNotifyHandleValid( ReplHandle ) ); + + if (ReplHandle != NULL) { + if (ReplHandle->Buffer != NULL) { + NetpMemoryFree( ReplHandle->Buffer ); + } + if ((ReplHandle->WaitableHandle) != NULL) { + (VOID) NtClose( ReplHandle->WaitableHandle ); + } + NetpMemoryFree( ReplHandle ); + } + + return (NO_ERROR); + +} // ReplCloseChangeNotify diff --git a/private/net/svcdlls/repl/common/chngnot.h b/private/net/svcdlls/repl/common/chngnot.h new file mode 100644 index 000000000..5b585e404 --- /dev/null +++ b/private/net/svcdlls/repl/common/chngnot.h @@ -0,0 +1,85 @@ +/*++ + +Copyright (c) 1992 Microsoft Corporation + +Module Name: + + ChngNot.h + +Abstract: + + This module defines some change notify datatypes and routines. + +Author: + + John Rogers (JohnRo) 25-Nov-1992 + +Environment: + + Runs under Windows NT. + Requires ANSI C extensions: slash-slash comments, long external names. + +Revision History: + + 25-Nov-1992 JohnRo + Repl should use filesystem change notify. + +--*/ + + +#ifndef _CHNGNOT_ +#define _CHNGNOT_ + + +typedef struct _REPL_CHANGE_NOTIFY_HANDLE { + + // Handle for use by callers. + HANDLE WaitableHandle; + + // From here on are "implementation details"; callers should NOT use them. + LPVOID Buffer; + DWORD BufferSize; + DWORD BufferBytesValid; + IO_STATUS_BLOCK IoStatusBlock; + LPVOID NextElementInBuffer; // Points in Buffer, or is NULL. + +} REPL_CHANGE_NOTIFY_HANDLE; + +typedef REPL_CHANGE_NOTIFY_HANDLE * PREPL_CHANGE_NOTIFY_HANDLE; +typedef REPL_CHANGE_NOTIFY_HANDLE * LPREPL_CHANGE_NOTIFY_HANDLE; + + +NET_API_STATUS +ReplSetupChangeNotify( + IN LPTSTR AbsPath, + OUT LPREPL_CHANGE_NOTIFY_HANDLE *ReplHandle + ); + + +NET_API_STATUS +ReplEnableChangeNotify( + IN OUT LPREPL_CHANGE_NOTIFY_HANDLE ReplHandle + ); + + +NET_API_STATUS +ReplGetChangeNotifyStatus( + IN LPREPL_CHANGE_NOTIFY_HANDLE ReplHandle + ); + + +NET_API_STATUS +ReplExtractChangeNotifyFirstDir( + IN OUT LPREPL_CHANGE_NOTIFY_HANDLE ReplHandle, + IN BOOL FirstTime, + OUT LPTSTR FirstLevelDirName + ); + + +NET_API_STATUS +ReplCloseChangeNotify( + IN OUT LPREPL_CHANGE_NOTIFY_HANDLE ReplHandle + ); + + +#endif // _CHNGNOT_ diff --git a/private/net/svcdlls/repl/common/data.c b/private/net/svcdlls/repl/common/data.c new file mode 100644 index 000000000..c38b87824 --- /dev/null +++ b/private/net/svcdlls/repl/common/data.c @@ -0,0 +1,45 @@ +/*++ + +Copyright (c) 1992 Microsoft Corporation + +Module Name: + + Data.c + +Abstract: + + Global data for repl debug routines. (Debug only, so no security problems.) + +Author: + + John Rogers (JohnRo) 14-Mar-1992 + +Environment: + + Portable to any flat, 32-bit environment. (Uses Win32 typedefs.) + Requires ANSI C extensions: slash-slash comments, long external names. + +Revision History: + + 14-Mar-1992 JohnRo + Created. +--*/ + + +// These must be included first: + +#include <windef.h> // DWORD, etc. +#include <lmcons.h> // Needed by repldefs.h/netlib.h. + +// These may be included in any order: + +#include <repldefs.h> // REPL_DEBUG_ALL. + +#if DBG + +//DWORD ReplGlobalTrace = 0; +DWORD ReplGlobalTrace = 0; //REPL_DEBUG_ALL; + +#endif + +// That's all, folks! diff --git a/private/net/svcdlls/repl/common/delfile.c b/private/net/svcdlls/repl/common/delfile.c new file mode 100644 index 000000000..4d4600631 --- /dev/null +++ b/private/net/svcdlls/repl/common/delfile.c @@ -0,0 +1,262 @@ +/*++ + +Copyright (c) 1993 Microsoft Corporation + +Module Name: + + DelFile.c + +Abstract: + + This file just contains ReplDeleteFile. + + This is callable even if the replicator service is not started. + +Author: + + JR (John Rogers, JohnRo@Microsoft) 26-Apr-1993 + +Environment: + + User Mode - Win32 + Portable to any flat, 32-bit environment. (Uses Win32 typedefs.) + Requires ANSI C extensions: slash-slash comments, long external names. + +Revision History: + + 26-Apr-1993 JohnRo + Created for RAID 7313: repl needs change permission to work on NTFS, + or we need to delete files differently. + +--*/ + + +// These must be included first: + +#include <nt.h> // NT_SUCCESS(), etc. +#include <ntrtl.h> +#include <nturtl.h> +#include <windows.h> // IN, GetLastError(), LPCTSTR, OPTIONAL, etc. +#include <lmcons.h> // NET_API_STATUS. + +// These may be included in any order: + +#include <lmerrlog.h> // NELOG_ equates. +#include <netdebug.h> // NetpKdPrint(), FORMAT_ equates, etc. +#include <netlibnt.h> // NetpNtStatusToApiStatus(). +#include <prefix.h> // PREFIX_ equates. +#include <repldefs.h> // IF_DEBUG(), my prototype, USE_ equates, etc. +#include <tstr.h> // TCHAR_EOS. +#include <winerror.h> // ERROR_ and NO_ERROR equates. + + +// BUGBUG: undo this! +#undef USE_BACKUP_APIS + + +NET_API_STATUS +ReplDeleteFile( + IN LPCTSTR FileName + ) +{ + NET_API_STATUS ApiStatus; +#ifdef USE_BACKUP_APIS + HANDLE FileHandle = INVALID_HANDLE_VALUE; + IO_STATUS_BLOCK IoStatusBlock; + + const ACCESS_MASK MyAccessDesired = + ( DELETE + | FILE_READ_ATTRIBUTES + | FILE_READ_DATA + | FILE_READ_EA + | FILE_TRAVERSE + | SYNCHRONIZE + ); + + const ULONG MyOpenOptions = + FILE_SYNCHRONOUS_IO_NONALERT + | FILE_DELETE_ON_CLOSE + | FILE_OPEN_FOR_BACKUP_INTENT + ; + + const ULONG MyShareAccess = + FILE_SHARE_READ; // BUGBUG +// FILE_SHARE_DELETE; + + NTSTATUS NtStatus; + OBJECT_ATTRIBUTES ObjectAttributes; + BOOL PathAllocated = FALSE; + UNICODE_STRING UnicodePath; +#endif + + // + // Check for caller errors. + // + + if ( (FileName==NULL) || ((*FileName)==TCHAR_EOS) ) { + ApiStatus = ERROR_INVALID_PARAMETER; + goto Cleanup; + } + + // + // Tell the world what we're going to do. + // + + IF_DEBUG( REPL ) { + NetpKdPrint(( PREFIX_REPL + "ReplDeleteFile: *** DELETING FILE *** '" FORMAT_LPTSTR "'.\n", + FileName )); + } + + // + // return no error if the file does not exist. + // + if ( !ReplFileOrDirExists( FileName ) ) { + return( NO_ERROR ); + } + +#ifndef USE_BACKUP_APIS + + // + // If the file system ACL allows us to delete, we can just + // use the Win32 APIs for this. + // + + if ( ! DeleteFile( (LPTSTR) FileName ) ) { + ApiStatus = (NET_API_STATUS) GetLastError(); + } else { + ApiStatus = NO_ERROR; + } + +#else + + // + // It turns out that "backup semantics" is very powerful. It allows + // us to create files in directories which have read-only ACLs. + // Unfortunately, there isn't a "backup semantics" flag for DeleteFile(), + // so we need to use the NT APIs to get the same effect. + // + + // + // Convert file name to NT style. + // + + RtlInitUnicodeString( + & UnicodePath, // output: struct + FileName ); // input: null terminated + + if( !RtlDosPathNameToNtPathName_U( + FileName, + &UnicodePath, + NULL, + NULL) ) { + + NetpKdPrint(( PREFIX_REPL_CLIENT + "ReplDeleteFile: RtlDosPathNameToNtPathname_U" + " of file '" FORMAT_LPTSTR "' failed.\n", FileName )); + + // BUGBUG: this is just our best guess for an error code this. + ApiStatus = ERROR_INVALID_PARAMETER; + goto Cleanup; + } + NetpAssert( UnicodePath.Buffer != NULL ); + PathAllocated = TRUE; + + InitializeObjectAttributes( + &ObjectAttributes, + (LPVOID) &UnicodePath, + OBJ_CASE_INSENSITIVE, + NULL, + NULL ); + + // + // Open the file, with backup semantics and delete on close. + // + + NtStatus = NtOpenFile( + & FileHandle, + MyAccessDesired, + &ObjectAttributes, + &IoStatusBlock, + MyShareAccess, + MyOpenOptions ); + + if ( !NT_SUCCESS( NtStatus ) ) { + + NetpKdPrint(( PREFIX_REPL_CLIENT + "ReplDeleteFile: NtOpenFile of file '" + FORMAT_LPTSTR "' gave NT status " FORMAT_NTSTATUS ".\n", + FileName, NtStatus )); + + ApiStatus = NetpNtStatusToApiStatus( NtStatus ); + NetpAssert( ApiStatus != NO_ERROR ); + goto Cleanup; + } + NetpAssert( NtStatus == STATUS_SUCCESS ); + NetpAssert( FileHandle != INVALID_HANDLE_VALUE ); + + // + // Close the file, which will delete it since we gave the + // FILE_CLOSE_ON_DELETE flag. + // + + NtStatus = NtClose( FileHandle ); + FileHandle = INVALID_HANDLE_VALUE; + + if ( !NT_SUCCESS( NtStatus ) ) { + + NetpKdPrint(( PREFIX_REPL_CLIENT + "ReplDeleteFile: NtClose failed, " + " NT status is " FORMAT_NTSTATUS + ".\n", NtStatus )); + + ApiStatus = NetpNtStatusToApiStatus( NtStatus ); + NetpAssert( ApiStatus != NO_ERROR ); + goto Cleanup; + } + NetpAssert( NtStatus == STATUS_SUCCESS ); + + (void) NtClose( FileHandle ); + FileHandle = INVALID_HANDLE_VALUE; + + (VOID) RtlFreeHeap( RtlProcessHeap(), 0, UnicodePath.Buffer ); + PathAllocated = FALSE; + + ApiStatus = NO_ERROR; + +#endif + + +Cleanup: + + if (ApiStatus != NO_ERROR) { + + NetpKdPrint(( PREFIX_REPL + "ReplDeleteFile: ERROR " FORMAT_API_STATUS ".\n", + ApiStatus )); + + // + // Log the error. + // BUGBUG: extract master server name and log there too. + // + ReplErrorLog( + NULL, // no server name (log locally) + NELOG_ReplSysErr, // log code + ApiStatus, + NULL, // optional str1 + NULL); // optional str2 + } + +#ifdef USE_BACKUP_APIS + if (FileHandle != INVALID_HANDLE_VALUE) { + (VOID) NtClose( FileHandle ); + } + + if (PathAllocated) { + (VOID) RtlFreeHeap( RtlProcessHeap(), 0, UnicodePath.Buffer ); + } +#endif + + return (ApiStatus); + +} diff --git a/private/net/svcdlls/repl/common/dirname.c b/private/net/svcdlls/repl/common/dirname.c new file mode 100644 index 000000000..b172cc862 --- /dev/null +++ b/private/net/svcdlls/repl/common/dirname.c @@ -0,0 +1,112 @@ +/*++ + +Copyright (c) 1992 Microsoft Corporation + +Module Name: + + DirName.c + +Abstract: + + This module has some simple replicator directory name helpers. + +Author: + + John Rogers (JohnRo) 07-Jan-1992 + +Environment: + + Runs under Windows NT. + Requires ANSI C extensions: slash-slash comments, long external names. + +Revision History: + + 07-Jan-1992 JohnRo + Created. + 24-Jan-1992 JohnRo + Changed to use LPTSTR etc. + 26-Mar-1992 JohnRo + Added check to disallow "c:\stuff" form. + +--*/ + + +// These must be included first: + +#include <windef.h> // IN, VOID, LPTSTR, etc. +#include <lmcons.h> // PATHLEN, etc. + +// These can be in any order: + +#include <dirname.h> // My prototypes. +#include <tstr.h> // STRLEN(). +#include <winerror.h> // ERROR_ equates, NO_ERROR. + + +BOOL +ReplIsDirNameValid( + IN LPTSTR DirName + ) + +/*++ + +Routine Description: + + ReplIsDirNameValid checks to see if a replicator directory name is + syntactically valid. No check is made to see if the directory exists. + +Arguments: + + DirName points to a string containing an alleged replicator directory + name. + +Return Value: + + BOOL - TRUE iff the directory name is valid. + +--*/ + +{ + TCHAR FirstChar; + + if ( (DirName == NULL) || (*DirName == L'\0') ) { + return (FALSE); + } + FirstChar = DirName[0]; + + + if (STRLEN( DirName ) > PATHLEN) { + return (FALSE); + } + + if (ISALPHA( FirstChar )) { + if (STRLEN(DirName) >= 2) { + + if (DirName[1] == TCHAR_COLON) { // Sneak in "c:\stuff"? + return (FALSE); // Name not valid! + } + } + } + + // + // BUGBUG: This is just a quick partial hack. Eventually we should + // call the canon routines. + // + + switch (FirstChar) { + case TCHAR_BACKSLASH: + // Name must be relative; no UNC or absolute paths allowed. + /*FALLTHROUGH*/ + case TCHAR_FWDSLASH: + // Name must be relative; no UNC or absolute paths allowed. + /*FALLTHROUGH*/ + + return (FALSE); // name is not valid + + default: + return (TRUE); + } + + /*NOTREACHED*/ + +} // ReplIsDirNameValid diff --git a/private/net/svcdlls/repl/common/dirname.h b/private/net/svcdlls/repl/common/dirname.h new file mode 100644 index 000000000..f201b63b7 --- /dev/null +++ b/private/net/svcdlls/repl/common/dirname.h @@ -0,0 +1,64 @@ +/*++ + +Copyright (c) 1991-92 Microsoft Corporation + +Module Name: + + DirName.h + +Abstract: + + This module has some simple replicator directory name helpers. + +Author: + + John Rogers (JohnRo) 31-Dec-1991 + +Environment: + + Runs under Windows NT. + Requires ANSI C extensions: slash-slash comments, long external names. + +Revision History: + + 31-Dec-1991 JohnRo + Created. + 08-Jan-1992 JohnRo + Added ReplDirNamesMatch() macro. + 09-Jan-1992 JohnRo + Use _wcscmpi() instead of wcscmpi(). + 24-Jan-1992 JohnRo + Changed to use LPTSTR etc. + 05-Dec-1992 JohnRo + Made changes suggested by PC-LINT 5.0 + +--*/ + +#ifndef _DIRNAME_ +#define _DIRNAME_ + + +// Don't complain about "unneeded" includes of these files: +/*lint -efile(764,tstr.h) */ +#include <tstr.h> // STRICMP(). + + +// BOOL +// ReplDirNamesMatch( +// IN LPTSTR OneName, +// IN LPTSTR TheOther +// ); +// +// BUGBUG: Should this canonicalize? (E.g. ".\a" == "a"?) +// +#define ReplDirNamesMatch(OneName,TheOther) \ + ( ( (STRICMP( (OneName), (TheOther))) == 0 ) ? TRUE : FALSE ) + + +BOOL +ReplIsDirNameValid( + IN LPTSTR DirName + ); + + +#endif // _DIRNAME_ diff --git a/private/net/svcdlls/repl/common/easize.c b/private/net/svcdlls/repl/common/easize.c new file mode 100644 index 000000000..dbf292fb3 --- /dev/null +++ b/private/net/svcdlls/repl/common/easize.c @@ -0,0 +1,236 @@ +/*++ + +Copyright (c) 1993 Microsoft Corporation + +Module Name: + + EaSize.c + +Abstract: + + Compute size of full EA list (using OS/2 semantics) for a file or + directory. This must match OS/2 usage, down to the bit, as this + value is used in the replicator checksum. One thing in particular: + the "EA size" of a file with no EAs is 4, as it takes four bytes to + indicate empty full EA list. + +Author: + + JR (John Rogers, JohnRo@Microsoft) 10-May-1993 + +Revision History: + + 10-May-1993 JohnRo + Created for RAID 3258: file not updated due to + ERROR_INVALID_USER_BUFFER (actually, massive rework of buggy + version in repl/server/filefind.c). + +--*/ + + +// These must be included first: + +#include <nt.h> // NT definitions +#include <ntrtl.h> // NT runtime library definitions +#include <nturtl.h> +#include <windows.h> +#include <lmcons.h> // NET_API_STATUS. + +// These may be included in any order: + +#include <lmerr.h> // NERR_ equates. +#include <lmerrlog.h> // NELOG_ equates. +#include <netdebug.h> // NetpAssert(), NetpKdPrint(), FORMAT_ equates. +#include <netlibnt.h> // NetpNtStatusToApiStatus(). +#include <prefix.h> // PREFIX_ equates. +#include <repldefs.h> // IF_DEBUG(), ReplErrorLog(), ReplGetEaSize(), etc. +#include <tstr.h> // STRLEN(), etc. + + +#define MY_ACCESS_DESIRED ( FILE_READ_DATA | FILE_READ_EA \ + | FILE_TRAVERSE \ + | SYNCHRONIZE | FILE_READ_ATTRIBUTES ) + + +DWORD +ReplGetEaSize( + IN LPCTSTR Path + ) + +/*++ + +Routine Description: + + Retrive EaSize of the given file and convert it to DosFindFirst2 + EaSize. + +Arguments: + + Path - file name. May refer to file or directory. May include drive + letter (e.g. "d:\import\dir\file.ext") or be UNC path (e.g. + "\\server\repl$\dir\dir2\file.ext"). + +Return Value: + + Return DosFindFirst2 EaSize. This value will be 4 if no EAs exist or + an error occurs. + +--*/ + +{ + NET_API_STATUS ApiStatus = NO_ERROR; + FILE_EA_INFORMATION EaInfo; + DWORD EaSize = EA_MIN_SIZE; // initially set to return on err + HANDLE FileHandle = INVALID_HANDLE_VALUE; + UNICODE_STRING FileName; + IO_STATUS_BLOCK IoStatusBlock; + NTSTATUS NtStatus = STATUS_SUCCESS; + OBJECT_ATTRIBUTES ObjectAttributes; + BOOL PathAllocated = FALSE; + DWORD PathLength; + + NetpAssert( Path != NULL ); + NetpAssert( (*Path) != TCHAR_EOS ); + + // + // Some systems don't like NtQueryEaFile with names like: + // + // \\server\REPL$\dir\. + // \\server\REPL$\dir\.. + // + // so avoid them. (They won't be used in checksums anyway, so it + // doesn't matter if we lie about their EA sizes.) + // + PathLength = STRLEN(Path); + if (PathLength >= 2) { + LPCTSTR LastTwoChars = &Path[ PathLength-2 ]; + NetpAssert( (*LastTwoChars) != TCHAR_EOS ); + if (STRCMP( LastTwoChars, SLASH_DOT ) == 0) { + goto Cleanup; + } + } + if (PathLength >= 3) { + LPCTSTR LastThreeChars = &Path[ PathLength-3 ]; + NetpAssert( (*LastThreeChars) != TCHAR_EOS ); + if (STRCMP( LastThreeChars, SLASH_DOT_DOT ) == 0) { + goto Cleanup; + } + } + +#ifndef UNICODE +#error Fix code below if UNICODE is not defined any more. +#endif + + if( !RtlDosPathNameToNtPathName_U( + Path, + &FileName, + NULL, + NULL + ) ) { + + NetpKdPrint(( PREFIX_REPL + "ReplGetEaSize: " + "Could not convert DOS path '" FORMAT_LPTSTR "' " + "to NT path.\n", Path )); + + ApiStatus = NERR_InternalError; + goto Cleanup; + } + PathAllocated = TRUE; + + InitializeObjectAttributes( + &ObjectAttributes, + &FileName, + OBJ_CASE_INSENSITIVE, + NULL, + NULL ); + + NtStatus = NtOpenFile( + &FileHandle, + MY_ACCESS_DESIRED, + &ObjectAttributes, + &IoStatusBlock, + FILE_SHARE_READ, + FILE_SYNCHRONOUS_IO_NONALERT ); // open options + + if (! NT_SUCCESS(NtStatus)) { + ApiStatus = NetpNtStatusToApiStatus( NtStatus ); + NetpKdPrint(( PREFIX_REPL + "ReplGetEaSize: NtOpenFile " FORMAT_LPTSTR " failed: " + FORMAT_NTSTATUS "\n", + Path, NtStatus )); + NetpAssert( ApiStatus != NO_ERROR ); + goto Cleanup; + } + + IF_DEBUG( FILEFIND ) { + NetpKdPrint(( PREFIX_REPL + "ReplGetEaSize: Succeeded in opening dir.\n" )); + } + + NtStatus = NtQueryInformationFile( + FileHandle, + &IoStatusBlock, + &EaInfo, + sizeof(FILE_EA_INFORMATION), + FileEaInformation ); // information class + + if ( !NT_SUCCESS( NtStatus ) ) { + + NetpKdPrint(( PREFIX_REPL + "ReplGetEaSize: NtQueryInformationFile for " + FORMAT_LPTSTR " FAILED, NtStatus=" + FORMAT_NTSTATUS ", iosb.info=" FORMAT_ULONG "\n", + Path, NtStatus, IoStatusBlock.Information )); + ApiStatus = NetpNtStatusToApiStatus( NtStatus ); + NetpAssert( ApiStatus != NO_ERROR ); + goto Cleanup; + } + + EaSize = EaInfo.EaSize; + if (EaSize == 0) { + EaSize = EA_MIN_SIZE; + } + +Cleanup: + + // + // Take care of things and return EaSize to caller. + // Also use ApiStatus to decide whether or not to log anything. + // + + if (ApiStatus != NO_ERROR) { + + // BUGBUG: log this remotely too. + ReplErrorLog( + NULL, // no server name (local) + NELOG_ReplSysErr, // log code + ApiStatus, // error code we got + NULL, // no optional str 1 + NULL ); // no optional str 2 + + NetpKdPrint(( PREFIX_REPL + "ReplGetEaSize: ERROR processing '" FORMAT_LPTSTR "', " + "final NT status " FORMAT_NTSTATUS ", " + "final API status " FORMAT_API_STATUS ".\n", + Path, NtStatus, ApiStatus )); + } + + IF_DEBUG( FILEFIND ) { + NetpKdPrint(( PREFIX_REPL + "ReplGetEaSize: returning EA size " FORMAT_DWORD " " + "for " FORMAT_LPTSTR ", final NT status " FORMAT_NTSTATUS ", " + "final API status " FORMAT_API_STATUS ".\n", + EaSize, Path, NtStatus, ApiStatus )); + } + + if (PathAllocated) { + (VOID) RtlFreeHeap( RtlProcessHeap(), 0, FileName.Buffer ); + } + + if (FileHandle != INVALID_HANDLE_VALUE) { + (void) NtClose(FileHandle); + } + + return (EaSize); +} diff --git a/private/net/svcdlls/repl/common/expalloc.c b/private/net/svcdlls/repl/common/expalloc.c new file mode 100644 index 000000000..da5fe7f1c --- /dev/null +++ b/private/net/svcdlls/repl/common/expalloc.c @@ -0,0 +1,120 @@ +/*++ + +Copyright (c) 1992 Microsoft Corporation + +Module Name: + + ExpAlloc.c + +Abstract: + + This file contains ExportDirAllocApiRecords(). + +Author: + + John Rogers (JohnRo) 22-Jan-1992 + +Environment: + + Runs under Windows NT. + Requires ANSI C extensions: slash-slash comments, long external names. + +Revision History: + + 22-Jan-1992 JohnRo + Created. + 28-Jan-1992 JohnRo + Changed ExportDirAllocApiRecords() to allow arrays. + +--*/ + + +// These must be included first: + +#include <windef.h> // IN, VOID, LPTSTR, etc. +#include <lmcons.h> // NET_API_STATUS, PARM equates, etc. +#include <rap.h> // Needed by <strucinf.h>. + +// These can be in any order: + +#include <expdir.h> // My prototype. +#include <lmapibuf.h> // NetApiBufferAllocate(). +#include <netdebug.h> // NetpAssert(). +#include <netlib.h> // NetpPointerPlusSomeBytes(). +#include <strucinf.h> // Netp{various}StructureInfo(). +#include <winerror.h> // ERROR_* defines; NO_ERROR. + + +NET_API_STATUS +ExportDirAllocApiRecords ( + IN DWORD Level, + IN DWORD EntryCount, + OUT LPBYTE * BufPtr, + IN OUT LPBYTE *StringLocation // Points just past top of data. + ) + +{ + LPBYTE FirstRecord = NULL; + NET_API_STATUS ApiStatus; + DWORD EntrySize; + + // + // Check for caller errors. + // + if (BufPtr == NULL) { + return (ERROR_INVALID_PARAMETER); + } + + * BufPtr = NULL; // Don't confuse caller about possible alloc'ed data. + + if (EntryCount == 0) { + return (ERROR_INVALID_PARAMETER); + } + + // + // Compute size of an entry (and check caller's Level too). + // + ApiStatus = NetpReplExportDirStructureInfo ( + Level, + PARMNUM_ALL, + TRUE, // want native sizes + NULL, // don't need DataDesc16 + NULL, // don't need DataDesc32 + NULL, // don't need DataDescSmb + & EntrySize, // need max size of structure + NULL, // don't need FixedSize + NULL); // don't need StringSize + if (ApiStatus != NO_ERROR) { + return (ApiStatus); + } + NetpAssert( EntrySize > 0 ); + + // + // Allocate the output area. + // + ApiStatus = NetApiBufferAllocate( + EntrySize * EntryCount, + (LPVOID *) & FirstRecord); + if (ApiStatus != NO_ERROR) { + + // ApiStatus is already set to return error to caller. + + } else { + NetpAssert( FirstRecord != NULL ); + + // + // Tell caller where top of string area is. + // + * StringLocation = NetpPointerPlusSomeBytes( + FirstRecord, + EntrySize * EntryCount ); + + } + + // + // Tell caller how everything went. + // + * BufPtr = FirstRecord; + return (ApiStatus); + +} diff --git a/private/net/svcdlls/repl/common/expbuild.c b/private/net/svcdlls/repl/common/expbuild.c new file mode 100644 index 000000000..690f23bff --- /dev/null +++ b/private/net/svcdlls/repl/common/expbuild.c @@ -0,0 +1,160 @@ +/*++ + +Copyright (c) 1992-1993 Microsoft Corporation + +Module Name: + + ExpBuild.c + +Abstract: + + This file contains ExportDirBuildApiRecord. This is used by + NetrReplExportDirGetInfo and NetrReplExportDirEnum. + +Author: + + John Rogers (JohnRo) 08-Jan-1992 + +Environment: + + Runs under Windows NT. + Requires ANSI C extensions: slash-slash comments, long external names. + +Notes: + + This code assumes that the export dir info levels are subsets of each other. + Also, this routine is callable whether or not the replicator service is + started. + +Revision History: + + 08-Jan-1992 JohnRo + Created. + 08-Jan-1992 JohnRo + Fixed level 1 trashing bug. + 21-Jan-1992 JohnRo + Changed ExportDirBuildApiRecord's interface. + 24-Jan-1992 JohnRo + Changed to use LPTSTR etc. + 26-Feb-1992 JohnRo + API records now contain timestamps instead of elapsed times. + Check lock fields for validity. + Added assertion of valid record at end. + 15-Mar-1992 JohnRo + Improve setinfo info level support. + 28-Jul-1992 JohnRo + RAID 2274: repl svc should impersonate caller. + 08-Feb-1993 JohnRo + PC-LINT found a bug. + Use NetpKdPrint() where possible. + +--*/ + + +// These must be included first: + +#include <windef.h> // IN, VOID, LPTSTR, etc. +#include <lmcons.h> // NET_API_STATUS, PARM equates, etc. +#include <repldefs.h> // ReplIsIntegrityValid(), etc. + +// These can be in any order: + +#include <align.h> // POINTER_IS_ALIGNED(), ALIGN_TCHAR. +#include <dirname.h> // ReplIsDirNameValid(). +#include <expdir.h> // My prototype, ExportDirIsLevelValid(). +#include <lmrepl.h> // LPREPL_EDIR_INFO_1, REPL_EXTENT_ stuff, etc. +#include <netdebug.h> // NetpAssert(), NetpKdPrint(), etc. +#include <prefix.h> // PREFIX_ equates. +#include <tstr.h> // STRLEN(), etc. +#include <winerror.h> // ERROR_ equates, NO_ERROR. + + +NET_API_STATUS +ExportDirBuildApiRecord ( + IN DWORD Level, + IN LPTSTR DirName, + IN DWORD Integrity, + IN DWORD Extent, + IN DWORD LockCount, + IN DWORD TimeOfFirstLock, // Seconds since 1970. + OUT LPVOID Buffer, + IN OUT LPBYTE *StringLocation // Points just past top of data. + ) + +{ + LPREPL_EDIR_INFO_2 ApiRecord = Buffer; // superset info level + LPTSTR StringDest; + DWORD StringLength; + + NetpAssert( StringLocation != NULL); + NetpAssert( *StringLocation != NULL); + + IF_DEBUG( EXPAPI ) { + NetpKdPrint(( PREFIX_REPL + "ExportDirBuildApiRecord: building record at " FORMAT_LPVOID + ", *str loc is " FORMAT_LPVOID ".\n", + (LPVOID) Buffer, (LPVOID) *StringLocation )); + } + + // + // Check for caller errors. + // + if (Buffer == NULL) { + return (ERROR_INVALID_PARAMETER); + } + NetpAssert( DirName != NULL); + if ( !ReplIsDirNameValid( DirName ) ) { + return (ERROR_INVALID_PARAMETER); + } + NetpAssert( Buffer != NULL); + if ( !ExportDirIsLevelValid( Level, FALSE ) ) { // don't allow setinfo. + return (ERROR_INVALID_LEVEL); + } + NetpAssert( ReplAreLockFieldsValid( LockCount, TimeOfFirstLock ) ); + + // + // First do subset common to all info levels. + // + StringLength = (DWORD) STRLEN( DirName ); + + NetpAssert( POINTER_IS_ALIGNED( *StringLocation, ALIGN_TCHAR ) ); + StringDest = (LPTSTR) (LPVOID) (*StringLocation); + StringDest -= (StringLength + 1); + + *StringLocation = (LPBYTE) (LPVOID) StringDest; + + ApiRecord->rped2_dirname = StringDest; + + (void) STRCPY( + StringDest, // dest + DirName); // src + + // + // Next do stuff found in 1 and 2. + // + if (Level > 0) { + NetpAssert( ReplIsIntegrityValid( Integrity ) ); + ApiRecord->rped2_integrity = Integrity; + + NetpAssert( ReplIsExtentValid( Extent ) ); + ApiRecord->rped2_extent = Extent; + + // + // Now stuff only in level 2. + // + if (Level == 2) { + ApiRecord->rped2_lockcount = LockCount; + + if (TimeOfFirstLock == 0) { + ApiRecord->rped2_locktime = 0; + } else { + ApiRecord->rped2_locktime = TimeOfFirstLock; + } + } + } + + NetpAssert( ExportDirIsApiRecordValid( Level, ApiRecord, NULL ) ); + + return (NO_ERROR); + +} diff --git a/private/net/svcdlls/repl/common/expconf.c b/private/net/svcdlls/repl/common/expconf.c new file mode 100644 index 000000000..eadffc5a0 --- /dev/null +++ b/private/net/svcdlls/repl/common/expconf.c @@ -0,0 +1,694 @@ +/*++ + +Copyright (c) 1992-1993 Microsoft Corporation + +Module Name: + + ExpConf.c + +Abstract: + + This file contains structures, function prototypes, and definitions + for the replicator export directory worker routines. + +Author: + + John Rogers (JohnRo) 09-Jan-1992 + +Environment: + + User Mode - Win32 + Portable to any flat, 32-bit environment. (Uses Win32 typedefs.) + Requires ANSI C extensions: slash-slash comments, long external names. + +Revision History: + + 09-Jan-1992 JohnRo + Created. + 23-Jan-1992 JohnRo + Clarify units for time parameters. + 28-Jan-1992 JohnRo + Added ExportDirConfigDataExists() and ExportDirDeleteConfigData(). + ExportDirReadConfigData() should return NERR_UnknownDevDir. + Changed to use LPTSTR etc. + 03-Feb-1992 JohnRo + Corrected config _write where extent trashed integrity value. + Got rid of extra parse of comma. + Call ReplConfigReportBadParmValue() to inform user. + Corrected lengths used for integrity and extent. + 10-Feb-1992 JohnRo + ExportDirReadConfigData() should handle section not found. + 13-Feb-1992 JohnRo + Implement ExportDirDeleteConfigData(). + Moved section name equates to ConfName.h. + 26-Feb-1992 JohnRo + API records now contain timestamps instead of elapsed times. + 23-Mar-1992 JohnRo + Get rid of old config helpers. + 10-Jul-1992 JohnRo + RAID 10503: srv mgr: repl dialog doesn't come up. + Use PREFIX_ equates. + 23-Jul-1992 JohnRo + RAID 2274: repl svc should impersonate caller. + 29-Sep-1992 JohnRo + Also fix remote repl admin. + 04-Dec-1992 JohnRo + RAID 3844: remote NetReplSetInfo uses local machine type. + Made changes suggested by PC-LINT 5.0 + 21-Jan-1993 JohnRo + RAID 7717: Repl assert if not logged on correctly. (Also do event + logging for real.) + More changes suggested by PC-LINT 5.0 + 25-Jan-1993 JohnRo + RAID 12914: avoid double close and free mem in ExportDirDeleteConfigData + 30-Apr-1993 JohnRo + Use NetpKdPrint() where possible. + +--*/ + + +#include <windef.h> // Win32 type definitions +#include <lmcons.h> // LAN Manager common definitions +#include <repldefs.h> // IF_DEBUG(), DWORDLEN. + +#include <config.h> // NetpConfig helpers. +#include <confname.h> // SECT_NT_ equates. +#include <dirname.h> // ReplIsDirNameValid(). +#include <expdir.h> // My prototypes. +#include <lmapibuf.h> // NetApiBufferFree(). +#include <lmerr.h> // NERR_, ERROR_, NO_ERROR equates. +#include <lmerrlog.h> // NELOG_ equates. +#include <lmrepl.h> // REPL_INTEGRITY equates, etc. +#include <netdebug.h> // NetpAssert(), etc. +#include <netlib.h> // NetpPointerPlusSomeBytes(). +#include <prefix.h> // PREFIX_ equates. +#include <replconf.h> // ReplConfigReportBadParmValue(). +#include <tstr.h> // STRCPY(), ATOL(). + + +#define STRING_FILE (LPVOID) TEXT("FILE") +#define STRING_TREE (LPVOID) TEXT("TREE") + +#define MAX_INTEGRITY_LEN 4 +#define MAX_EXTENT_LEN 4 + +#define EXPORT_VALUE_ARRAY_LEN \ + (MAX_INTEGRITY_LEN /* integrity */ \ + + 1 /* , */ \ + + MAX_EXTENT_LEN /* extent */ \ + + 1 /* , */ \ + + DWORDLEN /* lockcount */ \ + + 1 /* , */ \ + + DWORDLEN ) /* locktime (seconds since 1970) */ + + +// Tells whether or not config data for this directory exists. +// Callable even if the replicator service is not started. +BOOL +ExportDirConfigDataExists ( + IN LPTSTR UncServerName OPTIONAL, + IN LPTSTR DirName // Caller must check dir name syntax. + ) +{ + NET_API_STATUS ApiStatus; + LPNET_CONFIG_HANDLE Handle = NULL; + LPTSTR Value = NULL; + + // + // Check for caller's errors. + // + NetpAssert( ReplIsDirNameValid( DirName ) ); + + // + // Open the right section of the config file/whatever. + // + ApiStatus = NetpOpenConfigDataEx( + & Handle, + UncServerName, + (LPTSTR) SECT_NT_REPLICATOR, // section + (LPTSTR) SECT_NT_REPLICATOR_EXPORTS, // area (instead of parameters) + TRUE); // read-only + if (ApiStatus != NO_ERROR) { + // Log error on server we were trying to access. + ReplErrorLog( + UncServerName, + NELOG_ReplSysErr, + ApiStatus, + NULL, + NULL ); + return (FALSE); // section doesn't exist, so dir data doesn't. + } + + // + // Read the value from the config file/whatever. + // + ApiStatus = NetpGetConfigValue( + Handle, + DirName, // keyword is dir name + & Value); // alloc and set ptr + + // + // We're done with this, so close the config data and toss the buffer we + // got. But remember the status from NetpGetConfigValue! + // + if (Value != NULL) { + (void) NetApiBufferFree( Value ); + } + (void) NetpCloseConfigData( Handle ); + + // + // Now check the status of the Get. + // + if (ApiStatus == NERR_CfgParamNotFound) { + return (FALSE); // doesn't exist + } else if (ApiStatus == NO_ERROR) { + return (TRUE); // exists + } else { + // Log error on server we were trying to access. + ReplErrorLog( + UncServerName, + NELOG_ReplSysErr, + ApiStatus, + NULL, + NULL ); + return (FALSE); // Unexpected error, so assume it doesn't exist. + } + + /*NOTREACHED*/ + +} // ExportDirConfigDataExists + + +// Delete config data for this directory. +// Returns NERR_UnknownDevDir if config data doesn't exist for this dir. +// Callable even if the replicator service is not started. +NET_API_STATUS +ExportDirDeleteConfigData ( + IN LPTSTR UncServerName OPTIONAL, + IN LPTSTR DirName // Caller must check dir name syntax. + ) +{ + NET_API_STATUS ApiStatus; + LPNET_CONFIG_HANDLE Handle = NULL; + + // + // Check for caller's errors. + // + if ( ! ReplIsDirNameValid( DirName ) ) { + ApiStatus = ERROR_INVALID_PARAMETER; + goto Cleanup; // go log error + } + + // + // Open the right section of the config file/whatever. + // + ApiStatus = NetpOpenConfigDataEx( + & Handle, + UncServerName, + (LPTSTR) SECT_NT_REPLICATOR, // section + (LPTSTR) SECT_NT_REPLICATOR_EXPORTS, // area (instead of parameters) + FALSE ); // not read-only + if (ApiStatus == NERR_CfgCompNotFound) { + ApiStatus = NERR_UnknownDevDir; + goto Cleanup; // go log error + } else if (ApiStatus != NO_ERROR) { + goto Cleanup; // go log error + } + + // + // Delete this keyword from this section. + // + ApiStatus = NetpDeleteConfigKeyword( + Handle, + DirName ); // keyword is dir name + + IF_DEBUG(EXPAPI) { + NetpKdPrint(( PREFIX_REPL + "ExportDirDeleteConfigData( " FORMAT_LPTSTR " ): conf del ret " + FORMAT_API_STATUS ".\n", + (UncServerName!=NULL) ? UncServerName : (LPTSTR) TEXT("local"), + ApiStatus )); + } + + if (ApiStatus == NERR_CfgParamNotFound) { + ApiStatus = NERR_UnknownDevDir; + goto Cleanup; // go log error + } else if (ApiStatus != NO_ERROR) { + goto Cleanup; // go log error + } + +Cleanup: + + // + // All done. + // + if ( Handle != NULL ) { + NET_API_STATUS CloseStatus; + + CloseStatus = NetpCloseConfigData( Handle ); + + // Return this error iff it is first error we've gotten. + if ( (ApiStatus == NO_ERROR) && (CloseStatus != NO_ERROR) ) { + ApiStatus = CloseStatus; + } + } + + if (ApiStatus != NO_ERROR) { + + // Log error on server we were trying to access. + ReplErrorLog( + UncServerName, + NELOG_ReplSysErr, + ApiStatus, + NULL, + NULL ); + } + + return (ApiStatus); + +} // ExportDirDeleteConfigData + + +// Parse config data for a single export directory. Callable whether or not +// the replicator service is started. (This function is used in this file +// and by the NetReplExportDirEnum routine.) +NET_API_STATUS +ExportDirParseConfigData ( + IN LPTSTR UncServerName OPTIONAL, + IN LPTSTR ValueString, + OUT LPDWORD IntegrityPtr, + OUT LPDWORD ExtentPtr, + OUT LPDWORD LockCountPtr, + OUT LPDWORD LockTimePtr // Seconds since 1970. + ) +{ + LPTSTR CurrentValuePtr = ValueString; + + // + // Check for caller's errors. + // + NetpAssert( ValueString != NULL ); + if (STRLEN( ValueString ) > EXPORT_VALUE_ARRAY_LEN) { + goto ReportBadConfigLine; + } + + // + // Start parsing the value, which begins with a string containing the + // integrity. + // + +#define TRY_INTEGRITY( IntegrityEquate, IntegrityString ) \ + { \ + DWORD HopefulStringLength = STRLEN(IntegrityString); \ + if (STRNCMP( CurrentValuePtr, (IntegrityString), HopefulStringLength) == 0) { \ + *IntegrityPtr = (IntegrityEquate); \ + CurrentValuePtr = (LPTSTR) (LPVOID) \ + NetpPointerPlusSomeBytes( CurrentValuePtr, \ + HopefulStringLength * sizeof(TCHAR) ); \ + goto DoneIntegrity; \ + } \ + } + + TRY_INTEGRITY( REPL_INTEGRITY_FILE, STRING_FILE ) + + TRY_INTEGRITY( REPL_INTEGRITY_TREE, STRING_TREE ) + + goto ReportBadConfigLine; + +DoneIntegrity: + + // + // Parse the comma after the integrity string. + // + +#define PARSE_CHAR(AsciiChar) \ + { \ + if (*CurrentValuePtr == MAKE_TCHAR(AsciiChar)) { \ + ++CurrentValuePtr; \ + } else { \ + goto ReportBadConfigLine; \ + } \ + } + +#define PARSE_COMMA( ) PARSE_CHAR(',') + + PARSE_COMMA(); + + // + // Now do the extent string. + // + +#define TRY_EXTENT( ExtentEquate, ExtentString ) \ + { \ + DWORD HopefulStringLength = STRLEN(ExtentString); \ + if (STRNCMP( CurrentValuePtr, (ExtentString), HopefulStringLength) == 0) { \ + *ExtentPtr = (ExtentEquate); \ + CurrentValuePtr = (LPTSTR) (LPVOID) \ + NetpPointerPlusSomeBytes( CurrentValuePtr, \ + HopefulStringLength * sizeof(TCHAR) ); \ + goto DoneExtent; \ + } \ + } + + TRY_EXTENT( REPL_EXTENT_FILE, STRING_FILE ) + + TRY_EXTENT( REPL_EXTENT_TREE, STRING_TREE ) + + goto ReportBadConfigLine; + +DoneExtent: + + PARSE_COMMA(); + + // + // Parse the numbers on the rest of the line. + // + +#define PARSE_DWORD( NumberPtr ) \ + { \ + if ( ! ISDIGIT( *CurrentValuePtr ) ) { \ + goto ReportBadConfigLine; \ + } \ + NetpAssert( NumberPtr != NULL ); \ + * NumberPtr = (DWORD) ATOL( CurrentValuePtr ); \ + while ( ISDIGIT( *CurrentValuePtr ) ) { \ + ++CurrentValuePtr; \ + } \ + } + + PARSE_DWORD( LockCountPtr ); + + PARSE_COMMA(); + + PARSE_DWORD( LockTimePtr ); + + IF_DEBUG(EXPAPI) { + NetpKdPrint(( PREFIX_REPL + "ExportDirParseConfigValue: Value = '" FORMAT_LPTSTR "',\n", + ValueString )); + NetpKdPrint(( + " Integrity = " FORMAT_DWORD + ", Extent = " FORMAT_DWORD + ", lock count = " FORMAT_DWORD ".\n", + *IntegrityPtr, *ExtentPtr, *LockCountPtr )); + NetpDbgDisplayTimestamp( "lock time", *LockTimePtr ); + } + + if ( ! ReplIsIntegrityValid( *IntegrityPtr ) ) { + goto ReportBadConfigLine; + } + if ( ! ReplIsExtentValid( *ExtentPtr ) ) { + goto ReportBadConfigLine; + } + + return (NO_ERROR); + +ReportBadConfigLine: + + // BUGBUG: Sure would be nice if we could include dirname here. + + ReplConfigReportBadParmValue( + UncServerName, + (LPTSTR) SECT_NT_REPLICATOR_EXPORTS, + ValueString ); + return (ERROR_INVALID_DATA); + +} // ExportDirParseConfigData + + +// Read config data for a single export directory. Callable whether or not +// the replicator service is started. Returns NERR_UnknownDevDir if no +// config data exists for this directory. +NET_API_STATUS +ExportDirReadConfigData ( + IN LPTSTR UncServerName OPTIONAL, + IN LPTSTR DirName, + OUT LPDWORD IntegrityPtr, + OUT LPDWORD ExtentPtr, + OUT LPDWORD LockCountPtr, + OUT LPDWORD LockTimePtr // Seconds since 1970. + ) +{ + NET_API_STATUS ApiStatus; + LPNET_CONFIG_HANDLE Handle = NULL; + LPTSTR Value = NULL; + + // + // Check for caller's errors. + // + if ( ! ReplIsDirNameValid( DirName ) ) { + ApiStatus = ERROR_INVALID_PARAMETER; + goto Cleanup; // go log error + } + + // + // Open the right section of the config file/whatever. + // + ApiStatus = NetpOpenConfigDataEx( + & Handle, + UncServerName, + (LPTSTR) SECT_NT_REPLICATOR, // section + (LPTSTR) SECT_NT_REPLICATOR_EXPORTS, // area (instead of parameters) + TRUE); // read-only + if (ApiStatus == NERR_CfgCompNotFound) { + ApiStatus = NERR_UnknownDevDir; + goto Cleanup; // go log error + } else if (ApiStatus != NO_ERROR) { + goto Cleanup; // go log error + } + + // + // Read the value from the config file/whatever. + // + ApiStatus = NetpGetConfigValue( + Handle, + DirName, // keyword is dir name + & Value); // alloc and set ptr + if (ApiStatus == NERR_CfgParamNotFound) { + ApiStatus = NERR_UnknownDevDir; + goto Cleanup; // go log error + } else if (ApiStatus != NO_ERROR) { + goto Cleanup; // go log error + } + NetpAssert( Value != NULL ); + + IF_DEBUG(EXPAPI) { + NetpKdPrint(( PREFIX_REPL + "ExportDirReadConfigValue( " FORMAT_LPTSTR " ): '" + FORMAT_LPTSTR "' = '" FORMAT_LPTSTR "'.\n", + (UncServerName!=NULL) ? UncServerName : (LPTSTR) TEXT("local"), + DirName, Value )); + } + + // + // Parse the value string... + // + ApiStatus = ExportDirParseConfigData ( + UncServerName, + Value, + IntegrityPtr, + ExtentPtr, + LockCountPtr, + LockTimePtr); // Seconds since 1970. + // Fall through and log error if any. + +Cleanup: + + // + // All done. + // + if ( Handle != NULL ) { + NET_API_STATUS CloseStatus; + + CloseStatus = NetpCloseConfigData( Handle ); + + // Return this error iff it is first error we've gotten. + if ( (ApiStatus == NO_ERROR) && (CloseStatus != NO_ERROR) ) { + ApiStatus = CloseStatus; + } + } + + (VOID) NetApiBufferFree( Value ); + + if (ApiStatus != NO_ERROR) { + + // Log error on server we were trying to access. + ReplErrorLog( + UncServerName, + NELOG_ReplSysErr, + ApiStatus, + NULL, + NULL ); + } + return (ApiStatus); + +} // ExportDirReadConfigData + + + + + +// Write config data for a single export directory. Callable whether or not +// the replicator service is started. +NET_API_STATUS +ExportDirWriteConfigData ( + IN LPTSTR UncServerName OPTIONAL, + IN LPTSTR DirName, + IN DWORD Integrity, + IN DWORD Extent, + IN DWORD LockCount, + IN DWORD LockTime // Seconds since 1970. + ) +{ + NET_API_STATUS ApiStatus; + LPNET_CONFIG_HANDLE Handle = NULL; + TCHAR ValueArray[EXPORT_VALUE_ARRAY_LEN+1]; + + // + // Check for caller's errors. + // + if ( ! ReplIsDirNameValid( DirName ) ) { + ApiStatus = ERROR_INVALID_PARAMETER; + goto Cleanup; // go log error + } + if ( ! ReplIsIntegrityValid( Integrity ) ) { + ApiStatus = ERROR_INVALID_PARAMETER; + goto Cleanup; // go log error + } + if ( ! ReplIsExtentValid( Extent ) ) { + ApiStatus = ERROR_INVALID_PARAMETER; + goto Cleanup; // go log error + } + + // + // Open the right section of the config file/whatever. + // + ApiStatus = NetpOpenConfigDataEx( + & Handle, + UncServerName, + (LPTSTR) SECT_NT_REPLICATOR, // section + (LPTSTR) SECT_NT_REPLICATOR_EXPORTS, // area (instead of parameters) + FALSE); // not read-only + if (ApiStatus != NO_ERROR) { + goto Cleanup; // go log error + } + + // + // Start building the value, which begins with a string containing the + // integrity. + // + switch (Integrity) { + case REPL_INTEGRITY_FILE: + + (void) STRCPY( ValueArray, STRING_FILE); + break; + + case REPL_INTEGRITY_TREE: + + (void) STRCPY( ValueArray, STRING_TREE); + break; + + default: + NetpAssert( FALSE ); + ApiStatus = ERROR_INVALID_PARAMETER; + goto Cleanup; // go log error + } + + // + // Fields get seperated by commas. + // +/*lint -save -e767 */ // Don't complain about different definitions +#define WRITE_COMMA( ) \ + (void) STRCAT( ValueArray, (LPVOID) TEXT(",") ) +/*lint -restore */ // Resume checking for different macro definitions + + WRITE_COMMA(); + + // + // Next we do the extent. + // + switch (Extent) { + case REPL_EXTENT_FILE: + + (void) STRCAT( ValueArray, STRING_FILE); + break; + + case REPL_EXTENT_TREE: + + (void) STRCAT( ValueArray, STRING_TREE); + break; + + default: + NetpAssert( FALSE ); + ApiStatus = ERROR_INVALID_PARAMETER; + goto Cleanup; // go log error + } + + WRITE_COMMA(); + + // + // Now do the last two fields, with are both DWORDS. + // + +/*lint -save -e767 */ // Don't complain about different definitions +#define WRITE_DWORD( Number ) \ + { \ + LPTSTR StrEnd = & ValueArray[ STRLEN( ValueArray ) ]; \ + (void) ULTOA( (Number), StrEnd, /* radix */ 10 ); \ + } +/*lint -restore */ // Resume checking for different macro definitions + + WRITE_DWORD( LockCount ); + + WRITE_COMMA(); + + WRITE_DWORD( LockTime ); // Seconds since 1970. + + IF_DEBUG(EXPAPI) { + NetpKdPrint(( PREFIX_REPL + "ExportDirWriteConfigValue( " FORMAT_LPTSTR "): '" + FORMAT_LPTSTR "' = '" FORMAT_LPTSTR "'.\n", + (UncServerName!=NULL) ? UncServerName : (LPVOID) TEXT("local"), + DirName, ValueArray )); + } + + // + // Write this value out to the config file/whatever. + // + ApiStatus = NetpSetConfigValue( + Handle, + DirName, // keyword is dir name + ValueArray); + // Faill through and log error if any. + + +Cleanup: + + // + // All done. + // + if ( Handle != NULL ) { + NET_API_STATUS CloseStatus; + + CloseStatus = NetpCloseConfigData( Handle ); + + // Return this error iff it is first error we've gotten. + if ( (ApiStatus == NO_ERROR) && (CloseStatus != NO_ERROR) ) { + ApiStatus = CloseStatus; + } + } + + if (ApiStatus != NO_ERROR) { + + // Log error on server we were trying to access. + ReplErrorLog( + UncServerName, + NELOG_ReplSysErr, + ApiStatus, + NULL, + NULL ); + } + + return (ApiStatus); + +} // ExportDirWriteConfigData diff --git a/private/net/svcdlls/repl/common/expdir.h b/private/net/svcdlls/repl/common/expdir.h new file mode 100644 index 000000000..292b705fb --- /dev/null +++ b/private/net/svcdlls/repl/common/expdir.h @@ -0,0 +1,265 @@ +/*++ + +Copyright (c) 1992-1993 Microsoft Corporation + +Module Name: + + ExpDir.h + +Abstract: + + This file contains structures, function prototypes, and definitions + for the replicator export directory worker routines. + +Author: + + John Rogers (JohnRo) 08-Jan-1992 + +Environment: + + User Mode - Win32 + Portable to any flat, 32-bit environment. (Uses Win32 typedefs.) + Requires ANSI C extensions: slash-slash comments, long external names. + +Notes: + + You must include LmCons.h before this file. + +Revision History: + + 08-Jan-1992 JohnRo + Created. + 09-Jan-1992 JohnRo + Added EXPORT_DIR_SECTION_NAME equate. + Added ExportDir{Read,Write}ConfigData. + 20-Jan-1992 JohnRo + Netr prototypes are now generated by MIDL and put in repl.h. + 23-Jan-1992 JohnRo + Clarify units for time parameters. + Changed EXPORT_DIR_SECTION_NAME. + Changed ExportDirBuildApiRecord's interface. + Added ExportDirIsApiRecordValid(). + Added ExportDirAllocApiRecord(). + 28-Jan-1992 JohnRo + Changed ExportDirAllocApiRecords() to allow arrays. + Added ExportDirConfigDataExists() and ExportDirDeleteConfigData(). + Changed to use LPTSTR etc. + 09-Feb-1992 JohnRo + Added ExportDir{Start,Stop}Repl routines. + 13-Feb-1992 JohnRo + Moved section name equates to ConfName.h. + 15-Mar-1992 JohnRo + Update registry with new values. + Improve support for setinfo info levels. + 23-Mar-1992 JohnRo + Added ExportDirReadMasterList(). + 30-Jul-1992 JohnRo + Help PC-LINT understand ExportDirIsLevelValid(). + 29-Sep-1992 JohnRo + RAID 7962: Repl APIs in wrong role kill svc. + Also fix remote repl admin. + 01-Dec-1992 JohnRo + RAID 3844: remote NetReplSetInfo uses local machine type. + 13-Jan-1993 JohnRo + RAID 7053: locked trees added to pulse msg. (Actually fix all + kinds of remote lock handling.) + 13-Apr-1993 JohnRo + RAID 3107: locking directory over the net gives network path not found. + +--*/ + + +#ifndef _EXPDIR_ +#define _EXPDIR_ + + +#include <netlib.h> // IN_RANGE(). + + +// +// Export dir helper routines and macros: +// + +// Allocate one or more API records for an export directory. Callable whether +// or not the replicator service is started. (Used in getinfo stub, getinfo +// worker, and enum stub.) +NET_API_STATUS +ExportDirAllocApiRecords ( + IN DWORD Level, + IN DWORD EntryCount, + OUT LPBYTE * BufPtr, + IN OUT LPBYTE *StringLocation // Points just past top of data. + ); + +// Build API record for an export directory. Callable whether or not +// the replicator service is started. (Used in getinfo and enum.) +NET_API_STATUS +ExportDirBuildApiRecord ( + IN DWORD Level, + IN LPTSTR DirName, + IN DWORD Integrity, + IN DWORD Extent, + IN DWORD LockCount, + IN DWORD TimeOfFirstLock, // Seconds since 1970. + OUT LPVOID Buffer, + IN OUT LPBYTE *StringLocation // Points just past top of data. + ); + +// Tells whether or not config data for this directory exists. +// Callable even if the replicator service is not started. +BOOL +ExportDirConfigDataExists ( + IN LPTSTR UncServerName OPTIONAL, + IN LPTSTR DirName // Caller must check dir name syntax. + ); + +NET_API_STATUS +ExportDirConfigSetInfo ( + IN LPTSTR UncServerName OPTIONAL, + IN LPTSTR DirName, + IN DWORD Level, + IN LPVOID Buf, + OUT LPDWORD ParmError OPTIONAL + ); + +// Delete config data for this directory. +// Returns NERR_UnknownDevDir if config data doesn't exist for this dir. +// Callable even if the replicator service is not started. +NET_API_STATUS +ExportDirDeleteConfigData ( + IN LPTSTR UncServerName OPTIONAL, + IN LPTSTR DirName // Caller must check dir name syntax. + ); + +// Callable even if the replicator service is not started. +NET_API_STATUS +ExportDirEnumApiRecords( + IN LPTSTR UncServerName OPTIONAL, + IN DWORD Level, + OUT LPBYTE * BufPtr, + IN DWORD PrefMaxSize, + OUT LPDWORD EntriesRead, + OUT LPDWORD TotalEntries + ); + +// Callable even if the replicator service is not started. +NET_API_STATUS +ExportDirFixUserLockFiles( + IN LPCTSTR ExportPath, // Must include drive letter. + IN LPCTSTR DirName, + IN DWORD LockCount + ); + +// Callable even if the replicator service is not started. +NET_API_STATUS +ExportDirGetApiRecord ( + IN LPTSTR UncServerName OPTIONAL, + IN LPTSTR DirName, + IN DWORD Level, + OUT LPBYTE * BufPtr + ); + +BOOL +ExportDirIsApiRecordValid ( + IN DWORD Level, + IN LPVOID ApiRecord, + OUT LPDWORD ParmError OPTIONAL + ); + +// Callable whether or not service is started. +// If service is running, assume caller has lock (any kind) on RMGlobalListLock. +NET_API_STATUS +ExportDirLockInRegistry( + IN LPTSTR UncServerName OPTIONAL, + IN LPTSTR DirName + ); + +// Parse config data for a single export directory. Callable whether or not +// the replicator service is started. (This function is used by routines +// in Repl/Common/ExpConf.c and by the NetReplExportDirEnum routine.) +NET_API_STATUS +ExportDirParseConfigData ( + IN LPTSTR UncServerName OPTIONAL, + IN LPTSTR ValueString, + OUT LPDWORD IntegrityPtr, + OUT LPDWORD ExtentPtr, + OUT LPDWORD LockCountPtr, + OUT LPDWORD LockTimePtr // Seconds since 1970. + ); + +// Read config data for a single export directory. Callable whether or not +// the replicator service is started. +NET_API_STATUS +ExportDirReadConfigData ( + IN LPTSTR UncServerName OPTIONAL, + IN LPTSTR DirName, + OUT LPDWORD IntegrityPtr, + OUT LPDWORD ExtentPtr, + OUT LPDWORD LockCountPtr, + OUT LPDWORD LockTimePtr // Seconds since 1970. + ); + +// Read export dirs into service's master list. +// Only callable locally, when service is started. +// This also fixes the USERLOCK.* file(s) to match the lock count in registry. +NET_API_STATUS +ExportDirReadMasterList( + VOID + ); + +// Read specified export dir into service's master list. +NET_API_STATUS +ExportDirGetRegistryValues( + IN LPTSTR ServiceRegPath OPTIONAL, + IN LPTSTR TargetName + ); + +// Start replicating (exporting). +// Called when service starts or user does NetReplSetInfo() and changes role. +NET_API_STATUS +ExportDirStartRepl ( + IN BOOL ServiceIsStarting + ); + +// Stop replicating (exporting). +// Called when service stops or user does NetReplSetInfo() and changes role. +NET_API_STATUS +ExportDirStopRepl ( + VOID + ); + +// Callable whether or not service is started. +// If service is running, assume caller has lock (any kind) on RMGlobalListLock. +NET_API_STATUS +ExportDirUnlockInRegistry( + IN LPTSTR UncServerName OPTIONAL, + IN LPTSTR DirName, + IN DWORD UnlockForce + ); + +// Write config data for a single export directory. Callable whether or not +// the replicator service is started. +NET_API_STATUS +ExportDirWriteConfigData ( + IN LPTSTR UncServerName OPTIONAL, + IN LPTSTR DirName, + IN DWORD Integrity, + IN DWORD Extent, + IN DWORD LockCount, + IN DWORD LockTime // Seconds since 1970. + ); + +// BOOL +// ExportDirIsLevelValid( +// IN DWORD Level, // Info level +// IN BOOL SetInfo // Are setinfo levels allowed? +// ); +// +#define ExportDirIsLevelValid(Level,SetInfo) \ + /*lint -e506 */ /* don't complain about constant values here */ \ + ( ( (Level) <= 2 ) \ + || ( (SetInfo) && (IN_RANGE((Level), 1000, 1001)) ) ) \ + /*lint +e506 */ \ + + +#endif // _EXPDIR_ diff --git a/private/net/svcdlls/repl/common/expenum.c b/private/net/svcdlls/repl/common/expenum.c new file mode 100644 index 000000000..ffef39aa8 --- /dev/null +++ b/private/net/svcdlls/repl/common/expenum.c @@ -0,0 +1,298 @@ +/*++ + +Copyright (c) 1991-1993 Microsoft Corporation + +Module Name: + + ExpEnum.c + +Abstract: + + ExportDirEnumApiRecords(). + +Author: + + John Rogers (JohnRo) 29-Sep-1992 + +Environment: + + User Mode - Win32 + +Revision History: + + 29-Sep-1992 JohnRo + RAID 7962: Repl APIs in wrong role kill svc. (Extracted this code from + NetExportDirEnum's DLL stub.) + 01-Dec-1992 JohnRo + RAID 3844: remote NetReplSetInfo uses local machine type. + 10-Mar-1993 JohnRo + RAID 12871: replication UI shows nothing (adding entry while enumerating + results in empty list). + Made changes suggested by PC-LINT 5.0 + +--*/ + + +// These must be included first: + + +#include <windows.h> +#include <lmcons.h> // NET_API_STATUS, etc. +#include <netdebug.h> // NetpAssert(). + +// These may be included in any order: + +#include <config.h> // LPNET_CONFIG_HANDLE, Netp config routines. +#include <confname.h> // SECT_NT_ equates. +#include <dirname.h> // ReplIsDirNameValid(). +#include <expdir.h> // ExportDirIsApiRecordValid(), my prototype, etc. +#include <lmerr.h> // NERR_ and ERROR_ equates, NO_ERROR. +#include <lmerrlog.h> // NELOG_ equates. +#include <netlib.h> // NetpSetParmError(), etc. +#include <prefix.h> // PREFIX_ equates. +#include <repldefs.h> // IF_DEBUG(), ReplErrorLog(), etc. +#include <strucinf.h> // NetpReplExportDirStructureInfo(). + + +// Callable even if the replicator service is not started. +NET_API_STATUS +ExportDirEnumApiRecords( + IN LPTSTR UncServerName OPTIONAL, + IN DWORD Level, + OUT LPBYTE * BufPtr, + IN DWORD PrefMaxSize, + OUT LPDWORD EntriesRead, + OUT LPDWORD TotalEntries + ) +{ + NET_API_STATUS ApiStatus; + LPVOID ArrayEntry; + LPVOID ArrayStart = NULL; + DWORD EntriesAllocated = 0; + DWORD EntriesFound = 0; + BOOL FirstTime; + DWORD FixedEntrySize; + LPNET_CONFIG_HANDLE Handle = NULL; + LPBYTE StringLocation; + + UNREFERENCED_PARAMETER( PrefMaxSize ); + + if ( !ExportDirIsLevelValid( Level, FALSE ) ) { + ApiStatus = ERROR_INVALID_LEVEL; + goto Cleanup; + } else if (BufPtr == NULL) { + ApiStatus = ERROR_INVALID_PARAMETER; + goto Cleanup; + } else if (EntriesRead == NULL) { + ApiStatus = ERROR_INVALID_PARAMETER; + goto Cleanup; + } else if (TotalEntries == NULL) { + ApiStatus = ERROR_INVALID_PARAMETER; + goto Cleanup; + } + + // + // Set outputs in case we run into an error. + // + + * BufPtr = NULL; + * EntriesRead = 0; + * TotalEntries = 0; + + // + // Figure-out the size of a fixed entry for this info level. + // + ApiStatus = NetpReplExportDirStructureInfo ( + Level, + PARMNUM_ALL, + TRUE, // want native sizes + NULL, // don't need data desc 16 + NULL, // don't need data desc 32 + NULL, // don't need data desc SMB + NULL, // don't need max size + & FixedEntrySize, + NULL ); // don't need string size + + NetpAssert( ApiStatus == NO_ERROR ); // Already checked args. + NetpAssert( FixedEntrySize > 0 ); + + // + // Open the right section of the config file/whatever. + // + ApiStatus = NetpOpenConfigDataEx( + & Handle, + UncServerName, + (LPTSTR) SECT_NT_REPLICATOR, // service name + (LPTSTR) SECT_NT_REPLICATOR_EXPORTS, // area under service + TRUE); // read-only + if (ApiStatus != NO_ERROR) { + + // Handle section not found as empty enum array (not error). + if (ApiStatus == NERR_CfgCompNotFound) { + ApiStatus = NO_ERROR; + goto Cleanup; + } + + goto Cleanup; + } + + // + // Loop, expanding buffer if necessary, until we get it large enough. + // + + do { + + // + // Count entries in config data. + // + ApiStatus = NetpNumberOfConfigKeywords ( + Handle, + & EntriesAllocated ); + + if (ApiStatus != NO_ERROR) { + goto Cleanup; + } else if (EntriesAllocated == 0) { + goto Cleanup; + } + + // + // Alloc the array... + // + ApiStatus = ExportDirAllocApiRecords ( + Level, + EntriesAllocated, + (LPBYTE *) & ArrayStart, + & StringLocation ); // Points just past top of data. + if (ApiStatus == NO_ERROR) { + NetpAssert( ArrayStart != NULL ); + } else { + goto Cleanup; + } + + // + // Go back and reread, filling-in the config data as we go. + // + + ArrayEntry = ArrayStart; + FirstTime = TRUE; + + while (ApiStatus == NO_ERROR) { + LPTSTR DirName; + DWORD Integrity, Extent, LockCount, LockTime; + LPTSTR ValueString; + + ApiStatus = NetpEnumConfigSectionValues ( + Handle, + & DirName, // Keyword - alloc and set ptr. + & ValueString, // Must be freed by NetApiBufferFree(). + FirstTime ); + + FirstTime = FALSE; + + if (ApiStatus == NO_ERROR) { + NetpAssert( DirName != NULL ); + NetpAssert( ValueString != NULL ); + + ++EntriesFound; + if (EntriesFound > EntriesAllocated) { + EntriesFound = 0; + NetpMemoryFree( ArrayStart ); + ArrayStart = NULL; + ApiStatus = ERROR_MORE_DATA; + break; // exit per-entry loop and try again + } + + if ( !ReplIsDirNameValid( DirName ) ) { + // BUGBUG: perhaps delete entry, log event, and continue? + ApiStatus = ERROR_INVALID_DATA; + NetpMemoryFree( DirName ); + NetpMemoryFree( ValueString ); + goto Cleanup; + } + + // + // Parse the value string... + // + ApiStatus = ExportDirParseConfigData ( + UncServerName, + ValueString, + & Integrity, + & Extent, + & LockCount, + & LockTime); // Seconds since 1970. + + NetpMemoryFree( ValueString ); + + if (ApiStatus == NO_ERROR) { + // + // Build API record for this entry. + // + ApiStatus = ExportDirBuildApiRecord ( + Level, + DirName, + Integrity, + Extent, + LockCount, + LockTime, // Seconds since 1970. + ArrayEntry, + & StringLocation ); + if (ApiStatus != NO_ERROR) { + NetpKdPrint(( PREFIX_REPL + "ExportDirEnumApiRecords: error " + FORMAT_API_STATUS " from exp build.\n", + ApiStatus )); + NetpAssert( FALSE ); + goto Cleanup; + } + + ArrayEntry = NetpPointerPlusSomeBytes( + ArrayEntry, FixedEntrySize ); + } + NetpMemoryFree( DirName ); + + } + + } // while not error (may be NERR_CfgParamNotFound at end). + + if (ApiStatus == NERR_CfgParamNotFound) { + ApiStatus = NO_ERROR; + } else { + NetpAssert( ApiStatus != NO_ERROR ); + goto Cleanup; + } + + } while (ApiStatus == ERROR_MORE_DATA); + + // + // All done. + // + +Cleanup: + + if (Handle != NULL) { + (VOID) NetpCloseConfigData( Handle ); + } + + NetpAssert( ApiStatus != ERROR_MORE_DATA ); + if (ApiStatus == NO_ERROR) { + * BufPtr = ArrayStart; + * EntriesRead = EntriesFound; + * TotalEntries = EntriesFound; + } else { + NetpKdPrint(( PREFIX_REPL + "ExportDirEnumApiRecords: returning status " FORMAT_API_STATUS + ".\n", ApiStatus )); + + // Log the error. + ReplErrorLog( + UncServerName, // log here and there. + NELOG_ReplSysErr, + ApiStatus, + NULL, // no str1 + NULL ); // no str2 + + } + + return ApiStatus; + +} diff --git a/private/net/svcdlls/repl/common/expget.c b/private/net/svcdlls/repl/common/expget.c new file mode 100644 index 000000000..c6a4bbaf9 --- /dev/null +++ b/private/net/svcdlls/repl/common/expget.c @@ -0,0 +1,110 @@ +/*++ + +Copyright (c) 1991-1993 Microsoft Corporation + +Module Name: + + ExpGet.c + +Abstract: + + ExportDirGetApiRecord(). + +Author: + + John Rogers (JohnRo) 13-Nov-1992 + +Environment: + + User Mode - Win32 + +Revision History: + + 13-Nov-1992 JohnRo + RAID 1537: Repl APIs in wrong role kill svc. (Extracted from DLL + stubs.) + 04-Jan-1993 JohnRo + Made changes suggested by PC-LINT 5.0 + +--*/ + + +// These must be included first: + +#include <windows.h> +#include <lmcons.h> // NET_API_STATUS, etc. + +// These may be included in any order: + +#include <dirname.h> // ReplIsDirNameValid(). +#include <expdir.h> // My prototype, ExportDirIsApiRecordValid(), etc. +#include <netdebug.h> // NetpAssert(). + + +// Callable even if the replicator service is not started. +NET_API_STATUS +ExportDirGetApiRecord ( + IN LPTSTR UncServerName OPTIONAL, + IN LPTSTR DirName, + IN DWORD Level, + OUT LPBYTE * BufPtr + ) +{ + NET_API_STATUS ApiStatus; + + LPVOID ApiRecord = NULL; + DWORD Integrity, Extent, LockCount; + DWORD TimeOfFirstLock; // Seconds since 1970. + LPBYTE StringLocation; // Points just past top of data. + + ApiStatus = NO_ERROR; // Innocent until proven guilty. + + if (! ReplIsDirNameValid(DirName)) { + ApiStatus = ERROR_INVALID_PARAMETER; + } else if ( !ExportDirIsLevelValid( Level, FALSE ) ) { + ApiStatus = ERROR_INVALID_LEVEL; + } else if (BufPtr == NULL) { + ApiStatus = ERROR_INVALID_PARAMETER; + } + + if (ApiStatus == NO_ERROR) { + // Read config data for a single export directory. + ApiStatus = ExportDirReadConfigData ( + UncServerName, + DirName, + & Integrity, + & Extent, + & LockCount, + & TimeOfFirstLock ); // Seconds since 1970. + } + if (ApiStatus == NO_ERROR) { + + ApiStatus = ExportDirAllocApiRecords ( + Level, + 1, // only 1 record. + (LPBYTE *) & ApiRecord, // alloc and set ptr + (LPBYTE *) & StringLocation ); // Points just past top of data. + if (ApiStatus == NO_ERROR) { + NetpAssert( ApiRecord != NULL ); + ApiStatus = ExportDirBuildApiRecord ( + Level, + DirName, + Integrity, + Extent, + LockCount, + TimeOfFirstLock, // Seconds since 1970. + ApiRecord, + (LPBYTE *) (LPVOID) & StringLocation); + NetpAssert( ApiStatus == NO_ERROR ); // We checked all parms. + } + + } + + if (ApiStatus == NO_ERROR) { + NetpAssert( ApiRecord != NULL ); + NetpAssert( ExportDirIsApiRecordValid( Level, ApiRecord, NULL ) ); + } + *BufPtr = ApiRecord; // will be NULL on error. + + return ApiStatus; +} diff --git a/private/net/svcdlls/repl/common/explock.c b/private/net/svcdlls/repl/common/explock.c new file mode 100644 index 000000000..e1abace61 --- /dev/null +++ b/private/net/svcdlls/repl/common/explock.c @@ -0,0 +1,162 @@ +/*++ + +Copyright (c) 1992-1993 Microsoft Corporation + +Module Name: + + ExpLock.c + +Abstract: + + Common registry lock/unlock routines for export dirs. + +Author: + + John Rogers (JohnRo) 15-Mar-1992 + +Environment: + + User Mode - Win32 + +Notes: + + This file is extremely similar to ImpLock.c. If you fix any bugs here, + make sure they're reflected there, and vice versa. + +Revision History: + + 15-Mar-1992 JohnRo + Created these routines. + 23-Jul-1992 JohnRo + RAID 2274: repl svc should impersonate caller. + 29-Sep-1992 JohnRo + Also fix remote repl admin. + 13-Apr-1993 JohnRo + RAID 3107: locking directory over the net gives network path not found. + Made changes suggested by PC-LINT 5.0 + 30-Apr-1993 JohnRo + Use NetpKdPrint() where possible. + +--*/ + + +// These must be included first: + +#include <windef.h> +#include <lmcons.h> // NET_API_STATUS, etc. + +// These may be included in any order: + +#include <dirname.h> // ReplIsDirNameValid(). +#include <expdir.h> // My prototypes, etc. +#include <lmrepl.h> // REPL_UNLOCK_FORCE equates. +#include <netdebug.h> // NetpKdPrint(), etc. +#include <repldefs.h> // IF_DEBUG(). +#include <winerror.h> // NO_ERROR, ERROR_ equates. + + +// Callable whether or not service is started. +// If service is running, assume caller has lock (any kind) on RMGlobalListLock. +NET_API_STATUS +ExportDirLockInRegistry( + IN LPTSTR UncServerName OPTIONAL, + IN LPTSTR DirName + ) +{ + NET_API_STATUS ApiStatus; + DWORD Integrity, Extent, LockCount; + DWORD TimeOfFirstLock; // Seconds since 1970. + + IF_DEBUG(REPL) { + NetpKdPrint(( "ExportDirLockInRegistry( " FORMAT_LPTSTR + "): beginning...\n", + (UncServerName!=NULL) ? UncServerName : (LPTSTR) TEXT("local") )); + } + + if ( !ReplIsDirNameValid(DirName)) { + return (ERROR_INVALID_PARAMETER); + } + + // Read config data for a single export directory. + ApiStatus = ExportDirReadConfigData ( + UncServerName, + DirName, + & Integrity, + & Extent, + & LockCount, + & TimeOfFirstLock ); // Seconds since 1970. + if (ApiStatus == NO_ERROR) { + + ApiStatus = ReplIncrLockFields( + & LockCount, + & TimeOfFirstLock ); + } + if (ApiStatus == NO_ERROR) { + ApiStatus = ExportDirWriteConfigData ( + UncServerName, + DirName, + Integrity, + Extent, + LockCount, + TimeOfFirstLock ); // Seconds since 1970. + } + + return (ApiStatus); + +} // ExportDirLockInRegistry + + +// Callable whether or not service is started. +// If service is running, assume caller has lock (any kind) on RMGlobalListLock. +NET_API_STATUS +ExportDirUnlockInRegistry( + IN LPTSTR UncServerName OPTIONAL, + IN LPTSTR DirName, + IN DWORD UnlockForce + ) +{ + NET_API_STATUS ApiStatus; + DWORD Integrity, Extent, LockCount; + DWORD TimeOfFirstLock; // Seconds since 1970. + + IF_DEBUG(REPL) { + NetpKdPrint(( "ExportDirUnlockInRegistry( " FORMAT_LPTSTR + "): beginning...\n", + (UncServerName!=NULL) ? UncServerName : (LPTSTR) TEXT("local") )); + } + + if ( !ReplIsDirNameValid(DirName)) { + return (ERROR_INVALID_PARAMETER); + } else if ( !ReplIsForceLevelValid( UnlockForce ) ) { + return (ERROR_INVALID_PARAMETER); + } + + // Read config data for a single export directory. + ApiStatus = ExportDirReadConfigData ( + UncServerName, + DirName, + & Integrity, + & Extent, + & LockCount, + & TimeOfFirstLock ); // Seconds since 1970. + + if (ApiStatus == NO_ERROR) { + + ApiStatus = ReplDecrLockFields( + & LockCount, + & TimeOfFirstLock, + UnlockForce ); + } + if (ApiStatus == NO_ERROR) { + ApiStatus = ExportDirWriteConfigData ( + UncServerName, + DirName, + Integrity, + Extent, + LockCount, + TimeOfFirstLock ); // Seconds since 1970. + } + + return (ApiStatus); + +} // ExportDirUnlockInRegistry diff --git a/private/net/svcdlls/repl/common/expset.c b/private/net/svcdlls/repl/common/expset.c new file mode 100644 index 000000000..9744f9c2c --- /dev/null +++ b/private/net/svcdlls/repl/common/expset.c @@ -0,0 +1,195 @@ +/*++ + +Copyright (c) 1991-1993 Microsoft Corporation + +Module Name: + + ExpSet.c + +Abstract: + + ExportDirSetInfo(). + +Author: + + John Rogers (JohnRo) 29-Sep-1992 + +Environment: + + User Mode - Win32 + +Revision History: + + 29-Sep-1992 JohnRo + RAID 7962: Repl APIs in wrong role kill svc. (Extracted code from DLL + stubs.) + 30-Dec-1992 JohnRo + Corrected debug bit usage. + 30-Apr-1993 JohnRo + Use NetpKdPrint() where possible. + +--*/ + + +// These must be included first: + +#include <windows.h> +#include <lmcons.h> // NET_API_STATUS, etc. +#include <repldefs.h> // IF_DEBUG(). + +// These may be included in any order: + +#include <dirname.h> // ReplIsDirNameValid(). +#include <expdir.h> // My prototype, ExportDirIsApiRecordValid(), etc. +#include <lmrepl.h> // LPREPL_EDIR_INFO_1, etc. +#include <netdebug.h> // NetpKdPrint(), etc. +#include <prefix.h> // PREFIX_ equates. + + +NET_API_STATUS +ExportDirConfigSetInfo ( + IN LPTSTR UncServerName OPTIONAL, + IN LPTSTR DirName, + IN DWORD Level, + IN LPVOID Buffer, + OUT LPDWORD ParmError OPTIONAL + ) +{ + NET_API_STATUS ApiStatus; + + DWORD Integrity, Extent, LockCount; + DWORD TimeOfFirstLock; // Seconds since 1970. + + ApiStatus = NO_ERROR; // Innocent until proven guilty. + + NetpSetParmError( PARM_ERROR_UNKNOWN ); // Assume error until proven... + if (! ReplIsDirNameValid(DirName)) { + ApiStatus = ERROR_INVALID_PARAMETER; + + IF_DEBUG( EXPAPI ) { + NetpKdPrint(( PREFIX_REPL + "NetReplExportDirSetInfo: Invalid dir name parm.\n" )); + } + } + if (Buffer == NULL) { + + IF_DEBUG( EXPAPI ) { + NetpKdPrint(( PREFIX_REPL + "NetReplExportDirSetInfo: null buffer pointer.\n" )); + } + + return (ERROR_INVALID_PARAMETER); + } + + // BUGBUG: ParmError is not set in many paths through here! + + if (ApiStatus == NO_ERROR) { + + // Read config data for a single export directory. + // We have to do this 'cos the set info struct (level 1) is + // a subset of the info we need to do a write. + ApiStatus = ExportDirReadConfigData ( + UncServerName, + DirName, + & Integrity, + & Extent, + & LockCount, + & TimeOfFirstLock ); // Seconds since 1970. + } + + if (ApiStatus == NO_ERROR) { + + if (Level == 1) { + LPREPL_EDIR_INFO_1 ApiRecord = Buffer; + + if ( !ExportDirIsApiRecordValid( + Level, ApiRecord, ParmError ) ) { + + IF_DEBUG( EXPAPI ) { + NetpKdPrint(( PREFIX_REPL + "NetReplExportDirSetInfo: Invalid level 1 record, " + "ParmError is " FORMAT_DWORD "\n", + (ParmError!=NULL) + ? (*ParmError) + : PARM_ERROR_UNKNOWN )); + } + + ApiStatus = ERROR_INVALID_PARAMETER; + + } else { + + // BUGBUG: Match DirName and ApiRecord->rped1_dirname. + + // Write config data for this export directory. + ApiStatus = ExportDirWriteConfigData ( + UncServerName, + DirName, // new dir name (same) + ApiRecord->rped1_integrity, // new integrity + ApiRecord->rped1_extent, // new extent + LockCount, // old lock count + TimeOfFirstLock ); // old lock time + } + + } else if ( (Level==1000) || (Level==1001) ) { + + if (ApiStatus == NO_ERROR) { + if (Level==1000) { + LPREPL_EDIR_INFO_1000 ApiRecord = Buffer; + Integrity = ApiRecord->rped1000_integrity; + + if ( !ReplIsIntegrityValid( Integrity ) ) { + NetpSetParmError( 1 ); // error in first field. + ApiStatus = ERROR_INVALID_PARAMETER; + + IF_DEBUG( EXPAPI ) { + NetpKdPrint(( PREFIX_REPL + "NetReplExportDirSetInfo: " + "Bad integrity value.\n" )); + } + + } else { + // Write the revised value below. + + NetpSetParmError( PARM_ERROR_NONE ); + } + } else { + LPREPL_EDIR_INFO_1001 ApiRecord = Buffer; + NetpAssert( Level == 1001 ); + Extent = ApiRecord->rped1001_extent; + + if ( !ReplIsExtentValid( Extent ) ) { + NetpSetParmError( 1 ); // error in first field. + ApiStatus = ERROR_INVALID_PARAMETER; + + IF_DEBUG( EXPAPI ) { + NetpKdPrint(( PREFIX_REPL + "NetReplExportDirSetInfo: " + "Bad extent value.\n" )); + } + + } else { + // Write the revised value below. + NetpSetParmError( PARM_ERROR_NONE ); + ApiStatus = NO_ERROR; + } + } + + if (ApiStatus == NO_ERROR) { + // Write config data for this export directory. + ApiStatus = ExportDirWriteConfigData ( + UncServerName, + DirName, + Integrity, + Extent, + LockCount, + TimeOfFirstLock ); + NetpSetParmError( PARM_ERROR_NONE ); + } + } + } else { + ApiStatus = ERROR_INVALID_LEVEL; + } + } + + return ApiStatus; +} diff --git a/private/net/svcdlls/repl/common/expvalid.c b/private/net/svcdlls/repl/common/expvalid.c new file mode 100644 index 000000000..0fe5c5bf4 --- /dev/null +++ b/private/net/svcdlls/repl/common/expvalid.c @@ -0,0 +1,177 @@ +/*++ + +Copyright (c) 1992-1993 Microsoft Corporation + +Module Name: + + ExpValid.c + +Abstract: + + This file contains ExportDirIsApiRecordValid(). + +Author: + + John Rogers (JohnRo) 22-Jan-1992 + +Environment: + + Runs under Windows NT. + Requires ANSI C extensions: slash-slash comments, long external names. + +Notes: + + This code assumes that the info levels are subsets of each other. + +Revision History: + + 22-Jan-1992 JohnRo + Created ExportDirIsApiRecordValid() from code in NetrReplExportDirAdd(). + 28-Jan-1992 JohnRo + Oops, this code accidently said level 1 was invalid. + 30-Jan-1992 JohnRo + Made changes suggested by PC-LINT. + 18-Feb-1992 JohnRo + Handle level 2 as well. + 27-Feb-1992 JohnRo + Really allow level 2. + Check lock fields for validity. + 15-Mar-1992 JohnRo + Improve setinfo info level support. + 23-Mar-1993 JohnRo + Added debug output. + +--*/ + + +// These must be included first: + +#include <windef.h> // IN, VOID, LPTSTR, etc. +#include <lmcons.h> // NET_API_STATUS, PARM equates, etc. +#include <repldefs.h> // ReplIsIntegrityValid(), etc. + +// These can be in any order: + +#include <dirname.h> // ReplIsDirNameValid(). +#include <expdir.h> // My prototype. +#include <lmrepl.h> // LPREPL_EDIR_INFO_1, REPL_EXTENT_ stuff, etc. +#include <netdebug.h> // NetpAssert(), NetpKdPrint(). +#include <netlib.h> // NetpSetParmError(). +#include <prefix.h> // PREFIX_ equates. + +#define INDICATE_ERROR( text ) \ + { \ + NetpKdPrint(( PREFIX_REPL \ + "ExportDirIsApiRecordValid: " text ".\n" )); \ + /* NetpDbgHexDump( Buf, REASONABLE_DUMP_SIZE ); */ \ + } + + +BOOL +ExportDirIsApiRecordValid ( + IN DWORD Level, + IN LPVOID Buf, + OUT LPDWORD ParmError OPTIONAL + ) + +{ + + // + // First, make sure level is valid and there's actually a struct there. + // + NetpSetParmError( PARM_ERROR_UNKNOWN ); // Assume error until proven... + if ( !ExportDirIsLevelValid( Level, TRUE) ) { + + NetpKdPrint(( PREFIX_REPL + "ExportDirIsApiRecordValid: bad info level.\n" )); + + return (FALSE); // No, it's not valid. + } + if (Buf == NULL) { + + NetpKdPrint(( PREFIX_REPL + "ExportDirIsApiRecordValid: null buf ptr.\n" )); + + return (FALSE); // No, it's not valid. + } + + if (Level < PARMNUM_BASE_INFOLEVEL) { + LPREPL_EDIR_INFO_2 ApiRecord; // Superset info level. + ApiRecord = Buf; + + // + // Check item(s) common to all levels. + // + if ( !ReplIsDirNameValid(ApiRecord->rped2_dirname) ) { + NetpSetParmError( 1 ); // Error in first field in ApiRecord. + + INDICATE_ERROR( + "ExportDirIsApiRecordValid: bad dir name.\n" ); + + return (FALSE); // No, it's not valid. + } + + // + // Check items unique to level 1 and 2. + // + if (Level > 0) { + if ( !ReplIsIntegrityValid(ApiRecord->rped2_integrity) ) { + NetpSetParmError( 2 ); // Error in second field in ApiRecord. + + INDICATE_ERROR( "bad integrity (struct)" ); + + return (FALSE); // No, it's not valid. + } + if ( !ReplIsExtentValid(ApiRecord->rped2_extent) ) { + NetpSetParmError( 3 ); // Error in third field in ApiRecord. + + INDICATE_ERROR( "bad extent (struct)" ); + + return (FALSE); // No, it's not valid. + } + + if (Level >= 2) { + if ( !ReplAreLockFieldsValid( ApiRecord->rped2_lockcount, + ApiRecord->rped2_locktime ) ) { + NetpSetParmError( 4 ); // Err in fourth and/or fifth field. + + INDICATE_ERROR( "bad lock fields" ); + + return (FALSE); // No, it's not valid. + } + } + } + + } else if (Level == REPL_EXPORT_INTEGRITY_INFOLEVEL) { + + DWORD NewIntegrity = * (LPDWORD) (LPVOID) Buf; + + if ( !ReplIsIntegrityValid( NewIntegrity ) ) { + NetpSetParmError( 1 ); // Error in first field in ApiRecord. + + INDICATE_ERROR( "bad integrity (field)" ); + + return (FALSE); // No, it's not valid. + } + + } else { + + DWORD NewExtent = * (LPDWORD) (LPVOID) Buf; + NetpAssert( Level == REPL_EXPORT_EXTENT_INFOLEVEL ); + if ( !ReplIsExtentValid( NewExtent ) ) { + NetpSetParmError( 1 ); // Error in first field in ApiRecord. + + INDICATE_ERROR( "bad extent (field)" ); + + return (FALSE); // No, it's not valid. + } + + } + + // + // Everything went OK. Tell caller. + // + NetpSetParmError( PARM_ERROR_NONE ); + return (TRUE); // Yes, it's valid. + +} diff --git a/private/net/svcdlls/repl/common/fixlocks.c b/private/net/svcdlls/repl/common/fixlocks.c new file mode 100644 index 000000000..6cb44c389 --- /dev/null +++ b/private/net/svcdlls/repl/common/fixlocks.c @@ -0,0 +1,194 @@ +/*++ + +Copyright (c) 1993 Microsoft Corporation + +Module Name: + + FixLocks.c + +Abstract: + + This routine (ExportDirFixUserLockFiles) makes sure that the local + disk's UserLock.* file(s) are in agreement with the lock count from + the registry. The file(s) are deleted and/or created as necessary. + + This is callable even if the replicator service is not started. + + +Author: + + JR (John Rogers, JohnRo@Microsoft) 14-Jan-1993 + +Environment: + + User Mode - Win32 + Portable to any flat, 32-bit environment. (Uses Win32 typedefs.) + Requires ANSI C extensions: slash-slash comments, long external names. + +Revision History: + + 14-Jan-1993 JohnRo + Created for RAID 7053: locked trees added to pulse msg. (Actually + fix all kinds of remote lock handling.) + 26-Apr-1993 JohnRo + RAID 7313: repl needs change permission to work on NTFS, or we need + to delete files differently. + +--*/ + + +// These must be included first: + +#include <windows.h> // IN, GetLastError(), LPCTSTR, OPTIONAL, etc. +#include <lmcons.h> // NET_API_STATUS. + +// These may be included in any order: + + +#include <dirname.h> // ReplIsDirNameValid(). +#include <expdir.h> // My prototype. +#include <lmerrlog.h> // NELOG_ equates. +#include <netdebug.h> // NetpAssert(), NetpKdPrint(), FORMAT_ equates, etc. +#include <prefix.h> // PREFIX_ equates. +#include <repldefs.h> // SLASH, ReplCheckAbsPathSyntax(), etc. +#include <tstr.h> // STRCAT(), STRCPY(), STRLEN(). +#include <winerror.h> // ERROR_, NO_ERROR equates. + + +NET_API_STATUS +ExportDirFixUserLockFiles( + IN LPCTSTR ExportPath, // Must include drive letter. + IN LPCTSTR DirName, + IN DWORD LockCount + ) +{ + NET_API_STATUS ApiStatus; + HANDLE FileHandle = NULL; + TCHAR LockFileName[MAX_PATH+1]; + BOOL NtUserLockExists; + + // + // Check for caller errors. + // + if ( !ReplIsDirNameValid( (LPTSTR) DirName ) ) { + ApiStatus = ERROR_INVALID_PARAMETER; + goto Cleanup; + } + ApiStatus = ReplCheckAbsPathSyntax( (LPTSTR) ExportPath ); + if (ApiStatus != NO_ERROR) { + goto Cleanup; + } + + // + // Build NT version of lock file name. + // + (VOID) STRCPY( LockFileName, ExportPath ); + (VOID) STRCAT( LockFileName, SLASH ); + (VOID) STRCAT( LockFileName, DirName ); + (VOID) STRCAT( LockFileName, SLASH ); + (VOID) STRCAT( LockFileName, USERLOCK_NT ); + + NetpAssert( STRLEN( LockFileName ) <= MAX_PATH ); + + // + // See if the NT version of the user lock file exists. + // + NtUserLockExists = ReplFileOrDirExists( LockFileName ); + + if ( NtUserLockExists && (LockCount==0) ) { + + // + // Delete extraneous NT lock file. + // + NetpKdPrint(( PREFIX_REPL + "ExportDirFixUserLockFiles: " + "deleting extraneous user lock file '" FORMAT_LPTSTR "'...\n", + LockFileName )); + ApiStatus = ReplDeleteFile( LockFileName ); + if (ApiStatus != NO_ERROR) { + goto Cleanup; + } + + } else if ( (!NtUserLockExists) && (LockCount>0) ) { + + // + // Create a lock file if we can. (The directory might not exist yet, + // so we might not be able to do this. No problem.) + // + FileHandle = CreateFile( + (LPCTSTR) LockFileName, // name of file to create. + GENERIC_WRITE, // desired access. + FILE_SHARE_WRITE, // share mode: we don't care. + NULL, // default security attr. + CREATE_ALWAYS, // create disposition. + FILE_FLAG_WRITE_THROUGH, // flags&attr: don't cache writes. + NULL ); // no template file. + if (FileHandle == INVALID_HANDLE_VALUE) { + ApiStatus = (NET_API_STATUS) GetLastError(); + NetpAssert( ApiStatus != NO_ERROR ); + + if (ApiStatus == ERROR_PATH_NOT_FOUND) { + // First-level dir doesn't exist yet. That's OK, as pulser + // will correct for this when it gets created. + ApiStatus = NO_ERROR; + } else if (ApiStatus == ERROR_WRITE_PROTECT) { + // Perhaps just CD-ROM? OK, as registry lock count is correct, + // and ReplCheckExportLocks() checks registry before file + // system. + + ReplErrorLog( + NULL, // no server name (log locally) + NELOG_ReplAccessDenied, // log code + ApiStatus, + NULL, // optional str1 + NULL); // optional str2 + + // Don't prevent repl from exporting CD-ROM. + ApiStatus = NO_ERROR; + } else if (ApiStatus == ERROR_ACCESS_DENIED) { + + // Log in case service is running in wrong account, or + // an ACL is wrong somewhere. + ReplErrorLog( + NULL, // no server name (log locally) + NELOG_ReplAccessDenied, // log code + ApiStatus, + NULL, // optional str1 + NULL); // optional str2 + + // Don't prevent repl from exporting CD-ROM. + ApiStatus = NO_ERROR; + } + goto Cleanup; // go log error. + } + // Fall through to close the file in cleanup code. + } + + ApiStatus = NO_ERROR; + +Cleanup: + + if (FileHandle != NULL) { + (VOID) CloseHandle( FileHandle ); + } + + if (ApiStatus != NO_ERROR) { + + NetpKdPrint(( PREFIX_REPL + "ExportDirFixUserLockFiles: ERROR " FORMAT_API_STATUS ".\n", + ApiStatus )); + + // + // Log the error. + // BUGBUG: extract master server name and log there too. + // + ReplErrorLog( + NULL, // no server name (log locally) + NELOG_ReplSysErr, // log code + ApiStatus, + NULL, // optional str1 + NULL); // optional str2 + } + return (ApiStatus); + +} diff --git a/private/net/svcdlls/repl/common/fsresolu.c b/private/net/svcdlls/repl/common/fsresolu.c new file mode 100644 index 000000000..092bf946f --- /dev/null +++ b/private/net/svcdlls/repl/common/fsresolu.c @@ -0,0 +1,220 @@ +/*++ + +Copyright (c) 1992-1993 Microsoft Corporation + +Module Name: + + FsResolu.c + +Abstract: + + Module only contains ReplGetFsTimeResolutionSecs(). + +Author: + + JR (John Rogers, JohnRo@Microsoft) + +Environment: + + User mode only. + Contains NT-specific code. + Requires ANSI C extensions: slash-slash comments, long external names. + +Revision History: + + 17-Dec-1992 JohnRo + Created for RAID 1513: Repl does not maintain ACLs. (Also fix + HPFS->FAT timestamp.) + 26-Feb-1993 JohnRo + RAID 13126: Fix repl memory leak. + +--*/ + +// These must be included first: + +#include <nt.h> // NtOpenFile(), ULONG, etc. +#include <ntrtl.h> // PLARGE_INTEGER, TIME_FIELDS, etc. +#include <nturtl.h> // Needed for ntrtl.h and windows.h to co-exist. + +#include <windows.h> // GetLastError(), etc. +#include <lmcons.h> + +// These may be included in any order: + +#include <netdebug.h> // DBGSTATIC, NetpKdPrint(), FORMAT_ equates, etc. +#include <netlib.h> // NetpMemoryAllocate(), etc. +#include <prefix.h> // PREFIX_ equates. +#include <repldefs.h> // My prototype, UNKNOWN_FS_RESOLUTION, etc. +#include <tstring.h> // NetpNCopyWStrToTStr(). +#include <winerror.h> // NO_ERROR. + + +DWORD +ReplGetFsTimeResolutionSecs( + IN LPCTSTR AbsPath + ) +{ + NET_API_STATUS ApiStatus; + DWORD ResolutionSecs = UNKNOWN_FS_RESOLUTION; + HANDLE FileHandle = NULL; + IO_STATUS_BLOCK IoStatusBlock; + NTSTATUS NtStatus; + OBJECT_ATTRIBUTES ObjectAttributes; + + const ULONG OpenOptions = + FILE_SYNCHRONOUS_IO_NONALERT +#if 0 + | ( IsDirectory ? FILE_DIRECTORY_FILE : 0 ) +#endif + ; + + TCHAR FsName[MAXIMUM_FILENAME_LENGTH+1]; + DWORD FsNameLen; // char count in FsName, w/o nul char. + BOOL PathAllocated = FALSE; + UNICODE_STRING UnicodePath; + PFILE_FS_ATTRIBUTE_INFORMATION VolumeInfo = NULL; + ULONG VolumeInfoSize; + + NetpAssert( AbsPath != NULL ); + ApiStatus = ReplCheckAbsPathSyntax( (LPTSTR) AbsPath ); + NetpAssert( ApiStatus == NO_ERROR ); + + RtlInitUnicodeString( + & UnicodePath, // output: struct + AbsPath ); // input: null terminated + + if( !RtlDosPathNameToNtPathName_U( + AbsPath, + &UnicodePath, + NULL, + NULL) ) { + + NetpKdPrint(( PREFIX_REPL_CLIENT + "ReplGetFsTimeResolutionSecs: RtlDosPathNameToNtPathname_U" + " of source '" FORMAT_LPTSTR "' failed.\n", AbsPath )); + + // BUGBUG: log error + goto Cleanup; + } + PathAllocated = TRUE; + + InitializeObjectAttributes( + &ObjectAttributes, + (LPVOID) &UnicodePath, + OBJ_CASE_INSENSITIVE, + NULL, + NULL ); + NtStatus = NtOpenFile( + & FileHandle, + SYNCHRONIZE | // desired ... + FILE_READ_ATTRIBUTES, // ... access + &ObjectAttributes, + &IoStatusBlock, + FILE_SHARE_READ, // share access + OpenOptions ); + + if ( !NT_SUCCESS( NtStatus ) ) { + + NetpKdPrint(( PREFIX_REPL_CLIENT + "ReplGetFsTimeResolutionSecs: NtOpenFile of source '" + FORMAT_LPTSTR "' gave NT status " FORMAT_NTSTATUS ".\n", + AbsPath, NtStatus )); + + // BUGBUG: log error + goto Cleanup; + } + + // + // Alloc space for volume fs attr info (including various strings + // after the structure). + // + VolumeInfoSize = + sizeof(FILE_FS_ATTRIBUTE_INFORMATION) + + ( (MAXIMUM_FILENAME_LENGTH+1) * sizeof(WCHAR) ); + VolumeInfo = NetpMemoryAllocate( VolumeInfoSize ); + if (VolumeInfo == NULL) { + // BUGBUG: log the error! + goto Cleanup; + } + + NtStatus = NtQueryVolumeInformationFile( + FileHandle, + &IoStatusBlock, + (PVOID) VolumeInfo, + VolumeInfoSize, + FileFsAttributeInformation ); // FS info class + + if ( !NT_SUCCESS( NtStatus ) ) { + + NetpKdPrint(( PREFIX_REPL_CLIENT + "ReplGetFsTimeResolutionSecs: NtQueryVolumeInformationFile " + "FAILED, NT status is " FORMAT_NTSTATUS ".\n", + NtStatus )); + + // BUGBUG: log error + goto Cleanup; + } + + IF_DEBUG( REPL ) { + NetpKdPrint(( PREFIX_REPL + "ReplGetFsTimeResolutionSecs: got volume info, " + "name len is " FORMAT_DWORD ", name[0] is " FORMAT_WCHAR ".\n", + (DWORD) (VolumeInfo->FileSystemNameLength), + VolumeInfo->FileSystemName[0] )); + } + NetpAssert( ((VolumeInfo->FileSystemNameLength) % sizeof(WCHAR)) == 0 ); + + FsNameLen = (VolumeInfo->FileSystemNameLength) / sizeof(WCHAR); + // len w/o nul + + ApiStatus = NetpNCopyWStrToTStr( + FsName, // dest + VolumeInfo->FileSystemName, // src + FsNameLen); // chars + NetpAssert( ApiStatus == NO_ERROR ); + FsName[ FsNameLen ] = L'\0'; + + IF_DEBUG( REPL ) { + NetpKdPrint(( PREFIX_REPL + "ReplGetFsTimeResolutionSecs: got fs name '" FORMAT_LPTSTR + "'.\n", FsName )); + } + + // + // Compute ResolutionSecs using known file system names. + // + if (STRICMP( FsName, (LPTSTR) TEXT("FAT") ) == 0) { + ResolutionSecs = 2; + goto Cleanup; + } + if (STRICMP( FsName, (LPTSTR) TEXT("HPFS") ) == 0) { + ResolutionSecs = 1; + goto Cleanup; + } + if (STRICMP( FsName, (LPTSTR) TEXT("NTFS") ) == 0) { + ResolutionSecs = 1; + goto Cleanup; + } + + NetpKdPrint(( PREFIX_REPL + "ReplGetFsTimeResolutionSecs: UNKNOWN fs name of '" + "'.\n", FsName )); + // BUGBUG: log this error! + ResolutionSecs = UNKNOWN_FS_RESOLUTION; + +Cleanup: + + if (FileHandle != NULL) { + (VOID) NtClose( FileHandle ); + } + + if (VolumeInfo != NULL) { + NetpMemoryFree( VolumeInfo ); + } + + if (PathAllocated) { + (VOID) RtlFreeHeap( RtlProcessHeap(), 0, UnicodePath.Buffer ); + } + + return (ResolutionSecs); +} diff --git a/private/net/svcdlls/repl/common/ignorenm.c b/private/net/svcdlls/repl/common/ignorenm.c new file mode 100644 index 000000000..335655e7d --- /dev/null +++ b/private/net/svcdlls/repl/common/ignorenm.c @@ -0,0 +1,100 @@ +/*++ + +Copyright (c) 1992 Microsoft Corporation + +Module Name: + + IgnoreNm.c + +Abstract: + + This file contains ReplIgnoreDirOrFileName(). + +Author: + + John Rogers (JohnRo) 25-Feb-1992 + +Environment: + + User Mode - Win32 + Portable to any flat, 32-bit environment. (Uses Win32 typedefs.) + Requires ANSI C extensions: slash-slash comments, long external names. + +Revision History: + + 25-Feb-1992 JohnRo + Created this routine. + 19-Aug-1992 JohnRo + RAID 3603: import tree (TMPREE.RP$) generated at startup. + 08-Dec-1992 JohnRo + Made changes suggested by PC-LINT 5.0 + +--*/ + + +// These must be included first: + +#include <windef.h> // MAX_PATH, etc. +#include <lmcons.h> // LAN Manager common definitions + +// These can be in any order: + +#include <client.h> // RP, TMP_TREE, etc. +#include <dirname.h> // ReplIsDirNameValid(). +#include <netdebug.h> // NetpAssert(). +#include <repldefs.h> // My prototype, DOT, DOT_DOT. +#include <tstr.h> // TCHAR_ equates, STRLEN(), etc. +#include <winerror.h> // ERROR_, NO_ERROR equates. + + + + +BOOL +ReplIgnoreDirOrFileName ( + IN LPTSTR Name + ) +{ + INT len; + + NetpAssert( Name != NULL ); + NetpAssert( (*Name) != TCHAR_EOS ); + NetpAssert( ReplIsDirNameValid( Name ) ); // Not abs path, UNC, "c:x". + + // + // Definitely ignore "." and "..". + // + if ( (STRCMP(Name, DOT)==0) || (STRCMP(Name, DOT_DOT)==0) ) { + return (TRUE); // yes, ignore this one. + } + + // + // Ignore "*.RP$". This also gets TMPTREE.RP$, TMPTREEX.RP$. + // + len = ((INT) STRLEN( Name )) - ((INT)STRLEN( RP )); + + if ( (len > 0) && (STRICMP(&Name[len], RP) == 0) ) { + return (TRUE); // yes, ignore this one. + } + NetpAssert( STRICMP(Name, TMP_TREE) != 0 ); + NetpAssert( STRICMP(Name, TMP_TREEX) != 0 ); + + // + // Ignore "REPL.INI". + // + if (STRICMP(Name, REPL_INI) == 0) { + return (TRUE); // yes, ignore this one. + } + + // + // Ignore "USERLOCK.*". + // + if (STRNICMP(Name, ULOCK_PREFIX, STRLEN(ULOCK_PREFIX)) == 0) { + return (TRUE); // yes, ignore this one. + } + + // + // None of the above. + // + return (FALSE); // No, don't ignore this one. + +} // ReplIgnoreDirOrFileName diff --git a/private/net/svcdlls/repl/common/impalloc.c b/private/net/svcdlls/repl/common/impalloc.c new file mode 100644 index 000000000..e60e6cbce --- /dev/null +++ b/private/net/svcdlls/repl/common/impalloc.c @@ -0,0 +1,118 @@ +/*++ + +Copyright (c) 1992 Microsoft Corporation + +Module Name: + + ImpAlloc.c + +Abstract: + + This file contains ImportDirAllocApiRecords(). + +Author: + + John Rogers (JohnRo) 19-Feb-1992 + +Environment: + + Runs under Windows NT. + Requires ANSI C extensions: slash-slash comments, long external names. + +Revision History: + + 19-Feb-1992 JohnRo + Created this routine by cloning ExportDirAllocApiRecords(). + +--*/ + + +// These must be included first: + +#include <windef.h> // IN, VOID, LPTSTR, etc. +#include <lmcons.h> // NET_API_STATUS, PARM equates, etc. +#include <rap.h> // Needed by <strucinf.h>. + +// These can be in any order: + +#include <impdir.h> // My prototype. +#include <lmapibuf.h> // NetApiBufferAllocate(). +#include <netdebug.h> // NetpAssert(). +#include <netlib.h> // NetpPointerPlusSomeBytes(). +#include <strucinf.h> // Netp{various}StructureInfo(). +#include <winerror.h> // ERROR_* defines; NO_ERROR. + + +NET_API_STATUS +ImportDirAllocApiRecords ( + IN DWORD Level, + IN DWORD EntryCount, + OUT LPBYTE * BufPtr, + IN OUT LPBYTE *StringLocation // Points just past top of data. + ) + +{ + LPBYTE FirstRecord = NULL; + NET_API_STATUS ApiStatus; + DWORD EntrySize; + + // + // Check for caller errors. + // + if (BufPtr == NULL) { + return (ERROR_INVALID_PARAMETER); + } + + * BufPtr = NULL; // Don't confuse caller about possible alloc'ed data. + + if (EntryCount == 0) { + return (ERROR_INVALID_PARAMETER); + } + + // + // Compute size of an entry (and check caller's Level too). + // + ApiStatus = NetpReplImportDirStructureInfo ( + Level, + PARMNUM_ALL, + TRUE, // want native sizes + NULL, // don't need DataDesc16 + NULL, // don't need DataDesc32 + NULL, // don't need DataDescSmb + & EntrySize, // need max size of structure + NULL, // don't need FixedSize + NULL); // don't need StringSize + if (ApiStatus != NO_ERROR) { + return (ApiStatus); + } + NetpAssert( EntrySize > 0 ); + + // + // Allocate the output area. + // + ApiStatus = NetApiBufferAllocate( + EntrySize * EntryCount, + (LPVOID *) & FirstRecord); + if (ApiStatus != NO_ERROR) { + + // ApiStatus is already set to return error to caller. + + } else { + NetpAssert( FirstRecord != NULL ); + + // + // Tell caller where top of string area is. + // + * StringLocation = NetpPointerPlusSomeBytes( + FirstRecord, + EntrySize * EntryCount ); + + } + + // + // Tell caller how everything went. + // + * BufPtr = FirstRecord; + return (ApiStatus); + +} diff --git a/private/net/svcdlls/repl/common/impbuild.c b/private/net/svcdlls/repl/common/impbuild.c new file mode 100644 index 000000000..8043fd8fc --- /dev/null +++ b/private/net/svcdlls/repl/common/impbuild.c @@ -0,0 +1,203 @@ +/*++ + +Copyright (c) 1992-1993 Microsoft Corporation + +Module Name: + + ImpBuild.c + +Abstract: + + This file contains ImportDirBuildApiRecord. This is used by + NetrReplImportDirGetInfo and NetrReplImportDirEnum. + +Author: + + John Rogers (JohnRo) 08-Jan-1992 + +Environment: + + Portable to any flat, 32-bit environment. (Uses Win32 typedefs.) + Requires ANSI C extensions: slash-slash comments, long external names. + +Notes: + + This code assumes that the import dir info levels are subsets of each other. + +Revision History: + + 08-Jan-1992 JohnRo + Created. + 24-Jan-1992 JohnRo + Changed to use LPTSTR etc. + 27-Jan-1992 JohnRo + Changed interface to allow use when service is not running. + 21-Feb-1992 JohnRo + Fixed bug checking state parameter. + UncMaster parm is optional. + Added check of UncMaster validity. + Undid redundant checks of Buffer (3 of them!) + 21-Feb-1992 JohnRo + Changed ImportDirBuildApiRecord() so master name is not a UNC name. + 22-Feb-1992 JohnRo + Made changes suggested by PC-LINT. + 26-Feb-1992 JohnRo + Check lock fields for validity. + API records now contain timestamps instead of elapsed times. + Added assertion of valid record at end. + 25-Mar-1992 JohnRo + Avoid obsolete state values. + 27-Mar-1992 JohnRo + Allow MasterName to point to a null char. + 28-Jul-1992 JohnRo + RAID 2274: repl svc should impersonate caller. + Added debug output of structure after we build it. + 30-Apr-1993 JohnRo + Use NetpKdPrint() where possible. + +--*/ + + +// These must be included first: + +#include <windef.h> // IN, VOID, LPTSTR, etc. +#include <lmcons.h> // NET_API_STATUS. +#include <repldefs.h> // ReplIsIntegrityValid(), IF_DEBUG(), SLASH_SLASH, etc. + +// These can be in any order: + +#include <align.h> // POINTER_IS_ALIGNED(), ALIGN_TCHAR. +#include <dirname.h> // ReplIsDirNameValid(). +#include <impdir.h> // My prototype, ImportDirIsLevelValid(). +#include <lmrepl.h> // LPREPL_IDIR_INFO_1, REPL_EXTENT_ stuff, etc. +#include <names.h> // NetpIsComputerNameValid(). +#include <netdebug.h> // NetpAssert(), NetpKdPrint(), etc. +#include <prefix.h> // PREFIX_ equates. +#include <tstr.h> // STRLEN(), TCHAR_EOS, etc. +#include <winerror.h> // ERROR_ equates, NO_ERROR. + + +NET_API_STATUS +ImportDirBuildApiRecord ( + IN DWORD Level, + IN LPTSTR DirName, + IN DWORD State, + IN LPTSTR MasterName OPTIONAL, // computer name (not UNC). + IN DWORD TimeOfLastUpdate, // Seconds since 1970. + IN DWORD LockCount, + IN DWORD TimeOfFirstLock, // Seconds since 1970. + OUT LPVOID Buffer, + IN OUT LPBYTE *StringLocation // Points just past top of data. + ) + +{ + LPREPL_IDIR_INFO_1 ApiRecord = Buffer; // superset info level + LPTSTR StringDest; + DWORD StringLength; + + NetpAssert( StringLocation != NULL); + NetpAssert( *StringLocation != NULL); + + IF_DEBUG( IMPAPI ) { + NetpKdPrint(( PREFIX_REPL + "ImportDirBuildApiRecord: building record at " FORMAT_LPVOID + ", *str loc is " FORMAT_LPVOID ".\n", + (LPVOID) Buffer, (LPVOID) *StringLocation )); + } + + if ( (MasterName != NULL) && ((*MasterName) == TCHAR_EOS) ) { + MasterName = NULL; + } + + // + // Check for caller errors. + // + if ( ! ReplIsDirNameValid( DirName ) ) { + return (ERROR_INVALID_DATA); + } else if (Buffer == NULL) { + return (ERROR_INVALID_PARAMETER); + } else if ( !ReplIsStateValid( State ) ) { + return (ERROR_INVALID_DATA); + } else if ( !ImportDirIsLevelValid( Level ) ) { + return (ERROR_INVALID_LEVEL); + } else if ((MasterName!=NULL) && !NetpIsComputerNameValid(MasterName)) { + return (ERROR_INVALID_PARAMETER); + } else if ( !ReplAreLockFieldsValid( LockCount, TimeOfFirstLock ) ) { + return (ERROR_INVALID_PARAMETER); + } + + // + // First do subset common to both info levels. + // + StringLength = (DWORD) STRLEN( DirName ); + + NetpAssert( POINTER_IS_ALIGNED( *StringLocation, ALIGN_TCHAR ) ); + StringDest = (LPTSTR) (LPVOID) (*StringLocation); + StringDest -= (StringLength + 1); + + *StringLocation = (LPBYTE) (LPVOID) StringDest; + + ApiRecord->rpid1_dirname = StringDest; + + (void) STRCPY( + StringDest, // dest + DirName); // src + + // + // Next do stuff only found in level 1. + // + if (Level > 0) { + + // + // Do master name (only other string)... + // + if (MasterName != NULL) { + StringLength = (DWORD) STRLEN( MasterName ) + 2; // Ch to UNC. + + NetpAssert( POINTER_IS_ALIGNED( *StringLocation, ALIGN_TCHAR ) ); + StringDest = (LPTSTR) (LPVOID) (*StringLocation); + StringDest -= (StringLength + 1); + + *StringLocation = (LPBYTE) (LPVOID) StringDest; + + ApiRecord->rpid1_mastername = StringDest; + + (void) STRCPY( + StringDest, // dest + SLASH_SLASH ); // src + (void) STRCAT( + StringDest, // dest + MasterName); // src + } else { + ApiRecord->rpid1_mastername = NULL; + } + + // + // Now do simple stuff... + // + { + ApiRecord->rpid1_state = State; + } + + ApiRecord->rpid1_last_update_time = TimeOfLastUpdate; + + ApiRecord->rpid1_lockcount = LockCount; + + if (TimeOfFirstLock == 0) { + ApiRecord->rpid1_locktime = 0; + } else { + ApiRecord->rpid1_locktime = TimeOfFirstLock; + } + } + + IF_DEBUG( IMPAPI ) { + NetpKdPrint(( PREFIX_REPL + "ImportDirBuildApiRecord: built structure:\n" )); + NetpDbgDisplayReplImportDir( Level, Buffer ); + } + + NetpAssert( ImportDirIsApiRecordValid( Level, ApiRecord, NULL ) ); + + return (NO_ERROR); + +} diff --git a/private/net/svcdlls/repl/common/impconf.c b/private/net/svcdlls/repl/common/impconf.c new file mode 100644 index 000000000..127812f2a --- /dev/null +++ b/private/net/svcdlls/repl/common/impconf.c @@ -0,0 +1,720 @@ +/*++ + +Copyright (c) 1992-1993 Microsoft Corporation + +Module Name: + + ImpConf.c + +Abstract: + + This file contains structures, function prototypes, and definitions + for the replicator import directory worker routines. + +Author: + + John Rogers (JohnRo) 09-Jan-1992 + +Environment: + + User Mode - Win32 + Portable to any flat, 32-bit environment. (Uses Win32 typedefs.) + Requires ANSI C extensions: slash-slash comments, long external names. + +Revision History: + + 09-Jan-1992 JohnRo + Created. + 23-Jan-1992 JohnRo + Clarify units for time parameters. + 27-Jan-1992 JohnRo + ImportDirReadConfigData() should return NERR_UnknownDevDir. + Changed to use LPTSTR etc. + 10-Feb-1992 JohnRo + ImportDirReadConfigData() should handle section not found. + 13-Feb-1992 JohnRo + Moved section name equates to ConfName.h. + 21-Feb-1992 JohnRo + Fixed bugs handling UNC master. + Added support for REPL_STATE_NOT_STARTED. + Added ImportDirDeleteConfigData() and ImportDirConfigDataExists(). + 27-Feb-1992 JohnRo + Changed state not started to state never replicated. + 25-Mar-1992 JohnRo + Avoid obsolete state values. + Get rid of old config helpers. + 26-Mar-1992 JohnRo + Fixed bug parsing UncMaster. + 10-Jul-1992 JohnRo + RAID 10503: srv mgr: repl dialog doesn't come up. + Use PREFIX_ equates. + 23-Jul-1992 JohnRo + RAID 2274: repl svc should impersonate caller. + 29-Sep-1992 JohnRo + Fix remote repl admin. + 01-Dec-1992 JohnRo + RAID 3844: remote NetReplSetInfo uses local machine type. + 21-Jan-1993 JohnRo + RAID 7717: Repl assert if not logged on correctly. (Also do event + logging for real.) + Made changes suggested by PC-LINT 5.0 + 30-Apr-1993 JohnRo + Use NetpKdPrint() where possible. + +--*/ + + +// These must be included first: + +#include <windef.h> // Win32 type definitions +#include <lmcons.h> // LAN Manager common definitions + +// These may be included in any order: + +#include <config.h> // NetpConfig helpers. +#include <confname.h> // SECT_NT_ equates. +#include <dirname.h> // ReplIsDirNameValid(). +#include <impdir.h> // My prototypes. +#include <lmapibuf.h> // NetApiBufferFree(). +#include <lmerr.h> // NO_ERROR, ERROR_, and NERR_ equates. +#include <lmerrlog.h> // NELOG_ equates. +#include <lmrepl.h> // REPL_STATE_ equates. +#include <names.h> // NetpIsUncComputerNameValid(). +#include <netdebug.h> // NetpAssert(), etc. +#include <netlib.h> // NetpPointerPlusSomeBytes(). +#include <prefix.h> // PREFIX_ equates. +#include <replconf.h> // ReplConfigReportBadParmValue(). +#include <repldefs.h> // IF_DEBUG(), DWORDLEN, ReplErrorLog(). +#include <tstr.h> // STRCPY(), ATOL(). + + +#define IMPORT_VALUE_ARRAY_LEN \ + (STATE_LEN /* state */ \ + + 1 /* , */ \ + + UNCLEN /* master */ \ + + 1 /* , */ \ + + DWORDLEN /* last_update_time (seconds since 1970) */ \ + + 1 /* , */ \ + + DWORDLEN /* lockcount */ \ + + 1 /* , */ \ + + DWORDLEN ) /* locktime (seconds since 1970) */ + +#define OPTIONAL_LPTSTR( tstr ) \ + ( (tstr) ? (tstr) : (LPTSTR) TEXT("<noname>") ) + + +// Tells whether or not config data for this directory exists. +// Callable even if the replicator service is not started. +BOOL +ImportDirConfigDataExists ( + IN LPTSTR UncServerName OPTIONAL, + IN LPTSTR DirName // Caller must check dir name syntax. + ) +{ + NET_API_STATUS ApiStatus; + LPNET_CONFIG_HANDLE Handle; + LPTSTR Value; + + // + // Check for caller's errors. + // + NetpAssert( ReplIsDirNameValid( DirName ) ); + + // + // Open the right section of the config file/whatever. + // + ApiStatus = NetpOpenConfigDataEx( + & Handle, + UncServerName, + (LPTSTR) SECT_NT_REPLICATOR, // section + (LPTSTR) SECT_NT_REPLICATOR_IMPORTS, // area (instead of parameters) + TRUE); // read-only + + if (ApiStatus != NO_ERROR) { + + // Log error on server we were trying to access. + ReplErrorLog( + UncServerName, + NELOG_ReplSysErr, + ApiStatus, + NULL, + NULL ); + + return (FALSE); // section doesn't exist, so dir data doesn't. + } + + // + // Read the value from the config file/whatever. + // + ApiStatus = NetpGetConfigValue( + Handle, + DirName, // keyword is dir name + & Value); // alloc and set ptr + + // + // We're done with this, so close the config data and toss the buffer we + // got. But remember the status from NetpGetConfigValue! + // + if (Value != NULL) { + (void) NetApiBufferFree( Value ); + } + (void) NetpCloseConfigData( Handle ); + + // + // Now check the status of the Get. + // + if (ApiStatus == NERR_CfgParamNotFound) { + return (FALSE); // doesn't exist + } else if (ApiStatus == NO_ERROR) { + return (TRUE); // exists + } else { + // Log error on server we were trying to access. + ReplErrorLog( + UncServerName, + NELOG_ReplSysErr, + ApiStatus, + NULL, + NULL ); + + return (FALSE); // Say it doesn't exist, since we don't know. + } + + /*NOTREACHED*/ + +} // ImportDirConfigDataExists + + +// Delete config data for this directory. +// Returns NERR_UnknownDevDir if config data doesn't exist for this dir. +// Callable even if the replicator service is not started. +NET_API_STATUS +ImportDirDeleteConfigData ( + IN LPTSTR UncServerName OPTIONAL, + IN LPTSTR DirName // Caller must check dir name syntax. + ) +{ + NET_API_STATUS ApiStatus; + LPNET_CONFIG_HANDLE Handle = NULL; + + // + // Check for caller's errors. + // + if ( ! ReplIsDirNameValid( DirName ) ) { + ApiStatus = ERROR_INVALID_PARAMETER; + goto Cleanup; // Log error below. + } + + // + // Open the right section of the config file/whatever. + // + ApiStatus = NetpOpenConfigDataEx( + & Handle, + UncServerName, + (LPTSTR) SECT_NT_REPLICATOR, // section + (LPTSTR) SECT_NT_REPLICATOR_IMPORTS, // area (instead of parameters) + FALSE ); // not read-only + if (ApiStatus == NERR_CfgCompNotFound) { + ApiStatus = NERR_UnknownDevDir; + goto Cleanup; // Log error below. + } else if (ApiStatus != NO_ERROR) { + goto Cleanup; // Log error below. + } + + // + // Delete this keyword from this section. + // + ApiStatus = NetpDeleteConfigKeyword( + Handle, + DirName ); // keyword is dir name + + IF_DEBUG(EXPAPI) { + NetpKdPrint(( PREFIX_REPL + "ImportDirDeleteConfigData: conf del ret " FORMAT_API_STATUS + ".\n", ApiStatus )); + } + + if (ApiStatus == NERR_CfgParamNotFound) { + ApiStatus = NERR_UnknownDevDir; + goto Cleanup; // Log error below. + } else if (ApiStatus != NO_ERROR) { + goto Cleanup; // Log error below. + } + + // + // All done. + // +Cleanup: + + if ( Handle != NULL ) { + NET_API_STATUS CloseStatus; + + CloseStatus = NetpCloseConfigData( Handle ); + + // Return this error iff it is first error we've gotten. + if ( (ApiStatus == NO_ERROR) && (CloseStatus != NO_ERROR) ) { + ApiStatus = CloseStatus; + } + } + + if (ApiStatus != NO_ERROR) { + // Log error on server we were trying to access. + ReplErrorLog( + UncServerName, + NELOG_ReplSysErr, + ApiStatus, + NULL, + NULL ); + } + + + return (ApiStatus); + +} // ImportDirDeleteConfigData + + +// Parse config data for a single import directory. Callable whether or not +// the replicator service is started. +NET_API_STATUS +ImportDirParseConfigData ( + IN LPTSTR UncServerName OPTIONAL, + IN LPTSTR ValueString, + OUT LPDWORD StatePtr, + OUT LPTSTR UncMasterPtr, + OUT LPDWORD LastUpdateTimePtr, // Seconds since 1970. + OUT LPDWORD LockCountPtr, + OUT LPDWORD LockTimePtr // Seconds since 1970. + ) +{ + LPTSTR CurrentValuePtr = ValueString; + + // + // Check for caller's errors. + // + NetpAssert( ValueString != NULL); + if (STRLEN( ValueString ) > IMPORT_VALUE_ARRAY_LEN) { + goto ReportBadConfigLine; + } + + // + // Start parsing the value, which begins with a string containing the + // state. + // + +#define TRY_STATE( StateEquate, StateString ) \ + { \ + DWORD HopefulStringLength = STRLEN(StateString); \ + if (STRNCMP( CurrentValuePtr, (StateString), HopefulStringLength) == 0) { \ + *StatePtr = (StateEquate); \ + CurrentValuePtr = (LPTSTR) (LPVOID) \ + NetpPointerPlusSomeBytes( CurrentValuePtr, \ + HopefulStringLength * sizeof(TCHAR) ); \ + goto DoneState; \ + } \ + } + + TRY_STATE( REPL_STATE_OK, OK_RP ) + + TRY_STATE( REPL_STATE_NO_SYNC, NO_SYNC_RP ) + + TRY_STATE( REPL_STATE_NO_MASTER, NO_MASTER_RP ) + + TRY_STATE( REPL_STATE_NEVER_REPLICATED, NEVER_REPLICATED_RP ) + + goto ReportBadConfigLine; + +DoneState: + + // + // Parse the rest of the value string. + // + +#define PARSE_CHAR(AsciiChar) \ + { \ + if (*CurrentValuePtr == MAKE_TCHAR(AsciiChar)) { \ + ++CurrentValuePtr; \ + } else { \ + goto ReportBadConfigLine; \ + } \ + } + +#define PARSE_COMMA( ) PARSE_CHAR(',') + + PARSE_COMMA(); + + // + // Parse the (optional) UNC master name. + // + if (*CurrentValuePtr == MAKE_TCHAR('\\')) { + LPTSTR StringAfterMasterName; + + StringAfterMasterName = STRCHR( CurrentValuePtr, MAKE_TCHAR(',') ); + if (StringAfterMasterName == NULL) { + goto ReportBadConfigLine; + } + + *StringAfterMasterName = TCHAR_EOS; // changes master to its own str. + if ( !NetpIsUncComputerNameValid( CurrentValuePtr ) ) { + goto ReportBadConfigLine; + } + + (void) STRCPY( UncMasterPtr, CurrentValuePtr ); + *StringAfterMasterName = MAKE_TCHAR(','); // put line back as is was + CurrentValuePtr = StringAfterMasterName; // skip to the comma. + } else if (*CurrentValuePtr == MAKE_TCHAR(',')) { + if (UncMasterPtr != NULL) { + *UncMasterPtr = TCHAR_EOS; + } + } else { + goto ReportBadConfigLine; + } + + PARSE_COMMA(); + + // + // Parse the numbers on the rest of the line. + // + +#define PARSE_DWORD( NumberPtr ) \ + { \ + if ( ! ISDIGIT( *CurrentValuePtr ) ) { \ + goto ReportBadConfigLine; \ + } \ + NetpAssert( NumberPtr != NULL ); \ + * NumberPtr = (DWORD) ATOL( CurrentValuePtr ); \ + while ( ISDIGIT( *CurrentValuePtr ) ) { \ + ++CurrentValuePtr; \ + } \ + } + + PARSE_DWORD( LastUpdateTimePtr ); // Seconds since 1970. + + PARSE_COMMA(); + + PARSE_DWORD( LockCountPtr ); + + PARSE_COMMA(); + + PARSE_DWORD( LockTimePtr ); // Seconds since 1970. + + IF_DEBUG(IMPAPI) { + NetpKdPrint(( PREFIX_REPL + "ImportDirParseConfigValue: Value = '" FORMAT_LPTSTR "',\n", + ValueString )); + NetpKdPrint(( + " State = " FORMAT_DWORD + ", UncMaster = '" FORMAT_LPTSTR "'.\n", + *StatePtr, OPTIONAL_LPTSTR(UncMasterPtr) )); + NetpKdPrint(( + " last update time (secs since 1970) = " FORMAT_DWORD + ", lock count = " FORMAT_DWORD + ", lock time (secs since 1970) = " FORMAT_DWORD ".\n", + *LastUpdateTimePtr, *LockCountPtr, *LockTimePtr )); + } + + if ( ! ReplIsStateValid( *StatePtr ) ) { + goto ReportBadConfigLine; + } + + return (NO_ERROR); + +ReportBadConfigLine: + + // BUGBUG: Sure would be nice if we could include dirname here. + + ReplConfigReportBadParmValue( + UncServerName, + (LPTSTR) SECT_NT_REPLICATOR_IMPORTS, + ValueString ); + + return (ERROR_INVALID_DATA); + +} // ImportDirParseConfigData + + +// Read config data for a single import directory. Callable whether or not +// the replicator service is started. Returns NERR_UnknownDevDir if there +// is no config data for this directory. +NET_API_STATUS +ImportDirReadConfigData ( + IN LPTSTR UncServerName OPTIONAL, + IN LPTSTR DirName, + OUT LPDWORD StatePtr, + OUT LPTSTR UncMasterPtr, + OUT LPDWORD LastUpdateTimePtr, // Seconds since 1970. + OUT LPDWORD LockCountPtr, + OUT LPDWORD LockTimePtr // Seconds since 1970. + ) +{ + NET_API_STATUS ApiStatus; + LPNET_CONFIG_HANDLE Handle = NULL; + LPTSTR Value = NULL; + + // + // Check for caller's errors. + // + if ( ! ReplIsDirNameValid( DirName ) ) { + ApiStatus = ERROR_INVALID_PARAMETER; + goto Cleanup; // go log error + } + + // + // Open the right section of the config file/whatever. + // + ApiStatus = NetpOpenConfigDataEx( + & Handle, + UncServerName, + (LPTSTR) SECT_NT_REPLICATOR, // section + (LPTSTR) SECT_NT_REPLICATOR_IMPORTS, // area (instead of parameters) + TRUE); // read-only + if (ApiStatus == NERR_CfgCompNotFound) { + ApiStatus = NERR_UnknownDevDir; + goto Cleanup; // go log error + } else if (ApiStatus != NO_ERROR) { + goto Cleanup; // go log error + } + + // + // Read the value from the config file/whatever. + // + ApiStatus = NetpGetConfigValue( + Handle, + DirName, // keyword is dir name + & Value); // alloc and set ptr + if (ApiStatus == NERR_CfgParamNotFound) { + ApiStatus = NERR_UnknownDevDir; + goto Cleanup; // go log error + } else if (ApiStatus != NO_ERROR) { + goto Cleanup; // go log error + } + NetpAssert( Value != NULL ); + + IF_DEBUG(IMPAPI) { + NetpKdPrint(( PREFIX_REPL + "ImportDirReadConfigValue( " FORMAT_LPTSTR "): '" + FORMAT_LPTSTR "' = '" FORMAT_LPTSTR "'.\n", + (UncServerName!=NULL) ? UncServerName : (LPTSTR) TEXT("local"), + DirName, Value )); + } + + // + // Parse the value string... + // + ApiStatus = ImportDirParseConfigData ( + UncServerName, + Value, + StatePtr, + UncMasterPtr, + LastUpdateTimePtr, // Seconds since 1970. + LockCountPtr, + LockTimePtr); // Seconds since 1970. + // Fall through and log error if this failed. + +Cleanup: + // + // All done. + // + if ( Handle != NULL ) { + NET_API_STATUS CloseStatus; + + CloseStatus = NetpCloseConfigData( Handle ); + + // Return this error iff it is first error we've gotten. + if ( (ApiStatus == NO_ERROR) && (CloseStatus != NO_ERROR) ) { + ApiStatus = CloseStatus; + } + } + + if (Value != NULL) { + (VOID) NetApiBufferFree( Value ); + } + + if (ApiStatus != NO_ERROR) { + // Log error on server we were trying to access. + ReplErrorLog( + UncServerName, + NELOG_ReplSysErr, + ApiStatus, + NULL, + NULL ); + } + + return (ApiStatus); + +} // ImportDirReadConfigData + + + + + +// Write config data for a single import directory. Callable whether or not +// the replicator service is started. +NET_API_STATUS +ImportDirWriteConfigData ( + IN LPTSTR UncServerName OPTIONAL, + IN LPTSTR DirName, + IN DWORD State, + IN LPTSTR UncMaster OPTIONAL, + IN DWORD LastUpdateTime, // Seconds since 1970. + IN DWORD LockCount, + IN DWORD LockTime // Seconds since 1970. + ) +{ + NET_API_STATUS ApiStatus; + LPNET_CONFIG_HANDLE Handle = NULL; + TCHAR ValueArray[IMPORT_VALUE_ARRAY_LEN+1]; + + IF_DEBUG(IMPAPI) { + NetpKdPrint(( PREFIX_REPL + "ImportDirWriteConfigValue:( " FORMAT_LPTSTR " ): DirName = " + FORMAT_LPTSTR ".\n", + (UncServerName!=NULL) ? UncServerName : (LPTSTR) TEXT("local"), + DirName )); + NetpKdPrint(( + " State = " FORMAT_DWORD + ", UncMaster = '" FORMAT_LPTSTR "'.\n", + State, OPTIONAL_LPTSTR(UncMaster) )); + NetpKdPrint(( + " last update time (secs since 1970) = " FORMAT_DWORD + ", lock count = " FORMAT_DWORD + ", lock time (secs since 1970) = " FORMAT_DWORD ".\n", + LastUpdateTime, LockCount, LockTime )); + } + // + // Check for caller's errors. + // + if ( ! ReplIsDirNameValid( DirName ) ) { + ApiStatus = ERROR_INVALID_PARAMETER; + goto Cleanup; // go log error + } + if ( ! ReplIsStateValid( State ) ) { + ApiStatus = ERROR_INVALID_PARAMETER; + goto Cleanup; // go log error + } + if (UncMaster != NULL) { + if ( ! NetpIsUncComputerNameValid( UncMaster ) ) { + ApiStatus = ERROR_INVALID_PARAMETER; + goto Cleanup; // go log error + } + } + + // + // Open the right section of the config file/whatever. + // + ApiStatus = NetpOpenConfigDataEx( + & Handle, + UncServerName, + (LPTSTR) SECT_NT_REPLICATOR, // section + (LPTSTR) SECT_NT_REPLICATOR_IMPORTS, // area (instead of parameters) + FALSE); // not read-only + if (ApiStatus != NO_ERROR) { + goto Cleanup; // go log error + } + + // + // Start building the value, which begins with a string containing the + // state. + // + switch (State) { + case REPL_STATE_OK: + + (void) STRCPY( ValueArray, OK_RP); + break; + + case REPL_STATE_NO_SYNC: + + (void) STRCPY( ValueArray, NO_SYNC_RP); + break; + + case REPL_STATE_NO_MASTER: + + (void) STRCPY( ValueArray, NO_MASTER_RP); + break; + + case REPL_STATE_NEVER_REPLICATED: + + (void) STRCPY( ValueArray, NEVER_REPLICATED_RP); + break; + + default: + NetpAssert( FALSE ); + ApiStatus = ERROR_INVALID_PARAMETER; + goto Cleanup; // go log error + } + + // + // Build the rest of the value string. + // + (void) STRCAT( ValueArray, (LPTSTR) TEXT(",") ); + + if (UncMaster != NULL) { + (void) STRCAT( ValueArray, UncMaster ); + } + +/*lint -save -e767 */ // Don't complain about different definitions +#define WRITE_COMMA( ) \ + (void) STRCAT( ValueArray, (LPTSTR) TEXT(",") ) +/*lint -restore */ // Resume checking for different macro definitions + +/*lint -save -e767 */ // Don't complain about different definitions +#define WRITE_DWORD( Number ) \ + { \ + LPTSTR StrEnd = & ValueArray[ STRLEN( ValueArray ) ]; \ + (void) ULTOA( (Number), StrEnd, /* radix */ 10 ); \ + } +/*lint -restore */ // Resume checking for different macro definitions + + WRITE_COMMA(); + + WRITE_DWORD( LastUpdateTime ); // Seconds since 1970. + + WRITE_COMMA(); + + WRITE_DWORD( LockCount ); + + WRITE_COMMA(); + + WRITE_DWORD( LockTime ); // Seconds since 1970. + + IF_DEBUG(IMPAPI) { + NetpKdPrint(( PREFIX_REPL + "ImportDirWriteConfigValue: '" FORMAT_LPTSTR "' = '" + FORMAT_LPTSTR "'.\n", DirName, ValueArray )); + } + + // + // Write this value out to the config file/whatever. + // + ApiStatus = NetpSetConfigValue( + Handle, + DirName, // keyword is dir name + ValueArray); + // Fall through and log error if one happened. + +Cleanup: + // + // All done. + // + if ( Handle != NULL ) { + NET_API_STATUS CloseStatus; + + CloseStatus = NetpCloseConfigData( Handle ); + + // Return this error iff it is first error we've gotten. + if ( (ApiStatus == NO_ERROR) && (CloseStatus != NO_ERROR) ) { + ApiStatus = CloseStatus; + } + } + + if (ApiStatus != NO_ERROR) { + // Log error on server we were trying to access. + ReplErrorLog( + UncServerName, + NELOG_ReplSysErr, + ApiStatus, + NULL, + NULL ); + } + + return (ApiStatus); + +} // ImportDirWriteConfigData diff --git a/private/net/svcdlls/repl/common/impdir.h b/private/net/svcdlls/repl/common/impdir.h new file mode 100644 index 000000000..d38228c36 --- /dev/null +++ b/private/net/svcdlls/repl/common/impdir.h @@ -0,0 +1,259 @@ +/*++ + +Copyright (c) 1992-1993 Microsoft Corporation + +Module Name: + + ImpDir.h + +Abstract: + + This file contains structures, function prototypes, and definitions + for the replicator import directory worker routines. + +Author: + + John Rogers (JohnRo) 07-Jan-1992 + +Environment: + + User Mode - Win32 + Portable to any flat, 32-bit environment. (Uses Win32 typedefs.) + Requires ANSI C extensions: slash-slash comments, long external names. + +Notes: + + You must include LmCons.h and ReplDefs.h before this file. + +Revision History: + + 07-Jan-1992 JohnRo + Created. + 09-Jan-1992 JohnRo + Added ImportDirBuildApiRecord(). + Added IMPORT_DIR_SECTION_NAME equate. + Added ImportDir{Read,Write}ConfigData. + 16-Jan-1992 JohnRo + Corrected "Notes" comment above. + 20-Jan-1992 JohnRo + Netr prototypes are now generated by MIDL and put in repl.h. + 23-Jan-1992 JohnRo + Clarify units for time parameters. + Changed IMPORT_DIR_SECTION_NAME. + 27-Jan-1992 JohnRo + Added ImportDirSetState(). + Changed to use LPTSTR etc. + Changed to avoid use of client-specific data structure. + 09-Feb-1992 JohnRo + Added ImportDir{Start,Stop}Repl routines. + 13-Feb-1992 JohnRo + Moved section name equates to ConfName.h. + 19-Feb-1992 JohnRo + Added ImportDirIsApiRecordValid() and various other routines. + 21-Feb-1992 JohnRo + UncMaster parm is optional to ImportDirBuildApiRecord. + 21-Feb-1992 JohnRo + Changed ImportDirBuildApiRecord() so master name is not a UNC name. + 15-Mar-1992 JohnRo + Update registry with new values. + 23-Mar-1992 JohnRo + Added ImportDirReadClientList(). + 24-Mar-1992 JohnRo + UncMaster parm is optional to ImportDirWriteConfigData(). + 30-Jul-1992 JohnRo + Help PC-LINT understand ImportDirIsLevelValid(). + 25-Sep-1992 JohnRo + RAID 5494: repl svc does not maintain time stamp on import startup. + 29-Sep-1992 JohnRo + RAID 7962: Repl APIs in wrong role kill svc. + Also fix remote repl admin. + 01-Dec-1992 JohnRo + RAID 3844: remote NetReplSetInfo uses local machine type. + 13-Apr-1993 JohnRo + RAID 3107: locking directory over the net gives network path not found. + +--*/ + + +#ifndef _IMPDIR_ +#define _IMPDIR_ + + +// +// Import dir helper routines and macros: +// + + +// Allocate one or more API records for an import directory. Callable whether +// or not the replicator service is started. (Used in getinfo stub, getinfo +// worker, and enum stub.) +NET_API_STATUS +ImportDirAllocApiRecords ( + IN DWORD Level, + IN DWORD EntryCount, + OUT LPBYTE * BufPtr, + IN OUT LPBYTE *StringLocation // Points just past top of data. + ); + +NET_API_STATUS +ImportDirBuildApiRecord ( + IN DWORD Level, + IN LPTSTR DirName, + IN DWORD State, + IN LPTSTR MasterName OPTIONAL, // computer name (not UNC). + IN DWORD TimeOfLastUpdate, // Seconds since 1970. + IN DWORD LockCount, + IN DWORD TimeOfFirstLock, // Seconds since 1970. + OUT LPVOID Buffer, + IN OUT LPBYTE *StringLocation // Points just past top of data. + ); + +// Tells whether or not config data for this directory exists. +// Callable even if the replicator service is not started. +BOOL +ImportDirConfigDataExists ( + IN LPTSTR UncServerName OPTIONAL, + IN LPTSTR DirName // Caller must check dir name syntax. + ); + +NET_API_STATUS +ImportDirConfigSetInfo ( + IN LPTSTR UncServerName OPTIONAL, + IN LPTSTR DirName, + IN DWORD Level, + IN LPVOID Buf, + OUT LPDWORD ParmError OPTIONAL + ); + +// Delete config data for this directory. +// Returns NERR_UnknownDevDir if config data doesn't exist for this dir. +// Callable even if the replicator service is not started. +NET_API_STATUS +ImportDirDeleteConfigData ( + IN LPTSTR UncServerName OPTIONAL, + IN LPTSTR DirName // Caller must check dir name syntax. + ); + +// Callable even if the replicator service is not started. +NET_API_STATUS +ImportDirEnumApiRecords( + IN LPTSTR UncServerName OPTIONAL, + IN DWORD Level, + OUT LPBYTE * BufPtr, + IN DWORD PrefMaxSize, + OUT LPDWORD EntriesRead, + OUT LPDWORD TotalEntries + ); + +// Callable even if the replicator service is not started. +NET_API_STATUS +ImportDirGetApiRecord ( + IN LPTSTR UncServerName OPTIONAL, + IN LPTSTR DirName, + IN DWORD Level, + OUT LPBYTE * BufPtr + ); + +BOOL +ImportDirIsApiRecordValid ( + IN DWORD Level, + IN LPVOID ApiRecord, + OUT LPDWORD ParmError OPTIONAL + ); + +// BOOL +// ImportDirIsLevelValid( +// IN DWORD Level +// ); +// +#define ImportDirIsLevelValid(Level) \ + /*lint -e506 */ /* don't complain about constant values here */ \ + ( ((Level) <= 1 ) ? TRUE : FALSE ) \ + /*lint +e506 */ \ + +// Callable whether or not service is started. +// If service is running, assume caller has lock (any kind) on RCGlobalListLock. +NET_API_STATUS +ImportDirLockInRegistry( + IN LPTSTR UncServerName OPTIONAL, + IN LPTSTR DirName + ); + +// Parse config data for a single import directory. Callable whether or not +// the replicator service is started. +NET_API_STATUS +ImportDirParseConfigData ( + IN LPTSTR UncServerName OPTIONAL, + IN LPTSTR KeywordValue, + OUT LPDWORD StatePtr, + OUT LPTSTR MasterPtr, + OUT LPDWORD LastUpdateTimePtr, // Seconds since 1970. + OUT LPDWORD LockCountPtr, + OUT LPDWORD LockTimePtr // Seconds since 1970. + ); + +// Read import dirs into service's client list. +// Only callable as part of the service itself. +NET_API_STATUS +ImportDirReadClientList( + VOID + ); + +// Read config data for a single import directory. Callable whether or not +// the replicator service is started. +NET_API_STATUS +ImportDirReadConfigData ( + IN LPTSTR UncServerName OPTIONAL, + IN LPTSTR DirName, + OUT LPDWORD StatePtr, + OUT LPTSTR MasterPtr, + OUT LPDWORD LastUpdateTimePtr, // Seconds since 1970. + OUT LPDWORD LockCountPtr, + OUT LPDWORD LockTimePtr // Seconds since 1970. + ); + +// Change the state for a single import directory. +NET_API_STATUS +ImportDirSetState ( + IN LPTSTR DirName, + IN DWORD State // Must be REPL_STATE_ value. + ); + +// Start replicating (importing). +// Called when service starts or user does NetReplSetInfo() and changes role. +NET_API_STATUS +ImportDirStartRepl ( + IN BOOL ServiceIsStarting + ); + +// Stop replicating (importing). +// Called when service stops or user does NetReplSetInfo() and changes role. +NET_API_STATUS +ImportDirStopRepl ( + VOID + ); + +// Callable whether or not service is started. +// If service is running, assume caller has lock (any kind) on RCGlobalListLock. +NET_API_STATUS +ImportDirUnlockInRegistry( + IN LPTSTR UncServerName OPTIONAL, + IN LPTSTR DirName, + IN DWORD UnlockForce + ); + +// Write config data for a single import directory. Callable whether or not +// the replicator service is started. +NET_API_STATUS +ImportDirWriteConfigData ( + IN LPTSTR UncServerName OPTIONAL, + IN LPTSTR DirName, + IN DWORD State, + IN LPTSTR UncMaster OPTIONAL, + IN DWORD LastUpdateTime, // Seconds since 1970. + IN DWORD LockCount, + IN DWORD LockTime // Seconds since 1970. + ); + + +#endif // _IMPDIR_ diff --git a/private/net/svcdlls/repl/common/impenum.c b/private/net/svcdlls/repl/common/impenum.c new file mode 100644 index 000000000..0d03aba40 --- /dev/null +++ b/private/net/svcdlls/repl/common/impenum.c @@ -0,0 +1,321 @@ +/*++ + +Copyright (c) 1991-1993 Microsoft Corporation + +Module Name: + + ImpEnum.c + +Abstract: + + ImporDirEnumApiRecords. + +Author: + + John Rogers (JohnRo) 17-Dec-1991 + +Environment: + + User Mode - Win32 + +Revision History: + + 16-Nov-1992 JohnRo + RAID 1537: Repl APIs in wrong role kill svc. (Extracted from DLL stub.) + 01-Dec-1992 JohnRo + RAID 3844: remote NetReplSetInfo uses local machine type. + 10-Mar-1993 JohnRo + RAID 12871: replication UI shows nothing (adding entry while enumerating + results in empty list). + Made changes suggested by PC-LINT 5.0 + Use NetpKdPrint() where possible. + +--*/ + + +// These must be included first: + +#include <windows.h> // IN, DWORD, etc. +#include <lmcons.h> // NET_API_STATUS, etc. + +// These may be included in any order: + +#include <config.h> // LPNET_CONFIG_HANDLE, Netp config routines. +#include <confname.h> // SECT_NT_ equates. +#include <dirname.h> // ReplIsDirNameValid(). +#include <impdir.h> // My prototype. +#include <lmerr.h> // NERR_ and ERROR_ equates, NO_ERROR. +#include <lmerrlog.h> // NELOG_ equates. +#include <netdebug.h> // NetpAssert(), NetpKdPrint(), etc. +#include <prefix.h> // PREFIX_ equates. +#include <repldefs.h> // IF_DEBUG(), ReplErrorLog(), etc. +#include <strucinf.h> // NetpReplImportDirStructureInfo(). + + + +// Callable even if the replicator service is not started. +NET_API_STATUS +ImportDirEnumApiRecords( + IN LPTSTR UncServerName OPTIONAL, + IN DWORD Level, + OUT LPBYTE * BufPtr, + IN DWORD PrefMaxSize, + OUT LPDWORD EntriesRead, + OUT LPDWORD TotalEntries + ) + +{ + NET_API_STATUS ApiStatus; + + LPVOID ArrayEntry; + LPVOID ArrayStart = NULL; + DWORD EntriesAllocated = 0; + DWORD EntriesFound = 0; + BOOL FirstTime; + DWORD FixedEntrySize; + LPNET_CONFIG_HANDLE Handle = NULL; + LPBYTE StringLocation; + + UNREFERENCED_PARAMETER( PrefMaxSize ); + + IF_DEBUG( IMPAPI ) { + NetpKdPrint(( PREFIX_REPL + "ImportDirEnumApiRecords( " FORMAT_LPTSTR + " ): doing parameter checks...\n", + (UncServerName!=NULL) ? UncServerName : (LPTSTR) TEXT("local") + )); + } + + if ( ! ImportDirIsLevelValid( Level ) ) { + ApiStatus = ERROR_INVALID_LEVEL; + goto Cleanup; + } else if (BufPtr == NULL) { + ApiStatus = ERROR_INVALID_PARAMETER; + goto Cleanup; + } else if (EntriesRead == NULL) { + ApiStatus = ERROR_INVALID_PARAMETER; + goto Cleanup; + } else if (TotalEntries == NULL) { + ApiStatus = ERROR_INVALID_PARAMETER; + goto Cleanup; + } + + // + // Set outputs in case we run into an error. + // + + * BufPtr = NULL; + * EntriesRead = 0; + * TotalEntries = 0; + + // + // Figure-out the size of a fixed entry for this info level. + // + ApiStatus = NetpReplImportDirStructureInfo ( + Level, + PARMNUM_ALL, + TRUE, // want native sizes + NULL, // don't need data desc 16 + NULL, // don't need data desc 32 + NULL, // don't need data desc SMB + NULL, // don't need max size + & FixedEntrySize, + NULL ); // don't need string size + + NetpAssert( ApiStatus == NO_ERROR ); // Already checked args. + NetpAssert( FixedEntrySize > 0 ); + + // + // Open the right section of the config file/whatever. + // + ApiStatus = NetpOpenConfigDataEx( + & Handle, + UncServerName, + (LPTSTR) SECT_NT_REPLICATOR, // service name + (LPTSTR) SECT_NT_REPLICATOR_IMPORTS, // area under service + TRUE); // read-only + if (ApiStatus != NO_ERROR) { + + // Handle section not found as empty enum array (not error). + if (ApiStatus == NERR_CfgCompNotFound) { + ApiStatus = NO_ERROR; + goto Cleanup; + } + + goto Cleanup; + } + + // + // Loop, expanding buffer if necessary, until we get it large enough. + // + + do { + + // + // Count entries in config data. + // + ApiStatus = NetpNumberOfConfigKeywords ( + Handle, + & EntriesAllocated ); + + if (ApiStatus != NO_ERROR) { + goto Cleanup; + } else if (EntriesAllocated == 0) { + goto Cleanup; + } + + // + // Alloc and/or expand the array... + // + ApiStatus = ImportDirAllocApiRecords ( + Level, + EntriesAllocated, + (LPBYTE *) (LPVOID) & ArrayStart, + & StringLocation ); // Points just past top of data. + if (ApiStatus == NO_ERROR) { + NetpAssert( ArrayStart != NULL ); + } else { + goto Cleanup; + } + + // + // Go back and reread, filling-in the config data as we go. + // + + ArrayEntry = ArrayStart; + FirstTime = TRUE; + + while (ApiStatus == NO_ERROR) { + LPTSTR DirName; + DWORD LockCount; + DWORD State; + DWORD TimeOfFirstLock; // Seconds since 1970. + DWORD TimeOfLastUpdate; // Seconds since 1970. + TCHAR UncMaster[UNCLEN+1]; + LPTSTR ValueString; + + ApiStatus = NetpEnumConfigSectionValues ( + Handle, + & DirName, // Keyword - alloc and set ptr. + & ValueString, // Must be freed by NetApiBufferFree(). + FirstTime ); + + FirstTime = FALSE; + + if (ApiStatus == NO_ERROR) { + NetpAssert( DirName != NULL ); + NetpAssert( ValueString != NULL ); + + ++EntriesFound; + if (EntriesFound > EntriesAllocated) { + EntriesFound = 0; + NetpMemoryFree( ArrayStart ); + ArrayStart = NULL; + ApiStatus = ERROR_MORE_DATA; + break; // exit per-entry loop and try again + } + + if ( !ReplIsDirNameValid( DirName ) ) { + // BUGBUG: perhaps delete entry, log event, and continue? + ApiStatus = ERROR_INVALID_DATA; + NetpMemoryFree( DirName ); + NetpMemoryFree( ValueString ); + goto Cleanup; + } + + // + // Parse the value string... + // + ApiStatus = ImportDirParseConfigData ( + UncServerName, + ValueString, + & State, + UncMaster, + & TimeOfLastUpdate, // Seconds since 1970. + & LockCount, + & TimeOfFirstLock ); // Seconds since 1970. + + NetpMemoryFree( ValueString ); + + if (ApiStatus == NO_ERROR) { + LPTSTR MasterName; + NetpAssert( ArrayEntry != NULL ); + + if (*UncMaster) { + MasterName = UncMaster + 2; // Chg from UNC to non. + } else { + MasterName = NULL; + } + + // + // Build API record for this entry. + // + ApiStatus = ImportDirBuildApiRecord ( + Level, + DirName, + State, // State when svc was running. + MasterName, + TimeOfLastUpdate, // Seconds since 1970. + LockCount, + TimeOfFirstLock, // Seconds since 1970. + ArrayEntry, + & StringLocation ); + if (ApiStatus != NO_ERROR) { + NetpKdPrint(( PREFIX_REPL + "ImportDirEnumApiRecords: error " + FORMAT_API_STATUS " from imp build.\n", + ApiStatus )); + NetpAssert( FALSE ); + goto Cleanup; + } + + ArrayEntry = NetpPointerPlusSomeBytes( + ArrayEntry, FixedEntrySize ); + } + NetpMemoryFree( DirName ); + + } + + } // while not error (may be NERR_CfgParamNotFound at end). + + if (ApiStatus == NERR_CfgParamNotFound) { + ApiStatus = NO_ERROR; + } else { + NetpAssert( ApiStatus != NO_ERROR ); + goto Cleanup; + } + + } while (ApiStatus == ERROR_MORE_DATA); + + // + // All done. + // + +Cleanup: + + if (Handle != NULL) { + (VOID) NetpCloseConfigData( Handle ); + } + + NetpAssert( ApiStatus != ERROR_MORE_DATA ); + if (ApiStatus == NO_ERROR) { + * BufPtr = ArrayStart; + * EntriesRead = EntriesFound; + * TotalEntries = EntriesFound; + } else { + NetpKdPrint(( PREFIX_REPL + "ImportDirEnumApiRecords: returning status " FORMAT_API_STATUS + ".\n", ApiStatus )); + + // Log the error. + ReplErrorLog( + UncServerName, // log here and there. + NELOG_ReplSysErr, + ApiStatus, + NULL, // no str1 + NULL ); // no str2 + } + + return ApiStatus; + +} diff --git a/private/net/svcdlls/repl/common/impget.c b/private/net/svcdlls/repl/common/impget.c new file mode 100644 index 000000000..54a9e0513 --- /dev/null +++ b/private/net/svcdlls/repl/common/impget.c @@ -0,0 +1,149 @@ +/*++ + +Copyright (c) 1992 Microsoft Corporation + +Module Name: + + ImpGet.c + +Abstract: + + Read an API record with import directory info from the registry. + Callable even if the replicator service is not started. + +Author: + + John Rogers (JohnRo) 09-Nov-1992 + +Environment: + + User Mode - Win32 + +Revision History: + + 09-Nov-1992 JohnRo + Created for RAID 7962: Repl APIs in wrong role kill svc. + +--*/ + + +// These must be included first: + +//#include <nt.h> // Needed by <config.h> temporarily. +//#include <ntrtl.h> // Needed by <config.h> temporarily. +#include <windef.h> // IN, DWORD, etc. + +#include <lmcons.h> // NET_API_STATUS, etc. +//#include <rap.h> // Needed by <strucinf.h>. +//#include <repldefs.h> // Needed by <impdir.h>. +//#include <rpc.h> // Needed by <netrpc.h>. + +// These may be included in any order: + +//#include <config.h> // LPNET_CONFIG_HANDLE, Netp config routines. +//#include <confname.h> // SECT_NT_ equates. +#include <dirname.h> // ReplIsDirNameValid(). +#include <impdir.h> // My ptototype, ImportDirIsApiRecordValid(), etc. +#include <lmapibuf.h> // NetApiBufferFree(). +//#include <lmrepl.h> // My prototypes, etc. +//#include <lmsvc.h> // SERVICE_ equates. +#include <netdebug.h> // NetpAssert(). +//#include <netlib.h> // NetpSetParmError() macro. +//#include <netrpc.h> // NET_REMOTE macros. +//#include <prefix.h> // PREFIX_ equates. +//#include <repl.h> // MIDL-generated NetrRepl prototypes. +//#include <rpcutil.h> // GENERIC_INFO_CONTAINER, etc. +//#include <strucinf.h> // NetpReplImportDirStructureInfo(). +#include <winerror.h> // ERROR_ equates, NO_ERROR. + + + +NET_API_STATUS +ImportDirGetApiRecord ( + IN LPTSTR UncServerName OPTIONAL, + IN LPTSTR DirName, + IN DWORD Level, + OUT LPBYTE * BufPtr + ) +{ + NET_API_STATUS ApiStatus; + LPVOID ApiRecord = NULL; + DWORD LockCount; + LPTSTR MasterName; + DWORD State; + LPBYTE StringLocation; // Points just past top of data. + DWORD TimeOfFirstLock; // Seconds since 1970. + DWORD TimeOfLastUpdate; // Seconds since 1970. + TCHAR UncMaster[UNCLEN+1]; + + if ( !ReplIsDirNameValid( DirName )) { + ApiStatus = ERROR_INVALID_PARAMETER; + goto Cleanup; + } else if ( !ImportDirIsLevelValid( Level ) ) { + ApiStatus = ERROR_INVALID_LEVEL; + goto Cleanup; + } else if (BufPtr == NULL) { + ApiStatus = ERROR_INVALID_PARAMETER; + goto Cleanup; + } + + // + // Read config data for a single import directory. + // + ApiStatus = ImportDirReadConfigData ( + UncServerName, + DirName, + & State, + UncMaster, + & TimeOfLastUpdate, // Seconds since 1970. + & LockCount, + & TimeOfFirstLock ); // Seconds since 1970. + + if (ApiStatus != NO_ERROR) { + goto Cleanup; + } + + ApiStatus = ImportDirAllocApiRecords ( + Level, + 1, // only 1 record. + (LPBYTE *) & ApiRecord, // alloc and set ptr + (LPBYTE *) & StringLocation ); // Points just past top of data. + if (ApiStatus != NO_ERROR) { + goto Cleanup; + } + NetpAssert( ApiRecord != NULL ); + + if (*UncMaster) { + MasterName = UncMaster + 2; // Chg from UNC to non. + } else { + MasterName = NULL; + } + + ApiStatus = ImportDirBuildApiRecord ( + Level, + DirName, + State, + MasterName, + TimeOfLastUpdate, // Seconds since 1970 + LockCount, + TimeOfFirstLock, // Seconds since 1970. + ApiRecord, + (LPBYTE *) (LPVOID) & StringLocation); + NetpAssert( ApiStatus == NO_ERROR ); // We checked all parms. + + +Cleanup: + + if (ApiStatus == NO_ERROR) { + NetpAssert( ApiRecord != NULL ); + *BufPtr = ApiRecord; + } else { + *BufPtr = NULL; + if (ApiRecord != NULL) { + (VOID) NetApiBufferFree( ApiRecord ); + } + } + + return ApiStatus; + +} diff --git a/private/net/svcdlls/repl/common/implock.c b/private/net/svcdlls/repl/common/implock.c new file mode 100644 index 000000000..c94a70f05 --- /dev/null +++ b/private/net/svcdlls/repl/common/implock.c @@ -0,0 +1,172 @@ +/*++ + +Copyright (c) 1992-1993 Microsoft Corporation + +Module Name: + + ImpLock.c + +Abstract: + + Routines to update lock fields in registry (for import dirs). + +Author: + + John Rogers (JohnRo) 15-Mar-1992 + +Environment: + + User Mode - Win32 + +Notes: + + This file is extremely similar to ExpLock.c. If you fix any bugs here, + make sure they're reflected there, and vice versa. + +Revision History: + + 15-Mar-1992 JohnRo + Update registry with new values. + 29-Sep-1992 JohnRo + Also fix remote repl admin. + 13-Apr-1993 JohnRo + RAID 3107: locking directory over the net gives network path not found. + Made changes suggested by PC-LINT 5.0 + 30-Apr-1993 JohnRo + Use NetpKdPrint() where possible. + +--*/ + + +// These must be included first: + +#include <windef.h> // IN, DWORD, etc. +#include <lmcons.h> // NET_API_STATUS, etc. + +// These may be included in any order: + +#include <dirname.h> // ReplIsDirNameValid(). +#include <impdir.h> // My prototypes, etc. +#include <lmrepl.h> // REPL_FORCE_ equates. +#include <netdebug.h> // NetpKdPrint(). +#include <repldefs.h> // Stuff. +#include <winerror.h> // NO_ERROR, ERROR_ equates. + + + +// Callable whether or not service is started. +// If service is running, assume caller has lock (any kind) on RCGlobalListLock. +NET_API_STATUS +ImportDirLockInRegistry( + IN LPTSTR UncServerName OPTIONAL, + IN LPTSTR DirName + ) +{ + NET_API_STATUS ApiStatus; + DWORD LockCount; + DWORD State; + TCHAR UncMaster[UNCLEN+1]; + DWORD TimeOfFirstLock; // Seconds since 1970. + DWORD TimeOfLastUpdate; // Seconds since 1970. + + IF_DEBUG(REPL) { + NetpKdPrint(( "ImportDirLockInRegistry( " FORMAT_LPTSTR + "): beginnning...\n", + (UncServerName!=NULL) ? UncServerName : (LPTSTR) TEXT("local") )); + } + + if ( !ReplIsDirNameValid( DirName )) { + return (ERROR_INVALID_PARAMETER); + } + + // Read config data for a single import directory. + ApiStatus = ImportDirReadConfigData ( + UncServerName, + DirName, + & State, + UncMaster, + & TimeOfLastUpdate, // Seconds since 1970. + & LockCount, + & TimeOfFirstLock ); // Seconds since 1970. + + if (ApiStatus == NO_ERROR) { + + ApiStatus = ReplIncrLockFields( + & LockCount, + & TimeOfFirstLock ); + } + if (ApiStatus == NO_ERROR) { + ApiStatus = ImportDirWriteConfigData ( + UncServerName, + DirName, + State, + (*UncMaster) ? UncMaster : NULL, + TimeOfLastUpdate, // Seconds since 1970. + LockCount, + TimeOfFirstLock ); // Seconds since 1970. + } + + return ApiStatus; + +} // ImportDirLockInRegistry + + +// Callable whether or not service is started. +// If service is running, assume caller has lock (any kind) on RCGlobalListLock. +NET_API_STATUS +ImportDirUnlockInRegistry( + IN LPTSTR UncServerName OPTIONAL, + IN LPTSTR DirName, + IN DWORD UnlockForce + ) +{ + NET_API_STATUS ApiStatus; + DWORD LockCount; + DWORD State; + TCHAR UncMaster[UNCLEN+1]; + DWORD TimeOfFirstLock; // Seconds since 1970. + DWORD TimeOfLastUpdate; // Seconds since 1970. + + IF_DEBUG(REPL) { + NetpKdPrint(( "ImportDirUnlockInRegistry( " FORMAT_LPTSTR + "): beginnning...\n", + (UncServerName!=NULL) ? UncServerName : (LPTSTR) TEXT("local") )); + } + + if ( !ReplIsDirNameValid( DirName )) { + return (ERROR_INVALID_PARAMETER); + } + + // Read config data for a single import directory. + ApiStatus = ImportDirReadConfigData ( + UncServerName, + DirName, + & State, + UncMaster, + & TimeOfLastUpdate, // Seconds since 1970. + & LockCount, + & TimeOfFirstLock ); // Seconds since 1970. + + if (ApiStatus == NO_ERROR) { + + ApiStatus = ReplDecrLockFields( + & LockCount, + & TimeOfFirstLock, + UnlockForce ); + } + if (ApiStatus == NO_ERROR) { + // Write the new or revised data. + ApiStatus = ImportDirWriteConfigData ( + UncServerName, + DirName, + State, + (*UncMaster) ? UncMaster : NULL, + TimeOfLastUpdate, // Seconds since 1970. + LockCount, + TimeOfFirstLock ); // Seconds since 1970. + + } + + return ApiStatus; + +} // ImportDirUnlockInRegistry diff --git a/private/net/svcdlls/repl/common/imports.h b/private/net/svcdlls/repl/common/imports.h new file mode 100644 index 000000000..5a1f5577c --- /dev/null +++ b/private/net/svcdlls/repl/common/imports.h @@ -0,0 +1,58 @@ +/*++ + +Copyright (c) 1992 Microsoft Corporation + +Module Name: + + imports.h + +Abstract: + + This file allows us to include standard system header files in the + .idl file. The main .idl file imports a file called import.idl. + This allows the .idl file to use the types defined in these header + files. It also causes the following line to be added in the + MIDL generated header file: + + #include "imports.h" + + Thus these types are available to the RPC stub routines as well. + +Author: + + John Rogers (JohnRo) 17-Jan-1992 + +Revision History: + + 17-Jan-1992 JohnRo + Created the repl service RPC stuff from Rita's workstation RPC stuff. + 24-Jan-1992 JohnRo + Changed to use LPTSTR etc. + 16-Feb-1992 JohnRo + Corrected use of LPTSTR. + +--*/ + + +#include <windef.h> +#include <lmcons.h> + +#ifdef MIDL_PASS + +#ifdef UNICODE +#define LPTSTR [string] wchar_t * +#else +#define LPTSTR [string] LPTSTR +#endif + +#define LPSTR [string] char_t * +#define LPCSTR [string] char_t * +#define LPWSTR [string] wchar_t * +#define LPCWSTR [string] wchar_t * + +//#define LPSTR [string] LPSTR +#define BOOL DWORD + +#endif + +#include <lmrepl.h> diff --git a/private/net/svcdlls/repl/common/impstate.c b/private/net/svcdlls/repl/common/impstate.c new file mode 100644 index 000000000..ab467aa2e --- /dev/null +++ b/private/net/svcdlls/repl/common/impstate.c @@ -0,0 +1,124 @@ +/*++ + +Copyright (c) 1992-1993 Microsoft Corporation + +Module Name: + + ImpState.c + +Abstract: + + This file contains ImportDirSetState(). + +Author: + + John Rogers (JohnRo) 27-Jan-1992 + +Environment: + + User Mode - Win32 + Portable to any flat, 32-bit environment. (Uses Win32 typedefs.) + Requires ANSI C extensions: slash-slash comments, long external names. + +Revision History: + + 27-Jan-1992 JohnRo + Created. + 26-Mar-1992 JohnRo + Added more argument checking. + 26-Mar-1992 JohnRo + Don't pass ImportDirWriteConfigData() UncMaster as ptr to null char. + 29-Sep-1992 JohnRo + Fix remote repl admin. + 04-Dec-1992 JohnRo + Handle unexpected errors better. + Use PREFIX_ equates. + Made changes suggested by PC-LINT 5.0 + 30-Apr-1993 JohnRo + Use NetpKdPrint() where possible. + +--*/ + + +#include <windef.h> // Win32 type definitions +#include <lmcons.h> // NET_API_STATUS, UNCLEN. + +#include <dirname.h> // ReplIsDirNameValid(). +#include <impdir.h> // My prototypes, IMPORT_DIR_SECTION_NAME. +#include <lmerr.h> // ERROR_, NERR_, NO_ERROR equates. +#include <netdebug.h> // NetpAssert(). +#include <prefix.h> // PREFIX_ equates. +#include <repldefs.h> // IF_DEBUG(), ReplIsStateValid(), etc. +#include <tstr.h> // TCHAR_EOS. + + +// Change the state for a single import directory. +// Creates an entry with defaults if necessary. +NET_API_STATUS +ImportDirSetState ( + IN LPTSTR DirName, + IN DWORD State + ) +{ + NET_API_STATUS ApiStatus; + DWORD LastUpdateTime; // Seconds since 1970. + DWORD LockCount; + DWORD LockTime; // Seconds since 1970. + DWORD OldState; + TCHAR UncMaster[UNCLEN+1]; + + NetpAssert( ReplIsDirNameValid( DirName ) ); + NetpAssert( ReplIsStateValid( State ) ); + + // Read config data for a this import directory. + ApiStatus = ImportDirReadConfigData ( + NULL, // no server name + DirName, + & OldState, + UncMaster, + & LastUpdateTime, // Seconds since 1970. + & LockCount, + & LockTime); // Seconds since 1970. + + if (ApiStatus == NERR_UnknownDevDir) { + + // Set defaults. + LastUpdateTime = 0; + LockCount = 0; + LockTime = 0; + UncMaster[0] = TCHAR_EOS; + + } else if (ApiStatus != NO_ERROR) { + + NetpKdPrint(( PREFIX_REPL_CLIENT + "ImportDirSetState: unexpected ret " + FORMAT_API_STATUS " from ImportDirReadConfigData(" + FORMAT_LPTSTR ").\n", + ApiStatus, DirName )); + goto Cleanup; + + } + + // Write revised config data for this directory. + ApiStatus = ImportDirWriteConfigData ( + NULL, // no server name + DirName, + State, + (*UncMaster) ? UncMaster : NULL, + LastUpdateTime, // Seconds since 1970. + LockCount, + LockTime ); // Seconds since 1970. + + if (ApiStatus != NO_ERROR) { + + NetpKdPrint(( PREFIX_REPL_CLIENT + "ImportDirSetState: unexpected ret " + FORMAT_API_STATUS " from ImportDirWriteConfigData(" + FORMAT_LPTSTR ").\n", + ApiStatus, DirName )); + } + +Cleanup: + return (ApiStatus); + +} // ImportDirSetState diff --git a/private/net/svcdlls/repl/common/impvalid.c b/private/net/svcdlls/repl/common/impvalid.c new file mode 100644 index 000000000..2fc7eeb6d --- /dev/null +++ b/private/net/svcdlls/repl/common/impvalid.c @@ -0,0 +1,118 @@ +/*++ + +Copyright (c) 1992 Microsoft Corporation + +Module Name: + + ImpValid.c + +Abstract: + + This file contains ImportDirIsApiRecordValid(). + +Author: + + John Rogers (JohnRo) 22-Jan-1992 + +Environment: + + Runs under Windows NT. + Requires ANSI C extensions: slash-slash comments, long external names. + +Notes: + + This code assumes that the info levels are subsets of each other. + +Revision History: + + 18-Feb-1992 JohnRo + Added ImportDirIsApiRecordValid(). + 21-Feb-1992 JohnRo + rpid1_mastername is a UNC name. + 27-Feb-1992 JohnRo + Check lock fields for validity. + rpid1_mastername is optional. + +--*/ + + +// These must be included first: + +#include <windef.h> // IN, VOID, LPTSTR, etc. +#include <lmcons.h> // NET_API_STATUS, PARM equates, etc. +#include <repldefs.h> // IF_DEBUG(), ReplIsIntegrityValid(), etc. + +// These can be in any order: + +#include <dirname.h> // ReplIsDirNameValid(). +#include <impdir.h> // My prototype. +#include <lmrepl.h> // LPREPL_EDIR_INFO_1, REPL_EXTENT_ stuff, etc. +#include <names.h> // NetpIsUncComputerNameValid(). +#include <netlib.h> // NetpSetParmError(). + + +BOOL +ImportDirIsApiRecordValid ( + IN DWORD Level, + IN LPVOID Buf, + OUT LPDWORD ParmError OPTIONAL + ) + +{ + LPREPL_IDIR_INFO_1 ApiRecord; // Superset info level. + + // + // First, make sure level is valid and there's actually a struct there. + // + NetpSetParmError( PARM_ERROR_UNKNOWN ); // Assume error until proven... + if (Level > 1) { + return (FALSE); // No, it's not valid. + } + if (Buf == NULL) { + return (FALSE); // No, it's not valid. + } + ApiRecord = Buf; + + // + // Check item(s) common to all levels. + // + if ( ! ReplIsDirNameValid(ApiRecord->rpid1_dirname) ) { + NetpSetParmError( 1 ); // Error in first field in ApiRecord. + return (FALSE); // No, it's not valid. + } + + // + // Check items unique to level 1. + // + if (Level > 0) { + if ( ! ReplIsStateValid(ApiRecord->rpid1_state) ) { + NetpSetParmError( 2 ); // Error in second field in ApiRecord. + return (FALSE); // No, it's not valid. + } + + if ( ApiRecord->rpid1_mastername != NULL ) { + if ( ! NetpIsUncComputerNameValid(ApiRecord->rpid1_mastername) ) { + NetpSetParmError( 3 ); // Error in third field in ApiRecord. + return (FALSE); // No, it's not valid. + } + } + + + // BUGBUG: No check possible for the following field? + // 4 (last_update_time) + + if ( !ReplAreLockFieldsValid( ApiRecord->rpid1_lockcount, + ApiRecord->rpid1_locktime) ) { + NetpSetParmError( 5 ); // Error in fifth/sixth field. + return (FALSE); // No, it's not valid. + } + + } + + // + // Everything went OK. Tell caller. + // + NetpSetParmError( PARM_ERROR_NONE ); + return (TRUE); // Yes, it's valid. + +} diff --git a/private/net/svcdlls/repl/common/iniparm.h b/private/net/svcdlls/repl/common/iniparm.h new file mode 100644 index 000000000..861f8f0bf --- /dev/null +++ b/private/net/svcdlls/repl/common/iniparm.h @@ -0,0 +1,87 @@ +/*++ + +Copyright (c) 1987-1992 Microsoft Corporation + +Module Name: + iniparm.h + +Abstract: + Function prototypes and some global data + +Author: + Ported from Lan Man 2.x + +Environment: + Contains NT-specific code. + Requires ANSI C extensions: slash-slash comments, long external names. + +Revision History: + 10/23/91 (madana) + ported to NT. Converted to NT style. + 20-Jan-1992 JohnRo + More changes suggested by PC-LINT. + Removed support for lanman dir switch and/or config keyword. + The tryuser variable should be treated as a BOOL. + 24-Jan-1992 JohnRo + Added KEYWORD_ equates (for config use) and got rid of SW_ equates. + Added default equates for integrity and extent. + Changed BOTH_SW etc to be TCHARs. + Moved current role from P_repl_sw to ReplGlobalRole. + Use REPL_ROLE_ equates just like the APIs do. + 13-Feb-1992 JohnRo + Renamed KEYWORD_ equates to REPL_KEYWORD_ and moved to <confname.h>. + Got rid of DEFAULT_REPL equate. Ditto DEFAULT_EXPORTPATH etc. + 29-Jul-1992 JohnRo + RAID 2650: repl svc should handle new subdirs. + + +--*/ + + +#ifndef _INIPARM_ +#define _INIPARM_ + + +// default parameters + +//#define DEFAULT_REPL NULL + +//#define DEFAULT_EXPPATH NULL +//#define DEFAULT_IMPPATH NULL + +#define DEFAULT_EXPLIST NULL +#define DEFAULT_IMPLIST NULL + +#define DEFAULT_TRYUSER TRUE + +#define DEFAULT_INTEGRITY REPL_INTEGRITY_FILE +#define DEFAULT_EXTENT REPL_EXTENT_TREE + +#define DEFAULT_STATE REPL_STATE_NEVER_REPLICATED + + +// parameter range + +#define DEFAULT_LOGON NULL +#define DEFAULT_PASSWD NULL +#define DEFAULT_SYNC 5 +#define MAX_SYNC 60 +#define MIN_SYNC 1 +#define DEFAULT_PULSE 3 +#define MAX_PULSE 10 +#define MIN_PULSE 1 +#define DEFAULT_GUARD 2 +#define MAX_GUARD 30 +#define MIN_GUARD 0 +#define DEFAULT_RANDOM 60 +#define MAX_RANDOM 120 +#define MIN_RANDOM 1 + + +// +// (Global config variables used to be declared here. +// They are now declared in ReplGbl.h --JohnRo, 24-Jan-1992.) +// + + +#endif // _INIPARM_ diff --git a/private/net/svcdlls/repl/common/lstvalid.c b/private/net/svcdlls/repl/common/lstvalid.c new file mode 100644 index 000000000..20e853a06 --- /dev/null +++ b/private/net/svcdlls/repl/common/lstvalid.c @@ -0,0 +1,162 @@ +/*++ + +Copyright (c) 1987-1993 Microsoft Corporation + +Module Name: + + LstValid.c + +Abstract: + + ReplConfigIsListValid() is used to validate the syntax of export lists + and import lists. No existence checking is done. + +Author: + + John Rogers, using code ported from Lan Man 2.x + +Environment: + + Requires ANSI C extensions: slash-slash comments, long external names. + Tab size is set to 4. + +Revision History: + + 14-Aug-1992 JohnRo + RAID 3601: repl APIs should checked import & export lists. + (Extracted this code from repl/server/master.c to help track down bogus + import/export lists.) + 27-Aug-1992 JohnRo + RAID 4611: repl: fix import/export lists. + 05-Jan-1993 JohnRo + Repl WAN support. + Made changes suggested by PC-LINT 5.0 + 30-Apr-1993 JohnRo + Use NetpKdPrint() where possible. + + +--*/ + +// These must be included first: + +#include <windows.h> +#include <lmcons.h> + +// These may be included in any order: + +#include <netdebug.h> // NetpKdPrint(), FORMAT_ equates, etc. +#include <netlib.h> // NetpMemoryAllocate(), NetpIsServerStarted(). +#include <icanon.h> +#include <prefix.h> // PREFIX_ equates. +#include <repldefs.h> // IF_DEBUG(), etc. +#include <replconf.h> // My prototypes. +#include <tstr.h> // STRSIZE(), TCHAR_EOS. + + +BOOL +ReplConfigIsListValid( + IN LPTSTR UncanonList OPTIONAL + ) + +/*++ + +Routine Description: + + Makes sure the synax of List is valid. + Callable whether or not service is started. + +Arguments: + + UncanonList - optionally points to a semicolon-separated list of domain + names (e.g. TEXT("MyDomain")) and server names (e.g. + TEXT("SomeServer")). + +Return Value: + + BOOL - TRUE iff List has valid syntax. + +--*/ +{ + NET_API_STATUS ApiStatus; + DWORD EntryCount; + LPTSTR CanonList; + DWORD CanonListSize; + + // + // Handle simple cases first. + // + + if (UncanonList == NULL) { + return (TRUE); // yes, syntax is valid. + } + if (*UncanonList == TCHAR_EOS) { + return (TRUE); // yes, syntax is valid. + } + + // + // Allocate temp space for parsed list. + // + + CanonListSize = STRSIZE( UncanonList ); + + CanonList = NetpMemoryAllocate( CanonListSize ); + + if (CanonList == NULL) { + + NetpKdPrint(( PREFIX_REPL + "ReplConfigIsListValid() can't allocate memory for " + "CanonList.\n" )); + + return (FALSE); // can't tell if syntax is valid, so assume not. + } + + IF_DEBUG( REPL ) { + NetpKdPrint(( PREFIX_REPL + "ReplConfigIsListValid before canon:\n" )); + NetpDbgDisplayReplList( + "uncanon list", + UncanonList ); + } + + // + // Do the actual parse. + // + + ApiStatus = I_NetListCanonicalize(NULL, + UncanonList, + (LPTSTR) LIST_DELIMITER_STR_UI, + CanonList, + CanonListSize, + &EntryCount, + NULL, // PathTypes + 0, // PathTypesLen + (NAMETYPE_COMPUTER | + OUTLIST_TYPE_API | + INLC_FLAGS_MULTIPLE_DELIMITERS | + INLC_FLAGS_CANONICALIZE + )); + + if (ApiStatus != NO_ERROR) { + + NetpKdPrint(( PREFIX_REPL + "ReplConfigIsListValid() is in trouble calling " + "I_NetListCanonicalize, ApiStatus is " FORMAT_API_STATUS + "\n", ApiStatus )); + + NetpMemoryFree(CanonList); + + return (FALSE); // syntax is not valid, so say so. + } + + IF_DEBUG( REPL ) { + NetpKdPrint(( PREFIX_REPL + "ReplConfigIsListValid after canon:\n" )); + NetpDbgDisplayReplList( + "canon list", + CanonList ); + } + + NetpMemoryFree( CanonList ); + + return (TRUE); // yes, syntax is valid. +} diff --git a/private/net/svcdlls/repl/common/makefile b/private/net/svcdlls/repl/common/makefile new file mode 100644 index 000000000..6ee4f43fa --- /dev/null +++ b/private/net/svcdlls/repl/common/makefile @@ -0,0 +1,6 @@ +# +# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source +# file to this component. This file merely indirects to the real make file +# that is shared by all the components of NT OS/2 +# +!INCLUDE $(NTMAKEENV)\makefile.def diff --git a/private/net/svcdlls/repl/common/replbld.c b/private/net/svcdlls/repl/common/replbld.c new file mode 100644 index 000000000..b20694427 --- /dev/null +++ b/private/net/svcdlls/repl/common/replbld.c @@ -0,0 +1,190 @@ +/*++ + +Copyright (c) 1992-1993 Microsoft Corporation + +Module Name: + + ReplBld.c + +Abstract: + + This file contains ReplConfigAllocAndBuildApiRecord(). + +Author: + + John Rogers (JohnRo) 23-Jan-1992 + +Environment: + + User Mode - Win32 + Portable to any flat, 32-bit environment. (Uses Win32 typedefs.) + Requires ANSI C extensions: slash-slash comments, long external names. + +Revision History: + + 23-Jan-1992 JohnRo + Created. + 24-Jan-1992 JohnRo + Changed to use LPTSTR etc. + 18-Feb-1992 JohnRo + Validate more of caller's parms. + Added assertion check of built record. + 11-Mar-1992 JohnRo + Fixed an error code. + 30-Apr-1993 JohnRo + Use NetpKdPrint() where possible. + Use PREFIX_ equates. + +--*/ + + +#include <windef.h> // IN, DWORD, etc. +#include <lmcons.h> // LAN Manager common definitions +#include <repldefs.h> // IF_DEBUG(). + +#include <align.h> // ALIGN_ equates. +#include <lmapibuf.h> // NetApiBufferAllocate(). +#include <lmrepl.h> // LMREPL_INFO_0. +#include <netdebug.h> // NetpKdPrint(), etc. +#include <netlib.h> // NetpCopyDataToBuffer(), etc. +#include <prefix.h> // PREFIX_ equates. +#include <replconf.h> // My prototype. +#include <tstr.h> // STRLEN(). +#include <winerror.h> // ERROR_ equates, NO_ERROR. + + +#define POSSIBLE_STRSIZE(s) ((s) ? STRSIZE(s) : 0) + + +// Allocate and build a repl config API record. Callable whether or not +// the replicator service is started. +NET_API_STATUS +ReplConfigAllocAndBuildApiRecord ( + IN DWORD Level, + IN DWORD Role, + IN LPTSTR ExportPath OPTIONAL, + IN LPTSTR ExportList OPTIONAL, + IN LPTSTR ImportPath OPTIONAL, + IN LPTSTR ImportList OPTIONAL, + IN LPTSTR LogonUserName OPTIONAL, + IN DWORD Interval, + IN DWORD Pulse, + IN DWORD GuardTime, + IN DWORD Random, + OUT LPBYTE * BufPtr // Alloc and set pointer. + ) + + +{ + NET_API_STATUS ApiStatus; + LPREPL_INFO_0 Buffer; + LPVOID OutFixedDataEnd; + DWORD SizeNeeded; + LPBYTE StringLocation; + + // + // Check for caller's errors. + // + if ( Level != 0 ) { + return (ERROR_INVALID_LEVEL); + } else if (BufPtr == NULL) { + return (ERROR_INVALID_PARAMETER); + } + * BufPtr = NULL; // Test for memory access fault. + if ( !ReplIsIntervalValid(Interval) ) { + return (ERROR_INVALID_PARAMETER); + } else if ( !ReplIsPulseValid( Pulse ) ) { + return (ERROR_INVALID_PARAMETER); + } else if ( !ReplIsGuardTimeValid( GuardTime ) ) { + return (ERROR_INVALID_PARAMETER); + } else if ( !ReplIsRandomValid( Random ) ) { + return (ERROR_INVALID_PARAMETER); + } + + ApiStatus = ReplCheckAbsPathSyntax( ExportPath ); + if (ApiStatus != NO_ERROR) { + return (ERROR_INVALID_PARAMETER); + } + + ApiStatus = ReplCheckAbsPathSyntax( ImportPath ); + if (ApiStatus != NO_ERROR) { + return (ERROR_INVALID_PARAMETER); + } + + // BUGBUG: Check ImportList and ExportList. + // BUGBUG: Check LogonUserName. + + // + // Compute how much space we'll need and allocate it. + // + SizeNeeded = sizeof(REPL_INFO_0) + + POSSIBLE_STRSIZE(ExportPath) + + POSSIBLE_STRSIZE(ExportList) + + POSSIBLE_STRSIZE(ImportPath) + + POSSIBLE_STRSIZE(ImportList) + + POSSIBLE_STRSIZE(LogonUserName); + + ApiStatus = NetApiBufferAllocate( + SizeNeeded, + (LPVOID *) & Buffer); + if (ApiStatus != NO_ERROR) { + return (ApiStatus); + } + NetpAssert( Buffer != NULL ); + + // + // Fill in the numbers in the structure. + // + + Buffer->rp0_role = Role; + Buffer->rp0_interval = Interval; + Buffer->rp0_pulse = Pulse; + Buffer->rp0_guardtime = GuardTime; + Buffer->rp0_random = Random; + + // + // Do the strings... + // + + OutFixedDataEnd = NetpPointerPlusSomeBytes( Buffer, sizeof(REPL_INFO_0) ); + StringLocation = NetpPointerPlusSomeBytes( Buffer, SizeNeeded ); + +#define COPY_TSTRING_FIELD( destField, srcVar ) \ + { \ + if (srcVar != NULL) { \ + BOOL CopyOK; \ + CopyOK = NetpCopyDataToBuffer( \ + (LPVOID) srcVar, \ + STRSIZE(srcVar), \ + OutFixedDataEnd, \ + & StringLocation, \ + (LPVOID) & Buffer->rp0_ ## destField, \ + ALIGN_TCHAR); \ + NetpAssert(CopyOK); \ + } else { \ + Buffer->rp0_ ## destField = NULL; \ + } \ + } + + COPY_TSTRING_FIELD( exportpath, ExportPath ); + COPY_TSTRING_FIELD( exportlist, ExportList ); + COPY_TSTRING_FIELD( importpath, ImportPath ); + COPY_TSTRING_FIELD( importlist, ImportList ); + COPY_TSTRING_FIELD( logonusername, LogonUserName ); + + // + // All done. + // + + IF_DEBUG(REPLAPI) { + NetpKdPrint(( PREFIX_REPL + "ReplConfigAllocAndBuildApiRecord: built structure...\n" )); + NetpDbgDisplayRepl( Level, Buffer ); + } + + NetpAssert( ReplConfigIsApiRecordValid( Level, Buffer, NULL ) ); + + * BufPtr = (LPVOID) Buffer; + return (NO_ERROR); + +} // ReplConfigAllocAndBuildApiRecord diff --git a/private/net/svcdlls/repl/common/replconf.c b/private/net/svcdlls/repl/common/replconf.c new file mode 100644 index 000000000..5b40f032f --- /dev/null +++ b/private/net/svcdlls/repl/common/replconf.c @@ -0,0 +1,666 @@ +/*++ + +Copyright (c) 1992-1993 Microsoft Corporation + +Module Name: + + ReplConf.c + +Abstract: + + This file contains structures, function prototypes, and definitions + for the replicator export directory worker routines. + +Author: + + John Rogers (JohnRo) 27-Jan-1992 + +Environment: + + User Mode - Win32 + Portable to any flat, 32-bit environment. (Uses Win32 typedefs.) + Requires ANSI C extensions: slash-slash comments, long external names. + +Revision History: + + 27-Jan-1992 JohnRo + Created. + 04-Feb-1992 JohnRo + Fixed bug handling return code from ReplIsAbsPathValid(). + Improved handling of default strings (which may be NULL pointers). + 13-Feb-1992 JohnRo + Do some handling of errors for missing parameters. + Moved section name and keyword equates to ConfName.h. + 18-Feb-1992 JohnRo + Handle optional keywords in _write routine. + Fixed some overlooked cleanup in error paths in _read routine. + Moved ReplCheckAbsPathSyntax() out for general use. + Fixed occasional wrong keyword in error messages. + 24-Feb-1992 JohnRo + Interval is obsolete for NT: don't keep in registry. + (Keep in APIs just in case we implement repl APIs for OS/2, etc.) + 26-Feb-1992 JohnRo + Fixed bug in defaulting the interval. + 11-Mar-1992 JohnRo + Added some error checking for export path and import path on write. + Improved some error handling after calling NetpOpenConfigData(). + 23-Mar-1992 JohnRo + Get rid of old config helpers. + 27-Aug-1992 JohnRo + RAID 4611: validate ImportList and ExportList as read from registry. + 21-Sep-1992 JohnRo + RAID 6685: ReplConfigRead trashes Server Manager. + 04-Dec-1992 JohnRo + RAID 3844: remote NetReplSetInfo uses local machine type. + Improve range check of guard time field. + Also, the interval (sync) field is not obsolete after all. + 05-Jan-1993 JohnRo + Repl WAN support (get rid of repl name list limits). + Made changes suggested by PC-LINT 5.0 + 26-Jan-1993 JohnRo + RAID 7717: Repl assert if not logged on correctly. (Also do event + logging for real.) + +--*/ + + +// These must be included first: + +#include <windef.h> // MAX_PATH, etc. +#include <lmcons.h> // LAN Manager common definitions + +// These may be included in any order: + +#include <config.h> // NetpConfig helpers, LPNET_CONFIG_HANDLE. +#include <confname.h> // SECT_NT_ equates, REPL_KEYWORD_ too. +#include <lmapibuf.h> // NetApiBufferFree(). +#include <lmerr.h> // NERR_, ERROR_, NO_ERROR equates. +#include <lmerrlog.h> // NELOG_ equates. +#include <lmrepl.h> // REPL_ROLE equates, etc. +#include <netdebug.h> // NetpAssert(), FORMAT_ equates, etc. +#include <replconf.h> // My prototypes. +#include <repldefs.h> // IF_DEBUG(), ReplCheckAbsPathSyntax(). +#include <tstr.h> // STRICMP(), TCHAR_EOS, etc. + + +// +// Macro to set an output from a default string value (which may be NULL). +// +#define SET_STRING_TO_DEFAULT( output, default ) \ + { \ + /*lint -save -e506 */ /* don't complain about constant values here */ \ + if (default != NULL) { \ + (void) STRCPY( output, default ); \ + } else { \ + *output = TCHAR_EOS; \ + } \ + /*lint -restore */ \ + } + + + +// Callable whether or not service is started. +// All outputs are undefined if return value is not NO_ERROR. +NET_API_STATUS +ReplConfigRead( + IN LPTSTR UncServerName OPTIONAL, + OUT LPDWORD Role, + OUT LPTSTR ExportPath, + OUT LPTSTR *ExportList, // alloc and set ptr + OUT LPTSTR ImportPath, + OUT LPTSTR *ImportList, // alloc and set ptr + OUT LPTSTR LogonUserName, + OUT LPDWORD Interval, + OUT LPDWORD Pulse, + OUT LPDWORD GuardTime, + OUT LPDWORD Random + ) +{ + NET_API_STATUS ApiStatus; + DWORD DwordValue; + LPNET_CONFIG_HANDLE Handle = NULL; + LPTSTR StringValue = NULL; + + // + // Open the right section of the config file/whatever. + // + ApiStatus = NetpOpenConfigData( + & Handle, + UncServerName, + (LPTSTR) SECT_NT_REPLICATOR, + TRUE); // read-only + if (ApiStatus != NO_ERROR) { + + goto Cleanup; // go log error + } + + // + // Read role (REPLICATOR switch)... + // This value is required. + // For historical reasons, this can be a string ("Both" etc) or a DWORD + // (REPL_ROLE_BOTH etc). + // + ApiStatus = NetpGetConfigValue( + Handle, + (LPTSTR) REPL_KEYWORD_ROLE, // KeyWanted + & StringValue); // alloc and set ptr + if (ApiStatus == NERR_CfgParamNotFound) { + ReplConfigReportBadParmValue( + UncServerName, + (LPTSTR) REPL_KEYWORD_ROLE, + NULL ); + + goto Cleanup; // go log error + + } else if (ApiStatus == NO_ERROR) { // Read of string value OK. + + DWORD CharCount; + NetpAssert( StringValue != NULL ); + CharCount = STRLEN( StringValue ); + + if ( STRSPN( StringValue, (LPTSTR) TEXT("0123456789") ) == CharCount ) { + // + // Convert the string to a numeric value. + // + *Role = (DWORD) ATOL( StringValue ); + + if ( !ReplIsRoleValid( *Role ) ) { + ReplConfigReportBadParmValue( + UncServerName, + (LPTSTR) REPL_KEYWORD_ROLE, + StringValue ); + ApiStatus = ERROR_INVALID_DATA; + goto Cleanup; + } + } else if (STRICMP(StringValue, (LPTSTR) REPL_KEYWORD_ROLE_BOTH) == 0) { + *Role = REPL_ROLE_BOTH; + } else if (STRICMP(StringValue, (LPTSTR) REPL_KEYWORD_ROLE_EXPORT) == 0) { + *Role = REPL_ROLE_EXPORT; + } else if (STRICMP(StringValue, (LPTSTR) REPL_KEYWORD_ROLE_IMPORT) == 0) { + *Role = REPL_ROLE_IMPORT; + } else { + + ReplConfigReportBadParmValue( + UncServerName, + (LPTSTR) REPL_KEYWORD_ROLE, + StringValue ); + ApiStatus = ERROR_INVALID_DATA; + goto Cleanup; + + } + (void) NetApiBufferFree( StringValue ); + StringValue = NULL; + + } else if (ApiStatus == ERROR_INVALID_DATA) { // Probably REG_DWORD... + + ApiStatus = NetpGetConfigDword ( + Handle, + (LPTSTR) REPL_KEYWORD_ROLE, // Key wanted + (DWORD) -1, // default value (none!) + Role ); // set *Role with default or value read + if (ApiStatus != NO_ERROR) { + ReplConfigReportBadParmValue( + UncServerName, + (LPTSTR) REPL_KEYWORD_ROLE, + NULL ); + goto Cleanup; // go log error + } else if ( !ReplIsRoleValid( *Role ) ) { + ReplConfigReportBadParmValue( + UncServerName, + (LPTSTR) REPL_KEYWORD_ROLE, + NULL ); + ApiStatus = ERROR_INVALID_DATA; + goto Cleanup; + } + + } else { + ReplConfigReportBadParmValue( + UncServerName, + (LPTSTR) REPL_KEYWORD_ROLE, + NULL ); + goto Cleanup; // go log error + } + + // + // Read the export and import paths. + // Unlike LM2.x, these values do not have defaults under NT. + // +#define READ_PATH( keyword, output ) \ + { \ + ApiStatus = NetpGetConfigValue( \ + Handle, \ + (LPTSTR) keyword, \ + & StringValue); \ + if (ApiStatus == NERR_CfgParamNotFound) { \ + ReplConfigReportBadParmValue( \ + UncServerName, (LPTSTR) keyword, NULL ); \ + goto Cleanup; \ + } else if (ApiStatus == NO_ERROR) { \ + NetpAssert( StringValue != NULL ); \ + ApiStatus = ReplCheckAbsPathSyntax( StringValue ); \ + if (ApiStatus == NO_ERROR) { \ + (void) STRCPY( output, StringValue ); \ + } else if (ApiStatus == ERROR_INVALID_DATA) { \ + ReplConfigReportBadParmValue( \ + UncServerName, (LPTSTR) keyword, StringValue ); \ + goto Cleanup; \ + } else { \ + ReplConfigReportBadParmValue( \ + UncServerName, (LPTSTR) keyword, StringValue ); \ + ApiStatus = ERROR_INVALID_DATA; \ + goto Cleanup; \ + } \ + (void) NetApiBufferFree( StringValue ); \ + StringValue = NULL; \ + } else { \ + goto Cleanup; /* go log error */ \ + } \ + } + + READ_PATH( REPL_KEYWORD_EXPPATH, ExportPath ); + READ_PATH( REPL_KEYWORD_IMPPATH, ImportPath ); + + // + // Read the export and import lists. + // +#define READ_LIST( keyword, default, output ) \ + { \ + ApiStatus = NetpGetConfigValue( \ + Handle, \ + (LPTSTR) keyword, \ + & StringValue); \ + if (ApiStatus == NERR_CfgParamNotFound) { \ + *output = NULL; \ + } else if (ApiStatus == NO_ERROR) { \ + NetpAssert( output != NULL ); \ + NetpAssert( StringValue != NULL ); \ + if ( !ReplConfigIsListValid( StringValue ) ) { \ + ReplConfigReportBadParmValue( \ + UncServerName, (LPTSTR) keyword, StringValue ); \ + ApiStatus = ERROR_INVALID_DATA; \ + goto Cleanup; \ + } \ + *output = StringValue; \ + StringValue = NULL; /* don't confuse cleanup code */ \ + } else { \ + goto Cleanup; /* go log error */ \ + } \ + } + + READ_LIST( REPL_KEYWORD_EXPLIST, DEFAULT_EXPLIST, ExportList ); + READ_LIST( REPL_KEYWORD_IMPLIST, DEFAULT_IMPLIST, ImportList ); + + // + // Read logon user name. + // + ApiStatus = NetpGetConfigValue( + Handle, + (LPTSTR) REPL_KEYWORD_LOGON, + & StringValue); + if (ApiStatus == NERR_CfgParamNotFound) { + SET_STRING_TO_DEFAULT( LogonUserName, DEFAULT_LOGON ); + } else if (ApiStatus == NO_ERROR) { + NetpAssert( StringValue != NULL ); + /* BUGBUG: add error check on value! */ + (void) STRCPY( LogonUserName, StringValue ); + (void) NetApiBufferFree( StringValue ); + StringValue = NULL; + } else { + goto Cleanup; // go log error + } + + // + // Read interval (also called SYNC)... + // + ApiStatus = NetpGetConfigDword( + Handle, + (LPTSTR) REPL_KEYWORD_INTERVAL, + DEFAULT_SYNC, + & DwordValue ); + if (ApiStatus != NO_ERROR) { + ReplConfigReportBadParmValue( + UncServerName, + (LPTSTR) REPL_KEYWORD_INTERVAL, + NULL ); + goto Cleanup; // go log error + } + + if ( !ReplIsIntervalValid( DwordValue ) ) { + ReplConfigReportBadParmValue( + UncServerName, + (LPTSTR) REPL_KEYWORD_INTERVAL, + NULL ); + ApiStatus = ERROR_INVALID_DATA; + goto Cleanup; // go log error + } else { + * Interval = DwordValue; + } + + // + // Read pulse... + // + ApiStatus = NetpGetConfigDword( + Handle, + (LPTSTR) REPL_KEYWORD_PULSE, + DEFAULT_PULSE, + & DwordValue ); + if (ApiStatus != NO_ERROR) { + ReplConfigReportBadParmValue( + UncServerName, + (LPTSTR) REPL_KEYWORD_PULSE, + NULL ); + goto Cleanup; // go log error + } + + if ( !ReplIsPulseValid( DwordValue ) ) { + ReplConfigReportBadParmValue( + UncServerName, + (LPTSTR) REPL_KEYWORD_PULSE, + NULL ); + ApiStatus = ERROR_INVALID_DATA; + goto Cleanup; // go log error + } else { + * Pulse = DwordValue; + } + + // + // Read guardtime... + // + ApiStatus = NetpGetConfigDword( + Handle, + (LPTSTR) REPL_KEYWORD_GUARD, + DEFAULT_GUARD, + & DwordValue ); + if (ApiStatus != NO_ERROR) { + ReplConfigReportBadParmValue( + UncServerName, + (LPTSTR) REPL_KEYWORD_GUARD, + NULL ); + goto Cleanup; // go log error + } + if ( !ReplIsGuardTimeValid( DwordValue ) ) { + ReplConfigReportBadParmValue( + UncServerName, + (LPTSTR) REPL_KEYWORD_GUARD, + NULL ); + + ApiStatus = ERROR_INVALID_DATA; + goto Cleanup; // go log error + } else if ( DwordValue > ( (*Interval) / 2 ) ) { + ReplConfigReportBadParmValue( + UncServerName, + (LPTSTR) REPL_KEYWORD_GUARD, + NULL ); + + ApiStatus = ERROR_INVALID_DATA; + goto Cleanup; // go log error + } else { + * GuardTime = DwordValue; + } + + // + // Read random... + // + ApiStatus = NetpGetConfigDword( + Handle, + (LPTSTR) REPL_KEYWORD_RANDOM, + DEFAULT_RANDOM, + & DwordValue ); + if (ApiStatus != NO_ERROR) { + ReplConfigReportBadParmValue( + UncServerName, + (LPTSTR) REPL_KEYWORD_RANDOM, + NULL ); + goto Cleanup; // go log error + } + if ( !ReplIsRandomValid( DwordValue ) ) { + ReplConfigReportBadParmValue( + UncServerName, + (LPTSTR) REPL_KEYWORD_RANDOM, + NULL ); + ApiStatus = ERROR_INVALID_DATA; + goto Cleanup; // go log error + } else { + * Random = DwordValue; + } + + ApiStatus = NO_ERROR; + + // + // All done. + // + +Cleanup: + + if ( Handle != NULL ) { + NET_API_STATUS CloseStatus; + + CloseStatus = NetpCloseConfigData( Handle ); + + // Return this error iff it is first error we've gotten. + if ( (ApiStatus == NO_ERROR) && (CloseStatus != NO_ERROR) ) { + ApiStatus = CloseStatus; + } + } + + if (StringValue != NULL) { + (VOID) NetApiBufferFree( StringValue ); + } + + if (ApiStatus != NO_ERROR) { + + // Log error on server we were trying to access. + ReplErrorLog( + UncServerName, + NELOG_ReplSysErr, + ApiStatus, + NULL, + NULL ); + } + + return (ApiStatus); + +} // ReplConfigRead + + + + + +// Write config data for the replicator. +// Callable whether or not service is started. +NET_API_STATUS +ReplConfigWrite( + IN LPTSTR UncServerName OPTIONAL, + IN DWORD Role, + IN LPTSTR ExportPath OPTIONAL, + IN LPTSTR ExportList OPTIONAL, + IN LPTSTR ImportPath OPTIONAL, + IN LPTSTR ImportList OPTIONAL, + IN LPTSTR LogonUserName OPTIONAL, + IN DWORD Interval, + IN DWORD Pulse, + IN DWORD GuardTime, + IN DWORD Random + ) +{ + NET_API_STATUS ApiStatus; + LPNET_CONFIG_HANDLE Handle = NULL; + + // + // Check for caller's errors. + // + if ( !ReplIsRoleValid( Role ) ) { + ApiStatus = ERROR_INVALID_PARAMETER; + goto Cleanup; // go log error + } + if ( !ReplConfigIsRoleAllowed( UncServerName, Role ) ) { + ApiStatus = ERROR_INVALID_PARAMETER; + goto Cleanup; // go log error + } + if ( !ReplConfigIsListValid( ExportList ) ) { + ApiStatus = ERROR_INVALID_PARAMETER; + goto Cleanup; // go log error + } + if ( !ReplConfigIsListValid( ImportList ) ) { + ApiStatus = ERROR_INVALID_PARAMETER; + goto Cleanup; // go log error + } + if ( !ReplIsIntervalValid( Interval ) ) { + ApiStatus = ERROR_INVALID_PARAMETER; + goto Cleanup; // go log error + } + if ( !ReplIsPulseValid( Pulse ) ) { + ApiStatus = ERROR_INVALID_PARAMETER; + goto Cleanup; // go log error + } + if ( !ReplIsGuardTimeValid( GuardTime ) ) { + ApiStatus = ERROR_INVALID_PARAMETER; + goto Cleanup; // go log error + } + if ( !ReplIsRandomValid( Random ) ) { + ApiStatus = ERROR_INVALID_PARAMETER; + goto Cleanup; // go log error + } + + ApiStatus = ReplCheckAbsPathSyntax( ExportPath ); + if (ApiStatus != NO_ERROR) { + goto Cleanup; // go log error + } + + ApiStatus = ReplCheckAbsPathSyntax( ImportPath ); + if (ApiStatus != NO_ERROR) { + goto Cleanup; // go log error + } + + // BUGBUG: Error check LogonUserName. + + // + // Open the right section of the config file/whatever. + // + ApiStatus = NetpOpenConfigData( + & Handle, + UncServerName, + (LPTSTR) SECT_NT_REPLICATOR, + FALSE); // not read-only + if (ApiStatus != NO_ERROR) { + goto Cleanup; // go log error + } + + // + // Write role (replicate switch). + // This used to be a string (e.g. "Both"), but is now a number. + // + + ApiStatus = NetpSetConfigDword( + Handle, + (LPTSTR) REPL_KEYWORD_ROLE, + Role ); + if (ApiStatus != NO_ERROR) { + goto Cleanup; // go log error + } + +#define WRITE_OPTIONAL_STRING( keyword, value ) \ + { \ + if ( ( (value)!=NULL) && ( (*(value)) != TCHAR_EOS ) ) { \ + ApiStatus = NetpSetConfigValue( \ + Handle, \ + (LPTSTR) keyword, \ + value ); \ + if (ApiStatus != NO_ERROR) { \ + goto Cleanup; /* go log error */ \ + } \ + } else { \ + ApiStatus = NetpDeleteConfigKeyword( \ + Handle, \ + (LPTSTR) keyword); \ + if ( (ApiStatus!=NO_ERROR) \ + && (ApiStatus!=NERR_CfgParamNotFound) ) { \ + goto Cleanup; /* go log error */ \ + } \ + } \ + } + + // + // Write export and import paths. + // + +#define WRITE_PATH( keyword, value ) \ + WRITE_OPTIONAL_STRING( keyword, value ) + + WRITE_PATH( REPL_KEYWORD_EXPPATH, ExportPath ); + + WRITE_PATH( REPL_KEYWORD_IMPPATH, ImportPath ); + + // + // Write export and import lists. + // + +#define WRITE_LIST( keyword, value ) \ + WRITE_OPTIONAL_STRING( keyword, value ) + + WRITE_LIST( REPL_KEYWORD_EXPLIST, ExportList ); + + WRITE_LIST( REPL_KEYWORD_IMPLIST, ImportList ); + + // + // Write logon user name. + // + WRITE_OPTIONAL_STRING( REPL_KEYWORD_LOGON, LogonUserName ) + + // + // Write DWORDs (interval, pulse, guardtime, random). + // + +/*lint -save -e767 */ // Don't complain about different definitions +#define WRITE_DWORD( keyword, num ) \ + { \ + ApiStatus = NetpSetConfigDword( \ + Handle, \ + (LPTSTR) keyword, \ + num ); \ + if (ApiStatus != NO_ERROR) { \ + goto Cleanup; /* go log error */ \ + } \ + } +/*lint -restore */ // Resume checking for different macro definitions + + WRITE_DWORD( REPL_KEYWORD_INTERVAL, Interval ); + + WRITE_DWORD( REPL_KEYWORD_PULSE, Pulse ); + + WRITE_DWORD( REPL_KEYWORD_GUARD, GuardTime ); + + WRITE_DWORD( REPL_KEYWORD_RANDOM, Random ); + + ApiStatus = NO_ERROR; + +Cleanup: + + // + // All done. + // + if ( Handle != NULL ) { + NET_API_STATUS CloseStatus; + + CloseStatus = NetpCloseConfigData( Handle ); + + // Return this error iff it is first error we've gotten. + if ( (ApiStatus == NO_ERROR) && (CloseStatus != NO_ERROR) ) { + ApiStatus = CloseStatus; + } + } + + if (ApiStatus != NO_ERROR) { + + // Log error on server we were trying to access. + ReplErrorLog( + UncServerName, + NELOG_ReplSysErr, + ApiStatus, + NULL, + NULL ); + } + + return (ApiStatus); + +} // ReplConfigWrite diff --git a/private/net/svcdlls/repl/common/replconf.h b/private/net/svcdlls/repl/common/replconf.h new file mode 100644 index 000000000..ec81336c6 --- /dev/null +++ b/private/net/svcdlls/repl/common/replconf.h @@ -0,0 +1,167 @@ +/*++ + +Copyright (c) 1992-1993 Microsoft Corporation + +Module Name: + + ReplConf.h + +Abstract: + + This file contains structures, function prototypes, and definitions + for the replicator "config API" workers. + +Author: + + John Rogers (JohnRo) 15-Jan-1992 + +Environment: + + User Mode - Win32 + Portable to any flat, 32-bit environment. (Uses Win32 typedefs.) + Requires ANSI C extensions: slash-slash comments, long external names. + +Notes: + + You must include LmCons.h before this file. + +Revision History: + + 15-Jan-1992 JohnRo + Created. + 20-Jan-1992 JohnRo + Netr prototypes are now generated by MIDL and put in repl.h. + 23-Jan-1992 JohnRo + Added ReplConfigIsLevelValid() and some prototypes. + 13-Feb-1992 JohnRo + Added ReplConfigIsApiRecordValid(). + Added ReplConfigReportBadParmValue(). + Clarify that certain functions can be called if service is not started. + 11-Mar-1992 JohnRo + Added support for setinfo info levels in ReplConfigIsLevelValid(). + 24-Mar-1992 JohnRo + Renamed many ReplGlobal vars to ReplConfig vars. + 20-Jul-1992 JohnRo + RAID 2252: repl should prevent export on Windows/NT. + 14-Aug-1992 JohnRo + RAID 3601: repl APIs should checked import & export lists. + 01-Dec-1992 JohnRo + RAID 3844: remote NetReplSetInfo uses local machine type. + 05-Jan-1993 JohnRo + Repl WAN support (get rid of repl name list limits). + Made changes suggested by PC-LINT 5.0 + +--*/ + + +#ifndef _REPLCONF_ +#define _REPLCONF_ + + +#include <netlib.h> // IN_RANGE(). + + +BOOL +ReplConfigIsApiRecordValid ( + IN DWORD Level, + IN LPVOID ApiRecord, + OUT LPDWORD ParmError OPTIONAL + ); + +// BOOL +// ReplConfigIsLevelValid( +// IN DWORD Level, // Info level +// IN BOOL SetInfo // Are setinfo levels allowed? +// ); +// +#define ReplConfigIsLevelValid(Level,SetInfo) \ + ( \ + /*lint -e506 */ /* don't complain about constant values here */ \ + ( (Level) == 0 ) \ + || ( (SetInfo) && (IN_RANGE((Level), 1000, 1003)) ) \ + /*lint +e506 */ \ + ) + + +// Indicates whether or not the syntax of a list (export or import) is +// valid. Does no checking for the existence of items in the list. +// Callable whether or not service is started. +BOOL +ReplConfigIsListValid( + IN LPTSTR List OPTIONAL + ); + + +// Indicates whether the given role is allowed based on the current product +// type. Callable whether or not service is started. +BOOL +ReplConfigIsRoleAllowed( + IN LPTSTR UncServerName OPTIONAL, + IN DWORD Role + ); + +// Callable whether or not service is started. +NET_API_STATUS +ReplConfigAllocAndBuildApiRecord ( + IN DWORD Level, + IN DWORD Role, + IN LPTSTR ExportPath OPTIONAL, + IN LPTSTR ExportList OPTIONAL, + IN LPTSTR ImportPath OPTIONAL, + IN LPTSTR ImportList OPTIONAL, + IN LPTSTR LogonUserName OPTIONAL, + IN DWORD Interval, + IN DWORD Pulse, + IN DWORD GuardTime, + IN DWORD Random, + OUT LPBYTE * BufPtr // Alloc and set pointer. + ); + + +// Callable whether or not service is started. +NET_API_STATUS +ReplConfigRead( + IN LPTSTR UncServerName OPTIONAL, + OUT LPDWORD Role, + OUT LPTSTR ExportPath, + OUT LPTSTR *ExportList, // Alloc and set pointer. + OUT LPTSTR ImportPath, + OUT LPTSTR *ImportList, // Alloc and set pointer. + OUT LPTSTR LogonUserName, + OUT LPDWORD Interval, + OUT LPDWORD Pulse, + OUT LPDWORD GuardTime, + OUT LPDWORD Random + ); + +// Routine to report a bad parm value. +// There are two different versions of this routine, +// in client/report.c and server/error.c +// client/report.c is callable whether or not service is started. +// server/error.c only runs when service is starting; it talks to the service +// controller. +VOID +ReplConfigReportBadParmValue( + IN LPTSTR UncServerName OPTIONAL, + IN LPTSTR SwitchName, + IN LPTSTR TheValue OPTIONAL + ); + +// Callable whether or not service is started. +NET_API_STATUS +ReplConfigWrite( + IN LPTSTR UncServerName OPTIONAL, + IN DWORD Role, + IN LPTSTR ExportPath OPTIONAL, + IN LPTSTR ExportList OPTIONAL, + IN LPTSTR ImportPath OPTIONAL, + IN LPTSTR ImportList OPTIONAL, + IN LPTSTR LogonUserName OPTIONAL, + IN DWORD Interval, + IN DWORD Pulse, + IN DWORD GuardTime, + IN DWORD Random + ); + + +#endif // _REPLCONF_ diff --git a/private/net/svcdlls/repl/common/repldefs.h b/private/net/svcdlls/repl/common/repldefs.h new file mode 100644 index 000000000..8a58fd41f --- /dev/null +++ b/private/net/svcdlls/repl/common/repldefs.h @@ -0,0 +1,831 @@ +/*++ + +Copyright (c) 1987-1993 Microsoft Corporation + +Module Name: + repldefs.h + +Abstract: + Function prototypes and some global data + +Author: + Ported from Lan Man 2.x + +Environment: + Portable to any flat, 32-bit environment. (Uses Win32 typedefs.) + Requires ANSI C extensions: slash-slash comments, long external names. + +Revision History: + 10/07/91 (madana) + ported to NT. Converted to NT style. + 17-Dec-1991 JohnRo + Use BOOL (Win32) rather than BOOLEAN (NT) where possible.. + Replaced tabs in source file. + 26-Dec-1991 JohnRo + Added ReplIsIntegrityValid() and ReplIsExtentValid(). + 08-Jan-1992 JohnRo + Added ReplIsForceLevelValid(). + Added and revised trace bits. + 20-Jan-1992 JohnRo + Avoid lint warnings about IF_DEBUG stuff. + Changed ReplMain() prototype to match svc controller's needs. + ReportStatus() should add thread ID to status being reported. + Added DWORDLEN for use in config routines. + Temporarily enable all debug outputs. + Delete REPL_SECTION (use SECT_NT_REPLICATOR in config.h instead). + 22-Jan-1992 JohnRo + Added ReplRoleIncludes{Client,Master} macros. + Added REPL_ROLE_STOPPED (private) equate. + 27-Jan-1992 JohnRo + Added debug trace flags for DLL stubs. + Moved private REPL_STATE_ equates and ReplIsStateValid() to + <repldefs.h>. Ditto for the _RP equates and STATE_LEN. + Changed to use LPTSTR etc. + Added ReplIsRoleValid() (checks for everything but stopped). + Changed macro names to ReplRoleIncludes{Export,Import}. + 09-Feb-1992 JohnRo + Set up to dynamically change role. + 20-Feb-1992 JohnRo + Added support for REPL_STATE_NOT_STARTED. + Added Repl{Incr,Decr}LockFields(). + Added ReplCheckAbsPathSyntax(). + Added ReplIs{Interval,GuardTime,Pulse,Random}Valid(). + 22-Feb-1992 JohnRo + Clarify that text parm to ReplFinish() is optional. + 26-Feb-1992 JohnRo + Added ReplLockFieldsAreValid() macro. + Created ReplIgnoreDirOrFileName(). + 27-Feb-1992 JohnRo + Changed state not started to state never replicated. + 05-Mar-1992 JohnRo + Changed ReplMain's interface to match new service controller. + Cranked-down max tree depth for testing only. + 13-Mar-1992 JohnRo + Fixed bug handling tree depth. + Wait hint is in milliseconds for new service controller. + 15-Mar-1992 JohnRo + Put back IF_DEBUG() the way it belongs. + 24-Mar-1992 JohnRo + Got rid of useless master and client termination codes. + Use integrity and extent equates in <lmrepl.h>. + Modify REPL$ share handling. + Put tree depth back to normal max value. + 25-Mar-1992 JohnRo + Avoid obsolete state values. + 09-Apr-1992 JohnRo + Prepare for WCHAR.H (_wcsicmp vs _wcscmpi, etc). + 15-Jul-1992 JohnRo + RAID 10503: srv mgr: repl dialog doesn't come up. + Avoid compiler warnings. + 11-Aug-1992 JohnRo + RAID 3288: repl svc should preserve ACLs on copy. + 01-Sep-1992 JohnRo + RAID 3721: repl svc does not stop with shutdown msg. + 04-Dec-1992 JohnRo + Repl should use filesystem change notify. + Added trace bits for file find routines and checksum routines. + Made changes suggested by PC-LINT 5.0 + 08-Dec-1992 JohnRo + RAID 3316: access violation while stopping the replicator + 17-Dec-1992 JohnRo + RAID 1513: Repl does not maintain ACLs. (Also fix HPFS->FAT timestamp.) + Made changes suggested by PC-LINT 5.0 + 05-Jan-1993 JohnRo + Repl WAN support (get rid of repl name list limits). + 13-Jan-1993 JohnRo + RAID 7053: locked trees added to pulse msg. (Actually fix all + kinds of remote lock handling.) + 15-Jan-1993 JohnRo + RAID 7717: Repl assert if not logged on correctly. (Also do event + logging for real.) + 22-Jan-1993 JohnRo + RAID 7983: Repl svc needs to change process token to really copy ACLs. + 17-Feb-1993 JohnRo + RAID 11365: Fixed various repl mailslot problems. + Also get rid of obsolete default import/export path equates. + Made PC-LINT changes for free build. + 25-Jan-1993 JohnRo + RAID 12237: replicator tree depth exceeded. + 30-Mar-1993 JohnRo + Reduce checksum frequency by using change notify on import tree. + 06-Apr-1993 JohnRo + RAID 1938: Replicator un-ACLs files when not given enough permission. + 21-Apr-1993 JohnRo + RAID 7313: repl needs change permission to work on NTFS, or we need + to delete files differently. + 07-May-1993 JohnRo + RAID 3258: file not updated due to ERROR_INVALID_USER_BUFFER. + 21-May-1993 JohnRo + RAID 11103: repl svc doesn't handle time being set back. + 10-Jun-1993 JohnRo + RAID 13080: Allow repl between different timezones. + 24-Aug-1993 JohnRo + RAID 788 (was 16419): Repl: spaces in computer names do not work again. + +--*/ + + +#ifndef _REPLDEFS_ +#define _REPLDEFS_ + + +// Don't complain about "unneeded" includes of these files: +/*lint -efile(764,iniparm.h,lmrepl.h,netlib.h,windows.h) */ +/*lint -efile(766,iniparm.h,lmrepl.h,netlib.h,windows.h) */ +#include <windows.h> // PSECURITY_ATTRIBUTES. +#include <iniparm.h> // MIN_SYNC, etc. +#include <lmrepl.h> // REPL_EXTENT_FILE, etc. +#include <netlib.h> // IN_RANGE(). + + +// +// Conditional compilation options: +// + +#define USE_BACKUP_APIS + +// Uncomment this out when GetFileSecurity() stops returning +// ERROR_BAD_DESCRIPTOR_FORMAT for UNC names. +#define USE_UNC_GETFILESEC + + + +// +// Mailslot names and related lengths. +// + +#define MASTER_SLOT_NAME TEXT("\\MAILSLOT\\NET\\REPL_MAS") +#define CLIENT_SLOT_NAME TEXT("\\MAILSLOT\\NET\\REPL_CLI") + +// Length of CLIENT_SLOT_NAME in TCHARs, including the null char. +#define CLIENT_SLOT_NAME_LEN ( sizeof(CLIENT_SLOT_NAME) / sizeof(TCHAR) ) + +#define MAX_2_MSLOT_SIZE (441 - (CLIENT_SLOT_NAME_LEN + CNLEN + 1)) + +// Length of full client slot name (including null char) in TCHARs. +#define FULL_SLOT_NAME_SIZE (CLIENT_SLOT_NAME_LEN + CNLEN + 1 + 2) + +// Minimum size of DosFindFirst2 EaSize, for cbList field. +#define EA_MIN_SIZE 4 + + +// +// Various other constants. +// + +#define RADIX 10 + +#define SLASH (LPTSTR) TEXT("\\") +#define SLASH_DOT (LPTSTR) TEXT("\\.") +#define SLASH_DOT_DOT (LPTSTR) TEXT("\\..") +#define SLASH_SLASH (LPTSTR) TEXT("\\\\") +#define STAR_DOT_STAR (LPTSTR) TEXT("*.*") +#define DOT (LPTSTR) TEXT(".") +#define DOT_DOT (LPTSTR) TEXT("..") + + +// List of separator chars we allow between names in import and export lists. +#define REPL_LIST_DELIMITER_STR ((LPTSTR) TEXT("\t;,")) + + +// Define a value for unknown file system time resolution. +#define UNKNOWN_FS_RESOLUTION ( (DWORD) 0 ) + + +// DWORDLEN: DWORD takes this many decimal digits to store. +// BUGBUG This assumes that DWORD is 32-bits or less. +#define DWORDLEN 10 + + +// +// Service controller wait hints. +// These values are in milliseconds (formerly tenths of a second under LM 2.x). +// Max usable wait hint is 255 tenths of a second (25.5 seconds). +// NET.EXE's use of NetService APIs means we are stuck with this limit for now. +// +#define MAX_USABLE_WAIT_HINT (25500) + +// Service controller status wait hint. We use this for starting and +// stopping. +#define REPL_WAIT_HINT MAX_USABLE_WAIT_HINT + + +// +// Time might go backwards (because of syncing the clock or somebody changing +// the date and time), so define how much of this we can ignore. This value +// is in seconds. Since interval times are given in minutes, this value should +// be over a minute. 110 seconds is a first guess (almost 2 minutes). +// +#define BACKWARDS_TIME_CHNG_ALLOWED_SECS 110 + + +// +// AlertLogExit codes. +// +#define EXIT 1 +#define NO_EXIT 0 + +// +// Message types. +// + +// Sync messages +#define SYNC_MSG 1 +#define GUARD_MSG 2 +#define PULSE_MSG 3 + +// Query messages +#define IS_DIR_SUPPORTED 11 +#define IS_MASTER 12 +#define DIR_NOT_SUPPORTED 13 +#define DIR_SUPPORTED 14 +#define NOT_MASTER_DIR 15 +#define MASTER_DIR 16 +#define DIR_COLLIDE 17 + +// Internal pseudo-messages +#define GUARD_TIMEOUT 20 +#define DUPL_TIMEOUT 21 +#define PULSE_1_TIMEOUT 22 +#define PULSE_2_TIMEOUT 23 +#define PULSE_3_TIMEOUT 24 +#define NEXT_AVAILABLE_MESSAGE_NUMBER 25 + + +// Update opcodes. +#define START 1 +#define UPDATE 2 +#define END 3 +#define PULSE 4 +#define GUARD 5 + + +// Security information to copy with the files and directories. +// BUGBUG: Add SACL to this? Add other items when NT supports them! +#define REPL_SECURITY_TO_COPY \ + ( OWNER_SECURITY_INFORMATION \ + | GROUP_SECURITY_INFORMATION \ + | DACL_SECURITY_INFORMATION ) + + + +#define REPL_SHARE (LPTSTR) TEXT("REPL$") + +#define REPL_INI (LPTSTR) TEXT("REPL.INI") + +// Unlike downlevel, we represent one or more user locks by just one file. +// The lock count is kept in the registry. +#define USERLOCK_NT (LPTSTR) TEXT("USERLOCK.NT$") + + +#define NT_MSG_TOKEN 0xFFFFFFFF + + +// +// These former "signal file" names are now used as state strings in the +// config data for each directory. +// +#define OK_RP (LPTSTR) TEXT("OK.RP$") +#define NO_MASTER_RP (LPTSTR) TEXT("NO_MASTR.RP$") +#define NO_SYNC_RP (LPTSTR) TEXT("NO_SYNC.RP$") +#define NEVER_REPLICATED_RP (LPTSTR) TEXT("NEVERREP.RP$") /* Added for APIs. */ + +// +// Max len of the above strings. Since they were FAT file names (8.3), then +// the max len (in chars) is 8 + 1 (dot) + 3 (extension). +// +#define STATE_LEN (8+1+3) + + +// +// Debug Definititions +// + +#define REPL_DEBUG_REPL 0x00000001 // General debugging +#define REPL_DEBUG_MAJOR 0x00000002 // Major events + +#define REPL_DEBUG_CLIENT 0x00000010 // Debug the Client +#define REPL_DEBUG_WATCHD 0x00000020 // Debug the Watchdog thread +#define REPL_DEBUG_SYNC 0x00000040 // Debug the Syncer thread + +#define REPL_DEBUG_MASTER 0x00000100 // Debug the Master +#define REPL_DEBUG_PULSER 0x00000200 // Debug the Master +#define REPL_DEBUG_COPYTIME 0x00000800 // Debug the time copy routines. + +#define REPL_DEBUG_EXPAPI 0x00010000 // Debug export API routines +#define REPL_DEBUG_IMPAPI 0x00020000 // Debug import API routines +#define REPL_DEBUG_REPLAPI 0x00040000 // Debug repl API routines + +#define REPL_DEBUG_DIRNAME 0x01000000 // Debug dirname helpers +#define REPL_DEBUG_DLLSTUB 0x02000000 // DLL stubs. +#define REPL_DEBUG_RPCBIND 0x04000000 // RPC bind/unbind routines. +#define REPL_DEBUG_SVCCTRL 0x08000000 // Service controller stuff. +#define REPL_DEBUG_FILEFIND 0x10000000 // File find routines. +#define REPL_DEBUG_CHECKSUM 0x20000000 // Checksum routines. +#define REPL_DEBUG_CHNGNOT 0x40000000 // Change notify routines. + +#define REPL_DEBUG_STALLER 0x80000000 // Staller thread stuff. +#define REPL_DEBUG_STOPPER REPL_DEBUG_STALLER // Stopper thread too. + +#define REPL_DEBUG_ALL ((DWORD) -1) // All possible debug bits. + + + +// Private role (in addition to REPL_ROLE_ equates in LmRepl.h). +#define REPL_ROLE_STOPPED ( (DWORD) 'S' ) // arbitrary value + + +#undef IF_DEBUG + +#if DBG + +extern DWORD ReplGlobalTrace; + +#define IF_DEBUG(Function) if (ReplGlobalTrace & REPL_DEBUG_ ## Function) + +#else + +#define IF_DEBUG(Function) \ + /*lint -save -e506 */ /* don't complain about constant values here */ \ + if (FALSE) \ + /*lint -restore */ + +#endif // DBG + +// +// ReplNetNameCompare +// + +#ifdef UNICODE + +#define ReplNetNameCompare(_a, _b, _c, _e, _f ) \ + I_NetNameCompare((_a), (_b), (_c), (_e), (_f) ) + +#define ReplNetPathCompare(_a, _b, _c, _e, _f ) \ + I_NetPathCompare((_a), (_b), (_c), (_e), (_f) ) + +#else // UNICODE + +#define ReplNetNameCompare(_a, _b, _c, _e, _f ) \ + stricmp( (_b), (_c) ) + +#define ReplNetPathCompare(_a, _b, _c, _e, _f ) \ + stricmp( (_b), (_c) ) + +#endif // UNICODE + +// +// S T R U C T U R E S +// + + +// +// Definition of the checksum of a particular directory tree. +// + +struct checksum_rec { + DWORD checksum; + DWORD count; +}; + +typedef struct checksum_rec CHECKSUM_REC; +typedef struct checksum_rec * PCHECKSUM_REC; +typedef struct checksum_rec * LPCHECKSUM_REC; + +// MESSAGE STRUCTURES. + +struct msg_header { + DWORD msg_type; + TCHAR sender[CNLEN+1]; + TCHAR senders_domain[DNLEN+1]; +}; + +typedef struct msg_header MSG_HEADER; +typedef struct msg_header *PMSG_HEADER; +typedef struct msg_header *LPMSG_HEADER; + +struct status_rec { + TCHAR dir_name[PATHLEN]; + DWORD opcode; // 1 - start, 2 - update, 3 - end. + DWORD checksum; + DWORD count; + DWORD integrity; + DWORD extent; +}; + +typedef struct status_rec STATUS_REC; +typedef struct status_rec *PSTATUS_REC; +typedef struct status_rec *LPSTATUS_REC; + +struct msg_status_rec { + DWORD dir_name_offset; // offset where name string is + // from msg buffer start + + DWORD opcode; // 1 - start, 2 - update, 3 - end. + DWORD checksum; + DWORD count; + DWORD integrity; + DWORD extent; + +}; + +typedef struct msg_status_rec MSG_STATUS_REC; +typedef struct msg_status_rec *PMSG_STATUS_REC; +typedef struct msg_status_rec *LPMSG_STATUS_REC; + +struct repl_info { + DWORD random; + DWORD sync_rate; + DWORD pulse_rate; + DWORD guard_time; +}; + +typedef struct repl_info REPL_INFO; +typedef struct repl_info *PREPL_INFO; +typedef struct repl_info *LPREPL_INFO; + +struct query_msg { + MSG_HEADER header; + TCHAR dir_name[PATHLEN]; // ASCIIZ dir/tree name. +}; + +typedef struct query_msg QUERY_MSG; +typedef struct query_msg *PQUERY_MSG; +typedef struct query_msg *LPQUERY_MSG; + +struct sync_msg { + MSG_HEADER header; + REPL_INFO info; + DWORD update_count; + + // + // here come update_count msg_status_rec records, the file name strings + // stuffed at the end of the buffer by NetPackStr, dir_name is the + // offset from the start of the message. + // + +}; + +typedef struct sync_msg SYNCMSG; +typedef struct sync_msg *PSYNCMSG; +typedef struct sync_msg *LPSYNCMSG; + +// +// Global procedure definitions +// + +VOID +AlertLogExit( + IN NET_API_STATUS alert_code, + IN NET_API_STATUS errlog_code, + IN NET_API_STATUS sys_code, + IN LPTSTR str1, + IN LPTSTR str2, + IN BOOL exit_flag + ); + +VOID +ReportStatus( + IN DWORD State, + IN NET_API_STATUS ApiStatus, + IN DWORD WaitHint, + IN DWORD CheckPoint + ); + +VOID +ReplFinish ( + IN NET_API_STATUS ApiStatus + ); + +VOID +ScanTree( + IN LONG MasterTimeZoneOffsetSecs, // exporter offset from GMT + IN OUT LPTSTR Path, // path plus scratch space (to PATHLEN+1) + OUT PCHECKSUM_REC ScanRec + ); + +VOID +ScanDir( + IN LONG MasterTimeZoneOffsetSecs, // exporter offset from GMT + IN OUT LPTSTR Path, // path plus scratch space (to PATHLEN+1) + OUT PCHECKSUM_REC ScanRec, + IN DWORD Flag + ); + +NET_API_STATUS +Parse( + IN DWORD argc, + IN LPTSTR argv[] + ); + +VOID +ReplMain( + IN DWORD dwNumServicesArgs, + IN LPTSTR *lpServiceArgVectors + ); + +VOID +InitParseData( + VOID + ); + +VOID +FreeParseData( + VOID + ); + +DWORD +ReplMasterMain( + IN LPVOID parm // NULL if service is starting; non-NULL if role is changing + ); + +// BOOL +// ReplAreLockFieldsValid ( +// IN DWORD LockCount, +// IN DWORD LockTime +// ); +// +#define ReplAreLockFieldsValid(LockCount,LockTime) \ + ( ( ((LockCount)!=0) && ((LockTime)!=0) ) \ + || ( ((LockCount)==0) && ((LockTime)==0) ) ) + +NET_API_STATUS +ReplChangeRole( + IN DWORD NewRole + ); + +NET_API_STATUS +ReplCheckAbsPathSyntax ( + IN LPTSTR AbsPath + ); + +DWORD +ReplClientMain( + IN LPVOID parm // NULL if service is starting; non-NULL if role is changing + ); + +NET_API_STATUS +ReplCopyDirectoryItself( + IN LPCTSTR SourcePath, + IN LPCTSTR DestPath, + IN BOOL bFailIfExists + ); + +NET_API_STATUS +ReplCopyFile( + IN LPCTSTR SourcePath, + IN LPCTSTR DestPath, + IN BOOL bFailIfExists + ); + +VOID +ReplCopyJustDateTime( + IN LPCTSTR SourcePath, + IN LPCTSTR DestPath, + IN BOOL IsDirectory + ); + +NET_API_STATUS +ReplCopySecurity( + IN LPCTSTR SourcePath, + IN LPCTSTR DestPath + ); + +NET_API_STATUS +ReplDecrLockFields ( + IN OUT LPDWORD LockCountPtr, + IN OUT LPDWORD LockTimePtr, + IN DWORD UnlockForce // Use REPL_UNLOCK_FORCE or REPL_UNLOCK_NOFORCE. + ); + +NET_API_STATUS +ReplDeleteFile( + IN LPCTSTR FileName + ); + +NET_API_STATUS +ReplDisableBackupPermission( + VOID + ); + +// Callable even if the replicator service is not started. +NET_API_STATUS +ReplDoUserLockFilesExist( + IN LPCTSTR Path, // May be absolute path (with drive) or UNC path. + OUT LPBOOL IsLockedPtr + ); + +NET_API_STATUS +ReplEnableBackupPermission( + VOID + ); + +VOID +ReplErrorLog( + IN LPCTSTR UncServerName OPTIONAL, + IN NET_API_STATUS l_code, + IN NET_API_STATUS s_code, + IN LPTSTR str1 OPTIONAL, + IN LPTSTR str2 OPTIONAL + ); + +BOOL +ReplFileOrDirExists( + IN LPCTSTR FileName + ); + +DWORD +ReplGetEaSize( + IN LPCTSTR Path + ); + +BOOL +ReplIsFileTimeCloseEnough( + IN LPVOID MasterFileTime, // Points to a FILETIME value. + IN LPVOID ClientFileTime // Points to a FILETIME value. + ); + +// Returns UNKNOWN_FS_RESOLUTION on error. +DWORD +ReplGetFsTimeResolutionSecs( + IN LPCTSTR AbsPath + ); + +BOOL +ReplIgnoreDirOrFileName ( + IN LPTSTR Name + ); + +NET_API_STATUS +ReplIncrLockFields ( + IN OUT LPDWORD LockCountPtr, + IN OUT LPDWORD LockTimePtr + ); + +NET_API_STATUS +ReplInitAnyList( + IN LPCTSTR UncanonList OPTIONAL, + IN OUT LPTSTR ** NameListPtr, // Allocated by this routine (or set to NULL). + IN LPCTSTR ConfigKeywordName, + OUT LPDWORD EntryCount + ); + +NET_API_STATUS +ReplInitBackupPermission( + VOID + ); + +// BOOL +// ReplIsExtentValid( +// IN DWORD parm +// ); +// +#define ReplIsExtentValid(parm) \ + ( ((parm) == REPL_EXTENT_FILE) || ((parm) == REPL_EXTENT_TREE) ) + +// BOOL +// ReplIsForceLevelValid( +// IN DWORD Force +// ); +// +#define ReplIsForceLevelValid(Force) \ + ( ((Force) == REPL_UNLOCK_FORCE) || ((Force) == REPL_UNLOCK_NOFORCE) ) + +// BOOL +// ReplIsGuardTimeValid( +// IN DWORD parm +// ); +// +#if MIN_GUARD // low bound > 0 +#define ReplIsGuardTimeValid(parm) \ + ( IN_RANGE( (parm), MIN_GUARD, MAX_GUARD ) ) +#else // MIN_GUARD is zero. +#define ReplIsGuardTimeValid(parm) \ + ( (parm) <= MAX_GUARD ) +#endif + +// BOOL +// ReplIsIntegrityValid( +// IN DWORD parm +// ); +// +#define ReplIsIntegrityValid(parm) \ + ( ((parm) == REPL_INTEGRITY_FILE) || ((parm) == REPL_INTEGRITY_TREE) ) + +// BOOL +// ReplIsIntervalValid( +// IN DWORD parm +// ); +// +#define ReplIsIntervalValid(parm) \ + ( IN_RANGE((parm), MIN_SYNC, MAX_SYNC) ) + +// BOOL +// ReplIsPulseValid( +// IN DWORD parm +// ); +// +#define ReplIsPulseValid(parm) \ + ( IN_RANGE(parm, MIN_PULSE, MAX_PULSE) ) + +// BOOL +// ReplIsRandomValid( +// IN DWORD parm +// ); +// +#define ReplIsRandomValid(parm) \ + ( IN_RANGE((parm), MIN_RANDOM, MAX_RANDOM) ) + +// BOOL +// ReplIsRoleValid( +// IN DWORD role +// ); +// +// Check for valid roles (not including stopped, which is for internal use). +// +#define ReplIsRoleValid(role) \ + ( ((role) == REPL_ROLE_BOTH) \ + || ((role) == REPL_ROLE_EXPORT) \ + || ((role) == REPL_ROLE_IMPORT) ) + + +// Check for valid state. This includes the "private" state values. +#define ReplIsStateValid( State ) \ + ( ((State)==REPL_STATE_OK) \ + || ((State)==REPL_STATE_NO_MASTER) \ + || ((State)==REPL_STATE_NO_SYNC) \ + || ((State)==REPL_STATE_NEVER_REPLICATED) ) + +NET_API_STATUS +ReplMakeSecurityAttributes( + IN LPCTSTR SourcePath, + OUT PSECURITY_ATTRIBUTES * DestSecurityAttrPtr // alloc and set ptr + ); + +NET_API_STATUS +ReplMarshallQueryMsg( + IN PBYTE InBuf, + OUT PBYTE OutBuf, + IN LPDWORD BytesRead + ); + + +// BOOL +// ReplRoleIncludesExport(role) +// IN DWORD Role +// ); +#define ReplRoleIncludesExport(role) \ + ( ((role) == REPL_ROLE_EXPORT) || ((role) == REPL_ROLE_BOTH) ) + + +// BOOL +// ReplRoleIncludesImport(role) +// IN DWORD Role +// ); +#define ReplRoleIncludesImport(role) \ + ( ((role) == REPL_ROLE_IMPORT) || ((role) == REPL_ROLE_BOTH) ) + +DWORD +ReplStaller( + IN LPVOID Parm + ); + +DWORD +ReplStopper( + IN LPVOID Parm + ); + +VOID +ReplStopService( + VOID + ); + +NET_API_STATUS +ReplUnmarshallMessage( + IN PBYTE InBuf, + IN DWORD InBufLen, + OUT PBYTE OutBuf, + IN DWORD OutBufLen, + OUT LPDWORD BytesRead + ); + +NET_API_STATUS +ReplUnmarshallSyncMsg( + IN PBYTE InBuf, + IN DWORD InBufLen, + OUT PBYTE OutBuf, + IN DWORD OutBufLen, + OUT LPDWORD BytesRead + ); + +NET_API_STATUS +ReplUnmarshallQueryMsg( + IN PBYTE InBuf, + IN DWORD InBufLen, + OUT PBYTE OutBuf, + IN DWORD OutBufLen, + OUT LPDWORD BytesRead + ); + + +#endif // _REPLDEFS_ diff --git a/private/net/svcdlls/repl/common/replerr.c b/private/net/svcdlls/repl/common/replerr.c new file mode 100644 index 000000000..510fe5161 --- /dev/null +++ b/private/net/svcdlls/repl/common/replerr.c @@ -0,0 +1,298 @@ +/*++ + +Copyright (c) 1987-1993 Microsoft Corporation + +Module Name: + + ReplErr.c + +Abstract: + + Contains one routine for error handling: ReplErrorLog(). + + This routine is shared by the APIs (client side) and the service itself. + +Author: + + JR (John Rogers, JohnRo@Microsoft) 21-Jan-1993 + (Actually, just massive rework of LM 2.x code via MadanA and RitaW.) + +Environment: + + User mode only. + Uses Win32 stuff: ReportEvent(), etc. + Requires ANSI C extensions: slash-slash comments, long external names. + +Revision History: + + 21-Jan-1993 JohnRo + Created for RAID 7717: Repl assert if not logged on correctly. (Also + do event logging for real.) + 15-Feb-1993 JohnRo + RAID 10685: user name not in repl event log. + 13-May-1993 JohnRo + RAID 9741: Replicator logs same event over and over. + Changed debug bit to MAJOR for this. + Changed debug output on errors to be unconditional. + +--*/ + + +// These must be included first: + +#define NOMINMAX // Let stdlib.h define min() and max() +#include <windows.h> // LocalFree(), ReportEvent(), etc. +#include <lmcons.h> + +// These may be included in any order: + +#include <icanon.h> // NetpIsRemote(), ISREMOTE, etc. +#include <lmsname.h> // SERVICE_REPL. +#include <netdebug.h> // DBGSTATIC, NetpKdPrint(), FORMAT_ equates, etc. +#include <netlib.h> // NetpGetUserSid(). +#include <prefix.h> // PREFIX_ equates. +#include <repldefs.h> // My prototypes. +#include <tstr.h> // ULTOA(). (includes stdlib.h) + + +// +// Static values which we use to prevent logging the same error code over +// and over. +// BUGBUG: Add server name, str1, str2 static variables someday. +// + +DBGSTATIC NET_API_STATUS ReplLastLogCode = NO_ERROR; +DBGSTATIC NET_API_STATUS ReplLastApiStatus = NO_ERROR; + + +VOID +ReplErrorLog( + IN LPCTSTR UncServerName OPTIONAL, + IN NET_API_STATUS LogCode, + IN NET_API_STATUS StatusCode, + IN LPTSTR str1 OPTIONAL, + IN LPTSTR str2 OPTIONAL + ) +/*++ + +Routine Description: + + Writes entry into event log. + + This is a recursive routine. It writes a message remotely and then + recursively calls itself to copy the message locally. + +Arguments: + + UncServerName - Name of server on which to log this error. + + LogCode - Error log msg code (must appear in lmerrlog.h). + + StatusCode - In case of system / network error, the code. Should be zero + if not needed for message. + + str1 - Merge string for msg. Should be NULL if not needed for message. + + str2 - Merge string for msg. Should be NULL if not needed for message. + +Return Value: + + None. + +--*/ +{ + NET_API_STATUS ApiStatus; + TCHAR ErrCodeString[DWORDLEN+1]; // Long enough for any status. + HANDLE LogHandle = NULL; + LPTSTR StringArray[3]; // Space for ptrs to err code, str1, str2. + WORD StringCount = 0; // Num of ptrs in StringArray (so far). + BOOL SuccessFlag; + PSID UserSid = NULL; + + + IF_DEBUG( MAJOR ) { + NetpKdPrint(( PREFIX_REPL + "Error log message: " FORMAT_API_STATUS, LogCode )); + + } + + // + // Is this a redundant event log? + // + // To make life easier on ourselves, + // we only avoid redundant logs of local events with no optional strings. + // That covers the common cases well (like NELOG_ReplSysErr). + // And we don't have to worry about allocating/deallocating the strings + // either. + // + + if ( (LogCode==ReplLastLogCode) + && (StatusCode==ReplLastApiStatus) + && (UncServerName==NULL) + && (str1==NULL) + && (str2==NULL) ) { + + goto Cleanup; // Yes, this is redundant. + } + + ReplLastLogCode = LogCode; + ReplLastApiStatus = StatusCode; + + // + // Is sys/net error specified? If so, convert to string and store + // pointer in StringArray. + // + + if (StatusCode != 0) { + + (VOID) ULTOA(StatusCode, ErrCodeString, RADIX); + + StringArray[StringCount] = ErrCodeString; + ++StringCount; + + IF_DEBUG( MAJOR ) { + NetpKdPrint(( " " FORMAT_API_STATUS, StatusCode )); + } + } + + // + // Now take care of (optional) char strings. + // + + if (str1 != NULL) { + StringArray[StringCount] = str1; + ++StringCount; + + IF_DEBUG( MAJOR ) { + NetpKdPrint(( " " FORMAT_LPTSTR, str1 )); + } + } + if (str2 != NULL) { + StringArray[StringCount] = str2; + ++StringCount; + + IF_DEBUG( MAJOR ) { + NetpKdPrint(( " " FORMAT_LPTSTR, str2 )); + } + } + + IF_DEBUG( MAJOR ) { + NetpKdPrint(( "\n" )); + } + + NetpAssert( StringCount <= 3 ); // Update StringArray size if not. + + // + // Get event log handle using out service name as source. + // + + LogHandle = RegisterEventSource( + (LPTSTR) UncServerName, + (LPTSTR) SERVICE_REPL ); + + if (LogHandle == NULL) { + NetpKdPrint(( PREFIX_REPL "RegisterEventSource FAILED! status: " + FORMAT_API_STATUS "\n", + (NET_API_STATUS) GetLastError() )); + // Nothing to do; we can't log the fact that we can't log an error! + goto Cleanup; + } + + // + // Get SID of user which invoked this thread, if applicable. + // + + ApiStatus = NetpGetUserSid( + &UserSid ); // alloc and set ptr (free with LocalFree). + + if (ApiStatus != NO_ERROR) { + NetpKdPrint(( PREFIX_REPL + "ReplErrorLog: Can't get SID for user, status=" + FORMAT_API_STATUS "...\n", ApiStatus )); + + // Log without user ID is better than none, so continue... + UserSid = NULL; + } + + // + // Log the error code specified. + // + + SuccessFlag = ReportEvent( + LogHandle, + EVENTLOG_ERROR_TYPE, + 0, // Event category. + LogCode, // Message ID. + UserSid, + StringCount, + 0, // Zero bytes of raw data. + StringArray, // Pointer to array of ptrs to insert strings. + (PVOID) NULL ); // No pointer to raw data. + + if ( !SuccessFlag ) { + + ApiStatus = (NET_API_STATUS) GetLastError(); + NetpAssert( ApiStatus != NO_ERROR ); + + NetpKdPrint(( PREFIX_REPL + "FAILED ReportEvent call, status " FORMAT_API_STATUS ".\n", + ApiStatus )); + + // Not much else we can do but continue... + } + + // + // We're done with the event log handle. + // + + SuccessFlag = DeregisterEventSource(LogHandle); + + if ( !SuccessFlag ) { + + ApiStatus = (NET_API_STATUS) GetLastError(); + NetpAssert( ApiStatus != NO_ERROR ); + + NetpKdPrint(( PREFIX_REPL + "FAILED DeregisterEventSource call, status " + FORMAT_API_STATUS ".\n", + ApiStatus )); + + // Not much else we can do but continue... + } + + // + // If we were doing a remote message, then log a copy locally. + // + if ( (UncServerName!=NULL) && (UncServerName[0]!=TCHAR_EOS) ) { + + DWORD Location; + + ApiStatus = NetpIsRemote( + (LPTSTR) UncServerName, // input: uncanon name + & Location, // output: local or remote flag + NULL, // don't need canon name output + 0); // flags: normal + + if ( (ApiStatus!=NO_ERROR) || (Location==(DWORD)ISREMOTE) ) { + + // RECURSIVE CALL: Log error locally too, just in case. + ReplErrorLog( + NULL, // No server name this time. + LogCode, + StatusCode, + str1, + str2 ); + } + } + + // + // Clean up... + // + +Cleanup: + + if (UserSid != NULL) { + (VOID) LocalFree( UserSid ); + } + +} diff --git a/private/net/svcdlls/repl/common/replgbl.h b/private/net/svcdlls/repl/common/replgbl.h new file mode 100644 index 000000000..44d99c8bd --- /dev/null +++ b/private/net/svcdlls/repl/common/replgbl.h @@ -0,0 +1,139 @@ +/*++ + +Copyright (c) 1987-1993 Microsoft Corporation + +Module Name: + + ReplGbl.h + +Abstract: + + Constants and some global data definition. + +Author: + + Ported from Lan Man 2.x + +Environment: + + Contains NT-specific code. + Requires ANSI C extensions: slash-slash comments, long external names. + +Notes: + + The caller must include <lmcons.h> before this file. + +Revision History: + + 10/28/91 (madana) + ported to NT. Converted to NT style. + 20-Jan-1992 JohnRo + Changed file name from repl.h to replgbl.h to avoid MIDL conflict. + More changes suggested by PC-LINT. + 22-Jan-1992 JohnRo + Moved current role from P_repl_sw to ReplGlobalRole. + 24-Jan-1992 JohnRo + Changed to use LPTSTR etc. + Added ReplGlobal variables corresponding to the old P_ variables. + 09-Feb-1992 JohnRo + Set up to dynamically change role. + 05-Mar-1992 JohnRo + Changed ReplMain's interface to match new service controller. + 06-Mar-1992 JohnRo + Avoid starting RPC server too soon. + 24-Mar-1992 JohnRo + Renamed many ReplGlobal vars to ReplConfig vars. + 11-Aug-1992 JohnRo + RAID 2115: repl svc should wait while stopping or changing roles. + 08-Dec-1992 JohnRo + RAID 3316: access violation while stopping the replicator + 05-Jan-1993 JohnRo + Repl WAN support (get rid of repl name list limits). + 24-May-1993 JohnRo + RAID 10587: repl could deadlock with changed NetpStopRpcServer(), so + just call ExitProcess() instead. + +--*/ + + +#ifndef _REPLGBL_ +#define _REPLGBL_ + + +#include <netlock.h> // LPNET_LOCK. +//#include <repldefs.h> // MAX_NAME_BUF. +#include <winsvc.h> // SERVICE_STATUS_HANDLE, etc. + + +// +// "config" variables (read at startup and settable by NetReplSetInfo). +// + +extern LPNET_LOCK ReplConfigLock; // decl and init in repl.c +extern DWORD ReplConfigRole; // Locked by ReplConfigLock. +extern TCHAR ReplConfigExportPath[PATHLEN+1]; // Ditto. +extern LPTSTR ReplConfigExportList; // Ditto. +extern TCHAR ReplConfigImportPath[PATHLEN+1]; // Ditto. +extern LPTSTR ReplConfigImportList; // Ditto. +extern TCHAR ReplConfigLogonUserName[UNLEN+1]; // Ditto. +extern DWORD ReplConfigInterval; // Ditto. +extern DWORD ReplConfigPulse; // Ditto. +extern DWORD ReplConfigGuardTime; // Ditto. +extern DWORD ReplConfigRandom; // Ditto. + +// +// Variables to control termination of the service. +// + +extern HANDLE ReplGlobalClientTerminateEvent; +extern HANDLE ReplGlobalMasterTerminateEvent; + +// +// Variables to control service startup. +// + +extern HANDLE ReplGlobalExportStartupEvent; +extern HANDLE ReplGlobalImportStartupEvent; + +// +// Variables to control service stop. +// + +extern BOOL ReplGlobalIsServiceStopping; +extern DWORD ReplGlobalCheckpoint; + +// +// client thread handle +// +extern HANDLE ReplGlobalClientThreadHandle; + + +// +// master thread handle +// +extern HANDLE ReplGlobalMasterThreadHandle; + + +// +// Variables to control service error report. +// + +extern SERVICE_STATUS_HANDLE ReplGlobalServiceHandle; +extern DWORD ReplGlobalUninstallUicCode; + +// +// We talk to both downlevel and NT clients, who want ANSI and Unicode +// strings respectively. So, let's maintain copies of this (presumably +// constant) data in both forms: +// +extern WCHAR ReplGlobalUnicodeComputerName[CNLEN+1]; +extern WCHAR ReplGlobalUnicodeDomainName[DNLEN+1]; + +extern CHAR ReplGlobalAnsiComputerName[CNLEN+1]; +extern CHAR ReplGlobalAnsiDomainName[DNLEN+1]; + +extern LPTSTR ReplGlobalComputerName; // points to one of the above. +extern LPTSTR ReplGlobalDomainName; // points to one of the above. + + +#endif // _REPLGBL_ diff --git a/private/net/svcdlls/repl/common/replname.h b/private/net/svcdlls/repl/common/replname.h new file mode 100644 index 000000000..36afcecc2 --- /dev/null +++ b/private/net/svcdlls/repl/common/replname.h @@ -0,0 +1,35 @@ +/*++ + +Copyright (c) 1992 Microsoft Corporation + +Module Name: + + ReplName.h + +Abstract: + + Private header file which defines the replicator's interface name. + +Author: + + John Rogers (JohnRo) 16-Jan-1992 + +Revision History: + + 16-Jan-1992 JohnRo + Created the repl service RPC stuff from Rita's workstation RPC stuff. + 16-Dec-1992 JohnRo + Made changes suggested by PC-LINT 5.0 + Made this file include-able multiple times. + +--*/ + + +#ifndef _REPLNAME_ +#define _REPLNAME_ + + +#define REPLICATOR_INTERFACE_NAME (LPTSTR) TEXT("repl") + + +#endif // _REPLNAME_ diff --git a/private/net/svcdlls/repl/common/replp.c b/private/net/svcdlls/repl/common/replp.c new file mode 100644 index 000000000..f474e28aa --- /dev/null +++ b/private/net/svcdlls/repl/common/replp.c @@ -0,0 +1,271 @@ +/*++ + +Copyright (c) 1987-92 Microsoft Corporation + +Module Name: + + replp.c + +Abstract: + + contains library functions that may be moved to netlib later. + +Author: + + 10/24/91 madana + +Environment: + + Contains NT-specific code. + Requires ANSI C extensions: slash-slash comments, long external names. + +Revision History: + + 16-Jan-1992 JohnRo + Avoid using private logon functions. + Fixed bug regarding returned value from NetpReplWriteMail functions. + Fixed mistake in NetpKdPrint format string by using equate. + 23-Jan-1992 JohnRo + Indicate that NetpReplTimeNow(()) can be called even if service is + 30-Jan-1992 JohnRo + Made changes suggested by PC-LINT. + 17-Feb-1992 JohnRo + Added a little checking of mailslot name. + 21-Feb-1992 JohnRo + Minor changes to mailslot name handling. + 27-Feb-1992 JohnRo + Added debug code regarding NetpReplTimeNow(). + 11-Nov-1992 JohnRo + Fixed handle leak if WriteFile() fails. + More debug output of time. + Use PREFIX_ equates. + +--*/ + +#include <nt.h> +#include <ntrtl.h> +#include <nturtl.h> +#include <windef.h> +#include <winbase.h> + +#include <lmcons.h> +#include <netdebug.h> // NetpKdPrint(()), FORMAT_ equates, etc. +#include <netlib.h> // NetpMemoryFree(). +#include <prefix.h> // PREFIX_ equates. +#include <repldefs.h> // IF_DEBUG(). +#include <tstring.h> // NetpAlloc{type}From{type}(), etc. +#include <winerror.h> // NO_ERROR, ERROR_ equates. + + +DWORD +NetpReplTimeNow( + VOID + ) +/*++ + +Routine Description: + + Returns the current time in terms of number of seconds since + Jan 1, 1970. + + Note that this can be called even if service is not started. + + +Arguments: + + None. + +Return Value: + + Returns the current time in terms of number of seconds since + Jan 1, 1970. + +--*/ +{ + BOOL ConvOk; + NTSTATUS NtStatus; + LARGE_INTEGER TimeNow; + DWORD Time1970; + +#define SOME_BOGUS_VALUE 12345 + + NtStatus = NtQuerySystemTime( &TimeNow ); + NetpAssert( NT_SUCCESS( NtStatus ) ); + + Time1970 = SOME_BOGUS_VALUE; + ConvOk = RtlTimeToSecondsSince1970( &TimeNow, (PULONG) &Time1970 ); + + IF_DEBUG( REPL ) { + NetpKdPrint(( PREFIX_REPL + "NetpReplTimeNow: RTL says it is " FORMAT_DWORD ".\n", + Time1970 )); + NetpDbgDisplayTimestamp( " (formatted)", Time1970 ); + } + NetpAssert( ConvOk ); + NetpAssert( Time1970 != SOME_BOGUS_VALUE ); + + return Time1970; + +} // NetpReplTimeNow + + + + +NET_API_STATUS +NetpReplWriteMailW( + IN LPWSTR MailslotName, + IN LPBYTE Message, + IN DWORD MessageLength + ) +/*++ + +Routine Description : + + Writes a mail message to the specified mailslot. + +Arguments : + + MailslotName : Name of the mailslot where to write the mail + Message : mail message + Messagelength : mail message length + +Return Value : + + NO_ERROR : if the mail is successfully written to the mailslot + (other) : otherwise error code from CreateFileW or WriteFile. + +Threads: + + Only called by master, pulser, and syncer threads. + +--*/ +{ + + NET_API_STATUS ApiStatus; + HANDLE FileHandle; + DWORD NumberOfBytesWritten; + + NetpAssert( MailslotName != NULL ); + NetpAssert( MailslotName[0] == L'\\' ); + NetpAssert( MailslotName[1] == L'\\' ); + + NetpAssert( Message != NULL ); + NetpAssert( MessageLength != 0 ); + + // + // Open the mailslot to write. + // + + FileHandle = CreateFileW( + MailslotName, + GENERIC_WRITE, + FILE_SHARE_WRITE | FILE_SHARE_READ, + (LPSECURITY_ATTRIBUTES) NULL, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, + NULL ); + + if ( FileHandle == (HANDLE) (-1)) { + ApiStatus = GetLastError(); + NetpKdPrint(( PREFIX_REPL + "Problem with opening mailslot '" FORMAT_LPWSTR + "', error " FORMAT_API_STATUS ".\n", + MailslotName, ApiStatus)); + + NetpAssert( ApiStatus != NO_ERROR ); + NetpAssert( ApiStatus != ERROR_INVALID_FUNCTION ); + + return (ApiStatus); + } + + + + // + // Write message to mailslot + // + + if ( !WriteFile( + FileHandle, + Message, + MessageLength, + &NumberOfBytesWritten, + NULL + ) ) { + + ApiStatus = GetLastError(); + + NetpKdPrint(( PREFIX_REPL + "Error writing to " FORMAT_LPWSTR + " mailslot, error " FORMAT_API_STATUS ".\n", + MailslotName, ApiStatus)); + + NetpAssert( ApiStatus != NO_ERROR ); + NetpAssert( ApiStatus != ERROR_INVALID_FUNCTION ); + + (VOID) CloseHandle(FileHandle); + return (ApiStatus); + } + + (VOID) CloseHandle(FileHandle); + + return (NO_ERROR); + +} // NetpReplWriteMailW + + + + +NET_API_STATUS +NetpReplWriteMailA( + IN LPSTR MailslotName, + IN LPBYTE Message, + IN DWORD MessageLength + ) +/*++ + +Routine Description : + + Same as NetpReplWriteMailW, but the mailslot name is specified as + ANSI string. + + Writes a mail message to the specified mailslot. + +Arguments : + + MailslotName : Name of the mailslot where to write the mail + Message : mail message + Messagelength : mail message length + +Return Value : + + NO_ERROR : if the mail is successfully written to the mailslot + (other) : otherwise error code from CreateFileW or WriteFile. + +--*/ +{ + + NET_API_STATUS ApiStatus; + LPWSTR UnicodeMailslotName; + + NetpAssert( MailslotName != NULL ); + NetpAssert( MailslotName[0] == '\\' ); + NetpAssert( MailslotName[1] == '\\' ); + + NetpAssert( Message != NULL ); + NetpAssert( MessageLength != 0 ); + + UnicodeMailslotName = NetpAllocWStrFromStr( MailslotName ); + + if( UnicodeMailslotName == NULL) { + + return (ERROR_NOT_ENOUGH_MEMORY); + + } + + ApiStatus = NetpReplWriteMailW(UnicodeMailslotName, Message, MessageLength); + + NetpMemoryFree( UnicodeMailslotName ); + + return (ApiStatus); + +} // NetpReplWriteMailA diff --git a/private/net/svcdlls/repl/common/replp.h b/private/net/svcdlls/repl/common/replp.h new file mode 100644 index 000000000..fcdbee408 --- /dev/null +++ b/private/net/svcdlls/repl/common/replp.h @@ -0,0 +1,70 @@ +/*++ + +Copyright (c) 1987-92 Microsoft Corporation + +Module Name: + + replp.h + +Abstract: + + contains library functions that may be moved to netlib later. + +Author: + + 10/24/91 madana + +Environment: + + Contains NT-specific code. + Requires ANSI C extensions: slash-slash comments, long external names. + +Revision History: + + 05-Jan-1992 JohnRo + Fixed bug regarding returned value from NetpReplWriteMail functions. + 23-Jan-1992 JohnRo + Indicate that NetpReplTimeNow() can be called even if service is + not started. + +--*/ + + +#ifndef _REPLP_ +#define _REPLP_ + + +#ifdef UNICODE + +#define NetpReplWriteMail NetpReplWriteMailW + +#else // UNICODE + +#define NetpReplWriteMail NetpReplWriteMailA + +#endif // UNICODE + + +NET_API_STATUS +NetpReplWriteMailW( + IN LPWSTR, + IN LPBYTE, + IN DWORD + ); + +NET_API_STATUS +NetpReplWriteMailA( + IN LPSTR, + IN LPBYTE, + IN DWORD + ); + +// Return number of seconds since 1970. +// This can be called even if service is not started. +DWORD +NetpReplTimeNow( + VOID + ); + + +#endif // _REPLP_ diff --git a/private/net/svcdlls/repl/common/repvalid.c b/private/net/svcdlls/repl/common/repvalid.c new file mode 100644 index 000000000..428b891b6 --- /dev/null +++ b/private/net/svcdlls/repl/common/repvalid.c @@ -0,0 +1,198 @@ +/*++ + +Copyright (c) 1992-1993 Microsoft Corporation + +Module Name: + + RepValid.c + +Abstract: + + This file contains ReplConfigIsApiRecordValid(). + +Author: + + John Rogers (JohnRo) 14-Feb-1992 + +Environment: + + User Mode - Win32 + Portable to any flat, 32-bit environment. (Uses Win32 typedefs.) + Requires ANSI C extensions: slash-slash comments, long external names. + +Revision History: + + 14-Feb-1992 JohnRo + Created. + 18-Feb-1992 JohnRo + Use ReplCheckAbsPathSyntax(). + Use ReplIs{Interval,GuardTime,Pulse,Random}Valid() macros. + 10-Mar-1992 JohnRo + Added support for setinfo info levels. + 14-Aug-1992 JohnRo + Help track down bogus import/export lists. + 04-Jan-1993 JohnRo + Made changes suggested by PC-LINT 5.0 + +--*/ + + +#include <windef.h> // IN, DWORD, etc. +#include <lmcons.h> // LAN Manager common definitions +#include <rpc.h> // Needed by <repl.h>. + +#include <iniparm.h> // MIN_ and MAX_ equates. +#include <lmrepl.h> // LPREPL_INFO_0. +#include <netlib.h> // IN_RANGE(). +#include <replconf.h> // ReplConfigIsListValid(). +#include <repldefs.h> // ReplIsRoleValid(). +#include <winerror.h> // ERROR_ and NO_ERROR equates. + + +BOOL +ReplConfigIsApiRecordValid ( + IN DWORD Level, // Level must not be a setinfo-only level. + IN LPVOID ApiRecord, + OUT LPDWORD ParmError OPTIONAL // Set implicitly by some macros. + ) + +{ + + if (ApiRecord == NULL) { + NetpSetParmError( PARM_ERROR_UNKNOWN ); + return (FALSE); // No, it is not valid. + } + + // + // Check the actual data, based on the level. + // + + switch (Level) { + case 0 : + { + LPREPL_INFO_0 Buffer = ApiRecord; + + +#define CHECK_LIST( fieldName, parm_error ) \ + { \ + if (Buffer->rp0_ ## fieldName) { \ + if ( !ReplConfigIsListValid( Buffer->rp0_ ## fieldName ) ) { \ + NetpSetParmError( parm_error ); \ + return (FALSE); /* No, it is not valid. */ \ + } \ + } \ + } + + +#define CHECK_PATH( fieldName, parm_error ) \ + { \ + DWORD ApiStatus; \ + if (Buffer->rp0_ ## fieldName) { \ + ApiStatus = ReplCheckAbsPathSyntax( Buffer->rp0_ ## fieldName ); \ + if (ApiStatus != NO_ERROR) { \ + NetpSetParmError( parm_error ); \ + return (FALSE); /* No, it is not valid. */ \ + } \ + } \ + } + + + if ( ! ReplIsRoleValid( Buffer->rp0_role ) ) { + NetpSetParmError( 1 ); // first field in structure + return (FALSE); // No, it is not valid. + } + + CHECK_PATH( exportpath, 2 ); // second... + + CHECK_LIST( exportlist, 3 ); // third... + + CHECK_PATH( importpath, 4 ); // fourth... + + CHECK_LIST( importlist, 5 ); // fifth... + + // BUGBUG: Handle logonusername!!! // sixth... + + if ( !ReplIsIntervalValid( Buffer->rp0_interval ) ) { + NetpSetParmError( 7 ); // seventh... + return (FALSE); // No, it is not valid. + } + + if ( !ReplIsPulseValid( Buffer->rp0_pulse ) ) { + NetpSetParmError( 8 ); // eighth... + return (FALSE); // No, it is not valid. + } + + if ( !ReplIsGuardTimeValid( Buffer->rp0_guardtime ) ) { + NetpSetParmError( 9 ); // ninth... + return (FALSE); // No, it is not valid. + } + + if ( !ReplIsRandomValid( Buffer->rp0_random ) ) { + NetpSetParmError( 10 ); // tenth... + return (FALSE); // No, it is not valid. + } + + + } + return (TRUE); // yes, it's valid. + + case 1000 : + { + LPREPL_INFO_1000 Buffer = (LPVOID) ApiRecord; + DWORD NewValue = Buffer->rp1000_interval; + + if ( !ReplIsIntervalValid( NewValue ) ) { + NetpSetParmError( 1 ); // first field in structure. + return (FALSE); // No, it is not valid. + } + + } + return (TRUE); // yes, it's valid. + + case 1001 : + { + LPREPL_INFO_1001 Buffer = (LPVOID) ApiRecord; + DWORD NewValue = Buffer->rp1001_pulse; + + if ( !ReplIsPulseValid( NewValue ) ) { + NetpSetParmError( 1 ); // first field in structure. + return (FALSE); // No, it is not valid. + } + + } + return (TRUE); // yes, it's valid. + + case 1002 : + { + LPREPL_INFO_1002 Buffer = (LPVOID) ApiRecord; + DWORD NewValue = Buffer->rp1002_guardtime; + + if ( !ReplIsGuardTimeValid( NewValue ) ) { + NetpSetParmError( 1 ); // first field in structure. + return (FALSE); // No, it is not valid. + } + + } + return (TRUE); // yes, it's valid. + + case 1003 : + { + LPREPL_INFO_1003 Buffer = (LPVOID) ApiRecord; + DWORD NewValue = Buffer->rp1003_random; + + if ( !ReplIsRandomValid( NewValue ) ) { + NetpSetParmError( 1 ); // first field in structure. + return (FALSE); // No, it is not valid. + } + + } + return (TRUE); // yes, it's valid. + + default : + NetpSetParmError( PARM_ERROR_UNKNOWN ); + return (FALSE); // Don't know level, so say record is not valid. + } + + /*NOTREACHED*/ + +} // ReplConfigIsApiRecordValid diff --git a/private/net/svcdlls/repl/common/sources b/private/net/svcdlls/repl/common/sources new file mode 100644 index 000000000..9dbfb0d69 --- /dev/null +++ b/private/net/svcdlls/repl/common/sources @@ -0,0 +1,133 @@ +!IF 0 + +Copyright (c) 1989-1993 Microsoft Corporation + +Module Name: + + sources. + +Abstract: + + This file specifies the target component being built and the list of + sources files needed to build that component. Also specifies optional + compiler switches and libraries that are unique for the component being + built. + +Author: + + Steve Wood (stevewo) 12-Apr-1990 + +NOTE: Commented description of this file is in \nt\public\oak\bin\sources.tpl + +!ENDIF + +# +# The MAJORCOMP and MINORCOMP variables are defined +# so that $(MAJORCOMP)$(MINORCOMP)filename can be used in +# cross compiling to provide unique filenames in a flat namespace. +# + +MAJORCOMP=net +MINORCOMP=repl + + +NTPROFILEINPUT=YES + +# +# The TARGETNAME variable is defined by the developer. It is the name of +# the target (component) that is being built by this makefile. It +# should NOT include any path or file extension information. +# + +TARGETNAME=replcom + +# +# The TARGETPATH and TARGETTYPE variables are defined by the developer. +# The first specifies where the target is to be build. The second specifies +# the type of target (either PROGRAM, DYNLINK, LIBRARY, UMAPPL_NOLIB or +# BOOTPGM). UMAPPL_NOLIB is used when you're only building user-mode +# apps and don't need to build a library. +# + +TARGETPATH=obj + +# Pick one of the following and delete the others +TARGETTYPE=LIBRARY + +# +# The TARGETLIBS specifies additional libraries to link with you target +# image. Each library path specification should contain an asterisk (*) +# where the machine specific subdirectory name should go. +# + +TARGETLIBS= + +# +# The INCLUDES variable specifies any include paths that are specific to +# this source directory. Separate multiple directory paths with single +# semicolons. Relative path specifications are okay. +# + +# ..\server is where IgnoreNm.c gets Client.h until we can move some +# equates from Client.h to ReplDefs.h. +INCLUDES=.;..\..\..\inc;..\..\..\api;..\..\..\..\inc;..\server + +# +# The SOURCES variable is defined by the developer. It is a list of all the +# source files for this component. Each source file should be on a separate +# line using the line continuation character. This will minimize merge +# conflicts if two developers adding source files to the same component. +# + +!IFNDEF DISABLE_NET_UNICODE +UNICODE=1 +NET_C_DEFINES=-DUNICODE +!ENDIF + +USE_CRTDLL=1 + +SOURCES= \ + AbsPath.c \ + AllowRol.c \ + ChngLock.c \ + ChngNot.c \ + Data.c \ + DelFile.c \ + DirName.c \ + EaSize.c \ + ExpAlloc.c \ + ExpBuild.c \ + ExpConf.c \ + ExpEnum.c \ + ExpGet.c \ + ExpLock.c \ + ExpSet.c \ + ExpValid.c \ + FixLocks.c \ + FsResolu.c \ + IgnoreNm.c \ + ImpAlloc.c \ + ImpBuild.c \ + ImpConf.c \ + ImpGet.c \ + ImpLock.c \ + ImpState.c \ + ImpEnum.c \ + ImpValid.c \ + LstValid.c \ + ReplBld.c \ + ReplConf.c \ + ReplErr.c \ + ReplP.c \ + RepValid.c \ + UserLock.c + +# +# Next specify options for the compiler. +# + +# C_DEFINES=-DTRACE -DTRACE2 -DDEBUG + +C_DEFINES=-DRPC_NO_WINDOWS_H +WARNING_LEVEL=-W4 + diff --git a/private/net/svcdlls/repl/common/userlock.c b/private/net/svcdlls/repl/common/userlock.c new file mode 100644 index 000000000..c142993ad --- /dev/null +++ b/private/net/svcdlls/repl/common/userlock.c @@ -0,0 +1,158 @@ +/*++ + +Copyright (c) 1993 Microsoft Corporation + +Module Name: + + UserLock.c + +Abstract: + + ReplDoUserLockFilesExist(). + + This routine checks for UserLock.* files in the directory given. + The directory may be a UNC path name. + + This is callable even if the replicator service is not started. + +Author: + + JR (John Rogers, JohnRo@Microsoft)) 13-Jan-1993 + +Environment: + + User Mode - Win32 + Portable to any flat, 32-bit environment. (Uses Win32 typedefs.) + Requires ANSI C extensions: slash-slash comments, long external names. + +Revision History: + + 13-Jan-1993 JohnRo + Created for RAID 7053: locked trees added to pulse msg. (Actually + fix all kinds of remote lock handling.) + 02-Feb-1993 JohnRo + RAID 8355: Downlevel lock file check causes assert in repl importer. + +--*/ + + +// These must be included first: + +#include <windows.h> // FindFirstFile(), IN, LPCTSTR, OPTIONAL, etc. +#include <lmcons.h> // NET_API_STATUS. + +// These may be included in any order: + + +#include <client.h> // USER_LOCK. +#include <lmerrlog.h> // NELOG_ equates. +#include <netdebug.h> // NetpAssert(), NetpKdPrint(), FORMAT_ equates, etc. +#include <prefix.h> // PREFIX_ equates. +#include <repldefs.h> // My prototype, ReplErrorLog(), SLASH, etc. +#include <tstr.h> // IS_PATH_SEPARATOR(), STRCAT(), STRCPY(), STRLEN(). +#include <winerror.h> // ERROR_, NO_ERROR equates. + + +// Callable even if the replicator service is not started. +NET_API_STATUS +ReplDoUserLockFilesExist( + IN LPCTSTR Path, // May be absolute path (with drive) or UNC path. + OUT LPBOOL IsLockedPtr + ) +{ + NET_API_STATUS ApiStatus; + BOOL DirLocked = FALSE; // Default is not locked. + WIN32_FIND_DATA FindData; + HANDLE FindHandle = INVALID_HANDLE_VALUE; + TCHAR SearchPattern[MAX_PATH+1]; + + // + // Check for caller errors. + // + NetpAssert( IsLockedPtr != NULL ); + + if ( IS_PATH_SEPARATOR(Path[0]) ) { + // BUGBUG: Syntax check somehow. + // NetpAssert( NetpIsRemotePathValid( Path ) ); + if ( ! IS_PATH_SEPARATOR(Path[1]) ) { + ApiStatus = ERROR_INVALID_PARAMETER; + goto Cleanup; // Don't forget to unlock stuff. + } + } else { + ApiStatus = ReplCheckAbsPathSyntax( (LPTSTR) Path ); + if (ApiStatus != NO_ERROR) { + goto Cleanup; // Don't forget to unlock stuff. + } + } + + // + // Build a search pattern. This will look like one of the following: + // c:\dir1\dir2\dir3\USERLOCK.* + // \\server\REPL$\dirname\USERLOCK.* + // + + (VOID) STRCPY( SearchPattern, (LPTSTR) Path ); + (VOID) STRCAT( SearchPattern, SLASH ); + (VOID) STRCAT( SearchPattern, USER_LOCK ); // "USERLOCK.*". + + NetpAssert( STRLEN( SearchPattern ) <= MAX_PATH ); + + // NetpAssert( NetpIsRemotePathValid( SearchPattern ) ); + + // + // Check if any USERLOCK.* exists. + // + FindHandle = FindFirstFile( + SearchPattern, + &FindData ); + if (FindHandle != INVALID_HANDLE_VALUE) { + // Yes, there is a lock file. + DirLocked = TRUE; + ApiStatus = NO_ERROR; + } else { + ApiStatus = (NET_API_STATUS) GetLastError(); + IF_DEBUG( FILEFIND ) { + NetpKdPrint(( PREFIX_REPL + "ReplDoUserLockFilesExist: got err " FORMAT_API_STATUS + " from FindFirstFile.\n", + ApiStatus )); + } + NetpAssert( ApiStatus != NO_ERROR ); + if (ApiStatus == ERROR_FILE_NOT_FOUND) { + // No lock file. + DirLocked = FALSE; + ApiStatus = NO_ERROR; + } + // Unexpected error will be logged below. + } + + +Cleanup: + + if (ApiStatus != NO_ERROR) { + + ReplErrorLog( + NULL, // local (no server name) + NELOG_ReplSysErr, // log code + ApiStatus, // the unexpected error code + NULL, // no optional str1 + NULL ); // no optional str2 + + // BUGBUG: log unexpected error on remote machine too, if UNC path. + + NetpKdPrint(( PREFIX_REPL + "ReplDoUserLockFilesExist: ERROR " FORMAT_API_STATUS ".\n", + ApiStatus )); + } + + if (FindHandle != INVALID_HANDLE_VALUE) { + (VOID) FindClose( FindHandle ); + } + + if (IsLockedPtr != NULL) { + *IsLockedPtr = DirLocked; + } + + return (ApiStatus); + +} |