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