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