#else
#define move_file(from, to) rename(from, to)
#endif
+#define move_dir(from, to) rename(from, to)
#define LDIF ".ldif"
struct berval *oldpath,
const char **text )
{
- int res;
struct berval newpath;
- char *parentdir = NULL;
- int rc;
+ char *parentdir = NULL, *trash;
+ int rc, rename_res;
rc = ldif_prepare_create( op, entry, &newpath,
op->orr_newSup ? &parentdir : NULL, text );
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 );
+ trash = oldpath->bv_val; /* will be .ldif file to delete */
+ ldif2dir_len( newpath );
+ ldif2dir_len( *oldpath );
+ /* Move subdir before deleting old entry,
+ * so .ldif always exists if subdir does.
+ */
+ ldif2dir_name( newpath );
+ ldif2dir_name( *oldpath );
+ rename_res = move_dir( oldpath->bv_val, newpath.bv_val );
+ if ( rename_res != 0 && errno != ENOENT ) {
+ rc = LDAP_OTHER;
+ *text = "internal error (cannot move this subtree)";
+ trash = newpath.bv_val;
+ }
+
+ /* Delete old entry, or if error undo change */
+ for (;;) {
+ dir2ldif_name( newpath );
+ dir2ldif_name( *oldpath );
+ if ( unlink( trash ) == 0 )
+ break;
+ if ( rc == LDAP_SUCCESS ) {
+ /* Prepare to undo change and return failure */
+ rc = LDAP_OTHER;
+ *text = "internal error (cannot move this entry)";
+ trash = newpath.bv_val;
+ if ( rename_res != 0 )
+ continue;
+ /* First move subdirectory back */
+ ldif2dir_name( newpath );
+ ldif2dir_name( *oldpath );
+ if ( move_dir( newpath.bv_val, oldpath->bv_val ) == 0 )
+ continue;
+ }
+ *text = "added new but couldn't delete old entry!";
+ break;
+ }
+
+ if ( rc != LDAP_SUCCESS ) {
+ char s[128];
+ snprintf( s, sizeof s, "%s (%s)", *text, STRERROR( errno ));
+ Debug( LDAP_DEBUG_ANY,
+ "ldif_move_entry: %s: \"%s\" -> \"%s\"\n",
+ s, op->o_req_dn.bv_val, entry->e_dn );
+ }
}
SLAP_FREE( newpath.bv_val );