Line data Source code
1 : /*
2 : Bacula® - The Network Backup Solution
3 :
4 : Copyright (C) 2002-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 : * Encode and decode standard Unix attributes and
30 : * Extended attributes for Win32 and
31 : * other non-Unix systems, ...
32 : */
33 : /*
34 : * Some of these functions come from src/findlib/attribs.c in bacula-5.0.3.
35 : * Hence, the copyright notice above is retained.
36 : * Graham Keeling, 2014
37 : */
38 :
39 : #include "burp.h"
40 : #include "attribs.h"
41 : #include "alloc.h"
42 : #include "base64.h"
43 : #include "berrno.h"
44 : #include "cmd.h"
45 : #include "cntr.h"
46 : #include "log.h"
47 : #include "sbuf.h"
48 :
49 : // Encode a stat structure into a base64 character string.
50 95379 : int attribs_encode(struct sbuf *sb)
51 : {
52 : static char *p;
53 : static struct stat *statp;
54 :
55 95379 : if(!sb->attr.buf)
56 : {
57 95254 : sb->attr.cmd=CMD_ATTRIBS; // should not be needed
58 95254 : if(!(sb->attr.buf=(char *)malloc_w(256, __func__)))
59 : return -1;
60 : }
61 95379 : p=sb->attr.buf;
62 95379 : statp=&sb->statp;
63 :
64 95379 : if(sb->protocol2)
65 : {
66 : // Protocol1 does not have this field.
67 73445 : p += to_base64(sb->protocol2->index, p);
68 73445 : *p++ = ' ';
69 : // Protocol2 puts compression/encryption near the beginning.
70 73445 : p += to_base64(sb->compression, p);
71 73445 : *p++ = ' ';
72 73445 : p += to_base64(sb->encryption, p);
73 73445 : *p++ = ' ';
74 : }
75 95379 : p += to_base64(statp->st_dev, p);
76 95379 : *p++ = ' ';
77 95379 : p += to_base64(statp->st_ino, p);
78 95379 : *p++ = ' ';
79 95379 : p += to_base64(statp->st_mode, p);
80 95379 : *p++ = ' ';
81 95379 : p += to_base64(statp->st_nlink, p);
82 95379 : *p++ = ' ';
83 95379 : p += to_base64(statp->st_uid, p);
84 95379 : *p++ = ' ';
85 95379 : p += to_base64(statp->st_gid, p);
86 95379 : *p++ = ' ';
87 95379 : p += to_base64(statp->st_rdev, p);
88 95379 : *p++ = ' ';
89 95379 : p += to_base64(statp->st_size, p);
90 95379 : *p++ = ' ';
91 : #ifdef HAVE_WIN32
92 : p += to_base64(0, p); // place holder
93 : *p++ = ' ';
94 : p += to_base64(0, p); // place holder
95 : #else
96 95379 : p += to_base64(statp->st_blksize, p);
97 95379 : *p++ = ' ';
98 95379 : p += to_base64(statp->st_blocks, p);
99 : #endif
100 95379 : *p++ = ' ';
101 95379 : p += to_base64(statp->st_atime, p);
102 95379 : *p++ = ' ';
103 95379 : p += to_base64(statp->st_mtime, p);
104 95379 : *p++ = ' ';
105 95379 : p += to_base64(statp->st_ctime, p);
106 95379 : *p++ = ' ';
107 :
108 : #ifdef HAVE_CHFLAGS
109 : // chflags is a FreeBSD function.
110 : p += to_base64(statp->st_flags, p);
111 : #else
112 95379 : p += to_base64(0, p); // place holder
113 : #endif
114 95379 : *p++ = ' ';
115 :
116 95379 : p += to_base64(sb->winattr, p);
117 :
118 95379 : if(sb->protocol1)
119 : {
120 : // Protocol1 puts compression/encryption at the end.
121 21934 : *p++ = ' ';
122 21934 : p += to_base64(sb->compression, p);
123 21934 : *p++ = ' ';
124 21934 : p += to_base64(sb->encryption, p);
125 21934 : *p++ = ' ';
126 21934 : p += to_base64(sb->protocol1->salt, p);
127 : }
128 :
129 95379 : *p = 0;
130 :
131 95379 : sb->attr.len=p-sb->attr.buf;
132 :
133 95379 : return 0;
134 : }
135 :
136 : // Do casting according to unknown type to keep compiler happy.
137 : #define plug(st, val) st = (__typeof__(st))(val)
138 :
139 : // Decode a stat packet from base64 characters.
140 80764 : void attribs_decode(struct sbuf *sb)
141 : {
142 : static const char *p;
143 : static int64_t val;
144 : static struct stat *statp;
145 : static int eaten;
146 :
147 80764 : if(!(p=sb->attr.buf)) return;
148 80764 : statp=&sb->statp;
149 :
150 80764 : if(sb->protocol2)
151 : {
152 : // In protocol2, the first component (index) sometimes gets
153 : // stripped off of the attributes, so look out for that.
154 57098 : if(*p!=' ')
155 : {
156 : // Protocol1 does not have this field.
157 10024 : if(!(eaten=from_base64(&val, p)))
158 : return;
159 10024 : p+=eaten;
160 10024 : sb->protocol2->index=val;
161 : }
162 :
163 : // Compression for protocol2.
164 57098 : if(!(eaten=from_base64(&val, p)))
165 : return;
166 57098 : p+=eaten;
167 57098 : sb->compression=val;
168 :
169 : // Encryption for protocol2.
170 57098 : if(!(eaten=from_base64(&val, p)))
171 : return;
172 57097 : p+=eaten;
173 57097 : sb->encryption=val;
174 : }
175 :
176 80763 : if(!(eaten=from_base64(&val, p)))
177 : return;
178 80753 : p+=eaten;
179 80753 : plug(statp->st_dev, val);
180 :
181 80753 : if(!(eaten=from_base64(&val, p)))
182 : return;
183 80752 : p+=eaten;
184 80752 : plug(statp->st_ino, val);
185 :
186 80752 : if(!(eaten=from_base64(&val, p)))
187 : return;
188 80743 : p+=eaten;
189 80743 : plug(statp->st_mode, val);
190 :
191 80743 : if(!(eaten=from_base64(&val, p)))
192 : return;
193 80743 : p+=eaten;
194 80743 : plug(statp->st_nlink, val);
195 :
196 80743 : if(!(eaten=from_base64(&val, p)))
197 : return;
198 80743 : p+=eaten;
199 80743 : plug(statp->st_uid, val);
200 :
201 80743 : if(!(eaten=from_base64(&val, p)))
202 : return;
203 80743 : p+=eaten;
204 80743 : plug(statp->st_gid, val);
205 :
206 80743 : if(!(eaten=from_base64(&val, p)))
207 : return;
208 80743 : p+=eaten;
209 80743 : plug(statp->st_rdev, val);
210 :
211 80743 : if(!(eaten=from_base64(&val, p)))
212 : return;
213 80743 : p+=eaten;
214 80743 : plug(statp->st_size, val);
215 :
216 80743 : if(!(eaten=from_base64(&val, p)))
217 : return;
218 80743 : p+=eaten;
219 : #ifdef HAVE_WIN32
220 : // plug(statp->st_blksize, val);
221 :
222 : if(!(eaten=from_base64(&val, p)))
223 : return;
224 : p+=eaten;
225 : // plug(statp->st_blocks, val);
226 : #else
227 80743 : plug(statp->st_blksize, val);
228 :
229 80743 : if(!(eaten=from_base64(&val, p)))
230 : return;
231 80743 : p+=eaten;
232 80743 : plug(statp->st_blocks, val);
233 : #endif
234 :
235 80743 : if(!(eaten=from_base64(&val, p)))
236 : return;
237 80743 : p+=eaten;
238 80743 : plug(statp->st_atime, val);
239 :
240 80743 : if(!(eaten=from_base64(&val, p)))
241 : return;
242 80743 : p+=eaten;
243 80743 : plug(statp->st_mtime, val);
244 :
245 80743 : if(!(eaten=from_base64(&val, p)))
246 : return;
247 80743 : p+=eaten;
248 80743 : plug(statp->st_ctime, val);
249 :
250 : // FreeBSD user flags.
251 80743 : if(!(eaten=from_base64(&val, p)))
252 : return;
253 80743 : p+=eaten;
254 : #ifdef HAVE_CHFLAGS
255 : statp->st_flags=0;
256 : plug(statp->st_flags, val);
257 : #endif
258 :
259 : // Look for winattr.
260 80743 : sb->winattr=0;
261 80743 : if(!(eaten=from_base64(&val, p)))
262 : return;
263 80743 : p+=eaten;
264 80743 : sb->winattr=val;
265 :
266 80743 : if(sb->protocol1)
267 : {
268 23656 : sb->compression=-1;
269 23656 : sb->encryption=ENCRYPTION_UNSET;
270 :
271 : // Compression for protocol1.
272 23656 : if(!(eaten=from_base64(&val, p)))
273 : return;
274 23656 : p+=eaten;
275 23656 : sb->compression=val;
276 :
277 : // Encryption for protocol1.
278 23656 : if(!(eaten=from_base64(&val, p)))
279 : return;
280 23656 : p+=eaten;
281 23656 : sb->encryption=val;
282 :
283 : // Salt for protocol1.
284 23656 : if(!(eaten=from_base64(&val, p)))
285 : return;
286 23656 : p+=eaten;
287 23656 : sb->protocol1->salt=val;
288 : }
289 : }
290 :
291 28 : int attribs_set_file_times(struct asfd *asfd,
292 : const char *path, struct stat *statp,
293 : struct cntr *cntr)
294 : {
295 : int e;
296 :
297 : #ifdef HAVE_WIN32
298 : // You (probably) cannot set times on Windows junction points.
299 : if(statp->st_rdev==WIN32_JUNCTION_POINT)
300 : return 0;
301 :
302 : // The mingw64 utime() appears not to work on read-only files.
303 : // Use the utime() from bacula instead.
304 : e=win32_utime(path, statp);
305 : #elif HAVE_LUTIMES
306 : struct timeval t[2];
307 28 : t[0].tv_sec = statp->st_atime;
308 28 : t[0].tv_usec = 0;
309 28 : t[1].tv_sec = statp->st_mtime;
310 28 : t[1].tv_usec = 0;
311 28 : e=lutimes(path, t);
312 : #else
313 : struct timespec ts[2];
314 : ts[0].tv_sec=statp->st_atime;
315 : ts[0].tv_nsec=0;
316 : ts[1].tv_sec=statp->st_mtime;
317 : ts[1].tv_nsec=0;
318 : e=utimensat(AT_FDCWD, path, ts, AT_SYMLINK_NOFOLLOW);
319 : #endif
320 28 : if(e<0)
321 : {
322 : struct berrno be;
323 0 : berrno_init(&be);
324 0 : logw(asfd, cntr, "Unable to set file times %s: ERR=%s\n",
325 0 : path, berrno_bstrerror(&be, errno));
326 : return -1;
327 : }
328 : return 0;
329 : }
330 :
331 17034 : uint64_t decode_file_no(struct iobuf *iobuf)
332 : {
333 17034 : int64_t val=0;
334 17034 : from_base64(&val, iobuf->buf);
335 17034 : return (uint64_t)val;
336 : }
337 :
338 0 : uint64_t decode_file_no_and_save_path(struct iobuf *iobuf, char **save_path)
339 : {
340 : int64_t val;
341 : int eaten;
342 0 : char *p=iobuf->buf;
343 0 : if(!(eaten=from_base64(&val, iobuf->buf)))
344 : return 0;
345 0 : *save_path=p+eaten+1;
346 0 : return (uint64_t)val;
347 : }
348 :
349 28 : int attribs_set(struct asfd *asfd, const char *path,
350 : struct stat *statp, uint64_t winattr, struct cntr *cntr)
351 : {
352 : #ifdef HAVE_WIN32
353 : win32_chmod(path, statp->st_mode, winattr);
354 : attribs_set_file_times(asfd, path, statp, cntr);
355 : return 0;
356 : #endif
357 :
358 28 : if(lchown(path, statp->st_uid, statp->st_gid)<0)
359 : {
360 : struct berrno be;
361 0 : berrno_init(&be);
362 0 : char msg[256]="";
363 :
364 0 : snprintf(msg, sizeof(msg),
365 : "Unable to set file owner of %s to %d:%d: ERR=%s",
366 : path, statp->st_uid, statp->st_gid,
367 0 : berrno_bstrerror(&be, errno));
368 :
369 0 : if(errno==EPERM)
370 : {
371 : static int do_owner_warning=1;
372 0 : if(getuid()!=0)
373 : {
374 0 : if(!do_owner_warning)
375 : return -1;
376 :
377 0 : logw(asfd, cntr, "%s - possibly because you are not root. Will suppress subsequent messages of this type.\n", msg);
378 0 : do_owner_warning=0;
379 0 : return -1;
380 : }
381 : }
382 0 : logw(asfd, cntr, "%s\n", msg);
383 :
384 0 : return -1;
385 : }
386 :
387 : /* Watch out, a metadata restore will have cmd set to CMD_METADATA or
388 : CMD_ENC_META, but that is OK at the moment because we are not doing
389 : meta stuff on links. */
390 28 : if(S_ISLNK(statp->st_mode))
391 : {
392 0 : if(attribs_set_file_times(asfd, path, statp, cntr))
393 : return -1;
394 : }
395 : else
396 : {
397 28 : if(chmod(path, statp->st_mode) < 0)
398 : {
399 : struct berrno be;
400 0 : berrno_init(&be);
401 0 : logw(asfd, cntr,
402 : "Unable to set file modes %s: ERR=%s\n",
403 0 : path, berrno_bstrerror(&be, errno));
404 : return -1;
405 : }
406 :
407 28 : if(attribs_set_file_times(asfd, path, statp, cntr))
408 : return -1;
409 : #ifdef HAVE_CHFLAGS
410 : /*
411 : * FreeBSD user flags
412 : *
413 : * Note, this should really be done before the utime() above,
414 : * but if the immutable bit is set, it will make the utimes()
415 : * fail.
416 : */
417 : if(chflags(path, statp->st_flags)<0)
418 : {
419 : struct berrno be;
420 : berrno_init(&be);
421 : logw(asfd, cntr,
422 : "Unable to set file flags %s: ERR=%s\n",
423 : path, berrno_bstrerror(&be, errno));
424 : return -1;
425 : }
426 : #endif
427 : }
428 :
429 : return 0;
430 : }
|