]> git.sur5r.net Git - openldap/commitdiff
ITS#5408 part 4 - preparing for entry creation. More error handling.
authorHallvard Furuseth <hallvard@openldap.org>
Tue, 11 Nov 2008 23:16:22 +0000 (23:16 +0000)
committerHallvard Furuseth <hallvard@openldap.org>
Tue, 11 Nov 2008 23:16:22 +0000 (23:16 +0000)
- Move mkdir() into ldif_write_entry().  Modrdn lacked this.
- Factor tests for whether to create entry & dir out to ldif_prepare_create().
- Ensure an entry always exists if the corresponding subtree directory does.
- Move get_parent_path() up, accept NULL output param and malloc errors.

servers/slapd/back-ldif/ldif.c

index 3657a33ae98ac1ce19fde48218debaf248b01dc0..fe5a6b75ca8eabcf40f251042ba3ff1ef364d179 100644 (file)
@@ -240,6 +240,27 @@ dn2path( BackendDB *be, struct berval *dn, struct berval *res )
 #define ldif2dir_name(bv) ((bv).bv_val[(bv).bv_len] = '\0')
 #define dir2ldif_name(bv) ((bv).bv_val[(bv).bv_len] = LDIF_FILETYPE_SEP)
 
+/* Get the parent directory path, plus the LDIF suffix overwritten by a \0. */
+static int
+get_parent_path( struct berval *dnpath, struct berval *res )
+{
+       ber_len_t i = dnpath->bv_len;
+
+       while ( i > 0 && dnpath->bv_val[ --i ] != LDAP_DIRSEP[0] ) ;
+       if ( res == NULL ) {
+               res = dnpath;
+       } else {
+               res->bv_val = SLAP_MALLOC( i + 1 + STRLENOF(LDIF) );
+               if ( res->bv_val == NULL )
+                       return LDAP_OTHER;
+               AC_MEMCPY( res->bv_val, dnpath->bv_val, i );
+       }
+       res->bv_len = i;
+       strcpy( res->bv_val + i, LDIF );
+       res->bv_val[i] = '\0';
+       return LDAP_SUCCESS;
+}
+
 /* Make temporary filename pattern for mkstemp() based on dnpath. */
 static char *
 ldif_tempname( const struct berval *dnpath )
@@ -342,23 +363,35 @@ spew_file( int fd, const char *spew, int len, int *save_errno )
        return writeres;
 }
 
