]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/findlib/attribs.c
Backport from Bacula Enterprise
[bacula/bacula] / bacula / src / findlib / attribs.c
1 /*
2    Bacula(R) - The Network Backup Solution
3
4    Copyright (C) 2000-2015 Kern Sibbald
5    Copyright (C) 2002-2014 Free Software Foundation Europe e.V.
6
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.
9
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.
14
15    This notice must be preserved when any source code is 
16    conveyed and/or propagated.
17
18    Bacula(R) is a registered trademark of Kern Sibbald.
19 */
20 /*
21  *  Encode and decode standard Unix attributes and
22  *   Extended attributes for Win32 and
23  *   other non-Unix systems, or Unix systems with ACLs, ...
24  *
25  *    Kern Sibbald, October MMII
26  *
27  */
28
29 //#define _POSIX_C_SOURCE 200809L
30 //#define _BSD_SOURCE 1
31
32 #include "bacula.h"
33 #include "find.h"
34 #include "ch.h"
35
36 static uid_t my_uid = 1;
37 static gid_t my_gid = 1;
38 static bool uid_set = false;
39
40 /*
41  * For old systems that don't have lchown() or lchmod()
42  */
43 #ifndef HAVE_LCHOWN
44 #define lchown chown
45 #endif
46 #ifndef HAVE_LCHMOD
47 #define lchmod chmod
48 #endif
49
50 /*=============================================================*/
51 /*                                                             */
52 /*             ***  A l l  S y s t e m s ***                   */
53 /*                                                             */
54 /*=============================================================*/
55
56 /*
57  * To turn off use of fchown(), fchmod(), or futimes(),
58  *   uncomment one or more of the following.
59  */
60 //#undef HAVE_FCHOWN
61 //#undef HAVE_FCHMOD
62 //#undef HAVE_FUTIMES
63
64 /*
65  * Print errors only if debug level defined or we are root.
66  *  root should not get errors.  Errors for users causes
67  *  too much output.
68  */
69 #define print_error (chk_dbglvl(100) || my_uid == 0)
70
71 bool set_mod_own_time(JCR *jcr, BFILE *ofd, ATTR *attr)
72 {
73    bool ok = true;
74    struct utimbuf ut;
75
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 */
78       /*
79        * The #ifdefing is a bit ugly, but it is the only
80        *  way we can ensure this works on older systems.
81        */
82 #ifdef HAVE_FCHOWN
83       if (fchown(ofd->fid, attr->statp.st_uid, attr->statp.st_gid) < 0 && print_error) {
84 #else
85       if (lchown(attr->ofname, attr->statp.st_uid, attr->statp.st_gid) < 0 && print_error) {
86 #endif
87          berrno be;
88          Jmsg2(jcr, M_ERROR, 0, _("Unable to set file owner %s: ERR=%s\n"),
89             attr->ofname, be.bstrerror());
90          ok = false;
91       }
92
93 #ifdef HAVE_FCHMOD
94       if (fchmod(ofd->fid, attr->statp.st_mode) < 0 && print_error) {
95 #else
96       if (lchmod(attr->ofname, attr->statp.st_mode) < 0 && print_error) {
97 #endif
98          berrno be;
99          Jmsg2(jcr, M_ERROR, 0, _("Unable to set file modes %s: ERR=%s\n"),
100             attr->ofname, be.bstrerror());
101          ok = false;
102       }
103
104 #ifdef HAVE_FUTIMES
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) {
111 #else
112       ut.actime = attr->statp.st_atime;
113       ut.modtime = attr->statp.st_mtime;
114       //bclose(ofd);
115       if (utime(attr->ofname, &ut) < 0 && print_error) {
116 #endif
117          berrno be;
118          Jmsg2(jcr, M_ERROR, 0, _("Unable to set file times %s: ERR=%s\n"),
119             attr->ofname, be.bstrerror());
120          ok = false;
121       }
122    } else {
123       if (lchown(attr->ofname, attr->statp.st_uid, attr->statp.st_gid) < 0 && print_error) {
124          berrno be;
125          Jmsg2(jcr, M_ERROR, 0, _("Unable to set file owner %s: ERR=%s\n"),
126             attr->ofname, be.bstrerror());
127          ok = false;
128       }
129       if (lchmod(attr->ofname, attr->statp.st_mode) < 0 && print_error) {
130          berrno be;
131          Jmsg2(jcr, M_ERROR, 0, _("Unable to set file modes %s: ERR=%s\n"),
132             attr->ofname, be.bstrerror());
133          ok = false;
134       }
135       /*
136        * Reset file times.
137        */
138       ut.actime = attr->statp.st_atime;
139       ut.modtime = attr->statp.st_mtime;
140
141       if (utime(attr->ofname, &ut) < 0 && print_error) {
142          berrno be;
143          Jmsg2(jcr, M_ERROR, 0, _("Unable to set file times %s: ERR=%s\n"),
144             attr->ofname, be.bstrerror());
145          ok = false;
146       }
147    }
148    return ok;
149 }
150
151 /*
152  * Return the data stream that will be used
153  */
154 int select_data_stream(FF_PKT *ff_pkt)
155 {
156    int stream;
157
158    /* This is a plugin special restore object */
159    if (ff_pkt->type == FT_RESTORE_FIRST) {
160       ff_pkt->flags = 0;
161       return STREAM_FILE_DATA;
162    }
163
164    /*
165     *  Fix all incompatible options
166     */
167    /* No sparse option for encrypted data */
168    if (ff_pkt->flags & FO_ENCRYPT) {
169       ff_pkt->flags &= ~FO_SPARSE;
170    }
171
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;
178    } else {
179       stream = STREAM_FILE_DATA;
180    }
181    if (ff_pkt->flags & FO_OFFSETS) {
182       stream = STREAM_SPARSE_DATA;
183    }
184
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;
189    }
190
191    /* Compression is not supported for Mac fork data */
192    if (stream == STREAM_MACOS_FORK_DATA) {
193       ff_pkt->flags &= ~FO_COMPRESS;
194    }
195
196    /*
197     * Handle compression and encryption options
198     */
199 #if defined(HAVE_LIBZ) || defined(HAVE_LZO)
200    if (ff_pkt->flags & FO_COMPRESS) {
201       #ifdef HAVE_LIBZ
202          if(ff_pkt->Compress_algo == COMPRESS_GZIP) {
203             switch (stream) {
204             case STREAM_WIN32_DATA:
205                   stream = STREAM_WIN32_GZIP_DATA;
206                break;
207             case STREAM_SPARSE_DATA:
208                   stream = STREAM_SPARSE_GZIP_DATA;
209                break;
210             case STREAM_FILE_DATA:
211                   stream = STREAM_GZIP_DATA;
212                break;
213             default:
214                /*
215                 * All stream types that do not support compression should clear out
216                 * FO_COMPRESS above, and this code block should be unreachable.
217                 */
218                ASSERT(!(ff_pkt->flags & FO_COMPRESS));
219                return STREAM_NONE;
220             }
221          }
222       #endif
223       #ifdef HAVE_LZO
224          if(ff_pkt->Compress_algo == COMPRESS_LZO1X) {
225             switch (stream) {
226             case STREAM_WIN32_DATA:
227                   stream = STREAM_WIN32_COMPRESSED_DATA;
228                break;
229             case STREAM_SPARSE_DATA:
230                   stream = STREAM_SPARSE_COMPRESSED_DATA;
231                break;
232             case STREAM_FILE_DATA:
233                   stream = STREAM_COMPRESSED_DATA;
234                break;
235             default:
236                /*
237                 * All stream types that do not support compression should clear out
238                 * FO_COMPRESS above, and this code block should be unreachable.
239                 */
240                ASSERT(!(ff_pkt->flags & FO_COMPRESS));
241                return STREAM_NONE;
242             }
243          }
244       #endif
245    }
246 #endif
247 #ifdef HAVE_CRYPTO
248    if (ff_pkt->flags & FO_ENCRYPT) {
249       switch (stream) {
250       case STREAM_WIN32_DATA:
251          stream = STREAM_ENCRYPTED_WIN32_DATA;
252          break;
253       case STREAM_WIN32_GZIP_DATA:
254          stream = STREAM_ENCRYPTED_WIN32_GZIP_DATA;
255          break;
256       case STREAM_WIN32_COMPRESSED_DATA:
257          stream = STREAM_ENCRYPTED_WIN32_COMPRESSED_DATA;
258          break;
259       case STREAM_FILE_DATA:
260          stream = STREAM_ENCRYPTED_FILE_DATA;
261          break;
262       case STREAM_GZIP_DATA:
263          stream = STREAM_ENCRYPTED_FILE_GZIP_DATA;
264          break;
265       case STREAM_COMPRESSED_DATA:
266          stream = STREAM_ENCRYPTED_FILE_COMPRESSED_DATA;
267          break;
268       default:
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));
272          return STREAM_NONE;
273       }
274    }
275 #endif
276
277    return stream;
278 }
279
280
281 /*
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
290  *   not recommended.
291  */
292 void encode_stat(char *buf, struct stat *statp, int stat_size, int32_t LinkFI, int data_stream)
293 {
294    char *p = buf;
295    /*
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.
299     */
300    ASSERT(stat_size == (int)sizeof(struct stat));
301
302    /*
303     *  Encode a stat packet.  I should have done this more intelligently
304     *   with a length so that it could be easily expanded.
305     */
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);
309    *p++ = ' ';
310     p += to_base64((int64_t)statp->st_mode, p);
311    *p++ = ' ';
312     p += to_base64((int64_t)statp->st_nlink, p);
313    *p++ = ' ';
314     p += to_base64((int64_t)statp->st_uid, p);
315    *p++ = ' ';
316     p += to_base64((int64_t)statp->st_gid, p);
317    *p++ = ' ';
318     p += to_base64((int64_t)statp->st_rdev, p);
319    *p++ = ' ';
320     p += to_base64((int64_t)statp->st_size, p);
321    *p++ = ' ';
322 #ifndef HAVE_MINGW
323     p += to_base64((int64_t)statp->st_blksize, p);
324    *p++ = ' ';
325     p += to_base64((int64_t)statp->st_blocks, p);
326    *p++ = ' ';
327 #else
328     p += to_base64((int64_t)0, p); /* output place holder */
329    *p++ = ' ';
330     p += to_base64((int64_t)0, p); /* output place holder */
331    *p++ = ' ';
332 #endif
333     p += to_base64((int64_t)statp->st_atime, p);
334    *p++ = ' ';
335     p += to_base64((int64_t)statp->st_mtime, p);
336    *p++ = ' ';
337    p += to_base64((int64_t)statp->st_ctime, p);
338    *p++ = ' ';
339     p += to_base64((int64_t)LinkFI, p);
340    *p++ = ' ';
341
342 #ifdef HAVE_CHFLAGS
343    /* FreeBSD function */
344    p += to_base64((int64_t)statp->st_flags, p);  /* output st_flags */
345 #else
346    p += to_base64((int64_t)0, p);     /* output place holder */
347 #endif
348    *p++ = ' ';
349    p += to_base64((int64_t)data_stream, p);
350 #ifdef HAVE_MINGW
351    *p++ = ' ';
352    p += to_base64((int64_t)statp->st_fattrs, p);
353 #endif
354    *p = 0;
355    return;
356 }
357
358
359 /* Do casting according to unknown type to keep compiler happy */
360 #ifdef HAVE_TYPEOF
361   #define plug(st, val) st = (typeof st)val
362 #else
363   #if !HAVE_GCC & HAVE_SUN_OS
364     /* Sun compiler does not handle templates correctly */
365     #define plug(st, val) st = val
366   #elif __sgi
367     #define plug(st, val) st = val
368   #else
369     /* Use templates to do the casting */
370     template <class T> void plug(T &st, uint64_t val)
371       { st = static_cast<T>(val); }
372   #endif
373 #endif
374
375
376 /*
377  * Decode a stat packet from base64 characters
378  * returns: data_stream
379  */
380 int decode_stat(char *buf, struct stat *statp, int stat_size, int32_t *LinkFI)
381 {
382    char *p = buf;
383    int64_t val;
384    int data_stream;
385
386    /*
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.
390     */
391    ASSERT(stat_size == (int)sizeof(struct stat));
392
393    p += from_base64(&val, p);
394    plug(statp->st_dev, val);
395    p++;
396    p += from_base64(&val, p);
397    plug(statp->st_ino, val);
398    p++;
399    p += from_base64(&val, p);
400    plug(statp->st_mode, val);
401    p++;
402    p += from_base64(&val, p);
403    plug(statp->st_nlink, val);
404    p++;
405    p += from_base64(&val, p);
406    plug(statp->st_uid, val);
407    p++;
408    p += from_base64(&val, p);
409    plug(statp->st_gid, val);
410    p++;
411    p += from_base64(&val, p);
412    plug(statp->st_rdev, val);
413    p++;
414    p += from_base64(&val, p);
415    plug(statp->st_size, val);
416    p++;
417 #ifndef HAVE_MINGW
418    p += from_base64(&val, p);
419    plug(statp->st_blksize, val);
420    p++;
421    p += from_base64(&val, p);
422    plug(statp->st_blocks, val);
423    p++;
424 #else
425    p += from_base64(&val, p);
426 //   plug(statp->st_blksize, val);
427    p++;
428    p += from_base64(&val, p);
429 //   plug(statp->st_blocks, val);
430    p++;
431 #endif
432    p += from_base64(&val, p);
433    plug(statp->st_atime, val);
434    p++;
435    p += from_base64(&val, p);
436    plug(statp->st_mtime, val);
437    p++;
438    p += from_base64(&val, p);
439    plug(statp->st_ctime, val);
440
441    /* Optional FileIndex of hard linked file data */
442    if (*p == ' ' || (*p != 0 && *(p+1) == ' ')) {
443       p++;
444       p += from_base64(&val, p);
445       *LinkFI = (uint32_t)val;
446    } else {
447       *LinkFI = 0;
448       return 0;
449    }
450
451    /* FreeBSD user flags */
452    if (*p == ' ' || (*p != 0 && *(p+1) == ' ')) {
453       p++;
454       p += from_base64(&val, p);
455 #ifdef HAVE_CHFLAGS
456       plug(statp->st_flags, val);
457    } else {
458       statp->st_flags  = 0;
459 #endif
460    }
461
462    /* Look for data stream id */
463    if (*p == ' ' || (*p != 0 && *(p+1) == ' ')) {
464       p++;
465       p += from_base64(&val, p);
466    } else {
467       val = 0;
468    }
469    data_stream = val;
470 #ifdef HAVE_MINGW
471    if (*p == ' ' || (*p != 0 && *(p+1) == ' ')) {
472       p++;
473       p += from_base64(&val, p);
474       plug(statp->st_fattrs, val);
475    } else {
476       statp->st_fattrs = 0;
477       val = 0;
478    }
479 #endif
480    return data_stream;
481 }
482
483 /* Decode a LinkFI field of encoded stat packet */
484 int32_t decode_LinkFI(char *buf, struct stat *statp, int stat_size)
485 {
486    char *p = buf;
487    int64_t val;
488    /*
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.
492     */
493    ASSERT(stat_size == (int)sizeof(struct stat));
494
495    skip_nonspaces(&p);                /* st_dev */
496    p++;                               /* skip space */
497    skip_nonspaces(&p);                /* st_ino */
498    p++;
499    p += from_base64(&val, p);
500    plug(statp->st_mode, val);         /* st_mode */
501    p++;
502    skip_nonspaces(&p);                /* st_nlink */
503    p++;
504    skip_nonspaces(&p);                /* st_uid */
505    p++;
506    skip_nonspaces(&p);                /* st_gid */
507    p++;
508    skip_nonspaces(&p);                /* st_rdev */
509    p++;
510    skip_nonspaces(&p);                /* st_size */
511    p++;
512    skip_nonspaces(&p);                /* st_blksize */
513    p++;
514    skip_nonspaces(&p);                /* st_blocks */
515    p++;
516    skip_nonspaces(&p);                /* st_atime */
517    p++;
518    skip_nonspaces(&p);                /* st_mtime */
519    p++;
520    skip_nonspaces(&p);                /* st_ctime */
521
522    /* Optional FileIndex of hard linked file data */
523    if (*p == ' ' || (*p != 0 && *(p+1) == ' ')) {
524       p++;
525       p += from_base64(&val, p);
526       return (int32_t)val;
527    }
528    return 0;
529 }
530
531 /*
532  * Set file modes, permissions and times
533  *
534  *  fname is the original filename
535  *  ofile is the output filename (may be in a different directory)
536  *
537  * Returns:  true  on success
538  *           false on failure
539  */
540 bool set_attributes(JCR *jcr, ATTR *attr, BFILE *ofd)
541 {
542    mode_t old_mask;
543    bool ok = true;
544    boffset_t fsize;
545
546    if (uid_set) {
547       my_uid = getuid();
548       my_gid = getgid();
549       uid_set = true;
550    }
551
552    old_mask = umask(0);
553    if (is_bopen(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));
561       }
562    }
563
564    /*
565     * We do not restore sockets, so skip trying to restore their
566     *   attributes.
567     */
568    if (attr->type == FT_SPEC && S_ISSOCK(attr->statp.st_mode)) {
569       goto bail_out;
570    }
571
572    /* ***FIXME**** optimize -- don't do if already correct */
573    /*
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.
576     */
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) {
580          berrno be;
581          Jmsg2(jcr, M_ERROR, 0, _("Unable to set file owner %s: ERR=%s\n"),
582             attr->ofname, be.bstrerror());
583          ok = false;
584       }
585    } else {
586       /*
587        * At this point, we have a file that is not a LINK
588        */
589       ok = set_mod_own_time(jcr, ofd, attr);
590
591 #ifdef HAVE_CHFLAGS
592       /*
593        * FreeBSD user flags
594        *
595        * Note, this should really be done before the utime() above,
596        *  but if the immutable bit is set, it will make the utimes()
597        *  fail.
598        */
599       if (chflags(attr->ofname, attr->statp.st_flags) < 0 && print_error) {
600          berrno be;
601          Jmsg2(jcr, M_ERROR, 0, _("Unable to set file flags %s: ERR=%s\n"),
602             attr->ofname, be.bstrerror());
603          ok = false;
604       }
605 #endif
606    }
607
608 bail_out:
609    if (is_bopen(ofd)) {
610       bclose(ofd);
611    }
612    pm_strcpy(attr->ofname, "*none*");
613    umask(old_mask);
614    return ok;
615 }
616
617
618 /*=============================================================*/
619 /*                                                             */
620 /*                 * * *  U n i x * * * *                      */
621 /*                                                             */
622 /*=============================================================*/
623
624 #ifndef HAVE_WIN32
625
626 /*
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.
634  */
635 int encode_attribsEx(JCR *jcr, char *attribsEx, FF_PKT *ff_pkt)
636 {
637 #ifdef HAVE_DARWIN_OS
638    /*
639     * We save the Mac resource fork length so that on a
640     * restore, we can be sure we put back the whole resource.
641     */
642    char *p;
643
644    *attribsEx = 0;                 /* no extended attributes (yet) */
645    if (jcr->cmd_plugin || ff_pkt->type == FT_DELETED) {
646       return STREAM_UNIX_ATTRIBUTES;
647    }
648    p = attribsEx;
649    if (ff_pkt->flags & FO_HFSPLUS) {
650       p += to_base64((uint64_t)(ff_pkt->hfsinfo.rsrclength), p);
651    }
652    *p = 0;
653 #else
654    *attribsEx = 0;                    /* no extended attributes */
655 #endif
656    return STREAM_UNIX_ATTRIBUTES;
657 }
658
659 #endif
660