Line data Source code
1 : /*
2 : Bacula® - The Network Backup Solution
3 :
4 : Copyright (C) 2002-2009 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 three of the GNU Affero 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 Affero 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, ...
32 : */
33 : /*
34 : * Some of these functions come from src/findlib/attribs.c in bacula-5.0.3.
35 : * Hence, the copyright notice above is retained.
36 : * Graham Keeling, 2014
37 : */
38 :
39 : #include "burp.h"
40 : #include "attribs.h"
41 : #include "alloc.h"
42 : #include "base64.h"
43 : #include "berrno.h"
44 : #include "cmd.h"
45 : #include "cntr.h"
46 : #include "log.h"
47 : #include "sbuf.h"
48 :
49 : // Encode a stat structure into a base64 character string.
50 44060 : int attribs_encode(struct sbuf *sb)
51 : {
52 : static char *p;
53 : static struct stat *statp;
54 :
55 44060 : if(!sb->attr.buf)
56 : {
57 43992 : sb->attr.cmd=CMD_ATTRIBS; // should not be needed
58 43992 : if(!(sb->attr.buf=(char *)malloc_w(256, __func__)))
59 0 : return -1;
60 : }
61 44060 : p=sb->attr.buf;
62 44060 : statp=&sb->statp;
63 :
64 44060 : if(sb->protocol2)
65 : {
66 : // Protocol1 does not have this field.
67 22530 : p += to_base64(sb->protocol2->index, p);
68 22530 : *p++ = ' ';
69 : // Protocol2 puts compression near the beginning.
70 22530 : p += to_base64(sb->compression, p);
71 22530 : *p++ = ' ';
72 : // Protocol1 does not have this field.
73 22530 : p += to_base64(sb->protocol2->encryption, p);
74 22530 : *p++ = ' ';
75 : }
76 44060 : p += to_base64(statp->st_dev, p);
77 44060 : *p++ = ' ';
78 44060 : p += to_base64(statp->st_ino, p);
79 44060 : *p++ = ' ';
80 44060 : p += to_base64(statp->st_mode, p);
81 44060 : *p++ = ' ';
82 44060 : p += to_base64(statp->st_nlink, p);
83 44060 : *p++ = ' ';
84 44060 : p += to_base64(statp->st_uid, p);
85 44060 : *p++ = ' ';
86 44060 : p += to_base64(statp->st_gid, p);
87 44060 : *p++ = ' ';
88 44060 : p += to_base64(statp->st_rdev, p);
89 44060 : *p++ = ' ';
90 44060 : p += to_base64(statp->st_size, p);
91 44060 : *p++ = ' ';
92 : #ifdef HAVE_WIN32
93 : p += to_base64(0, p); // place holder
94 : *p++ = ' ';
95 : p += to_base64(0, p); // place holder
96 : #else
97 44060 : p += to_base64(statp->st_blksize, p);
98 44060 : *p++ = ' ';
99 44060 : p += to_base64(statp->st_blocks, p);
100 : #endif
101 44060 : *p++ = ' ';
102 44060 : p += to_base64(statp->st_atime, p);
103 44060 : *p++ = ' ';
104 44060 : p += to_base64(statp->st_mtime, p);
105 44060 : *p++ = ' ';
106 44060 : p += to_base64(statp->st_ctime, p);
107 44060 : *p++ = ' ';
108 :
109 : #ifdef HAVE_CHFLAGS
110 : // chflags is a FreeBSD function.
111 : p += to_base64(statp->st_flags, p);
112 : #else
113 44060 : p += to_base64(0, p); // place holder
114 : #endif
115 44060 : *p++ = ' ';
116 :
117 44060 : p += to_base64(sb->winattr, p);
118 :
119 44060 : if(sb->protocol1)
120 : {
121 : // Protocol1 puts compression at the end.
122 21530 : *p++ = ' ';
123 21530 : p += to_base64(sb->compression, p);
124 : }
125 :
126 44060 : *p = 0;
127 :
128 44060 : sb->attr.len=p-sb->attr.buf;
129 :
130 44060 : return 0;
131 : }
132 :
133 : // Do casting according to unknown type to keep compiler happy.
134 : #ifdef HAVE_TYPEOF
135 : #define plug(st, val) st = (typeof st)val
136 : #else
137 : #if !HAVE_GCC & HAVE_SUN_OS
138 : // Sun compiler does not handle templates correctly.
139 : #define plug(st, val) st = val
140 : #elif __sgi
141 : #define plug(st, val) st = val
142 : #else
143 : // Use templates to do the casting.
144 : template <class T> void plug(T &st, uint64_t val)
145 : { st = static_cast<T>(val); }
146 : #endif
147 : #endif
148 :
149 : // Decode a stat packet from base64 characters.
150 46578 : void attribs_decode(struct sbuf *sb)
151 : {
152 : static const char *p;
153 : static int64_t val;
154 : static struct stat *statp;
155 :
156 46578 : if(!(p=sb->attr.buf)) return;
157 46578 : statp=&sb->statp;
158 :
159 46578 : if(sb->protocol2)
160 : {
161 : // Protocol1 does not have this field.
162 23288 : p += from_base64(&val, p);
163 23288 : sb->protocol2->index=val;
164 23288 : p++;
165 : // Compression for protocol2.
166 23288 : p += from_base64(&val, p);
167 23288 : sb->compression=val;
168 23288 : p++;
169 : // Protocol1 does not have this field.
170 23288 : p += from_base64(&val, p);
171 23288 : sb->protocol2->encryption=val;
172 23288 : p++;
173 : }
174 46578 : p += from_base64(&val, p);
175 46578 : plug(statp->st_dev, val);
176 46578 : p++;
177 46578 : p += from_base64(&val, p);
178 46578 : plug(statp->st_ino, val);
179 46578 : p++;
180 46578 : p += from_base64(&val, p);
181 46578 : plug(statp->st_mode, val);
182 46578 : p++;
183 46578 : p += from_base64(&val, p);
184 46578 : plug(statp->st_nlink, val);
185 46578 : p++;
186 46578 : p += from_base64(&val, p);
187 46578 : plug(statp->st_uid, val);
188 46578 : p++;
189 46578 : p += from_base64(&val, p);
190 46578 : plug(statp->st_gid, val);
191 46578 : p++;
192 46578 : p += from_base64(&val, p);
193 46578 : plug(statp->st_rdev, val);
194 46578 : p++;
195 46578 : p += from_base64(&val, p);
196 46578 : plug(statp->st_size, val);
197 46578 : p++;
198 46578 : p += from_base64(&val, p);
199 : #ifdef HAVE_WIN32
200 : // plug(statp->st_blksize, val);
201 : p++;
202 : p += from_base64(&val, p);
203 : // plug(statp->st_blocks, val);
204 : #else
205 46578 : plug(statp->st_blksize, val);
206 46578 : p++;
207 46578 : p += from_base64(&val, p);
208 46578 : plug(statp->st_blocks, val);
209 : #endif
210 46578 : p++;
211 46578 : p += from_base64(&val, p);
212 46578 : plug(statp->st_atime, val);
213 46578 : p++;
214 46578 : p += from_base64(&val, p);
215 46578 : plug(statp->st_mtime, val);
216 46578 : p++;
217 46578 : p += from_base64(&val, p);
218 46578 : plug(statp->st_ctime, val);
219 :
220 : // FreeBSD user flags.
221 46578 : if(*p == ' ' || (*p != 0 && *(p+1) == ' '))
222 : {
223 46578 : p++;
224 46578 : if(!*p) return;
225 46578 : p += from_base64(&val, p);
226 : #ifdef HAVE_CHFLAGS
227 : plug(statp->st_flags, val);
228 : }
229 : else
230 : {
231 : statp->st_flags = 0;
232 : #endif
233 : }
234 :
235 : // Look for winattr.
236 46578 : if(*p == ' ' || (*p != 0 && *(p+1) == ' '))
237 : {
238 46578 : p++;
239 46578 : p += from_base64(&val, p);
240 : }
241 : else
242 0 : val = 0;
243 46578 : sb->winattr=val;
244 :
245 : // Compression for protocol1.
246 46578 : if(sb->protocol1)
247 : {
248 23290 : if(*p == ' ' || (*p != 0 && *(p+1) == ' '))
249 : {
250 23290 : p++;
251 23290 : if(!*p) return;
252 23290 : p += from_base64(&val, p);
253 23290 : sb->compression=val;
254 : }
255 : else
256 0 : sb->compression=-1;
257 : }
258 : }
259 :
260 0 : static int set_file_times(struct asfd *asfd,
261 : const char *path, struct utimbuf *ut,
262 : struct stat *statp, struct cntr *cntr)
263 : {
264 : int e;
265 : // The mingw64 utime() appears not to work on read-only files.
266 : // Use the utime() from bacula instead.
267 : #ifdef HAVE_WIN32
268 : //e=utime(path, ut);
269 : e=win32_utime(path, ut);
270 : #else
271 0 : e=utime(path, ut);
272 : #endif
273 0 : if(e<0)
274 : {
275 : berrno be;
276 0 : berrno_init(&be);
277 : logw(asfd, cntr, "Unable to set file times %s: ERR=%s\n",
278 0 : path, berrno_bstrerror(&be, errno));
279 0 : return -1;
280 : }
281 0 : return 0;
282 : }
283 :
284 0 : uint64_t decode_file_no(struct iobuf *iobuf)
285 : {
286 : int64_t val;
287 0 : from_base64(&val, iobuf->buf);
288 0 : return (uint64_t)val;
289 : }
290 :
291 0 : uint64_t decode_file_no_and_save_path(struct iobuf *iobuf, char **save_path)
292 : {
293 : int64_t val;
294 0 : char *p=iobuf->buf;
295 0 : p+=from_base64(&val, iobuf->buf);
296 0 : *save_path=p+1;
297 0 : return (uint64_t)val;
298 : }
299 :
300 : #ifdef HAVE_LUTIMES
301 0 : static int do_lutimes(const char *path, struct stat *statp)
302 : {
303 : struct timeval t[2];
304 0 : t[0].tv_sec = statp->st_atime;
305 0 : t[0].tv_usec = 0;
306 0 : t[1].tv_sec = statp->st_mtime;
307 0 : t[1].tv_usec = 0;
308 0 : return lutimes(path, t);
309 : }
310 : #endif
311 :
312 0 : int attribs_set(struct asfd *asfd, const char *path,
313 : struct stat *statp, uint64_t winattr, struct cntr *cntr)
314 : {
315 : struct utimbuf ut;
316 :
317 0 : ut.actime=statp->st_atime;
318 0 : ut.modtime=statp->st_mtime;
319 :
320 : #ifdef HAVE_WIN32
321 : win32_chmod(path, statp->st_mode, winattr);
322 : set_file_times(asfd, path, &ut, statp, cntr);
323 : return 0;
324 : #endif
325 :
326 0 : if(lchown(path, statp->st_uid, statp->st_gid)<0)
327 : {
328 : berrno be;
329 0 : berrno_init(&be);
330 : logw(asfd, cntr, "Unable to set file owner %s: ERR=%s\n",
331 0 : path, berrno_bstrerror(&be, errno));
332 0 : return -1;
333 : }
334 :
335 : /* Watch out, a metadata restore will have cmd set to CMD_METADATA or
336 : CMD_ENC_META, but that is OK at the moment because we are not doing
337 : meta stuff on links. */
338 0 : if(S_ISLNK(statp->st_mode))
339 : {
340 : #ifdef HAVE_LUTIMES
341 0 : if(do_lutimes(path, statp)) {
342 : berrno be;
343 0 : berrno_init(&be);
344 : logw(asfd, cntr, "Unable to set lutimes %s: ERR=%s\n",
345 0 : path, berrno_bstrerror(&be, errno));
346 0 : return -1;
347 : }
348 : #endif
349 : }
350 : else
351 : {
352 0 : if(chmod(path, statp->st_mode) < 0)
353 : {
354 : berrno be;
355 0 : berrno_init(&be);
356 : logw(asfd, cntr,
357 : "Unable to set file modes %s: ERR=%s\n",
358 0 : path, berrno_bstrerror(&be, errno));
359 0 : return -1;
360 : }
361 :
362 0 : if(set_file_times(asfd, path, &ut, statp, cntr))
363 0 : return -1;
364 : #ifdef HAVE_CHFLAGS
365 : /*
366 : * FreeBSD user flags
367 : *
368 : * Note, this should really be done before the utime() above,
369 : * but if the immutable bit is set, it will make the utimes()
370 : * fail.
371 : */
372 : if(chflags(path, statp->st_flags)<0)
373 : {
374 : berrno be;
375 : berrno_init(&be);
376 : logw(asfd, cntr,
377 : "Unable to set file flags %s: ERR=%s\n",
378 : path, berrno_bstrerror(&be, errno));
379 : return -1;
380 : }
381 : #endif
382 : }
383 :
384 0 : return 0;
385 : }
|