// The failure conditions here are dealt with by the rubble cleaning code. static int delete_backup(struct sdirs *sdirs, const char *cname, struct bu *bu, const char *manual_delete) { logp("deleting %s backup %" PRId64 "\n", cname, bu->bno); if(sdirs->global_sparse) { const char *candidate_str=bu->path+strlen(sdirs->base)+1; if(remove_from_global_sparse( sdirs->global_sparse, candidate_str)) return -1; } if(!bu->next && !bu->prev) { // The current, and only, backup. if(do_rename_w(bu->path, sdirs->deleteme, cname, bu)) return -1; // If interrupted here, there will be a dangling 'current' // symlink. if(unlink(sdirs->current)) { logp("unlink %s: %s\n", sdirs->current, strerror(errno)); return -1; } return recursive_delete_w(sdirs, bu, manual_delete); } if(!bu->next && bu->prev) { // The current backup. There are other backups left. // Need to point the symlink at the previous backup. const char *target=NULL; target=bu->prev->basename; unlink(sdirs->currenttmp); if(do_symlink(target, sdirs->currenttmp)) return -1; // If interrupted here, there is a currenttmp and a current // symlink, and they both point to valid directories. if(do_rename_w(bu->path, sdirs->deleteme, cname, bu)) return -1; // If interrupted here, there is a currenttmp and a current // symlink, and the current link is dangling. if(do_rename(sdirs->currenttmp, sdirs->current)) return -1; // If interrupted here, moving the symlink could have failed // after current was deleted but before currenttmp was renamed. if(recursive_delete_w(sdirs, bu, manual_delete)) return -1; return 0; } // It is not the current backup. if(do_rename_w(bu->path, sdirs->deleteme, cname, bu) || recursive_delete_w(sdirs, bu, manual_delete)) return -1; return 0; }
// The failure conditions here are dealt with by the rubble cleaning code. int delete_backup(struct sdirs *sdirs, struct conf *conf, struct bu *bu) { logp("deleting %s backup %lu\n", conf->cname, bu->bno); if(!bu->next && !bu->prev) { // The current, and only, backup. if(do_rename_w(bu->path, sdirs->deleteme)) return -1; // If interrupted here, there will be a dangling 'current' // symlink. if(unlink(sdirs->current)) { logp("unlink %s: %s\n", sdirs->current, strerror(errno)); return -1; } return recursive_delete_w(sdirs, bu); } if(!bu->next && bu->prev) { // The current backup. There are other backups left. // Need to point the symlink at the previous backup. const char *target=NULL; target=bu->prev->basename; unlink(sdirs->currenttmp); if(symlink(target, sdirs->currenttmp)) { logp("could not symlink '%s' to '%s': %s\n", sdirs->currenttmp, target, strerror(errno)); return -1; } // If interrupted here, there is a currenttmp and a current // symlink, and they both point to valid directories. if(do_rename_w(bu->path, sdirs->deleteme)) return -1; // If interrupted here, there is a currenttmp and a current // symlink, and the current link is dangling. if(do_rename_w(sdirs->currenttmp, sdirs->current)) return -1; // If interrupted here, moving the symlink could have failed // after current was deleted but before currenttmp was renamed. if(recursive_delete_w(sdirs, bu)) return -1; return 0; } // It is not the current backup. if(do_rename_w(bu->path, sdirs->deleteme) || recursive_delete_w(sdirs, bu)) return -1; return 0; }