+
+/*
+ * 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 )
+{
+ struct ldif_info *li = (struct ldif_info *) op->o_bd->be_private;
+ struct berval *ndn = &e->e_nname;
+ struct berval ppath = BER_BVNULL;
+ struct stat st;
+ Entry *parent = NULL;
+ int rc;
+
+ if ( op->o_abandon )
+ return SLAPD_ABANDON;
+
+ rc = ndn2path( op, ndn, dnpath, 0 );
+ if ( rc != LDAP_SUCCESS ) {
+ return rc;
+ }
+
+ 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,
+ (op->o_tag != LDAP_REQ_ADD || get_manageDSAit( op )
+ ? &parent : NULL),
+ text );
+ switch ( rc ) {
+ case LDAP_SUCCESS:
+ /* Check that parent is not a referral, unless
+ * ldif_back_referrals() already checked.
+ */
+ if ( parent != NULL ) {
+ int is_ref = is_entry_referral( parent );
+ entry_free( parent );
+ if ( is_ref ) {
+ rc = LDAP_AFFECTS_MULTIPLE_DSAS;
+ *text = op->o_tag == LDAP_REQ_MODDN
+ ? "newSuperior is a referral object"
+ : "parent is a referral object";
+ break;
+ }
+ }
+ /* 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;
+ }