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