LCOV - code coverage report
Current view: top level - src/server - delete.c (source / functions) Hit Total Coverage
Test: burp-coverage-clean.info Lines: 105 112 93.8 %
Date: 2020-07-31 05:59:47 Functions: 7 7 100.0 %

          Line data    Source code
       1             : #include "../burp.h"
       2             : #include "../alloc.h"
       3             : #include "../asfd.h"
       4             : #include "../bu.h"
       5             : #include "../cmd.h"
       6             : #include "../cntr.h"
       7             : #include "../cstat.h"
       8             : #include "../fsops.h"
       9             : #include "../log.h"
      10             : #include "../prepend.h"
      11             : #include "../strlist.h"
      12             : #include "bu_get.h"
      13             : #include "child.h"
      14             : #include "sdirs.h"
      15             : #include "protocol2/backup_phase4.h"
      16             : #include "delete.h"
      17             : 
      18          77 : static int do_rename_w(const char *a, const char *b,
      19             :         const char *cname, struct bu *bu)
      20             : {
      21          77 :         int ret=-1;
      22          77 :         char *target=NULL;
      23          77 :         char new_name[256]="";
      24          77 :         snprintf(new_name, sizeof(new_name), "%s-%s", cname, bu->basename);
      25          77 :         if(!(target=prepend_s(b, new_name))
      26          77 :           || build_path_w(target))
      27             :                 goto end;
      28          77 :         if(do_rename(a, target))
      29             :         {
      30           0 :                 logp("Error when trying to rename for delete %s\n", a);
      31             :                 goto end;
      32             :         }
      33             :         ret=0;
      34             : end:
      35          77 :         free_w(&target);
      36          77 :         return ret;
      37             : }
      38             : 
      39          77 : static int recursive_delete_w(struct sdirs *sdirs, struct bu *bu,
      40             :         const char *manual_delete)
      41             : {
      42          77 :         if(manual_delete) return 0;
      43          77 :         if(recursive_delete(sdirs->deleteme))
      44             :         {
      45           0 :                 logp("Error when trying to delete %s\n", bu->path);
      46             :                 return -1;
      47             :         }
      48             :         return 0;
      49             : }
      50             : 
      51             : // The failure conditions here are dealt with by the rubble cleaning code.
      52          77 : static int delete_backup(struct sdirs *sdirs, const char *cname, struct bu *bu,
      53             :         const char *manual_delete)
      54             : {
      55          77 :         logp("deleting %s backup %" PRId64 "\n", cname, bu->bno);
      56             : 
      57          77 :         if(sdirs->global_sparse)
      58             :         {
      59          43 :                 const char *candidate_str=bu->path+strlen(sdirs->base)+1;
      60          43 :                 if(remove_backup_from_global_sparse(
      61             :                         sdirs->global_sparse, candidate_str))
      62             :                                 return -1;
      63             :         }
      64             : 
      65          77 :         if(!bu->next && !bu->prev)
      66             :         {
      67             :                 // The current, and only, backup.
      68           2 :                 if(do_rename_w(bu->path, sdirs->deleteme, cname, bu))
      69             :                         return -1;
      70             :                 // If interrupted here, there will be a dangling 'current'
      71             :                 // symlink.
      72           2 :                 if(unlink(sdirs->current))
      73             :                 {
      74           0 :                         logp("unlink %s: %s\n",
      75           0 :                                 sdirs->current, strerror(errno));
      76           0 :                         return -1;
      77             :                 }
      78           2 :                 return recursive_delete_w(sdirs, bu, manual_delete);
      79             :         }
      80          75 :         if(!bu->next && bu->prev)
      81             :         {
      82             :                 // The current backup. There are other backups left.
      83             :                 // Need to point the symlink at the previous backup.
      84           3 :                 const char *target=NULL;
      85             :                 
      86           3 :                 target=bu->prev->basename;
      87           3 :                 unlink(sdirs->currenttmp);
      88           3 :                 if(do_symlink(target, sdirs->currenttmp))
      89             :                         return -1;
      90             :                 // If interrupted here, there is a currenttmp and a current
      91             :                 // symlink, and they both point to valid directories.
      92           3 :                 if(do_rename_w(bu->path, sdirs->deleteme, cname, bu))
      93             :                         return -1;
      94             :                 // If interrupted here, there is a currenttmp and a current
      95             :                 // symlink, and the current link is dangling.
      96           3 :                 if(do_rename(sdirs->currenttmp, sdirs->current))
      97             :                         return -1;
      98             :                 // If interrupted here, moving the symlink could have failed
      99             :                 // after current was deleted but before currenttmp was renamed.
     100           3 :                 if(recursive_delete_w(sdirs, bu, manual_delete))
     101             :                         return -1;
     102           3 :                 return 0;
     103             :         }
     104             : 
     105             :         // It is not the current backup.
     106          72 :         if(do_rename_w(bu->path, sdirs->deleteme, cname, bu)
     107          72 :           || recursive_delete_w(sdirs, bu, manual_delete))
     108             :                 return -1;
     109             :         return 0;
     110             : }
     111             : 
     112          64 : static int range_loop(struct sdirs *sdirs, const char *cname,
     113             :         struct strlist *keep, unsigned long rmin, struct bu *bu_list,
     114             :         struct bu *last, const char *manual_delete, int *deleted)
     115             : {
     116          64 :         struct bu *bu=NULL;
     117          64 :         unsigned long r=0;
     118          64 :         unsigned long rmax=0;
     119             : 
     120          64 :         rmax=rmin*keep->next->flag;
     121             : 
     122             :         // This is going over each range.
     123         216 :         for(r=rmax; r>rmin; r-=rmin)
     124             :         {
     125          88 :                 int count=0;
     126          88 :                 unsigned long s=r-rmin;
     127             : 
     128             :                 // Count the backups in the range.
     129         855 :                 for(bu=bu_list; bu; bu=bu->next)
     130         767 :                   if(s<bu->trbno && bu->trbno<=r)
     131         165 :                         count++;
     132             : 
     133             :                 // Want to leave one entry in each range.
     134          88 :                 if(count<=1) continue;
     135             : 
     136             :                 // Try to delete from the most recent in each
     137             :                 // so that hardlinked backups get taken out
     138             :                 // last.
     139             : 
     140         358 :                 for(bu=last; bu; bu=bu->prev)
     141             :                 {
     142         378 :                         if(s<bu->trbno
     143         172 :                           && bu->trbno<r
     144          80 :                           && (bu->flags & BU_DELETABLE))
     145             :                         {
     146          45 :                                 if(delete_backup(sdirs, cname, bu,
     147             :                                         manual_delete)) return -1;
     148          45 :                                 (*deleted)++;
     149          45 :                                 if(--count<=1) break;
     150             :                         }
     151             :                 }
     152             :         }
     153             : 
     154             :         return 0;
     155             : }
     156             : 
     157          57 : static int do_delete_backups(struct sdirs *sdirs, const char *cname,
     158             :         struct strlist *keep, struct bu *bu_list, const char *manual_delete)
     159             : {
     160          57 :         int ret=-1;
     161          57 :         int deleted=0;
     162          57 :         unsigned long m=1;
     163          57 :         struct bu *bu=NULL;
     164          57 :         struct bu *last=NULL;
     165          57 :         struct strlist *k=NULL;
     166             : 
     167             :         // Find the last entry in the list.
     168          57 :         for(bu=bu_list; bu; bu=bu->next) last=bu;
     169             : 
     170             :         // For each of the 'keep' values, generate ranges in which to keep
     171             :         // one backup.
     172         121 :         for(k=keep; k; k=k->next)
     173             :         {
     174         121 :                 unsigned long rmin=0;
     175         121 :                 rmin=m * k->flag;
     176             : 
     177         121 :                 if(k->next && range_loop(sdirs, cname,
     178             :                         k, rmin, bu_list, last, manual_delete, &deleted))
     179             :                                 goto end;
     180         121 :                 m=rmin;
     181             :         }
     182             : 
     183             :         // Remove the very oldest backups.
     184         202 :         for(bu=bu_list; bu; bu=bu->next) if(bu->trbno>m) break;
     185             : 
     186          26 :         for(; bu; bu=bu->prev)
     187             :         {
     188          26 :                 if(delete_backup(sdirs, cname, bu, manual_delete))
     189             :                         goto end;
     190          26 :                 deleted++;
     191             :         }
     192             : 
     193          57 :         ret=deleted;
     194             : end:
     195          57 :         return ret;
     196             : }
     197             : 
     198          24 : int delete_backups(struct sdirs *sdirs,
     199             :         const char *cname, struct strlist *keep, const char *manual_delete)
     200             : {
     201          24 :         int ret=-1;
     202          24 :         struct bu *bu_list=NULL;
     203             :         // Deleting a backup might mean that more become available to delete.
     204             :         // Keep trying to delete until we cannot delete any more.
     205             :         while(1)
     206             :         {
     207          90 :                 if(bu_get_list(sdirs, &bu_list)) goto end;
     208          57 :                 switch(do_delete_backups(sdirs, cname, keep, bu_list,
     209             :                         manual_delete))
     210             :                 {
     211             :                         case 0: ret=0; goto end;
     212           0 :                         case -1: ret=-1; goto end;
     213             :                         default: break;
     214             :                 }
     215          33 :                 bu_list_free(&bu_list);
     216             :         }
     217             : end:
     218          24 :         bu_list_free(&bu_list);
     219          24 :         return ret;
     220             : }
     221             : 
     222          13 : int do_delete_server(struct asfd *asfd,
     223             :         struct sdirs *sdirs, struct cntr *cntr,
     224             :         const char *cname, const char *backup, const char *manual_delete)
     225             : {
     226          13 :         int ret=-1;
     227          13 :         int found=0;
     228          13 :         unsigned long bno=0;
     229          13 :         struct bu *bu=NULL;
     230          13 :         struct bu *bu_list=NULL;
     231             : 
     232          13 :         logp("in do_delete\n");
     233             : 
     234          13 :         if(bu_get_list(sdirs, &bu_list))
     235             :                 goto end;
     236             : 
     237          13 :         if(backup && *backup) bno=strtoul(backup, NULL, 10);
     238             : 
     239          37 :         for(bu=bu_list; bu; bu=bu->next)
     240             :         {
     241          32 :                 if(!backup || !*backup) continue;
     242             :                 if(!found
     243          32 :                   && (!strcmp(bu->timestamp, backup)
     244          32 :                         || bu->bno==bno))
     245             :                 {
     246           8 :                         if(bu->flags & BU_DELETABLE)
     247             :                         {
     248           6 :                                 found=1;
     249           6 :                                 if(cntr)
     250           0 :                                         cntr->bno=(int)bu->bno;
     251           6 :                                 if(write_status(CNTR_STATUS_DELETING,
     252             :                                         NULL, cntr))
     253             :                                                 goto end;
     254           6 :                                 if(asfd->write_str(asfd, CMD_GEN, "ok")
     255           6 :                                   || delete_backup(sdirs, cname, bu,
     256             :                                         manual_delete))
     257             :                                                 goto end;
     258             :                         }
     259             :                         else
     260             :                         {
     261           2 :                                 asfd->write_str(asfd, CMD_ERROR,
     262             :                                         "backup not deletable");
     263           2 :                                 goto end;
     264             :                         }
     265             :                         break;
     266             :                 }
     267             :         }
     268             : 
     269          11 :         if(backup && *backup && !found)
     270             :         {
     271           4 :                 asfd->write_str(asfd, CMD_ERROR, "backup not found");
     272           4 :                 goto end;
     273             :         }
     274             : 
     275             :         ret=0;
     276             : end:
     277          13 :         bu_list_free(&bu_list);
     278          13 :         return ret;
     279             : }

Generated by: LCOV version 1.13