Merge pull request #1 from damonearp/xattr

Fixed up the XATTR_Branch
This commit is contained in:
4n6Tools authored and GitHub committed 2016-10-13 06:33:42 -04:00
commit ecfbf3def0
17 files changed
+384 -96

No files matched your search

+1 -1
View File
@@ -23,7 +23,7 @@ PROJECT_NAME = dcp
# This could be handy for archiving the generated documentation or
# if some version control system is used.
PROJECT_NUMBER = 1.0.0
PROJECT_NUMBER = 1.0.6
# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)
# base path where the generated documentation will be put.
+1 -1
View File
@@ -1 +1 @@
1.0.0
1.0.6
+2
View File
@@ -21,6 +21,8 @@ option "output" o "where to write output" string typestr="FILE" optional
option "input" i "output from a previous run to check for uniqueness"
string typestr="FILE" optional multiple
option "xattr" x "where to write eXtended ATTRibutes" string typestr="FILE" optional
option "owner" O "username to chown new files/dirs"
string typestr="USER" optional
+6 -6
View File
@@ -1,14 +1,14 @@
bin_PROGRAMS=dcp
dcp_SOURCES=main.c digest.c cmdline.c io/io_entry.c io/io_metadata.c \
io/pack.c io/io_index.c index/db_index.c io_dcp_processor.c logging.c \
fd.c impl/dcp.c impl/process_regular.c impl/process_directory.c \
dcp_SOURCES=main.c digest.c cmdline.c io/io_entry.c io/io_metadata.c \
io/pack.c io/io_index.c io/io_xattr.c index/db_index.c io_dcp_processor.c \
logging.c fd.c impl/dcp.c impl/process_regular.c impl/process_directory.c \
impl/process_symlink.c impl/preprocess.c impl/process_special.c
dcp_CPPFLAGS=-Wall -Wextra -Werror -fpie -Wno-unused-but-set-variable
dcp_LDFLAGS=-lcrypto -ljansson -ldb -pie
# ensure the headers make it into the dist tarball
EXTRA_DIST=digest.h cmdline.h io/io_entry.h io/io_metadata.h io/pack.h \
io/io.h io/io_index.h fd.h index/index.h io_dcp_processor.h logging.h \
entry.h impl/dcp.h impl/process.h
EXTRA_DIST=digest.h cmdline.h io/io_entry.h io/io_metadata.h io/pack.h \
io/io.h io/io_index.h io/io_xattr.h fd.h index/index.h io_dcp_processor.h \
logging.h entry.h impl/dcp.h impl/process.h
+12 -8
View File
@@ -120,9 +120,11 @@ int dcp(const char *newpath, const char *src[], size_t srcc,
dapath = NULL;
destpath = NULL;
/* dest is the directory to clone every entry in, if newpath is an
/*
* dest is the directory to clone every entry in, if newpath is an
* existing directory dest represents that, otherwise it is the parent
* of the file/directory to create */
* of the file/directory to create
*/
if (initdestandpaths(&destroot,path,&destpath,&dapath,sanitized,srcc) != 0)
{
free(path);
@@ -168,7 +170,8 @@ int dcp(const char *newpath, const char *src[], size_t srcc,
if (do_append(ent, &destroot, sanitized))
strcat(strcat(path, "/"), ent->fts_name);
/* unfortunatly we have two cases where dapath wont be set right
/*
* unfortunatly we have two cases where dapath wont be set right
* 1. cp a dir to a dir that dne: report dapath as "/"
* 2. cp a file to a path that dne: report dapath as "/$filename"
*/
@@ -374,8 +377,9 @@ void process(file_t *newdir, const char *newpath, FTSENT *ent,
state = DCP_DIR_FAILED;
}
popts->callback(state, pathmd5, dapath, ent->fts_statp, NULL, NULL,
NULL, NULL, -1, popts->callback_ctx);
popts->callback(state, pathmd5, dapath, ent->fts_statp,
ent->fts_accpath, NULL, NULL, NULL, NULL, NULL, -1,
popts->callback_ctx);
break;
}
@@ -417,7 +421,7 @@ void process(file_t *newdir, const char *newpath, FTSENT *ent,
case FTS_ERR:
{
popts->callback(DCP_FAILED, pathmd5, dapath, NULL, NULL, NULL, NULL,
NULL, -1, popts->callback_ctx);
NULL, NULL, NULL, -1, popts->callback_ctx);
errno = ent->fts_errno;
log_error("fts_read '%s'", ent->fts_path);
break;
@@ -426,7 +430,7 @@ void process(file_t *newdir, const char *newpath, FTSENT *ent,
case FTS_NS:
{
popts->callback(DCP_FAILED, pathmd5, dapath, NULL, NULL, NULL, NULL,
NULL, -1, popts->callback_ctx);
NULL, NULL, NULL, -1, popts->callback_ctx);
errno = ent->fts_errno;
log_error("cannot stat '%s'", ent->fts_path);
break;
@@ -435,7 +439,7 @@ void process(file_t *newdir, const char *newpath, FTSENT *ent,
case FTS_DNR:
{
popts->callback(DCP_FAILED, pathmd5, dapath, NULL, NULL, NULL, NULL,
NULL, -1, popts->callback_ctx);
NULL, NULL, NULL, -1, popts->callback_ctx);
errno = ent->fts_errno;
log_error("cannot read dir '%s'", ent->fts_path);
break;
+2 -1
View File
@@ -53,7 +53,8 @@ typedef enum {
* calculated.
*/
typedef int (*dcp_callback_f)(dcp_state_t state, const void *pathmd5,
const char *path, const struct stat *sstat, const void *md5,
const char *dapath, const struct stat *sstat, const char *accesspath,
const char *symlinkpath, const void *md5,
const void *sha1, const void *sha256, const void *sha512,
unsigned long process_time, void *context);
+23 -17
View File
@@ -19,6 +19,10 @@
#include <time.h>
#include <unistd.h>
#include <malloc.h>
#include <sys/xattr.h>
#include <stdio.h>
#include "process.h"
#include "../digest.h"
#include "../fd.h"
@@ -26,7 +30,6 @@
#include "../logging.h"
#include "dcp.h"
/* Type Defs ******************************************************************/
@@ -103,7 +106,7 @@ static int copy_fd(int dirfd, const char *pathname, struct stream *stream,
*
* @return number of bytes that are valid in buf, -1 on error
*/
static ssize_t cache_n_digest(digesterset_t *set, int fd, void *buf,
static ssize_t cache_n_digest(digesterset_t *set, int fd, void *buf,
size_t blen);
/**
@@ -160,8 +163,8 @@ int process_regular(file_t *newdir, const char *newpath, const char *oldpath,
if ((s = open(oldpath, O_RDONLY)) == -1)
{
log_error("cannot open '%s'", oldpath);
opts->callback(DCP_FAILED, pathmd5, dapath, oldst, NULL, NULL, NULL,
NULL, -1, opts->callback_ctx);
opts->callback(DCP_FAILED, pathmd5, dapath, oldst, oldpath, NULL, NULL,
NULL, NULL, NULL, -1, opts->callback_ctx);
return -1;
}
@@ -170,8 +173,10 @@ int process_regular(file_t *newdir, const char *newpath, const char *oldpath,
/* ensure we create the hash needed for the and index */
digesterset_create(&dgstset, opts->digests | idxkeytype);
/* there is no index to check against, just copy and digest at the same
* time */
/*
* there is no index to check against, just copy and digest at the same
* time
*/
if (opts->index == NULL)
{
valid_len = copy_n_digest(newdir->fd, newpath, opts->uid, opts->gid,
@@ -180,8 +185,8 @@ int process_regular(file_t *newdir, const char *newpath, const char *oldpath,
if (valid_len < 0)
{
log_debugx("failed copying and hashing '%s'", oldpath);
opts->callback(DCP_FAILED, pathmd5, dapath, oldst, NULL, NULL,
NULL, NULL, -1, opts->callback_ctx);
opts->callback(DCP_FAILED, pathmd5, dapath, oldst, oldpath, NULL,
NULL, NULL, NULL, NULL, -1, opts->callback_ctx);
ret = -1;
goto cleanup;
}
@@ -192,7 +197,7 @@ int process_regular(file_t *newdir, const char *newpath, const char *oldpath,
diff = ((clock() - start) * 1000) / CLOCKS_PER_SEC;
/* finally send the information to the file processor */
opts->callback(DCP_FILE_COPIED, pathmd5, dapath, oldst,
opts->callback(DCP_FILE_COPIED, pathmd5, dapath, oldst, oldpath, NULL,
digesterset_get_value(&dgstset, DGST_MD5),
digesterset_get_value(&dgstset, DGST_SHA1),
digesterset_get_value(&dgstset, DGST_SHA256),
@@ -202,14 +207,13 @@ int process_regular(file_t *newdir, const char *newpath, const char *oldpath,
}
else
{
/* read in the file and calculate the desired digests */
if ((valid_len = cache_n_digest(&dgstset, s, opts->buffer,
opts->buffer_size)) == -1)
{
log_debugx("cannot calculate hashes for '%s'", oldpath);
opts->callback(DCP_FAILED, pathmd5, dapath, oldst, NULL, NULL,
NULL, NULL, -1, opts->callback_ctx);
opts->callback(DCP_FAILED, pathmd5, dapath, oldst, oldpath, NULL,
NULL, NULL, NULL, NULL, -1, opts->callback_ctx);
ret = -1;
goto cleanup;
}
@@ -226,8 +230,8 @@ int process_regular(file_t *newdir, const char *newpath, const char *oldpath,
ret = -1;
goto cleanup;
/* we have seen this file, skip it */
case INDEX_SUCCESS:
/* we have seen this file, skip it */
ret = 0; /* set ret to success */
goto cleanup;
@@ -236,9 +240,11 @@ int process_regular(file_t *newdir, const char *newpath, const char *oldpath,
}
}
/* if cache_n_digest was able to store the whole file in the buffer then
/*
* if cache_n_digest was able to store the whole file in the buffer then
* we do not need to seek to the beginning of the fd and reread the
* bytes */
* bytes
*/
if (valid_len == oldst->st_size)
{
datastream.bytes = opts->buffer;
@@ -259,7 +265,7 @@ int process_regular(file_t *newdir, const char *newpath, const char *oldpath,
diff = ((clock() - start) * 1000) / CLOCKS_PER_SEC;
/* finally send the information to the file processor */
opts->callback(state, pathmd5, dapath, oldst,
opts->callback(state, pathmd5, dapath, oldst, oldpath, NULL,
digesterset_get_value(&dgstset, DGST_MD5),
digesterset_get_value(&dgstset, DGST_SHA1),
digesterset_get_value(&dgstset, DGST_SHA256),
@@ -280,7 +286,7 @@ int process_regular(file_t *newdir, const char *newpath, const char *oldpath,
/* Private Impl ***************************************************************/
int copy_fd(int dirfd, const char *pathname, struct stream *stream, uid_t uid,
int copy_fd(int dirfd, const char *pathname, struct stream *stream, uid_t uid,
gid_t gid)
{
int d;
+1 -1
View File
@@ -40,7 +40,7 @@ int process_special(file_t *newdir, const char *newpath, const char *oldpath,
if (r == 0 && fchownat(newdir->fd, newpath, opts->uid, opts->gid, 0) != 0)
log_warn("cannot chown '%s'", pathstr(newdir, newpath));
opts->callback(state, pathmd5, dapath, oldst, NULL, NULL, NULL, NULL, -1,
opts->callback(state, pathmd5, dapath, oldst, oldpath, NULL, NULL, NULL, NULL, NULL, -1,
opts->callback_ctx);
return r;
}
+3 -1
View File
@@ -14,6 +14,8 @@
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include "process.h"
#include "../logging.h"
#include "dcp.h"
@@ -72,7 +74,7 @@ int process_symlink(file_t *newdir, const char *newpath, const char *oldpath,
}
}
}
opts->callback(state, pathmd5, dapath, oldst, NULL, NULL, NULL, NULL, -1,
opts->callback(state, pathmd5, dapath, oldst, oldpath, buf, NULL, NULL, NULL, NULL, -1,
opts->callback_ctx);
/* if we allocated a new buffer free it */
+1
View File
@@ -16,6 +16,7 @@
#include "io_entry.h"
#include "io_metadata.h"
#include "io_index.h"
#include "io_xattr.h"
#endif
+65 -30
View File
@@ -18,7 +18,7 @@
#include <time.h>
#include <linux/limits.h>
#include "jansson.h"
#include <jansson.h>
#include "io_entry.h"
#include "../entry.h"
@@ -117,7 +117,7 @@ int io_entry_read(entry_t *entry, FILE *in, size_t *line)
} while (buf[0] == '#');
/* for jannson's documentation, JSON_REJECT_DUPLICATES issues an error when
/* for jansson's documentation, JSON_REJECT_DUPLICATES issues an error when
* multiple keys in an object have the same name instead of default
* behavior which is to use the last defined value */
if ((obj = json_loads(buf, JSON_REJECT_DUPLICATES, &jerr)) == NULL)
@@ -311,15 +311,16 @@ int io_entry_read(entry_t *entry, FILE *in, size_t *line)
}
/* while jansson can be used for creating a json structure then printing it
/*
* while jansson can be used for creating a json structure then printing it
* out, there is a large overhead cost. Since we control the data only use
* jansson to escape the strings we cannot control. */
* jansson to escape the strings we cannot control.
*/
int io_entry_write_fields(const char *state, const char *path,
const struct stat *st, const void *pathmd5, const void *md5,
const void *sha1, const void *sha256, const void *sha512,
long elapsed, FILE *stream)
const struct stat *st, const void *pathmd5, const char *symlinkpath,
const void *md5, const void *sha1, const void *sha256,
const void *sha512, long elapsed, FILE *stream)
{
enum { MAX_LENGTH = PATH_MAX * 4 };
int ret;
@@ -328,14 +329,15 @@ int io_entry_write_fields(const char *state, const char *path,
/* use jansson for string character escaping of paths */
json_t *escaped;
/* used to hold hex strings for the hashes and the path if it contains
* non utf-8 characters */
/*
* used to hold hex strings for the hashes and the path if it contains
* non utf-8 characters
*/
char buf[MAX_LENGTH];
ret = 0;
/* we are writing a json object on the line*/
/* we are writing a json object on the line */
fputc('{', stream);
if (md5 != NULL)
@@ -362,18 +364,26 @@ int io_entry_write_fields(const char *state, const char *path,
fprintf(stream, "\"sha512\":\"%s\",", buf);
}
/*
* up till this point we have been appending commas to the end of the
* entries, this is because we don't know which hashes are going to be
* provided. Now that pathmd5 has been put on the stream we switch to
* commas before any new entries, allowing errors to simply exit and not
* output malformed json.
*/
unpack(buf, pathmd5, MD5_DIGEST_LENGTH);
fprintf(stream, "\"pathmd5\":\"%s\",", buf);
fprintf(stream, "\"pathmd5\":\"%s\"", buf); /* no commas before or after */
if (st != NULL)
{
/* mode, size and timestamps */
fprintf(stream,
"\"uid\":%u,\"gid\":%u,"
",\"uid\":%u,\"gid\":%u,"
"\"mode\":%u,\"size\":%jd,"
"\"asec\":%ld,\"ansec\":%ld,"
"\"msec\":%ld,\"mnsec\":%ld,"
"\"csec\":%ld,\"cnsec\":%ld,",
"\"csec\":%ld,\"cnsec\":%ld",
st->st_uid, st->st_gid,
st->st_mode, (intmax_t) st->st_size,
st->st_atim.tv_sec, st->st_atim.tv_nsec,
@@ -381,7 +391,7 @@ int io_entry_write_fields(const char *state, const char *path,
st->st_ctim.tv_sec, st->st_ctim.tv_nsec);
/* extract what type of file from the mode */
fprintf(stream, "\"type\":\"%s\",",
fprintf(stream, ",\"type\":\"%s\"",
S_ISREG(st->st_mode)? "reg" : S_ISDIR(st->st_mode)? "dir" :
S_ISLNK(st->st_mode)? "lnk" : S_ISCHR(st->st_mode)? "chr" :
S_ISBLK(st->st_mode)? "blk" : S_ISFIFO(st->st_mode)? "fifo" :
@@ -395,30 +405,54 @@ int io_entry_write_fields(const char *state, const char *path,
ret = -1;
goto cleanup;
}
fputs("\"state\":", stream);
fputs(",\"state\":", stream);
json_dumpf(escaped, stream, JSON_ENCODE_ANY);
json_decref(escaped);
fputc(',', stream);
/* # of secs elapsed while processing */
if (elapsed > -1)
fprintf(stream, "\"elapsed\":%ld,", elapsed);
fprintf(stream, ",\"elapsed\":%ld", elapsed);
/* PATH and PATHHEX, we prefer to output PATH which is a valid UTF-8 JSON
* escaped string, however if we come across a path with invalid utf-8 we
* still need a way to output it. */
/* if entry is a symlink we include what its target path was */
if (symlinkpath != NULL)
{
/*
* symlinkTarget valid utf-8 JSON escaped string where pointing
* symlinkTargetHex hex encoding of the target if jansson cannot encode
*/
if ((escaped = json_string(symlinkpath)) != NULL)
{
fputs(",\"symlinkTarget\":", stream);
json_dumpf(escaped, stream, JSON_ENCODE_ANY);
json_decref(escaped);
}
else /* jansson was unable to handle the string */
{
len = strlen(symlinkpath);
if ((len * 2 + 1) > MAX_LENGTH)
{
log_errorx("buffer too small, expected string with length < %d,"
" for non valid utf-8 string: '%s'", MAX_LENGTH,
symlinkpath);
ret = -1;
goto cleanup;
}
unpack(buf, symlinkpath, len);
fprintf(stream, ",\"symlinkTargetHex\":\"%s\"", buf);
}
}
/*
* path valid utf-8 JSON escaped path to the file
* pathHex hex encoding of the path, provided if jansson cannot encode
*/
if ((escaped = json_string(path)) != NULL)
{
fputs("\"path\":", stream);
/*
* JSON_ENCODE_ANY tell jansson to write any json type to stream not
* just Objects and Arrays
*/
fputs(",\"path\":", stream);
json_dumpf(escaped, stream, JSON_ENCODE_ANY);
json_decref(escaped);
}
else /* jansson was unable to handle the string, */
else /* jansson was unable to handle the string */
{
len = strlen(path);
if ((len * 2 + 1) > MAX_LENGTH)
@@ -429,9 +463,10 @@ int io_entry_write_fields(const char *state, const char *path,
goto cleanup;
}
unpack(buf, path, len);
fprintf(stream, "\"pathhex\":\"%s\",", buf);
fprintf(stream, ",\"pathhex\":\"%s\"", buf);
}
cleanup:
/* print a newline our record separator */
fputs("}\n", stream);
+4 -3
View File
@@ -46,6 +46,7 @@ int io_entry_read(entry_t *entry, FILE *in, size_t *line);
* @param path abs path of the file, with src dir treated as root
* @param st pointer to the source file's stat struct
* @param pathmd5 16 byte md5 of the path
* @param symlinkpath if entry is symlink where it's pointing, NULL otherwise
* @param md5 the md5 of the file's contents or NULL if not applicable
* @param sha1 sha1 of the file's contents or NULL if not applicable
* @param sha256 sha256 of the file's contents or NULL if not applicable
@@ -56,9 +57,9 @@ int io_entry_read(entry_t *entry, FILE *in, size_t *line);
* @return 0 on success, -1 on error
*/
int io_entry_write_fields(const char *state, const char *path,
const struct stat *st, const void *pathmd5, const void *md5,
const void *sha1, const void *sha256, const void *sha512,
long process_time, FILE *stream);
const struct stat *st, const void *pathmd5, const char *symlinkpath,
const void *md5, const void *sha1, const void *sha256,
const void *sha512, long process_time, FILE *stream);
#endif
+95
View File
@@ -0,0 +1,95 @@
/**
* @file
*
* @version 1.0
*
* @section DESCRIPTION
*
* Implementation of the io_xattr.h interface. Entries in dcp input and output
* are an entry in the filesystem that was copied/duplicated. For each
* file and symbolic link we log xattr information about each as a single line
* json object.
*/
#include <stdio.h>
#include <string.h>
#include <stddef.h>
#include <stdint.h>
#include <time.h>
#include <jansson.h>
#include <openssl/bio.h>
#include <openssl/evp.h>
#include "io_xattr.h"
#include "../digest.h"
#include "pack.h"
#include "../logging.h"
/* Public Impl ****************************************************************/
int io_entry_write_xattr_fields(const void *pathmd5, const char *name,
void *valuebuffer, ssize_t valuesize, FILE *stream)
{
int ret;
int w;
/* where to store the hex representation of the path md5 sum */
char buf[(MD5_DIGEST_LENGTH * 2) + 1];
/* we store the xattr value as base64 */
BIO *bio, *b64;
/* used to properly escape the utf-8 name of an xattr */
json_t *escaped;
ret = 0;
b64 = NULL;
/* we are writing a json object on the line */
fputc('{', stream);
unpack(buf, pathmd5, MD5_DIGEST_LENGTH);
fprintf(stream, "\"pathmd5\":\"%s\",", buf);
if (name != NULL)
{
if ((escaped = json_string(name)) == NULL)
{
log_errorx("non valid utf-8 xattr string '%s'", name);
ret = -1;
goto cleanup;
}
fputs("\"xattrName\":", stream);
json_dumpf(escaped, stream, JSON_ENCODE_ANY);
json_decref(escaped);
}
if (valuesize > 0)
{
fputs(",\"xattrValue\":\"", stream);
/*
* base64 encoding
* https://www.openssl.org/docs/manmaster/crypto/BIO_f_base64.html
*/
b64 = BIO_new(BIO_f_base64());
BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL); /* do not append newline */
bio = BIO_new_fp(stream, BIO_NOCLOSE); /* do not close stream */
BIO_push(b64, bio);
if ((w = BIO_write(b64, valuebuffer, valuesize)) != valuesize)
{
log_errorx("cannot base64 encode xattr value for attr: '%s'", name);
ret = -1;
}
BIO_flush(b64);
BIO_free_all(b64);
fputc('"', stream);
}
cleanup:
/* print a newline our record separator */
fputs("}\n", stream);
return ret;
}
+36
View File
@@ -0,0 +1,36 @@
/**
* @file
*
* @version 1.0
*
* @section DESCRIPTION
*
* API for reading and writing extended attributes to a stream. Each attribute
* is written as a JSON Object with the path's md5.
*/
#ifndef IO_XATTR_H__
#define IO_XATTR_H__
#include <stdio.h>
#include <stddef.h>
#include <sys/types.h>
/* Public API *****************************************************************/
/**
* write the following fields as a JSON object to the stream
*
* @param pathmd5 16 byte md5 of the path
* @param name the name of the xattr field
* @param valuebuffer the contents of the xattr field
* @param valuesize the size of the xattr field
* @param stream where to write the json object
*
* @return 0 on success, -1 on error
*/
int io_entry_write_xattr_fields(const void *pathmd5, const char *name,
void *valuebuffer, ssize_t valuesize, FILE *stream);
#endif
+65 -7
View File
@@ -11,6 +11,8 @@
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/xattr.h>
#include <linux/limits.h>
#include "io_dcp_processor.h"
#include "entry.h"
@@ -28,32 +30,44 @@
*/
struct io_dcp_processor_ctx {
FILE *out; /**< where to write each file system entry info to */
FILE *xattrout; /**< where to write xattr values for paths */
};
/* Private API ****************************************************************/
static int process_xattrs(const void *pathmd5, const char *filepath, FILE *out);
/* Public Impl ****************************************************************/
int io_dcp_processor(dcp_state_t state, const void *pathmd5,
const char *dapath, const struct stat *st, const void *md5,
const void *sha1, const void *sha256, const void *sha512,
unsigned long process_time, void *context)
const char *dapath, const struct stat *st, const char *accesspath,
const char *symlinkpath, const void *md5, const void *sha1,
const void *sha256, const void *sha512, unsigned long process_time,
void *context)
{
struct io_dcp_processor_ctx *ctx = context;
return io_entry_write_fields(dcp_strstate(state), dapath, st,
pathmd5, md5, sha1, sha256, sha512, process_time, ctx->out);
process_xattrs(pathmd5, accesspath, ctx->xattrout);
return io_entry_write_fields(dcp_strstate(state), dapath, st, pathmd5,
symlinkpath, md5, sha1, sha256, sha512, process_time, ctx->out);
}
int io_dcp_processor_ctx_create(io_dcp_processor_ctx_t **ctx, FILE *stream)
int io_dcp_processor_ctx_create(io_dcp_processor_ctx_t **ctx, FILE *stream,
FILE *xattrstream)
{
if (ctx != NULL)
{
*ctx = malloc(sizeof(struct io_dcp_processor_ctx));
(*ctx)->out = stream;
(*ctx)->xattrout = xattrstream;
return 0;
}
return 0;
return -1;
}
@@ -63,3 +77,47 @@ int io_dcp_processor_ctx_free(io_dcp_processor_ctx_t *ctx)
free(ctx);
return 0;
}
/* Private Impl **************************************************************/
int process_xattrs(const void *pathmd5, const char *filepath, FILE *out)
{
char keys[XATTR_LIST_MAX];
size_t keysbuffersize = XATTR_LIST_MAX;
uint8_t valuebuffer[XATTR_SIZE_MAX];
size_t valuebuffersize = XATTR_SIZE_MAX;
ssize_t bufsize, valuesize;
char *next, *end;
if (filepath == NULL)
return 0; /* Nothing to do */
if ((bufsize = llistxattr(filepath, keys, keysbuffersize)) == 0)
return 0;
else if (bufsize < 0)
{
/* xattrs not supported or disabled for this file, success */
if (errno == ENOTSUP)
return 0;
log_error("llistxattr");
return -1;
}
end = keys + bufsize; /* pointer to the end of the list */
/* keys is one large string with '\0' delimited names */
for (next = keys; next < end; next += (strlen(next) + 1))
{
memset(valuebuffer, 0, valuebuffersize);
valuesize = lgetxattr(filepath, next, valuebuffer, valuebuffersize);
if (valuesize < 0)
log_error("lgetxattr");
else
io_entry_write_xattr_fields(pathmd5,next,valuebuffer,valuesize,out);
}
fflush(out);
return 0;
}
+12 -8
View File
@@ -34,11 +34,12 @@ typedef struct io_dcp_processor_ctx io_dcp_processor_ctx_t;
* An dcp callback function which writes each file/dir/dev to the configured
* FILE stream. Outputs each entry using @see io_entry.h.
*
* @param state the resulting state of dcp processing,
* @see impl/dcp.h
* @param path mount relative path to the file to be copied
* @param state the resulting state of processing, @see impl/dcp.h
* @param pathmd5 the md5 sum of the file's dapath
* @param dapath mount relative path to the file to be copied
* @param st stat struct for the source file
* @param dpath where the file is being copied to
* @param accesspath path to the original file
* @param symlinkpath if file is a symbolic link, where is it pointing
* @param md5 md5 digest of the file
* @param sha1 sha1 digest of the file
* @param sha256 sha256 digest of the file
@@ -50,9 +51,10 @@ typedef struct io_dcp_processor_ctx io_dcp_processor_ctx_t;
* @return 0 on success
*/
int io_dcp_processor(dcp_state_t state, const void *pathmd5,
const char *path, const struct stat *st, const void *md5,
const void *sha1, const void *sha256, const void *sha512,
unsigned long process_time, void *context);
const char *dapath, const struct stat *st, const char *accesspath,
const char *symlinkpath, const void *md5, const void *sha1,
const void *sha256, const void *sha512, unsigned long process_time,
void *context);
/**
@@ -60,10 +62,12 @@ int io_dcp_processor(dcp_state_t state, const void *pathmd5,
*
* @param ctx pointer to the context to initialize
* @param stream where to serialize the entries to.
* @param xattrstream where to serialize the extended attributes to
*
* @return 0 on success
*/
int io_dcp_processor_ctx_create(io_dcp_processor_ctx_t **ctx, FILE *stream);
int io_dcp_processor_ctx_create(io_dcp_processor_ctx_t **ctx, FILE *stream,
FILE *xattrstream);
/**
+55 -12
View File
@@ -65,6 +65,8 @@ struct mainopts {
size_t inputcount; /**< # input files specified */
FILE *outputstream; /**< where we should write results to */
char *outfilename; /**< the output file that outputstream is writing */
FILE *xattroutputstream;/**< where we should write xattr results to */
char *xattroutfilename; /**< the output file that xattroutputstream is writing to */
uid_t uid; /**< id of who will own the copies */
gid_t gid; /**< id of what group will own the copies */
@@ -95,6 +97,8 @@ static int print_metadata(FILE *out, const char *version, int argc,
static int parse_digests(const struct cmdline_info *info);
static FILE *parse_outputstream(const struct cmdline_info *info,
char **outfilename);
static FILE *parse_xattroutputstream(const struct cmdline_info *info,
char **xattroutfilename);
static gid_t parse_group(const struct cmdline_info *info, char **name);
static uid_t parse_owner(const struct cmdline_info *info, char **name);
static size_t parse_cache_size(const struct cmdline_info *info);
@@ -217,7 +221,42 @@ FILE *parse_outputstream(const struct cmdline_info *info, char **outfilename)
else
log_crit(EXIT_FAILURE, "cannot create output file '%s'", name);
}
if ((stream = fdopen(fd, "a")) == NULL)
log_crit(EXIT_FAILURE, "cannot create output stream");
*outfilename = strdup(name);
}
return stream;
}
FILE *parse_xattroutputstream(const struct cmdline_info *info, char **outfilename)
{
int fd;
size_t i;
char name[38]; /* enough space to hold "dcp(1234567890).xattr.out\0" */
FILE *stream;
if (info->xattr_given)
{
if ((stream = fopen(info->xattr_arg, "w")) == NULL)
log_crit(EXIT_FAILURE,"failed to open output file '%s'",
info->xattr_arg);
*outfilename = strdup(info->xattr_arg);
}
/* if no output is specified create an dcp.xattr.out in cwd */
else
{
snprintf(name, sizeof(name), "dcp.xattr.out");
i = 0;
while ((fd = open(name, O_WRONLY | O_CREAT | O_EXCL, 0666)) == -1)
{
if (errno == EEXIST)
snprintf(name, sizeof(name), "dcp(%zu).xattr.out", ++i);
else
log_crit(EXIT_FAILURE, "cannot create output file '%s'", name);
}
if ((stream = fdopen(fd, "a")) == NULL)
log_crit(EXIT_FAILURE, "cannot create output stream");
*outfilename = strdup(name);
@@ -296,6 +335,7 @@ int mainopts_parse(struct mainopts *opts, const struct cmdline_info *info)
opts->dest = opts->files[opts->filecount];
opts->digests = parse_digests(info);
opts->outputstream = parse_outputstream(info, &opts->outfilename);
opts->xattroutputstream = parse_xattroutputstream(info, &opts->xattroutfilename);
opts->inputs = (const char **) info->input_arg;
opts->inputcount = info->input_given;
opts->uid = parse_owner(info, &opts->username);
@@ -309,9 +349,11 @@ int mainopts_parse(struct mainopts *opts, const struct cmdline_info *info)
void mainopts_cleanup(struct mainopts *opts)
{
if (opts->outfilename != NULL) free(opts->outfilename);
if (opts->xattroutfilename != NULL) free(opts->xattroutfilename);
if (opts->username != NULL) free(opts->username);
if (opts->groupname != NULL) free(opts->groupname);
if (opts->outputstream != NULL) fclose(opts->outputstream);
if (opts->xattroutputstream != NULL) fclose(opts->xattroutputstream);
}
@@ -339,9 +381,10 @@ int dcp_main(const struct mainopts *opts, int argc, const char *argv[])
/* output information about this run of dcp */
print_metadata(opts->outputstream, VERSION, argc, argv, opts, digests);
print_metadata(opts->xattroutputstream, VERSION, argc, argv, opts, digests);
/* setup how and where to send the data gathered during this run */
if (io_dcp_processor_ctx_create(&ctx, opts->outputstream) == -1)
if (io_dcp_processor_ctx_create(&ctx, opts->outputstream, opts->xattroutputstream) == -1)
log_critx(EXIT_FAILURE, "cannot instantiate output context");
/* set the options struct */
@@ -382,10 +425,10 @@ index_t *build_index(int digests, const char *paths[], size_t count)
digest_t type;
size_t i;
/* assign type to the first valid one we find, checking md5 then sha1 ... */
if ( !(type = digests & DGST_MD5) && !(type = digests & DGST_SHA1) &&
!(type = digests & DGST_SHA256) && !(type = digests & DGST_SHA512))
log_critx(EXIT_FAILURE, "corrput parsing of digest types from inputs");
/* assign type to the first valid one we find, checking md5 then sha1 ... */
if ( !(type = digests & DGST_MD5) && !(type = digests & DGST_SHA1) &&
!(type = digests & DGST_SHA256) && !(type = digests & DGST_SHA512))
log_critx(EXIT_FAILURE, "corrput parsing of digest types from inputs");
if (index_create(&idx, type) != 0)
log_critx(EXIT_FAILURE, "cannot create index");
@@ -439,8 +482,8 @@ int prepare(const char **files, size_t count, const char *dest, char **newdest)
{
name = basename(path);
/* build the dest/name path including the slash if needed */
if(asprintf(&fulldest, "%s%s%s",
dest, dest[strlen(dest)-1] == '/'? "" : "/", name) < 0)
if(asprintf(&fulldest, "%s%s%s", dest,
dest[strlen(dest)-1] == '/'? "" : "/", name) < 0)
{
fulldest = NULL;
}
@@ -491,7 +534,7 @@ int print_metadata(FILE *out, const char *version, int argc,
/* current working directory */
if ((cwd = getcwd(NULL, 0)) == NULL)
log_warn("cannot retrieve current working directory");
log_warn("cannot retrieve current working directory");
/* hostname */
gethostname(hostname, sizeof(hostname));
@@ -506,13 +549,13 @@ int print_metadata(FILE *out, const char *version, int argc,
if (cwd != NULL)
{
io_metadata_put_json("cwd ", 1, (const char **) &cwd, out);
free(cwd);
io_metadata_put_json("cwd ", 1, (const char **) &cwd, out);
free(cwd);
}
io_metadata_put_json("sources ", opts->filecount, opts->files, out);
io_metadata_put_json("destination", 1, (const char **) &opts->dest, out);
io_metadata_put_json("output ", 1,(const char**)&opts->outfilename,out);
io_metadata_put_json("destination",1,(const char **) &opts->dest, out);
io_metadata_put_json("output ",1,(const char**)&opts->outfilename,out);
if (opts->username != NULL)
io_metadata_put( "data_owner ", opts->username, out);