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

Generated by: LCOV version 1.13