Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

mtree: add xattr support #1400

Draft
wants to merge 3 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 2 additions & 0 deletions Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,8 @@ include_HEADERS= libarchive/archive.h libarchive/archive_entry.h
libarchive_la_SOURCES= \
libarchive/archive_acl.c \
libarchive/archive_acl_private.h \
libarchive/archive_base64.c \
libarchive/archive_base64_private.h \
libarchive/archive_check_magic.c \
libarchive/archive_cmdline.c \
libarchive/archive_cmdline_private.h \
Expand Down
2 changes: 2 additions & 0 deletions libarchive/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ SET(include_HEADERS
SET(libarchive_SOURCES
archive_acl.c
archive_acl_private.h
archive_base64.c
archive_base64_private.h
archive_check_magic.c
archive_cmdline.c
archive_cmdline_private.h
Expand Down
148 changes: 148 additions & 0 deletions libarchive/archive_base64.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
#include "archive_platform.h"

#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
#ifdef HAVE_STRING_H
#include <string.h>
#endif

#include "archive_base64_private.h"

/*
* base64_decode - Base64 decode
*
* This accepts most variations of base-64 encoding, including:
* * with or without line breaks
* * with or without the final group padded with '=' or '_' characters
* (The most economical Base-64 variant does not pad the last group and
* omits line breaks; RFC1341 used for MIME requires both.)
*/
char *
base64_decode(const char *s, size_t len, size_t *out_len)
{
static const unsigned char digits[64] = {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems identical to the digits[] in encode. If so, let's move it to global scope while preserving the static const notation.

'A','B','C','D','E','F','G','H','I','J','K','L','M','N',
'O','P','Q','R','S','T','U','V','W','X','Y','Z','a','b',
'c','d','e','f','g','h','i','j','k','l','m','n','o','p',
'q','r','s','t','u','v','w','x','y','z','0','1','2','3',
'4','5','6','7','8','9','+','/' };
static unsigned char decode_table[128];
char *out, *d;
const unsigned char *src = (const unsigned char *)s;

/* If the decode table is not yet initialized, prepare it. */
if (decode_table[digits[1]] != 1) {
unsigned i;
memset(decode_table, 0xff, sizeof(decode_table));
for (i = 0; i < sizeof(digits); i++)
decode_table[digits[i]] = i;
}

/* Allocate enough space to hold the entire output. */
/* Note that we may not use all of this... */
out = (char *)malloc(len - len / 4 + 1);
if (out == NULL) {
*out_len = 0;
return (NULL);
}
d = out;

while (len > 0) {
/* Collect the next group of (up to) four characters. */
int v = 0;
int group_size = 0;
while (group_size < 4 && len > 0) {
/* '=' or '_' padding indicates final group. */
if (*src == '=' || *src == '_') {
len = 0;
break;
}
/* Skip illegal characters (including line breaks) */
if (*src > 127 || *src < 32
|| decode_table[*src] == 0xff) {
len--;
src++;
continue;
}
v <<= 6;
v |= decode_table[*src++];
len --;
group_size++;
}
/* Align a short group properly. */
v <<= 6 * (4 - group_size);
/* Unpack the group we just collected. */
switch (group_size) {
case 4: d[2] = v & 0xff;
/* FALLTHROUGH */
case 3: d[1] = (v >> 8) & 0xff;
/* FALLTHROUGH */
case 2: d[0] = (v >> 16) & 0xff;
break;
case 1: /* this is invalid! */
break;
}
d += group_size * 3 / 4;
}

*out_len = d - out;
return (out);
}

/*
* Encode a sequence of bytes into a C string using base-64 encoding.
*
* Returns a null-terminated C string allocated with malloc(); caller
* is responsible for freeing the result.
*/
char *
base64_encode(const char *s, size_t len)
{
static const char digits[64] =
{ 'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O',
'P','Q','R','S','T','U','V','W','X','Y','Z','a','b','c','d',
'e','f','g','h','i','j','k','l','m','n','o','p','q','r','s',
't','u','v','w','x','y','z','0','1','2','3','4','5','6','7',
'8','9','+','/' };
int v;
char *d, *out;

/* 3 bytes becomes 4 chars, but round up and allow for trailing NUL */
out = (char *)malloc((len * 4 + 2) / 3 + 1);
if (out == NULL)
return (NULL);
d = out;

/* Convert each group of 3 bytes into 4 characters. */
while (len >= 3) {
v = (((int)s[0] << 16) & 0xff0000)
| (((int)s[1] << 8) & 0xff00)
| (((int)s[2]) & 0x00ff);
s += 3;
len -= 3;
*d++ = digits[(v >> 18) & 0x3f];
*d++ = digits[(v >> 12) & 0x3f];
*d++ = digits[(v >> 6) & 0x3f];
*d++ = digits[(v) & 0x3f];
}
/* Handle final group of 1 byte (2 chars) or 2 bytes (3 chars). */
switch (len) {
case 0: break;
case 1:
v = (((int)s[0] << 16) & 0xff0000);
*d++ = digits[(v >> 18) & 0x3f];
*d++ = digits[(v >> 12) & 0x3f];
break;
case 2:
v = (((int)s[0] << 16) & 0xff0000)
| (((int)s[1] << 8) & 0xff00);
*d++ = digits[(v >> 18) & 0x3f];
*d++ = digits[(v >> 12) & 0x3f];
*d++ = digits[(v >> 6) & 0x3f];
break;
}
/* Add trailing NUL character so output is a valid C string. */
*d = '\0';
return (out);
}
13 changes: 13 additions & 0 deletions libarchive/archive_base64_private.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#ifndef ARCHIVE_BASE64_PRIVATE_H_INCLUDED
#define ARCHIVE_BASE64_PRIVATE_H_INCLUDED

#ifndef __LIBARCHIVE_BUILD
#ifndef __LIBARCHIVE_TEST
#error This header is only to be used internally to libarchive.
#endif
#endif

char *base64_decode(const char *s, size_t len, size_t *out_len);
char *base64_encode(const char *s, size_t len);

#endif
30 changes: 30 additions & 0 deletions libarchive/archive_read_support_format_mtree.c
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ __FBSDID("$FreeBSD: head/lib/libarchive/archive_read_support_format_mtree.c 2011
#endif

#include "archive.h"
#include "archive_base64_private.h"
#include "archive_entry.h"
#include "archive_entry_private.h"
#include "archive_private.h"
Expand Down Expand Up @@ -79,6 +80,7 @@ __FBSDID("$FreeBSD: head/lib/libarchive/archive_read_support_format_mtree.c 2011

#define MTREE_HAS_OPTIONAL 0x0800
#define MTREE_HAS_NOCHANGE 0x1000 /* FreeBSD specific */
#define MTREE_HAS_XATTR 0x2000 /* extension */

#define MAX_LINE_LEN (1024 * 1024)

Expand Down Expand Up @@ -1829,6 +1831,34 @@ parse_keyword(struct archive_read *a, struct mtree *mtree,
break;
}
__LA_FALLTHROUGH;
case 'x':
if (strncmp(key, "xattr.", sizeof("xattr.") - 1) == 0) {
char *name;
char *decoded_val;
size_t decoded_len;
*parsed_kws |= MTREE_HAS_XATTR;
name = strchr(key, '.');
if (*++name == '\0') {
archive_set_error(&a->archive,
ARCHIVE_ERRNO_FILE_FORMAT,
"Malformed attribute \"%s\"; "
"ignoring", key);
return (ARCHIVE_WARN);
}
parse_escapes(name, NULL);
decoded_val = base64_decode(val, strlen(val),
&decoded_len);
if (decoded_val == NULL) {
archive_set_error(&a->archive, ENOMEM,
"Can't allocate memory");
return (ARCHIVE_FATAL);
}
archive_entry_xattr_add_entry(entry, name,
decoded_val, decoded_len);
free(decoded_val);
break;
}
__LA_FALLTHROUGH;
default:
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
"Unrecognized key %s=%s", key, val);
Expand Down
83 changes: 1 addition & 82 deletions libarchive/archive_read_support_format_tar.c
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ __FBSDID("$FreeBSD: head/lib/libarchive/archive_read_support_format_tar.c 201161

#include "archive.h"
#include "archive_acl_private.h" /* For ACL parsing routines. */
#include "archive_base64_private.h"
#include "archive_entry.h"
#include "archive_entry_locale.h"
#include "archive_private.h"
Expand Down Expand Up @@ -159,7 +160,6 @@ struct tar {
};

static int archive_block_is_null(const char *p);
static char *base64_decode(const char *, size_t, size_t *);
static int gnu_add_sparse_entry(struct archive_read *, struct tar *,
int64_t offset, int64_t remaining);

Expand Down Expand Up @@ -2798,87 +2798,6 @@ readline(struct archive_read *a, struct tar *tar, const char **start,
}
}

/*
* base64_decode - Base64 decode
*
* This accepts most variations of base-64 encoding, including:
* * with or without line breaks
* * with or without the final group padded with '=' or '_' characters
* (The most economical Base-64 variant does not pad the last group and
* omits line breaks; RFC1341 used for MIME requires both.)
*/
static char *
base64_decode(const char *s, size_t len, size_t *out_len)
{
static const unsigned char digits[64] = {
'A','B','C','D','E','F','G','H','I','J','K','L','M','N',
'O','P','Q','R','S','T','U','V','W','X','Y','Z','a','b',
'c','d','e','f','g','h','i','j','k','l','m','n','o','p',
'q','r','s','t','u','v','w','x','y','z','0','1','2','3',
'4','5','6','7','8','9','+','/' };
static unsigned char decode_table[128];
char *out, *d;
const unsigned char *src = (const unsigned char *)s;

/* If the decode table is not yet initialized, prepare it. */
if (decode_table[digits[1]] != 1) {
unsigned i;
memset(decode_table, 0xff, sizeof(decode_table));
for (i = 0; i < sizeof(digits); i++)
decode_table[digits[i]] = i;
}

/* Allocate enough space to hold the entire output. */
/* Note that we may not use all of this... */
out = (char *)malloc(len - len / 4 + 1);
if (out == NULL) {
*out_len = 0;
return (NULL);
}
d = out;

while (len > 0) {
/* Collect the next group of (up to) four characters. */
int v = 0;
int group_size = 0;
while (group_size < 4 && len > 0) {
/* '=' or '_' padding indicates final group. */
if (*src == '=' || *src == '_') {
len = 0;
break;
}
/* Skip illegal characters (including line breaks) */
if (*src > 127 || *src < 32
|| decode_table[*src] == 0xff) {
len--;
src++;
continue;
}
v <<= 6;
v |= decode_table[*src++];
len --;
group_size++;
}
/* Align a short group properly. */
v <<= 6 * (4 - group_size);
/* Unpack the group we just collected. */
switch (group_size) {
case 4: d[2] = v & 0xff;
/* FALLTHROUGH */
case 3: d[1] = (v >> 8) & 0xff;
/* FALLTHROUGH */
case 2: d[0] = (v >> 16) & 0xff;
break;
case 1: /* this is invalid! */
break;
}
d += group_size * 3 / 4;
}

*out_len = d - out;
return (out);
}

static char *
url_decode(const char *in)
{
Expand Down