summaryrefslogtreecommitdiffstats
path: root/ldap/admin/lib/dsalib_util.c
diff options
context:
space:
mode:
authorcvsadm <cvsadm>2005-01-21 00:44:34 +0000
committercvsadm <cvsadm>2005-01-21 00:44:34 +0000
commitb2093e3016027d6b5cf06b3f91f30769bfc099e2 (patch)
treecf58939393a9032182c4fbc4441164a9456e82f8 /ldap/admin/lib/dsalib_util.c
downloadds-ldapserver7x.tar.gz
ds-ldapserver7x.tar.xz
ds-ldapserver7x.zip
Moving NSCP Directory Server from DirectoryBranch to TRUNK, initial drop. (foxworth)ldapserver7x
Diffstat (limited to 'ldap/admin/lib/dsalib_util.c')
-rw-r--r--ldap/admin/lib/dsalib_util.c1123
1 files changed, 1123 insertions, 0 deletions
diff --git a/ldap/admin/lib/dsalib_util.c b/ldap/admin/lib/dsalib_util.c
new file mode 100644
index 00000000..a6cf4bee
--- /dev/null
+++ b/ldap/admin/lib/dsalib_util.c
@@ -0,0 +1,1123 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+#if defined( XP_WIN32 )
+#include <windows.h>
+#include <io.h>
+#else /* XP_WIN32 */
+# if defined( AIXV4 )
+# include <fcntl.h>
+# else /* AIXV4 */
+# include <sys/fcntl.h>
+# endif /* AIXV4 */
+#include <dirent.h>
+#include <unistd.h>
+#include <fcntl.h>
+#endif /* XP_WIN3 */
+#include "dsalib.h"
+#include <sys/types.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <ctype.h>
+#include <nspr.h>
+
+#define COPY_BUFFER_SIZE 4096
+/* This is the separator string to use when outputting key/value pairs
+ to be read by the non-HTML front end (Java console)
+*/
+static const char *SEPARATOR = ":"; /* from AdmTask.java */
+
+#define LOGFILEENVVAR "DEBUG_LOGFILE" /* used for logfp */
+
+static int internal_rm_rf(const char *path, DS_RM_RF_ERR_FUNC ds_rm_rf_err_func, void *arg);
+
+/* return a FILE * opened in append mode to the log file
+ caller must use fclose to close it
+*/
+static FILE *
+get_logfp(void)
+{
+ FILE *logfp = NULL;
+ char *logfile = getenv(LOGFILEENVVAR);
+
+ if (logfile) {
+ logfp = fopen(logfile, "a");
+ }
+ return logfp;
+}
+
+DS_EXPORT_SYMBOL int
+ds_file_exists(char *filename)
+{
+ struct stat finfo;
+
+ if ( filename == NULL )
+ return 0;
+
+ if ( stat(filename, &finfo) == 0 ) /* successful */
+ return 1;
+ else
+ return 0;
+}
+
+DS_EXPORT_SYMBOL int
+ds_mkdir(char *dir, int mode)
+{
+ if(!ds_file_exists(dir)) {
+#ifdef XP_UNIX
+ if(mkdir(dir, mode) == -1)
+#else /* XP_WIN32 */
+ if(!CreateDirectory(dir, NULL))
+#endif /* XP_WIN32 */
+ return -1;
+ }
+ return 0;
+}
+
+
+DS_EXPORT_SYMBOL char *
+ds_mkdir_p(char *dir, int mode)
+{
+ static char errmsg[ERR_SIZE];
+ struct stat fi;
+ char *t;
+
+#ifdef XP_UNIX
+ t = dir + 1;
+#else /* XP_WIN32 */
+ t = dir + 3;
+#endif /* XP_WIN32 */
+
+ while(1) {
+ t = strchr(t, FILE_PATHSEP);
+
+ if(t) *t = '\0';
+ if(stat(dir, &fi) == -1) {
+ if(ds_mkdir(dir, mode) == -1) {
+ sprintf(errmsg, "mkdir %s failed (%s)", dir, ds_system_errmsg());
+ return errmsg;
+ }
+ }
+ if(t) *t++ = FILE_PATHSEP;
+ else break;
+ }
+ return NULL;
+}
+
+
+/*
+ * Given the name of a directory, return a NULL-terminated array of
+ * the file names contained in that directory. Returns NULL if the directory
+ * does not exist or an error occurs, and returns an array with a
+ * single NULL string if the directory exists but is empty. The caller
+ * is responsible for freeing the returned array of strings.
+ * File names "." and ".." are not returned.
+ */
+#if !defined( XP_WIN32 )
+DS_EXPORT_SYMBOL char **
+ds_get_file_list( char *dir )
+{
+ DIR *dirp;
+ struct dirent *direntp;
+ char **ret = NULL;
+ int nfiles = 0;
+
+ if (( dirp = opendir( dir )) == NULL ) {
+ return NULL;
+ }
+
+ if (( ret = malloc( sizeof( char * ))) == NULL ) {
+ return NULL;
+ };
+
+ while (( direntp = readdir( dirp )) != NULL ) {
+ if ( strcmp( direntp->d_name, "." ) &&
+ strcmp( direntp->d_name, ".." )) {
+ if (( ret = (char **) realloc( ret,
+ sizeof( char * ) * ( nfiles + 2 ))) == NULL );
+ ret[ nfiles ] = strdup( direntp->d_name );
+ nfiles++;
+ }
+ }
+ (void) closedir( dirp );
+
+ ret[ nfiles ] = NULL;
+ return ret;
+}
+#else
+DS_EXPORT_SYMBOL char **
+ds_get_file_list( char *dir )
+{
+ char szWildcardFileSpec[MAX_PATH];
+ char **ret = NULL;
+ long hFile;
+ struct _finddata_t fileinfo;
+ int nfiles = 0;
+
+ if( ( dir == NULL ) || (strlen( dir ) == 0) )
+ return NULL;
+
+ if( ( ret = malloc( sizeof( char * ) ) ) == NULL )
+ return NULL;
+
+ strcpy(szWildcardFileSpec, dir);
+ strcat(szWildcardFileSpec, "/*");
+
+ hFile = _findfirst( szWildcardFileSpec, &fileinfo);
+ if( hFile == -1 )
+ return NULL;
+
+ if( ( strcmp( fileinfo.name, "." ) != 0 ) &&
+ ( strcmp( fileinfo.name, ".." ) != 0 ) )
+ {
+ ret[ nfiles++ ] = strdup( fileinfo.name );
+ }
+
+ while( _findnext( hFile, &fileinfo ) == 0 )
+ {
+ if( ( strcmp( fileinfo.name, "." ) != 0 ) &&
+ ( strcmp( fileinfo.name, ".." ) != 0 ) )
+ {
+ if( ( ret = (char **) realloc( ret, sizeof( char * ) * ( nfiles + 2 ) ) ) != NULL )
+ ret[ nfiles++ ] = strdup( fileinfo.name);
+ }
+ }
+
+ _findclose( hFile );
+ ret[ nfiles ] = NULL;
+ return ret;
+}
+#endif /* ( XP_WIN32 ) */
+
+
+DS_EXPORT_SYMBOL time_t
+ds_get_mtime(char *filename)
+{
+ struct stat fi;
+
+ if ( stat(filename, &fi) )
+ return 0;
+ return fi.st_mtime;
+}
+
+/*
+ * Copy files: return is
+ * 1: success
+ * 0: failure
+ * Print errors as needed.
+ */
+DS_EXPORT_SYMBOL int
+ds_cp_file(char *sfile, char *dfile, int mode)
+{
+#if defined( XP_WIN32 )
+ return( CopyFile( sfile, dfile, FALSE ) ); /* Copy even if dfile exists */
+#else
+ int sfd, dfd, len;
+ struct stat fi;
+ char copy_buffer[COPY_BUFFER_SIZE];
+ unsigned long read_len;
+ char error[BIG_LINE];
+
+/* Make sure we're in the right umask */
+ umask(022);
+
+ if( (sfd = open(sfile, O_RDONLY)) == -1) {
+ sprintf(error, "Can't open file %s for reading.", sfile);
+ ds_send_error(error, 1);
+ return(0);
+ }
+
+ fstat(sfd, &fi);
+ if (!(S_ISREG(fi.st_mode))) {
+ sprintf(error, "File %s is not a regular file.", sfile);
+ ds_send_error(error, 1);
+ close(sfd);
+ return(0);
+ }
+ len = fi.st_size;
+
+ if( (dfd = open(dfile, O_RDWR | O_CREAT | O_TRUNC, mode)) == -1) {
+ sprintf(error, "can't write to file %s", dfile);
+ ds_send_error(error, 1);
+ close(sfd);
+ return(0);
+ }
+ while (len) {
+ read_len = len>COPY_BUFFER_SIZE?COPY_BUFFER_SIZE:len;
+
+ if ( (read_len = read(sfd, copy_buffer, read_len)) == -1) {
+ sprintf(error, "Error reading file %s for copy.", sfile);
+ ds_send_error(error, 1);
+ close(sfd);
+ close(dfd);
+ return(0);
+ }
+
+ if ( write(dfd, copy_buffer, read_len) != read_len) {
+ sprintf(error, "Error writing file %s for copy.", dfile);
+ ds_send_error(error, 1);
+ close(sfd);
+ close(dfd);
+ return(0);
+ }
+
+ len -= read_len;
+ }
+ close(sfd);
+ close(dfd);
+ return(1);
+#endif
+}
+
+/* Returns a directory path used for tmp files. */
+DS_EXPORT_SYMBOL char *
+ds_get_tmp_dir()
+{
+ static char tmpdir[] = "/tmp";
+ static char tmp[256] = {0};
+ unsigned ilen;
+ char pch;
+ char* instanceDir = ds_get_install_root();
+
+ if(instanceDir == NULL)
+ {
+ #if defined( XP_WIN32 )
+ ilen = strlen(tmp);
+ GetTempPath( ilen +1, tmp );
+ /* Remove trailing slash. */
+ pch = tmp[ilen-1];
+ if( pch == '\\' || pch == '/' )
+ tmp[ilen-1] = '\0';
+ return tmp;
+ #else
+ return( tmpdir );
+ #endif
+ }
+
+ sprintf(tmp,"%s/tmp",instanceDir);
+
+#if defined( XP_WIN32 )
+ for(ilen=0;ilen < strlen(tmp); ilen++)
+ {
+ if(tmp[ilen]=='/')
+ tmp[ilen]='\\';
+ }
+#endif
+
+ if(!ds_file_exists(tmp))
+ ds_mkdir_p(tmp,00770);
+
+ return ( tmp );
+}
+
+DS_EXPORT_SYMBOL void
+ds_unixtodospath(char *szText)
+{
+ if(szText)
+ {
+ while(*szText)
+ {
+ if( *szText == '/' )
+ *szText = '\\';
+ szText++;
+ }
+ }
+}
+
+/* converts '\' chars to '/' */
+DS_EXPORT_SYMBOL void
+ds_dostounixpath(char *szText)
+{
+ if(szText)
+ {
+ while(*szText)
+ {
+ if( *szText == '\\' )
+ *szText = '/';
+ szText++;
+ }
+ }
+}
+
+/* converts ':' chars to ' ' */
+DS_EXPORT_SYMBOL void
+ds_timetofname(char *szText)
+{
+ if(szText)
+ {
+ /* Replace trailing newline */
+ szText[ strlen( szText ) -1 ] = 0;
+ while(*szText)
+ {
+ if( *szText == ':' ||
+ *szText == ' ' )
+ *szText = '_';
+ szText++;
+ }
+ }
+}
+
+/* Effects a rename in 2 steps, needed on NT because if the
+target of a rename() already exists, the rename() will fail. */
+DS_EXPORT_SYMBOL int
+ds_saferename(char *szSrc, char *szTarget)
+{
+#ifdef XP_WIN32
+ int iRetVal;
+ char *szTmpFile;
+ struct stat buf;
+#endif
+
+ if( !szSrc || !szTarget )
+ return 1;
+
+#if defined( XP_WIN32 )
+
+ szTmpFile = mktemp("slrnXXXXXX" );
+ if( stat( szTarget, &buf ) == 0 )
+ {
+ /* Target file exists */
+ if( !szTmpFile )
+ return 1;
+
+ if( !ds_cp_file( szTarget, szTmpFile, 0644) )
+ return( 1 );
+
+ unlink( szTarget );
+ if( (iRetVal = rename( szSrc, szTarget )) != 0 )
+ {
+ /* Failed to rename, copy back. */
+ ds_cp_file( szTmpFile, szTarget, 0644);
+ }
+ /* Now remove temp file */
+ unlink( szTmpFile );
+ }
+ else
+ iRetVal = rename(szSrc, szTarget);
+
+ return iRetVal;
+#else
+ return rename(szSrc, szTarget);
+#endif
+
+}
+
+DS_EXPORT_SYMBOL char*
+ds_encode_all (const char* s)
+{
+ char* r;
+ size_t l;
+ size_t i;
+ if (s == NULL || *s == '\0') {
+ return strdup ("");
+ }
+ l = strlen (s);
+ r = malloc (l * 3 + 1);
+ for (i = 0; *s != '\0'; ++s) {
+ r[i++] = '%';
+ sprintf (r + i, "%.2X", 0xFF & (unsigned int)*s);
+ i += 2;
+ }
+ r[i] = '\0';
+ return r;
+}
+
+DS_EXPORT_SYMBOL char*
+ds_URL_encode (const char* s)
+{
+ char* r;
+ size_t l;
+ size_t i;
+ if (s == NULL || *s == '\0') {
+ return strdup ("");
+ }
+ l = strlen (s) + 1;
+ r = malloc (l);
+ for (i = 0; *s != '\0'; ++s) {
+ if (*s >= 0x20 && *s <= 0x7E && strchr (" <>\"#%{}[]|\\^~`?,;=+\n", *s) == NULL) {
+ if (l - i <= 1) r = realloc (r, l *= 2);
+ r[i++] = *s;
+ } else { /* encode *s */
+ if (l - i <= 3) r = realloc (r, l *= 2);
+ r[i++] = '%';
+ sprintf (r + i, "%.2X", 0xFF & (unsigned int)*s);
+ i += 2;
+ }
+ }
+ r[i] = '\0';
+ return r;
+}
+
+DS_EXPORT_SYMBOL char*
+ds_URL_decode (const char* original)
+{
+ char* r = strdup (original);
+ char* s;
+ for (s = r; *s != '\0'; ++s) {
+ if (*s == '+') {
+ *s = ' ';
+ }
+ else if (*s == '%' && isxdigit(s[1]) && isxdigit(s[2])) {
+ memmove (s, s+1, 2);
+ s[2] = '\0';
+ *s = (char)strtoul (s, NULL, 16);
+ memmove (s+1, s+3, strlen (s+3) + 1);
+ }
+ }
+ return r;
+}
+
+#if !defined( XP_WIN32 )
+#include <errno.h> /* errno */
+#include <pwd.h> /* getpwnam */
+
+static int saved_uid_valid = 0;
+static uid_t saved_uid;
+static int saved_gid_valid = 0;
+static gid_t saved_gid;
+
+#if defined( HPUX )
+#define SETEUID(id) setresuid((uid_t) -1, id, (uid_t) -1)
+#else
+#define SETEUID(id) seteuid(id)
+#endif
+
+#endif
+
+DS_EXPORT_SYMBOL char*
+ds_become_localuser_name (char *localuser)
+{
+#if !defined( XP_WIN32 )
+ if (localuser != NULL) {
+ struct passwd* pw = getpwnam (localuser);
+ if (pw == NULL) {
+ fprintf (stderr, "getpwnam(%s) == NULL; errno %d",
+ localuser, errno);
+ fprintf (stderr, "\n");
+ fflush (stderr);
+ } else {
+ if ( ! saved_uid_valid) saved_uid = geteuid();
+ if ( ! saved_gid_valid) saved_gid = getegid();
+ if (setgid (pw->pw_gid) == 0) {
+ saved_gid_valid = 1;
+ } else {
+ fprintf (stderr, "setgid(%li) != 0; errno %d",
+ (long)pw->pw_gid, errno);
+ fprintf (stderr, "\n");
+ fflush (stderr);
+ }
+ if (SETEUID (pw->pw_uid) == 0) {
+ saved_uid_valid = 1;
+ } else {
+ fprintf (stderr, "seteuid(%li) != 0; errno %d",
+ (long)pw->pw_uid, errno);
+ fprintf (stderr, "\n");
+ fflush (stderr);
+ }
+ }
+ }
+ return NULL;
+#else
+ return NULL;
+#endif
+}
+
+DS_EXPORT_SYMBOL char*
+ds_become_localuser (char **ds_config)
+{
+#if !defined( XP_WIN32 )
+ char* localuser = ds_get_value (ds_config, ds_get_var_name(DS_LOCALUSER), 0, 1);
+ if (localuser != NULL) {
+ char *rv = ds_become_localuser_name(localuser);
+
+ free(localuser);
+ return rv;
+ }
+ return NULL;
+#else
+ return NULL;
+#endif
+}
+
+DS_EXPORT_SYMBOL char*
+ds_become_original (char **ds_config)
+{
+#if !defined( XP_WIN32 )
+ if (saved_uid_valid) {
+ if (SETEUID (saved_uid) == 0) {
+ saved_uid_valid = 0;
+ } else {
+ fprintf (stderr, "seteuid(%li) != 0; errno %d<br>n",
+ (long)saved_uid, errno);
+ fflush (stderr);
+ }
+ }
+ if (saved_gid_valid) {
+ if (setgid (saved_gid) == 0) {
+ saved_gid_valid = 0;
+ } else {
+ fprintf (stderr, "setgid(%li) != 0; errno %d<br>\n",
+ (long)saved_gid, errno);
+ fflush (stderr);
+ }
+ }
+ return NULL;
+#else
+ return NULL;
+#endif
+}
+
+/*
+ * When a path containing a long filename is passed to system(), the call
+ * fails. Therfore, we need to use the short version of the path, when
+ * constructing the path to pass to system().
+ */
+DS_EXPORT_SYMBOL char*
+ds_makeshort( char * filepath )
+{
+#if defined( XP_WIN32 )
+ char *shortpath = malloc( MAX_PATH );
+ DWORD dwStatus;
+ if( shortpath )
+ {
+ dwStatus = GetShortPathName( filepath, shortpath, MAX_PATH );
+ return( shortpath );
+ }
+#endif
+ return filepath;
+}
+
+/* returns 1 if string "searchstring" found in file "filename" */
+DS_EXPORT_SYMBOL int
+ds_search_file(char *filename, char *searchstring)
+{
+ struct stat finfo;
+ FILE * sf;
+ char big_line[BIG_LINE];
+
+ if( filename == NULL )
+ return 0;
+
+ if( stat(filename, &finfo) != 0 ) /* successful */
+ return 0;
+
+ if( !(sf = fopen(filename, "r")) )
+ return 0;
+
+ while ( fgets(big_line, BIG_LINE, sf) ) {
+ if( strstr( big_line, searchstring ) != NULL ) {
+ fclose(sf);
+ return 1;
+ }
+ }
+
+ fclose(sf);
+
+ return 0;
+}
+
+/*
+ * on linux when running as root, doing something like
+ * system("date > out.log 2>&1") will fail, because of an
+ * ambigious redirect. This works for /bin/sh, but not /bin/csh or /bin/tcsh
+ *
+ * using this would turn
+ * system("date > out.log 2>&1");
+ * into
+ * system("/bin/sh/ -c \"date > out.log 2>&1\"")
+ *
+ */
+DS_EXPORT_SYMBOL void
+alter_startup_line(char *startup_line)
+{
+#if (defined Linux && !defined LINUX2_4)
+ char temp_startup_line[BIG_LINE+40];
+
+ sprintf(temp_startup_line, "/bin/sh -c \"%s\"", startup_line);
+ strcpy(startup_line, temp_startup_line);
+#else
+ /* do nothing */
+#endif /* Linux */
+}
+
+DS_EXPORT_SYMBOL void
+ds_send_error(char *errstr, int print_errno)
+{
+ FILE *logfp;
+ fprintf(stdout, "error%s%s\n", SEPARATOR, errstr);
+ if (print_errno && errno)
+ fprintf(stdout, "system_errno%s%d\n", SEPARATOR, errno);
+
+ fflush(stdout);
+
+ if (logfp = get_logfp()) {
+ fprintf(logfp, "error%s%s\n", SEPARATOR, errstr);
+ if (print_errno && errno)
+ fprintf(logfp, "system_errno%s%d\n", SEPARATOR, errno);
+ fclose(logfp);
+ }
+
+}
+
+DS_EXPORT_SYMBOL void
+ds_send_status(char *str)
+{
+ FILE *logfp;
+ fprintf(stdout, "[%s]: %s\n", ds_get_server_name(), str);
+ fflush(stdout);
+
+ if (logfp = get_logfp()) {
+ fprintf(logfp, "[%s]: %s\n", ds_get_server_name(), str);
+ fclose(logfp);
+ }
+}
+
+/* type and doexit are unused
+ I'm not sure what type is supposed to be used for
+ removed the doexit code because we don't want to
+ exit abruptly anymore, we must exit by returning an
+ exit code from the return in main()
+*/
+static void
+report_error(int type, char *msg, char *details, int doexit)
+{
+ char error[BIG_LINE*4] = {0};
+
+ if (msg)
+ {
+ strcat(error, msg);
+ strcat(error, SEPARATOR);
+ }
+ if (details)
+ strcat(error, details);
+ ds_send_error(error, 1);
+}
+
+DS_EXPORT_SYMBOL void
+ds_report_error(int type, char *msg, char *details)
+{
+ /* richm - changed exit flag to 0 - we must not exit
+ abruptly, we should instead exit by returning a code
+ as the return value of main - this ensures that callers
+ are properly notified of the status
+ */
+ report_error(type, msg, details, 0);
+}
+
+DS_EXPORT_SYMBOL void
+ds_report_warning(int type, char *msg, char *details)
+{
+ report_error(type, msg, details, 0);
+}
+
+DS_EXPORT_SYMBOL void
+ds_show_message(const char *message)
+{
+ FILE *logfp;
+ printf("%s\n", message);
+ fflush(stdout);
+
+ if (logfp = get_logfp()) {
+ fprintf(logfp, "%s\n", message);
+ fclose(logfp);
+ }
+
+ return;
+}
+
+DS_EXPORT_SYMBOL void
+ds_show_key_value(char *key, char *value)
+{
+ FILE *logfp;
+ printf("%s%s%s\n", key, SEPARATOR, value);
+
+ if (logfp = get_logfp()) {
+ fprintf(logfp, "%s%s%s\n", key, SEPARATOR, value);
+ fclose(logfp);
+ }
+ return;
+}
+
+/* Stolen from the Admin Server dsgw_escape_for_shell */
+DS_EXPORT_SYMBOL char *
+ds_escape_for_shell( char *s )
+{
+ char *escaped;
+ char tmpbuf[4];
+ size_t x,l;
+
+ if ( s == NULL ) {
+ return( s );
+ }
+
+ l = 3 * strlen( s ) + 1;
+ escaped = malloc( l );
+ memset( escaped, 0, l );
+ for ( x = 0; s[x]; x++ ) {
+ if (( (unsigned char)s[x] & 0x80 ) == 0 ) {
+ strncat( escaped, &s[x], 1 );
+ } else {
+ /* not an ASCII character - escape it */
+ sprintf( tmpbuf, "\\%x", (unsigned)(((unsigned char)(s[x])) & 0xff) );
+ strcat( escaped, tmpbuf );
+ }
+ }
+ return( escaped );
+}
+
+DS_EXPORT_SYMBOL char *
+ds_system_errmsg(void)
+{
+ static char static_error[BUFSIZ];
+ char *lmsg = 0; /* Local message pointer */
+ size_t msglen = 0;
+ int sys_error = 0;
+#ifdef XP_WIN32
+ LPTSTR sysmsg = 0;
+#endif
+
+ /* Grab the OS error message */
+#ifdef XP_WIN32
+ sys_error = GetLastError();
+#else
+ sys_error = errno;
+#endif
+
+#if defined(XP_WIN32)
+ msglen = FormatMessage(
+ FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_ALLOCATE_BUFFER,
+ NULL,
+ GetLastError(),
+ LOCALE_SYSTEM_DEFAULT,
+ (LPTSTR)&sysmsg,
+ 0,
+ 0);
+ if (msglen > 0)
+ lmsg = sysmsg;
+ SetLastError(0);
+#else
+ lmsg = strerror(errno);
+ errno = 0;
+#endif
+
+ if (!lmsg)
+ static_error[0] = 0;
+ else
+ {
+ /* At this point lmsg points to something. */
+ int min = 0;
+ msglen = strlen(lmsg);
+
+ min = msglen > BUFSIZ ? BUFSIZ : msglen;
+ strncpy(static_error, lmsg, min);
+ static_error[min-1] = 0;
+ }
+
+#ifdef XP_WIN32
+ /* NT's FormatMessage() dynamically allocated the msg; free it */
+ if (sysmsg)
+ LocalFree(sysmsg);
+#endif
+
+ return static_error;
+}
+
+/* get db path dir info from dse.ldif and remove it if it's not under path
+*/
+#ifndef MAXPATHLEN
+#define MAXPATHLEN 1024
+#endif
+
+enum {
+ DB_DIRECTORY = 0,
+ DB_LOGDIRECTORY,
+ DB_CHANGELOGDIRECTORY,
+ DB_HOME_DIRECTORY
+};
+
+static int
+is_fullpath(char *path)
+{
+ int len;
+ if (NULL == path || '\0' == *path)
+ return 0;
+
+ if (FILE_PATHSEP == *path) /* UNIX */
+ return 1;
+
+ len = strlen(path);
+ if (len > 2)
+ {
+ if (':' == path[1] && ('/' == path[2] || '\\' == path[2])) /* Windows */
+ return 1;
+ }
+ return 0;
+}
+
+static void
+rm_db_dirs(char *fullpath, DS_RM_RF_ERR_FUNC ds_rm_rf_err_func, void *arg)
+{
+ FILE *fp = fopen(fullpath, "r");
+ char buf[2][MAXPATHLEN];
+ char rmbuf[MAXPATHLEN];
+ char *bufp, *nextbufp;
+ char *retp;
+ int readit = 0;
+
+ if (fp == NULL)
+ {
+ ds_rm_rf_err_func(fullpath, "opening dse.ldif", arg);
+ return;
+ }
+
+ bufp = buf[0]; *bufp = '\0';
+ nextbufp = buf[1]; *nextbufp = '\0';
+
+ while (readit || (retp = fgets(bufp, MAXPATHLEN, fp)) != NULL)
+ {
+ int len = strlen(bufp);
+ int type = -1;
+ char *p, *q;
+
+ if (strstr(bufp, "nsslapd-directory"))
+ type = DB_DIRECTORY;
+ else if (strstr(bufp, "nsslapd-db-home-directory"))
+ type = DB_HOME_DIRECTORY;
+ else if (strstr(bufp, "nsslapd-db-logdirectory"))
+ type = DB_LOGDIRECTORY;
+ else if (strstr(bufp, "nsslapd-changelogdir"))
+ type = DB_CHANGELOGDIRECTORY;
+ else
+ {
+ readit = 0;
+ continue;
+ }
+
+ p = bufp + len;
+
+ while ((retp = fgets(nextbufp, MAXPATHLEN, fp)) != NULL)
+ {
+ int thislen;
+ if (*nextbufp == ' ')
+ {
+ thislen = strlen(nextbufp);
+ len += thislen;
+ if (len < MAXPATHLEN)
+ {
+ strncpy(p, nextbufp, thislen);
+ p += thislen;
+ }
+ /* else too long as a path. ignore it */
+ }
+ else
+ break;
+ }
+ if (retp == NULL) /* done */
+ break;
+
+ p = strchr(bufp, ':');
+ if (p == NULL)
+ {
+ char *tmpp = bufp;
+ bufp = nextbufp;
+ nextbufp = tmpp;
+ readit = 1;
+ continue;
+ }
+
+ while (*(++p) == ' ') ;
+
+ q = p + strlen(p) - 1;
+ while (*q == ' ' || *q == '\t' || *q == '\n')
+ q--;
+ *(q+1) = '\0';
+
+ switch (type)
+ {
+ case DB_DIRECTORY:
+ case DB_LOGDIRECTORY:
+ case DB_CHANGELOGDIRECTORY:
+ if (is_fullpath(p))
+ internal_rm_rf(p, ds_rm_rf_err_func, NULL);
+ break;
+ case DB_HOME_DIRECTORY:
+ internal_rm_rf(p, ds_rm_rf_err_func, NULL);
+ break;
+ }
+ }
+
+ fclose(fp);
+}
+
+/* this function will recursively remove a directory hierarchy from the file
+ system, like "rm -rf"
+ In order to handle errors, the user supplies a callback function. When an
+ error occurs, the callback function is called with the file or directory name
+ and the system errno. The callback function should return TRUE if it wants
+ to continue or FALSE if it wants the remove aborted.
+ The error callback should use PR_GetError and/or PR_GetOSError to
+ determine the cause of the failure
+*/
+/* you could locate db dirs non standard location
+ we should remove them, as well.
+*/
+static int
+internal_rm_rf(const char *path, DS_RM_RF_ERR_FUNC ds_rm_rf_err_func, void *arg)
+{
+ struct PRFileInfo prfi;
+ char *fullpath = NULL;
+ int retval = 0;
+
+ if (PR_GetFileInfo(path, &prfi) != PR_SUCCESS) {
+ if (!ds_rm_rf_err_func(path, "reading directory", arg)) {
+ return 1;
+ }
+ }
+
+ if (prfi.type == PR_FILE_DIRECTORY)
+ {
+ PRDir *dir;
+ PRDirEntry *dirent;
+
+ if (!(dir = PR_OpenDir(path))) {
+ if (!ds_rm_rf_err_func(path, "opening directory", arg)) {
+ return 1;
+ }
+ return 0;
+ }
+
+ while (dirent = PR_ReadDir(dir, PR_SKIP_BOTH)) {
+ char *fullpath = PR_smprintf("%s%c%s", path, FILE_PATHSEP, dirent->name);
+ if (PR_GetFileInfo(fullpath, &prfi) != PR_SUCCESS) {
+ if (!ds_rm_rf_err_func(fullpath, "reading file", arg)) {
+ PR_smprintf_free(fullpath);
+ PR_CloseDir(dir);
+ return 1;
+ } /* else just continue */
+ } else if (prfi.type == PR_FILE_DIRECTORY) {
+ retval = internal_rm_rf(fullpath, ds_rm_rf_err_func, arg);
+ if (retval) { /* non zero return means stop */
+ PR_smprintf_free(fullpath);
+ break;
+ }
+ } else {
+ /* if dse.ldif, check db dir is under the instance dir or not */
+ if (0 == strcmp(dirent->name, "dse.ldif"))
+ rm_db_dirs(fullpath, ds_rm_rf_err_func, arg);
+
+ if (PR_Delete(fullpath) != PR_SUCCESS) {
+ if (!ds_rm_rf_err_func(fullpath, "deleting file", arg)) {
+ PR_smprintf_free(fullpath);
+ PR_CloseDir(dir);
+ return 1;
+ }
+ }
+ }
+ PR_smprintf_free(fullpath);
+ }
+ PR_CloseDir(dir);
+ if (PR_RmDir(path) != PR_SUCCESS) {
+ if (!ds_rm_rf_err_func(path, "removing directory", arg)) {
+ retval = 1;
+ }
+ }
+ }
+
+ return retval;
+}
+
+static int
+default_err_func(const char *path, const char *op, void *arg)
+{
+ PRInt32 errcode = PR_GetError();
+ char *msg;
+ const char *errtext;
+
+ if (!errcode || (errcode == PR_UNKNOWN_ERROR)) {
+ errcode = PR_GetOSError();
+ errtext = ds_system_errmsg();
+ } else {
+ errtext = PR_ErrorToString(errcode, PR_LANGUAGE_I_DEFAULT);
+ }
+
+ msg = PR_smprintf("%s %s: error code %d (%s)", op, path, errcode, errtext);
+ ds_send_error(msg, 0);
+ PR_smprintf_free(msg);
+ return 1; /* just continue */
+}
+
+DS_EXPORT_SYMBOL int
+ds_rm_rf(const char *dir, DS_RM_RF_ERR_FUNC ds_rm_rf_err_func, void *arg)
+{
+ int retval = 0;
+ struct PRFileInfo prfi;
+
+ if (!dir) {
+ ds_send_error("Could not remove NULL directory name", 1);
+ return 1;
+ }
+
+ if (!ds_rm_rf_err_func) {
+ ds_rm_rf_err_func = default_err_func;
+ }
+
+ if (PR_GetFileInfo(dir, &prfi) != PR_SUCCESS) {
+ if (ds_rm_rf_err_func(dir, "reading directory", arg)) {
+ return 0;
+ } else {
+ return 1;
+ }
+ }
+ if (prfi.type != PR_FILE_DIRECTORY) {
+ char *msg = PR_smprintf("Cannot remove directory %s because it is not a directory", dir);
+ ds_send_error(msg, 0);
+ PR_smprintf_free(msg);
+ return 1;
+ }
+
+ return internal_rm_rf(dir, ds_rm_rf_err_func, arg);
+}
+
+DS_EXPORT_SYMBOL int
+ds_remove_reg_key(void *base, const char *format, ...)
+{
+ int rc = 0;
+#ifdef XP_WIN32
+ int retries = 3;
+ HKEY hkey = (HKEY)base;
+ char *key;
+ va_list ap;
+
+ va_start(ap, format);
+ key = PR_vsmprintf(format, ap);
+ va_end(ap);
+
+ do {
+ if (ERROR_SUCCESS != RegDeleteKey(hkey, key)) {
+ rc = GetLastError();
+ if (rc == ERROR_BADKEY || rc == ERROR_CANTOPEN ||
+ rc == ERROR_CANTREAD ||
+ rc == ERROR_CANTWRITE || rc == ERROR_KEY_DELETED ||
+ rc == ERROR_ALREADY_EXISTS || rc == ERROR_NO_MORE_FILES) {
+ rc = 0; /* key already deleted - no error */
+ } else if ((retries > 1) && (rc == ERROR_IO_PENDING)) {
+ /* the key is busy - lets wait and try again */
+ PR_Sleep(PR_SecondsToInterval(3));
+ retries--;
+ } else {
+ char *errmsg = PR_smprintf("Could not remove registry key %s - error %d (%s)",
+ key, rc, ds_system_errmsg());
+ ds_send_error(errmsg, 0);
+ PR_smprintf_free(errmsg);
+ break; /* no retry, just fail */
+ }
+ }
+ } while (rc && retries);
+ PR_smprintf_free(key);
+#endif
+ return rc;
+}