]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/findlib/attribs.c
Cygwin tweaks
[bacula/bacula] / bacula / src / findlib / attribs.c
1 /*
2  *  Encode and decode standard Unix attributes and
3  *   Extended attributes for Win32 and
4  *   other non-Unix systems, or Unix systems with ACLs, ...
5  *
6  *    Kern Sibbald, October MMII
7  *
8  *   Version $Id$
9  *
10  */
11 /*
12    Copyright (C) 2000-2003 Kern Sibbald and John Walker
13
14    This program is free software; you can redistribute it and/or
15    modify it under the terms of the GNU General Public License as
16    published by the Free Software Foundation; either version 2 of
17    the License, or (at your option) any later version.
18
19    This program is distributed in the hope that it will be useful,
20    but WITHOUT ANY WARRANTY; without even the implied warranty of
21    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22    General Public License for more details.
23
24    You should have received a copy of the GNU General Public
25    License along with this program; if not, write to the Free
26    Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
27    MA 02111-1307, USA.
28
29  */
30
31 #include "bacula.h"
32 #include "find.h"
33 #include "jcr.h"
34
35 #ifdef HAVE_CYGWIN
36 #include <windows.h>
37
38 /* Forward referenced subroutines */
39 static
40 int set_win32_attributes(void *jcr, char *fname, char *ofile, char *lname, 
41                          int type, int stream, struct stat *statp,
42                          char *attribsEx, int *ofd);
43 void unix_name_to_win32(POOLMEM **win32_name, char *name);
44 extern "C" HANDLE get_osfhandle(int fd);
45 void win_error(void *jcr, char *prefix, POOLMEM *ofile);
46 #endif
47
48 /* For old systems that don't have lchown() use chown() */
49 #ifndef HAVE_LCHOWN
50 #define lchown chown
51 #endif
52
53 /*=============================================================*/
54 /*                                                             */
55 /*             ***  A l l  S y s t e m s ***                   */
56 /*                                                             */
57 /*=============================================================*/
58
59
60 /* Encode a stat structure into a base64 character string */
61 void encode_stat(char *buf, struct stat *statp, uint32_t LinkFI)
62 {
63    char *p = buf;
64    /*
65     * NOTE: we should use rdev as major and minor device if
66     * it is a block or char device (S_ISCHR(statp->st_mode)
67     * or S_ISBLK(statp->st_mode)).  In all other cases,
68     * it is not used.   
69     *
70     */
71    p += to_base64((int64_t)statp->st_dev, p);
72    *p++ = ' ';                        /* separate fields with a space */
73    p += to_base64((int64_t)statp->st_ino, p);
74    *p++ = ' ';
75    p += to_base64((int64_t)statp->st_mode, p);
76    *p++ = ' ';
77    p += to_base64((int64_t)statp->st_nlink, p);
78    *p++ = ' ';
79    p += to_base64((int64_t)statp->st_uid, p);
80    *p++ = ' ';
81    p += to_base64((int64_t)statp->st_gid, p);
82    *p++ = ' ';
83    p += to_base64((int64_t)statp->st_rdev, p);
84    *p++ = ' ';
85    p += to_base64((int64_t)statp->st_size, p);
86    *p++ = ' ';
87    p += to_base64((int64_t)statp->st_blksize, p);
88    *p++ = ' ';
89    p += to_base64((int64_t)statp->st_blocks, p);
90    *p++ = ' ';
91    p += to_base64((int64_t)statp->st_atime, p);
92    *p++ = ' ';
93    p += to_base64((int64_t)statp->st_mtime, p);
94    *p++ = ' ';
95    p += to_base64((int64_t)statp->st_ctime, p);
96    *p++ = ' ';
97    p += to_base64((int64_t)LinkFI, p);
98    *p = 0;
99    return;
100 }
101
102
103
104 /* Decode a stat packet from base64 characters */
105 void
106 decode_stat(char *buf, struct stat *statp, uint32_t *LinkFI) 
107 {
108    char *p = buf;
109    int64_t val;
110
111    p += from_base64(&val, p);
112    statp->st_dev = val;
113    p++;                               /* skip space */
114    p += from_base64(&val, p);
115    statp->st_ino = val;
116    p++;
117    p += from_base64(&val, p);
118    statp->st_mode = val;
119    p++;
120    p += from_base64(&val, p);
121    statp->st_nlink = val;
122    p++;
123    p += from_base64(&val, p);
124    statp->st_uid = val;
125    p++;
126    p += from_base64(&val, p);
127    statp->st_gid = val;
128    p++;
129    p += from_base64(&val, p);
130    statp->st_rdev = val;
131    p++;
132    p += from_base64(&val, p);
133    statp->st_size = val;
134    p++;
135    p += from_base64(&val, p);
136    statp->st_blksize = val;
137    p++;
138    p += from_base64(&val, p);
139    statp->st_blocks = val;
140    p++;
141    p += from_base64(&val, p);
142    statp->st_atime = val;
143    p++;
144    p += from_base64(&val, p);
145    statp->st_mtime = val;
146    p++;
147    p += from_base64(&val, p);
148    statp->st_ctime = val;
149    /* Optional FileIndex of hard linked file data */
150    if (*p == ' ' || (*p != 0 && *(p+1) == ' ')) {
151       p++;
152       p += from_base64(&val, p);
153       *LinkFI = (uint32_t)val;
154   } else {
155       *LinkFI = 0;
156   }
157 }
158
159 /*
160  * Set file modes, permissions and times
161  *
162  *  fname is the original filename  
163  *  ofile is the output filename (may be in a different directory)
164  *
165  * Returns:  1 on success
166  *           0 on failure
167  */
168 int set_attributes(void *jcr, char *fname, char *ofile, char *lname, 
169                    int type, int stream, struct stat *statp,
170                    char *attribsEx, int *ofd)
171 {
172    struct utimbuf ut;    
173
174 #ifdef HAVE_CYGWIN
175    if (set_win32_attributes(jcr, fname, ofile, lname, type, stream,
176                             statp, attribsEx, ofd)) {
177       return 1;
178    }
179    /*
180     * If Windows stuff failed, e.g. attempt to restore Unix file
181     *  to Windows, simply fall through and we will do it the     
182     *  universal way.
183     */
184 #endif
185
186    if (*ofd != -1) {
187       close(*ofd);                    /* first close file */
188       *ofd = -1;
189    }
190
191    ut.actime = statp->st_atime;
192    ut.modtime = statp->st_mtime;
193
194    /* ***FIXME**** optimize -- don't do if already correct */
195    if (type == FT_LNK) {
196       if (lchown(ofile, statp->st_uid, statp->st_gid) < 0) {
197          Jmsg2(jcr, M_ERROR, 0, "Unable to set file owner %s: ERR=%s\n",
198             ofile, strerror(errno));
199          return 0;
200       }
201    } else {
202       if (chown(ofile, statp->st_uid, statp->st_gid) < 0) {
203          Jmsg2(jcr, M_ERROR, 0, "Unable to set file owner %s: ERR=%s\n",
204             ofile, strerror(errno));
205          return 0;
206       }
207    }
208    if (chmod(ofile, statp->st_mode) < 0) {
209       Jmsg2(jcr, M_ERROR, 0, "Unable to set file modes %s: ERR=%s\n",
210          ofile, strerror(errno));
211       return 0;
212    }
213
214    /*
215     * Reset file times.
216     */
217    if (utime(ofile, &ut) < 0) {
218       Jmsg2(jcr, M_ERROR, 0, "Unable to set file times %s: ERR=%s\n",
219          ofile, strerror(errno));
220       return 0;
221    }
222    return 1;
223 }
224
225
226 /*=============================================================*/
227 /*                                                             */
228 /*                 * * *  U n i x * * * *                      */
229 /*                                                             */
230 /*=============================================================*/
231
232 #ifndef HAVE_CYGWIN
233     
234 /*
235  * If you have a Unix system with extended attributes (e.g.
236  *  ACLs for Solaris, do it here.
237  */
238 int encode_attribsEx(void *jcr, char *attribsEx, FF_PKT *ff_pkt)
239 {
240    *attribsEx = 0;                    /* no extended attributes */
241    return STREAM_UNIX_ATTRIBUTES;
242 }
243
244 #endif
245
246
247
248 /*=============================================================*/
249 /*                                                             */
250 /*                 * * *  W i n 3 2 * * * *                    */
251 /*                                                             */
252 /*=============================================================*/
253
254 #ifdef HAVE_CYGWIN
255
256 int NoGetFileAttributesEx = 0;
257
258 int encode_attribsEx(void *jcr, char *attribsEx, FF_PKT *ff_pkt)
259 {
260    char *p = attribsEx;
261    WIN32_FILE_ATTRIBUTE_DATA atts;
262    ULARGE_INTEGER li;
263
264    attribsEx[0] = 0;                  /* no extended attributes */
265
266    if (NoGetFileAttributesEx) {
267       return STREAM_UNIX_ATTRIBUTES;
268    }
269
270    unix_name_to_win32(&ff_pkt->sys_fname, ff_pkt->fname);
271    if (!GetFileAttributesEx(ff_pkt->sys_fname, GetFileExInfoStandard,
272                             (LPVOID)&atts)) {
273       win_error(jcr, "GetFileAttributesEx:", ff_pkt->sys_fname);
274       return STREAM_WIN32_ATTRIBUTES;
275    }
276
277    p += to_base64((uint64_t)atts.dwFileAttributes, p);
278    *p++ = ' ';                        /* separate fields with a space */
279    li.LowPart = atts.ftCreationTime.dwLowDateTime;
280    li.HighPart = atts.ftCreationTime.dwHighDateTime;
281    p += to_base64((uint64_t)li.QuadPart, p);
282    *p++ = ' ';
283    li.LowPart = atts.ftLastAccessTime.dwLowDateTime;
284    li.HighPart = atts.ftLastAccessTime.dwHighDateTime;
285    p += to_base64((uint64_t)li.QuadPart, p);
286    *p++ = ' ';
287    li.LowPart = atts.ftLastWriteTime.dwLowDateTime;
288    li.HighPart = atts.ftLastWriteTime.dwHighDateTime;
289    p += to_base64((uint64_t)li.QuadPart, p);
290    *p++ = ' ';
291    p += to_base64((uint64_t)atts.nFileSizeHigh, p);
292    *p++ = ' ';
293    p += to_base64((uint64_t)atts.nFileSizeLow, p);
294    *p = 0;
295    return STREAM_WIN32_ATTRIBUTES;
296 }
297
298 /* Define attributes that are legal to set with SetFileAttributes() */
299 #define SET_ATTRS ( \
300          FILE_ATTRIBUTE_ARCHIVE| \
301          FILE_ATTRIBUTE_HIDDEN| \
302          FILE_ATTRIBUTE_NORMAL| \
303          FILE_ATTRIBUTE_NOT_CONTENT_INDEXED| \
304          FILE_ATTRIBUTE_OFFLINE| \
305          FILE_ATTRIBUTE_READONLY| \
306          FILE_ATTRIBUTE_SYSTEM| \
307          FILE_ATTRIBUTE_TEMPORARY)
308
309
310 /*
311  * Set Extended File Attributes for Win32
312  *
313  *  fname is the original filename  
314  *  ofile is the output filename (may be in a different directory)
315  *
316  * Returns:  1 on success
317  *           0 on failure
318  */
319 static
320 int set_win32_attributes(void *jcr, char *fname, char *ofile, char *lname, 
321                          int type, int stream, struct stat *statp,
322                          char *attribsEx, int *ofd)
323 {
324    char *p = attribsEx;
325    int64_t val;
326    WIN32_FILE_ATTRIBUTE_DATA atts;
327    ULARGE_INTEGER li;
328    int fid, stat;
329    POOLMEM *win32_ofile;
330
331    if (!p || !*p) {                   /* we should have attributes */
332       Dmsg2(100, "Attributes missing. of=%s ofd=%d\n", ofile, *ofd);
333       if (*ofd != -1) {
334          close(*ofd);
335          *ofd = -1;
336       }
337       return 0;
338    } else {
339       Dmsg2(100, "Attribs %s = %s\n", ofile, attribsEx);
340    }
341
342    p += from_base64(&val, p);
343    atts.dwFileAttributes = val;
344    p++;                               /* skip space */
345    p += from_base64(&val, p);
346    li.QuadPart = val;
347    atts.ftCreationTime.dwLowDateTime = li.LowPart;
348    atts.ftCreationTime.dwHighDateTime = li.HighPart;
349    p++;                               /* skip space */
350    p += from_base64(&val, p);
351    li.QuadPart = val;
352    atts.ftLastAccessTime.dwLowDateTime = li.LowPart;
353    atts.ftLastAccessTime.dwHighDateTime = li.HighPart;
354    p++;                               /* skip space */
355    p += from_base64(&val, p);
356    li.QuadPart = val;
357    atts.ftLastWriteTime.dwLowDateTime = li.LowPart;
358    atts.ftLastWriteTime.dwHighDateTime = li.HighPart;
359    p++;   
360    p += from_base64(&val, p);
361    atts.nFileSizeHigh = val;
362    p++;
363    p += from_base64(&val, p);
364    atts.nFileSizeLow = val;
365
366    /* At this point, we have reconstructed the WIN32_FILE_ATTRIBUTE_DATA pkt */
367
368    /* Convert to Windows path format */
369    win32_ofile = get_pool_memory(PM_FNAME);
370    unix_name_to_win32(&win32_ofile, ofile);
371
372    if (*ofd == -1) {
373       Dmsg1(100, "File not open: %s\n", ofile);
374       fid = open(ofile, O_RDWR|O_BINARY);   /* attempt to open the file */
375       if (fid >= 0) {
376          *ofd = fid;
377       }
378    }
379
380    if (*ofd != -1) {
381       Dmsg1(100, "SetFileTime %s\n", ofile);
382       stat = SetFileTime(get_osfhandle(*ofd),
383                          &atts.ftCreationTime,
384                          &atts.ftLastAccessTime,
385                          &atts.ftLastWriteTime);
386       if (stat != 1) {
387          win_error(jcr, "SetFileTime:", win32_ofile);
388       }
389       close(*ofd);
390       *ofd = -1;
391    }
392
393    Dmsg1(100, "SetFileAtts %s\n", ofile);
394    stat = SetFileAttributes(win32_ofile, atts.dwFileAttributes & SET_ATTRS);
395    if (stat != 1) {
396       win_error(jcr, "SetFileAttributes:", win32_ofile);
397    }
398    free_pool_memory(win32_ofile);
399    return 1;
400 }
401
402 void win_error(void *vjcr, char *prefix, POOLMEM *win32_ofile)
403 {
404    JCR *jcr = (JCR *)vjcr; 
405    DWORD lerror = GetLastError();
406    LPTSTR msg;
407    FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|
408                  FORMAT_MESSAGE_FROM_SYSTEM,
409                  NULL,
410                  lerror,
411                  0,
412                  (LPTSTR)&msg,
413                  0,
414                  NULL);
415    Dmsg3(100, "Error in %s on file %s: ERR=%s\n", prefix, win32_ofile, msg);
416    Jmsg3(jcr, M_INFO, 0, _("Error in %s file %s: ERR=%s\n"), prefix, win32_ofile, msg);
417    LocalFree(msg);
418 }
419
420 /* Cygwin API definition */
421 extern "C" void cygwin_conv_to_win32_path(const char *path, char *win32_path);
422
423 void unix_name_to_win32(POOLMEM **win32_name, char *name)
424 {
425    /* One extra byte should suffice, but we double it */
426    *win32_name = check_pool_memory_size(*win32_name, 2*strlen(name)+1);
427    cygwin_conv_to_win32_path(name, *win32_name);
428 }
429
430 #endif  /* HAVE_CYGWIN */