+/* Write an entry LDIF file.  Create parentdir first if non-NULL. */
 static int
 ldif_write_entry(
        Operation *op,
        Entry *e,
        const struct berval *path,
+       const char *parentdir,
        const char **text )
 {
        int rc = LDAP_OTHER, res, save_errno = 0;
        int fd, entry_length;
        char *entry_as_string, *tmpfname;
 
+       if ( parentdir != NULL && mkdir( parentdir, 0750 ) < 0 ) {
+               save_errno = errno;
+               Debug( LDAP_DEBUG_ANY, "ldif_write_entry: %s \"%s\": %s\n",
+                       "cannot create parent directory",
+                       parentdir, STRERROR( save_errno ) );
+               *text = "internal error (cannot create parent directory)";
+               return rc;
+       }
+
        tmpfname = ldif_tempname( path );
        fd = tmpfname == NULL ? -1 : mkstemp( tmpfname );
        if ( fd < 0 ) {
                save_errno = errno;
                Debug( LDAP_DEBUG_ANY, "ldif_write_entry: %s for \"%s\": %s\n",
                        "cannot create file", e->e_dn, STRERROR( save_errno ) );
+               *text = "internal error (cannot create file)";
 
        } else {
                ber_len_t dn_len = e->e_name.bv_len;
@@ -399,6 +432,7 @@ ldif_write_entry(
                                Debug( LDAP_DEBUG_ANY, "ldif_write_entry: "
                                        "could not put entry file for \"%s\" in place: %s\n",
                                        e->e_name.bv_val, STRERROR( save_errno ), 0 );
+                               *text = "internal error (could not put entry file in place)";
                        }
                } else if ( res == -1 ) {
                        Debug( LDAP_DEBUG_ANY, "ldif_write_entry: %s \"%s\": %s\n",
@@ -411,9 +445,6 @@ ldif_write_entry(
                }
        }
 
-       if ( rc == LDAP_OTHER && save_errno == ENOENT )
-               rc = LDAP_NO_SUCH_OBJECT;
-
        if ( tmpfname )
                SLAP_FREE( tmpfname );
        return rc;
@@ -705,21 +736,89 @@ enum_tree(
 }
 
 
-/* Get the parent directory path, plus the LDIF suffix overwritten by a \0 */
-static void
-get_parent_path( struct berval *dnpath, struct berval *res )
+/*
+ * Prepare to create or rename an entry:
+ * Check that the entry does not already exist.
+ * Check that the parent entry exists and can have subordinates,
+ * unless need_dir is NULL or adding the suffix entry.
+ *
+ * Return an LDAP result code.  May set *text to a message on failure.
+ * If success, set *dnpath to LDIF entry path and *need_dir to
+ * (directory must be created ? dirname : NULL).
+ */
+static int
+ldif_prepare_create(
+       Operation *op,
+       Entry *e,
+       struct berval *dnpath,
+       char **need_dir,
+       const char **text )
 {
-       int dnpathlen = dnpath->bv_len;
-       int i;
-       
-       for(i = dnpathlen;i>0;i--) /* find the first path seperator */
-               if(dnpath->bv_val[i] == LDAP_DIRSEP[0])
+       BackendDB *be = op->o_bd;
+       struct ldif_info *li = (struct ldif_info *) be->be_private;
+       struct berval *ndn = &e->e_nname;
+       struct berval ppath = BER_BVNULL;
+       struct stat st;
+       int rc = LDAP_SUCCESS;
+
+       dn2path( be, ndn, dnpath );
+
+       if ( stat( dnpath->bv_val, &st ) == 0 ) { /* entry .ldif file */
+               rc = LDAP_ALREADY_EXISTS;
+
+       } else if ( errno != ENOENT ) {
+               Debug( LDAP_DEBUG_ANY,
+                       "ldif_prepare_create: cannot stat \"%s\": %s\n",
+                       dnpath->bv_val, STRERROR( errno ), 0 );
+               rc = LDAP_OTHER;
+               *text = "internal error (cannot check entry file)";
+
+       } else if ( need_dir != NULL ) {
+               *need_dir = NULL;
+               rc = get_parent_path( dnpath, &ppath );
+               /* If parent dir exists, so does parent .ldif:
+                * The directory gets created after and removed before the .ldif.
+                * Except with the database directory, which has no matching entry.
+                */
+               if ( rc == LDAP_SUCCESS && stat( ppath.bv_val, &st ) < 0 ) {
+                       rc = errno == ENOENT && ppath.bv_len > li->li_base_path.bv_len
+                               ? LDAP_NO_SUCH_OBJECT : LDAP_OTHER;
+               }
+               switch ( rc ) {
+               case LDAP_NO_SUCH_OBJECT:
+                       /* No parent dir, check parent .ldif */
+                       dir2ldif_name( ppath );
+                       rc = ldif_read_entry( op, ppath.bv_val, NULL, NULL,
+                               NULL, text );
+                       switch ( rc ) {
+                       case LDAP_SUCCESS:
+                               /* Must create parent directory. */
+                               ldif2dir_name( ppath );
+                               *need_dir = ppath.bv_val;
+                               break;
+                       case LDAP_NO_SUCH_OBJECT:
+                               *text = op->o_tag == LDAP_REQ_MODDN
+                                       ? "newSuperior object does not exist"
+                                       : "parent does not exist";
+                               break;
+                       }
                        break;
-       res->bv_len = i;
-       res->bv_val = ch_malloc( res->bv_len + 1 + STRLENOF(LDIF) );
-       strncpy(res->bv_val, dnpath->bv_val, i);
-       strcpy(res->bv_val+i, LDIF);
-       res->bv_val[i] = '\0';
+               case LDAP_OTHER:
+                       Debug( LDAP_DEBUG_ANY,
+                               "ldif_prepare_create: cannot stat \"%s\" parent dir: %s\n",
+                               ndn->bv_val, STRERROR( errno ), 0 );
+                       *text = "internal error (cannot stat parent dir)";
+                       break;
+               }
+               if ( *need_dir == NULL && ppath.bv_val != NULL )
+                       SLAP_FREE( ppath.bv_val );
+       }
+
+       if ( rc != LDAP_SUCCESS ) {
+               SLAP_FREE( dnpath->bv_val );
+               BER_BVZERO( dnpath );
+       }
+       return rc;
 }
 
 static int apply_modify_to_entry(Entry * entry,
@@ -1008,75 +1107,38 @@ static int ldif_back_search(Operation *op, SlapReply *rs)
 static int ldif_back_add(Operation *op, SlapReply *rs) {
        struct ldif_info *li = (struct ldif_info *) op->o_bd->be_private;
        Entry * e = op->ora_e;
-       struct berval dn = e->e_nname;
-       struct berval leaf_path = BER_BVNULL;
-       struct stat stats;
-       int statres;
+       struct berval path;
+       char *parentdir;
        char textbuf[SLAP_TEXT_BUFLEN];
+       int rc;
 
-       Debug( LDAP_DEBUG_TRACE, "ldif_back_add: \"%s\"\n", dn.bv_val, 0, 0);
+       Debug( LDAP_DEBUG_TRACE, "ldif_back_add: \"%s\"\n", e->e_dn, 0, 0 );
 
-       rs->sr_err = entry_schema_check(op, e, NULL, 0, 1,
+       rc = entry_schema_check( op, e, NULL, 0, 1,
                &rs->sr_text, textbuf, sizeof( textbuf ) );
-       if ( rs->sr_err != LDAP_SUCCESS ) goto send_res;
+       if ( rc != LDAP_SUCCESS )
+               goto send_res;
 
-       rs->sr_err = slap_add_opattrs( op,
-               &rs->sr_text, textbuf, sizeof( textbuf ), 1 );
-       if ( rs->sr_err != LDAP_SUCCESS ) goto send_res;
+       rc = slap_add_opattrs( op, &rs->sr_text, textbuf, sizeof( textbuf ), 1 );
+       if ( rc != LDAP_SUCCESS )
+               goto send_res;
 
        ldap_pvt_thread_rdwr_wlock(&li->li_rdwr);
 
-       dn2path( op->o_bd, &dn, &leaf_path );
-
-       if(leaf_path.bv_val != NULL) {
-               struct berval base = BER_BVNULL;
-               /* build path to container and ldif of container */
-               get_parent_path(&leaf_path, &base);
-
-               statres = stat(base.bv_val, &stats); /* check if container exists */
-               if(statres == -1 && errno == ENOENT) { /* container missing */
-                       base.bv_val[base.bv_len] = LDIF_FILETYPE_SEP;
-                       statres = stat(base.bv_val, &stats); /* check for leaf node */
-                       base.bv_val[base.bv_len] = '\0';
-                       if(statres == -1 && errno == ENOENT) {
-                               rs->sr_err = LDAP_NO_SUCH_OBJECT; /* parent doesn't exist */
-                               rs->sr_text = "Parent does not exist";
-                       }
-                       else if(statres != -1) { /* create parent */
-                               int mkdirres = mkdir(base.bv_val, 0750);
-                               if(mkdirres == -1) {
-                                       rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
-                                       rs->sr_text = "Could not create parent folder";
-                                       Debug( LDAP_DEBUG_ANY, "could not create folder \"%s\": %s\n",
-                                               base.bv_val, STRERROR( errno ), 0 );
-                               }
-                       }
-                       else
-                               rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
-               }/* container was possibly created, move on to add the entry */
-               if(rs->sr_err == LDAP_SUCCESS) {
-                       statres = stat(leaf_path.bv_val, &stats);
-                       if(statres == -1 && errno == ENOENT) {
-                               rs->sr_err = ldif_write_entry( op, e, &leaf_path, &rs->sr_text );
-                       }
-                       else if ( statres == -1 ) {
-                               rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
-                               Debug( LDAP_DEBUG_ANY, "could not stat file \"%s\": %s\n",
-                                       leaf_path.bv_val, STRERROR( errno ), 0 );
-                       }
-                       else /* it already exists */
-                               rs->sr_err = LDAP_ALREADY_EXISTS;
-               }
-               SLAP_FREE(base.bv_val);
-               SLAP_FREE(leaf_path.bv_val);
+       rc = ldif_prepare_create( op, e, &path, &parentdir, &rs->sr_text );
+       if ( rc == LDAP_SUCCESS ) {
+               rc = ldif_write_entry( op, e, &path, parentdir, &rs->sr_text );
+               SLAP_FREE( path.bv_val );
+               if ( parentdir != NULL )
+                       SLAP_FREE( parentdir );
        }
 
        ldap_pvt_thread_rdwr_wunlock(&li->li_rdwr);
 
-send_res:
-       Debug( LDAP_DEBUG_TRACE, 
-                       "ldif_back_add: err: %d text: %s\n", rs->sr_err, rs->sr_text ?
-                               rs->sr_text : "", 0);
+ send_res:
+       rs->sr_err = rc;
+       Debug( LDAP_DEBUG_TRACE, "ldif_back_add: err: %d text: %s\n",
+               rc, rs->sr_text ? rs->sr_text : "", 0 );
        send_ldap_result(op, rs);
        slap_graduate_commit_csn( op );
        return rs->sr_err;
@@ -1097,7 +1159,7 @@ static int ldif_back_modify(Operation *op, SlapReply *rs) {
        if ( rc == LDAP_SUCCESS ) {
                rc = apply_modify_to_entry( entry, modlst, op, rs );
                if ( rc == LDAP_SUCCESS ) {
-                       rc = ldif_write_entry( op, entry, &path, &rs->sr_text );
+                       rc = ldif_write_entry( op, entry, &path, NULL, &rs->sr_text );
                }
 
                entry_free( entry );
@@ -1181,43 +1243,29 @@ ldif_move_entry(
        const char **text )
 {
        int res;
-       int exists_res;
        struct berval newpath;
+       char *parentdir = NULL;
+       int rc;
 
-       dn2path( op->o_bd, &entry->e_nname, &newpath );
+       rc = ldif_prepare_create( op, entry, &newpath,
+                       op->orr_newSup ? &parentdir : NULL, text );
 
-       if((entry == NULL || oldpath->bv_val == NULL) || newpath.bv_val == NULL) {
-               /* some object doesn't exist */
-               res = LDAP_NO_SUCH_OBJECT;
-       }
-       else { /* do the modrdn */
-               exists_res = open(newpath.bv_val, O_RDONLY);
-               if(exists_res == -1 && errno == ENOENT) {
-                       res = ldif_write_entry( op, entry, &newpath, text );
-                       if ( res == LDAP_SUCCESS ) {
+       if ( rc == LDAP_SUCCESS ) {
+               rc = ldif_write_entry( op, entry, &newpath, parentdir, text );
+               if ( rc == LDAP_SUCCESS ) {
                                /* if this fails we should log something bad */
                                res = unlink( oldpath->bv_val );
                                oldpath->bv_val[oldpath->bv_len - STRLENOF(".ldif")] = '\0';
                                newpath.bv_val[newpath.bv_len - STRLENOF(".ldif")] = '\0';
                                res = rename( oldpath->bv_val, newpath.bv_val );
-                               res = LDAP_SUCCESS;
-                       }
-               }
-               else if(exists_res) {
-                       int close_res = close(exists_res);
-                       res = LDAP_ALREADY_EXISTS;
-                       if(close_res == -1) {
-                       /* log heinous error */
-                       }
-               }
-               else {
-                       res = LDAP_UNWILLING_TO_PERFORM;
                }
+
+               SLAP_FREE( newpath.bv_val );
+               if ( parentdir != NULL )
+                       SLAP_FREE( parentdir );
        }
 
-       if(newpath.bv_val != NULL)
-               SLAP_FREE(newpath.bv_val);
-       return res;
+       return rc;
 }
 
 static int
@@ -1237,21 +1285,7 @@ ldif_back_modrdn(Operation *op, SlapReply *rs)
        if ( rc == LDAP_SUCCESS ) {
                /* build new dn, and new ndn for the entry */
                if ( op->oq_modrdn.rs_newSup != NULL ) {
-                       struct berval   op_dn = op->o_req_dn,
-                                       op_ndn = op->o_req_ndn;
-                       Entry           *np;
-
-                       /* new superior */
                        p_dn = *op->oq_modrdn.rs_newSup;
-                       op->o_req_dn = *op->oq_modrdn.rs_newSup;
-                       op->o_req_ndn = *op->oq_modrdn.rs_nnewSup;
-                       rc = get_entry( op, &np, NULL, &rs->sr_text );
-                       op->o_req_dn = op_dn;
-                       op->o_req_ndn = op_ndn;
-                       if ( rc != LDAP_SUCCESS ) {
-                               goto no_such_object;
-                       }
-                       entry_free( np );
                } else {
                        dnParent( &entry->e_name, &p_dn );
                }
@@ -1267,7 +1301,6 @@ ldif_back_modrdn(Operation *op, SlapReply *rs)
                if ( rc == LDAP_SUCCESS )
                        rc = ldif_move_entry( op, entry, &old_path, &rs->sr_text );
 
-no_such_object:;
                entry_free( entry );
                SLAP_FREE( old_path.bv_val );
        }
@@ -1376,52 +1409,22 @@ ldif_tool_entry_put( BackendDB *be, Entry *e, struct berval *text )
 {
        int rc;
        const char *errmsg = NULL;
-       struct berval leaf_path = BER_BVNULL;
-       struct stat stats;
-       int statres;
-       int res = LDAP_SUCCESS;
+       struct berval path;
+       char *parentdir;
        Operation op = {0};
 
-       dn2path( be, &e->e_nname, &leaf_path );
-
-       if(leaf_path.bv_val != NULL) {
-               struct berval base = BER_BVNULL;
-               /* build path to container, and path to ldif of container */
-               get_parent_path(&leaf_path, &base);
+       op.o_bd = be;
+       rc = ldif_prepare_create( &op, e, &path, &parentdir, &errmsg );
+       if ( rc == LDAP_SUCCESS ) {
+               rc = ldif_write_entry( &op, e, &path, parentdir, &errmsg );
 
-               statres = stat(base.bv_val, &stats); /* check if container exists */
-               if(statres == -1 && errno == ENOENT) { /* container missing */
-                       base.bv_val[base.bv_len] = LDIF_FILETYPE_SEP;
-                       statres = stat(base.bv_val, &stats); /* check for leaf node */
-                       base.bv_val[base.bv_len] = '\0';
-                       if(statres == -1 && errno == ENOENT) {
-                               res = LDAP_NO_SUCH_OBJECT; /* parent doesn't exist */
-                       }
-                       else if(statres != -1) { /* create parent */
-                               int mkdirres = mkdir(base.bv_val, 0750);
-                               if(mkdirres == -1) {
-                                       res = LDAP_UNWILLING_TO_PERFORM;
-                               }
-                       }
-                       else
-                               res = LDAP_UNWILLING_TO_PERFORM;
-               }/* container was possibly created, move on to add the entry */
-               if(res == LDAP_SUCCESS) {
-                       statres = stat(leaf_path.bv_val, &stats);
-                       if(statres == -1 && errno == ENOENT) {
-                               res = ldif_write_entry( &op, e, &leaf_path, &errmsg );
-                       }
-                       else /* it already exists */
-                               res = LDAP_ALREADY_EXISTS;
-               }
-               SLAP_FREE(base.bv_val);
-               SLAP_FREE(leaf_path.bv_val);
+               SLAP_FREE( path.bv_val );
+               if ( parentdir != NULL )
+                       SLAP_FREE( parentdir );
+               if ( rc == LDAP_SUCCESS )
+                       return 1;
        }
 
-       if(res == LDAP_SUCCESS) {
-               return 1;
-       }
-       rc = res;
        if ( errmsg == NULL && rc != LDAP_OTHER )
                errmsg = ldap_err2string( rc );
        if ( errmsg != NULL )