From: Hallvard Furuseth Date: Tue, 11 Nov 2008 23:22:24 +0000 (+0000) Subject: ITS#5408 part 5 - handle modrdn file error. Move entry/subtree back if needed. X-Git-Tag: ACLCHECK_0~1121 X-Git-Url: https://git.sur5r.net/?a=commitdiff_plain;h=5c41dfdabe17150d8ba29573ba09c26310f7c025;p=openldap ITS#5408 part 5 - handle modrdn file error. Move entry/subtree back if needed. Add move_dir() macro, matching move_file(). --- diff --git a/servers/slapd/back-ldif/ldif.c b/servers/slapd/back-ldif/ldif.c index fe5a6b75ca..8fa8877e06 100644 --- a/servers/slapd/back-ldif/ldif.c +++ b/servers/slapd/back-ldif/ldif.c @@ -52,6 +52,7 @@ struct ldif_info { #else #define move_file(from, to) rename(from, to) #endif +#define move_dir(from, to) rename(from, to) #define LDIF ".ldif" @@ -1242,10 +1243,9 @@ ldif_move_entry( 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 ); @@ -1253,11 +1253,51 @@ ldif_move_entry( 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 );