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 95158 : int attribs_encode(struct sbuf *sb)
51 : {
52 : static char *p;
53 : static struct stat *statp;
54 :
55 95158 : if(!sb->attr.buf)
56 : {
57 95027 : sb->attr.cmd=CMD_ATTRIBS; // should not be needed
58 95027 : if(!(sb->attr.buf=(char *)malloc_w(256, __func__)))
59 : return -1;
60 : }
61 95158 : p=sb->attr.buf;
62 95158 : statp=&sb->statp;
63 :
64 95158 : if(sb->protocol2)
65 : {
66 : // Protocol1 does not have this field.
67 73424 : p += to_base64(sb->protocol2->index, p);
68 73424 : *p++ = ' ';
69 : // Protocol2 puts compression near the beginning.
70 73424 : p += to_base64(sb->compression, p);
71 73424 : *p++ = ' ';
72 : // Protocol1 does not have this field.
73 73424 : p += to_base64(sb->protocol2->encryption, p);
74 73424 : *p++ = ' ';
75 : }
76 95158 : p += to_base64(statp->st_dev, p);
77 95158 : *p++ = ' ';
78 95158 : p += to_base64(statp->st_ino, p);
79 95158 : *p++ = ' ';
80 95158 : p += to_base64(statp->st_mode, p);
81 95158 : *p++ = ' ';
82 95158 : p += to_base64(statp->st_nlink, p);
83 95158 : *p++ = ' ';
84 95158 : p += to_base64(statp->st_uid, p);
85 95158 : *p++ = ' ';
86 95158 : p += to_base64(statp->st_gid, p);
87 95158 : *p++ = ' ';
88 95158 : p += to_base64(statp->st_rdev, p);
89 95158 : *p++ = ' ';
90 95158 : p += to_base64(statp->st_size, p);
91 95158 : *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 95158 : p += to_base64(statp->st_blksize, p);
98 95158 : *p++ = ' ';
99 95158 : p += to_base64(statp->st_blocks, p);
100 : #endif
101 95158 : *p++ = ' ';
102 95158 : p += to_base64(statp->st_atime, p);
103 95158 : *p++ = ' ';
104 95158 : p += to_base64(statp->st_mtime, p);
105 95158 : *p++ = ' ';
106 95158 : p += to_base64(statp->st_ctime, p);
107 95158 : *p++ = ' ';
108 :
109 : #ifdef HAVE_CHFLAGS
110 : // chflags is a FreeBSD function.
111 : p += to_base64(statp->st_flags, p);
112 : #else
113 95158 : p += to_base64(0, p); // place holder
114 : #endif
115 95158 : *p++ = ' ';
116 :
117 95158 : p += to_base64(sb->winattr, p);
118 :
119 95158 : if(sb->protocol1)
120 : {
121 : // Protocol1 puts compression at the end.
122 21734 : *p++ = ' ';
123 21734 : p += to_base64(sb->compression, p);
124 : }
125 :
126 95158 : *p = 0;
127 :
128 95158 : sb->attr.len=p-sb->attr.buf;
129 :
130 95158 : 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 80538 : void attribs_decode(struct sbuf *sb)
151 : {
152 : static const char *p;
153 : static int64_t val;
154 : static struct stat *statp;
155 :
156 80538 : if(!(p=sb->attr.buf)) return;
157 80538 : statp=&sb->statp;
158 :
159 80538 : if(sb->protocol2)
160 : {
161 : // Protocol1 does not have this field.
162 57073 : p += from_base64(&val, p);
163 57073 : sb->protocol2->index=val;
164 57073 : p++;
165 : // Compression for protocol2.
166 57073 : p += from_base64(&val, p);
167 57073 : sb->compression=val;
168 57073 : p++;
169 : // Protocol1 does not have this field.
170 57073 : p += from_base64(&val, p);
171 57073 : sb->protocol2->encryption=val;
172 57073 : p++;
173 : }
174 80538 : p += from_base64(&val, p);
175 80538 : plug(statp->st_dev, val);
176 80538 : p++;
177 80538 : p += from_base64(&val, p);
178 80538 : plug(statp->st_ino, val);
179 80538 : p++;
180 80538 : p += from_base64(&val, p);
181 80538 : plug(statp->st_mode, val);
182 80538 : p++;
183 80538 : p += from_base64(&val, p);
184 80538 : plug(statp->st_nlink, val);
185 80538 : p++;
186 80538 : p += from_base64(&val, p);
187 80538 : plug(statp->st_uid, val);
188 80538 : p++;
189 80538 : p += from_base64(&val, p);
190 80538 : plug(statp->st_gid, val);
191 80538 : p++;
192 80538 : p += from_base64(&val, p);
193 80538 : plug(statp->st_rdev, val);
194 80538 : p++;
195 80538 : p += from_base64(&val, p);
196 80538 : plug(statp->st_size, val);
197 80538 : p++;
198 80538 : 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 80538 : plug(statp->st_blksize, val);
206 80538 : p++;
207 80538 : p += from_base64(&val, p);
208 80538 : plug(statp->st_blocks, val);
209 : #endif
210 80538 : p++;
211 80538 : p += from_base64(&val, p);
212 80538 : plug(statp->st_atime, val);
213 80538 : p++;
214 80538 : p += from_base64(&val, p);
215 80538 : plug(statp->st_mtime, val);
216 80538 : p++;
217 80538 : p += from_base64(&val, p);
218 80538 : plug(statp->st_ctime, val);
219 :
220 : // FreeBSD user flags.
221 80538 : if(*p == ' ' || (*p != 0 && *(p+1) == ' '))
222 : {
223 80520 : p++;
224 80520 : if(!*p) return;
225 80519 : 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 80537 : if(*p == ' ' || (*p != 0 && *(p+1) == ' '))
237 : {
238 80519 : p++;
239 80519 : p += from_base64(&val, p);
240 : }
241 : else
242 18 : val = 0;
243 80537 : sb->winattr=val;
244 :
245 : // Compression for protocol1.
246 80537 : if(sb->protocol1)
247 : {
248 23464 : if(*p == ' ' || (*p != 0 && *(p+1) == ' '))
249 : {
250 23456 : p++;
251 23456 : if(!*p) return;
252 23456 : p += from_base64(&val, p);
253 23456 : sb->compression=val;
254 : }
255 : else
256 8 : sb->compression=-1;
257 : }
258 : }
259 :
260 28 : 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 28 : e=utime(path, ut);
272 : #endif
273 28 : 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 : return -1;
280 : }
281 : return 0;
282 : }
283 :
284 17034 : uint64_t decode_file_no(struct iobuf *iobuf)
285 : {
286 : int64_t val;
287 17034 : from_base64(&val, iobuf->buf);
288 17034 : 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 : 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 28 : int attribs_set(struct asfd *asfd, const char *path,
313 0 : struct stat *statp, uint64_t winattr, struct cntr *cntr)
314 : {
315 : struct utimbuf ut;
316 :
317 28 : ut.actime=statp->st_atime;
318 28 : 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 28 : if(lchown(path, statp->st_uid, statp->st_gid)<0)
327 : {
328 : berrno be;
329 0 : berrno_init(&be);
330 : logw(asfd, cntr,
331 : "Unable to set file owner of %s to %d:%d: ERR=%s\n",
332 : path, statp->st_uid, statp->st_gid,
333 0 : berrno_bstrerror(&be, errno));
334 : return -1;
335 : }
336 :
337 : /* Watch out, a metadata restore will have cmd set to CMD_METADATA or
338 : CMD_ENC_META, but that is OK at the moment because we are not doing
339 : meta stuff on links. */
340 28 : if(S_ISLNK(statp->st_mode))
341 : {
342 : #ifdef HAVE_LUTIMES
343 0 : if(do_lutimes(path, statp)) {
344 : berrno be;
345 0 : berrno_init(&be);
346 : logw(asfd, cntr, "Unable to set lutimes %s: ERR=%s\n",
347 0 : path, berrno_bstrerror(&be, errno));
348 : return -1;
349 : }
350 : #endif
351 : }
352 : else
353 : {
354 28 : if(chmod(path, statp->st_mode) < 0)
355 : {
356 : berrno be;
357 0 : berrno_init(&be);
358 : logw(asfd, cntr,
359 : "Unable to set file modes %s: ERR=%s\n",
360 0 : path, berrno_bstrerror(&be, errno));
361 : return -1;
362 : }
363 :
364 28 : if(set_file_times(asfd, path, &ut, statp, cntr))
365 : return -1;
366 : #ifdef HAVE_CHFLAGS
367 : /*
368 : * FreeBSD user flags
369 : *
370 : * Note, this should really be done before the utime() above,
371 : * but if the immutable bit is set, it will make the utimes()
372 : * fail.
373 : */
374 : if(chflags(path, statp->st_flags)<0)
375 : {
376 : berrno be;
377 : berrno_init(&be);
378 : logw(asfd, cntr,
379 : "Unable to set file flags %s: ERR=%s\n",
380 : path, berrno_bstrerror(&be, errno));
381 : return -1;
382 : }
383 : #endif
384 : }
385 :
386 : return 0;
387 : }
|