/*++ Copyright (c) 1992-1993 Microsoft Corporation Module Name: ExpLock.c Abstract: This file contains: NetrReplExportDirLock NetrReplExportDirUnlock Author: John Rogers (JohnRo) 07-Jan-1992 Environment: Runs under Windows NT. Requires ANSI C extensions: slash-slash comments, long external names. 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: 07-Jan-1992 JohnRo Created. 20-Jan-1992 JohnRo Netr prototypes are now generated by MIDL and put in repl.h. 24-Jan-1992 JohnRo Changed to use LPTSTR etc. 18-Feb-1992 JohnRo Use Repl{Incr,Decr}LockFields(). 15-Mar-1992 JohnRo Update registry with new values. 22-Jul-1992 JohnRo RAID 2274: repl svc should impersonate caller. 17-Nov-1992 JohnRo RAID 1537: repl APIs in wrong role kill service. 12-Jan-1993 JohnRo RAID 7064: replicator exporter skips new data (change notify while dir locked is lost). Made changes suggested by PC-LINT 5.0 13-Jan-1993 JohnRo RAID 7053: locked trees added to pulse msg. (Actually fix all kinds of remote lock handling.) 04-Mar-1993 JohnRo RAID 7988: downlevel repl importer might not see lock file for new first-level dir. 13-Apr-1993 JohnRo RAID 3107: locking directory over the net gives network path not found. --*/ // These must be included first: #include // IN, VOID, LPTSTR, etc. #include // NET_API_STATUS, PARM equates, etc. #include // (Required by masproto.h) #include // LPMASTER_LIST_REC, RMGlobalListLock. #include // Needed by . // These can be in any order: #include // ReplIsDirNameValid(). #include // ExportDirLockInRegistry(), etc. #include // NERR_ equates, NO_ERROR. #include // REPL_UNLOCK_ equates. #include // GetMasterRec(). #include // NetpAssert(). #include // ACQUIRE_LOCK(), etc. #include // PulserTimeOfLastNotifyOrUnlock, etc. #include // My prototype (in MIDL-generated .h file). #include // ReplConfigLock, ReplConfigRole. #include // NetpReplTimeNow(). #include // NetpImpersonateClient(), NetpRevertToSelf(). NET_API_STATUS NetrReplExportDirLock ( IN LPTSTR UncServerName OPTIONAL, IN LPTSTR DirName ) /*++ Routine Description: Same as NetReplExportDirLock. Arguments: Same as NetReplExportDirLock. Return Value: Same as NetReplExportDirLock. --*/ { NET_API_STATUS ApiStatus; BOOL ConfigLocked = FALSE; BOOL Impersonated = FALSE; BOOL ListLocked = FALSE; LPMASTER_LIST_REC MasterRecord; if ( !ReplIsDirNameValid( DirName ) ) { return (ERROR_INVALID_PARAMETER); } // // Impersonate caller, so security check (write to registry) reflects // the client's process, not the repl service process. // ApiStatus = NetpImpersonateClient(); if (ApiStatus != NO_ERROR) { goto Cleanup; } Impersonated = TRUE; // // Get a shared lock on config data so we can see if role includes export. // ACQUIRE_LOCK_SHARED( ReplConfigLock ); ConfigLocked = TRUE; // // Lock global list and matching registry data. // We need this lock even if this side of service is not running, // because the XxxDirLockInRegistry routines are not atomic. // ACQUIRE_LOCK_SHARED( RMGlobalListLock ); ListLocked = TRUE; // // Update lock values in registry first. // This has the side-effect of doing a security check. // ApiStatus = ExportDirLockInRegistry( UncServerName, DirName ); if ( (ApiStatus == NO_ERROR) && (ReplRoleIncludesExport(ReplConfigRole)) ) { MasterRecord = GetMasterRec( DirName ); if (MasterRecord == NULL) { ApiStatus = NERR_UnknownDevDir; goto Cleanup; // Don't forget to release lock... } else { // // Update lock values in service. // ApiStatus = ReplIncrLockFields( & (MasterRecord->lockcount), & (MasterRecord->time_of_first_lock) ); NetpAssert( ApiStatus == NO_ERROR ); // BUGBUG // // Make sure we have a userlock file, so downlevel clients // know about lock. // ApiStatus = ExportDirFixUserLockFiles( (LPCTSTR) ReplConfigExportPath, (LPCTSTR) DirName, MasterRecord->lockcount ); NetpAssert( ApiStatus == NO_ERROR ); // BUGBUG if (ApiStatus != NO_ERROR) { goto Cleanup; } MasterRecord->locks_fixed = TRUE; } } Cleanup: if (Impersonated) { (VOID) NetpRevertToSelf(); } if (ListLocked) { RELEASE_LOCK( RMGlobalListLock ); } if (ConfigLocked) { RELEASE_LOCK( ReplConfigLock ); } return (ApiStatus); } // NetrReplExportDirLock NET_API_STATUS NetrReplExportDirUnlock ( IN LPTSTR UncServerName OPTIONAL, IN LPTSTR DirName, IN DWORD UnlockForce ) /*++ Routine Description: Same as NetReplExportDirUnlock. Arguments: Same as NetReplExportDirUnlock. Return Value: Same as NetReplExportDirUnlock. --*/ { NET_API_STATUS ApiStatus; BOOL ConfigLocked = FALSE; BOOL Impersonated = FALSE; BOOL ListLocked = FALSE; LPMASTER_LIST_REC MasterRecord; if ( !ReplIsDirNameValid( DirName ) ) { return (ERROR_INVALID_PARAMETER); } else if ( !ReplIsForceLevelValid( UnlockForce ) ) { return (ERROR_INVALID_PARAMETER); } // // Impersonate caller, so security check (write to registry) reflects // the client's process, not the repl service process. // ApiStatus = NetpImpersonateClient(); if (ApiStatus != NO_ERROR) { goto Cleanup; } Impersonated = TRUE; // // Get a shared lock on config data so we can see if role includes export. // ACQUIRE_LOCK_SHARED( ReplConfigLock ); ConfigLocked = TRUE; // // Lock global list and matching registry data. // We need this lock even if this side of service is not running, // because the XxxDirLockInRegistry routines are not atomic. // ACQUIRE_LOCK_SHARED( RMGlobalListLock ); ListLocked = TRUE; // // Update lock values in registry first. // This has the side-effect of doing a security check. // ApiStatus = ExportDirUnlockInRegistry( UncServerName, DirName, UnlockForce ); if ( (ApiStatus == NO_ERROR) && (ReplRoleIncludesExport(ReplConfigRole)) ) { MasterRecord = GetMasterRec( DirName ); if (MasterRecord == NULL) { ApiStatus = NERR_UnknownDevDir; // Don't forget to release lock... } else { // // Update lock values in service. // ApiStatus = ReplDecrLockFields( & (MasterRecord->lockcount), & (MasterRecord->time_of_first_lock), UnlockForce ); NetpAssert( ApiStatus == NO_ERROR ); // BUGBUG // // Update time so pulser knows to do another checksum. // PulserTimeOfLastNotifyOrUnlock = NetpReplTimeNow(); // // Consider removing userlock file, so downlevel clients // know we don't have lock anymore. // ApiStatus = ExportDirFixUserLockFiles( (LPCTSTR) ReplConfigExportPath, (LPCTSTR) DirName, MasterRecord->lockcount ); NetpAssert( ApiStatus == NO_ERROR ); // BUGBUG if (ApiStatus != NO_ERROR) { goto Cleanup; // Don't forget to release lock... } MasterRecord->locks_fixed = TRUE; } } Cleanup: if (Impersonated) { (VOID) NetpRevertToSelf(); } if (ListLocked) { RELEASE_LOCK( RMGlobalListLock ); } if (ConfigLocked) { RELEASE_LOCK( ReplConfigLock ); } return (ApiStatus); } // NetrReplExportDirUnlock