瀏覽代碼

Resolves: bug 185602
Bug Description: Netscape Console allows instance directory to be set as change log
Reviewed by: nkinder (Thanks!)
Fix Description: 1) When removing the changelog files and directories, only remove the actual db related files - version, guardian, *db4, log.*, and __db.* - This should take care of the cases where the changelog was already created in an existing directory.
2) Disallow adding/changing a changelog db directory if it already exists and is not empty
Platforms tested: RHEL5 x86_64
Flag Day: no
Doc impact: no
QA impact: should be covered by regular nightly and manual testing
New Tests integrated into TET: none

Rich Megginson 18 年之前
父節點
當前提交
5cf62b66a4

+ 78 - 1
ldap/servers/plugins/replication/cl5_api.c

@@ -3835,6 +3835,39 @@ static void _cl5DBClose ()
 	}
 }
 
+/* see if the given file is a changelog db file */
+static int
+_cl5IsDbFile(const char *fname)
+{
+	char *ptr = NULL;
+	if (!fname || !*fname) {
+		return 0;
+	}
+
+	if (!strcmp(fname, GUARDIAN_FILE)) {
+		return 1;
+	}
+
+	if (!strcmp(fname, VERSION_FILE)) {
+		return 1;
+	}
+
+	if (_cl5FileEndsWith(fname, DB_EXTENSION)) {
+		return 1;
+	}
+
+	if (_cl5IsLogFile(fname)) {
+		return 1;
+	}
+
+	ptr = strstr(fname, "__db.");
+	if (ptr == fname) { /* begins with __db. */
+		return 1;
+	}
+
+	return 0; /* not a filename we recognize as being associated with the db */
+}
+
 /* state lock must be locked */
 static int  _cl5Delete (const char *clDir, int rmDir)
 {
@@ -3842,6 +3875,7 @@ static int  _cl5Delete (const char *clDir, int rmDir)
 	char  filename[MAXPATHLEN + 1];
 	PRDirEntry *entry = NULL;
 	int rc;
+	int dirisempty = 1;
 
 	/* remove all files in the directory and the directory */
 	dir = PR_OpenDir(clDir);
@@ -3860,6 +3894,13 @@ static int  _cl5Delete (const char *clDir, int rmDir)
 		{
 			break;
 		}
+		if (!_cl5IsDbFile(entry->name)) {
+			slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name_cl, 
+							"_cl5Delete: Skipping file [%s/%s] because it is not a changelogdb file.\n",
+							clDir, entry->name);
+			dirisempty = 0; /* skipped at least one file - dir not empty */
+			continue;
+		}
 		PR_snprintf(filename, MAXPATHLEN, "%s/%s", clDir, entry->name);
 		rc = PR_Delete(filename);
 		if (rc != PR_SUCCESS)
@@ -3879,7 +3920,7 @@ static int  _cl5Delete (const char *clDir, int rmDir)
 		return CL5_SYSTEM_ERROR;
 	}
 		
-	if (rmDir)
+	if (rmDir && dirisempty)
 	{
 		rc = PR_RmDir (clDir);
 		if (rc != 0)
@@ -3889,6 +3930,10 @@ static int  _cl5Delete (const char *clDir, int rmDir)
 					clDir, errno);
 			return CL5_SYSTEM_ERROR;
 		}
+	} else if (rmDir && !dirisempty) {
+		slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name_cl, 
+						"_cl5Delete: changelog dir (%s) is not empty - cannot remove\n",
+						clDir);
 	}
 			
 	return CL5_SUCCESS;
@@ -6770,3 +6815,35 @@ cl5_diskspace_is_available()
 #endif
     return rval;
 }
+
+int
+cl5DbDirIsEmpty(const char *dir)
+{
+	PRDir *prDir;
+	PRDirEntry *prDirEntry;
+	int isempty = 1;
+
+	if (!dir || !*dir) {
+		return isempty;
+	}
+	/* assume failure means it does not exist - other failure
+	   cases will be handled by code which attempts to create the
+	   db in this directory */
+	if (PR_Access(dir, PR_ACCESS_EXISTS)) {
+		return isempty;
+	}
+	prDir = PR_OpenDir(dir);
+	if (prDir == NULL) {
+		return isempty; /* assume failure means does not exist */
+	}
+	while (NULL != (prDirEntry = PR_ReadDir(prDir, PR_SKIP_DOT | PR_SKIP_DOT_DOT))) {
+		if (NULL == prDirEntry->name) {	/* NSPR doesn't behave like the docs say it should */
+			break;
+		}
+		isempty = 0; /* found at least one "real" file */
+		break;
+	}
+	PR_CloseDir(prDir);
+
+	return isempty;
+}

+ 9 - 0
ldap/servers/plugins/replication/cl5_api.h

@@ -519,4 +519,13 @@ void cl5DestroyCSNList (CSN*** csns);
 int cl5_is_diskfull();
 int cl5_diskspace_is_available();
 
+/* Name: cl5DbDirIsEmpty
+   Description: See if the given cldb directory is empty or doesn't yet exist.
+   Parameters:	dir - Contains the name of the directory.
+   Return:		TRUE - directory does not exist or is empty, is NULL, or is
+                       an empty string
+				FALSE - otherwise
+*/
+int cl5DbDirIsEmpty(const char *dir);
+
 #endif

+ 28 - 0
ldap/servers/plugins/replication/cl5_config.c

@@ -205,6 +205,20 @@ changelog5_config_add (Slapi_PBlock *pb, Slapi_Entry* e, Slapi_Entry* entryAfter
 		goto done;	
 	}	
 
+	if (!cl5DbDirIsEmpty(config.dir))
+	{
+		*returncode = 1;
+		if (returntext)
+		{
+			PR_snprintf(returntext, SLAPI_DSE_RETURNTEXT_SIZE,
+						"The changelog directory [%s] already exists and is not empty.  "
+						"Please choose a directory that does not exist or is empty.\n",
+						config.dir);
+		}
+		
+		goto done;
+	}
+
 	/* start the changelog */
 	rc = cl5Open (config.dir, &config.dbconfig);
 	if (rc != CL5_SUCCESS)
@@ -450,6 +464,20 @@ changelog5_config_modify (Slapi_PBlock *pb, Slapi_Entry* entryBefore, Slapi_Entr
 		if (strcmp (currentDir, config.dir) != 0)
 #endif
 		{
+			if (!cl5DbDirIsEmpty(config.dir))
+			{
+				*returncode = 1;
+				if (returntext)
+				{
+					PR_snprintf(returntext, SLAPI_DSE_RETURNTEXT_SIZE,
+								"The changelog directory [%s] already exists and is not empty.  "
+								"Please choose a directory that does not exist or is empty.\n",
+								config.dir);
+				}
+
+				goto done;
+			}
+
 			if (!_is_absolutepath(config.dir) || (CL5_SUCCESS != cl5CreateDirIfNeeded(config.dir)))
 			{
 				*returncode = 1;