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 95156 : int attribs_encode(struct sbuf *sb)
51 : {
52 : static char *p;
53 : static struct stat *statp;
54 :
55 95156 : if(!sb->attr.buf)
56 : {
57 95025 : sb->attr.cmd=CMD_ATTRIBS; // should not be needed
58 95025 : if(!(sb->attr.buf=(char *)malloc_w(256, __func__)))
59 : return -1;
60 : }
61 95156 : p=sb->attr.buf;
62 95156 : statp=&sb->statp;
63 :
64 95156 : if(sb->protocol2)
65 : {
66 : // Protocol1 does not have this field.
67 73422 : p += to_base64(sb->protocol2->index, p);
68 73422 : *p++ = ' ';
69 : // Protocol2 puts compression near the beginning.
70 73422 : p += to_base64(sb->compression, p);
71 73422 : *p++ = ' ';
72 : // Protocol1 does not have this field.
73 73422 : p += to_base64(sb->protocol2->encryption, p);
74 73422 : *p++ = ' ';
75 : }
76 95156 : p += to_base64(statp->st_dev, p);
77 95156 : *p++ = ' ';
78 95156 : p += to_base64(statp->st_ino, p);
79 95156 : *p++ = ' ';
80 95156 : p += to_base64(statp->st_mode, p);
81 95156 : *p++ = ' ';
82 95156 : p += to_base64(statp->st_nlink, p);
83 95156 : *p++ = ' ';
84 95156 : p += to_base64(statp->st_uid, p);
85 95156 : *p++ = ' ';
86 95156 : p += to_base64(statp->st_gid, p);
87 95156 : *p++ = ' ';
88 95156 : p += to_base64(statp->st_rdev, p);
89 95156 : *p++ = ' ';
90 95156 : p += to_base64(statp->st_size, p);
91 95156 : *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 95156 : p += to_base64(statp->st_blksize, p);
98 95156 : *p++ = ' ';
99 95156 : p += to_base64(statp->st_blocks, p);
100 : #endif
101 95156 : *p++ = ' ';
102 95156 : p += to_base64(statp->st_atime, p);
103 95156 : *p++ = ' ';
104 95156 : p += to_base64(statp->st_mtime, p);
105 95156 : *p++ = ' ';
106 95156 : p += to_base64(statp->st_ctime, p);
107 95156 : *p++ = ' ';
108 :
109 : #ifdef HAVE_CHFLAGS
110 : // chflags is a FreeBSD function.
111 : p += to_base64(statp->st_flags, p);
112 : #else
113 95156 : p += to_base64(0, p); // place holder
114 : #endif
115 95156 : *p++ = ' ';
116 :
117 95156 : p += to_base64(sb->winattr, p);
118 :
119 95156 : 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 95156 : *p = 0;
127 :
128 95156 : sb->attr.len=p-sb->attr.buf;
129 :
130 95156 : 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 80520 : void attribs_decode(struct sbuf *sb)
151 : {
152 : static const char *p;
153 : static int64_t val;
154 : static struct stat *statp;
155 :
156 80520 : if(!(p=sb->attr.buf)) return;
157 80520 : statp=&sb->statp;
158 :
159 80520 : if(sb->protocol2)
160 : {
161 : // Protocol1 does not have this field.
162 57063 : p += from_base64(&val, p);
163 57063 : sb->protocol2->index=val;
164 57063 : p++;
165 : // Compression for protocol2.
166 57063 : p += from_base64(&val, p);
167 57063 : sb->compression=val;
168 57063 : p++;
169 : // Protocol1 does not have this field.
170 57063 : p += from_base64(&val, p);
171 57063 : sb->protocol2->encryption=val;
172 57063 : p++;
173 : }
174 80520 : p += from_base64(&val, p);
175 80520 : plug(statp->st_dev, val);
176 80520 : p++;
177 80520 : p += from_base64(&val, p);
178 80520 : plug(statp->st_ino, val);
179 80520 : p++;
180 80520 : p += from_base64(&val, p);
181 80520 : plug(statp->st_mode, val);
182 80520 : p++;
183 80520 : p += from_base64(&val, p);
184 80520 : plug(statp->st_nlink, val);
185 80520 : p++;
186 80520 : p += from_base64(&val, p);
187 80520 : plug(statp->st_uid, val);
188 80520 : p++;
189 80520 : p += from_base64(&val, p);
190 80520 : plug(statp->st_gid, val);
191 80520 : p++;
192 80520 : p += from_base64(&val, p);
193 80520 : plug(statp->st_rdev, val);
194 80520 : p++;
195 80520 : p += from_base64(&val, p);
196 80520 : plug(statp->st_size, val);
197 80520 : p++;
198 80520 : 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 80520 : plug(statp->st_blksize, val);
206 80520 : p++;
207 80520 : p += from_base64(&val, p);
208 80520 : plug(statp->st_blocks, val);
209 : #endif
210 80520 : p++;
211 80520 : p += from_base64(&val, p);
212 80520 : plug(statp->st_atime, val);
213 80520 : p++;
214 80520 : p += from_base64(&val, p);
215 80520 : plug(statp->st_mtime, val);
216 80520 : p++;
217 80520 : p += from_base64(&val, p);
218 80520 : plug(statp->st_ctime, val);
219 :
220 : // FreeBSD user flags.
221 80520 : if(*p == ' ' || (*p != 0 && *(p+1) == ' '))
222 : {
223 80519 : p++;
224 80519 : 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 80520 : if(*p == ' ' || (*p != 0 && *(p+1) == ' '))
237 : {
238 80519 : p++;
239 80519 : p += from_base64(&val, p);
240 : }
241 : else
242 1 : val = 0;
243 80520 : sb->winattr=val;
244 :
245 : // Compression for protocol1.
246 80520 : if(sb->protocol1)
247 : {
248 23457 : 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 1 : 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 : }
|