2 Bacula(R) - The Network Backup Solution
4 Copyright (C) 2000-2015 Kern Sibbald
5 Copyright (C) 2002-2014 Free Software Foundation Europe e.V.
7 The original author of Bacula is Kern Sibbald, with contributions
8 from many others, a complete list can be found in the file AUTHORS.
10 You may use this file and others of this release according to the
11 license defined in the LICENSE file, which includes the Affero General
12 Public License, v3.0 ("AGPLv3") and some additional permissions and
13 terms pursuant to its AGPLv3 Section 7.
15 This notice must be preserved when any source code is
16 conveyed and/or propagated.
18 Bacula(R) is a registered trademark of Kern Sibbald.
21 * Encode and decode standard Unix attributes and
22 * Extended attributes for Win32 and
23 * other non-Unix systems, or Unix systems with ACLs, ...
25 * Kern Sibbald, October MMII
29 //#define _POSIX_C_SOURCE 200809L
30 //#define _BSD_SOURCE 1
36 static uid_t my_uid = 1;
37 static gid_t my_gid = 1;
38 static bool uid_set = false;
41 * For old systems that don't have lchown() or lchmod()
50 /*=============================================================*/
52 /* *** A l l S y s t e m s *** */
54 /*=============================================================*/
57 * To turn off use of fchown(), fchmod(), or futimes(),
58 * uncomment one or more of the following.
65 * Print errors only if debug level defined or we are root.
66 * root should not get errors. Errors for users causes
69 #define print_error (chk_dbglvl(100) || my_uid == 0)
71 bool set_mod_own_time(JCR *jcr, BFILE *ofd, ATTR *attr)
76 /* Do not try to set rights with f functions when using a plugin */
77 if (is_bopen(ofd) && !ofd->cmd_plugin) { /* TODO: Look with opt_plugin */
79 * The #ifdefing is a bit ugly, but it is the only
80 * way we can ensure this works on older systems.
83 if (fchown(ofd->fid, attr->statp.st_uid, attr->statp.st_gid) < 0 && print_error) {
85 if (lchown(attr->ofname, attr->statp.st_uid, attr->statp.st_gid) < 0 && print_error) {
88 Jmsg2(jcr, M_ERROR, 0, _("Unable to set file owner %s: ERR=%s\n"),
89 attr->ofname, be.bstrerror());
94 if (fchmod(ofd->fid, attr->statp.st_mode) < 0 && print_error) {
96 if (lchmod(attr->ofname, attr->statp.st_mode) < 0 && print_error) {
99 Jmsg2(jcr, M_ERROR, 0, _("Unable to set file modes %s: ERR=%s\n"),
100 attr->ofname, be.bstrerror());
105 struct timeval times[2];
106 times[0].tv_sec = attr->statp.st_atime;
107 times[0].tv_usec = 0;
108 times[1].tv_sec = attr->statp.st_mtime;
109 times[1].tv_usec = 0;
110 if (futimes(ofd->fid, times) < 0 && print_error) {
112 ut.actime = attr->statp.st_atime;
113 ut.modtime = attr->statp.st_mtime;
115 if (utime(attr->ofname, &ut) < 0 && print_error) {
118 Jmsg2(jcr, M_ERROR, 0, _("Unable to set file times %s: ERR=%s\n"),
119 attr->ofname, be.bstrerror());
123 if (lchown(attr->ofname, attr->statp.st_uid, attr->statp.st_gid) < 0 && print_error) {
125 Jmsg2(jcr, M_ERROR, 0, _("Unable to set file owner %s: ERR=%s\n"),
126 attr->ofname, be.bstrerror());
129 if (lchmod(attr->ofname, attr->statp.st_mode) < 0 && print_error) {
131 Jmsg2(jcr, M_ERROR, 0, _("Unable to set file modes %s: ERR=%s\n"),
132 attr->ofname, be.bstrerror());
138 ut.actime = attr->statp.st_atime;
139 ut.modtime = attr->statp.st_mtime;
141 if (utime(attr->ofname, &ut) < 0 && print_error) {
143 Jmsg2(jcr, M_ERROR, 0, _("Unable to set file times %s: ERR=%s\n"),
144 attr->ofname, be.bstrerror());
152 * Return the data stream that will be used
154 int select_data_stream(FF_PKT *ff_pkt)
158 /* This is a plugin special restore object */
159 if (ff_pkt->type == FT_RESTORE_FIRST) {
161 return STREAM_FILE_DATA;
165 * Fix all incompatible options
167 /* No sparse option for encrypted data */
168 if (ff_pkt->flags & FO_ENCRYPT) {
169 ff_pkt->flags &= ~FO_SPARSE;
172 /* Note, no sparse option for win32_data */
173 if (!is_portable_backup(&ff_pkt->bfd)) {
174 stream = STREAM_WIN32_DATA;
175 ff_pkt->flags &= ~FO_SPARSE;
176 } else if (ff_pkt->flags & FO_SPARSE) {
177 stream = STREAM_SPARSE_DATA;
179 stream = STREAM_FILE_DATA;
181 if (ff_pkt->flags & FO_OFFSETS) {
182 stream = STREAM_SPARSE_DATA;
185 /* Encryption is only supported for file data */
186 if (stream != STREAM_FILE_DATA && stream != STREAM_WIN32_DATA &&
187 stream != STREAM_MACOS_FORK_DATA) {
188 ff_pkt->flags &= ~FO_ENCRYPT;
191 /* Compression is not supported for Mac fork data */
192 if (stream == STREAM_MACOS_FORK_DATA) {
193 ff_pkt->flags &= ~FO_COMPRESS;
197 * Handle compression and encryption options
199 #if defined(HAVE_LIBZ) || defined(HAVE_LZO)
200 if (ff_pkt->flags & FO_COMPRESS) {
202 if(ff_pkt->Compress_algo == COMPRESS_GZIP) {
204 case STREAM_WIN32_DATA:
205 stream = STREAM_WIN32_GZIP_DATA;
207 case STREAM_SPARSE_DATA:
208 stream = STREAM_SPARSE_GZIP_DATA;
210 case STREAM_FILE_DATA:
211 stream = STREAM_GZIP_DATA;
215 * All stream types that do not support compression should clear out
216 * FO_COMPRESS above, and this code block should be unreachable.
218 ASSERT(!(ff_pkt->flags & FO_COMPRESS));
224 if(ff_pkt->Compress_algo == COMPRESS_LZO1X) {
226 case STREAM_WIN32_DATA:
227 stream = STREAM_WIN32_COMPRESSED_DATA;
229 case STREAM_SPARSE_DATA:
230 stream = STREAM_SPARSE_COMPRESSED_DATA;
232 case STREAM_FILE_DATA:
233 stream = STREAM_COMPRESSED_DATA;
237 * All stream types that do not support compression should clear out
238 * FO_COMPRESS above, and this code block should be unreachable.
240 ASSERT(!(ff_pkt->flags & FO_COMPRESS));
248 if (ff_pkt->flags & FO_ENCRYPT) {
250 case STREAM_WIN32_DATA:
251 stream = STREAM_ENCRYPTED_WIN32_DATA;
253 case STREAM_WIN32_GZIP_DATA:
254 stream = STREAM_ENCRYPTED_WIN32_GZIP_DATA;
256 case STREAM_WIN32_COMPRESSED_DATA:
257 stream = STREAM_ENCRYPTED_WIN32_COMPRESSED_DATA;
259 case STREAM_FILE_DATA:
260 stream = STREAM_ENCRYPTED_FILE_DATA;
262 case STREAM_GZIP_DATA:
263 stream = STREAM_ENCRYPTED_FILE_GZIP_DATA;
265 case STREAM_COMPRESSED_DATA:
266 stream = STREAM_ENCRYPTED_FILE_COMPRESSED_DATA;
269 /* All stream types that do not support encryption should clear out
270 * FO_ENCRYPT above, and this code block should be unreachable. */
271 ASSERT(!(ff_pkt->flags & FO_ENCRYPT));
282 * Encode a stat structure into a base64 character string
283 * All systems must create such a structure.
284 * In addition, we tack on the LinkFI, which is non-zero in
285 * the case of a hard linked file that has no data. This
286 * is a File Index pointing to the link that does have the
287 * data (always the first one encountered in a save).
288 * You may piggyback attributes on this packet by encoding
289 * them in the encode_attribsEx() subroutine, but this is
292 void encode_stat(char *buf, struct stat *statp, int stat_size, int32_t LinkFI, int data_stream)
296 * We read the stat packet so make sure the caller's conception
297 * is the same as ours. They can be different if LARGEFILE is not
298 * the same when compiling this library and the calling program.
300 ASSERT(stat_size == (int)sizeof(struct stat));
303 * Encode a stat packet. I should have done this more intelligently
304 * with a length so that it could be easily expanded.
306 p += to_base64((int64_t)statp->st_dev, p);
307 *p++ = ' '; /* separate fields with a space */
308 p += to_base64((int64_t)statp->st_ino, p);
310 p += to_base64((int64_t)statp->st_mode, p);
312 p += to_base64((int64_t)statp->st_nlink, p);
314 p += to_base64((int64_t)statp->st_uid, p);
316 p += to_base64((int64_t)statp->st_gid, p);
318 p += to_base64((int64_t)statp->st_rdev, p);
320 p += to_base64((int64_t)statp->st_size, p);
323 p += to_base64((int64_t)statp->st_blksize, p);
325 p += to_base64((int64_t)statp->st_blocks, p);
328 p += to_base64((int64_t)0, p); /* output place holder */
330 p += to_base64((int64_t)0, p); /* output place holder */
333 p += to_base64((int64_t)statp->st_atime, p);
335 p += to_base64((int64_t)statp->st_mtime, p);
337 p += to_base64((int64_t)statp->st_ctime, p);
339 p += to_base64((int64_t)LinkFI, p);
343 /* FreeBSD function */
344 p += to_base64((int64_t)statp->st_flags, p); /* output st_flags */
346 p += to_base64((int64_t)0, p); /* output place holder */
349 p += to_base64((int64_t)data_stream, p);
352 p += to_base64((int64_t)statp->st_fattrs, p);
359 /* Do casting according to unknown type to keep compiler happy */
361 #define plug(st, val) st = (typeof st)val
363 #if !HAVE_GCC & HAVE_SUN_OS
364 /* Sun compiler does not handle templates correctly */
365 #define plug(st, val) st = val
367 #define plug(st, val) st = val
369 /* Use templates to do the casting */
370 template <class T> void plug(T &st, uint64_t val)
371 { st = static_cast<T>(val); }
377 * Decode a stat packet from base64 characters
378 * returns: data_stream
380 int decode_stat(char *buf, struct stat *statp, int stat_size, int32_t *LinkFI)
387 * We store into the stat packet so make sure the caller's conception
388 * is the same as ours. They can be different if LARGEFILE is not
389 * the same when compiling this library and the calling program.
391 ASSERT(stat_size == (int)sizeof(struct stat));
393 p += from_base64(&val, p);
394 plug(statp->st_dev, val);
396 p += from_base64(&val, p);
397 plug(statp->st_ino, val);
399 p += from_base64(&val, p);
400 plug(statp->st_mode, val);
402 p += from_base64(&val, p);
403 plug(statp->st_nlink, val);
405 p += from_base64(&val, p);
406 plug(statp->st_uid, val);
408 p += from_base64(&val, p);
409 plug(statp->st_gid, val);
411 p += from_base64(&val, p);
412 plug(statp->st_rdev, val);
414 p += from_base64(&val, p);
415 plug(statp->st_size, val);
418 p += from_base64(&val, p);
419 plug(statp->st_blksize, val);
421 p += from_base64(&val, p);
422 plug(statp->st_blocks, val);
425 p += from_base64(&val, p);
426 // plug(statp->st_blksize, val);
428 p += from_base64(&val, p);
429 // plug(statp->st_blocks, val);
432 p += from_base64(&val, p);
433 plug(statp->st_atime, val);
435 p += from_base64(&val, p);
436 plug(statp->st_mtime, val);
438 p += from_base64(&val, p);
439 plug(statp->st_ctime, val);
441 /* Optional FileIndex of hard linked file data */
442 if (*p == ' ' || (*p != 0 && *(p+1) == ' ')) {
444 p += from_base64(&val, p);
445 *LinkFI = (uint32_t)val;
451 /* FreeBSD user flags */
452 if (*p == ' ' || (*p != 0 && *(p+1) == ' ')) {
454 p += from_base64(&val, p);
456 plug(statp->st_flags, val);
462 /* Look for data stream id */
463 if (*p == ' ' || (*p != 0 && *(p+1) == ' ')) {
465 p += from_base64(&val, p);
471 if (*p == ' ' || (*p != 0 && *(p+1) == ' ')) {
473 p += from_base64(&val, p);
474 plug(statp->st_fattrs, val);
476 statp->st_fattrs = 0;
483 /* Decode a LinkFI field of encoded stat packet */
484 int32_t decode_LinkFI(char *buf, struct stat *statp, int stat_size)
489 * We store into the stat packet so make sure the caller's conception
490 * is the same as ours. They can be different if LARGEFILE is not
491 * the same when compiling this library and the calling program.
493 ASSERT(stat_size == (int)sizeof(struct stat));
495 skip_nonspaces(&p); /* st_dev */
496 p++; /* skip space */
497 skip_nonspaces(&p); /* st_ino */
499 p += from_base64(&val, p);
500 plug(statp->st_mode, val); /* st_mode */
502 skip_nonspaces(&p); /* st_nlink */
504 skip_nonspaces(&p); /* st_uid */
506 skip_nonspaces(&p); /* st_gid */
508 skip_nonspaces(&p); /* st_rdev */
510 skip_nonspaces(&p); /* st_size */
512 skip_nonspaces(&p); /* st_blksize */
514 skip_nonspaces(&p); /* st_blocks */
516 skip_nonspaces(&p); /* st_atime */
518 skip_nonspaces(&p); /* st_mtime */
520 skip_nonspaces(&p); /* st_ctime */
522 /* Optional FileIndex of hard linked file data */
523 if (*p == ' ' || (*p != 0 && *(p+1) == ' ')) {
525 p += from_base64(&val, p);
532 * Set file modes, permissions and times
534 * fname is the original filename
535 * ofile is the output filename (may be in a different directory)
537 * Returns: true on success
540 bool set_attributes(JCR *jcr, ATTR *attr, BFILE *ofd)
554 char ec1[50], ec2[50];
555 fsize = blseek(ofd, 0, SEEK_END);
556 if (attr->type == FT_REG && fsize > 0 && attr->statp.st_size > 0 &&
557 fsize != (boffset_t)attr->statp.st_size) {
558 Jmsg3(jcr, M_ERROR, 0, _("File size of restored file %s not correct. Original %s, restored %s.\n"),
559 attr->ofname, edit_uint64(attr->statp.st_size, ec1),
560 edit_uint64(fsize, ec2));
565 * We do not restore sockets, so skip trying to restore their
568 if (attr->type == FT_SPEC && S_ISSOCK(attr->statp.st_mode)) {
572 /* ***FIXME**** optimize -- don't do if already correct */
574 * For link, change owner of link using lchown, but don't
575 * try to do a chmod as that will update the file behind it.
577 if (attr->type == FT_LNK) {
578 /* Change owner of link, not of real file */
579 if (lchown(attr->ofname, attr->statp.st_uid, attr->statp.st_gid) < 0 && print_error) {
581 Jmsg2(jcr, M_ERROR, 0, _("Unable to set file owner %s: ERR=%s\n"),
582 attr->ofname, be.bstrerror());
587 * At this point, we have a file that is not a LINK
589 ok = set_mod_own_time(jcr, ofd, attr);
595 * Note, this should really be done before the utime() above,
596 * but if the immutable bit is set, it will make the utimes()
599 if (chflags(attr->ofname, attr->statp.st_flags) < 0 && print_error) {
601 Jmsg2(jcr, M_ERROR, 0, _("Unable to set file flags %s: ERR=%s\n"),
602 attr->ofname, be.bstrerror());
612 pm_strcpy(attr->ofname, "*none*");
618 /*=============================================================*/
620 /* * * * U n i x * * * * */
622 /*=============================================================*/
627 * It is possible to piggyback additional data e.g. ACLs on
628 * the encode_stat() data by returning the extended attributes
629 * here. They must be "self-contained" (i.e. you keep track
630 * of your own length), and they must be in ASCII string
631 * format. Using this feature is not recommended.
632 * The code below shows how to return nothing. See the Win32
633 * code below for returning something in the attributes.
635 int encode_attribsEx(JCR *jcr, char *attribsEx, FF_PKT *ff_pkt)
637 #ifdef HAVE_DARWIN_OS
639 * We save the Mac resource fork length so that on a
640 * restore, we can be sure we put back the whole resource.
644 *attribsEx = 0; /* no extended attributes (yet) */
645 if (jcr->cmd_plugin || ff_pkt->type == FT_DELETED) {
646 return STREAM_UNIX_ATTRIBUTES;
649 if (ff_pkt->flags & FO_HFSPLUS) {
650 p += to_base64((uint64_t)(ff_pkt->hfsinfo.rsrclength), p);
654 *attribsEx = 0; /* no extended attributes */
656 return STREAM_UNIX_ATTRIBUTES;