|
|
3db888 |
/******************************************************/
|
|
|
3db888 |
/* tpax: a topological pax implementation */
|
|
|
3db888 |
/* Copyright (C) 2020 Z. Gilboa */
|
|
|
3db888 |
/* Released under GPLv2 and GPLv3; see COPYING.TPAX. */
|
|
|
3db888 |
/******************************************************/
|
|
|
3db888 |
|
|
|
3db888 |
#include <stdint.h>
|
|
|
3db888 |
#include <stdlib.h>
|
|
|
3db888 |
#include <string.h>
|
|
|
3db888 |
#include <unistd.h>
|
|
|
3db888 |
#include <fcntl.h>
|
|
|
3db888 |
#include <errno.h>
|
|
|
3db888 |
#include <grp.h>
|
|
|
3db888 |
#include <pwd.h>
|
|
|
3db888 |
#include <sys/stat.h>
|
|
|
3db888 |
|
|
|
3db888 |
#include <tpax/tpax.h>
|
|
|
3db888 |
#include <tpax/tpax_specs.h>
|
|
|
3db888 |
#include "tpax_driver_impl.h"
|
|
|
3db888 |
#include "tpax_tmpfile_impl.h"
|
|
|
3db888 |
#include "tpax_errinfo_impl.h"
|
|
|
3db888 |
|
|
|
3db888 |
#ifndef ssizeof
|
|
|
3db888 |
#define ssizeof(x) (ssize_t)(sizeof(x))
|
|
|
3db888 |
#endif
|
|
|
3db888 |
|
|
|
3db888 |
static int tpax_archive_append_memory_data(
|
|
|
3db888 |
int fdout,
|
|
|
3db888 |
void * buf,
|
|
|
3db888 |
ssize_t nbytes)
|
|
|
3db888 |
{
|
|
|
3db888 |
ssize_t ret;
|
|
|
3db888 |
char * ch;
|
|
|
3db888 |
|
|
|
3db888 |
for (ch=buf; nbytes; ch+=ret) {
|
|
|
3db888 |
ret = write(fdout,ch,nbytes);
|
|
|
3db888 |
|
|
|
3db888 |
while ((ret < 0) && (errno == EINTR))
|
|
|
3db888 |
ret = write(fdout,ch,nbytes);
|
|
|
3db888 |
|
|
|
3db888 |
if (ret < 0)
|
|
|
3db888 |
return ret;
|
|
|
3db888 |
|
|
|
3db888 |
nbytes -= ret;
|
|
|
3db888 |
}
|
|
|
3db888 |
|
|
|
3db888 |
return 0;
|
|
|
3db888 |
}
|
|
|
3db888 |
|
|
|
3db888 |
static int tpax_archive_append_pad(
|
|
|
3db888 |
int fdout,
|
|
|
3db888 |
const struct stat * st)
|
|
|
3db888 |
{
|
|
|
3db888 |
ssize_t nbytes;
|
|
|
3db888 |
char buf[512];
|
|
|
3db888 |
|
|
|
3db888 |
nbytes = st->st_size;
|
|
|
3db888 |
nbytes += 0x1ff;
|
|
|
3db888 |
nbytes |= 0x1ff;
|
|
|
3db888 |
nbytes ^= 0x1ff;
|
|
|
3db888 |
nbytes -= st->st_size;
|
|
|
3db888 |
|
|
|
3db888 |
memset(buf,0,nbytes);
|
|
|
3db888 |
|
|
|
3db888 |
return tpax_archive_append_memory_data(
|
|
|
3db888 |
fdout,buf,nbytes);
|
|
|
3db888 |
}
|
|
|
3db888 |
|
|
|
3db888 |
int tpax_archive_append(
|
|
|
3db888 |
const struct tpax_driver_ctx * dctx,
|
|
|
3db888 |
const struct tpax_unit_ctx * uctx)
|
|
|
3db888 |
{
|
|
|
3db888 |
struct tpax_ustar_header uhdr;
|
|
|
3db888 |
int fdout;
|
|
|
3db888 |
int fdtmp;
|
|
|
3db888 |
ssize_t nread;
|
|
|
3db888 |
ssize_t nbytes;
|
|
|
3db888 |
void * buf;
|
|
|
3db888 |
size_t buflen;
|
|
|
3db888 |
size_t cmplen;
|
|
|
3db888 |
void * membuf;
|
|
|
3db888 |
char sbuf[2048];
|
|
|
3db888 |
|
|
|
3db888 |
/* record errors */
|
|
|
3db888 |
tpax_driver_set_ectx(
|
|
|
3db888 |
dctx,0,
|
|
|
3db888 |
*uctx->path);
|
|
|
3db888 |
|
|
|
3db888 |
/* driver */
|
|
|
3db888 |
fdout = tpax_driver_fdout(dctx);
|
|
|
3db888 |
|
|
|
3db888 |
/* header */
|
|
|
3db888 |
if (tpax_init_ustar_header(
|
|
|
3db888 |
dctx,*uctx->path,uctx->st,
|
|
|
3db888 |
*uctx->link,&uhdr) < 0)
|
|
|
3db888 |
return TPAX_NESTED_ERROR(dctx);
|
|
|
3db888 |
|
|
|
3db888 |
/* buffer */
|
|
|
3db888 |
membuf = 0;
|
|
|
3db888 |
fdtmp = -1;
|
|
|
3db888 |
|
|
|
3db888 |
if ((buf = tpax_get_driver_anon_map_addr(dctx,&buflen)))
|
|
|
3db888 |
if (buflen >= (cmplen = uctx->st->st_size))
|
|
|
3db888 |
membuf = buf;
|
|
|
3db888 |
|
|
|
3db888 |
if (ssizeof(sbuf) >= (uctx->st->st_size))
|
|
|
3db888 |
membuf = sbuf;
|
|
|
3db888 |
|
|
|
3db888 |
/* snapshot */
|
|
|
3db888 |
if (membuf) {
|
|
|
3db888 |
if (tpax_file_create_memory_snapshot(
|
|
|
3db888 |
dctx,*uctx->path,
|
|
|
3db888 |
uctx->st,membuf) < 0)
|
|
|
3db888 |
return TPAX_NESTED_ERROR(dctx);
|
|
|
3db888 |
} else {
|
|
|
3db888 |
if ((fdtmp = tpax_file_create_tmpfs_snapshot(
|
|
|
3db888 |
dctx,*uctx->path,
|
|
|
3db888 |
uctx->st)) < 0)
|
|
|
3db888 |
return TPAX_NESTED_ERROR(dctx);
|
|
|
3db888 |
|
|
|
3db888 |
if (lseek(fdtmp,0,SEEK_SET) < 0)
|
|
|
3db888 |
return TPAX_SYSTEM_ERROR(dctx);
|
|
|
3db888 |
}
|
|
|
3db888 |
|
|
|
3db888 |
/* append header */
|
|
|
3db888 |
if (tpax_archive_append_memory_data(fdout,&uhdr,ssizeof(uhdr)) < 0) {
|
|
|
3db888 |
if (fdtmp >= 0)
|
|
|
3db888 |
close(fdtmp);
|
|
|
3db888 |
|
|
|
3db888 |
return TPAX_SYSTEM_ERROR(dctx);
|
|
|
3db888 |
}
|
|
|
3db888 |
|
|
|
3db888 |
/* append data from snapshot */
|
|
|
3db888 |
if (fdtmp >= 0) {
|
|
|
3db888 |
if (!buf) {
|
|
|
3db888 |
buf = sbuf;
|
|
|
3db888 |
buflen = sizeof(sbuf);
|
|
|
3db888 |
}
|
|
|
3db888 |
|
|
|
3db888 |
for (nread=0; nread<uctx->st->st_size; ) {
|
|
|
3db888 |
nbytes = read(fdtmp,buf,buflen);
|
|
|
3db888 |
|
|
|
3db888 |
while ((nbytes < 0) && (errno == EINTR))
|
|
|
3db888 |
nbytes = read(fdtmp,buf,buflen);
|
|
|
3db888 |
|
|
|
3db888 |
if (nbytes < 0) {
|
|
|
3db888 |
close(fdtmp);
|
|
|
3db888 |
return TPAX_SYSTEM_ERROR(dctx);
|
|
|
3db888 |
|
|
|
3db888 |
} else if (nbytes == 0) {
|
|
|
3db888 |
close(fdtmp);
|
|
|
3db888 |
return TPAX_CUSTOM_ERROR(dctx,TPAX_ERR_FLOW_ERROR);
|
|
|
3db888 |
|
|
|
3db888 |
} else {
|
|
|
3db888 |
nread += nbytes;
|
|
|
3db888 |
}
|
|
|
3db888 |
|
|
|
3db888 |
if (tpax_archive_append_memory_data(fdout,buf,nbytes) < 0) {
|
|
|
3db888 |
close(fdtmp);
|
|
|
3db888 |
return TPAX_SYSTEM_ERROR(dctx);
|
|
|
3db888 |
}
|
|
|
3db888 |
}
|
|
|
3db888 |
|
|
|
3db888 |
close(fdtmp);
|
|
|
3db888 |
} else {
|
|
|
3db888 |
if (tpax_archive_append_memory_data(
|
|
|
3db888 |
fdout,membuf,
|
|
|
3db888 |
uctx->st->st_size) < 0)
|
|
|
3db888 |
return TPAX_SYSTEM_ERROR(dctx);
|
|
|
3db888 |
}
|
|
|
3db888 |
|
|
|
3db888 |
return tpax_archive_append_pad(
|
|
|
3db888 |
fdout,uctx->st);
|
|
|
3db888 |
}
|