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