1 /*
2 Bacula® - The Network Backup Solution
3
4 Copyright (C) 2000-2009 Free Software Foundation Europe e.V.
5
6 The main author of Bacula is Kern Sibbald, with contributions from
7 many others, a complete list can be found in the file AUTHORS.
8 This program is Free Software; you can redistribute it and/or
9 modify it under the terms of version three of the GNU Affero General Public
10 License as published by the Free Software Foundation and included
11 in the file LICENSE.
12
13 This program is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 General Public License for more details.
17
18 You should have received a copy of the GNU Affero General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21 02110-1301, USA.
22
23 Bacula® is a registered trademark of Kern Sibbald.
24 The licensor of Bacula is the Free Software Foundation Europe
25 (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
26 Switzerland, email:ftf@fsfeurope.org.
27 */
28 /*
29 * Traces of * bacula-5.0.3:src/filed/backup.c still exist in this file, hence
30 * the copyright notice above. Specifically, FF_PKT and the FF_* types. At
31 * some point, these will be removed in favour of the burp sbuf code.
32 * Graham Keeling, 2014.
33 */
34
35 #include "../burp.h"
36 #include "../alloc.h"
37 #include "../asfd.h"
38 #include "../async.h"
39 #include "../attribs.h"
40 #include "../cmd.h"
41 #include "../cntr.h"
42 #include "../linkhash.h"
43 #include "../log.h"
44 #include "../strlist.h"
45 #include "extrameta.h"
46 #include "find.h"
47 #include "backup_phase1.h"
48
49 static int encryption=ENCRYPTION_NONE;
50 static enum cmd filesymbol=CMD_FILE;
51 static enum cmd dirsymbol=CMD_DIRECTORY;
52 #ifdef HAVE_WIN32
53 static enum cmd metasymbol=CMD_VSS;
54 static enum cmd vss_trail_symbol=CMD_VSS_T;
55 #else
56 static enum cmd metasymbol=CMD_METADATA;
57 #endif
58
59 static int enable_acl=0;
60 static int enable_xattr=0;
61
usual_stuff(struct asfd * asfd,struct cntr * cntr,const char * path,const char * link,struct sbuf * sb,enum cmd cmd)62 static int usual_stuff(struct asfd *asfd,
63 struct cntr *cntr, const char *path, const char *link,
64 struct sbuf *sb, enum cmd cmd)
65 {
66 // When run with ACTION_ESTIMATE, asfd is NULL.
67 if(asfd)
68 {
69 if(asfd->write_str(asfd, CMD_ATTRIBS, sb->attr.buf)
70 || asfd->write_str(asfd, cmd, path)
71 || ((cmd==CMD_HARD_LINK || cmd==CMD_SOFT_LINK)
72 && asfd->write_str(asfd, cmd, link)))
73 return -1;
74 }
75 cntr_add_phase1(cntr, cmd, 1);
76 return 0;
77 }
78
maybe_send_extrameta(struct asfd * asfd,const char * path,enum cmd cmd,struct sbuf * sb,struct cntr * cntr,enum cmd symbol)79 static int maybe_send_extrameta(struct asfd *asfd,
80 const char *path, enum cmd cmd,
81 struct sbuf *sb,
82 struct cntr *cntr, enum cmd symbol)
83 {
84 // FIX THIS: should probably initialise extrameta with the desired
85 // conf parameters so that they do not need to be passed in all the
86 // time.
87 if(!has_extrameta(path, cmd, enable_acl, enable_xattr))
88 return 0;
89 return usual_stuff(asfd, cntr, path, NULL, sb, symbol);
90 }
91
ft_err(struct asfd * asfd,struct conf ** confs,struct FF_PKT * ff,const char * msg)92 static int ft_err(struct asfd *asfd,
93 struct conf **confs, struct FF_PKT *ff, const char *msg)
94 {
95 int raise_error;
96 const char *prefix="";
97 raise_error=get_int(confs[OPT_SCAN_PROBLEM_RAISES_ERROR]);
98 if(raise_error) prefix="Err: ";
99 if(logw(asfd, get_cntr(confs), "%s%s %s: %s\n", prefix, msg,
100 ff->fname, strerror(errno))) return -1;
101 if(raise_error) return -1;
102 return 0;
103 }
104
do_to_server(struct asfd * asfd,struct conf ** confs,struct FF_PKT * ff,struct sbuf * sb,enum cmd cmd,int compression)105 static int do_to_server(struct asfd *asfd,
106 struct conf **confs, struct FF_PKT *ff, struct sbuf *sb,
107 enum cmd cmd, int compression)
108 {
109 #ifdef HAVE_WIN32
110 int split_vss=0;
111 int strip_vss=0;
112 if(get_protocol(confs)==PROTO_1)
113 {
114 split_vss=get_int(confs[OPT_SPLIT_VSS]);
115 strip_vss=get_int(confs[OPT_STRIP_VSS]);
116 }
117 #endif
118 struct cntr *cntr=get_cntr(confs);
119 sb->compression=compression;
120 sb->encryption=encryption;
121 sb->statp=ff->statp;
122 sb->winattr=ff->winattr;
123 attribs_encode(sb);
124
125 #ifdef HAVE_WIN32
126 if(split_vss
127 && !strip_vss
128 && cmd!=CMD_EFS_FILE
129 && maybe_send_extrameta(asfd, ff->fname,
130 cmd, sb, cntr, metasymbol))
131 return -1;
132 #endif
133
134 if(usual_stuff(asfd, cntr, ff->fname, ff->link, sb, cmd)) return -1;
135
136 if(ff->type==FT_REG)
137 cntr_add_val(cntr, CMD_BYTES_ESTIMATED,
138 (uint64_t)ff->statp.st_size);
139 #ifdef HAVE_WIN32
140 if(split_vss
141 && !strip_vss
142 && cmd!=CMD_EFS_FILE
143 // FIX THIS: May have to check that it is not a directory here.
144 && !S_ISDIR(sb->statp.st_mode) // does this work?
145 && maybe_send_extrameta(asfd,
146 ff->fname, cmd, sb, cntr, vss_trail_symbol))
147 return -1;
148 return 0;
149 #else
150 return maybe_send_extrameta(asfd, ff->fname, cmd, sb,
151 cntr, metasymbol);
152 #endif
153 }
154
to_server(struct asfd * asfd,struct conf ** confs,struct FF_PKT * ff,struct sbuf * sb,enum cmd cmd)155 static int to_server(struct asfd *asfd, struct conf **confs, struct FF_PKT *ff,
156 struct sbuf *sb, enum cmd cmd)
157 {
158 return do_to_server(asfd, confs,
159 ff, sb, cmd, get_int(confs[OPT_COMPRESSION]));
160 }
161
my_send_file(struct asfd * asfd,struct FF_PKT * ff,struct conf ** confs)162 static int my_send_file(struct asfd *asfd, struct FF_PKT *ff, struct conf **confs)
163 {
164 static struct sbuf *sb=NULL;
165 struct cntr *cntr=get_cntr(confs);
166
167 if(!sb && !(sb=sbuf_alloc(get_protocol(confs)))) return -1;
168
169 #ifdef HAVE_WIN32
170 if(ff->winattr & FILE_ATTRIBUTE_ENCRYPTED)
171 {
172 if(ff->type==FT_REG
173 || ff->type==FT_DIR)
174 return to_server(asfd, confs, ff, sb, CMD_EFS_FILE);
175 return logw(asfd, cntr,
176 "EFS type %d not yet supported: %s\n",
177 ff->type, ff->fname);
178 }
179 #endif
180
181 switch(ff->type)
182 {
183 case FT_REG:
184 case FT_RAW:
185 case FT_FIFO:
186 return do_to_server(asfd, confs, ff, sb, filesymbol,
187 in_exclude_comp(get_strlist(confs[OPT_EXCOM]),
188 ff->fname, get_int(confs[OPT_COMPRESSION])));
189 case FT_DIR:
190 case FT_REPARSE:
191 case FT_JUNCTION:
192 return to_server(asfd, confs, ff, sb, dirsymbol);
193 case FT_LNK_S:
194 return to_server(asfd, confs, ff, sb, CMD_SOFT_LINK);
195 case FT_LNK_H:
196 return to_server(asfd, confs, ff, sb, CMD_HARD_LINK);
197 case FT_SPEC:
198 return to_server(asfd, confs, ff, sb, CMD_SPECIAL);
199 case FT_NOFSCHG:
200 return ft_err(asfd, confs, ff, "Will not descend: "
201 "file system change not allowed");
202 case FT_NOFOLLOW:
203 return ft_err(asfd, confs, ff, "Could not follow link");
204 case FT_NOSTAT:
205 return ft_err(asfd, confs, ff, "Could not stat");
206 case FT_NOOPEN:
207 return ft_err(asfd, confs, ff, "Could not open directory");
208 default:
209 return logw(asfd, cntr,
210 "Err: Unknown file type %d: %s\n",
211 ff->type, ff->fname);
212 }
213 }
214
backup_phase1_client(struct asfd * asfd,struct conf ** confs)215 int backup_phase1_client(struct asfd *asfd, struct conf **confs)
216 {
217 int ret=-1;
218 struct FF_PKT *ff=NULL;
219 struct strlist *l=NULL;
220 enable_acl=get_int(confs[OPT_ACL]);
221 enable_xattr=get_int(confs[OPT_XATTR]);
222
223 // First, tell the server about everything that needs to be backed up.
224
225 logp("Phase 1 begin (file system scan)\n");
226
227 // Encryption not yet supported in protocol2.
228 if(get_protocol(confs)==PROTO_1
229 && get_string(confs[OPT_ENCRYPTION_PASSWORD]))
230 {
231 encryption=ENCRYPTION_KEY_DERIVED;
232 filesymbol=CMD_ENC_FILE;
233 metasymbol=CMD_ENC_METADATA;
234 #ifdef HAVE_WIN32
235 metasymbol=CMD_ENC_VSS;
236 vss_trail_symbol=CMD_ENC_VSS_T;
237 #endif
238 }
239 #ifdef HAVE_WIN32
240 dirsymbol=filesymbol;
241 if(get_protocol(confs)==PROTO_1
242 && get_int(confs[OPT_STRIP_VSS]))
243 dirsymbol=CMD_DIRECTORY;
244 #endif
245
246 if(!(ff=find_files_init(my_send_file))) goto end;
247 for(l=get_strlist(confs[OPT_STARTDIR]); l; l=l->next) if(l->flag)
248 if(find_files_begin(asfd, ff, confs, l->path)) goto end;
249 ret=0;
250 end:
251 cntr_print_end_phase1(get_cntr(confs));
252 if(ret) logp("Error in phase 1\n");
253 logp("Phase 1 end (file system scan)\n");
254 find_files_free(&ff);
255
256 return ret;
257 }
258