2 Bacula(R) - The Network Backup Solution
4 Copyright (C) 2000-2017 Kern Sibbald
6 The original author of Bacula is Kern Sibbald, with contributions
7 from many others, a complete list can be found in the file AUTHORS.
9 You may use this file and others of this release according to the
10 license defined in the LICENSE file, which includes the Affero General
11 Public License, v3.0 ("AGPLv3") and some additional permissions and
12 terms pursuant to its AGPLv3 Section 7.
14 This notice must be preserved when any source code is
15 conveyed and/or propagated.
17 Bacula(R) is a registered trademark of Kern Sibbald.
20 * Encode and decode standard Unix attributes and
21 * Extended attributes for Win32 and
22 * other non-Unix systems, or Unix systems with ACLs, ...
24 * Kern Sibbald, October MMII
28 //#define _POSIX_C_SOURCE 200809L
29 //#define _BSD_SOURCE 1
35 static uid_t my_uid = 1;
36 static gid_t my_gid = 1;
37 static bool uid_set = false;
40 * For old systems that don't have lchown() or lchmod()
49 /*=============================================================*/
51 /* *** A l l S y s t e m s *** */
53 /*=============================================================*/
56 * To turn off use of fchown(), fchmod(), or futimes(),
57 * uncomment one or more of the following.
64 * Print errors only if debug level defined or we are root.
65 * root should not get errors. Errors for users causes
68 #define print_error (chk_dbglvl(100) || my_uid == 0)
70 bool set_mod_own_time(JCR *jcr, BFILE *ofd, ATTR *attr)
75 /* Do not try to set rights with f functions when using a plugin */
76 if (is_bopen(ofd) && !ofd->cmd_plugin) { /* TODO: Look with opt_plugin */
78 * The #ifdefing is a bit ugly, but it is the only
79 * way we can ensure this works on older systems.
82 if (fchown(ofd->fid, attr->statp.st_uid, attr->statp.st_gid) < 0 && print_error) {
84 if (lchown(attr->ofname, attr->statp.st_uid, attr->statp.st_gid) < 0 && print_error) {
87 Jmsg2(jcr, M_ERROR, 0, _("Unable to set file owner %s: ERR=%s\n"),
88 attr->ofname, be.bstrerror());
93 if (fchmod(ofd->fid, attr->statp.st_mode) < 0 && print_error) {
95 if (lchmod(attr->ofname, attr->statp.st_mode) < 0 && print_error) {
98 Jmsg2(jcr, M_ERROR, 0, _("Unable to set file modes %s: ERR=%s\n"),
99 attr->ofname, be.bstrerror());
104 struct timeval times[2];
105 times[0].tv_sec = attr->statp.st_atime;
106 times[0].tv_usec = 0;
107 times[1].tv_sec = attr->statp.st_mtime;
108 times[1].tv_usec = 0;
109 if (futimes(ofd->fid, times) < 0 && print_error) {
111 ut.actime = attr->statp.st_atime;
112 ut.modtime = attr->statp.st_mtime;
114 if (utime(attr->ofname, &ut) < 0 && print_error) {
117 Jmsg2(jcr, M_ERROR, 0, _("Unable to set file times %s: ERR=%s\n"),
118 attr->ofname, be.bstrerror());
122 if (lchown(attr->ofname, attr->statp.st_uid, attr->statp.st_gid) < 0 && print_error) {
124 Jmsg2(jcr, M_ERROR, 0, _("Unable to set file owner %s: ERR=%s\n"),
125 attr->ofname, be.bstrerror());
128 if (lchmod(attr->ofname, attr->statp.st_mode) < 0 && print_error) {
130 Jmsg2(jcr, M_ERROR, 0, _("Unable to set file modes %s: ERR=%s\n"),
131 attr->ofname, be.bstrerror());
137 ut.actime = attr->statp.st_atime;
138 ut.modtime = attr->statp.st_mtime;
140 if (utime(attr->ofname, &ut) < 0 && print_error) {
142 Jmsg2(jcr, M_ERROR, 0, _("Unable to set file times %s: ERR=%s\n"),
143 attr->ofname, be.bstrerror());
151 * Return the data stream that will be used
153 int select_data_stream(FF_PKT *ff_pkt)
157 /* This is a plugin special restore object */
158 if (ff_pkt->type == FT_RESTORE_FIRST) {
160 return STREAM_FILE_DATA;
164 * Fix all incompatible options
166 /* No sparse option for encrypted data */
167 if (ff_pkt->flags & FO_ENCRYPT) {
168 ff_pkt->flags &= ~FO_SPARSE;
171 /* Note, no sparse option for win32_data */
172 if (!is_portable_backup(&ff_pkt->bfd)) {
173 stream = STREAM_WIN32_DATA;
174 ff_pkt->flags &= ~FO_SPARSE;
175 } else if (ff_pkt->flags & FO_SPARSE) {
176 stream = STREAM_SPARSE_DATA;
178 stream = STREAM_FILE_DATA;
180 if (ff_pkt->flags & FO_OFFSETS) {
181 stream = STREAM_SPARSE_DATA;
184 /* Encryption is only supported for file data */
185 if (stream != STREAM_FILE_DATA && stream != STREAM_WIN32_DATA &&
186 stream != STREAM_MACOS_FORK_DATA) {
187 ff_pkt->flags &= ~FO_ENCRYPT;
190 /* Compression is not supported for Mac fork data */
191 if (stream == STREAM_MACOS_FORK_DATA) {
192 ff_pkt->flags &= ~FO_COMPRESS;
196 * Handle compression and encryption options
198 #if defined(HAVE_LIBZ) || defined(HAVE_LZO)
199 if (ff_pkt->flags & FO_COMPRESS) {
201 if(ff_pkt->Compress_algo == COMPRESS_GZIP) {
203 case STREAM_WIN32_DATA:
204 stream = STREAM_WIN32_GZIP_DATA;
206 case STREAM_SPARSE_DATA:
207 stream = STREAM_SPARSE_GZIP_DATA;
209 case STREAM_FILE_DATA:
210 stream = STREAM_GZIP_DATA;
214 * All stream types that do not support compression should clear out
215 * FO_COMPRESS above, and this code block should be unreachable.
217 ASSERT(!(ff_pkt->flags & FO_COMPRESS));
223 if(ff_pkt->Compress_algo == COMPRESS_LZO1X) {
225 case STREAM_WIN32_DATA:
226 stream = STREAM_WIN32_COMPRESSED_DATA;
228 case STREAM_SPARSE_DATA:
229 stream = STREAM_SPARSE_COMPRESSED_DATA;
231 case STREAM_FILE_DATA:
232 stream = STREAM_COMPRESSED_DATA;
236 * All stream types that do not support compression should clear out
237 * FO_COMPRESS above, and this code block should be unreachable.
239 ASSERT(!(ff_pkt->flags & FO_COMPRESS));
247 if (ff_pkt->flags & FO_ENCRYPT) {
249 case STREAM_WIN32_DATA:
250 stream = STREAM_ENCRYPTED_WIN32_DATA;
252 case STREAM_WIN32_GZIP_DATA:
253 stream = STREAM_ENCRYPTED_WIN32_GZIP_DATA;
255 case STREAM_WIN32_COMPRESSED_DATA:
256 stream = STREAM_ENCRYPTED_WIN32_COMPRESSED_DATA;
258 case STREAM_FILE_DATA:
259 stream = STREAM_ENCRYPTED_FILE_DATA;
261 case STREAM_GZIP_DATA:
262 stream = STREAM_ENCRYPTED_FILE_GZIP_DATA;
264 case STREAM_COMPRESSED_DATA:
265 stream = STREAM_ENCRYPTED_FILE_COMPRESSED_DATA;
268 /* All stream types that do not support encryption should clear out
269 * FO_ENCRYPT above, and this code block should be unreachable. */
270 ASSERT(!(ff_pkt->flags & FO_ENCRYPT));
281 * Encode a stat structure into a base64 character string
282 * All systems must create such a structure.
283 * In addition, we tack on the LinkFI, which is non-zero in
284 * the case of a hard linked file that has no data. This
285 * is a File Index pointing to the link that does have the
286 * data (always the first one encountered in a save).
287 * You may piggyback attributes on this packet by encoding
288 * them in the encode_attribsEx() subroutine, but this is
291 void encode_stat(char *buf, struct stat *statp, int stat_size, int32_t LinkFI, int data_stream)
295 * We read the stat packet so make sure the caller's conception
296 * is the same as ours. They can be different if LARGEFILE is not
297 * the same when compiling this library and the calling program.
299 ASSERT(stat_size == (int)sizeof(struct stat));
302 * Encode a stat packet. I should have done this more intelligently
303 * with a length so that it could be easily expanded.
305 p += to_base64((int64_t)statp->st_dev, p);
306 *p++ = ' '; /* separate fields with a space */
307 p += to_base64((int64_t)statp->st_ino, p);
309 p += to_base64((int64_t)statp->st_mode, p);
311 p += to_base64((int64_t)statp->st_nlink, p);
313 p += to_base64((int64_t)statp->st_uid, p);
315 p += to_base64((int64_t)statp->st_gid, p);
317 p += to_base64((int64_t)statp->st_rdev, p);
319 p += to_base64((int64_t)statp->st_size, p);
322 p += to_base64((int64_t)statp->st_blksize, p);
324 p += to_base64((int64_t)statp->st_blocks, p);
327 p += to_base64((int64_t)0, p); /* output place holder */
329 p += to_base64((int64_t)0, p); /* output place holder */
332 p += to_base64((int64_t)statp->st_atime, p);
334 p += to_base64((int64_t)statp->st_mtime, p);
336 p += to_base64((int64_t)statp->st_ctime, p);
338 p += to_base64((int64_t)LinkFI, p);
342 /* FreeBSD function */
343 p += to_base64((int64_t)statp->st_flags, p); /* output st_flags */
345 p += to_base64((int64_t)0, p); /* output place holder */
348 p += to_base64((int64_t)data_stream, p);
351 p += to_base64((int64_t)statp->st_fattrs, p);
357 /* Do casting according to unknown type to keep compiler happy */
359 #define plug(st, val) st = (typeof st)val
361 #if !HAVE_GCC & HAVE_SUN_OS
362 /* Sun compiler does not handle templates correctly */
363 #define plug(st, val) st = val
365 #define plug(st, val) st = val
367 /* Use templates to do the casting */
368 template <class T> void plug(T &st, uint64_t val)
369 { st = static_cast<T>(val); }
375 * Decode a stat packet from base64 characters
376 * returns: data_stream
378 int decode_stat(char *buf, struct stat *statp, int stat_size, int32_t *LinkFI)
385 * We store into the stat packet so make sure the caller's conception
386 * is the same as ours. They can be different if LARGEFILE is not
387 * the same when compiling this library and the calling program.
389 ASSERT(stat_size == (int)sizeof(struct stat));
391 p += from_base64(&val, p);
392 plug(statp->st_dev, val);
394 p += from_base64(&val, p);
395 plug(statp->st_ino, val);
397 p += from_base64(&val, p);
398 plug(statp->st_mode, val);
400 p += from_base64(&val, p);
401 plug(statp->st_nlink, val);
403 p += from_base64(&val, p);
404 plug(statp->st_uid, val);
406 p += from_base64(&val, p);
407 plug(statp->st_gid, val);
409 p += from_base64(&val, p);
410 plug(statp->st_rdev, val);
412 p += from_base64(&val, p);
413 plug(statp->st_size, val);
416 p += from_base64(&val, p);
417 plug(statp->st_blksize, val);
419 p += from_base64(&val, p);
420 plug(statp->st_blocks, val);
423 p += from_base64(&val, p);
424 // plug(statp->st_blksize, val);
426 p += from_base64(&val, p);
427 // plug(statp->st_blocks, val);
430 p += from_base64(&val, p);
431 plug(statp->st_atime, val);
433 p += from_base64(&val, p);
434 plug(statp->st_mtime, val);
436 p += from_base64(&val, p);
437 plug(statp->st_ctime, val);
439 /* Optional FileIndex of hard linked file data */
440 if (*p == ' ' || (*p != 0 && *(p+1) == ' ')) {
442 p += from_base64(&val, p);
443 *LinkFI = (uint32_t)val;
449 /* FreeBSD user flags */
450 if (*p == ' ' || (*p != 0 && *(p+1) == ' ')) {
452 p += from_base64(&val, p);
454 plug(statp->st_flags, val);
460 /* Look for data stream id */
461 if (*p == ' ' || (*p != 0 && *(p+1) == ' ')) {
463 p += from_base64(&val, p);
469 if (*p == ' ' || (*p != 0 && *(p+1) == ' ')) {
471 p += from_base64(&val, p);
472 plug(statp->st_fattrs, val);
474 statp->st_fattrs = 0;
481 /* Decode a LinkFI field of encoded stat packet */
482 int32_t decode_LinkFI(char *buf, struct stat *statp, int stat_size)
487 * We store into the stat packet so make sure the caller's conception
488 * is the same as ours. They can be different if LARGEFILE is not
489 * the same when compiling this library and the calling program.
491 ASSERT(stat_size == (int)sizeof(struct stat));
493 skip_nonspaces(&p); /* st_dev */
494 p++; /* skip space */
495 skip_nonspaces(&p); /* st_ino */
497 p += from_base64(&val, p);
498 plug(statp->st_mode, val); /* st_mode */
500 skip_nonspaces(&p); /* st_nlink */
502 skip_nonspaces(&p); /* st_uid */
504 skip_nonspaces(&p); /* st_gid */
506 skip_nonspaces(&p); /* st_rdev */
508 skip_nonspaces(&p); /* st_size */
510 skip_nonspaces(&p); /* st_blksize */
512 skip_nonspaces(&p); /* st_blocks */
514 skip_nonspaces(&p); /* st_atime */
516 skip_nonspaces(&p); /* st_mtime */
518 skip_nonspaces(&p); /* st_ctime */
520 /* Optional FileIndex of hard linked file data */
521 if (*p == ' ' || (*p != 0 && *(p+1) == ' ')) {
523 p += from_base64(&val, p);
530 * Set file modes, permissions and times
532 * fname is the original filename
533 * ofile is the output filename (may be in a different directory)
535 * Returns: true on success
538 bool set_attributes(JCR *jcr, ATTR *attr, BFILE *ofd)
552 char ec1[50], ec2[50];
553 fsize = blseek(ofd, 0, SEEK_END);
554 if (attr->type == FT_REG && fsize > 0 && attr->statp.st_size > 0 &&
555 fsize != (boffset_t)attr->statp.st_size) {
556 Jmsg3(jcr, M_ERROR, 0, _("File size of restored file %s not correct. Original %s, restored %s.\n"),
557 attr->ofname, edit_uint64(attr->statp.st_size, ec1),
558 edit_uint64(fsize, ec2));
563 * We do not restore sockets, so skip trying to restore their
566 if (attr->type == FT_SPEC && S_ISSOCK(attr->statp.st_mode)) {
570 /* ***FIXME**** optimize -- don't do if already correct */
572 * For link, change owner of link using lchown, but don't
573 * try to do a chmod as that will update the file behind it.
575 if (attr->type == FT_LNK) {
577 /* Change owner of link, not of real file */
578 if (lchown(attr->ofname, attr->statp.st_uid, attr->statp.st_gid) < 0 && print_error) {
580 Jmsg2(jcr, M_ERROR, 0, _("Unable to set file owner %s: ERR=%s\n"),
581 attr->ofname, be.bstrerror());
586 struct timeval times[2];
587 times[0].tv_sec = attr->statp.st_atime;
588 times[0].tv_usec = 0;
589 times[1].tv_sec = attr->statp.st_mtime;
590 times[1].tv_usec = 0;
591 if (lutimes(attr->ofname, times) < 0 && print_error) {
593 Jmsg2(jcr, M_ERROR, 0, _("Unable to set file times %s: ERR=%s\n"),
594 attr->ofname, be.bstrerror());
600 * At this point, we have a file that is not a LINK
602 ok = set_mod_own_time(jcr, ofd, attr);
608 * Note, this should really be done before the utime() above,
609 * but if the immutable bit is set, it will make the utimes()
612 if (chflags(attr->ofname, attr->statp.st_flags) < 0 && print_error) {
614 Jmsg2(jcr, M_ERROR, 0, _("Unable to set file flags %s: ERR=%s\n"),
615 attr->ofname, be.bstrerror());
625 pm_strcpy(attr->ofname, "*none*");
631 /*=============================================================*/
633 /* * * * U n i x * * * * */
635 /*=============================================================*/
640 * It is possible to piggyback additional data e.g. ACLs on
641 * the encode_stat() data by returning the extended attributes
642 * here. They must be "self-contained" (i.e. you keep track
643 * of your own length), and they must be in ASCII string
644 * format. Using this feature is not recommended.
645 * The code below shows how to return nothing. See the Win32
646 * code below for returning something in the attributes.
648 int encode_attribsEx(JCR *jcr, char *attribsEx, FF_PKT *ff_pkt)
650 #ifdef HAVE_DARWIN_OS
652 * We save the Mac resource fork length so that on a
653 * restore, we can be sure we put back the whole resource.
657 *attribsEx = 0; /* no extended attributes (yet) */
658 if (jcr->cmd_plugin || ff_pkt->type == FT_DELETED) {
659 return STREAM_UNIX_ATTRIBUTES;
662 if (ff_pkt->flags & FO_HFSPLUS) {
663 p += to_base64((uint64_t)(ff_pkt->hfsinfo.rsrclength), p);
667 *attribsEx = 0; /* no extended attributes */
669 return STREAM_UNIX_ATTRIBUTES;