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