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