From 68c10f0f45adc3378f62611d3487ecd83cdea219 Mon Sep 17 00:00:00 2001 From: Victor Kamensky Date: Sat, 9 Jul 2016 18:24:15 -0700 Subject: [PATCH] cpio: added patch that can produce newcx format with extended attributes The patch matches kernel changes https://lkml.org/lkml/2018/1/24/857. --- src/Makefile.am | 3 +- src/copyin.c | 100 +++++++++++++++++++++++++--- src/copyout.c | 98 ++++++++++++++++++++++++++- src/cpiohdr.h | 25 +++++++ src/defer.c | 7 ++ src/extern.h | 8 ++- src/global.c | 3 + src/main.c | 11 +++- src/util.c | 1 + src/xattrs.c | 200 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 10 files changed, 441 insertions(+), 15 deletions(-) create mode 100644 src/xattrs.c diff --git a/src/Makefile.am b/src/Makefile.am index 9d1f322f3006..1c7e2b8642fb 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -40,7 +40,8 @@ cpio_SOURCES = \ filemode.c\ idcache.c\ makepath.c\ - userspec.c + userspec.c \ + xattrs.c noinst_HEADERS =\ cpio.h\ diff --git a/src/copyin.c b/src/copyin.c index 053afe7f4982..f412f9c1c542 100644 --- a/src/copyin.c +++ b/src/copyin.c @@ -112,7 +112,9 @@ tape_skip_padding (int in_file_des, off_t offset) { off_t pad; - if (archive_format == arf_crcascii || archive_format == arf_newascii) + if (archive_format == arf_crcascii || + archive_format == arf_newascii || + archive_format == arf_newasciix) pad = (4 - (offset % 4)) % 4; else if (archive_format == arf_binary || archive_format == arf_hpbinary) pad = (2 - (offset % 2)) % 2; @@ -407,6 +409,8 @@ create_final_defers () if (close (out_file_des) < 0) close_error (d->header.c_name); + if (d->header.c_xattrs_size) + set_xattrs(d->header.c_name, d->header.c_xattrs, d->header.c_xattrs_size); } } @@ -421,8 +425,9 @@ copyin_regular_file (struct cpio_file_stat* file_hdr, int in_file_des) { /* Can the current file be linked to a previously copied file? */ if (file_hdr->c_nlink > 1 - && (archive_format == arf_newascii - || archive_format == arf_crcascii) ) + && (archive_format == arf_newascii || + archive_format == arf_newasciix || + archive_format == arf_crcascii) ) { int link_res; if (file_hdr->c_filesize == 0) @@ -561,7 +566,9 @@ copyin_regular_file (struct cpio_file_stat* file_hdr, int in_file_des) tape_skip_padding (in_file_des, file_hdr->c_filesize); if (file_hdr->c_nlink > 1 - && (archive_format == arf_newascii || archive_format == arf_crcascii) ) + && (archive_format == arf_newascii || + archive_format == arf_newasciix || + archive_format == arf_crcascii) ) { /* (see comment above for how the newc and crc formats store multiple links). Now that we have the data @@ -939,10 +946,10 @@ read_pattern_file () } -uintmax_t -from_ascii (char const *where, size_t digs, unsigned logbase) +unsigned long long +from_ascii_64 (char const *where, size_t digs, unsigned logbase) { - uintmax_t value = 0; + unsigned long long value = 0; char const *buf = where; char const *end = buf + digs; int overflow = 0; @@ -985,6 +992,13 @@ from_ascii (char const *where, size_t digs, unsigned logbase) return value; } +uintmax_t +from_ascii (char const *where, size_t digs, unsigned logbase) +{ + uintmax_t value = from_ascii_64(where, digs, logbase); + return value; +} + /* Return 16-bit integer I with the bytes swapped. */ @@ -1026,6 +1040,8 @@ read_in_header (struct cpio_file_stat *file_hdr, int in_des) archive_format = arf_crcascii; crc_i_flag = true; } + else if (!strncmp (tmpbuf, "070703", 6)) + archive_format = arf_newasciix; else if ((*((unsigned short *) tmpbuf) == 070707) || (*((unsigned short *) tmpbuf) == swab_short ((unsigned short) 070707))) archive_format = arf_binary; @@ -1074,6 +1090,15 @@ read_in_header (struct cpio_file_stat *file_hdr, int in_des) read_in_new_ascii (file_hdr, in_des); break; } + if (archive_format == arf_newasciix + && !strncmp (magic.str, "070703", 6)) + { + if (bytes_skipped > 0) + warn_junk_bytes (bytes_skipped); + file_hdr->c_magic = 070703; + read_in_new_asciix (file_hdr, in_des); + break; + } if (archive_format == arf_crcascii && !strncmp (magic.str, "070702", 6)) { @@ -1212,6 +1237,53 @@ read_in_new_ascii (struct cpio_file_stat *file_hdr, int in_des) tape_skip_padding (in_des, file_hdr->c_namesize + 110); } +void +read_in_new_asciix (struct cpio_file_stat *file_hdr, int in_des) +{ + struct new_asciix_header ascii_header; + + tape_buffered_read (ascii_header.c_ino, in_des, + sizeof ascii_header - sizeof ascii_header.c_magic); + + file_hdr->c_ino = FROM_HEX (ascii_header.c_ino); + file_hdr->c_mode = FROM_HEX (ascii_header.c_mode); + file_hdr->c_uid = FROM_HEX (ascii_header.c_uid); + file_hdr->c_gid = FROM_HEX (ascii_header.c_gid); + file_hdr->c_nlink = FROM_HEX (ascii_header.c_nlink); + file_hdr->c_mtime = FROM_HEX_64 (ascii_header.c_mtime); + file_hdr->c_mtime_nsec = FROM_HEX (ascii_header.c_mtime_nsec); + file_hdr->c_filesize = FROM_HEX_64 (ascii_header.c_filesize); + file_hdr->c_dev_maj = FROM_HEX (ascii_header.c_dev_maj); + file_hdr->c_dev_min = FROM_HEX (ascii_header.c_dev_min); + file_hdr->c_rdev_maj = FROM_HEX (ascii_header.c_rdev_maj); + file_hdr->c_rdev_min = FROM_HEX (ascii_header.c_rdev_min); + file_hdr->c_namesize = FROM_HEX (ascii_header.c_namesize); + file_hdr->c_xattrs_size = FROM_HEX (ascii_header.c_xattrsize); + + /* Read file name from input. */ + if (file_hdr->c_name != NULL) + free (file_hdr->c_name); + if (file_hdr->c_xattrs != NULL) + { + free (file_hdr->c_xattrs); + file_hdr->c_xattrs = NULL; + } + file_hdr->c_name = (char *) xmalloc (file_hdr->c_namesize); + tape_buffered_read (file_hdr->c_name, in_des, (long) file_hdr->c_namesize); + + /* In SVR4 ASCII format, the amount of space allocated for the header + is rounded up to the next long-word, so we might need to drop + 1-3 bytes. */ + tape_skip_padding (in_des, file_hdr->c_namesize + sizeof ascii_header); + + if (file_hdr->c_xattrs_size) + { + file_hdr->c_xattrs = (char *) xmalloc (file_hdr->c_xattrs_size); + tape_buffered_read (file_hdr->c_xattrs, in_des, (long) file_hdr->c_xattrs_size); + tape_skip_padding (in_des, file_hdr->c_xattrs_size); + } +} + /* Fill in FILE_HDR by reading a binary format cpio header from file descriptor IN_DES, except for the first 6 bytes (the magic number, device, and inode number), which are already filled in. */ @@ -1342,6 +1414,8 @@ process_copy_in () read_pattern_file (); } file_hdr.c_name = NULL; + file_hdr.c_xattrs_size = 0; + file_hdr.c_xattrs = NULL; if (rename_batch_file) { @@ -1453,8 +1527,9 @@ process_copy_in () links that we didn't skip, and this file might have the data for the links. If it does, we'll copy in the data to the links, but not to this file. */ - if (file_hdr.c_nlink > 1 && (archive_format == arf_newascii - || archive_format == arf_crcascii) ) + if (file_hdr.c_nlink > 1 && (archive_format == arf_newascii || + archive_format == arf_newasciix || + archive_format == arf_crcascii) ) { if (create_defered_links_to_skipped(&file_hdr, in_file_des) < 0) { @@ -1543,6 +1618,9 @@ process_copy_in () copyin_file(&file_hdr, in_file_des); + if (file_hdr.c_xattrs_size) + set_xattrs(file_hdr.c_name, file_hdr.c_xattrs, file_hdr.c_xattrs_size); + if (verbose_flag) fprintf (stderr, "%s\n", file_hdr.c_name); if (dot_flag) @@ -1558,7 +1636,9 @@ process_copy_in () if (append_flag) return; - if (archive_format == arf_newascii || archive_format == arf_crcascii) + if (archive_format == arf_newascii || + archive_format == arf_newasciix || + archive_format == arf_crcascii) { create_final_defers (); } diff --git a/src/copyout.c b/src/copyout.c index 1f0987a372ae..f12d408c60bd 100644 --- a/src/copyout.c +++ b/src/copyout.c @@ -80,7 +80,7 @@ tape_pad_output (int out_file_des, int offset) { size_t pad; - if (archive_format == arf_newascii || archive_format == arf_crcascii) + if (archive_format == arf_newascii || archive_format == arf_newasciix || archive_format == arf_crcascii) pad = (4 - (offset % 4)) % 4; else if (archive_format == arf_tar || archive_format == arf_ustar) pad = (512 - (offset % 512)) % 512; @@ -382,6 +382,77 @@ write_out_new_ascii_header (const char *magic_string, } int +write_out_new_asciix_header (const char *magic_string, + struct cpio_file_stat *file_hdr, int out_des) +{ + struct new_asciix_header ascii_header; + char *p; + + p = stpcpy ((char *)&ascii_header, magic_string); + to_ascii_or_warn (p, file_hdr->c_ino, 8, LG_16, + file_hdr->c_name, _("inode number")); + p += 8; + to_ascii_or_warn (p, file_hdr->c_mode, 8, LG_16, file_hdr->c_name, + _("file mode")); + p += 8; + to_ascii_or_warn (p, file_hdr->c_uid, 8, LG_16, file_hdr->c_name, + _("uid")); + p += 8; + to_ascii_or_warn (p, file_hdr->c_gid, 8, LG_16, file_hdr->c_name, + _("gid")); + p += 8; + to_ascii_or_warn (p, file_hdr->c_nlink, 8, LG_16, file_hdr->c_name, + _("number of links")); + p += 8; + to_ascii_or_warn (p, file_hdr->c_mtime, 16, LG_16, file_hdr->c_name, + _("modification time")); + p += 16; + to_ascii_or_warn (p, file_hdr->c_mtime_nsec, 8, LG_16, file_hdr->c_name, + _("modification time (nsec)")); + p += 8; + if (to_ascii_or_error (p, file_hdr->c_filesize, 16, LG_16, file_hdr->c_name, + _("file size"))) + return 1; + p += 16; + if (to_ascii_or_error (p, file_hdr->c_dev_maj, 8, LG_16, file_hdr->c_name, + _("device major number"))) + return 1; + p += 8; + if (to_ascii_or_error (p, file_hdr->c_dev_min, 8, LG_16, file_hdr->c_name, + _("device minor number"))) + return 1; + p += 8; + if (to_ascii_or_error (p, file_hdr->c_rdev_maj, 8, LG_16, file_hdr->c_name, + _("rdev major"))) + return 1; + p += 8; + if (to_ascii_or_error (p, file_hdr->c_rdev_min, 8, LG_16, file_hdr->c_name, + _("rdev minor"))) + return 1; + p += 8; + if (to_ascii_or_error (p, file_hdr->c_namesize, 8, LG_16, file_hdr->c_name, + _("name size"))) + return 1; + p += 8; + if (to_ascii_or_error (p, file_hdr->c_xattrs_size, 8, LG_16, file_hdr->c_name, + _("xattrs size"))) + return 1; + + tape_buffered_write ((char *)&ascii_header, out_des, sizeof ascii_header); + + /* Write file name to output. */ + tape_buffered_write (file_hdr->c_name, out_des, (long) file_hdr->c_namesize); + tape_pad_output (out_des, file_hdr->c_namesize + sizeof ascii_header); + /* Write xattrs to output. */ + if (file_hdr->c_xattrs) + { + tape_buffered_write (file_hdr->c_xattrs, out_des, (long) file_hdr->c_xattrs_size); + tape_pad_output (out_des, file_hdr->c_xattrs_size); + } + return 0; +} + +int write_out_old_ascii_header (dev_t dev, dev_t rdev, struct cpio_file_stat *file_hdr, int out_des) { @@ -531,6 +602,9 @@ write_out_header (struct cpio_file_stat *file_hdr, int out_des) case arf_newascii: return write_out_new_ascii_header ("070701", file_hdr, out_des); + case arf_newasciix: + return write_out_new_asciix_header ("070703", file_hdr, out_des); + case arf_crcascii: return write_out_new_ascii_header ("070702", file_hdr, out_des); @@ -595,6 +669,8 @@ process_copy_out () /* Initialize the copy out. */ ds_init (&input_name, 128); file_hdr.c_magic = 070707; + file_hdr.c_xattrs = NULL; + file_hdr.c_xattrs_size = 0; /* Check whether the output file might be a tape. */ out_file_des = archive_des; @@ -633,6 +709,12 @@ process_copy_out () continue; } + if (file_hdr.c_xattrs) + { + free(file_hdr.c_xattrs); + file_hdr.c_xattrs = NULL; + } + /* Process next file. */ if ((*xstat) (input_name.ds_string, &file_stat) < 0) stat_error (input_name.ds_string); @@ -682,6 +764,15 @@ process_copy_out () file_hdr.c_namesize = strlen (input_name.ds_string) + 1; } #endif + if (archive_format == arf_newasciix) + { + file_hdr.c_xattrs_size = get_xattrs(input_name.ds_string, &file_hdr.c_xattrs); + } + else + { + file_hdr.c_xattrs_size = 0; + file_hdr.c_xattrs = NULL; + } /* Copy the named file to the output. */ switch (file_hdr.c_mode & CP_IFMT) @@ -700,7 +791,7 @@ process_copy_out () break; } } - if ( (archive_format == arf_newascii || archive_format == arf_crcascii) + if ( (archive_format == arf_newascii || archive_format == arf_newasciix || archive_format == arf_crcascii) && (file_hdr.c_nlink > 1) ) { if (last_link (&file_hdr) ) @@ -863,11 +954,14 @@ process_copy_out () file_hdr.c_rdev_maj = 0; file_hdr.c_rdev_min = 0; file_hdr.c_mtime = 0; + file_hdr.c_mtime_nsec = 0; file_hdr.c_chksum = 0; file_hdr.c_filesize = 0; file_hdr.c_namesize = 11; + file_hdr.c_xattrs_size = 0; file_hdr.c_name = CPIO_TRAILER_NAME; + file_hdr.c_xattrs = NULL; if (archive_format != arf_tar && archive_format != arf_ustar) write_out_header (&file_hdr, out_file_des); else diff --git a/src/cpiohdr.h b/src/cpiohdr.h index b29e6fb6cdc1..d2ec194649ac 100644 --- a/src/cpiohdr.h +++ b/src/cpiohdr.h @@ -109,6 +109,28 @@ struct new_ascii_header the sum of all the bytes in the file */ } ATTRIB_PACKED; +# ifdef HAVE_PRAGMA_PACK_HPPA +# pragma pack 1 +# endif +struct new_asciix_header +{ + char c_magic[6]; /* "070703" for "newcx" format */ + char c_ino[8]; + char c_mode[8]; + char c_uid[8]; + char c_gid[8]; + char c_nlink[8]; + char c_mtime[16]; + char c_mtime_nsec[8]; + char c_filesize[16]; /* must be 0 for FIFOs and directories */ + char c_dev_maj[8]; + char c_dev_min[8]; + char c_rdev_maj[8]; /* only valid for chr and blk special files */ + char c_rdev_min[8]; /* only valid for chr and blk special files */ + char c_namesize[8]; /* count includes terminating NUL in pathname */ + char c_xattrsize[8]; /* count of xattrs */ +} ATTRIB_PACKED; + struct cpio_file_stat /* Internal representation of a CPIO header */ { unsigned short c_magic; @@ -118,14 +140,17 @@ struct cpio_file_stat /* Internal representation of a CPIO header */ gid_t c_gid; size_t c_nlink; time_t c_mtime; + unsigned long c_mtime_nsec; off_t c_filesize; long c_dev_maj; long c_dev_min; long c_rdev_maj; long c_rdev_min; size_t c_namesize; + size_t c_xattrs_size; uint32_t c_chksum; char *c_name; + char *c_xattrs; char *c_tar_linkname; }; diff --git a/src/defer.c b/src/defer.c index c07750fd6933..6654a4ce7487 100644 --- a/src/defer.c +++ b/src/defer.c @@ -33,6 +33,12 @@ create_deferment (struct cpio_file_stat *file_hdr) d->header = *file_hdr; d->header.c_name = (char *) xmalloc (strlen (file_hdr->c_name) + 1); strcpy (d->header.c_name, file_hdr->c_name); + + if (file_hdr->c_xattrs_size) + { + d->header.c_xattrs = xmalloc (file_hdr->c_xattrs_size); + memcpy(d->header.c_xattrs, file_hdr->c_xattrs, file_hdr->c_xattrs_size); + } return d; } @@ -40,5 +46,6 @@ void free_deferment (struct deferment *d) { free (d->header.c_name); + free (d->header.c_xattrs); free (d); } diff --git a/src/extern.h b/src/extern.h index d864bde8b53f..c6249d8a9770 100644 --- a/src/extern.h +++ b/src/extern.h @@ -24,7 +24,7 @@ enum archive_format { arf_unknown, arf_binary, arf_oldascii, arf_newascii, arf_crcascii, - arf_tar, arf_ustar, arf_hpoldascii, arf_hpbinary + arf_tar, arf_ustar, arf_hpoldascii, arf_hpbinary, arf_newasciix }; extern enum archive_format archive_format; @@ -58,6 +58,7 @@ extern unsigned int warn_option; extern mode_t newdir_umask; extern int renumber_inodes_option; extern int ignore_devno_option; +extern int xattrs_flag; /* Values for warn_option */ #define CPIO_WARN_NONE 0 @@ -108,6 +109,7 @@ void warn_junk_bytes (long bytes_skipped); void read_in_header (struct cpio_file_stat *file_hdr, int in_des); void read_in_old_ascii (struct cpio_file_stat *file_hdr, int in_des); void read_in_new_ascii (struct cpio_file_stat *file_hdr, int in_des); +void read_in_new_asciix (struct cpio_file_stat *file_hdr, int in_des); void read_in_binary (struct cpio_file_stat *file_hdr, struct old_cpio_header *short_hdr, int in_des); void swab_array (char *arg, int count); @@ -210,9 +212,11 @@ void change_dir (void); #define LG_16 4 uintmax_t from_ascii (char const *where, size_t digs, unsigned logbase); +unsigned long long from_ascii_64 (char const *where, size_t digs, unsigned logbase); #define FROM_OCTAL(f) from_ascii (f, sizeof f, LG_8) #define FROM_HEX(f) from_ascii (f, sizeof f, LG_16) +#define FROM_HEX_64(f) from_ascii_64 (f, sizeof f, LG_16) void delay_cpio_set_stat (struct cpio_file_stat *file_stat, mode_t invert_permissions); @@ -223,3 +227,5 @@ void apply_delayed_set_stat (void); int arf_stores_inode_p (enum archive_format arf); +unsigned int get_xattrs(const char *name, char **xattrs); +int set_xattrs(const char *name, char *xattrs, unsigned int xattrs_size); diff --git a/src/global.c b/src/global.c index 336fce4adbfa..c5ac548be9e8 100644 --- a/src/global.c +++ b/src/global.c @@ -190,6 +190,9 @@ char *program_name; /* Extract files over symbolic links */ bool extract_over_symlinks; +/* If true, archieve files exteneded attributes if any. */ +int xattrs_flag = false; + /* A pointer to either lstat or stat, depending on whether dereferencing of symlinks is done for input files. */ int (*xstat) (); diff --git a/src/main.c b/src/main.c index 87cb309dc695..62c44991bec8 100644 --- a/src/main.c +++ b/src/main.c @@ -250,6 +250,8 @@ static struct argp_option options[] = { N_("Replace all files unconditionally"), GRID+1 }, {"sparse", SPARSE_OPTION, NULL, 0, N_("Write files with large blocks of zeros as sparse files"), GRID+1 }, + {"xattrs", 'Z', NULL, 0, + N_("Save/restore extended attributes into archiece, note produces non-standard CPIO archieve"), GRID+1 }, #undef GRID {0, 0, 0, 0} @@ -372,6 +374,8 @@ parse_opt (int key, char *arg, struct argp_state *state) archive_format = arf_crcascii; else if (!strcasecmp (arg, "newc")) archive_format = arf_newascii; + else if (!strcasecmp (arg, "newcx")) + archive_format = arf_newasciix; else if (!strcasecmp (arg, "odc")) archive_format = arf_oldascii; else if (!strcasecmp (arg, "bin")) @@ -387,7 +391,7 @@ parse_opt (int key, char *arg, struct argp_state *state) else USAGE_ERROR ((0, 0, _("\ invalid archive format `%s'; valid formats are:\n\ -crc newc odc bin ustar tar (all-caps also recognized)"), arg)); +crc newc newcx odc bin ustar tar (all-caps also recognized)"), arg)); break; case 'i': /* Copy-in mode. */ @@ -558,6 +562,11 @@ crc newc odc bin ustar tar (all-caps also recognized)"), arg)); to_stdout_option = true; break; + case 'Z': /* Save/restore extended file attributes. */ + xattrs_flag = true; + archive_format = arf_newasciix; + break; + default: return ARGP_ERR_UNKNOWN; } diff --git a/src/util.c b/src/util.c index 6ff603269c79..52f3c0e2dc78 100644 --- a/src/util.c +++ b/src/util.c @@ -1296,6 +1296,7 @@ stat_to_cpio (struct cpio_file_stat *hdr, struct stat *st) hdr->c_rdev_maj = major (st->st_rdev); hdr->c_rdev_min = minor (st->st_rdev); hdr->c_mtime = st->st_mtime; + hdr->c_mtime_nsec = st->st_mtim.tv_nsec; hdr->c_filesize = st->st_size; hdr->c_chksum = 0; hdr->c_tar_linkname = NULL; diff --git a/src/xattrs.c b/src/xattrs.c new file mode 100644 index 000000000000..d3a5b307997d --- /dev/null +++ b/src/xattrs.c @@ -0,0 +1,200 @@ +/* xattrs.c - extended attributes operations + Copyright (C) 2017-2018 Free + Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public + License along with this program; if not, write to the Free + Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301 USA. */ + +/* Code read and write file extended attributes, largely derived + from similar functions in Linux kernel initramfs xattrs code + by Mimi Zohar and Taras Kondratiuk. + + Victor Kamensky */ + +#include +#include +#include +#include +#include +#include + +#include + +static char *xattr_names; +static ssize_t xattr_nameslen; + +#define DEFAULT_XATTR_BUFSIZE 1024 +static char *xattr_buf; +static unsigned int xattr_bufsize; + +struct xattr_hdr { + char c_size[8]; /* total size including c_size field */ + char c_data[]; +}; + +unsigned int +get_xattrs(const char *name, char **xattrs) +{ + char xattr_num[9]; + char *xname, *buf, *bufend; + ssize_t new_xattr_nameslen; + size_t xname_len = 0; + + new_xattr_nameslen = llistxattr(name, NULL, 0); +#if 0 + fprintf(stderr, "get_xattrs: name = %s, new_xattr_nameslen = %zd\n", + name, new_xattr_nameslen); +#endif + if (new_xattr_nameslen <= 0) + return 0; + + if (new_xattr_nameslen > xattr_nameslen) + { + if (xattr_names) + free(xattr_names); + xattr_nameslen = new_xattr_nameslen; + xattr_names = malloc(xattr_nameslen + 1); + if (!xattr_names) + { + error(0, 0, _("xattr_names out of memory")); + return 0; + } + } + xattr_names[xattr_nameslen] = 0; + xattr_nameslen = llistxattr(name, xattr_names, xattr_nameslen); + if (xattr_nameslen <= 0) + return 0; + + /* xattr data format: \0 */ + if (!xattr_buf) + { + xattr_buf = malloc(DEFAULT_XATTR_BUFSIZE); + if (!xattr_buf) + { + error(0, 0, _("xattr_buf out of memory")); + return 0; + } + xattr_bufsize = DEFAULT_XATTR_BUFSIZE; + } + buf = xattr_buf; + bufend = xattr_buf + xattr_bufsize; + + for (xname = xattr_names; xname < (xattr_names + xattr_nameslen); + xname += xname_len) + { + xname_len = strlen(xname) + 1; /* +1 for NUL */ + ssize_t xattrsize, xattr_entry_size = 0; + + xattrsize = lgetxattr(name, xname, NULL, 0); + if (xattrsize <= 0) + continue; + + xattr_entry_size = sizeof(struct xattr_hdr) + + xname_len + xattrsize; + if (xattr_entry_size > (bufend - buf)) + { + char *new_xattr_buf; + size_t alloc_size; + + alloc_size = xattr_entry_size - (bufend - buf); + if (alloc_size < DEFAULT_XATTR_BUFSIZE) + alloc_size = DEFAULT_XATTR_BUFSIZE; + + new_xattr_buf = realloc(xattr_buf, + xattr_bufsize + alloc_size); + if (!new_xattr_buf) + { + error(0, 0, _("xattr_buf out of memory")); + return 0; + } + xattr_buf = new_xattr_buf; + xattr_bufsize += alloc_size; + buf = xattr_buf; + bufend = xattr_buf + xattr_bufsize; + } + + if (xattrsize != lgetxattr(name, xname, + buf + sizeof(struct xattr_hdr) + xname_len, + xattrsize)) + { + error(0, 0, _("xattrsize got changed")); + continue; + } + +#if 0 + fprintf(stderr, "%s: %s %lu (%d)\n", name, xname, xattrsize, + num_xattrs); +#endif + + /* fill in xattr size, type and name */ + sprintf(buf, "%08X%s", xattr_entry_size, xname); + buf += xattr_entry_size; + } + + *xattrs = malloc(buf - xattr_buf); + + if (*xattrs) + { + memcpy(*xattrs, xattr_buf,buf - xattr_buf); + return buf - xattr_buf; + } + else + { + return 0; + } +} + +int +set_xattrs(const char *name, char *xattrs, unsigned int xattrs_size) +{ + char *buf = xattrs; + char *bufend = buf + xattrs_size; + struct xattr_hdr *hdr; + char str[sizeof(hdr->c_size) + 1]; + + if (!xattrs_size) + return 0; + + str[sizeof(hdr->c_size)] = 0; + + while (buf < bufend) + { + char *xattr_name, *xattr_value; + unsigned long xattr_entry_size, xattr_value_size; + int ret; + + hdr = (struct xattr_hdr *)buf; + memcpy(str, hdr->c_size, sizeof(hdr->c_size)); + xattr_entry_size = strtoul(str, NULL, 16); + buf += xattr_entry_size; + if (ret || buf > bufend) + { + error(0, 0, _("malformed xattrs")); + break; + } + + xattr_name = hdr->c_data; + xattr_value = xattr_name + strlen(xattr_name) + 1; + xattr_value_size = buf - xattr_value; + + ret = lsetxattr(name, xattr_name, xattr_value, + xattr_value_size, 0); +#if 0 + fprintf(stderr, "%s: %s size: %lu val: %s (ret: %d)\n", name, xattr_name, + xattr_value_size, xattr_value, ret); +#endif + } + return 0; +} -- 2.7.4