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