]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/findlib/attribs.c
Tweak: comments
[bacula/bacula] / bacula / src / findlib / attribs.c
1 /*
2    Bacula® - The Network Backup Solution
3
4    Copyright (C) 2002-2010 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 two of the GNU 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 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, or Unix systems with ACLs, ...
32  *
33  *    Kern Sibbald, October MMII
34  *
35  */
36
37 #include "bacula.h"
38 #include "find.h"
39
40 static uid_t my_uid = 1;
41 static gid_t my_gid = 1;                        
42 static bool uid_set = false;
43
44
45 #if defined(HAVE_WIN32)
46 /* Forward referenced subroutines */
47 static bool set_win32_attributes(JCR *jcr, ATTR *attr, BFILE *ofd);
48 void unix_name_to_win32(POOLMEM **win32_name, char *name);
49 void win_error(JCR *jcr, const char *prefix, POOLMEM *ofile);
50 HANDLE bget_handle(BFILE *bfd);
51 #endif /* HAVE_WIN32 */
52
53 /* For old systems that don't have lchown() use chown() */
54 #ifndef HAVE_LCHOWN
55 #define lchown chown
56 #endif
57
58 /*=============================================================*/
59 /*                                                             */
60 /*             ***  A l l  S y s t e m s ***                   */
61 /*                                                             */
62 /*=============================================================*/
63
64 /**
65  * Return the data stream that will be used
66  */
67 int select_data_stream(FF_PKT *ff_pkt)
68 {
69    int stream;
70
71    /**
72     *  Fix all incompatible options
73     */
74    /** No sparse option for encrypted data */
75    if (ff_pkt->flags & FO_ENCRYPT) {
76       ff_pkt->flags &= ~FO_SPARSE;
77    }
78
79    /** Note, no sparse option for win32_data */
80    if (!is_portable_backup(&ff_pkt->bfd)) {
81       stream = STREAM_WIN32_DATA;
82       ff_pkt->flags &= ~FO_SPARSE;
83    } else if (ff_pkt->flags & FO_SPARSE) {
84       stream = STREAM_SPARSE_DATA;
85    } else {
86       stream = STREAM_FILE_DATA;
87    }
88
89    /** Encryption is only supported for file data */
90    if (stream != STREAM_FILE_DATA && stream != STREAM_WIN32_DATA &&
91          stream != STREAM_MACOS_FORK_DATA) {
92       ff_pkt->flags &= ~FO_ENCRYPT;
93    }
94
95    /** Compression is not supported for Mac fork data */
96    if (stream == STREAM_MACOS_FORK_DATA) {
97       ff_pkt->flags &= ~FO_GZIP;
98    }
99
100    /**
101     * Handle compression and encryption options
102     */
103 #ifdef HAVE_LIBZ
104    if (ff_pkt->flags & FO_GZIP) {
105       switch (stream) {
106       case STREAM_WIN32_DATA:
107          stream = STREAM_WIN32_GZIP_DATA;
108          break;
109       case STREAM_SPARSE_DATA:
110          stream = STREAM_SPARSE_GZIP_DATA;
111          break;
112       case STREAM_FILE_DATA:
113          stream = STREAM_GZIP_DATA;
114          break;
115       default:
116          /**
117           * All stream types that do not support gzip should clear out
118           * FO_GZIP above, and this code block should be unreachable.
119           */
120          ASSERT(!(ff_pkt->flags & FO_GZIP));
121          return STREAM_NONE;
122       }
123    }
124 #endif
125 #ifdef HAVE_CRYPTO
126    if (ff_pkt->flags & FO_ENCRYPT) {
127       switch (stream) {
128       case STREAM_WIN32_DATA:
129          stream = STREAM_ENCRYPTED_WIN32_DATA;
130          break;
131       case STREAM_WIN32_GZIP_DATA:
132          stream = STREAM_ENCRYPTED_WIN32_GZIP_DATA;
133          break;
134       case STREAM_FILE_DATA:
135          stream = STREAM_ENCRYPTED_FILE_DATA;
136          break;
137       case STREAM_GZIP_DATA:
138          stream = STREAM_ENCRYPTED_FILE_GZIP_DATA;
139          break;
140       default:
141          /* All stream types that do not support encryption should clear out
142           * FO_ENCRYPT above, and this code block should be unreachable. */
143          ASSERT(!(ff_pkt->flags & FO_ENCRYPT));
144          return STREAM_NONE;
145       }
146    }
147 #endif
148
149    return stream;
150 }
151
152
153 /**
154  * Encode a stat structure into a base64 character string
155  *   All systems must create such a structure.
156  *   In addition, we tack on the LinkFI, which is non-zero in
157  *   the case of a hard linked file that has no data.  This
158  *   is a File Index pointing to the link that does have the
159  *   data (always the first one encountered in a save).
160  * You may piggyback attributes on this packet by encoding
161  *   them in the encode_attribsEx() subroutine, but this is
162  *   not recommended.
163  */
164 void encode_stat(char *buf, struct stat *statp, int32_t LinkFI, int data_stream)
165 {
166    char *p = buf;
167
168    /**
169     *  Encode a stat packet.  I should have done this more intelligently
170     *   with a length so that it could be easily expanded.
171     */
172    p += to_base64((int64_t)statp->st_dev, p);
173    *p++ = ' ';                        /* separate fields with a space */
174    p += to_base64((int64_t)statp->st_ino, p);
175    *p++ = ' ';
176    p += to_base64((int64_t)statp->st_mode, p);
177    *p++ = ' ';
178    p += to_base64((int64_t)statp->st_nlink, p);
179    *p++ = ' ';
180    p += to_base64((int64_t)statp->st_uid, p);
181    *p++ = ' ';
182    p += to_base64((int64_t)statp->st_gid, p);
183    *p++ = ' ';
184    p += to_base64((int64_t)statp->st_rdev, p);
185    *p++ = ' ';
186    p += to_base64((int64_t)statp->st_size, p);
187    *p++ = ' ';
188 #ifndef HAVE_MINGW
189    p += to_base64((int64_t)statp->st_blksize, p);
190    *p++ = ' ';
191    p += to_base64((int64_t)statp->st_blocks, p);
192    *p++ = ' ';
193 #else
194    p += to_base64((int64_t)0, p); /* output place holder */
195    *p++ = ' ';
196    p += to_base64((int64_t)0, p); /* output place holder */
197    *p++ = ' ';
198 #endif
199    p += to_base64((int64_t)statp->st_atime, p);
200    *p++ = ' ';
201    p += to_base64((int64_t)statp->st_mtime, p);
202    *p++ = ' ';
203    p += to_base64((int64_t)statp->st_ctime, p);
204    *p++ = ' ';
205    p += to_base64((int64_t)LinkFI, p);
206    *p++ = ' ';
207
208 #ifdef HAVE_CHFLAGS
209    /* FreeBSD function */
210    p += to_base64((int64_t)statp->st_flags, p);  /* output st_flags */
211 #else
212    p += to_base64((int64_t)0, p);     /* output place holder */
213 #endif
214    *p++ = ' ';
215    p += to_base64((int64_t)data_stream, p);
216    *p = 0;
217    return;
218 }
219
220
221 /* Do casting according to unknown type to keep compiler happy */
222 #ifdef HAVE_TYPEOF
223   #define plug(st, val) st = (typeof st)val
224 #else
225   #if !HAVE_GCC & HAVE_SUN_OS
226     /* Sun compiler does not handle templates correctly */
227     #define plug(st, val) st = val
228   #elif __sgi
229     #define plug(st, val) st = val
230   #else
231     /* Use templates to do the casting */
232     template <class T> void plug(T &st, uint64_t val)
233       { st = static_cast<T>(val); }
234   #endif
235 #endif
236
237
238 /** Decode a stat packet from base64 characters */
239 int decode_stat(char *buf, struct stat *statp, int32_t *LinkFI)
240 {
241    char *p = buf;
242    int64_t val;
243
244    p += from_base64(&val, p);
245    plug(statp->st_dev, val);
246    p++;
247    p += from_base64(&val, p);
248    plug(statp->st_ino, val);
249    p++;
250    p += from_base64(&val, p);
251    plug(statp->st_mode, val);
252    p++;
253    p += from_base64(&val, p);
254    plug(statp->st_nlink, val);
255    p++;
256    p += from_base64(&val, p);
257    plug(statp->st_uid, val);
258    p++;
259    p += from_base64(&val, p);
260    plug(statp->st_gid, val);
261    p++;
262    p += from_base64(&val, p);
263    plug(statp->st_rdev, val);
264    p++;
265    p += from_base64(&val, p);
266    plug(statp->st_size, val);
267    p++;
268 #ifndef HAVE_MINGW
269    p += from_base64(&val, p);
270    plug(statp->st_blksize, val);
271    p++;
272    p += from_base64(&val, p);
273    plug(statp->st_blocks, val);
274    p++;
275 #else
276    p += from_base64(&val, p);
277 //   plug(statp->st_blksize, val);
278    p++;
279    p += from_base64(&val, p);
280 //   plug(statp->st_blocks, val);
281    p++;
282 #endif
283    p += from_base64(&val, p);
284    plug(statp->st_atime, val);
285    p++;
286    p += from_base64(&val, p);
287    plug(statp->st_mtime, val);
288    p++;
289    p += from_base64(&val, p);
290    plug(statp->st_ctime, val);
291
292    /* Optional FileIndex of hard linked file data */
293    if (*p == ' ' || (*p != 0 && *(p+1) == ' ')) {
294       p++;
295       p += from_base64(&val, p);
296       *LinkFI = (uint32_t)val;
297    } else {
298       *LinkFI = 0;
299       return 0;
300    }
301
302    /* FreeBSD user flags */
303    if (*p == ' ' || (*p != 0 && *(p+1) == ' ')) {
304       p++;
305       p += from_base64(&val, p);
306 #ifdef HAVE_CHFLAGS
307       plug(statp->st_flags, val);
308    } else {
309       statp->st_flags  = 0;
310 #endif
311    }
312
313    /* Look for data stream id */
314    if (*p == ' ' || (*p != 0 && *(p+1) == ' ')) {
315       p++;
316       p += from_base64(&val, p);
317    } else {
318       val = 0;
319    }
320    return (int)val;
321 }
322
323 /** Decode a LinkFI field of encoded stat packet */
324 int32_t decode_LinkFI(char *buf, struct stat *statp)
325 {
326    char *p = buf;
327    int64_t val;
328
329    skip_nonspaces(&p);                /* st_dev */
330    p++;                               /* skip space */
331    skip_nonspaces(&p);                /* st_ino */
332    p++;
333    p += from_base64(&val, p);
334    plug(statp->st_mode, val);         /* st_mode */
335    p++;
336    skip_nonspaces(&p);                /* st_nlink */
337    p++;
338    skip_nonspaces(&p);                /* st_uid */
339    p++;
340    skip_nonspaces(&p);                /* st_gid */
341    p++;
342    skip_nonspaces(&p);                /* st_rdev */
343    p++;
344    skip_nonspaces(&p);                /* st_size */
345    p++;
346    skip_nonspaces(&p);                /* st_blksize */
347    p++;
348    skip_nonspaces(&p);                /* st_blocks */
349    p++;
350    skip_nonspaces(&p);                /* st_atime */
351    p++;
352    skip_nonspaces(&p);                /* st_mtime */
353    p++;
354    skip_nonspaces(&p);                /* st_ctime */
355
356    /* Optional FileIndex of hard linked file data */
357    if (*p == ' ' || (*p != 0 && *(p+1) == ' ')) {
358       p++;
359       p += from_base64(&val, p);
360       return (int32_t)val;
361    }
362    return 0;
363 }
364
365 /**
366  * Set file modes, permissions and times
367  *
368  *  fname is the original filename
369  *  ofile is the output filename (may be in a different directory)
370  *
371  * Returns:  true  on success
372  *           false on failure
373  */
374 bool set_attributes(JCR *jcr, ATTR *attr, BFILE *ofd)
375 {
376    struct utimbuf ut;
377    mode_t old_mask;
378    bool ok = true;
379    boffset_t fsize;
380  
381    if (uid_set) {
382       my_uid = getuid();
383       my_gid = getgid();
384       uid_set = true;
385    }
386
387 #if defined(HAVE_WIN32)
388    if (attr->stream == STREAM_UNIX_ATTRIBUTES_EX &&
389        set_win32_attributes(jcr, attr, ofd)) {
390        if (is_bopen(ofd)) {
391            bclose(ofd);
392        }
393        pm_strcpy(attr->ofname, "*none*");
394        return true;
395    }
396    if (attr->data_stream == STREAM_WIN32_DATA ||
397        attr->data_stream == STREAM_WIN32_GZIP_DATA) {
398       if (is_bopen(ofd)) {
399          bclose(ofd);
400       }
401       pm_strcpy(attr->ofname, "*none*");
402       return true;
403    }
404
405
406    /**
407     * If Windows stuff failed, e.g. attempt to restore Unix file
408     *  to Windows, simply fall through and we will do it the
409     *  universal way.
410     */
411 #endif
412
413    old_mask = umask(0);
414    if (is_bopen(ofd)) {
415       char ec1[50], ec2[50];
416       fsize = blseek(ofd, 0, SEEK_END);
417       bclose(ofd);                    /* first close file */
418       if (attr->type == FT_REG && fsize > 0 && attr->statp.st_size > 0 && 
419                         fsize != (boffset_t)attr->statp.st_size) {
420          Jmsg3(jcr, M_ERROR, 0, _("File size of restored file %s not correct. Original %s, restored %s.\n"),
421             attr->ofname, edit_uint64(attr->statp.st_size, ec1),
422             edit_uint64(fsize, ec2));
423       }
424    }
425
426    /**
427     * We do not restore sockets, so skip trying to restore their
428     *   attributes.
429     */
430    if (attr->type == FT_SPEC && S_ISSOCK(attr->statp.st_mode)) {
431       goto bail_out;
432    }
433
434    ut.actime = attr->statp.st_atime;
435    ut.modtime = attr->statp.st_mtime;
436
437    /* ***FIXME**** optimize -- don't do if already correct */
438    /**
439     * For link, change owner of link using lchown, but don't
440     *   try to do a chmod as that will update the file behind it.
441     */
442    if (attr->type == FT_LNK) {
443       /** Change owner of link, not of real file */
444       if (lchown(attr->ofname, attr->statp.st_uid, attr->statp.st_gid) < 0 && my_uid == 0) {
445          berrno be;
446          Jmsg2(jcr, M_ERROR, 0, _("Unable to set file owner %s: ERR=%s\n"),
447             attr->ofname, be.bstrerror());
448          ok = false;
449       }
450    } else {
451       if (chown(attr->ofname, attr->statp.st_uid, attr->statp.st_gid) < 0 && my_uid == 0) {
452          berrno be;
453          Jmsg2(jcr, M_ERROR, 0, _("Unable to set file owner %s: ERR=%s\n"),
454             attr->ofname, be.bstrerror());
455          ok = false;
456       }
457       if (chmod(attr->ofname, attr->statp.st_mode) < 0 && my_uid == 0) {
458          berrno be;
459          Jmsg2(jcr, M_ERROR, 0, _("Unable to set file modes %s: ERR=%s\n"),
460             attr->ofname, be.bstrerror());
461          ok = false;
462       }
463
464       /**
465        * Reset file times.
466        */
467       if (utime(attr->ofname, &ut) < 0 && my_uid == 0) {
468          berrno be;
469          Jmsg2(jcr, M_ERROR, 0, _("Unable to set file times %s: ERR=%s\n"),
470             attr->ofname, be.bstrerror());
471          ok = false;
472       }
473 #ifdef HAVE_CHFLAGS
474       /**
475        * FreeBSD user flags
476        *
477        * Note, this should really be done before the utime() above,
478        *  but if the immutable bit is set, it will make the utimes()
479        *  fail.
480        */
481       if (chflags(attr->ofname, attr->statp.st_flags) < 0 && my_uid == 0) {
482          berrno be;
483          Jmsg2(jcr, M_ERROR, 0, _("Unable to set file flags %s: ERR=%s\n"),
484             attr->ofname, be.bstrerror());
485          ok = false;
486       }
487 #endif
488    }
489
490 bail_out:
491    pm_strcpy(attr->ofname, "*none*");
492    umask(old_mask);
493    return ok;
494 }
495
496
497 /*=============================================================*/
498 /*                                                             */
499 /*                 * * *  U n i x * * * *                      */
500 /*                                                             */
501 /*=============================================================*/
502
503 #if !defined(HAVE_WIN32)
504
505 /**
506  * It is possible to piggyback additional data e.g. ACLs on
507  *   the encode_stat() data by returning the extended attributes
508  *   here.  They must be "self-contained" (i.e. you keep track
509  *   of your own length), and they must be in ASCII string
510  *   format. Using this feature is not recommended.
511  * The code below shows how to return nothing.  See the Win32
512  *   code below for returning something in the attributes.
513  */
514 int encode_attribsEx(JCR *jcr, char *attribsEx, FF_PKT *ff_pkt)
515 {
516 #ifdef HAVE_DARWIN_OS
517    /**
518     * We save the Mac resource fork length so that on a
519     * restore, we can be sure we put back the whole resource.
520     */
521    char *p;
522
523    *attribsEx = 0;                 /* no extended attributes (yet) */
524    if (jcr->cmd_plugin || ff_pkt->type == FT_DELETED) {
525       return STREAM_UNIX_ATTRIBUTES;
526    }
527    p = attribsEx;
528    if (ff_pkt->flags & FO_HFSPLUS) {
529       p += to_base64((uint64_t)(ff_pkt->hfsinfo.rsrclength), p);
530    }
531    *p = 0;
532 #else
533    *attribsEx = 0;                    /* no extended attributes */
534 #endif
535    return STREAM_UNIX_ATTRIBUTES;
536 }
537
538 #endif
539
540
541
542 /*=============================================================*/
543 /*                                                             */
544 /*                 * * *  W i n 3 2 * * * *                    */
545 /*                                                             */
546 /*=============================================================*/
547
548 #if defined(HAVE_WIN32)
549
550 int encode_attribsEx(JCR *jcr, char *attribsEx, FF_PKT *ff_pkt)
551 {
552    char *p = attribsEx;
553    WIN32_FILE_ATTRIBUTE_DATA atts;
554    ULARGE_INTEGER li;
555
556    attribsEx[0] = 0;                  /* no extended attributes */
557
558    if (jcr->cmd_plugin || ff_pkt->type == FT_DELETED) {
559       return STREAM_UNIX_ATTRIBUTES;
560    }
561
562    unix_name_to_win32(&ff_pkt->sys_fname, ff_pkt->fname);
563
564    /** try unicode version */
565    if (p_GetFileAttributesExW)  {
566       POOLMEM* pwszBuf = get_pool_memory(PM_FNAME);   
567       make_win32_path_UTF8_2_wchar(&pwszBuf, ff_pkt->fname);
568
569       BOOL b=p_GetFileAttributesExW((LPCWSTR)pwszBuf, GetFileExInfoStandard, 
570                                     (LPVOID)&atts);
571       free_pool_memory(pwszBuf);
572
573       if (!b) {
574          win_error(jcr, "GetFileAttributesExW:", ff_pkt->sys_fname);
575          return STREAM_UNIX_ATTRIBUTES;
576       }
577    }
578    else {
579       if (!p_GetFileAttributesExA)
580          return STREAM_UNIX_ATTRIBUTES;      
581
582       if (!p_GetFileAttributesExA(ff_pkt->sys_fname, GetFileExInfoStandard,
583                               (LPVOID)&atts)) {
584          win_error(jcr, "GetFileAttributesExA:", ff_pkt->sys_fname);
585          return STREAM_UNIX_ATTRIBUTES;
586       }
587    }
588
589    p += to_base64((uint64_t)atts.dwFileAttributes, p);
590    *p++ = ' ';                        /* separate fields with a space */
591    li.LowPart = atts.ftCreationTime.dwLowDateTime;
592    li.HighPart = atts.ftCreationTime.dwHighDateTime;
593    p += to_base64((uint64_t)li.QuadPart, p);
594    *p++ = ' ';
595    li.LowPart = atts.ftLastAccessTime.dwLowDateTime;
596    li.HighPart = atts.ftLastAccessTime.dwHighDateTime;
597    p += to_base64((uint64_t)li.QuadPart, p);
598    *p++ = ' ';
599    li.LowPart = atts.ftLastWriteTime.dwLowDateTime;
600    li.HighPart = atts.ftLastWriteTime.dwHighDateTime;
601    p += to_base64((uint64_t)li.QuadPart, p);
602    *p++ = ' ';
603    p += to_base64((uint64_t)atts.nFileSizeHigh, p);
604    *p++ = ' ';
605    p += to_base64((uint64_t)atts.nFileSizeLow, p);
606    *p = 0;
607    return STREAM_UNIX_ATTRIBUTES_EX;
608 }
609
610 /** Define attributes that are legal to set with SetFileAttributes() */
611 #define SET_ATTRS ( \
612          FILE_ATTRIBUTE_ARCHIVE| \
613          FILE_ATTRIBUTE_HIDDEN| \
614          FILE_ATTRIBUTE_NORMAL| \
615          FILE_ATTRIBUTE_NOT_CONTENT_INDEXED| \
616          FILE_ATTRIBUTE_OFFLINE| \
617          FILE_ATTRIBUTE_READONLY| \
618          FILE_ATTRIBUTE_SYSTEM| \
619          FILE_ATTRIBUTE_TEMPORARY)
620
621
622 /**
623  * Set Extended File Attributes for Win32
624  *
625  *  fname is the original filename
626  *  ofile is the output filename (may be in a different directory)
627  *
628  * Returns:  true  on success
629  *           false on failure
630  */
631 static bool set_win32_attributes(JCR *jcr, ATTR *attr, BFILE *ofd)
632 {
633    char *p = attr->attrEx;
634    int64_t val;
635    WIN32_FILE_ATTRIBUTE_DATA atts;
636    ULARGE_INTEGER li;
637    POOLMEM *win32_ofile;
638
639    /** if we have neither Win ansi nor wchar API, get out */
640    if (!(p_SetFileAttributesW || p_SetFileAttributesA)) {
641       return false;
642    }
643
644    if (!p || !*p) {                   /* we should have attributes */
645       Dmsg2(100, "Attributes missing. of=%s ofd=%d\n", attr->ofname, ofd->fid);
646       if (is_bopen(ofd)) {
647          bclose(ofd);
648       }
649       return false;
650    } else {
651       Dmsg2(100, "Attribs %s = %s\n", attr->ofname, attr->attrEx);
652    }
653
654    p += from_base64(&val, p);
655    plug(atts.dwFileAttributes, val);
656    p++;                               /* skip space */
657    p += from_base64(&val, p);
658    li.QuadPart = val;
659    atts.ftCreationTime.dwLowDateTime = li.LowPart;
660    atts.ftCreationTime.dwHighDateTime = li.HighPart;
661    p++;                               /* skip space */
662    p += from_base64(&val, p);
663    li.QuadPart = val;
664    atts.ftLastAccessTime.dwLowDateTime = li.LowPart;
665    atts.ftLastAccessTime.dwHighDateTime = li.HighPart;
666    p++;                               /* skip space */
667    p += from_base64(&val, p);
668    li.QuadPart = val;
669    atts.ftLastWriteTime.dwLowDateTime = li.LowPart;
670    atts.ftLastWriteTime.dwHighDateTime = li.HighPart;
671    p++;
672    p += from_base64(&val, p);
673    plug(atts.nFileSizeHigh, val);
674    p++;
675    p += from_base64(&val, p);
676    plug(atts.nFileSizeLow, val);
677
678    /** Convert to Windows path format */
679    win32_ofile = get_pool_memory(PM_FNAME);
680    unix_name_to_win32(&win32_ofile, attr->ofname);
681
682    /** At this point, we have reconstructed the WIN32_FILE_ATTRIBUTE_DATA pkt */
683
684    if (!is_bopen(ofd)) {
685       Dmsg1(100, "File not open: %s\n", attr->ofname);
686       bopen(ofd, attr->ofname, O_WRONLY|O_BINARY, 0);   /* attempt to open the file */
687    }
688
689    if (is_bopen(ofd)) {
690       Dmsg1(100, "SetFileTime %s\n", attr->ofname);
691       if (!SetFileTime(bget_handle(ofd),
692                          &atts.ftCreationTime,
693                          &atts.ftLastAccessTime,
694                          &atts.ftLastWriteTime)) {
695          win_error(jcr, "SetFileTime:", win32_ofile);
696       }
697       bclose(ofd);
698    }
699
700    Dmsg1(100, "SetFileAtts %s\n", attr->ofname);
701    if (!(atts.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
702       if (p_SetFileAttributesW) {
703          POOLMEM* pwszBuf = get_pool_memory(PM_FNAME);   
704          make_win32_path_UTF8_2_wchar(&pwszBuf, attr->ofname);
705
706          BOOL b=p_SetFileAttributesW((LPCWSTR)pwszBuf, atts.dwFileAttributes & SET_ATTRS);
707          free_pool_memory(pwszBuf);
708       
709          if (!b) 
710             win_error(jcr, "SetFileAttributesW:", win32_ofile); 
711       }
712       else {
713          if (!p_SetFileAttributesA(win32_ofile, atts.dwFileAttributes & SET_ATTRS)) {
714             win_error(jcr, "SetFileAttributesA:", win32_ofile);
715          }
716       }
717    }
718    free_pool_memory(win32_ofile);
719    return true;
720 }
721
722 void win_error(JCR *jcr, const char *prefix, POOLMEM *win32_ofile)
723 {
724    DWORD lerror = GetLastError();
725    LPTSTR msg;
726    FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|
727                  FORMAT_MESSAGE_FROM_SYSTEM,
728                  NULL,
729                  lerror,
730                  0,
731                  (LPTSTR)&msg,
732                  0,
733                  NULL);
734    Dmsg3(100, "Error in %s on file %s: ERR=%s\n", prefix, win32_ofile, msg);
735    strip_trailing_junk(msg);
736    Jmsg3(jcr, M_ERROR, 0, _("Error in %s file %s: ERR=%s\n"), prefix, win32_ofile, msg);
737    LocalFree(msg);
738 }
739
740 void win_error(JCR *jcr, const char *prefix, DWORD lerror)
741 {
742    LPTSTR msg;
743    FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|
744                  FORMAT_MESSAGE_FROM_SYSTEM,
745                  NULL,
746                  lerror,
747                  0,
748                  (LPTSTR)&msg,
749                  0,
750                  NULL);
751    strip_trailing_junk(msg);
752    if (jcr) {
753       Jmsg2(jcr, M_ERROR, 0, _("Error in %s: ERR=%s\n"), prefix, msg);
754    } else {
755       MessageBox(NULL, msg, prefix, MB_OK);
756    }
757    LocalFree(msg);
758 }
759 #endif  /* HAVE_WIN32 */