1 /*
2 BAREOS® - Backup Archiving REcovery Open Sourced
3
4 Copyright (C) 2008-2012 Free Software Foundation Europe e.V.
5 Copyright (C) 2011-2012 Planets Communications B.V.
6 Copyright (C) 2013-2020 Bareos GmbH & Co. KG
7
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 Affero 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 /*
24 * Functions to handle Extended Attributes for bareos.
25 *
26 * Extended Attributes are so OS specific we only restore Extended Attributes if
27 * they were saved using a filed on the same platform.
28 *
29 * Currently we support the following OSes:
30 * Written by Marco van Wieringen, November 2008
31 * Major overhaul January 2012 + June 2012
32 * Moved into findlib so it can be used from other programs, May 2012
33 */
34 /**
35 * @file
36 * Functions to handle Extended Attributes for bareos.
37 *
38 * Extended Attributes are so OS specific we only restore Extended Attributes if
39 * they were saved using a filed on the same platform.
40 *
41 * Currently we support the following OSes:
42 * - AIX (Extended Attributes)
43 * - Darwin (Extended Attributes)
44 * - FreeBSD (Extended Attributes)
45 * - GNU HURD (Extended Attributes)
46 * - IRIX (Extended Attributes)
47 * - Linux (Extended Attributes)
48 * - NetBSD (Extended Attributes)
49 * - OpenBSD (Extended Attributes)
50 * (As it seems either they never implemented xattr or they are removed
51 * the support as it stated it was in version 3.1 but the current syscall
52 * tabled shows the extattr_ functions are not implemented. So as such we
53 * might eventually support xattr on OpenBSD when they implemented them
54 * using the same interface as FreeBSD and NetBSD.
55 * - Solaris (Extended Attributes and Extensible Attributes)
56 * - Tru64 (Extended Attributes)
57 */
58
59 #include "include/bareos.h"
60 #include "find.h"
61 #include "lib/berrno.h"
62 #include "lib/bsock.h"
63 #include "include/jcr.h"
64
65 static std::string error_message_disabling_xattributes{
66 _("Disabling restore of XATTRs on this filesystem, "
67 "not supported. Current file: \"%s\"\n")};
68
69 #if !defined(HAVE_XATTR)
70 /**
71 * Entry points when compiled without support for XATTRs or on an unsupported
72 * platform.
73 */
BuildXattrStreams(JobControlRecord * jcr,XattrData * xattr_data,FindFilesPacket * ff_pkt)74 BxattrExitCode BuildXattrStreams(JobControlRecord* jcr,
75 XattrData* xattr_data,
76 FindFilesPacket* ff_pkt)
77 {
78 return BxattrExitCode::kErrorFatal;
79 }
80
ParseXattrStreams(JobControlRecord * jcr,XattrData * xattr_data,int stream,char * content,uint32_t content_length)81 BxattrExitCode ParseXattrStreams(JobControlRecord* jcr,
82 XattrData* xattr_data,
83 int stream,
84 char* content,
85 uint32_t content_length)
86 {
87 return BxattrExitCode::kErrorFatal;
88 }
89 #else
90 /**
91 * Send a XATTR stream to the SD.
92 */
SendXattrStream(JobControlRecord * jcr,XattrData * xattr_data,int stream)93 BxattrExitCode SendXattrStream(JobControlRecord* jcr,
94 XattrData* xattr_data,
95 int stream)
96 {
97 BareosSocket* sd = jcr->store_bsock;
98 POOLMEM* msgsave;
99 # ifdef FD_NO_SEND_TEST
100 return BxattrExitCode::kSuccess;
101 # endif
102
103 /*
104 * Sanity check
105 */
106 if (xattr_data->u.build->content_length <= 0) {
107 return BxattrExitCode::kSuccess;
108 }
109
110 /*
111 * Send header
112 */
113 if (!sd->fsend("%ld %d 0", jcr->JobFiles, stream)) {
114 Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
115 sd->bstrerror());
116 return BxattrExitCode::kErrorFatal;
117 }
118
119 /*
120 * Send the buffer to the storage deamon
121 */
122 Dmsg1(400, "Backing up XATTR <%s>\n", xattr_data->u.build->content);
123 msgsave = sd->msg;
124 sd->msg = xattr_data->u.build->content;
125 sd->message_length = xattr_data->u.build->content_length;
126 if (!sd->send()) {
127 sd->msg = msgsave;
128 sd->message_length = 0;
129 Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
130 sd->bstrerror());
131 return BxattrExitCode::kErrorFatal;
132 }
133
134 jcr->JobBytes += sd->message_length;
135 sd->msg = msgsave;
136 if (!sd->signal(BNET_EOD)) {
137 Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
138 sd->bstrerror());
139 return BxattrExitCode::kErrorFatal;
140 }
141 Dmsg1(200, "XATTR of file: %s successfully backed up!\n",
142 xattr_data->last_fname);
143 return BxattrExitCode::kSuccess;
144 }
145
146 /**
147 * First some generic functions for OSes that use the same xattr encoding
148 * scheme. Currently for all OSes except for Solaris.
149 */
XattrDropInternalTable(alist * xattr_value_list)150 void XattrDropInternalTable(alist* xattr_value_list)
151 {
152 xattr_t* current_xattr = nullptr;
153
154 /*
155 * Walk the list of xattrs and free allocated memory on traversing.
156 */
157 foreach_alist (current_xattr, xattr_value_list) {
158 /*
159 * See if we can shortcut.
160 */
161 if (current_xattr == NULL || current_xattr->magic != XATTR_MAGIC) break;
162
163 free(current_xattr->name);
164
165 if (current_xattr->value_length > 0) free(current_xattr->value);
166
167 free(current_xattr);
168 }
169
170 delete xattr_value_list;
171 }
172
173 /**
174 * The xattr stream for OSX, FreeBSD, Linux and NetBSD is a serialized stream of
175 * bytes which encodes one or more xattr_t structures.
176 *
177 * The Serialized stream consists of the following elements:
178 * magic - A magic string which makes it easy to detect any binary
179 * incompatabilites name_length - The length of the following xattr name name -
180 * The name of the extended attribute value_length - The length of the following
181 * xattr data value - The actual content of the extended attribute
182 *
183 * This is repeated 1 or more times.
184 *
185 */
SerializeXattrStream(JobControlRecord * jcr,XattrData * xattr_data,uint32_t expected_serialize_len,alist * xattr_value_list)186 uint32_t SerializeXattrStream(JobControlRecord* jcr,
187 XattrData* xattr_data,
188 uint32_t expected_serialize_len,
189 alist* xattr_value_list)
190 {
191 xattr_t* current_xattr = nullptr;
192 ser_declare;
193
194 /*
195 * Make sure the serialized stream fits in the poolmem buffer.
196 * We allocate some more to be sure the stream is gonna fit.
197 */
198 xattr_data->u.build->content = CheckPoolMemorySize(
199 xattr_data->u.build->content, expected_serialize_len + 10);
200 SerBegin(xattr_data->u.build->content, expected_serialize_len + 10);
201
202 /*
203 * Walk the list of xattrs and Serialize the data.
204 */
205 foreach_alist (current_xattr, xattr_value_list) {
206 /*
207 * See if we can shortcut.
208 */
209 if (current_xattr == NULL || current_xattr->magic != XATTR_MAGIC) break;
210
211 ser_uint32(current_xattr->magic);
212 ser_uint32(current_xattr->name_length);
213 SerBytes(current_xattr->name, current_xattr->name_length);
214
215 ser_uint32(current_xattr->value_length);
216 if (current_xattr->value_length > 0 && current_xattr->value) {
217 SerBytes(current_xattr->value, current_xattr->value_length);
218
219 Dmsg3(100, "Backup xattr named %s, value %*s\n", current_xattr->name,
220 current_xattr->value_length, current_xattr->value);
221 } else {
222 Dmsg1(100, "Backup empty xattr named %s\n", current_xattr->name);
223 }
224 }
225
226 SerEnd(xattr_data->u.build->content, expected_serialize_len + 10);
227 xattr_data->u.build->content_length = SerLength(xattr_data->u.build->content);
228
229 return xattr_data->u.build->content_length;
230 }
231
UnSerializeXattrStream(JobControlRecord * jcr,XattrData * xattr_data,char * content,uint32_t content_length,alist * xattr_value_list)232 BxattrExitCode UnSerializeXattrStream(JobControlRecord* jcr,
233 XattrData* xattr_data,
234 char* content,
235 uint32_t content_length,
236 alist* xattr_value_list)
237 {
238 unser_declare;
239 xattr_t* current_xattr;
240
241 /**
242 * Parse the stream and call restore_xattr_on_file for each extended
243 * attribute.
244 *
245 * Start unserializing the data. We keep on looping while we have not
246 * unserialized all bytes in the stream.
247 */
248 UnserBegin(content, content_length);
249 while (UnserLength(content) < content_length) {
250 /*
251 * First make sure the magic is present. This way we can easily catch
252 * corruption. Any missing MAGIC is fatal we do NOT try to continue.
253 */
254 current_xattr = (xattr_t*)malloc(sizeof(xattr_t));
255 unser_uint32(current_xattr->magic);
256 if (current_xattr->magic != XATTR_MAGIC) {
257 Mmsg1(jcr->errmsg,
258 _("Illegal xattr stream, no XATTR_MAGIC on file \"%s\"\n"),
259 xattr_data->last_fname);
260 Dmsg1(100, "Illegal xattr stream, no XATTR_MAGIC on file \"%s\"\n",
261 xattr_data->last_fname);
262 free(current_xattr);
263 return BxattrExitCode::kError;
264 }
265
266 /*
267 * Decode the valuepair. First decode the length of the name.
268 */
269 unser_uint32(current_xattr->name_length);
270 if (current_xattr->name_length == 0) {
271 Mmsg1(jcr->errmsg,
272 _("Illegal xattr stream, xattr name length <= 0 on file \"%s\"\n"),
273 xattr_data->last_fname);
274 Dmsg1(100,
275 "Illegal xattr stream, xattr name length <= 0 on file \"%s\"\n",
276 xattr_data->last_fname);
277 free(current_xattr);
278 return BxattrExitCode::kError;
279 }
280
281 /*
282 * Allocate room for the name and decode its content.
283 */
284 current_xattr->name = (char*)malloc(current_xattr->name_length + 1);
285 UnserBytes(current_xattr->name, current_xattr->name_length);
286
287 /*
288 * The xattr_name needs to be null terminated.
289 */
290 current_xattr->name[current_xattr->name_length] = '\0';
291
292 /*
293 * Decode the value length.
294 */
295 unser_uint32(current_xattr->value_length);
296
297 if (current_xattr->value_length > 0) {
298 /*
299 * Allocate room for the value and decode its content.
300 */
301 current_xattr->value = (char*)malloc(current_xattr->value_length);
302 UnserBytes(current_xattr->value, current_xattr->value_length);
303
304 Dmsg3(100, "Restoring xattr named %s, value %*s\n", current_xattr->name,
305 current_xattr->value_length, current_xattr->value);
306 } else {
307 current_xattr->value = NULL;
308 Dmsg1(100, "Restoring empty xattr named %s\n", current_xattr->name);
309 }
310
311 xattr_value_list->append(current_xattr);
312 }
313
314 UnserEnd(content, content_length);
315 return BxattrExitCode::kSuccess;
316 }
317
318 /**
319 * This is a supported OS, See what kind of interface we should use.
320 */
321 # if defined(HAVE_AIX_OS)
322
323 # if (!defined(HAVE_LISTEA) && !defined(HAVE_LLISTEA)) \
324 || (!defined(HAVE_GETEA) && !defined(HAVE_LGETEA)) \
325 || (!defined(HAVE_SETEA) && !defined(HAVE_LSETEA))
326 # error "Missing full support for the Extended Attributes (EA) functions."
327 # endif
328
329 # ifdef HAVE_SYS_EA_H
330 # include <sys/ea.h>
331 # else
332 # error "Missing sys/ea.h header file"
333 # endif
334
335 /**
336 * Define the supported XATTR streams for this OS
337 */
338 static int os_default_xattr_streams[1] = {STREAM_XATTR_AIX};
339
340 /**
341 * Fallback to the non l-functions when those are not available.
342 */
343 # if defined(HAVE_GETEA) && !defined(HAVE_LGETEA)
344 # define lgetea getea
345 # endif
346 # if defined(HAVE_SETEA) && !defined(HAVE_LSETEA)
347 # define lsetea setea
348 # endif
349 # if defined(HAVE_LISTEA) && !defined(HAVE_LLISTEA)
350 # define llistea listea
351 # endif
352
aix_build_xattr_streams(JobControlRecord * jcr,XattrData * xattr_data,FindFilesPacket * ff_pkt)353 static BxattrExitCode aix_build_xattr_streams(JobControlRecord* jcr,
354 XattrData* xattr_data,
355 FindFilesPacket* ff_pkt)
356 {
357 char* bp;
358 bool skip_xattr;
359 char* xattr_list = NULL;
360 int cnt, xattr_count = 0;
361 uint32_t name_length;
362 int32_t xattr_list_len, xattr_value_len;
363 uint32_t expected_serialize_len = 0;
364 xattr_t* current_xattr;
365 alist* xattr_value_list = NULL;
366 BxattrExitCode retval = BxattrExitCode::kError;
367
368 /*
369 * First get the length of the available list with extended attributes.
370 */
371 xattr_list_len = llistea(xattr_data->last_fname, NULL, 0);
372 switch (xattr_list_len) {
373 case -1: {
374 BErrNo be;
375
376 switch (errno) {
377 case ENOENT:
378 case EFORMAT:
379 retval = BxattrExitCode::kSuccess;
380 goto bail_out;
381 case ENOTSUP:
382 /*
383 * If the filesystem reports it doesn't support XATTRs we clear the
384 * BXATTR_FLAG_SAVE_NATIVE flag so we skip XATTR saves on all other
385 * files on the same filesystem. The BXATTR_FLAG_SAVE_NATIVE flags
386 * gets sets again when we change from one filesystem to another.
387 */
388 xattr_data->flags &= ~BXATTR_FLAG_SAVE_NATIVE;
389 retval = BxattrExitCode::kWarning;
390 Mmsg(jcr->errmsg, error_message_disabling_xattributes.c_str(),
391 xattr_data->last_fname);
392 Dmsg1(100, error_message_disabling_xattributes.c_str(),
393 xattr_data->last_fname);
394 goto bail_out;
395 default:
396 Mmsg2(jcr->errmsg, _("llistea error on file \"%s\": ERR=%s\n"),
397 xattr_data->last_fname, be.bstrerror());
398 Dmsg2(100, "llistea error file=%s ERR=%s\n", xattr_data->last_fname,
399 be.bstrerror());
400 goto bail_out;
401 }
402 break;
403 }
404 case 0:
405 retval = BxattrExitCode::kSuccess;
406 goto bail_out;
407 default:
408 break;
409 }
410
411 /*
412 * Allocate room for the extented attribute list.
413 */
414 xattr_list = (char*)malloc(xattr_list_len + 1);
415 memset(xattr_list, 0, xattr_list_len + 1);
416
417 /*
418 * Get the actual list of extended attributes names for a file.
419 */
420 xattr_list_len = llistea(xattr_data->last_fname, xattr_list, xattr_list_len);
421 switch (xattr_list_len) {
422 case -1: {
423 BErrNo be;
424
425 switch (errno) {
426 case ENOENT:
427 case EFORMAT:
428 retval = BxattrExitCode::kSuccess;
429 goto bail_out;
430 default:
431 Mmsg2(jcr->errmsg, _("llistea error on file \"%s\": ERR=%s\n"),
432 xattr_data->last_fname, be.bstrerror());
433 Dmsg2(100, "llistea error file=%s ERR=%s\n", xattr_data->last_fname,
434 be.bstrerror());
435 goto bail_out;
436 }
437 break;
438 }
439 default:
440 break;
441 }
442 xattr_list[xattr_list_len] = '\0';
443
444 /*
445 * Walk the list of extended attributes names and retrieve the data.
446 * We already count the bytes needed for serializing the stream later on.
447 */
448 for (bp = xattr_list; (bp - xattr_list) + 1 < xattr_list_len;
449 bp = strchr(bp, '\0') + 1) {
450 skip_xattr = false;
451
452 /*
453 * We want to skip certain xattrs which start with a 0xF8 character on AIX.
454 */
455 if (*bp == 0xF8) { skip_xattr = true; }
456
457 name_length = strlen(bp);
458 if (skip_xattr || name_length == 0) {
459 Dmsg1(100, "Skipping xattr named %s\n", bp);
460 continue;
461 }
462
463 /*
464 * First see how long the value is for the extended attribute.
465 */
466 xattr_value_len = lgetea(xattr_data->last_fname, bp, NULL, 0);
467 switch (xattr_value_len) {
468 case -1: {
469 BErrNo be;
470
471 switch (errno) {
472 case ENOENT:
473 case EFORMAT:
474 retval = BxattrExitCode::kSuccess;
475 goto bail_out;
476 default:
477 Mmsg2(jcr->errmsg, _("lgetea error on file \"%s\": ERR=%s\n"),
478 xattr_data->last_fname, be.bstrerror());
479 Dmsg2(100, "lgetea error file=%s ERR=%s\n", xattr_data->last_fname,
480 be.bstrerror());
481 goto bail_out;
482 }
483 break;
484 }
485 default:
486 break;
487 }
488
489 /*
490 * Each xattr valuepair starts with a magic so we can parse it easier.
491 */
492 current_xattr = (xattr_t*)malloc(sizeof(xattr_t));
493 current_xattr->magic = XATTR_MAGIC;
494 expected_serialize_len += sizeof(current_xattr->magic);
495
496 /*
497 * Allocate space for storing the name.
498 */
499 current_xattr->name_length = name_length;
500 current_xattr->name = (char*)malloc(current_xattr->name_length);
501 memcpy(current_xattr->name, bp, current_xattr->name_length);
502
503 expected_serialize_len
504 += sizeof(current_xattr->name_length) + current_xattr->name_length;
505
506 switch (xattr_value_len) {
507 case 0:
508 current_xattr->value = NULL;
509 current_xattr->value_length = 0;
510 expected_serialize_len += sizeof(current_xattr->value_length);
511 break;
512 default:
513 /*
514 * Allocate space for storing the value.
515 */
516 current_xattr->value = (char*)malloc(xattr_value_len);
517 memset(current_xattr->value, 0, xattr_value_len);
518
519 xattr_value_len = lgetea(xattr_data->last_fname, bp,
520 current_xattr->value, xattr_value_len);
521 if (xattr_value_len < 0) {
522 BErrNo be;
523
524 switch (errno) {
525 case ENOENT:
526 case EFORMAT:
527 retval = BxattrExitCode::kSuccess;
528 break;
529 default:
530 Mmsg2(jcr->errmsg, _("lgetea error on file \"%s\": ERR=%s\n"),
531 xattr_data->last_fname, be.bstrerror());
532 Dmsg2(100, "lgetea error file=%s ERR=%s\n",
533 xattr_data->last_fname, be.bstrerror());
534 break;
535 }
536
537 /*
538 * Default failure path out when retrieval of attr fails.
539 */
540 free(current_xattr->value);
541 free(current_xattr->name);
542 free(current_xattr);
543 goto bail_out;
544 }
545
546 /*
547 * Store the actual length of the value.
548 */
549 current_xattr->value_length = xattr_value_len;
550 expected_serialize_len += sizeof(current_xattr->value_length)
551 + current_xattr->value_length;
552 break;
553 }
554
555 if (xattr_value_list == NULL) {
556 xattr_value_list = new alist(10, not_owned_by_alist);
557 }
558
559 xattr_value_list->append(current_xattr);
560 xattr_count++;
561
562 /*
563 * Protect ourself against things getting out of hand.
564 */
565 if (expected_serialize_len >= MAX_XATTR_STREAM) {
566 Mmsg2(jcr->errmsg,
567 _("Xattr stream on file \"%s\" exceeds maximum size of %d bytes\n"),
568 xattr_data->last_fname, MAX_XATTR_STREAM);
569 goto bail_out;
570 }
571 }
572
573 free(xattr_list);
574 xattr_list = (char*)NULL;
575
576 /*
577 * If we found any xattr send them to the SD.
578 */
579 if (xattr_count > 0) {
580 /*
581 * Serialize the datastream.
582 */
583 if (SerializeXattrStream(jcr, xattr_data, expected_serialize_len,
584 xattr_value_list)
585 < expected_serialize_len) {
586 Mmsg1(jcr->errmsg,
587 _("Failed to Serialize extended attributes on file \"%s\"\n"),
588 xattr_data->last_fname);
589 Dmsg1(100, "Failed to Serialize extended attributes on file \"%s\"\n",
590 xattr_data->last_fname);
591 goto bail_out;
592 }
593
594 /*
595 * Send the datastream to the SD.
596 */
597 retval = SendXattrStream(jcr, xattr_data, os_default_xattr_streams[0]);
598 } else {
599 retval = BxattrExitCode::kSuccess;
600 }
601
602 bail_out:
603 if (xattr_list != NULL) { free(xattr_list); }
604 if (xattr_value_list != NULL) { XattrDropInternalTable(xattr_value_list); }
605
606 return retval;
607 }
608
aix_parse_xattr_streams(JobControlRecord * jcr,XattrData * xattr_data,int stream,char * content,uint32_t content_length)609 static BxattrExitCode aix_parse_xattr_streams(JobControlRecord* jcr,
610 XattrData* xattr_data,
611 int stream,
612 char* content,
613 uint32_t content_length)
614 {
615 xattr_t* current_xattr;
616 alist* xattr_value_list;
617 BxattrExitCode retval = BxattrExitCode::kError;
618
619 xattr_value_list = new alist(10, not_owned_by_alist);
620
621 if (UnSerializeXattrStream(jcr, xattr_data, content, content_length,
622 xattr_value_list)
623 != BxattrExitCode::kSuccess) {
624 goto bail_out;
625 }
626
627 foreach_alist (current_xattr, xattr_value_list) {
628 if (lsetea(xattr_data->last_fname, current_xattr->name,
629 current_xattr->value, current_xattr->value_length, 0)
630 != 0) {
631 BErrNo be;
632
633 switch (errno) {
634 case ENOENT:
635 case EFORMAT:
636 goto bail_out;
637 case ENOTSUP:
638 /*
639 * If the filesystem reports it doesn't support XATTRs we clear
640 * the BXATTR_FLAG_RESTORE_NATIVE flag so we skip XATTR restores
641 * on all other files on the same filesystem. The
642 * BXATTR_FLAG_RESTORE_NATIVE flags gets sets again when we
643 * change from one filesystem to another.
644 */
645 xattr_data->flags &= ~BXATTR_FLAG_RESTORE_NATIVE;
646 retval = BxattrExitCode::kWarning;
647 Mmsg(jcr->errmsg, error_message_disabling_xattributes.c_str(),
648 xattr_data->last_fname);
649 Dmsg1(100, error_message_disabling_xattributes.c_str(),
650 xattr_data->last_fname);
651 goto bail_out;
652 default:
653 Mmsg2(jcr->errmsg, _("lsetea error on file \"%s\": ERR=%s\n"),
654 xattr_data->last_fname, be.bstrerror());
655 Dmsg2(100, "lsetea error file=%s ERR=%s\n", xattr_data->last_fname,
656 be.bstrerror());
657 goto bail_out;
658 }
659 }
660 }
661
662 retval = BxattrExitCode::kSuccess;
663
664 bail_out:
665 XattrDropInternalTable(xattr_value_list);
666
667 return retval;
668 }
669
670 /**
671 * Function pointers to the build and parse function to use for these xattrs.
672 */
673 static BxattrExitCode (*os_build_xattr_streams)(JobControlRecord* jcr,
674 XattrData* xattr_data,
675 FindFilesPacket* ff_pkt)
676 = aix_build_xattr_streams;
677 static BxattrExitCode (*os_parse_xattr_streams)(JobControlRecord* jcr,
678 XattrData* xattr_data,
679 int stream,
680 char* content,
681 uint32_t content_length)
682 = aix_parse_xattr_streams;
683
684 # elif defined(HAVE_IRIX_OS)
685
686 # include <sys/attributes.h>
687
688 /**
689 * Define the supported XATTR streams for this OS
690 */
691 static int os_default_xattr_streams[1] = {STREAM_XATTR_IRIX};
692 static const char* xattr_acl_skiplist[1] = {NULL};
693 static const char* xattr_skiplist[1] = {NULL};
694
695 struct xattr_naming_space {
696 const char* name;
697 int flags;
698 };
699
700 static xattr_naming_space xattr_naming_spaces[]
701 = {{"user.", ATTR_DONTFOLLOW},
702 {"root.", ATTR_ROOT | ATTR_DONTFOLLOW},
703 {NULL, 0}};
704
irix_build_xattr_streams(JobControlRecord * jcr,XattrData * xattr_data,FindFilesPacket * ff_pkt)705 static BxattrExitCode irix_build_xattr_streams(JobControlRecord* jcr,
706 XattrData* xattr_data,
707 FindFilesPacket* ff_pkt)
708 {
709 char dummy[32];
710 int cnt, length, xattr_count = 0;
711 attrlist_cursor_t cursor;
712 attrlist_t* attrlist;
713 attrlist_ent_t* attrlist_ent;
714 xattr_t* current_xattr;
715 alist* xattr_value_list = NULL;
716 uint32_t expected_serialize_len = 0;
717 BxattrExitCode retval = BxattrExitCode::kError;
718 POOLMEM* xattrbuf = GetMemory(ATTR_MAX_VALUELEN);
719
720 for (cnt = 0; xattr_naming_spaces[cnt].name != NULL; cnt++) {
721 memset(&cursor, 0, sizeof(attrlist_cursor_t));
722 while (1) {
723 if (attr_list(xattr_data->last_fname, xattrbuf, ATTR_MAX_VALUELEN,
724 xattr_naming_spaces[cnt].flags, &cursor)
725 != 0) {
726 BErrNo be;
727
728 switch (errno) {
729 case ENOENT:
730 retval = BxattrExitCode::kSuccess;
731 goto bail_out;
732 default:
733 Mmsg2(jcr->errmsg, _("attr_list error on file \"%s\": ERR=%s\n"),
734 xattr_data->last_fname, be.bstrerror());
735 Dmsg2(100, "attr_list error file=%s ERR=%s\n",
736 xattr_data->last_fname, be.bstrerror());
737 goto bail_out;
738 }
739 }
740
741 attrlist = (attrlist_t*)xattrbuf;
742
743 /*
744 * Walk the available attributes.
745 */
746 for (cnt = 0; cnt < attrlist->al_count; cnt++) {
747 attrlist_ent = ATTR_ENTRY(xattrbuf, cnt);
748
749 /*
750 * First determine if we can retrieve the xattr and how big it really
751 * is.
752 */
753 length = sizeof(dummy);
754 if (attr_get(xattr_data->last_fname, attrlist_ent->a_name, dummy,
755 &length, xattr_naming_spaces[cnt].flags)
756 != 0) {
757 BErrNo be;
758
759 switch (errno) {
760 case ENOENT:
761 case ENOATTR:
762 retval = BxattrExitCode::kSuccess;
763 goto bail_out;
764 case E2BIG:
765 /*
766 * Size of the xattr is bigger then the 32 bytes dummy which is
767 * likely. As length now contains its actual length we can
768 * allocate a properly size buffer for the real retrieval.
769 */
770 break;
771 default:
772 Mmsg2(jcr->errmsg, _("attr_list error on file \"%s\": ERR=%s\n"),
773 xattr_data->last_fname, be.bstrerror());
774 Dmsg2(100, "attr_list error file=%s ERR=%s\n",
775 xattr_data->last_fname, be.bstrerror());
776 goto bail_out;
777 }
778 }
779
780 /*
781 * Each xattr valuepair starts with a magic so we can parse it easier.
782 */
783 current_xattr = (xattr_t*)malloc(sizeof(xattr_t));
784 current_xattr->magic = XATTR_MAGIC;
785 expected_serialize_len += sizeof(current_xattr->magic);
786
787 /*
788 * Allocate space for storing the name.
789 * We store the name as <naming_space_name><xattr_name>
790 */
791 current_xattr->name_length = strlen(xattr_naming_spaces[cnt].name)
792 + strlen(attrlist_ent->a_name) + 1;
793 current_xattr->name = (char*)malloc(current_xattr->name_length);
794 Bsnprintf(current_xattr->name, current_xattr->name_length, "%s%s",
795 xattr_naming_spaces[cnt].name, attrlist_ent->a_name);
796
797 expected_serialize_len
798 += sizeof(current_xattr->name_length) + current_xattr->name_length;
799
800 current_xattr->value_length = length;
801 current_xattr->value = (char*)malloc(current_xattr->value_length);
802
803 /*
804 * Retrieve the actual value of the xattr.
805 */
806 if (attr_get(xattr_data->last_fname, attrlist_ent->a_name,
807 current_xattr->value, &length,
808 xattr_naming_spaces[cnt].flags)
809 != 0) {
810 BErrNo be;
811
812 switch (errno) {
813 case ENOENT:
814 case ENOATTR:
815 retval = BxattrExitCode::kSuccess;
816 break;
817 case E2BIG:
818 /*
819 * The buffer for the xattr isn't big enough. the value of
820 * current_xattr->value_length is updated with the actual size
821 * of the xattr. So we free the old buffer and create a new one
822 * and try again. Normally this cannot happen as we size the
823 * buffer using a call to attr_get before but in case of an
824 * race condition it might happen.
825 */
826 free(current_xattr->value);
827 current_xattr->value = (char*)malloc(length);
828 if (attr_get(xattr_data->last_fname, attrlist_ent->a_name,
829 current_xattr->value, &length,
830 xattr_naming_spaces[cnt].flags)
831 != 0) {
832 switch (errno) {
833 case ENOENT:
834 case ENOATTR:
835 retval = BxattrExitCode::kSuccess;
836 break;
837 default:
838 Mmsg2(jcr->errmsg,
839 _("attr_list error on file \"%s\": ERR=%s\n"),
840 xattr_data->last_fname, be.bstrerror(errno));
841 Dmsg2(100, "attr_list error file=%s ERR=%s\n",
842 xattr_data->last_fname, be.bstrerror());
843 break;
844 }
845 } else {
846 goto ok_continue;
847 }
848 break;
849 default:
850 Mmsg2(jcr->errmsg, _("attr_list error on file \"%s\": ERR=%s\n"),
851 xattr_data->last_fname, be.bstrerror());
852 Dmsg2(100, "attr_list error file=%s ERR=%s\n",
853 xattr_data->last_fname, be.bstrerror());
854 break;
855 }
856
857 /*
858 * Default failure path out when retrieval of attr fails.
859 */
860 free(current_xattr->value);
861 free(current_xattr->name);
862 free(current_xattr);
863 goto bail_out;
864 }
865
866 ok_continue:
867 current_xattr->value_length = length;
868 expected_serialize_len += sizeof(current_xattr->value_length)
869 + current_xattr->value_length;
870
871 if (xattr_value_list == NULL) {
872 xattr_value_list = new alist(10, not_owned_by_alist);
873 }
874
875 xattr_value_list->append(current_xattr);
876 xattr_count++;
877
878 /*
879 * Protect ourself against things getting out of hand.
880 */
881 if (expected_serialize_len >= MAX_XATTR_STREAM) {
882 Mmsg2(jcr->errmsg,
883 _("Xattr stream on file \"%s\" exceeds maximum size of %d "
884 "bytes\n"),
885 xattr_data->last_fname, MAX_XATTR_STREAM);
886 goto bail_out;
887 }
888 }
889
890 /*
891 * See if there are more attributes available for a next run of attr_list.
892 */
893 if (attrlist->al_more == 0) { break; }
894 }
895 }
896
897 /*
898 * If we found any xattr send them to the SD.
899 */
900 if (xattr_count > 0) {
901 /*
902 * Serialize the datastream.
903 */
904 if (SerializeXattrStream(jcr, xattr_data, expected_serialize_len,
905 xattr_value_list)
906 < expected_serialize_len) {
907 Mmsg1(jcr->errmsg,
908 _("Failed to Serialize extended attributes on file \"%s\"\n"),
909 xattr_data->last_fname);
910 Dmsg1(100, "Failed to Serialize extended attributes on file \"%s\"\n",
911 xattr_data->last_fname);
912 goto bail_out;
913 }
914
915 /*
916 * Send the datastream to the SD.
917 */
918 retval = SendXattrStream(jcr, xattr_data, os_default_xattr_streams[0]);
919 } else {
920 retval = BxattrExitCode::kSuccess;
921 }
922
923 bail_out:
924 FreePoolMemory(xattrbuf);
925
926 if (xattr_value_list != NULL) { XattrDropInternalTable(xattr_value_list); }
927
928 return retval;
929 }
930
irix_parse_xattr_streams(JobControlRecord * jcr,XattrData * xattr_data,int stream,char * content,uint32_t content_length)931 static BxattrExitCode irix_parse_xattr_streams(JobControlRecord* jcr,
932 XattrData* xattr_data,
933 int stream,
934 char* content,
935 uint32_t content_length)
936 {
937 char* bp;
938 int cnt, cmp_size, name_space_index, flags;
939 xattr_t* current_xattr;
940 alist* xattr_value_list;
941 BxattrExitCode retval = BxattrExitCode::kError;
942
943 xattr_value_list = new alist(10, not_owned_by_alist);
944
945 if (UnSerializeXattrStream(jcr, xattr_data, content, content_length,
946 xattr_value_list)
947 != BxattrExitCode::kSuccess) {
948 goto bail_out;
949 }
950
951 foreach_alist (current_xattr, xattr_value_list) {
952 /*
953 * See to what namingspace this xattr belongs to.
954 */
955 name_space_index = 0;
956 for (cnt = 0; xattr_naming_spaces[cnt].name != NULL; cnt++) {
957 cmp_size = strlen(xattr_naming_spaces[cnt].name);
958 if (bstrncasecmp(current_xattr->name, xattr_naming_spaces[cnt].name,
959 cmp_size)) {
960 name_space_index = cnt;
961 break;
962 }
963 }
964
965 /*
966 * If we got a xattr that doesn't belong to an valid namespace complain.
967 */
968 if (name_space_index == 0) {
969 Mmsg2(jcr->errmsg, _("Received illegal xattr named %s on file \"%s\"\n"),
970 current_xattr->name, xattr_data->last_fname);
971 Dmsg2(100, "Received illegal xattr named %s on file \"%s\"\n",
972 current_xattr->name, xattr_data->last_fname);
973 goto bail_out;
974 }
975
976 /*
977 * Restore the xattr first try to create the attribute from scratch.
978 */
979 flags = xattr_naming_spaces[name_space_index].flags | ATTR_CREATE;
980 bp = strchr(current_xattr->name, '.');
981 if (attr_set(xattr_data->last_fname, ++bp, current_xattr->value,
982 current_xattr->value_length, flags)
983 != 0) {
984 BErrNo be;
985
986 switch (errno) {
987 case ENOENT:
988 retval = BxattrExitCode::kSuccess;
989 goto bail_out;
990 case EEXIST:
991 /*
992 * The xattr already exists we need to replace it.
993 */
994 flags = xattr_naming_spaces[name_space_index].flags | ATTR_REPLACE;
995 if (attr_set(xattr_data->last_fname, bp, current_xattr->value,
996 current_xattr->value_length, flags)
997 != 0) {
998 switch (errno) {
999 case ENOENT:
1000 retval = BxattrExitCode::kSuccess;
1001 goto bail_out;
1002 default:
1003 Mmsg2(jcr->errmsg, _("attr_set error on file \"%s\": ERR=%s\n"),
1004 xattr_data->last_fname, be.bstrerror(errno));
1005 Dmsg2(100, "attr_set error file=%s ERR=%s\n",
1006 xattr_data->last_fname, be.bstrerror());
1007 goto bail_out;
1008 }
1009 }
1010 break;
1011 default:
1012 Mmsg2(jcr->errmsg, _("attr_set error on file \"%s\": ERR=%s\n"),
1013 xattr_data->last_fname, be.bstrerror());
1014 Dmsg2(100, "attr_set error file=%s ERR=%s\n", xattr_data->last_fname,
1015 be.bstrerror());
1016 goto bail_out;
1017 }
1018 }
1019 }
1020
1021 retval = BxattrExitCode::kSuccess;
1022
1023 bail_out:
1024 XattrDropInternalTable(xattr_value_list);
1025
1026 return retval;
1027 }
1028
1029 /**
1030 * Function pointers to the build and parse function to use for these xattrs.
1031 */
1032 static BxattrExitCode (*os_build_xattr_streams)(JobControlRecord* jcr,
1033 XattrData* xattr_data,
1034 FindFilesPacket* ff_pkt)
1035 = irix_build_xattr_streams;
1036 static BxattrExitCode (*os_parse_xattr_streams)(JobControlRecord* jcr,
1037 XattrData* xattr_data,
1038 int stream,
1039 char* content,
1040 uint32_t content_length)
1041 = irix_parse_xattr_streams;
1042
1043 # elif defined(HAVE_DARWIN_OS) || defined(HAVE_LINUX_OS) \
1044 || defined(HAVE_HURD_OS)
1045
1046 # if (!defined(HAVE_LISTXATTR) && !defined(HAVE_LLISTXATTR)) \
1047 || (!defined(HAVE_GETXATTR) && !defined(HAVE_LGETXATTR)) \
1048 || (!defined(HAVE_SETXATTR) && !defined(HAVE_LSETXATTR))
1049 # error "Missing full support for the XATTR functions."
1050 # endif
1051
1052 # ifdef HAVE_SYS_XATTR_H
1053 # include <sys/xattr.h>
1054 # else
1055 # error "Missing sys/xattr.h header file"
1056 # endif
1057
1058 /**
1059 * Define the supported XATTR streams for this OS
1060 */
1061 # if defined(HAVE_DARWIN_OS)
1062 static int os_default_xattr_streams[1] = {STREAM_XATTR_DARWIN};
1063 static const char* xattr_acl_skiplist[2] = {"com.apple.system.Security", NULL};
1064 static const char* xattr_skiplist[3]
1065 = {"com.apple.system.extendedsecurity", "com.apple.ResourceFork", NULL};
1066 # elif defined(HAVE_LINUX_OS)
1067 static int os_default_xattr_streams[1] = {STREAM_XATTR_LINUX};
1068 static const char* xattr_acl_skiplist[3]
1069 = {"system.posix_acl_access", "system.posix_acl_default", NULL};
1070 static const char* xattr_skiplist[]
1071 = {"ceph.dir.entries", "ceph.dir.files", "ceph.dir.rbytes",
1072 "ceph.dir.rctime", "ceph.dir.rentries", "ceph.dir.rfiles",
1073 "ceph.dir.rsubdirs", "ceph.dir.subdirs", NULL};
1074 # elif defined(HAVE_HURD_OS)
1075 static int os_default_xattr_streams[1] = {STREAM_XATTR_HURD};
1076 static const char* xattr_acl_skiplist[1] = {NULL};
1077 static const char* xattr_skiplist[1] = {NULL};
1078 # endif
1079
1080 /**
1081 * OSX doesn't have llistxattr, lgetxattr and lsetxattr but has
1082 * listxattr, getxattr and setxattr with an extra options argument
1083 * which mimics the l variants of the functions when we specify
1084 * XATTR_NOFOLLOW as the options value.
1085 */
1086 # if defined(HAVE_DARWIN_OS)
1087 # define llistxattr(path, list, size) \
1088 listxattr((path), (list), (size), XATTR_NOFOLLOW)
1089 # define lgetxattr(path, name, value, size) \
1090 getxattr((path), (name), (value), (size), 0, XATTR_NOFOLLOW)
1091 # define lsetxattr(path, name, value, size, flags) \
1092 setxattr((path), (name), (value), (size), (flags), XATTR_NOFOLLOW)
1093 # else
1094 /*
1095 * Fallback to the non l-functions when those are not available.
1096 */
1097 # if defined(HAVE_GETXATTR) && !defined(HAVE_LGETXATTR)
1098 # define lgetxattr getxattr
1099 # endif
1100 # if defined(HAVE_SETXATTR) && !defined(HAVE_LSETXATTR)
1101 # define lsetxattr setxattr
1102 # endif
1103 # if defined(HAVE_LISTXATTR) && !defined(HAVE_LLISTXATTR)
1104 # define llistxattr listxattr
1105 # endif
1106 # endif
1107
generic_build_xattr_streams(JobControlRecord * jcr,XattrData * xattr_data,FindFilesPacket * ff_pkt)1108 static BxattrExitCode generic_build_xattr_streams(JobControlRecord* jcr,
1109 XattrData* xattr_data,
1110 FindFilesPacket* ff_pkt)
1111 {
1112 char* bp;
1113 bool skip_xattr;
1114 char* xattr_list = NULL;
1115 int cnt, xattr_count = 0;
1116 uint32_t name_length;
1117 int32_t xattr_list_len, xattr_value_len;
1118 uint32_t expected_serialize_len = 0;
1119 xattr_t* current_xattr;
1120 alist* xattr_value_list = NULL;
1121 BxattrExitCode retval = BxattrExitCode::kError;
1122
1123 /*
1124 * First get the length of the available list with extended attributes.
1125 */
1126 xattr_list_len = llistxattr(xattr_data->last_fname, NULL, 0);
1127 switch (xattr_list_len) {
1128 case -1: {
1129 BErrNo be;
1130
1131 switch (errno) {
1132 case ENOENT:
1133 retval = BxattrExitCode::kSuccess;
1134 goto bail_out;
1135 case BXATTR_ENOTSUP:
1136 /*
1137 * If the filesystem reports it doesn't support XATTRs we clear
1138 * the BXATTR_FLAG_RESTORE_NATIVE flag so we skip XATTR restores
1139 * on all other files on the same filesystem. The
1140 * BXATTR_FLAG_RESTORE_NATIVE flags gets sets again when we
1141 * change from one filesystem to another.
1142 */
1143 xattr_data->flags &= ~BXATTR_FLAG_SAVE_NATIVE;
1144 retval = BxattrExitCode::kWarning;
1145 Mmsg(jcr->errmsg, error_message_disabling_xattributes.c_str(),
1146 xattr_data->last_fname);
1147 Dmsg1(100, error_message_disabling_xattributes.c_str(),
1148 xattr_data->last_fname);
1149 goto bail_out;
1150 default:
1151 Mmsg2(jcr->errmsg, _("llistxattr error on file \"%s\": ERR=%s\n"),
1152 xattr_data->last_fname, be.bstrerror());
1153 Dmsg2(100, "llistxattr error file=%s ERR=%s\n",
1154 xattr_data->last_fname, be.bstrerror());
1155 goto bail_out;
1156 }
1157 break;
1158 }
1159 case 0:
1160 retval = BxattrExitCode::kSuccess;
1161 goto bail_out;
1162 default:
1163 break;
1164 }
1165
1166 /*
1167 * Allocate room for the extented attribute list.
1168 */
1169 xattr_list = (char*)malloc(xattr_list_len + 1);
1170 memset(xattr_list, 0, xattr_list_len + 1);
1171
1172 /*
1173 * Get the actual list of extended attributes names for a file.
1174 */
1175 xattr_list_len
1176 = llistxattr(xattr_data->last_fname, xattr_list, xattr_list_len);
1177 switch (xattr_list_len) {
1178 case -1: {
1179 BErrNo be;
1180
1181 switch (errno) {
1182 case ENOENT:
1183 retval = BxattrExitCode::kSuccess;
1184 goto bail_out;
1185 default:
1186 Mmsg2(jcr->errmsg, _("llistxattr error on file \"%s\": ERR=%s\n"),
1187 xattr_data->last_fname, be.bstrerror());
1188 Dmsg2(100, "llistxattr error file=%s ERR=%s\n",
1189 xattr_data->last_fname, be.bstrerror());
1190 goto bail_out;
1191 }
1192 break;
1193 }
1194 default:
1195 break;
1196 }
1197 xattr_list[xattr_list_len] = '\0';
1198
1199 /*
1200 * Walk the list of extended attributes names and retrieve the data.
1201 * We already count the bytes needed for serializing the stream later on.
1202 */
1203 for (bp = xattr_list; (bp - xattr_list) + 1 < xattr_list_len;
1204 bp = strchr(bp, '\0') + 1) {
1205 skip_xattr = false;
1206
1207 /*
1208 * On some OSes you also get the acls in the extented attribute list.
1209 * So we check if we are already backing up acls and if we do we
1210 * don't store the extended attribute with the same info.
1211 */
1212 if (BitIsSet(FO_ACL, ff_pkt->flags)) {
1213 for (cnt = 0; xattr_acl_skiplist[cnt] != NULL; cnt++) {
1214 if (bstrcmp(bp, xattr_acl_skiplist[cnt])) {
1215 skip_xattr = true;
1216 break;
1217 }
1218 }
1219 }
1220
1221 /*
1222 * On some OSes we want to skip certain xattrs which are in the
1223 * xattr_skiplist array.
1224 */
1225 if (!skip_xattr) {
1226 for (cnt = 0; xattr_skiplist[cnt] != NULL; cnt++) {
1227 if (bstrcmp(bp, xattr_skiplist[cnt])) {
1228 skip_xattr = true;
1229 break;
1230 }
1231 }
1232 }
1233
1234 name_length = strlen(bp);
1235 if (skip_xattr || name_length == 0) {
1236 Dmsg1(100, "Skipping xattr named %s\n", bp);
1237 continue;
1238 }
1239
1240 /*
1241 * First see how long the value is for the extended attribute.
1242 */
1243 xattr_value_len = lgetxattr(xattr_data->last_fname, bp, NULL, 0);
1244 switch (xattr_value_len) {
1245 case -1: {
1246 BErrNo be;
1247
1248 switch (errno) {
1249 case ENOENT:
1250 retval = BxattrExitCode::kSuccess;
1251 goto bail_out;
1252 default:
1253 Mmsg2(jcr->errmsg, _("lgetxattr error on file \"%s\": ERR=%s\n"),
1254 xattr_data->last_fname, be.bstrerror());
1255 Dmsg2(100, "lgetxattr error file=%s ERR=%s\n",
1256 xattr_data->last_fname, be.bstrerror());
1257 goto bail_out;
1258 }
1259 break;
1260 }
1261 default:
1262 break;
1263 }
1264
1265 /*
1266 * Each xattr valuepair starts with a magic so we can parse it easier.
1267 */
1268 current_xattr = (xattr_t*)malloc(sizeof(xattr_t));
1269 current_xattr->magic = XATTR_MAGIC;
1270 current_xattr->value = NULL;
1271 expected_serialize_len += sizeof(current_xattr->magic);
1272
1273 /*
1274 * Allocate space for storing the name.
1275 */
1276 current_xattr->name_length = name_length;
1277 current_xattr->name = (char*)malloc(current_xattr->name_length);
1278 memcpy(current_xattr->name, bp, current_xattr->name_length);
1279
1280 expected_serialize_len
1281 += sizeof(current_xattr->name_length) + current_xattr->name_length;
1282
1283 switch (xattr_value_len) {
1284 case 0:
1285 current_xattr->value = NULL;
1286 current_xattr->value_length = 0;
1287 expected_serialize_len += sizeof(current_xattr->value_length);
1288 break;
1289 default:
1290 /*
1291 * Allocate space for storing the value.
1292 */
1293 current_xattr->value = (char*)malloc(xattr_value_len);
1294 memset(current_xattr->value, 0, xattr_value_len);
1295
1296 xattr_value_len = lgetxattr(xattr_data->last_fname, bp,
1297 current_xattr->value, xattr_value_len);
1298 if (xattr_value_len < 0) {
1299 BErrNo be;
1300
1301 switch (errno) {
1302 case ENOENT:
1303 retval = BxattrExitCode::kSuccess;
1304 break;
1305 default:
1306 Mmsg2(jcr->errmsg, _("lgetxattr error on file \"%s\": ERR=%s\n"),
1307 xattr_data->last_fname, be.bstrerror());
1308 Dmsg2(100, "lgetxattr error file=%s ERR=%s\n",
1309 xattr_data->last_fname, be.bstrerror());
1310 break;
1311 }
1312
1313 /*
1314 * Default failure path out when retrieval of attr fails.
1315 */
1316 free(current_xattr->value);
1317 free(current_xattr->name);
1318 free(current_xattr);
1319 goto bail_out;
1320 }
1321 /*
1322 * Store the actual length of the value.
1323 */
1324 current_xattr->value_length = xattr_value_len;
1325 expected_serialize_len += sizeof(current_xattr->value_length)
1326 + current_xattr->value_length;
1327 break;
1328 }
1329
1330 if (xattr_value_list == NULL) {
1331 xattr_value_list = new alist(10, not_owned_by_alist);
1332 }
1333
1334 xattr_value_list->append(current_xattr);
1335 xattr_count++;
1336
1337 /*
1338 * Protect ourself against things getting out of hand.
1339 */
1340 if (expected_serialize_len >= MAX_XATTR_STREAM) {
1341 Mmsg2(jcr->errmsg,
1342 _("Xattr stream on file \"%s\" exceeds maximum size of %d bytes\n"),
1343 xattr_data->last_fname, MAX_XATTR_STREAM);
1344 goto bail_out;
1345 }
1346 }
1347
1348 free(xattr_list);
1349 xattr_list = (char*)NULL;
1350
1351 /*
1352 * If we found any xattr send them to the SD.
1353 */
1354 if (xattr_count > 0) {
1355 /*
1356 * Serialize the datastream.
1357 */
1358 if (SerializeXattrStream(jcr, xattr_data, expected_serialize_len,
1359 xattr_value_list)
1360 < expected_serialize_len) {
1361 Mmsg1(jcr->errmsg,
1362 _("Failed to Serialize extended attributes on file \"%s\"\n"),
1363 xattr_data->last_fname);
1364 Dmsg1(100, "Failed to Serialize extended attributes on file \"%s\"\n",
1365 xattr_data->last_fname);
1366 goto bail_out;
1367 }
1368
1369 /*
1370 * Send the datastream to the SD.
1371 */
1372 retval = SendXattrStream(jcr, xattr_data, os_default_xattr_streams[0]);
1373 } else {
1374 retval = BxattrExitCode::kSuccess;
1375 }
1376
1377 bail_out:
1378 if (xattr_list != NULL) { free(xattr_list); }
1379 if (xattr_value_list != NULL) { XattrDropInternalTable(xattr_value_list); }
1380
1381 return retval;
1382 }
1383
generic_parse_xattr_streams(JobControlRecord * jcr,XattrData * xattr_data,int stream,char * content,uint32_t content_length)1384 static BxattrExitCode generic_parse_xattr_streams(JobControlRecord* jcr,
1385 XattrData* xattr_data,
1386 int stream,
1387 char* content,
1388 uint32_t content_length)
1389 {
1390 xattr_t* current_xattr = nullptr;
1391 alist* xattr_value_list;
1392 BxattrExitCode retval = BxattrExitCode::kError;
1393
1394 xattr_value_list = new alist(10, not_owned_by_alist);
1395
1396 if (UnSerializeXattrStream(jcr, xattr_data, content, content_length,
1397 xattr_value_list)
1398 != BxattrExitCode::kSuccess) {
1399 goto bail_out;
1400 }
1401
1402 foreach_alist (current_xattr, xattr_value_list) {
1403 if (lsetxattr(xattr_data->last_fname, current_xattr->name,
1404 current_xattr->value, current_xattr->value_length, 0)
1405 != 0) {
1406 BErrNo be;
1407
1408 switch (errno) {
1409 case ENOENT:
1410 goto bail_out;
1411 case BXATTR_ENOTSUP:
1412 /*
1413 * If the filesystem reports it doesn't support XATTRs we clear
1414 * the BXATTR_FLAG_RESTORE_NATIVE flag so we skip XATTR restores
1415 * on all other files on the same filesystem. The
1416 * BXATTR_FLAG_RESTORE_NATIVE flags gets sets again when we
1417 * change from one filesystem to another.
1418 */
1419 xattr_data->flags &= ~BXATTR_FLAG_RESTORE_NATIVE;
1420 retval = BxattrExitCode::kWarning;
1421 Mmsg(jcr->errmsg, error_message_disabling_xattributes.c_str(),
1422 xattr_data->last_fname);
1423 Dmsg1(100, error_message_disabling_xattributes.c_str(),
1424 xattr_data->last_fname);
1425 goto bail_out;
1426 default:
1427 Mmsg2(jcr->errmsg, _("lsetxattr error on file \"%s\": ERR=%s\n"),
1428 xattr_data->last_fname, be.bstrerror());
1429 Dmsg2(100, "lsetxattr error file=%s ERR=%s\n", xattr_data->last_fname,
1430 be.bstrerror());
1431 goto bail_out;
1432 }
1433 }
1434 }
1435
1436 retval = BxattrExitCode::kSuccess;
1437
1438 bail_out:
1439 XattrDropInternalTable(xattr_value_list);
1440
1441 return retval;
1442 }
1443
1444 /**
1445 * Function pointers to the build and parse function to use for these xattrs.
1446 */
1447 static BxattrExitCode (*os_build_xattr_streams)(JobControlRecord* jcr,
1448 XattrData* xattr_data,
1449 FindFilesPacket* ff_pkt)
1450 = generic_build_xattr_streams;
1451 static BxattrExitCode (*os_parse_xattr_streams)(JobControlRecord* jcr,
1452 XattrData* xattr_data,
1453 int stream,
1454 char* content,
1455 uint32_t content_length)
1456 = generic_parse_xattr_streams;
1457
1458 # elif defined(HAVE_FREEBSD_OS) || defined(HAVE_NETBSD_OS) \
1459 || defined(HAVE_OPENBSD_OS)
1460
1461 # if (!defined(HAVE_EXTATTR_GET_LINK) && !defined(HAVE_EXTATTR_GET_FILE)) \
1462 || (!defined(HAVE_EXTATTR_SET_LINK) \
1463 && !defined(HAVE_EXTATTR_SET_FILE)) \
1464 || (!defined(HAVE_EXTATTR_LIST_LINK) \
1465 && !defined(HAVE_EXTATTR_LIST_FILE)) \
1466 || !defined(HAVE_EXTATTR_NAMESPACE_TO_STRING) \
1467 || !defined(HAVE_EXTATTR_STRING_TO_NAMESPACE)
1468 # error "Missing full support for the extattr functions."
1469 # endif
1470
1471 # ifdef HAVE_SYS_EXTATTR_H
1472 # include <sys/extattr.h>
1473 # else
1474 # error "Missing sys/extattr.h header file"
1475 # endif
1476
1477 # ifdef HAVE_LIBUTIL_H
1478 # include <libutil.h>
1479 # endif
1480
1481 # if !defined(HAVE_EXTATTR_GET_LINK) && defined(HAVE_EXTATTR_GET_FILE)
1482 # define extattr_get_link extattr_get_file
1483 # endif
1484 # if !defined(HAVE_EXTATTR_SET_LINK) && defined(HAVE_EXTATTR_SET_FILE)
1485 # define extattr_set_link extattr_set_file
1486 # endif
1487 # if !defined(HAVE_EXTATTR_LIST_LINK) && defined(HAVE_EXTATTR_LIST_FILE)
1488 # define extattr_list_link extattr_list_file
1489 # endif
1490
1491 # if defined(HAVE_FREEBSD_OS)
1492 static int os_default_xattr_streams[1] = {STREAM_XATTR_FREEBSD};
1493 static int os_default_xattr_namespaces[2]
1494 = {EXTATTR_NAMESPACE_USER, EXTATTR_NAMESPACE_SYSTEM};
1495 static const char* xattr_acl_skiplist[4]
1496 = {"system.posix1e.acl_access", "system.posix1e.acl_default",
1497 "system.nfs4.acl", NULL};
1498 static const char* xattr_skiplist[1] = {NULL};
1499 # elif defined(HAVE_NETBSD_OS)
1500 static int os_default_xattr_streams[1] = {STREAM_XATTR_NETBSD};
1501 static int os_default_xattr_namespaces[2]
1502 = {EXTATTR_NAMESPACE_USER, EXTATTR_NAMESPACE_SYSTEM};
1503 static const char* xattr_acl_skiplist[1] = {NULL};
1504 static const char* xattr_skiplist[1] = {NULL};
1505 # elif defined(HAVE_OPENBSD_OS)
1506 static int os_default_xattr_streams[1] = {STREAM_XATTR_OPENBSD};
1507 static int os_default_xattr_namespaces[2]
1508 = {EXTATTR_NAMESPACE_USER, EXTATTR_NAMESPACE_SYSTEM};
1509 static const char* xattr_acl_skiplist[1] = {NULL};
1510 static const char* xattr_skiplist[1] = {NULL};
1511 # endif
1512
bsd_build_xattr_streams(JobControlRecord * jcr,XattrData * xattr_data,FindFilesPacket * ff_pkt)1513 static BxattrExitCode bsd_build_xattr_streams(JobControlRecord* jcr,
1514 XattrData* xattr_data,
1515 FindFilesPacket* ff_pkt)
1516 {
1517 bool skip_xattr;
1518 char* xattr_list = NULL;
1519 int cnt, index, xattr_count = 0;
1520 int32_t xattr_list_len, xattr_value_len;
1521 uint32_t expected_serialize_len = 0;
1522 unsigned int namespace_index;
1523 int attrnamespace;
1524 char* current_attrnamespace = NULL;
1525 char current_attrname[XATTR_BUFSIZ], current_attrtuple[XATTR_BUFSIZ];
1526 xattr_t* current_xattr;
1527 alist* xattr_value_list = NULL;
1528 BxattrExitCode retval = BxattrExitCode::kError;
1529
1530 /*
1531 * Loop over all available xattr namespaces.
1532 */
1533 for (namespace_index = 0;
1534 namespace_index < sizeof(os_default_xattr_namespaces) / sizeof(int);
1535 namespace_index++) {
1536 attrnamespace = os_default_xattr_namespaces[namespace_index];
1537
1538 /*
1539 * First get the length of the available list with extended attributes.
1540 * If we get EPERM on system namespace, don't return error.
1541 * This is expected for normal users trying to archive the system
1542 * namespace on FreeBSD 6.2 and later. On NetBSD 3.1 and later,
1543 * they've decided to return EOPNOTSUPP instead.
1544 */
1545 xattr_list_len
1546 = extattr_list_link(xattr_data->last_fname, attrnamespace, NULL, 0);
1547 switch (xattr_list_len) {
1548 case -1: {
1549 BErrNo be;
1550
1551 switch (errno) {
1552 case ENOENT:
1553 retval = BxattrExitCode::kSuccess;
1554 goto bail_out;
1555 # if defined(EOPNOTSUPP)
1556 case EOPNOTSUPP:
1557 # endif
1558 case EPERM:
1559 if (attrnamespace == EXTATTR_NAMESPACE_SYSTEM) { continue; }
1560 /*
1561 * FALLTHROUGH
1562 */
1563 default:
1564 Mmsg2(jcr->errmsg,
1565 _("extattr_list_link error on file \"%s\": ERR=%s\n"),
1566 xattr_data->last_fname, be.bstrerror());
1567 Dmsg2(100, "extattr_list_link error file=%s ERR=%s\n",
1568 xattr_data->last_fname, be.bstrerror());
1569 goto bail_out;
1570 }
1571 break;
1572 }
1573 case 0:
1574 continue;
1575 default:
1576 break;
1577 }
1578
1579 /*
1580 * Allocate room for the extented attribute list.
1581 */
1582 xattr_list = (char*)malloc(xattr_list_len + 1);
1583 memset(xattr_list, 0, xattr_list_len + 1);
1584
1585 /*
1586 * Get the actual list of extended attributes names for a file.
1587 */
1588 xattr_list_len = extattr_list_link(xattr_data->last_fname, attrnamespace,
1589 xattr_list, xattr_list_len);
1590 switch (xattr_list_len) {
1591 case -1: {
1592 BErrNo be;
1593
1594 switch (errno) {
1595 case ENOENT:
1596 retval = BxattrExitCode::kSuccess;
1597 goto bail_out;
1598 default:
1599 Mmsg2(jcr->errmsg,
1600 _("extattr_list_link error on file \"%s\": ERR=%s\n"),
1601 xattr_data->last_fname, be.bstrerror());
1602 Dmsg2(100, "extattr_list_link error file=%s ERR=%s\n",
1603 xattr_data->last_fname, be.bstrerror());
1604 goto bail_out;
1605 }
1606 break;
1607 }
1608 default:
1609 break;
1610 }
1611 xattr_list[xattr_list_len] = '\0';
1612
1613 /*
1614 * Convert the numeric attrnamespace into a string representation and make
1615 * a private copy of that string. The extattr_namespace_to_string functions
1616 * returns a strdupped string which we need to free.
1617 */
1618 if (extattr_namespace_to_string(attrnamespace, ¤t_attrnamespace)
1619 != 0) {
1620 Mmsg2(jcr->errmsg,
1621 _("Failed to convert %d into namespace on file \"%s\"\n"),
1622 attrnamespace, xattr_data->last_fname);
1623 Dmsg2(100, "Failed to convert %d into namespace on file \"%s\"\n",
1624 attrnamespace, xattr_data->last_fname);
1625 goto bail_out;
1626 }
1627
1628 /*
1629 * Walk the list of extended attributes names and retrieve the data.
1630 * We already count the bytes needed for serializing the stream later on.
1631 */
1632 for (index = 0; index < xattr_list_len; index += xattr_list[index] + 1) {
1633 skip_xattr = false;
1634
1635 /*
1636 * Print the current name into the buffer as its not null terminated
1637 * we need to use the length encoded in the string for copying only
1638 * the needed bytes.
1639 */
1640 cnt = xattr_list[index];
1641 if (cnt > ((int)sizeof(current_attrname) - 1)) {
1642 cnt = ((int)sizeof(current_attrname) - 1);
1643 }
1644 strncpy(current_attrname, xattr_list + (index + 1), cnt);
1645 current_attrname[cnt] = '\0';
1646
1647 /*
1648 * First make a xattr tuple of the current namespace and the name of
1649 * the xattr. e.g. something like user.<attrname> or system.<attrname>
1650 */
1651 Bsnprintf(current_attrtuple, sizeof(current_attrtuple), "%s.%s",
1652 current_attrnamespace, current_attrname);
1653
1654 /*
1655 * On some OSes you also get the acls in the extented attribute list.
1656 * So we check if we are already backing up acls and if we do we
1657 * don't store the extended attribute with the same info.
1658 */
1659 if (BitIsSet(FO_ACL, ff_pkt->flags)) {
1660 for (cnt = 0; xattr_acl_skiplist[cnt] != NULL; cnt++) {
1661 if (bstrcmp(current_attrtuple, xattr_acl_skiplist[cnt])) {
1662 skip_xattr = true;
1663 break;
1664 }
1665 }
1666 }
1667
1668 /*
1669 * On some OSes we want to skip certain xattrs which are in the
1670 * xattr_skiplist array.
1671 */
1672 if (!skip_xattr) {
1673 for (cnt = 0; xattr_skiplist[cnt] != NULL; cnt++) {
1674 if (bstrcmp(current_attrtuple, xattr_skiplist[cnt])) {
1675 skip_xattr = true;
1676 break;
1677 }
1678 }
1679 }
1680
1681 if (skip_xattr) {
1682 Dmsg1(100, "Skipping xattr named %s\n", current_attrname);
1683 continue;
1684 }
1685
1686 /*
1687 * First see how long the value is for the extended attribute.
1688 */
1689 xattr_value_len = extattr_get_link(xattr_data->last_fname, attrnamespace,
1690 current_attrname, NULL, 0);
1691 switch (xattr_value_len) {
1692 case -1: {
1693 BErrNo be;
1694
1695 switch (errno) {
1696 case ENOENT:
1697 retval = BxattrExitCode::kSuccess;
1698 goto bail_out;
1699 default:
1700 Mmsg2(jcr->errmsg,
1701 _("extattr_get_link error on file \"%s\": ERR=%s\n"),
1702 xattr_data->last_fname, be.bstrerror());
1703 Dmsg2(100, "extattr_get_link error file=%s ERR=%s\n",
1704 xattr_data->last_fname, be.bstrerror());
1705 goto bail_out;
1706 }
1707 break;
1708 }
1709 default:
1710 break;
1711 }
1712
1713 /*
1714 * Each xattr valuepair starts with a magic so we can parse it easier.
1715 */
1716 current_xattr = (xattr_t*)malloc(sizeof(xattr_t));
1717 current_xattr->magic = XATTR_MAGIC;
1718 current_xattr->value = NULL;
1719 expected_serialize_len += sizeof(current_xattr->magic);
1720
1721 /*
1722 * Allocate space for storing the name.
1723 */
1724 current_xattr->name_length = strlen(current_attrtuple);
1725 current_xattr->name = (char*)malloc(current_xattr->name_length);
1726 memcpy(current_xattr->name, current_attrtuple,
1727 current_xattr->name_length);
1728
1729 expected_serialize_len
1730 += sizeof(current_xattr->name_length) + current_xattr->name_length;
1731
1732 switch (xattr_value_len) {
1733 case 0:
1734 current_xattr->value = NULL;
1735 current_xattr->value_length = 0;
1736 expected_serialize_len += sizeof(current_xattr->value_length);
1737 break;
1738 default:
1739 /*
1740 * Allocate space for storing the value.
1741 */
1742 current_xattr->value = (char*)malloc(xattr_value_len);
1743 memset(current_xattr->value, 0, xattr_value_len);
1744
1745 xattr_value_len = extattr_get_link(
1746 xattr_data->last_fname, attrnamespace, current_attrname,
1747 current_xattr->value, xattr_value_len);
1748 if (xattr_value_len < 0) {
1749 BErrNo be;
1750
1751 switch (errno) {
1752 case ENOENT:
1753 retval = BxattrExitCode::kSuccess;
1754 break;
1755 default:
1756 Mmsg2(jcr->errmsg,
1757 _("extattr_get_link error on file \"%s\": ERR=%s\n"),
1758 xattr_data->last_fname, be.bstrerror());
1759 Dmsg2(100, "extattr_get_link error file=%s ERR=%s\n",
1760 xattr_data->last_fname, be.bstrerror());
1761 break;
1762 }
1763
1764 /*
1765 * Default failure path out when retrieval of attr fails.
1766 */
1767 free(current_xattr->value);
1768 free(current_xattr->name);
1769 free(current_xattr);
1770 goto bail_out;
1771 }
1772
1773 /*
1774 * Store the actual length of the value.
1775 */
1776 current_xattr->value_length = xattr_value_len;
1777 expected_serialize_len += sizeof(current_xattr->value_length)
1778 + current_xattr->value_length;
1779 break;
1780 }
1781
1782 if (xattr_value_list == NULL) {
1783 xattr_value_list = new alist(10, not_owned_by_alist);
1784 }
1785
1786 xattr_value_list->append(current_xattr);
1787 xattr_count++;
1788
1789 /*
1790 * Protect ourself against things getting out of hand.
1791 */
1792 if (expected_serialize_len >= MAX_XATTR_STREAM) {
1793 Mmsg2(
1794 jcr->errmsg,
1795 _("Xattr stream on file \"%s\" exceeds maximum size of %d bytes\n"),
1796 xattr_data->last_fname, MAX_XATTR_STREAM);
1797 goto bail_out;
1798 }
1799 }
1800
1801 /*
1802 * Drop the local copy of the current_attrnamespace.
1803 */
1804 free(current_attrnamespace);
1805 current_attrnamespace = NULL;
1806
1807 /*
1808 * We are done with this xattr list.
1809 */
1810 free(xattr_list);
1811 xattr_list = (char*)NULL;
1812 }
1813
1814 /*
1815 * If we found any xattr send them to the SD.
1816 */
1817 if (xattr_count > 0) {
1818 /*
1819 * Serialize the datastream.
1820 */
1821 if (SerializeXattrStream(jcr, xattr_data, expected_serialize_len,
1822 xattr_value_list)
1823 < expected_serialize_len) {
1824 Mmsg1(jcr->errmsg,
1825 _("Failed to Serialize extended attributes on file \"%s\"\n"),
1826 xattr_data->last_fname);
1827 Dmsg1(100, "Failed to Serialize extended attributes on file \"%s\"\n",
1828 xattr_data->last_fname);
1829 goto bail_out;
1830 }
1831
1832 /*
1833 * Send the datastream to the SD.
1834 */
1835 retval = SendXattrStream(jcr, xattr_data, os_default_xattr_streams[0]);
1836 } else {
1837 retval = BxattrExitCode::kSuccess;
1838 }
1839
1840 bail_out:
1841 if (current_attrnamespace != NULL) { free(current_attrnamespace); }
1842 if (xattr_list != NULL) { free(xattr_list); }
1843 if (xattr_value_list != NULL) { XattrDropInternalTable(xattr_value_list); }
1844
1845 return retval;
1846 }
1847
bsd_parse_xattr_streams(JobControlRecord * jcr,XattrData * xattr_data,int stream,char * content,uint32_t content_length)1848 static BxattrExitCode bsd_parse_xattr_streams(JobControlRecord* jcr,
1849 XattrData* xattr_data,
1850 int stream,
1851 char* content,
1852 uint32_t content_length)
1853 {
1854 xattr_t* current_xattr = nullptr;
1855 alist* xattr_value_list;
1856 int current_attrnamespace, cnt;
1857 char *attrnamespace, *attrname;
1858 BxattrExitCode retval = BxattrExitCode::kError;
1859
1860 xattr_value_list = new alist(10, not_owned_by_alist);
1861
1862 if (UnSerializeXattrStream(jcr, xattr_data, content, content_length,
1863 xattr_value_list)
1864 != BxattrExitCode::kSuccess) {
1865 goto bail_out;
1866 }
1867
1868 foreach_alist (current_xattr, xattr_value_list) {
1869 /*
1870 * Try splitting the xattr_name into a namespace and name part.
1871 * The splitting character is a .
1872 */
1873 attrnamespace = current_xattr->name;
1874 if ((attrname = strchr(attrnamespace, '.')) == (char*)NULL) {
1875 Mmsg2(
1876 jcr->errmsg,
1877 _("Failed to split %s into namespace and name part on file \"%s\"\n"),
1878 current_xattr->name, xattr_data->last_fname);
1879 Dmsg2(100,
1880 "Failed to split %s into namespace and name part on file \"%s\"\n",
1881 current_xattr->name, xattr_data->last_fname);
1882 goto bail_out;
1883 }
1884 *attrname++ = '\0';
1885
1886 /*
1887 * Make sure the attrnamespace makes sense.
1888 */
1889 if (extattr_string_to_namespace(attrnamespace, ¤t_attrnamespace)
1890 != 0) {
1891 Mmsg2(jcr->errmsg,
1892 _("Failed to convert %s into namespace on file \"%s\"\n"),
1893 attrnamespace, xattr_data->last_fname);
1894 Dmsg2(100, "Failed to convert %s into namespace on file \"%s\"\n",
1895 attrnamespace, xattr_data->last_fname);
1896 goto bail_out;
1897 }
1898
1899 /*
1900 * Try restoring the extended attribute.
1901 */
1902 cnt = extattr_set_link(xattr_data->last_fname, current_attrnamespace,
1903 attrname, current_xattr->value,
1904 current_xattr->value_length);
1905 if (cnt < 0 || cnt != (int)current_xattr->value_length) {
1906 BErrNo be;
1907
1908 switch (errno) {
1909 case ENOENT:
1910 goto bail_out;
1911 break;
1912 default:
1913 Mmsg2(jcr->errmsg,
1914 _("extattr_set_link error on file \"%s\": ERR=%s\n"),
1915 xattr_data->last_fname, be.bstrerror());
1916 Dmsg2(100, "extattr_set_link error file=%s ERR=%s\n",
1917 xattr_data->last_fname, be.bstrerror());
1918 goto bail_out;
1919 break;
1920 }
1921 }
1922 }
1923
1924 retval = BxattrExitCode::kSuccess;
1925
1926 bail_out:
1927 XattrDropInternalTable(xattr_value_list);
1928
1929 return retval;
1930 }
1931
1932 /**
1933 * Function pointers to the build and parse function to use for these xattrs.
1934 */
1935 static BxattrExitCode (*os_build_xattr_streams)(JobControlRecord* jcr,
1936 XattrData* xattr_data,
1937 FindFilesPacket* ff_pkt)
1938 = bsd_build_xattr_streams;
1939 static BxattrExitCode (*os_parse_xattr_streams)(JobControlRecord* jcr,
1940 XattrData* xattr_data,
1941 int stream,
1942 char* content,
1943 uint32_t content_length)
1944 = bsd_parse_xattr_streams;
1945
1946 # elif defined(HAVE_OSF1_OS)
1947
1948 # if !defined(HAVE_GETPROPLIST) || !defined(HAVE_GET_PROPLIST_ENTRY) \
1949 || !defined(HAVE_SIZEOF_PROPLIST_ENTRY) \
1950 || !defined(HAVE_ADD_PROPLIST_ENTRY) || !defined(HAVE_SETPROPLIST)
1951 # error "Missing full support for the Extended Attributes functions."
1952 # endif
1953
1954 # ifdef HAVE_SYS_PROPLIST_H
1955 # include <sys/proplist.h>
1956 # else
1957 # error "Missing sys/proplist.h header file"
1958 # endif
1959
1960 /**
1961 * Define the supported XATTR streams for this OS
1962 */
1963 static int os_default_xattr_streams[1] = {STREAM_XATTR_TRU64};
1964 static const char* xattr_acl_skiplist[1] = {NULL};
1965 static const char* xattr_skiplist[1] = {NULL};
1966
tru64_build_xattr_streams(JobControlRecord * jcr,XattrData * xattr_data,FindFilesPacket * ff_pkt)1967 static BxattrExitCode tru64_build_xattr_streams(JobControlRecord* jcr,
1968 XattrData* xattr_data,
1969 FindFilesPacket* ff_pkt)
1970 {
1971 int cnt;
1972 char *bp, *xattr_name, *xattr_value;
1973 bool skip_xattr;
1974 int xattr_count = 0;
1975 int32_t *flags, *xattr_value_len;
1976 int32_t xattr_list_len, xattrbuf_size, xattrbuf_min_size;
1977 uint32_t expected_serialize_len = 0;
1978 xattr_t* current_xattr;
1979 alist* xattr_value_list = NULL;
1980 struct proplistname_args prop_args;
1981 BxattrExitCode retval = BxattrExitCode::kError;
1982 POOLMEM* xattrbuf = GetPoolMemory(PM_MESSAGE);
1983
1984 xattrbuf_size = SizeofPoolMemory(xattrbuf);
1985 xattrbuf_min_size = 0;
1986 xattr_list_len = getproplist(xattr_data->last_fname, 1, &prop_args,
1987 xattrbuf_size, xattrbuf, &xattrbuf_min_size);
1988
1989 /*
1990 * See what xattr are available.
1991 */
1992 switch (xattr_list_len) {
1993 case -1: {
1994 BErrNo be;
1995
1996 switch (errno) {
1997 case EOPNOTSUPP:
1998 /*
1999 * If the filesystem reports it doesn't support XATTRs we clear
2000 * the BXATTR_FLAG_RESTORE_NATIVE flag so we skip XATTR restores
2001 * on all other files on the same filesystem. The
2002 * BXATTR_FLAG_RESTORE_NATIVE flags gets sets again when we
2003 * change from one filesystem to another.
2004 */
2005 xattr_data->flags &= ~BXATTR_FLAG_SAVE_NATIVE;
2006 retval = BxattrExitCode::kWarning;
2007 Mmsg(jcr->errmsg, error_message_disabling_xattributes.c_str(),
2008 xattr_data->last_fname);
2009 Dmsg2(100, error_message_disabling_xattributes.c_str(),
2010 xattr_data->last_fname);
2011 goto bail_out;
2012 default:
2013 Mmsg2(jcr->errmsg, _("getproplist error on file \"%s\": ERR=%s\n"),
2014 xattr_data->last_fname, be.bstrerror());
2015 Dmsg2(100, "getproplist error file=%s ERR=%s\n",
2016 xattr_data->last_fname, be.bstrerror());
2017 goto bail_out;
2018 }
2019 break;
2020 }
2021 case 0:
2022 if (xattrbuf_min_size) {
2023 /*
2024 * The buffer isn't big enough to hold the xattr data, we now have
2025 * a minimum buffersize so we resize the buffer and try again.
2026 */
2027 xattrbuf = CheckPoolMemorySize(xattrbuf, xattrbuf_min_size + 1);
2028 xattrbuf_size = xattrbuf_min_size + 1;
2029 xattr_list_len
2030 = getproplist(xattr_data->last_fname, 1, &prop_args, xattrbuf_size,
2031 xattrbuf, &xattrbuf_min_size);
2032 switch (xattr_list_len) {
2033 case -1: {
2034 BErrNo be;
2035
2036 switch (errno) {
2037 default:
2038 Mmsg2(jcr->errmsg,
2039 _("getproplist error on file \"%s\": ERR=%s\n"),
2040 xattr_data->last_fname, be.bstrerror());
2041 Dmsg2(100, "getproplist error file=%s ERR=%s\n",
2042 xattr_data->last_fname, be.bstrerror());
2043 goto bail_out;
2044 }
2045 break;
2046 }
2047 case 0:
2048 /*
2049 * This should never happen as we sized the buffer according to the
2050 * minimumsize returned by a previous getproplist call. If it does
2051 * happen things are fishy and we are better of forgetting this
2052 * xattr as it seems its list is changing at this exact moment so we
2053 * can never make a good backup copy of it.
2054 */
2055 retval = BxattrExitCode::kSuccess;
2056 goto bail_out;
2057 default:
2058 break;
2059 }
2060 } else {
2061 /*
2062 * No xattr on file.
2063 */
2064 retval = BxattrExitCode::kSuccess;
2065 goto bail_out;
2066 }
2067 break;
2068 default:
2069 break;
2070 }
2071
2072 /*
2073 * Walk the list of extended attributes names and retrieve the data.
2074 * We already count the bytes needed for serializing the stream later on.
2075 */
2076 bp = xattrbuf;
2077 while (xattrbuf_size > 0) {
2078 /*
2079 * Call getproplist_entry to initialize name and value
2080 * pointers to entries position within buffer.
2081 */
2082 xattrbuf_size -= get_proplist_entry(&xattr_name, &flags, &xattr_value_len,
2083 &xattr_value, &bp);
2084
2085 /*
2086 * On some OSes you also get the acls in the extented attribute list.
2087 * So we check if we are already backing up acls and if we do we
2088 * don't store the extended attribute with the same info.
2089 */
2090 if (BitIsSet(FO_ACL, ff_pkt->flags)) {
2091 for (cnt = 0; xattr_acl_skiplist[cnt] != NULL; cnt++) {
2092 if (bstrcmp(xattr_name, xattr_acl_skiplist[cnt])) {
2093 skip_xattr = true;
2094 break;
2095 }
2096 }
2097 }
2098
2099 /*
2100 * On some OSes we want to skip certain xattrs which are in the
2101 * xattr_skiplist array.
2102 */
2103 if (!skip_xattr) {
2104 for (cnt = 0; xattr_skiplist[cnt] != NULL; cnt++) {
2105 if (bstrcmp(xattr_name, xattr_skiplist[cnt])) {
2106 skip_xattr = true;
2107 break;
2108 }
2109 }
2110 }
2111
2112 if (skip_xattr) {
2113 Dmsg1(100, "Skipping xattr named %s\n", xattr_name);
2114 continue;
2115 }
2116
2117 /*
2118 * Each xattr valuepair starts with a magic so we can parse it easier.
2119 */
2120 current_xattr = (xattr_t*)malloc(sizeof(xattr_t));
2121 current_xattr->magic = XATTR_MAGIC;
2122 expected_serialize_len += sizeof(current_xattr->magic);
2123
2124 current_xattr->name_length = strlen(xattr_name);
2125 current_xattr->name = strdup(xattr_name);
2126
2127 expected_serialize_len
2128 += sizeof(current_xattr->name_length) + current_xattr->name_length;
2129
2130 current_xattr->value_length = *xattr_value_len;
2131 current_xattr->value = (char*)malloc(current_xattr->value_length);
2132 memcpy(current_xattr->value, xattr_value, current_xattr->value_length);
2133
2134 expected_serialize_len
2135 += sizeof(current_xattr->value_length) + current_xattr->value_length;
2136
2137 if (xattr_value_list == NULL) {
2138 xattr_value_list = new alist(10, not_owned_by_alist);
2139 }
2140
2141 xattr_value_list->append(current_xattr);
2142 xattr_count++;
2143
2144 /*
2145 * Protect ourself against things getting out of hand.
2146 */
2147 if (expected_serialize_len >= MAX_XATTR_STREAM) {
2148 Mmsg2(jcr->errmsg,
2149 _("Xattr stream on file \"%s\" exceeds maximum size of %d bytes\n"),
2150 xattr_data->last_fname, MAX_XATTR_STREAM);
2151 goto bail_out;
2152 }
2153 }
2154
2155 /*
2156 * If we found any xattr send them to the SD.
2157 */
2158 if (xattr_count > 0) {
2159 /*
2160 * Serialize the datastream.
2161 */
2162 if (SerializeXattrStream(jcr, xattr_data, expected_serialize_len,
2163 xattr_value_list)
2164 < expected_serialize_len) {
2165 Mmsg1(jcr->errmsg,
2166 _("Failed to Serialize extended attributes on file \"%s\"\n"),
2167 xattr_data->last_fname);
2168 Dmsg1(100, "Failed to Serialize extended attributes on file \"%s\"\n",
2169 xattr_data->last_fname);
2170 goto bail_out;
2171 }
2172
2173 /*
2174 * Send the datastream to the SD.
2175 */
2176 retval = SendXattrStream(jcr, xattr_data, os_default_xattr_streams[0]);
2177 } else {
2178 retval = BxattrExitCode::kSuccess;
2179 }
2180
2181 bail_out:
2182 if (xattr_value_list != NULL) { XattrDropInternalTable(xattr_value_list); }
2183 FreePoolMemory(xattrbuf);
2184
2185 return retval;
2186 }
2187
tru64_parse_xattr_streams(JobControlRecord * jcr,XattrData * xattr_data,int stream,char * content,uint32_t content_length)2188 static BxattrExitCode tru64_parse_xattr_streams(JobControlRecord* jcr,
2189 XattrData* xattr_data,
2190 int stream,
2191 char* content,
2192 uint32_t content_length)
2193 {
2194 char *bp, *xattrbuf = NULL;
2195 int32_t xattrbuf_size, cnt;
2196 xattr_t* current_xattr;
2197 alist* xattr_value_list;
2198 BxattrExitCode retval = BxattrExitCode::kError;
2199
2200 xattr_value_list = new alist(10, not_owned_by_alist);
2201
2202 if (UnSerializeXattrStream(jcr, xattr_data, content, content_length,
2203 xattr_value_list)
2204 != BxattrExitCode::kSuccess) {
2205 goto bail_out;
2206 }
2207
2208 /*
2209 * See how big the propertylist must be.
2210 */
2211 xattrbuf_size = 0;
2212 foreach_alist (current_xattr, xattr_value_list) {
2213 xattrbuf_size += sizeof_proplist_entry(current_xattr->name,
2214 current_xattr->value_length);
2215 }
2216
2217 xattrbuf = (char*)malloc(xattrbuf_size);
2218
2219 /*
2220 * Add all value pairs to the proplist.
2221 */
2222 cnt = 0;
2223 bp = xattrbuf;
2224 foreach_alist (current_xattr, xattr_value_list) {
2225 cnt = add_proplist_entry(current_xattr->name, 0,
2226 current_xattr->value_length, current_xattr->value,
2227 &bp);
2228 }
2229
2230 /*
2231 * Sanity check.
2232 */
2233 if (cnt != xattrbuf_size) {
2234 Mmsg1(jcr->errmsg,
2235 _("Unable create proper proplist to restore xattrs on file \"%s\"\n"),
2236 xattr_data->last_fname);
2237 Dmsg1(100,
2238 "Unable create proper proplist to restore xattrs on file \"%s\"\n",
2239 xattr_data->last_fname);
2240 goto bail_out;
2241 }
2242
2243 /*
2244 * Restore the list of extended attributes on the file.
2245 */
2246 cnt = setproplist(xattr_data->last_fname, 1, xattrbuf_size, xattrbuf);
2247 switch (cnt) {
2248 case -1: {
2249 BErrNo be;
2250
2251 switch (errno) {
2252 case EOPNOTSUPP:
2253 /*
2254 * If the filesystem reports it doesn't support XATTRs we clear
2255 * the BXATTR_FLAG_RESTORE_NATIVE flag so we skip XATTR restores
2256 * on all other files on the same filesystem. The
2257 * BXATTR_FLAG_RESTORE_NATIVE flags gets sets again when we
2258 * change from one filesystem to another.
2259 */
2260 xattr_data->flags &= ~BXATTR_FLAG_RESTORE_NATIVE;
2261 retval = BxattrExitCode::kWarning;
2262 Mmsg(jcr->errmsg, error_message_disabling_xattributes.c_str(),
2263 xattr_data->last_fname);
2264 Dmsg2(100, error_message_disabling_xattributes.c_str(),
2265 xattr_data->last_fname);
2266 goto bail_out;
2267 default:
2268 Mmsg2(jcr->errmsg, _("setproplist error on file \"%s\": ERR=%s\n"),
2269 xattr_data->last_fname, be.bstrerror());
2270 Dmsg2(100, "setproplist error file=%s ERR=%s\n",
2271 xattr_data->last_fname, be.bstrerror());
2272 goto bail_out;
2273 }
2274 break;
2275 }
2276 default:
2277 break;
2278 }
2279
2280 retval = BxattrExitCode::kSuccess;
2281
2282 bail_out:
2283 if (xattrbuf) { free(xattrbuf); }
2284 XattrDropInternalTable(xattr_value_list);
2285
2286 return retval;
2287 }
2288
2289 /**
2290 * Function pointers to the build and parse function to use for these xattrs.
2291 */
2292 static BxattrExitCode (*os_build_xattr_streams)(JobControlRecord* jcr,
2293 XattrData* xattr_data,
2294 FindFilesPacket* ff_pkt)
2295 = tru64_build_xattr_streams;
2296 static BxattrExitCode (*os_parse_xattr_streams)(JobControlRecord* jcr,
2297 XattrData* xattr_data,
2298 int stream,
2299 char* content,
2300 uint32_t content_length)
2301 = tru64_parse_xattr_streams;
2302
2303 # elif defined(HAVE_SUN_OS)
2304 /**
2305 * Solaris extended attributes were introduced in Solaris 9
2306 * by PSARC 1999/209
2307 *
2308 * Solaris extensible attributes were introduced in OpenSolaris
2309 * by PSARC 2007/315 Solaris extensible attributes are also
2310 * sometimes called extended system attributes.
2311 *
2312 * man fsattr(5) on Solaris gives a wealth of info. The most
2313 * important bits are:
2314 *
2315 * Attributes are logically supported as files within the file
2316 * system. The file system is therefore augmented with an
2317 * orthogonal name space of file attributes. Any file (includ-
2318 * ing attribute files) can have an arbitrarily deep attribute
2319 * tree associated with it. Attribute values are accessed by
2320 * file descriptors obtained through a special attribute inter-
2321 * face. This logical view of "attributes as files" allows the
2322 * leveraging of existing file system interface functionality
2323 * to support the construction, deletion, and manipulation of
2324 * attributes.
2325 *
2326 * The special files "." and ".." retain their accustomed
2327 * semantics within the attribute hierarchy. The "." attribute
2328 * file refers to the current directory and the ".." attribute
2329 * file refers to the parent directory. The unnamed directory
2330 * at the head of each attribute tree is considered the "child"
2331 * of the file it is associated with and the ".." file refers
2332 * to the associated file. For any non-directory file with
2333 * attributes, the ".." entry in the unnamed directory refers
2334 * to a file that is not a directory.
2335 *
2336 * Conceptually, the attribute model is fully general. Extended
2337 * attributes can be any type of file (doors, links, direc-
2338 * tories, and so forth) and can even have their own attributes
2339 * (fully recursive). As a result, the attributes associated
2340 * with a file could be an arbitrarily deep directory hierarchy
2341 * where each attribute could have an equally complex attribute
2342 * tree associated with it. Not all implementations are able
2343 * to, or want to, support the full model. Implementation are
2344 * therefore permitted to reject operations that are not sup-
2345 * ported. For example, the implementation for the UFS file
2346 * system allows only regular files as attributes (for example,
2347 * no sub-directories) and rejects attempts to place attributes
2348 * on attributes.
2349 *
2350 * The following list details the operations that are rejected
2351 * in the current implementation:
2352 *
2353 * link Any attempt to create links between
2354 * attribute and non-attribute space
2355 * is rejected to prevent security-
2356 * related or otherwise sensitive
2357 * attributes from being exposed, and
2358 * therefore manipulable, as regular
2359 * files.
2360 *
2361 * rename Any attempt to rename between
2362 * attribute and non-attribute space
2363 * is rejected to prevent an already
2364 * linked file from being renamed and
2365 * thereby circumventing the link res-
2366 * triction above.
2367 *
2368 * mkdir, symlink, mknod Any attempt to create a "non-
2369 * regular" file in attribute space is
2370 * rejected to reduce the functional-
2371 * ity, and therefore exposure and
2372 * risk, of the initial implementa-
2373 * tion.
2374 *
2375 * The entire available name space has been allocated to "gen-
2376 * eral use" to bring the implementation in line with the NFSv4
2377 * draft standard [NFSv4]. That standard defines "named attri-
2378 * butes" (equivalent to Solaris Extended Attributes) with no
2379 * naming restrictions. All Sun applications making use of
2380 * opaque extended attributes will use the prefix "SUNW".
2381 *
2382 */
2383 # ifdef HAVE_SYS_ATTR_H
2384 # include <sys/attr.h>
2385 # endif
2386
2387 # ifdef HAVE_ATTR_H
2388 # include <attr.h>
2389 # endif
2390
2391 # ifdef HAVE_SYS_NVPAIR_H
2392 # include <sys/nvpair.h>
2393 # endif
2394
2395 # ifdef HAVE_SYS_ACL_H
2396 # include <sys/acl.h>
2397 # endif
2398
2399 # if !defined(HAVE_OPENAT) || !defined(HAVE_UNLINKAT) \
2400 || !defined(HAVE_FCHOWNAT) || !defined(HAVE_FUTIMESAT)
2401 # error \
2402 "Unable to compile code because of missing openat, unlinkat, fchownat or futimesat function"
2403 # endif
2404
2405 /**
2406 * Define the supported XATTR streams for this OS
2407 */
2408 # if defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED)
2409 static int os_default_xattr_streams[2]
2410 = {STREAM_XATTR_SOLARIS, STREAM_XATTR_SOLARIS_SYS};
2411 # else
2412 static int os_default_xattr_streams[1] = {STREAM_XATTR_SOLARIS};
2413 # endif /* defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED) */
2414
2415 /**
2416 * This code creates a temporary cache with entries for each xattr which has
2417 * a link count > 1 (which indicates it has one or more hard linked
2418 * counterpart(s))
2419 */
find_xattr_link_cache_entry(XattrData * xattr_data,ino_t inum)2420 static inline xattr_link_cache_entry_t* find_xattr_link_cache_entry(
2421 XattrData* xattr_data,
2422 ino_t inum)
2423 {
2424 xattr_link_cache_entry_t* ptr;
2425
2426 foreach_alist (ptr, xattr_data->u.build->link_cache) {
2427 if (ptr && ptr->inum == inum) { return ptr; }
2428 }
2429 return NULL;
2430 }
2431
add_xattr_link_cache_entry(XattrData * xattr_data,ino_t inum,char * target)2432 static inline void add_xattr_link_cache_entry(XattrData* xattr_data,
2433 ino_t inum,
2434 char* target)
2435 {
2436 xattr_link_cache_entry_t* ptr;
2437
2438 ptr = (xattr_link_cache_entry_t*)malloc(sizeof(xattr_link_cache_entry_t));
2439 memset(ptr, 0, sizeof(xattr_link_cache_entry_t));
2440 ptr->inum = inum;
2441 ptr->target = strdup(target);
2442
2443 if (!xattr_data->u.build->link_cache) {
2444 xattr_data->u.build->link_cache = new alist(10, not_owned_by_alist);
2445 }
2446 xattr_data->u.build->link_cache->append(ptr);
2447 }
2448
DropXattrLinkCache(XattrData * xattr_data)2449 static inline void DropXattrLinkCache(XattrData* xattr_data)
2450 {
2451 xattr_link_cache_entry_t* ptr;
2452
2453 /*
2454 * Walk the list of xattr link cache entries and free allocated memory on
2455 * traversing.
2456 */
2457 foreach_alist (ptr, xattr_data->u.build->link_cache) {
2458 free(ptr->target);
2459 free(ptr);
2460 }
2461
2462 delete xattr_data->u.build->link_cache;
2463 xattr_data->u.build->link_cache = NULL;
2464 }
2465
2466 # if defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED)
2467 /**
2468 * This function returns true if a non default extended system attribute
2469 * list is associated with fd and returns false when an error has occured
2470 * or when only extended system attributes other than archive,
2471 * av_modified or crtime are set.
2472 *
2473 * The function returns true for the following cases:
2474 *
2475 * - any extended system attribute other than the default attributes
2476 * ('archive', 'av_modified' and 'crtime') is set
2477 * - nvlist has NULL name string
2478 * - nvpair has data type of 'nvlist'
2479 * - default data type.
2480 */
SolarisHasNonTransientExtensibleAttributes(int fd)2481 static bool SolarisHasNonTransientExtensibleAttributes(int fd)
2482 {
2483 boolean_t value;
2484 data_type_t type;
2485 nvlist_t* response;
2486 nvpair_t* pair;
2487 f_attr_t fattr;
2488 char* name;
2489 bool retval = false;
2490
2491 if (fgetattr(fd, XATTR_VIEW_READWRITE, &response) != 0) { return false; }
2492
2493 pair = NULL;
2494 while ((pair = nvlist_next_nvpair(response, pair)) != NULL) {
2495 name = nvpair_name(pair);
2496
2497 if (name != NULL) {
2498 fattr = name_to_attr(name);
2499 } else {
2500 retval = true;
2501 goto bail_out;
2502 }
2503
2504 type = nvpair_type(pair);
2505 switch (type) {
2506 case DATA_TYPE_BOOLEAN_VALUE:
2507 if (nvpair_value_boolean_value(pair, &value) != 0) { continue; }
2508 if (value && fattr != F_ARCHIVE && fattr != F_AV_MODIFIED) {
2509 retval = true;
2510 goto bail_out;
2511 }
2512 break;
2513 case DATA_TYPE_UINT64_ARRAY:
2514 if (fattr != F_CRTIME) {
2515 retval = true;
2516 goto bail_out;
2517 }
2518 break;
2519 case DATA_TYPE_NVLIST:
2520 default:
2521 retval = true;
2522 goto bail_out;
2523 }
2524 }
2525
2526 bail_out:
2527 if (response != NULL) { nvlist_free(response); }
2528 return retval;
2529 }
2530 # endif /* HAVE_SYS_NVPAIR_H && _PC_SATTR_ENABLED */
2531
2532 # if defined(HAVE_ACL) && !defined(HAVE_EXTENDED_ACL)
2533 /**
2534 * See if an acl is a trivial one (e.g. just the stat bits encoded as acl.)
2535 * There is no need to store those acls as we already store the stat bits too.
2536 */
AclIsTrivial(int count,aclent_t * entries)2537 static bool AclIsTrivial(int count, aclent_t* entries)
2538 {
2539 int n;
2540 aclent_t* ace;
2541
2542 for (n = 0; n < count; n++) {
2543 ace = &entries[n];
2544 if (!(ace->a_type == USER_OBJ || ace->a_type == GROUP_OBJ
2545 || ace->a_type == OTHER_OBJ || ace->a_type == CLASS_OBJ))
2546 return false;
2547 }
2548 return true;
2549 }
2550 # endif /* HAVE_ACL && !HAVE_EXTENDED_ACL */
2551
solaris_save_xattr_acl(JobControlRecord * jcr,XattrData * xattr_data,int fd,const char * attrname,char ** acl_text)2552 static BxattrExitCode solaris_save_xattr_acl(JobControlRecord* jcr,
2553 XattrData* xattr_data,
2554 int fd,
2555 const char* attrname,
2556 char** acl_text)
2557 {
2558 BxattrExitCode retval = BxattrExitCode::kError;
2559 # ifdef HAVE_ACL
2560 # ifdef HAVE_EXTENDED_ACL
2561 int flags;
2562 acl_t* aclp = NULL;
2563
2564 /*
2565 * See if this attribute has an ACL
2566 */
2567 if ((fd != -1 && fpathconf(fd, _PC_ACL_ENABLED) > 0)
2568 || pathconf(attrname, _PC_ACL_ENABLED) > 0) {
2569 /*
2570 * See if there is a non trivial acl on the file.
2571 */
2572 if ((fd != -1 && facl_get(fd, ACL_NO_TRIVIAL, &aclp) != 0)
2573 || acl_get(attrname, ACL_NO_TRIVIAL, &aclp) != 0) {
2574 BErrNo be;
2575
2576 switch (errno) {
2577 case ENOENT:
2578 retval = BxattrExitCode::kSuccess;
2579 goto bail_out;
2580 default:
2581 Mmsg3(jcr->errmsg,
2582 _("Unable to get acl on xattr %s on file \"%s\": ERR=%s\n"),
2583 attrname, xattr_data->last_fname, be.bstrerror());
2584 Dmsg3(100, "facl_get/acl_get of xattr %s on \"%s\" failed: ERR=%s\n",
2585 attrname, xattr_data->last_fname, be.bstrerror());
2586 goto bail_out;
2587 }
2588 }
2589
2590 if (aclp != NULL) {
2591 # if defined(ACL_SID_FMT)
2592 /*
2593 * New format flag added in newer Solaris versions.
2594 */
2595 flags = ACL_APPEND_ID | ACL_COMPACT_FMT | ACL_SID_FMT;
2596 # else
2597 flags = ACL_APPEND_ID | ACL_COMPACT_FMT;
2598 # endif /* ACL_SID_FMT */
2599
2600 *acl_text = acl_totext(aclp, flags);
2601 acl_free(aclp);
2602 } else {
2603 *acl_text = NULL;
2604 }
2605 } else {
2606 *acl_text = NULL;
2607 }
2608 retval = BxattrExitCode::kSuccess;
2609 # else /* HAVE_EXTENDED_ACL */
2610 int n;
2611 aclent_t* acls = NULL;
2612
2613 /*
2614 * See if this attribute has an ACL
2615 */
2616 if (fd != -1) {
2617 n = facl(fd, GETACLCNT, 0, NULL);
2618 } else {
2619 n = acl(attrname, GETACLCNT, 0, NULL);
2620 }
2621
2622 if (n >= MIN_ACL_ENTRIES) {
2623 acls = (aclent_t*)malloc(n * sizeof(aclent_t));
2624 if ((fd != -1 && facl(fd, GETACL, n, acls) != n)
2625 || acl(attrname, GETACL, n, acls) != n) {
2626 BErrNo be;
2627
2628 switch (errno) {
2629 case ENOENT:
2630 free(acls);
2631 retval = BxattrExitCode::kSuccess;
2632 goto bail_out;
2633 default:
2634 Mmsg3(jcr->errmsg,
2635 _("Unable to get acl on xattr %s on file \"%s\": ERR=%s\n"),
2636 attrname, xattr_data->last_fname, be.bstrerror());
2637 Dmsg3(100, "facl/acl of xattr %s on \"%s\" failed: ERR=%s\n",
2638 attrname, xattr_data->last_fname, be.bstrerror());
2639 free(acls);
2640 goto bail_out;
2641 }
2642 }
2643
2644 /*
2645 * See if there is a non trivial acl on the file.
2646 */
2647 if (!AclIsTrivial(n, acls)) {
2648 if ((*acl_text = acltotext(acls, n)) == NULL) {
2649 BErrNo be;
2650
2651 Mmsg3(jcr->errmsg,
2652 _("Unable to get acl text on xattr %s on file \"%s\": ERR=%s\n"),
2653 attrname, xattr_data->last_fname, be.bstrerror());
2654 Dmsg3(100, "acltotext of xattr %s on \"%s\" failed: ERR=%s\n", attrname,
2655 xattr_data->last_fname, be.bstrerror());
2656 free(acls);
2657 goto bail_out;
2658 }
2659 } else {
2660 *acl_text = NULL;
2661 }
2662
2663 free(acls);
2664 } else {
2665 *acl_text = NULL;
2666 }
2667 retval = BxattrExitCode::kSuccess;
2668 # endif /* HAVE_EXTENDED_ACL */
2669
2670 # else /* HAVE_ACL */
2671 retval = BxattrExitCode::kSuccess;
2672 # endif /* HAVE_ACL */
2673
2674 bail_out:
2675 return retval;
2676 }
2677
2678 /**
2679 * Forward declaration for recursive function call.
2680 */
2681 static BxattrExitCode solaris_save_xattrs(JobControlRecord* jcr,
2682 XattrData* xattr_data,
2683 const char* xattr_namespace,
2684 const char* attr_parent);
2685
2686 /**
2687 * Save an extended or extensible attribute.
2688 * This is stored as an opaque stream of bytes with the following encoding:
2689 *
2690 * <xattr_name>\0<stat_buffer>\0<acl_string>\0<actual_xattr_data>
2691 *
2692 * or for a hardlinked or symlinked attribute
2693 *
2694 * <xattr_name>\0<stat_buffer>\0<xattr_link_source>\0
2695 *
2696 * xattr_name can be a subpath relative to the file the xattr is on.
2697 * stat_buffer is the string representation of the stat struct.
2698 * acl_string is an acl text when a non trivial acl is set on the xattr.
2699 * actual_xattr_data is the content of the xattr file.
2700 */
solaris_save_xattr(JobControlRecord * jcr,XattrData * xattr_data,int fd,const char * xattr_namespace,const char * attrname,bool toplevel_hidden_dir,int stream)2701 static BxattrExitCode solaris_save_xattr(JobControlRecord* jcr,
2702 XattrData* xattr_data,
2703 int fd,
2704 const char* xattr_namespace,
2705 const char* attrname,
2706 bool toplevel_hidden_dir,
2707 int stream)
2708 {
2709 int cnt;
2710 int attrfd = -1;
2711 struct stat st;
2712 xattr_link_cache_entry_t* xlce;
2713 char target_attrname[PATH_MAX];
2714 char link_source[PATH_MAX];
2715 char* acl_text = NULL;
2716 char attribs[XATTR_BUFSIZ];
2717 char buffer[XATTR_BUFSIZ];
2718 BxattrExitCode retval = BxattrExitCode::kError;
2719
2720 Bsnprintf(target_attrname, sizeof(target_attrname), "%s%s", xattr_namespace,
2721 attrname);
2722
2723 /*
2724 * Get the stats of the extended or extensible attribute.
2725 */
2726 if (fstatat(fd, attrname, &st, AT_SYMLINK_NOFOLLOW) < 0) {
2727 BErrNo be;
2728
2729 switch (errno) {
2730 case ENOENT:
2731 retval = BxattrExitCode::kSuccess;
2732 goto bail_out;
2733 default:
2734 Mmsg3(jcr->errmsg,
2735 _("Unable to get status on xattr %s on file \"%s\": ERR=%s\n"),
2736 target_attrname, xattr_data->last_fname, be.bstrerror());
2737 Dmsg3(100, "fstatat of xattr %s on \"%s\" failed: ERR=%s\n",
2738 target_attrname, xattr_data->last_fname, be.bstrerror());
2739 goto bail_out;
2740 }
2741 }
2742
2743 /*
2744 * Based on the filetype perform the correct action. We support most filetypes
2745 * here, more then the actual implementation on Solaris supports so some code
2746 * may never get executed due to limitations in the implementation.
2747 */
2748 switch (st.st_mode & S_IFMT) {
2749 case S_IFIFO:
2750 case S_IFCHR:
2751 case S_IFBLK:
2752 /*
2753 * Get any acl on the xattr.
2754 */
2755 if (solaris_save_xattr_acl(jcr, xattr_data, attrfd, attrname, &acl_text)
2756 != BxattrExitCode::kSuccess)
2757 goto bail_out;
2758
2759 /*
2760 * The current implementation of xattr on Solaris doesn't support this,
2761 * but if it ever does we are prepared.
2762 * Encode the stat struct into an ASCII representation.
2763 */
2764 EncodeStat(attribs, &st, sizeof(st), 0, stream);
2765 cnt = Bsnprintf(buffer, sizeof(buffer), "%s%c%s%c%s%c", target_attrname,
2766 0, attribs, 0, (acl_text) ? acl_text : "", 0);
2767 break;
2768 case S_IFDIR:
2769 /*
2770 * Get any acl on the xattr.
2771 */
2772 if (solaris_save_xattr_acl(jcr, xattr_data, attrfd, attrname, &acl_text)
2773 != BxattrExitCode::kSuccess)
2774 goto bail_out;
2775
2776 /*
2777 * See if this is the toplevel_hidden_dir being saved.
2778 */
2779 if (toplevel_hidden_dir) {
2780 /*
2781 * Save the data for later storage when we encounter a real xattr.
2782 * We store the data in the xattr_data->u.build->content buffer
2783 * and flush that just before sending out the first real xattr.
2784 * Encode the stat struct into an ASCII representation and jump
2785 * out of the function.
2786 */
2787 EncodeStat(attribs, &st, sizeof(st), 0, stream);
2788 cnt = Bsnprintf(buffer, sizeof(buffer), "%s%c%s%c%s%c", target_attrname,
2789 0, attribs, 0, (acl_text) ? acl_text : "", 0);
2790 PmMemcpy(xattr_data->u.build->content, buffer, cnt);
2791 xattr_data->u.build->content_length = cnt;
2792 goto bail_out;
2793 } else {
2794 /*
2795 * The current implementation of xattr on Solaris doesn't support this,
2796 * but if it ever does we are prepared.
2797 * Encode the stat struct into an ASCII representation.
2798 */
2799 EncodeStat(attribs, &st, sizeof(st), 0, stream);
2800 cnt = Bsnprintf(buffer, sizeof(buffer), "%s%c%s%c%s%c", target_attrname,
2801 0, attribs, 0, (acl_text) ? acl_text : "", 0);
2802 }
2803 break;
2804 case S_IFREG:
2805 /*
2806 * If this is a hardlinked file check the inode cache for a hit.
2807 */
2808 if (st.st_nlink > 1) {
2809 /*
2810 * See if the cache already knows this inode number.
2811 */
2812 if ((xlce = find_xattr_link_cache_entry(xattr_data, st.st_ino))
2813 != NULL) {
2814 /*
2815 * Generate a xattr encoding with the reference to the target in
2816 * there.
2817 */
2818 EncodeStat(attribs, &st, sizeof(st), st.st_ino, stream);
2819 cnt = Bsnprintf(buffer, sizeof(buffer), "%s%c%s%c%s%c",
2820 target_attrname, 0, attribs, 0, xlce->target, 0);
2821 PmMemcpy(xattr_data->u.build->content, buffer, cnt);
2822 xattr_data->u.build->content_length = cnt;
2823 retval = SendXattrStream(jcr, xattr_data, stream);
2824
2825 /*
2826 * For a hard linked file we are ready now, no need to recursively
2827 * save the attributes.
2828 */
2829 goto bail_out;
2830 }
2831
2832 /*
2833 * Store this hard linked file in the cache.
2834 * Store the name relative to the top level xattr space.
2835 */
2836 add_xattr_link_cache_entry(xattr_data, st.st_ino, target_attrname + 1);
2837 }
2838
2839 /*
2840 * Get any acl on the xattr.
2841 */
2842 if (solaris_save_xattr_acl(jcr, xattr_data, attrfd, attrname, &acl_text)
2843 != BxattrExitCode::kSuccess) {
2844 goto bail_out;
2845 }
2846
2847 /*
2848 * Encode the stat struct into an ASCII representation.
2849 */
2850 EncodeStat(attribs, &st, sizeof(st), 0, stream);
2851 cnt = Bsnprintf(buffer, sizeof(buffer), "%s%c%s%c%s%c", target_attrname,
2852 0, attribs, 0, (acl_text) ? acl_text : "", 0);
2853
2854 /*
2855 * Open the extended or extensible attribute file.
2856 */
2857 if ((attrfd = openat(fd, attrname, O_RDONLY)) < 0) {
2858 BErrNo be;
2859
2860 switch (errno) {
2861 case ENOENT:
2862 retval = BxattrExitCode::kSuccess;
2863 goto bail_out;
2864 default:
2865 Mmsg3(jcr->errmsg, _("Unable to open xattr %s on \"%s\": ERR=%s\n"),
2866 target_attrname, xattr_data->last_fname, be.bstrerror());
2867 Dmsg3(100, "openat of xattr %s on \"%s\" failed: ERR=%s\n",
2868 target_attrname, xattr_data->last_fname, be.bstrerror());
2869 goto bail_out;
2870 }
2871 }
2872 break;
2873 case S_IFLNK:
2874 /*
2875 * The current implementation of xattr on Solaris doesn't support this,
2876 * but if it ever does we are prepared. Encode the stat struct into an
2877 * ASCII representation.
2878 */
2879 if (readlink(attrname, link_source, sizeof(link_source)) < 0) {
2880 BErrNo be;
2881
2882 switch (errno) {
2883 case ENOENT:
2884 retval = BxattrExitCode::kSuccess;
2885 goto bail_out;
2886 default:
2887 Mmsg3(jcr->errmsg,
2888 _("Unable to read symlin %s on \"%s\": ERR=%s\n"),
2889 target_attrname, xattr_data->last_fname, be.bstrerror());
2890 Dmsg3(100, "readlink of xattr %s on \"%s\" failed: ERR=%s\n",
2891 target_attrname, xattr_data->last_fname, be.bstrerror());
2892 goto bail_out;
2893 }
2894 }
2895
2896 /*
2897 * Generate a xattr encoding with the reference to the target in there.
2898 */
2899 EncodeStat(attribs, &st, sizeof(st), st.st_ino, stream);
2900 cnt = Bsnprintf(buffer, sizeof(buffer), "%s%c%s%c%s%c", target_attrname,
2901 0, attribs, 0, link_source, 0);
2902 PmMemcpy(xattr_data->u.build->content, buffer, cnt);
2903 xattr_data->u.build->content_length = cnt;
2904 retval = SendXattrStream(jcr, xattr_data, stream);
2905
2906 if (retval == BxattrExitCode::kSuccess) {
2907 xattr_data->u.build->nr_saved++;
2908 }
2909
2910 /*
2911 * For a soft linked file we are ready now, no need to recursively save
2912 * the attributes.
2913 */
2914 goto bail_out;
2915 default:
2916 goto bail_out;
2917 }
2918
2919 /*
2920 * See if this is the first real xattr being saved.
2921 * If it is save the toplevel_hidden_dir attributes first.
2922 * This is easy as its stored already in the
2923 * xattr_data->u.build->content buffer.
2924 */
2925 if (xattr_data->u.build->nr_saved == 0) {
2926 retval = SendXattrStream(jcr, xattr_data, STREAM_XATTR_SOLARIS);
2927 if (retval != BxattrExitCode::kSuccess) { goto bail_out; }
2928 xattr_data->u.build->nr_saved++;
2929 }
2930
2931 PmMemcpy(xattr_data->u.build->content, buffer, cnt);
2932 xattr_data->u.build->content_length = cnt;
2933
2934 /*
2935 * Only dump the content of regular files.
2936 */
2937 switch (st.st_mode & S_IFMT) {
2938 case S_IFREG:
2939 if (st.st_size > 0) {
2940 /*
2941 * Protect ourself against things getting out of hand.
2942 */
2943 if (st.st_size >= MAX_XATTR_STREAM) {
2944 Mmsg2(jcr->errmsg,
2945 _("Xattr stream on file \"%s\" exceeds maximum size of %d "
2946 "bytes\n"),
2947 xattr_data->last_fname, MAX_XATTR_STREAM);
2948 goto bail_out;
2949 }
2950
2951 while ((cnt = read(attrfd, buffer, sizeof(buffer))) > 0) {
2952 xattr_data->u.build->content
2953 = CheckPoolMemorySize(xattr_data->u.build->content,
2954 xattr_data->u.build->content_length + cnt);
2955 memcpy(xattr_data->u.build->content
2956 + xattr_data->u.build->content_length,
2957 buffer, cnt);
2958 xattr_data->u.build->content_length += cnt;
2959 }
2960
2961 if (cnt < 0) {
2962 Mmsg2(jcr->errmsg,
2963 _("Unable to read content of xattr %s on file \"%s\"\n"),
2964 target_attrname, xattr_data->last_fname);
2965 Dmsg2(100, "read of data from xattr %s on \"%s\" failed\n",
2966 target_attrname, xattr_data->last_fname);
2967 goto bail_out;
2968 }
2969 }
2970 break;
2971
2972 default:
2973 break;
2974 }
2975
2976 /*
2977 * We build a new xattr stream send it to the SD.
2978 */
2979 retval = SendXattrStream(jcr, xattr_data, stream);
2980 if (retval != BxattrExitCode::kSuccess) { goto bail_out; }
2981 xattr_data->u.build->nr_saved++;
2982
2983 /*
2984 * Recursivly call solaris_save_extended_attributes for archiving the
2985 * attributes available on this extended attribute.
2986 */
2987 retval = solaris_save_xattrs(jcr, xattr_data, xattr_namespace, attrname);
2988
2989 /*
2990 * The recursive call could change our working dir so change back to the
2991 * wanted workdir.
2992 */
2993 if (fchdir(fd) < 0) {
2994 BErrNo be;
2995
2996 switch (errno) {
2997 case ENOENT:
2998 retval = BxattrExitCode::kSuccess;
2999 goto bail_out;
3000 default:
3001 Mmsg2(jcr->errmsg,
3002 _("Unable to chdir to xattr space of file \"%s\": ERR=%s\n"),
3003 xattr_data->last_fname, be.bstrerror());
3004 Dmsg3(100,
3005 "Unable to fchdir to xattr space of file \"%s\" using fd %d: "
3006 "ERR=%s\n",
3007 xattr_data->last_fname, fd, be.bstrerror());
3008 goto bail_out;
3009 }
3010 }
3011
3012 bail_out:
3013 if (acl_text != NULL) { free(acl_text); }
3014 if (attrfd != -1) { close(attrfd); }
3015 return retval;
3016 }
3017
solaris_save_xattrs(JobControlRecord * jcr,XattrData * xattr_data,const char * xattr_namespace,const char * attr_parent)3018 static BxattrExitCode solaris_save_xattrs(JobControlRecord* jcr,
3019 XattrData* xattr_data,
3020 const char* xattr_namespace,
3021 const char* attr_parent)
3022 {
3023 const char* name;
3024 int fd, filefd = -1, attrdirfd = -1;
3025 DIR* dirp;
3026 struct dirent* dp;
3027 char current_xattr_namespace[PATH_MAX];
3028 BxattrExitCode retval = BxattrExitCode::kError;
3029
3030 /*
3031 * Determine what argument to use. Use attr_parent when set
3032 * (recursive call) or xattr_data->last_fname for first call. Also save
3033 * the current depth of the xattr_space we are in.
3034 */
3035 if (attr_parent) {
3036 name = attr_parent;
3037 if (xattr_namespace) {
3038 Bsnprintf(current_xattr_namespace, sizeof(current_xattr_namespace),
3039 "%s%s/", xattr_namespace, attr_parent);
3040 } else {
3041 bstrncpy(current_xattr_namespace, "/", sizeof(current_xattr_namespace));
3042 }
3043 } else {
3044 name = xattr_data->last_fname;
3045 bstrncpy(current_xattr_namespace, "/", sizeof(current_xattr_namespace));
3046 }
3047
3048 /*
3049 * Open the file on which to save the xattrs read-only.
3050 */
3051 if ((filefd = open(name, O_RDONLY | O_NONBLOCK)) < 0) {
3052 BErrNo be;
3053
3054 switch (errno) {
3055 case ENOENT:
3056 retval = BxattrExitCode::kSuccess;
3057 goto bail_out;
3058 default:
3059 Mmsg2(jcr->errmsg, _("Unable to open file \"%s\": ERR=%s\n"),
3060 xattr_data->last_fname, be.bstrerror());
3061 Dmsg2(100, "Unable to open file \"%s\": ERR=%s\n",
3062 xattr_data->last_fname, be.bstrerror());
3063 goto bail_out;
3064 }
3065 }
3066
3067 /*
3068 * Open the xattr naming space.
3069 */
3070 if ((attrdirfd = openat(filefd, ".", O_RDONLY | O_XATTR)) < 0) {
3071 BErrNo be;
3072
3073 switch (errno) {
3074 case EINVAL:
3075 /*
3076 * Gentile way of the system saying this type of xattr layering is not
3077 * supported. Which is not problem we just forget about this this xattr.
3078 * But as this is not an error we return a positive return value.
3079 */
3080 retval = BxattrExitCode::kSuccess;
3081 goto bail_out;
3082 case ENOENT:
3083 retval = BxattrExitCode::kSuccess;
3084 goto bail_out;
3085 default:
3086 Mmsg3(jcr->errmsg,
3087 _("Unable to open xattr space %s on file \"%s\": ERR=%s\n"), name,
3088 xattr_data->last_fname, be.bstrerror());
3089 Dmsg3(100, "Unable to open xattr space %s on file \"%s\": ERR=%s\n",
3090 name, xattr_data->last_fname, be.bstrerror());
3091 goto bail_out;
3092 }
3093 }
3094
3095 /*
3096 * We need to change into the attribute directory to determine if each of the
3097 * attributes should be saved.
3098 */
3099 if (fchdir(attrdirfd) < 0) {
3100 BErrNo be;
3101
3102 Mmsg2(jcr->errmsg,
3103 _("Unable to chdir to xattr space on file \"%s\": ERR=%s\n"),
3104 xattr_data->last_fname, be.bstrerror());
3105 Dmsg3(
3106 100,
3107 "Unable to fchdir to xattr space on file \"%s\" using fd %d: ERR=%s\n",
3108 xattr_data->last_fname, attrdirfd, be.bstrerror());
3109 goto bail_out;
3110 }
3111
3112 /*
3113 * Save the data of the toplevel xattr hidden_dir. We save this one before
3114 * anything else because the readdir returns "." entry after the extensible
3115 * attr entry. And as we want this entry before anything else we better just
3116 * save its data.
3117 */
3118 if (!attr_parent)
3119 solaris_save_xattr(jcr, xattr_data, attrdirfd, current_xattr_namespace, ".",
3120 true, STREAM_XATTR_SOLARIS);
3121
3122 if ((fd = dup(attrdirfd)) == -1 || (dirp = fdopendir(fd)) == (DIR*)NULL) {
3123 BErrNo be;
3124
3125 Mmsg2(jcr->errmsg,
3126 _("Unable to list the xattr space on file \"%s\": ERR=%s\n"),
3127 xattr_data->last_fname, be.bstrerror());
3128 Dmsg3(
3129 100,
3130 "Unable to fdopendir xattr space on file \"%s\" using fd %d: ERR=%s\n",
3131 xattr_data->last_fname, fd, be.bstrerror());
3132
3133 goto bail_out;
3134 }
3135
3136 /*
3137 * Walk the namespace.
3138 */
3139 while ((dp = readdir(dirp)) != NULL) {
3140 /*
3141 * Skip only the toplevel . dir.
3142 */
3143 if (!attr_parent && bstrcmp(dp->d_name, ".")) continue;
3144
3145 /*
3146 * Skip all .. directories
3147 */
3148 if (bstrcmp(dp->d_name, "..")) continue;
3149
3150 Dmsg3(400, "processing extended attribute %s%s on file \"%s\"\n",
3151 current_xattr_namespace, dp->d_name, xattr_data->last_fname);
3152
3153 # if defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED)
3154 /*
3155 * We are not interested in read-only extensible attributes.
3156 */
3157 if (bstrcmp(dp->d_name, VIEW_READONLY)) {
3158 Dmsg3(400,
3159 "Skipping readonly extensible attributes %s%s on file \"%s\"\n",
3160 current_xattr_namespace, dp->d_name, xattr_data->last_fname);
3161
3162 continue;
3163 }
3164
3165 /*
3166 * We are only interested in read-write extensible attributes
3167 * when they contain non-transient values.
3168 */
3169 if (bstrcmp(dp->d_name, VIEW_READWRITE)) {
3170 /*
3171 * Determine if there are non-transient system attributes at the toplevel.
3172 * We need to provide a fd to the open file.
3173 */
3174 if (!SolarisHasNonTransientExtensibleAttributes(filefd)) {
3175 Dmsg3(400,
3176 "Skipping transient extensible attributes %s%s on file \"%s\"\n",
3177 current_xattr_namespace, dp->d_name, xattr_data->last_fname);
3178 continue;
3179 }
3180
3181 /*
3182 * Save the xattr.
3183 */
3184 solaris_save_xattr(jcr, xattr_data, attrdirfd, current_xattr_namespace,
3185 dp->d_name, false, STREAM_XATTR_SOLARIS_SYS);
3186 continue;
3187 }
3188 # endif /* HAVE_SYS_NVPAIR_H && _PC_SATTR_ENABLED */
3189
3190 /*
3191 * Save the xattr.
3192 */
3193 solaris_save_xattr(jcr, xattr_data, attrdirfd, current_xattr_namespace,
3194 dp->d_name, false, STREAM_XATTR_SOLARIS);
3195 }
3196
3197 closedir(dirp);
3198 retval = BxattrExitCode::kSuccess;
3199
3200 bail_out:
3201 if (attrdirfd != -1) close(attrdirfd);
3202 if (filefd != -1) close(filefd);
3203 return retval;
3204 }
3205
3206 # ifdef HAVE_ACL
solaris_restore_xattr_acl(JobControlRecord * jcr,XattrData * xattr_data,int fd,const char * attrname,char * acl_text)3207 static BxattrExitCode solaris_restore_xattr_acl(JobControlRecord* jcr,
3208 XattrData* xattr_data,
3209 int fd,
3210 const char* attrname,
3211 char* acl_text)
3212 {
3213 # ifdef HAVE_EXTENDED_ACL
3214 int error;
3215 acl_t* aclp = NULL;
3216
3217 if ((error = acl_fromtext(acl_text, &aclp)) != 0) {
3218 Mmsg1(jcr->errmsg, _("Unable to convert acl from text on file \"%s\"\n"),
3219 xattr_data->last_fname);
3220 return BxattrExitCode::kError;
3221 }
3222
3223 if ((fd != -1 && facl_set(fd, aclp) != 0) || acl_set(attrname, aclp) != 0) {
3224 BErrNo be;
3225
3226 Mmsg3(jcr->errmsg,
3227 _("Unable to restore acl of xattr %s on file \"%s\": ERR=%s\n"),
3228 attrname, xattr_data->last_fname, be.bstrerror());
3229 Dmsg3(100, "Unable to restore acl of xattr %s on file \"%s\": ERR=%s\n",
3230 attrname, xattr_data->last_fname, be.bstrerror());
3231 return BxattrExitCode::kError;
3232 }
3233
3234 if (aclp) { acl_free(aclp); }
3235 return BxattrExitCode::kSuccess;
3236
3237 # else /* HAVE_EXTENDED_ACL */
3238 int n;
3239 aclent_t* acls = NULL;
3240
3241 acls = aclfromtext(acl_text, &n);
3242 if (!acls) {
3243 if ((fd != -1 && facl(fd, SETACL, n, acls) != 0)
3244 || acl(attrname, SETACL, n, acls) != 0) {
3245 BErrNo be;
3246
3247 Mmsg3(jcr->errmsg,
3248 _("Unable to restore acl of xattr %s on file \"%s\": ERR=%s\n"),
3249 attrname, xattr_data->last_fname, be.bstrerror());
3250 Dmsg3(100, "Unable to restore acl of xattr %s on file \"%s\": ERR=%s\n",
3251 attrname, xattr_data->last_fname, be.bstrerror());
3252 return BxattrExitCode::kError;
3253 }
3254 }
3255
3256 if (acls) { free(acls); }
3257 return BxattrExitCode::kSuccess;
3258
3259 # endif /* HAVE_EXTENDED_ACL */
3260 }
3261 # endif /* HAVE_ACL */
3262
solaris_restore_xattrs(JobControlRecord * jcr,XattrData * xattr_data,bool is_extensible,char * content,uint32_t content_length)3263 static BxattrExitCode solaris_restore_xattrs(JobControlRecord* jcr,
3264 XattrData* xattr_data,
3265 bool is_extensible,
3266 char* content,
3267 uint32_t content_length)
3268
3269 {
3270 int fd, filefd = -1, attrdirfd = -1, attrfd = -1;
3271 int used_bytes, cnt;
3272 char *bp, *target_attrname, *attribs;
3273 char* linked_target = NULL;
3274 char* acl_text = NULL;
3275 char* data = NULL;
3276 int32_t inum;
3277 struct stat st;
3278 struct timeval times[2];
3279 BxattrExitCode retval = BxattrExitCode::kError;
3280
3281 /*
3282 * Parse the xattr stream. First the part that is the same for all xattrs.
3283 */
3284 used_bytes = 0;
3285
3286 /*
3287 * The name of the target xattr has a leading / we are not interested
3288 * in that so skip it when decoding the string. We always start a the /
3289 * of the xattr space anyway.
3290 */
3291 target_attrname = content + 1;
3292 if ((bp = strchr(target_attrname, '\0')) == (char*)NULL
3293 || (used_bytes = (bp - content)) >= (int32_t)(content_length - 1)) {
3294 goto parse_error;
3295 }
3296 attribs = ++bp;
3297
3298 /*
3299 * Open the file on which to restore the xattrs read-only.
3300 */
3301 if ((filefd = open(xattr_data->last_fname, O_RDONLY | O_NONBLOCK)) < 0) {
3302 BErrNo be;
3303
3304 Mmsg2(jcr->errmsg, _("Unable to open file \"%s\": ERR=%s\n"),
3305 xattr_data->last_fname, be.bstrerror());
3306 Dmsg2(100, "Unable to open file \"%s\": ERR=%s\n", xattr_data->last_fname,
3307 be.bstrerror());
3308 goto bail_out;
3309 }
3310
3311 /*
3312 * Open the xattr naming space and make it the current working dir.
3313 */
3314 if ((attrdirfd = openat(filefd, ".", O_RDONLY | O_XATTR)) < 0) {
3315 BErrNo be;
3316
3317 Mmsg2(jcr->errmsg, _("Unable to open xattr space on file \"%s\": ERR=%s\n"),
3318 xattr_data->last_fname, be.bstrerror());
3319 Dmsg2(100, "Unable to open xattr space on file \"%s\": ERR=%s\n",
3320 xattr_data->last_fname, be.bstrerror());
3321 goto bail_out;
3322 }
3323
3324 if (fchdir(attrdirfd) < 0) {
3325 BErrNo be;
3326
3327 Mmsg2(jcr->errmsg,
3328 _("Unable to chdir to xattr space on file \"%s\": ERR=%s\n"),
3329 xattr_data->last_fname, be.bstrerror());
3330 Dmsg3(
3331 100,
3332 "Unable to fchdir to xattr space on file \"%s\" using fd %d: ERR=%s\n",
3333 xattr_data->last_fname, attrdirfd, be.bstrerror());
3334 goto bail_out;
3335 }
3336
3337 /*
3338 * Try to open the correct xattr subdir based on the target_attrname given.
3339 * e.g. check if its a subdir attrname. Each / in the string makes us go
3340 * one level deeper.
3341 */
3342 while ((bp = strchr(target_attrname, '/')) != (char*)NULL) {
3343 *bp = '\0';
3344
3345 if ((fd = open(target_attrname, O_RDONLY | O_NONBLOCK)) < 0) {
3346 BErrNo be;
3347
3348 Mmsg3(jcr->errmsg, _("Unable to open xattr %s on file \"%s\": ERR=%s\n"),
3349 target_attrname, xattr_data->last_fname, be.bstrerror());
3350 Dmsg3(100, "Unable to open xattr %s on file \"%s\": ERR=%s\n",
3351 target_attrname, xattr_data->last_fname, be.bstrerror());
3352 goto bail_out;
3353 }
3354
3355 close(filefd);
3356 filefd = fd;
3357
3358 /*
3359 * Open the xattr naming space.
3360 */
3361 if ((fd = openat(filefd, ".", O_RDONLY | O_XATTR)) < 0) {
3362 BErrNo be;
3363
3364 Mmsg3(jcr->errmsg,
3365 _("Unable to open xattr space %s on file \"%s\": ERR=%s\n"),
3366 target_attrname, xattr_data->last_fname, be.bstrerror());
3367 Dmsg3(100, "Unable to open xattr space %s on file \"%s\": ERR=%s\n",
3368 target_attrname, xattr_data->last_fname, be.bstrerror());
3369 goto bail_out;
3370 }
3371
3372 close(attrdirfd);
3373 attrdirfd = fd;
3374
3375 /*
3376 * Make the xattr space our current workingdir.
3377 */
3378 if (fchdir(attrdirfd) < 0) {
3379 BErrNo be;
3380
3381 Mmsg3(jcr->errmsg,
3382 _("Unable to chdir to xattr space %s on file \"%s\": ERR=%s\n"),
3383 target_attrname, xattr_data->last_fname, be.bstrerror());
3384 Dmsg4(100,
3385 "Unable to fchdir to xattr space %s on file \"%s\" using fd %d: "
3386 "ERR=%s\n",
3387 target_attrname, xattr_data->last_fname, attrdirfd, be.bstrerror());
3388 goto bail_out;
3389 }
3390
3391 target_attrname = ++bp;
3392 }
3393
3394 /*
3395 * Decode the attributes from the stream.
3396 */
3397 DecodeStat(attribs, &st, sizeof(st), &inum);
3398
3399 /*
3400 * Decode the next field (acl_text).
3401 */
3402 if ((bp = strchr(attribs, '\0')) == (char*)NULL
3403 || (used_bytes = (bp - content)) >= (int32_t)(content_length - 1)) {
3404 goto parse_error;
3405 }
3406 acl_text = ++bp;
3407
3408 /*
3409 * Based on the filetype perform the correct action. We support most filetypes
3410 * here, more then the actual implementation on Solaris supports so some code
3411 * may never get executed due to limitations in the implementation.
3412 */
3413 switch (st.st_mode & S_IFMT) {
3414 case S_IFIFO:
3415 /*
3416 * The current implementation of xattr on Solaris doesn't support this,
3417 * but if it ever does we are prepared.
3418 */
3419 unlinkat(attrdirfd, target_attrname, 0);
3420 if (mkfifo(target_attrname, st.st_mode) < 0) {
3421 BErrNo be;
3422
3423 Mmsg3(jcr->errmsg,
3424 _("Unable to mkfifo xattr %s on file \"%s\": ERR=%s\n"),
3425 target_attrname, xattr_data->last_fname, be.bstrerror());
3426 Dmsg3(100, "Unable to mkfifo xattr %s on file \"%s\": ERR=%s\n",
3427 target_attrname, xattr_data->last_fname, be.bstrerror());
3428 goto bail_out;
3429 }
3430 break;
3431 case S_IFCHR:
3432 case S_IFBLK:
3433 /*
3434 * The current implementation of xattr on Solaris doesn't support this,
3435 * but if it ever does we are prepared.
3436 */
3437 unlinkat(attrdirfd, target_attrname, 0);
3438 if (mknod(target_attrname, st.st_mode, st.st_rdev) < 0) {
3439 BErrNo be;
3440
3441 Mmsg3(jcr->errmsg,
3442 _("Unable to mknod xattr %s on file \"%s\": ERR=%s\n"),
3443 target_attrname, xattr_data->last_fname, be.bstrerror());
3444 Dmsg3(100, "Unable to mknod xattr %s on file \"%s\": ERR=%s\n",
3445 target_attrname, xattr_data->last_fname, be.bstrerror());
3446 goto bail_out;
3447 }
3448 break;
3449 case S_IFDIR:
3450 /*
3451 * If its not the hidden_dir create the entry.
3452 * The current implementation of xattr on Solaris doesn't support this,
3453 * but if it ever does we are prepared.
3454 */
3455 if (!bstrcmp(target_attrname, ".")) {
3456 unlinkat(attrdirfd, target_attrname, AT_REMOVEDIR);
3457 if (mkdir(target_attrname, st.st_mode) < 0) {
3458 BErrNo be;
3459
3460 Jmsg3(jcr, M_WARNING, 0,
3461 _("Unable to mkdir xattr %s on file \"%s\": ERR=%s\n"),
3462 target_attrname, xattr_data->last_fname, be.bstrerror());
3463 Dmsg3(100, "Unable to mkdir xattr %s on file \"%s\": ERR=%s\n",
3464 target_attrname, xattr_data->last_fname, be.bstrerror());
3465 goto bail_out;
3466 }
3467 }
3468 break;
3469 case S_IFREG:
3470 /*
3471 * See if this is a hard linked file. e.g. inum != 0
3472 */
3473 if (inum != 0) {
3474 linked_target = bp;
3475
3476 unlinkat(attrdirfd, target_attrname, 0);
3477 if (link(linked_target, target_attrname) < 0) {
3478 BErrNo be;
3479
3480 Mmsg4(jcr->errmsg,
3481 _("Unable to link xattr %s to %s on file \"%s\": ERR=%s\n"),
3482 target_attrname, linked_target, xattr_data->last_fname,
3483 be.bstrerror());
3484 Dmsg4(100, "Unable to link xattr %s to %s on file \"%s\": ERR=%s\n",
3485 target_attrname, linked_target, xattr_data->last_fname,
3486 be.bstrerror());
3487 goto bail_out;
3488 }
3489
3490 /*
3491 * Successfully restored xattr.
3492 */
3493 retval = BxattrExitCode::kSuccess;
3494 goto bail_out;
3495 } else {
3496 if ((bp = strchr(acl_text, '\0')) == (char*)NULL
3497 || (used_bytes = (bp - content)) >= (int32_t)content_length) {
3498 goto parse_error;
3499 }
3500
3501 if (used_bytes < (int32_t)(content_length - 1)) data = ++bp;
3502
3503 /*
3504 * Restore the actual xattr.
3505 */
3506 if (!is_extensible) { unlinkat(attrdirfd, target_attrname, 0); }
3507
3508 if ((attrfd = openat(attrdirfd, target_attrname,
3509 O_RDWR | O_CREAT | O_TRUNC, st.st_mode))
3510 < 0) {
3511 BErrNo be;
3512
3513 Mmsg3(jcr->errmsg,
3514 _("Unable to open xattr %s on file \"%s\": ERR=%s\n"),
3515 target_attrname, xattr_data->last_fname, be.bstrerror());
3516 Dmsg3(100, "Unable to open xattr %s on file \"%s\": ERR=%s\n",
3517 target_attrname, xattr_data->last_fname, be.bstrerror());
3518 goto bail_out;
3519 }
3520 }
3521
3522 /*
3523 * Restore the actual data.
3524 */
3525 if (st.st_size > 0) {
3526 used_bytes = (data - content);
3527 cnt = content_length - used_bytes;
3528
3529 /*
3530 * Do a sanity check, the st.st_size should be the same as the number of
3531 * bytes we have available as data of the stream.
3532 */
3533 if (cnt != st.st_size) {
3534 Mmsg2(jcr->errmsg,
3535 _("Unable to restore data of xattr %s on file \"%s\": Not all "
3536 "data available in xattr stream\n"),
3537 target_attrname, xattr_data->last_fname);
3538 Dmsg2(100,
3539 "Unable to restore data of xattr %s on file \"%s\": Not all "
3540 "data available in xattr stream\n",
3541 target_attrname, xattr_data->last_fname);
3542 goto bail_out;
3543 }
3544
3545 while (cnt > 0) {
3546 cnt = write(attrfd, data, cnt);
3547 if (cnt < 0) {
3548 BErrNo be;
3549
3550 Mmsg3(jcr->errmsg,
3551 _("Unable to restore data of xattr %s on file \"%s\": "
3552 "ERR=%s\n"),
3553 target_attrname, xattr_data->last_fname, be.bstrerror());
3554 Dmsg3(100,
3555 "Unable to restore data of xattr %s on file \"%s\": ERR=%s\n",
3556 target_attrname, xattr_data->last_fname, be.bstrerror());
3557 goto bail_out;
3558 }
3559
3560 used_bytes += cnt;
3561 data += cnt;
3562 cnt = content_length - used_bytes;
3563 }
3564 }
3565 break;
3566 case S_IFLNK:
3567 /*
3568 * The current implementation of xattr on Solaris doesn't support this,
3569 * but if it ever does we are prepared.
3570 */
3571 linked_target = bp;
3572
3573 if (symlink(linked_target, target_attrname) < 0) {
3574 BErrNo be;
3575
3576 Mmsg4(jcr->errmsg,
3577 _("Unable to symlink xattr %s to %s on file \"%s\": ERR=%s\n"),
3578 target_attrname, linked_target, xattr_data->last_fname,
3579 be.bstrerror());
3580 Dmsg4(100, "Unable to symlink xattr %s to %s on file \"%s\": ERR=%s\n",
3581 target_attrname, linked_target, xattr_data->last_fname,
3582 be.bstrerror());
3583 goto bail_out;
3584 }
3585
3586 /*
3587 * Successfully restored xattr.
3588 */
3589 retval = BxattrExitCode::kSuccess;
3590 goto bail_out;
3591 default:
3592 goto bail_out;
3593 }
3594
3595 /*
3596 * Restore owner and acl for non extensible attributes.
3597 */
3598 if (!is_extensible) {
3599 if (fchownat(attrdirfd, target_attrname, st.st_uid, st.st_gid,
3600 AT_SYMLINK_NOFOLLOW)
3601 < 0) {
3602 BErrNo be;
3603
3604 switch (errno) {
3605 case EINVAL:
3606 /*
3607 * Gentile way of the system saying this type of xattr layering is not
3608 * supported. But as this is not an error we return a positive return
3609 * value.
3610 */
3611 retval = BxattrExitCode::kSuccess;
3612 break;
3613 case ENOENT:
3614 retval = BxattrExitCode::kSuccess;
3615 break;
3616 default:
3617 Mmsg3(
3618 jcr->errmsg,
3619 _("Unable to restore owner of xattr %s on file \"%s\": ERR=%s\n"),
3620 target_attrname, xattr_data->last_fname, be.bstrerror());
3621 Dmsg3(100,
3622 "Unable to restore owner of xattr %s on file \"%s\": ERR=%s\n",
3623 target_attrname, xattr_data->last_fname, be.bstrerror());
3624 }
3625 goto bail_out;
3626 }
3627 }
3628
3629 # ifdef HAVE_ACL
3630 if (acl_text && *acl_text)
3631 if (solaris_restore_xattr_acl(jcr, xattr_data, attrfd, target_attrname,
3632 acl_text)
3633 != BxattrExitCode::kSuccess)
3634 goto bail_out;
3635 # endif /* HAVE_ACL */
3636
3637 /*
3638 * For a non extensible attribute restore access and modification time on the
3639 * xattr.
3640 */
3641 if (!is_extensible) {
3642 times[0].tv_sec = st.st_atime;
3643 times[0].tv_usec = 0;
3644 times[1].tv_sec = st.st_mtime;
3645 times[1].tv_usec = 0;
3646
3647 if (futimesat(attrdirfd, target_attrname, times) < 0) {
3648 BErrNo be;
3649
3650 Mmsg3(
3651 jcr->errmsg,
3652 _("Unable to restore filetimes of xattr %s on file \"%s\": ERR=%s\n"),
3653 target_attrname, xattr_data->last_fname, be.bstrerror());
3654 Dmsg3(100,
3655 "Unable to restore filetimes of xattr %s on file \"%s\": ERR=%s\n",
3656 target_attrname, xattr_data->last_fname, be.bstrerror());
3657 goto bail_out;
3658 }
3659 }
3660
3661 /*
3662 * Successfully restored xattr.
3663 */
3664 retval = BxattrExitCode::kSuccess;
3665 goto bail_out;
3666
3667 parse_error:
3668 Mmsg1(
3669 jcr->errmsg,
3670 _("Illegal xattr stream, failed to parse xattr stream on file \"%s\"\n"),
3671 xattr_data->last_fname);
3672 Dmsg1(100,
3673 "Illegal xattr stream, failed to parse xattr stream on file \"%s\"\n",
3674 xattr_data->last_fname);
3675
3676 bail_out:
3677 if (attrfd != -1) { close(attrfd); }
3678 if (attrdirfd != -1) { close(attrdirfd); }
3679 if (filefd != -1) { close(filefd); }
3680 return retval;
3681 }
3682
solaris_build_xattr_streams(JobControlRecord * jcr,XattrData * xattr_data,FindFilesPacket * ff_pkt)3683 static BxattrExitCode solaris_build_xattr_streams(JobControlRecord* jcr,
3684 XattrData* xattr_data,
3685 FindFilesPacket* ff_pkt)
3686 {
3687 char cwd[PATH_MAX];
3688 BxattrExitCode retval = BxattrExitCode::kSuccess;
3689
3690 /*
3691 * First see if extended attributes or extensible attributes are present.
3692 * If not just pretend things went ok.
3693 */
3694 if (pathconf(xattr_data->last_fname, _PC_XATTR_EXISTS) > 0) {
3695 xattr_data->u.build->nr_saved = 0;
3696
3697 /*
3698 * As we change the cwd in the save function save the current cwd
3699 * for restore after return from the solaris_save_xattrs function.
3700 */
3701 getcwd(cwd, sizeof(cwd));
3702 retval = solaris_save_xattrs(jcr, xattr_data, NULL, NULL);
3703 chdir(cwd);
3704 if (xattr_data->u.build->link_cache) { DropXattrLinkCache(xattr_data); }
3705 }
3706 return retval;
3707 }
3708
solaris_parse_xattr_streams(JobControlRecord * jcr,XattrData * xattr_data,int stream,char * content,uint32_t content_length)3709 static BxattrExitCode solaris_parse_xattr_streams(JobControlRecord* jcr,
3710 XattrData* xattr_data,
3711 int stream,
3712 char* content,
3713 uint32_t content_length)
3714 {
3715 char cwd[PATH_MAX];
3716 bool is_extensible = false;
3717 BxattrExitCode retval = BxattrExitCode::kError;
3718
3719 /*
3720 * First make sure we can restore xattr on the filesystem.
3721 */
3722 switch (stream) {
3723 # if defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED)
3724 case STREAM_XATTR_SOLARIS_SYS:
3725 if (pathconf(xattr_data->last_fname, _PC_SATTR_ENABLED) <= 0) {
3726 Mmsg1(jcr->errmsg,
3727 _("Failed to restore extensible attributes on file \"%s\"\n"),
3728 xattr_data->last_fname);
3729 Dmsg1(100,
3730 "Unable to restore extensible attributes on file \"%s\", "
3731 "filesystem doesn't support this\n",
3732 xattr_data->last_fname);
3733 goto bail_out;
3734 }
3735
3736 is_extensible = true;
3737 break;
3738 # endif
3739 case STREAM_XATTR_SOLARIS:
3740 if (pathconf(xattr_data->last_fname, _PC_XATTR_ENABLED) <= 0) {
3741 Mmsg1(jcr->errmsg,
3742 _("Failed to restore extended attributes on file \"%s\"\n"),
3743 xattr_data->last_fname);
3744 Dmsg1(100,
3745 "Unable to restore extended attributes on file \"%s\", "
3746 "filesystem doesn't support this\n",
3747 xattr_data->last_fname);
3748 goto bail_out;
3749 }
3750 break;
3751 default:
3752 goto bail_out;
3753 }
3754
3755 /*
3756 * As we change the cwd in the restore function save the current cwd
3757 * for restore after return from the solaris_restore_xattrs function.
3758 */
3759 getcwd(cwd, sizeof(cwd));
3760 retval = solaris_restore_xattrs(jcr, xattr_data, is_extensible, content,
3761 content_length);
3762 chdir(cwd);
3763
3764 bail_out:
3765 return retval;
3766 }
3767
3768
3769 /**
3770 * Function pointers to the build and parse function to use for these xattrs.
3771 */
3772 static BxattrExitCode (*os_build_xattr_streams)(JobControlRecord* jcr,
3773 XattrData* xattr_data,
3774 FindFilesPacket* ff_pkt)
3775 = solaris_build_xattr_streams;
3776 static BxattrExitCode (*os_parse_xattr_streams)(JobControlRecord* jcr,
3777 XattrData* xattr_data,
3778 int stream,
3779 char* content,
3780 uint32_t content_length)
3781 = solaris_parse_xattr_streams;
3782
3783 # endif /* defined(HAVE_SUN_OS) */
3784
3785 /**
3786 * Entry points when compiled with support for XATTRs on a supported platform.
3787 */
BuildXattrStreams(JobControlRecord * jcr,XattrData * xattr_data,FindFilesPacket * ff_pkt)3788 BxattrExitCode BuildXattrStreams(JobControlRecord* jcr,
3789 XattrData* xattr_data,
3790 FindFilesPacket* ff_pkt)
3791 {
3792 /*
3793 * See if we are changing from one device to another.
3794 * We save the current device we are scanning and compare
3795 * it with the current st_dev in the last stat performed on
3796 * the file we are currently storing.
3797 */
3798 Dmsg0(1000, "BuildXattrStreams(): Enter\n");
3799 if (xattr_data->first_dev
3800 || xattr_data->current_dev != ff_pkt->statp.st_dev) {
3801 xattr_data->flags = BXATTR_FLAG_SAVE_NATIVE;
3802 xattr_data->first_dev = false;
3803 xattr_data->current_dev = ff_pkt->statp.st_dev;
3804 }
3805
3806 #ifdef __DragonFly__
3807 {
3808 #else
3809 if ((xattr_data->flags & BXATTR_FLAG_SAVE_NATIVE) && os_build_xattr_streams) {
3810 return os_build_xattr_streams(jcr, xattr_data, ff_pkt);
3811 } else {
3812 #endif
3813 return BxattrExitCode::kSuccess;
3814 }
3815 }
3816
3817 BxattrExitCode ParseXattrStreams(JobControlRecord* jcr,
3818 XattrData* xattr_data,
3819 int stream,
3820 char* content,
3821 uint32_t content_length)
3822 {
3823 int ret;
3824 struct stat st;
3825 unsigned int cnt;
3826 BxattrExitCode retval = BxattrExitCode::kError;
3827
3828 Dmsg0(1000, "ParseXattrStreams(): Enter\n");
3829 /*
3830 * See if we are changing from one device to another.
3831 * We save the current device we are restoring to and compare
3832 * it with the current st_dev in the last stat performed on
3833 * the file we are currently restoring.
3834 */
3835 ret = lstat(xattr_data->last_fname, &st);
3836 switch (ret) {
3837 case -1: {
3838 BErrNo be;
3839
3840 switch (errno) {
3841 case ENOENT:
3842 retval = BxattrExitCode::kSuccess;
3843 goto bail_out;
3844 default:
3845 Mmsg2(jcr->errmsg, _("Unable to stat file \"%s\": ERR=%s\n"),
3846 xattr_data->last_fname, be.bstrerror());
3847 Dmsg2(100, "Unable to stat file \"%s\": ERR=%s\n",
3848 xattr_data->last_fname, be.bstrerror());
3849 goto bail_out;
3850 }
3851 break;
3852 }
3853 case 0:
3854 break;
3855 }
3856 if (xattr_data->first_dev || xattr_data->current_dev != st.st_dev) {
3857 xattr_data->flags = BXATTR_FLAG_RESTORE_NATIVE;
3858 xattr_data->first_dev = false;
3859 xattr_data->current_dev = st.st_dev;
3860 }
3861
3862 /*
3863 * See if we are still restoring native xattr to this filesystem.
3864 */
3865 #ifdef __DragonFly__
3866 {
3867 #else
3868 if ((xattr_data->flags & BXATTR_FLAG_RESTORE_NATIVE)
3869 && os_parse_xattr_streams) {
3870 /*
3871 * See if we can parse this stream, and ifso give it a try.
3872 */
3873 for (cnt = 0; cnt < sizeof(os_default_xattr_streams) / sizeof(int); cnt++) {
3874 if (os_default_xattr_streams[cnt] == stream) {
3875 retval = os_parse_xattr_streams(jcr, xattr_data, stream, content,
3876 content_length);
3877 goto bail_out;
3878 }
3879 }
3880 } else {
3881 #endif
3882 /*
3883 * Increment error count but don't log an error again for the same
3884 * filesystem.
3885 */
3886 xattr_data->u.parse->nr_errors++;
3887 retval = BxattrExitCode::kSuccess;
3888 goto bail_out;
3889 }
3890
3891 /*
3892 * Issue a warning and discard the message. But pretend the restore was ok.
3893 */
3894 Jmsg2(jcr, M_WARNING, 0,
3895 _("Can't restore Extended Attributes of %s - incompatible xattr stream "
3896 "encountered - %d\n"),
3897 xattr_data->last_fname, stream);
3898
3899 bail_out:
3900 return retval;
3901 }
3902 #endif
3903