]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/findlib/attribs.c
Update doc
[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     * Update 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 encode_attribsEx(void *jcr, char *attribsEx, FF_PKT *ff_pkt)
257 {
258    char *p = attribsEx;
259    WIN32_FILE_ATTRIBUTE_DATA atts;
260    ULARGE_INTEGER li;
261
262    attribsEx[0] = 0;                  /* no extended attributes */
263
264    unix_name_to_win32(&ff_pkt->sys_fname, ff_pkt->fname);
265    if (!GetFileAttributesEx(ff_pkt->sys_fname, GetFileExInfoStandard,
266                             (LPVOID)&atts)) {
267       win_error(jcr, "GetFileAttributesEx:", ff_pkt->sys_fname);
268       return STREAM_WIN32_ATTRIBUTES;
269    }
270
271    p += to_base64((uint64_t)atts.dwFileAttributes, p);
272    *p++ = ' ';                        /* separate fields with a space */
273    li.LowPart = atts.ftCreationTime.dwLowDateTime;
274    li.HighPart = atts.ftCreationTime.dwHighDateTime;
275    p += to_base64((uint64_t)li.QuadPart, p);
276    *p++ = ' ';
277    li.LowPart = atts.ftLastAccessTime.dwLowDateTime;
278    li.HighPart = atts.ftLastAccessTime.dwHighDateTime;
279    p += to_base64((uint64_t)li.QuadPart, p);
280    *p++ = ' ';
281    li.LowPart = atts.ftLastWriteTime.dwLowDateTime;
282    li.HighPart = atts.ftLastWriteTime.dwHighDateTime;
283    p += to_base64((uint64_t)li.QuadPart, p);
284    *p++ = ' ';
285    p += to_base64((uint64_t)atts.nFileSizeHigh, p);
286    *p++ = ' ';
287    p += to_base64((uint64_t)atts.nFileSizeLow, p);
288    *p = 0;
289    return STREAM_WIN32_ATTRIBUTES;
290 }
291
292 /* Define attributes that are legal to set with SetFileAttributes() */
293 #define SET_ATTRS ( \
294          FILE_ATTRIBUTE_ARCHIVE| \
295          FILE_ATTRIBUTE_HIDDEN| \
296          FILE_ATTRIBUTE_NORMAL| \
297          FILE_ATTRIBUTE_NOT_CONTENT_INDEXED| \
298          FILE_ATTRIBUTE_OFFLINE| \
299          FILE_ATTRIBUTE_READONLY| \
300          FILE_ATTRIBUTE_SYSTEM| \
301          FILE_ATTRIBUTE_TEMPORARY)
302
303
304 /*
305  * Set Extended File Attributes for Win32
306  *
307  *  fname is the original filename  
308  *  ofile is the output filename (may be in a different directory)
309  *
310  * Returns:  1 on success
311  *           0 on failure
312  */
313 static
314 int set_win32_attributes(void *jcr, char *fname, char *ofile, char *lname, 
315                          int type, int stream, struct stat *statp,
316                          char *attribsEx, int *ofd)
317 {
318    char *p = attribsEx;
319    int64_t val;
320    WIN32_FILE_ATTRIBUTE_DATA atts;
321    ULARGE_INTEGER li;
322    int fid, stat;
323    POOLMEM *win32_ofile;
324
325    if (!p || !*p) {                   /* we should have attributes */
326       Dmsg2(100, "Attributes missing. of=%s ofd=%d\n", ofile, *ofd);
327       if (*ofd != -1) {
328          close(*ofd);
329          *ofd = -1;
330       }
331       return 0;
332    } else {
333       Dmsg2(100, "Attribs %s = %s\n", ofile, attribsEx);
334    }
335
336    p += from_base64(&val, p);
337    atts.dwFileAttributes = val;
338    p++;                               /* skip space */
339    p += from_base64(&val, p);
340    li.QuadPart = val;
341    atts.ftCreationTime.dwLowDateTime = li.LowPart;
342    atts.ftCreationTime.dwHighDateTime = li.HighPart;
343    p++;                               /* skip space */
344    p += from_base64(&val, p);
345    li.QuadPart = val;
346    atts.ftLastAccessTime.dwLowDateTime = li.LowPart;
347    atts.ftLastAccessTime.dwHighDateTime = li.HighPart;
348    p++;                               /* skip space */
349    p += from_base64(&val, p);
350    li.QuadPart = val;
351    atts.ftLastWriteTime.dwLowDateTime = li.LowPart;
352    atts.ftLastWriteTime.dwHighDateTime = li.HighPart;
353    p++;   
354    p += from_base64(&val, p);
355    atts.nFileSizeHigh = val;
356    p++;
357    p += from_base64(&val, p);
358    atts.nFileSizeLow = val;
359
360    /* At this point, we have reconstructed the WIN32_FILE_ATTRIBUTE_DATA pkt */
361
362    /* Convert to Windows path format */
363    win32_ofile = get_pool_memory(PM_FNAME);
364    unix_name_to_win32(&win32_ofile, ofile);
365
366    if (*ofd == -1) {
367       Dmsg1(100, "File not open: %s\n", ofile);
368       fid = open(ofile, O_RDWR|O_BINARY);   /* attempt to open the file */
369       if (fid >= 0) {
370          *ofd = fid;
371       }
372    }
373
374    if (*ofd != -1) {
375       Dmsg1(100, "SetFileTime %s\n", ofile);
376       stat = SetFileTime(get_osfhandle(*ofd),
377                          &atts.ftCreationTime,
378                          &atts.ftLastAccessTime,
379                          &atts.ftLastWriteTime);
380       if (stat != 1) {
381          win_error(jcr, "SetFileTime:", win32_ofile);
382       }
383       close(*ofd);
384       *ofd = -1;
385    }
386
387    Dmsg1(100, "SetFileAtts %s\n", ofile);
388    stat = SetFileAttributes(win32_ofile, atts.dwFileAttributes & SET_ATTRS);
389    if (stat != 1) {
390       win_error(jcr, "SetFileAttributes:", win32_ofile);
391    }
392    free_pool_memory(win32_ofile);
393    return 1;
394 }
395
396 void win_error(void *vjcr, char *prefix, POOLMEM *win32_ofile)
397 {
398    JCR *jcr = (JCR *)vjcr; 
399    DWORD lerror = GetLastError();
400    LPTSTR msg;
401    FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|
402                  FORMAT_MESSAGE_FROM_SYSTEM,
403                  NULL,
404                  lerror,
405                  0,
406                  (LPTSTR)&msg,
407                  0,
408                  NULL);
409    Dmsg3(100, "Error in %s on file %s: ERR=%s\n", prefix, win32_ofile, msg);
410    Jmsg3(jcr, M_INFO, 0, _("Error in %s file %s: ERR=%s\n"), prefix, win32_ofile, msg);
411    LocalFree(msg);
412 }
413
414 /* Cygwin API definition */
415 extern "C" void cygwin_conv_to_win32_path(const char *path, char *win32_path);
416
417 void unix_name_to_win32(POOLMEM **win32_name, char *name)
418 {
419    /* One extra byte should suffice, but we double it */
420    *win32_name = check_pool_memory_size(*win32_name, 2*strlen(name)+1);
421    cygwin_conv_to_win32_path(name, *win32_name);
422 }
423
424 #endif  /* HAVE_CYGWIN */