Projects
Mega:24.03
cpio
_service:tar_scm:add-option-to-add-metadata-in-...
Sign Up
Log In
Username
Password
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File _service:tar_scm:add-option-to-add-metadata-in-copy-out-mode.patch of Package cpio
From 531cabc88e9ecdc3231fad6e4856869baa9a91ef Mon Sep 17 00:00:00 2001 From: Roberto Sassu <roberto.sassu@huawei.com> Date: Wed, 22 May 2019 09:04:39 +0200 Subject: [PATCH] cpio: add option to add file metadata in copy-out mode This patch adds the -e <type> option to include file metadata in the image. At the moment, only the xattr type is supported. If the xattr type is selected, the patch includes an additional file for each file passed to stdin, with special name 'METADATA!!!'. The additional file might contain multiple metadata records. The format of each record is: <metadata len (ASCII, 8 chars)><version><type><metadata> The format of metadata for the xattr type is: <xattr name>\0<xattr value> Signed-off-by: Roberto Sassu <roberto.sassu@huawei.com> --- doc/cpio.texi | 3 ++ src/copyout.c | 138 +++++++++++++++++++++++++++++++++++++++++++++++- src/dstring.c | 26 +++++++-- src/dstring.h | 1 + src/extern.h | 2 + src/global.c | 4 ++ src/initramfs.h | 21 ++++++++ src/main.c | 22 ++++++++ 8 files changed, 212 insertions(+), 5 deletions(-) create mode 100644 src/initramfs.h diff --git a/doc/cpio.texi b/doc/cpio.texi index bef7ba5..ea73a92 100644 --- a/doc/cpio.texi +++ b/doc/cpio.texi @@ -279,6 +279,9 @@ Set the I/O block size to the given @var{number} of bytes. @item -D @var{dir} @itemx --directory=@var{dir} Change to directory @var{dir} +@item -e @var{type} +@itemx --file-metadata=@var{type} +Include in the image file metadata with the specified type. @item --force-local Treat the archive file as local, even if its name contains colons. @item -F [[@var{user}@@]@var{host}:]@var{archive-file} diff --git a/src/copyout.c b/src/copyout.c index 6e82f4c..8ae1a48 100644 --- a/src/copyout.c +++ b/src/copyout.c @@ -21,6 +21,7 @@ #include <stdio.h> #include <sys/types.h> #include <sys/stat.h> +#include <sys/xattr.h> #include "filetypes.h" #include "cpiohdr.h" #include "dstring.h" @@ -586,6 +587,94 @@ assign_string (char **pvar, char *value) *pvar = p; } +static int +write_xattrs (int metadata_fd, char *path) +{ + struct metadata_hdr hdr = { .c_version = 1, .c_type = TYPE_XATTR }; + char str[sizeof(hdr.c_size) + 1]; + char *xattr_list = NULL; + char *list_ptr = NULL; + char *xattr_value = NULL; + ssize_t list_len, name_len, value_len, len; + int ret = -EINVAL; + + if (metadata_fd < 0) + return 0; + + list_len = llistxattr(path, NULL, 0); + if (list_len <= 0) + return -ENOENT; + + list_ptr = xattr_list = malloc(list_len); + if (!list_ptr) { + error (0, 0, _("out of memory")); + return ret; + } + + len = llistxattr(path, xattr_list, list_len); + if (len != list_len) + goto out; + + if (ftruncate(metadata_fd, 0)) + goto out; + + lseek(metadata_fd, 0, SEEK_SET); + + while (list_ptr < xattr_list + list_len) { + name_len = strlen(list_ptr); + + value_len = lgetxattr(path, list_ptr, NULL, 0); + if (value_len < 0) { + error (0, 0, _("cannot get xattrs")); + break; + } + + if (value_len) { + xattr_value = malloc(value_len); + if (!xattr_value) { + error (0, 0, _("out of memory")); + break; + } + } else { + xattr_value = NULL; + } + + len = lgetxattr(path, list_ptr, xattr_value, value_len); + if (len != value_len) + break; + + snprintf(str, sizeof(str), "%.8lx", + sizeof(hdr) + name_len + 1 + value_len); + + memcpy(hdr.c_size, str, sizeof(hdr.c_size)); + + if (write(metadata_fd, &hdr, sizeof(hdr)) != sizeof(hdr)) + break; + + if (write(metadata_fd, list_ptr, name_len + 1) != name_len + 1) + break; + + if (write(metadata_fd, xattr_value, value_len) != value_len) + break; + + if (fsync(metadata_fd)) + break; + + list_ptr += name_len + 1; + free(xattr_value); + xattr_value = NULL; + } + + free(xattr_value); +out: + free(xattr_list); + + if (list_ptr != xattr_list + list_len) + return ret; + + return 0; +} + /* Read a list of file names from the standard input and write a cpio collection on the standard output. The format of the header depends on the compatibility (-c) flag. */ @@ -601,6 +690,8 @@ process_copy_out (void) int in_file_des; /* Source file descriptor. */ int out_file_des; /* Output file descriptor. */ char *orig_file_name = NULL; + char template[] = "/tmp/cpio-metadata-XXXXXX"; + int ret, metadata_fd, metadata = 0, old_metadata, hard_link; /* Initialize the copy out. */ file_hdr.c_magic = 070707; @@ -632,9 +723,37 @@ process_copy_out (void) else change_dir (); + /* Create a temporary file to store file metadata */ + if (metadata_type != TYPE_NONE) { + metadata_fd = mkstemp(template); + if (metadata_fd < 0) { + error (0, 0, _("cannot create temporary file")); + return; + } + } + /* Copy files with names read from stdin. */ - while (ds_fgetstr (stdin, &input_name, name_end) != NULL) + while ((metadata_type != TYPE_NONE && metadata) || + ds_fgetstr (stdin, &input_name, name_end) != NULL) { + old_metadata = metadata; + hard_link = 0; + + if (metadata) { + metadata = 0; + + if (metadata_type != TYPE_XATTR) { + error (0, 0, _("metadata type not supported")); + continue; + } + + ret = write_xattrs(metadata_fd, orig_file_name); + if (ret < 0) + continue; + + ds_sgetstr (template, &input_name, name_end); + } + /* Check for blank line. */ if (input_name.ds_string[0] == 0) { @@ -660,7 +779,14 @@ process_copy_out (void) } } - assign_string (&orig_file_name, input_name.ds_string); + if (old_metadata) { + assign_string (&orig_file_name, template); + ds_sgetstr (METADATA_FILENAME, &input_name, name_end); + file_hdr.c_mode |= 0x10000; + } else { + assign_string (&orig_file_name, input_name.ds_string); + } + cpio_safer_name_suffix (input_name.ds_string, false, !no_abs_paths_flag, true); cpio_set_c_name (&file_hdr, input_name.ds_string); @@ -692,6 +818,7 @@ process_copy_out (void) else { add_link_defer (&file_hdr); + hard_link = 1; break; } } @@ -830,6 +957,8 @@ process_copy_out (void) fprintf (stderr, "%s\n", orig_file_name); if (dot_flag) fputc ('.', stderr); + if (metadata_type != TYPE_NONE && !old_metadata && !hard_link) + metadata = 1; } } @@ -870,4 +999,9 @@ process_copy_out (void) } cpio_file_stat_free (&file_hdr); ds_free (&input_name); + + if (metadata_type != TYPE_NONE) { + close(metadata_fd); + unlink(template); + } } diff --git a/src/dstring.c b/src/dstring.c index b425121..f5d8ab5 100644 --- a/src/dstring.c +++ b/src/dstring.c @@ -73,8 +73,8 @@ ds_reset (dynamic_string *s, size_t len) Return NULL if end of file is detected. Otherwise, Return a pointer to the null-terminated string in S. */ -char * -ds_fgetstr (FILE *f, dynamic_string *s, char eos) +static char * +ds_fgetstr_common (FILE *f, char *input_string, dynamic_string *s, char eos) { int next_ch; @@ -82,10 +82,18 @@ ds_fgetstr (FILE *f, dynamic_string *s, char eos) s->ds_idx = 0; /* Read the input string. */ - while ((next_ch = getc (f)) != eos && next_ch != EOF) + if (input_string) + next_ch = *input_string++; + else + next_ch = getc (f); + while (next_ch != eos && next_ch != EOF) { ds_resize (s, 0); s->ds_string[s->ds_idx++] = next_ch; + if (input_string) + next_ch = *input_string++; + else + next_ch = getc (f); } ds_resize (s, 0); s->ds_string[s->ds_idx] = '\0'; @@ -119,6 +127,12 @@ ds_concat (dynamic_string *s, char const *str) s->ds_string[s->ds_idx] = 0; } +char * +ds_fgetstr (FILE *f, dynamic_string *s, char eos) +{ + return ds_fgetstr_common (f, NULL, s, eos); +} + char * ds_fgets (FILE *f, dynamic_string *s) { @@ -131,6 +145,12 @@ ds_fgetname (FILE *f, dynamic_string *s) return ds_fgetstr (f, s, '\0'); } +char * +ds_sgetstr (char *input_string, dynamic_string *s, char eos) +{ + return ds_fgetstr_common (NULL, input_string, s, eos); +} + /* Return true if the dynamic string S ends with character C. */ int ds_endswith (dynamic_string *s, int c) diff --git a/src/dstring.h b/src/dstring.h index ac540be..d934d1d 100644 --- a/src/dstring.h +++ b/src/dstring.h @@ -40,6 +40,7 @@ void ds_reset (dynamic_string *s, size_t len); char *ds_fgetname (FILE *f, dynamic_string *s); char *ds_fgets (FILE *f, dynamic_string *s); char *ds_fgetstr (FILE *f, dynamic_string *s, char eos); +char *ds_sgetstr (char *input_string, dynamic_string *s, char eos); void ds_append (dynamic_string *s, int c); void ds_concat (dynamic_string *s, char const *str); diff --git a/src/extern.h b/src/extern.h index 6afbdd2..49369ab 100644 --- a/src/extern.h +++ b/src/extern.h @@ -18,6 +18,7 @@ #include "paxlib.h" #include "quotearg.h" +#include "initramfs.h" #include "quote.h" #include "inttostr.h" @@ -100,6 +101,7 @@ extern char output_is_seekable; extern int (*xstat) (); extern void (*copy_function) (); extern char *change_directory_option; +extern enum metadata_types metadata_type; #define STRINGIFY_BIGINT(i, b) umaxtostr (i, b) enum { UINTMAX_STRSIZE_BOUND = INT_BUFSIZE_BOUND (intmax_t) }; diff --git a/src/global.c b/src/global.c index 7c4bca8..bbd84fe 100644 --- a/src/global.c +++ b/src/global.c @@ -194,4 +194,8 @@ char *change_directory_option; int renumber_inodes_option; int ignore_devno_option; + +/* include file metadata into the image */ +enum metadata_types metadata_type = TYPE_NONE; + int ignore_dirnlink_option; diff --git a/src/initramfs.h b/src/initramfs.h new file mode 100644 index 0000000..88abae7 --- /dev/null +++ b/src/initramfs.h @@ -0,0 +1,21 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * include/linux/initramfs.h + * + * Include file for file metadata in the initial ram disk. + */ +#ifndef _LINUX_INITRAMFS_H +#define _LINUX_INITRAMFS_H + +#define METADATA_FILENAME "METADATA!!!" + +enum metadata_types { TYPE_NONE, TYPE_XATTR, TYPE__LAST }; + +struct metadata_hdr { + char c_size[8]; /* total size including c_size field */ + char c_version; /* header version */ + char c_type; /* metadata type */ + char c_metadata[]; /* metadata */ +} __attribute__((packed)); + +#endif /*_LINUX_INITRAMFS_H*/ diff --git a/src/main.c b/src/main.c index f9b4d85..8d5988e 100644 --- a/src/main.c +++ b/src/main.c @@ -202,6 +202,8 @@ static struct argp_option options[] = { {"device-independent", DEVICE_INDEPENDENT_OPTION, NULL, 0, N_("Create device-independent (reproducible) archives") }, {"reproducible", 0, NULL, OPTION_ALIAS }, + {"file-metadata", 'e', N_("TYPE"), 0, + N_("Include file metadata"), GRID+1 }, #undef GRID /* ********** */ @@ -295,6 +297,22 @@ warn_control (char *arg) return 1; } +static enum metadata_types +parse_metadata_type(char *arg) +{ + static char *metadata_type_str[TYPE__LAST] = { + [TYPE_NONE] = "none", + [TYPE_XATTR] = "xattr", + }; + int i; + + for (i = 0; i < TYPE__LAST; i++) + if (!strcmp (metadata_type_str[i], arg)) + return i; + + return TYPE_NONE; +} + static error_t parse_opt (int key, char *arg, struct argp_state *state) { @@ -357,6 +375,10 @@ parse_opt (int key, char *arg, struct argp_state *state) copy_matching_files = false; break; + case 'e': /* Metadata type. */ + metadata_type = parse_metadata_type(arg); + break; + case 'E': /* Pattern file name. */ pattern_file_name = arg; break; -- 2.27.0
Locations
Projects
Search
Status Monitor
Help
Open Build Service
OBS Manuals
API Documentation
OBS Portal
Reporting a Bug
Contact
Mailing List
Forums
Chat (IRC)
Twitter
Open Build Service (OBS)
is an
openSUSE project
.
浙ICP备2022010568号-2