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