LCOV - code coverage report
Current view: top level - src/server/protocol1 - link.c (source / functions) Hit Total Coverage
Test: burp-coverage-clean.info Lines: 4 70 5.7 %
Date: 2021-07-02 04:40:54 Functions: 1 3 33.3 %

          Line data    Source code
       1             : #include "../../burp.h"
       2             : #include "../../alloc.h"
       3             : #include "../../cntr.h"
       4             : #include "../../conf.h"
       5             : #include "../../cstat.h"
       6             : #include "../../fsops.h"
       7             : #include "../../fzp.h"
       8             : #include "../../log.h"
       9             : #include "../../prepend.h"
      10             : #include "../child.h"
      11             : #include "link.h"
      12             : 
      13           0 : int recursive_hardlink(const char *src, const char *dst, struct conf **confs)
      14             : {
      15           0 :         int ret=-1;
      16           0 :         DIR *dirp=NULL;
      17           0 :         char *tmp=NULL;
      18           0 :         char *fullpatha=NULL;
      19           0 :         char *fullpathb=NULL;
      20           0 :         struct dirent *entry=NULL;
      21             : 
      22           0 :         if(!(tmp=prepend_s(dst, "dummy")))
      23             :                 goto end;
      24           0 :         if(mkpath(&tmp, dst))
      25             :         {
      26           0 :                 logp("could not mkpath for %s\n", tmp);
      27           0 :                 goto end;
      28             :         }
      29             : 
      30           0 :         if(!(dirp=opendir(src)))
      31             :         {
      32           0 :                 logp("opendir %s in %s: %s\n",
      33           0 :                         src, __func__, strerror(errno));
      34           0 :                 goto end;
      35             :         }
      36             : 
      37             :         while(1)
      38             :         {
      39             :                 struct stat statp;
      40             : 
      41           0 :                 errno=0;
      42           0 :                 if(!(entry=readdir(dirp)))
      43             :                 {
      44           0 :                         if(errno)
      45             :                         {
      46           0 :                                 logp("error in readdir in %s: %s\n",
      47             :                                         __func__, strerror(errno));
      48           0 :                                 goto end;
      49             :                         }
      50           0 :                         break;
      51             :                 }
      52             : 
      53           0 :                 if(!filter_dot(entry))
      54           0 :                         continue;
      55             : 
      56           0 :                 free_w(&fullpatha);
      57           0 :                 free_w(&fullpathb);
      58           0 :                 if(!(fullpatha=prepend_s(src, entry->d_name))
      59           0 :                   || !(fullpathb=prepend_s(dst, entry->d_name)))
      60             :                         goto end;
      61             : 
      62             : #ifdef _DIRENT_HAVE_D_TYPE
      63             : // Faster evaluation on most systems.
      64           0 :                 if(entry->d_type==DT_DIR)
      65             :                 {
      66           0 :                         if(recursive_hardlink(fullpatha, fullpathb, confs))
      67             :                                 goto end;
      68             :                 }
      69             :                 else
      70             : #endif
      71             :                 // Otherwise, we have to do an lstat() anyway, because we
      72             :                 // will need to check the number of hardlinks in do_link().
      73           0 :                 if(lstat(fullpatha, &statp))
      74             :                 {
      75           0 :                         logp("could not lstat %s\n", fullpatha);
      76             :                 }
      77           0 :                 else if(S_ISDIR(statp.st_mode))
      78             :                 {
      79           0 :                         if(recursive_hardlink(fullpatha, fullpathb, confs))
      80             :                                 goto end;
      81             :                 }
      82             :                 else
      83             :                 {
      84             :                         //logp("hardlinking %s to %s\n", fullpathb, fullpatha);
      85           0 :                         if(timed_operation_status_only(CNTR_STATUS_SHUFFLING,
      86             :                                 fullpathb, confs)
      87           0 :                           || do_link(fullpatha, fullpathb, &statp, confs,
      88             :                                 0 /* do not overwrite target */))
      89             :                                         goto end;
      90             :                 }
      91             :         }
      92             : 
      93           0 :         ret=0;
      94             : end:
      95           0 :         if(dirp) closedir(dirp);
      96           0 :         free_w(&fullpatha);
      97           0 :         free_w(&fullpathb);
      98           0 :         free_w(&tmp);
      99             : 
     100           0 :         return ret;
     101             : }
     102             : 
     103             : #define DUP_CHUNK       4096
     104           0 : static int duplicate_file(const char *oldpath, const char *newpath)
     105             : {
     106           0 :         int ret=-1;
     107           0 :         size_t s=0;
     108           0 :         size_t t=0;
     109           0 :         struct fzp *op=NULL;
     110           0 :         struct fzp *np=NULL;
     111           0 :         char buf[DUP_CHUNK]="";
     112           0 :         if(!(op=fzp_open(oldpath, "rb"))
     113           0 :           || !(np=fzp_open(newpath, "wb")))
     114             :                 goto end;
     115             : 
     116           0 :         while((s=fzp_read(op, buf, DUP_CHUNK))>0)
     117             :         {
     118           0 :                 t=fzp_write(np, buf, s);
     119           0 :                 if(t!=s)
     120             :                 {
     121           0 :                         logp("could not write all bytes: %lu!=%lu\n",
     122             :                                 (unsigned long)s, (unsigned long)t);
     123           0 :                         goto end;
     124             :                 }
     125             :         }
     126             : 
     127             :         ret=0;
     128             : end:
     129           0 :         fzp_close(&np);
     130           0 :         fzp_close(&op);
     131           0 :         if(ret) logp("could not duplicate %s to %s\n", oldpath, newpath);
     132           0 :         return ret;
     133             : }
     134             : 
     135           9 : int do_link(const char *oldpath, const char *newpath, struct stat *statp,
     136             :         struct conf **confs, uint8_t overwrite)
     137             : {
     138             :         /* Avoid creating too many hardlinks */
     139           9 :         if(confs
     140           6 :           && statp->st_nlink >= (unsigned int)get_int(confs[OPT_MAX_HARDLINKS]))
     141             :         {
     142           0 :                 return duplicate_file(oldpath, newpath);
     143             :         }
     144           9 :         else if(link(oldpath, newpath))
     145             :         {
     146           0 :                 if(overwrite && errno==EEXIST)
     147             :                 {
     148           0 :                         unlink(newpath);
     149           0 :                         if(!link(oldpath, newpath))
     150             :                         {
     151             :                                 //logp("Successful hard link of '%s' to '%s' after unlinking the former\n", newpath, oldpath);
     152             :                                 return 0;
     153             :                         }
     154             :                 }
     155           0 :                 logp("could not hard link '%s' to '%s': %s\n",
     156           0 :                         newpath, oldpath, strerror(errno));
     157           0 :                 return -1;
     158             :         }
     159             :         return 0;
     160             : }

Generated by: LCOV version 1.13