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 : }
|