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