Browse Source

459181 - Add attreplacefile option to ldclt

This option will accept format like "-e attreplacefile=jpegPhoto:/some/binary.file"
to ldclt. The content of the given file will be used to replace the attribute
"jpegPhoto" (in this case). The given file could be plain text or binary file.
Yi Zhang 16 years ago
parent
commit
1484974a30

+ 230 - 10
ldap/servers/slapd/tools/ldclt/ldapfct.c

@@ -1349,18 +1349,22 @@ int
 freeAttrib (
 	LDAPMod	**attrs)
 {
-  int	 i;
-  for (i=0 ; attrs[i]!=NULL ; i++)
-  {
-    if (attrs[i]->mod_op & LDAP_MOD_BVALUES)
-    {
-      free (attrs[i]->mod_bvalues[0]);
+  int	i;
+  int	j;
+
+  for (i=0 ; attrs[i]!=NULL ; i++) {
+    if (attrs[i]->mod_op & LDAP_MOD_BVALUES) {
+      for (j=0; attrs[i]->mod_bvalues[j] != NULL; j++) {
+        free (attrs[i]->mod_bvalues[j]);
+      }
       free (attrs[i]->mod_bvalues);
-    }
-    else
+    } else {
       free (attrs[i]->mod_values);
+    }
+
     free (attrs[i]);
   }
+
   return (0);
 }
 
@@ -1478,7 +1482,70 @@ printErrorFromLdap (
 
 
 
-					/* New function */	/*JLS 21-11-00*/
+
+
+
+
+/* ****************************************************************************
+	FUNCTION :	buildNewModAttribFile
+	PURPOSE :	Build a new (random or incremental) target DN and the
+			corresponding LDAPMod for attribute modification.
+	INPUT :		tttctx	= thread context
+	OUTPUT :	newDN	= DN of the new entry
+			attrs	= attributes for the ldap_modify
+	RETURN :	-1 if error, 0 else.
+ *****************************************************************************/
+int
+buildNewModAttribFile (
+	thread_context	 *tttctx,
+	char		 *newDn,
+	LDAPMod		**attrs)
+{
+  int		 nbAttribs;	/* Nb of attributes */
+  LDAPMod	 attribute;	/* To build the attributes */
+  struct berval	*bv = malloc(sizeof(struct berval *));
+  attribute.mod_bvalues = (struct berval **)malloc(2 * sizeof(struct berval *));
+
+  if ((bv == NULL) || (attribute.mod_bvalues == NULL)) {
+    return -1;
+  }
+
+  /*
+   * Build the new DN
+   * We will assume that the filter (-f argument) is set to use it
+   * to build the rdn of the new entry.
+   * Note that the random new attribute is also build by this function.
+   */
+  if (buildRandomRdnOrFilter (tttctx) < 0)
+    return (-1);
+  strcpy (newDn, tttctx->bufFilter);
+  strcat (newDn, ",");
+  strcat (newDn, tttctx->bufBaseDN);
+
+  /*
+   * Build the attributes modification
+   */
+  bv->bv_len = mctx.attrplFileSize;
+  bv->bv_val = mctx.attrplFileContent;
+  attrs[0]  = NULL;	/* No attributes yet */
+  nbAttribs = 0;	/* No attributes yet */
+  attribute.mod_op     = LDAP_MOD_REPLACE | LDAP_MOD_BVALUES;
+  attribute.mod_type   = mctx.attrplName;
+  attribute.mod_bvalues[0] = bv;
+  attribute.mod_bvalues[1] = NULL;
+
+  if (addAttrib (attrs, nbAttribs++, &attribute) < 0)
+    return (-1);
+
+  /*
+   * Normal end
+   */
+  return (0);
+}
+
+
+
+/* New function */	/*JLS 21-11-00*/
 /* ****************************************************************************
 	FUNCTION :	buildNewModAttrib
 	PURPOSE :	Build a new (random or incremental) target DN and the
@@ -3050,7 +3117,6 @@ doAddEntry (
 
 
 
-
 /* ****************************************************************************
 	FUNCTION :	doAttrReplace
 	PURPOSE :	Perform an ldap_modify() operation, to replace an
@@ -3207,7 +3273,161 @@ doAttrReplace (
 
 
 
+/* ****************************************************************************
+	FUNCTION :	doAttrFileReplace
+	PURPOSE :	Perform an ldap_modify() operation, to replace an
+			attribute of the entry with content read from file .
+	INPUT :		tttctx	= thread context
+	OUTPUT :	None.
+	RETURN :	-1 if error, 0 else.
+	DESCRIPTION :
+ *****************************************************************************/
+int
+doAttrFileReplace (
+	thread_context	*tttctx)
+{
+  char		 newDn[MAX_DN_LENGTH];	/* DN of the new entry */
+  LDAPMod	*attrs[MAX_ATTRIBS];	/* Attributes of this entry */
+  int		 ret;			/* Return values */
+  int		 msgid;			/* For asynchronous mode */
+
+  /*
+   * Connection to the server
+   * The function connectToServer() will take care of the various connection/
+   * disconnection, bind/unbind/close etc... requested by the user.
+   * The cost is one more function call in this application, but the
+   * resulting source code will be much more easiest to maintain.
+   */
+  if (connectToServer (tttctx) < 0)	/* if connection is being established, */
+    return (-1);			/* then tttctx->ldapCtx would exist and holds connection */
+  if (!(tttctx->binded))
+    return (0);
+
+  /*
+   * Do the modify
+   * Maybe we are in synchronous mode ?
+   */
+  if (!(mctx.mode & ASYNC))
+  {
+    /*
+     * Build the new entry
+     */
+    if (buildNewModAttribFile (tttctx, newDn, attrs) < 0)
+      return (-1);
 
+    /*
+     * We will modify this entry
+     */
+    ret = ldap_modify_ext_s (tttctx->ldapCtx, newDn, attrs, NULL, NULL);
+    if (ret != LDAP_SUCCESS)
+    {
+      if (!((mctx.mode & QUIET) && ignoreError (ret)))
+      {
+	printf ("ldclt[%d]: T%03d: AttriFileReplace Error Cannot modify (%s), error=%d (%s)\n",
+		mctx.pid, tttctx->thrdNum, newDn, ret, my_ldap_err2string (ret));
+	fflush (stdout);
+      }
+      if (addErrorStat (ret) < 0)
+	return (-1);
+    }
+    else
+    {
+      printf ("ldclt[%d]: T%03d: AttriFileReplace modify (%s) success ,\n",
+		mctx.pid, tttctx->thrdNum, newDn);
+      if (incrementNbOpers (tttctx) < 0)	/* Memorize operation */
+	return (-1);
+    }
+
+    /*
+     * Free the attributes
+     */
+    if (freeAttrib (attrs) < 0)
+      return (-1);
+
+    /*
+     * End of synchronous operations
+     */
+    return (0);
+  }
+
+  /*
+   * Here, we are in asynchronous mode...
+   * Too bad, lot of things to do here.
+   * First, let's see if we are above the reading threshold.
+   */
+  if (getPending (tttctx, &(mctx.timeval)) < 0)
+    return (-1);
+
+  /*
+   * Maybe we may send another request ?
+   * Well... there is no proper way to retrieve the error number for
+   * this, so I guess I may use direct access to the ldap context
+   * to read the field ld_errno.
+   */
+  if (tttctx->pendingNb > mctx.asyncMax)
+  {
+    if ((mctx.mode & VERBOSE)   &&
+	(tttctx->asyncHit == 1) &&
+	(!(mctx.mode & SUPER_QUIET)))
+    {
+      tttctx->asyncHit = 1;
+      printf ("ldclt[%d]: T%03d: Max pending request hit.\n",
+               mctx.pid, tttctx->thrdNum);
+      fflush (stdout);
+    }
+  }
+  else
+  {
+    if ((mctx.mode & VERBOSE)   &&
+	(tttctx->asyncHit == 1) &&
+	(!(mctx.mode & SUPER_QUIET)))
+    {
+      tttctx->asyncHit = 0;
+      printf ("ldclt[%d]: T%03d: Restart sending.\n",
+               mctx.pid, tttctx->thrdNum);
+      fflush (stdout);
+    }
+
+    /*
+     * Build the new entry
+     */
+    if (buildNewModAttrib (tttctx, newDn, attrs) < 0)
+      return (-1);
+
+    ret = ldap_modify_ext (tttctx->ldapCtx, newDn, attrs, NULL, NULL, &msgid);
+    if (ret != LDAP_SUCCESS)
+    {
+      if (!((mctx.mode & QUIET) && ignoreError (ret)))
+      {
+	printf ("ldclt[%d]: T%03d: Cannot modify(%s), error=%d (%s)\n",
+		mctx.pid, tttctx->thrdNum, newDn, ret, my_ldap_err2string (ret));
+	fflush (stdout);
+      }
+      if (addErrorStat (ret) < 0)
+	return (-1);
+    }
+    else
+    {
+      /*
+       * Memorize the operation
+       */
+      if (msgIdAdd (tttctx, msgid, newDn, newDn, attrs) < 0)
+	return (-1);
+      if (incrementNbOpers (tttctx) < 0)
+	return (-1);
+      tttctx->pendingNb++;
+    }
+  }
+
+  if (mctx.mode & VERY_VERBOSE)
+    printf ("ldclt[%d]: T%03d: pendingNb=%d\n",
+             mctx.pid, tttctx->thrdNum, tttctx->pendingNb);
+
+  /*
+   * End of asynchronous operation... and also end of function.
+   */
+  return (0);
+}
 
 
 /* ****************************************************************************

+ 100 - 0
ldap/servers/slapd/tools/ldclt/ldclt.c

@@ -1267,6 +1267,10 @@ basicInit (void)
   int		 i;	/* For the loops */			/*JLS 21-11-00*/
   int		 ret;	/* Return value */
   int		 oflags;/* open() flags */			/*JLS 05-04-01*/
+  struct stat file_st ; /* file status checker for attreplacefile option */
+  FILE *attrF;		/* file pointer for attreplacefile option */
+  int	buffersize=1024;	/* buffer size for buffer */
+  char	buffer[buffersize];	/* buffer used to read attreplacefile content */
 
   /*
    * Misc inits
@@ -1471,6 +1475,86 @@ basicInit (void)
     }								/*JLS 21-11-00*/
   }								/*JLS 21-11-00*/
 
+  /*
+   * Parse attreplacefile subvalue
+   */
+  if (mctx.mod2 & M2_ATTR_REPLACE_FILE)
+  {
+    printf ("debug: parse attreplacefile subvalue\n");
+    /*
+     * Find the attribute name
+     */
+    for (i=0 ; (i<strlen(mctx.attrpl)) &&
+                        (mctx.attrpl[i]!=':') ; i++);
+    mctx.attrplName = (char *)malloc(i+1);
+    strncpy (mctx.attrplName, mctx.attrpl, i);
+    mctx.attrplName[i] = '\0';
+
+    /*
+     * Parse the attribute value
+     */
+    mctx.attrplFile = (char *)malloc(strlen(mctx.attrpl+i+1) + 1);
+    if (mctx.attrplFile == NULL) {
+      printf ("Error: unable to allocate memory for attreplfile\n");
+      return (-1);
+    }
+
+    strncpy(mctx.attrplFile, mctx.attrpl+i+1, strlen(mctx.attrpl+i+1));
+    mctx.attrplFile[strlen(mctx.attrpl+i+1)] = '\0';
+
+   /* 
+    * start working on file verification here 
+      (1) check whether file exist 
+      (2) check whether we have permission to read it 
+      (3) save the content into mctx.attrplFileContent 
+    */
+
+    /* determine file size here */
+    if (stat(mctx.attrplFile, &file_st) < 0){
+      printf ("attr replace file [%s] does not exist, exit\n", mctx.attrplFile);
+      return (-1);
+    }else{
+      mctx.attrplFileSize = file_st.st_size;
+      printf ("file has size [%d] bytes\n", mctx.attrplFileSize );
+    }   
+   
+    /* open file to read */ 
+    if ((attrF = fopen(mctx.attrplFile, "r")) == NULL )
+    {
+      printf("ERROR reading attr file [%s]\n",mctx.attrplFile); 
+      return (-1);
+    }else{
+      printf("file opened for reading\n");
+    }
+
+    /* start to read file content */
+    mctx.attrplFileContent = (char *)malloc(mctx.attrplFileSize + 1);    
+    i=0;
+    while ( fread(buffer, buffersize , 1, attrF) )
+    {
+      memcpy(mctx.attrplFileContent+i, buffer , buffersize );
+      memset(buffer ,'\0', buffersize );
+      i = i + buffersize;
+    } 
+    /* copy remainding content into mctx.attrplFileContent */
+    if (i<mctx.attrplFileSize)
+    {
+      memcpy(mctx.attrplFileContent+i, buffer , (mctx.attrplFileSize - 1 - i));
+      memset(buffer ,'\0', buffersize );  /* clear the buffer */
+    }
+
+    mctx.attrplFileContent[mctx.attrplFileSize]='\0'; // append the close bit
+
+    if ((fclose(attrF)) == EOF )
+    {
+      printf("ERROR closing attr file [%s]\n",mctx.attrplFile);
+      return (-1);
+    }else{
+      printf("file closed\n");
+    }
+
+  }
+
 
   /*
    * Initiates statistics fields
@@ -2123,6 +2207,8 @@ char *execParams[] = {
 	"abandon",
 #define EP_DEREF		 	50
 	"deref",
+#define EP_ATT_REPLACE_FILE		51
+	"attreplacefile",
 	NULL
 };
 
@@ -2165,6 +2251,15 @@ decodeExecParams (
 	}							/*JLS 21-11-00*/
 	mctx.attrpl = strdup (subvalue);			/*JLS 21-11-00*/
 	break;							/*JLS 21-11-00*/
+      case EP_ATT_REPLACE_FILE:
+        mctx.mod2 |= M2_ATTR_REPLACE_FILE;
+        if (subvalue == NULL)
+        {
+          fprintf (stderr, "Error: missing arg attreplacefile\n");
+          return (-1);
+        }
+        mctx.attrpl = strdup (subvalue);
+        break;
       case EP_ATTRLIST:						/*JLS 15-03-01*/
 	return (addAttrToList (subvalue));			/*JLS 15-03-01*/
 	break;							/*JLS 15-03-01*/
@@ -3094,6 +3189,11 @@ main (
       printf ("Attribute's head   = \"%s\"\n", mctx.attrplHead);/*JLS 21-11-00*/
       printf ("Attribute's tail   = \"%s\"\n", mctx.attrplTail);/*JLS 21-11-00*/
     }								/*JLS 21-11-00*/
+    if (mctx.mod2 & M2_ATTR_REPLACE_FILE)
+    {
+      printf ("Attribute to replace  = \"%s\"\n", mctx.attrplName);
+      printf ("Attribute value file  = \"%s\"\n", mctx.attrplFile);
+    }
     if (mctx.mode & ASYNC)
     {
       printf ("Async max pending  = %d\n", mctx.asyncMax);

+ 6 - 2
ldap/servers/slapd/tools/ldclt/ldclt.h

@@ -279,6 +279,7 @@ dd/mm/yy | Author	| Comments
 #define M2_RANDOM_SASLAUTHID     0x00000080 /* -e randomauthid */
 #define M2_ABANDON     0x00000100 /* -e abandon */
 #define M2_DEREF     0x00000200 /* -e deref */
+#define M2_ATTR_REPLACE_FILE	 0x00000400 /* -e attreplacefile */
 
 /*
  * Combinatory defines
@@ -288,11 +289,11 @@ dd/mm/yy | Author	| Comments
  *  - VALID_OPERS	: valid operations
  */
 #define NEED_FILTER	(ADD_ENTRIES|DELETE_ENTRIES|EXACT_SEARCH|RENAME_ENTRIES|ATTR_REPLACE|SCALAB01)
-#define M2_NEED_FILTER	(M2_ABANDON)
+#define M2_NEED_FILTER	(M2_ABANDON|M2_ATTR_REPLACE_FILE)
 #define NEED_RANGE	(INCREMENTAL|RANDOM)
 #define NEED_RND_INCR	(ADD_ENTRIES|DELETE_ENTRIES|RENAME_ENTRIES)
 #define VALID_OPERS	(ADD_ENTRIES|DELETE_ENTRIES|EXACT_SEARCH|RENAME_ENTRIES|ATTR_REPLACE|SCALAB01)
-#define M2_VALID_OPERS	(M2_GENLDIF|M2_BINDONLY|M2_ABANDON)
+#define M2_VALID_OPERS	(M2_GENLDIF|M2_BINDONLY|M2_ABANDON|M2_ATTR_REPLACE_FILE)
 #define NEED_CLASSES	(ADD_ENTRIES)
 #define THE_CLASSES	(OC_PERSON|OC_EMAILPERSON|OC_INETORGPRSON)
 
@@ -506,6 +507,9 @@ typedef struct main_context {
 	char		*attrlist[MAX_ATTRIBS];			/*JLS 15-03-01*/
 	int		 attrlistNb;	/* Nb attrib in list */	/*JLS 15-03-01*/
 	char		*attrpl;	/* Attrib argument */	/*JLS 21-11-00*/
+	char		*attrplFile;	/* Attrib file to get value from */
+	char		*attrplFileContent;	/* Attrib file content */
+	int		attrplFileSize;		/* Attrib file size*/
 	char		*attrplHead;	/* Attrib value head */	/*JLS 21-11-00*/
 	char		*attrplName;	/* Attrib name */	/*JLS 21-11-00*/
 	int		 attrplNbDigit;	/* Attrib nb digits */	/*JLS 21-11-00*/

+ 1 - 0
ldap/servers/slapd/tools/ldclt/ldcltU.c

@@ -163,6 +163,7 @@ void usage ()
   (void) printf ("		add               : ldap_add() entries.\n");
   (void) printf ("		append            : append entries to the genldif file.\n");
   (void) printf ("		ascii             : ascii 7-bits strings.\n");
+  (void) printf ("		attreplacefile=attrname:<file name> : replace attribute with given file content.\n");
   (void) printf ("		attreplace=name:mask    : replace attribute of existing entry.\n");
   (void) printf ("		attrlist=name:name:name : specify list of attribs to retrieve\n");
   (void) printf ("		attrsonly=0|1     : ldap_search() parameter. Set 0 to read values.\n");

+ 25 - 0
ldap/servers/slapd/tools/ldclt/threadMain.c

@@ -1114,6 +1114,23 @@ threadMain (
 			mctx.attrplTail);
   }
 
+
+  /*
+   * Initiates the attribute replace buffers attrplName
+   */
+  if ( mctx.mod2 & M2_ATTR_REPLACE_FILE )
+  {
+    /* bufAttrpl should point to the same memory location that mctx.attrplFileContent points to */
+    tttctx->bufAttrpl = mctx.attrplFileContent;
+    if (tttctx->bufAttrpl == NULL)
+    {
+      printf ("ldclt[%d]: T%03d: cannot malloc(tttctx->bufAttrpl), error=%d (%s), can we read file [%s]\n",
+		mctx.pid, tttctx->thrdNum, errno, strerror (errno), mctx.attrplFile);
+      ldcltExit (EXIT_INIT);					/*JLS 18-12-00*/
+    }
+  }
+
+
   /*
    * We are ready to go !
    */
@@ -1154,6 +1171,14 @@ threadMain (
 	go = 0;							/*JLS 21-11-00*/
 	continue;						/*JLS 21-11-00*/
       }								/*JLS 21-11-00*/
+
+    if (mctx.mod2 & M2_ATTR_REPLACE_FILE )
+      if (doAttrFileReplace (tttctx) < 0)
+      {	
+	go = 0;	
+	continue;
+      }	
+
     if (tttctx->mode & DELETE_ENTRIES)
       if (doDeleteEntry (tttctx) < 0)
       {