|
|
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>
|
|
|
022508 |
#include <sys/mman.h>
|
|
|
3db888 |
#include <sys/stat.h>
|
|
|
3db888 |
|
|
|
3db888 |
#include <tpax/tpax.h>
|
|
|
3db888 |
#include <tpax/tpax_specs.h>
|
|
|
3db888 |
#include "tpax_driver_impl.h"
|
|
|
022508 |
#include "tpax_getdents_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(
|
|
|
409008 |
const struct tpax_driver_ctx * dctx,
|
|
|
409008 |
int fdout,
|
|
|
409008 |
const struct stat * st)
|
|
|
3db888 |
{
|
|
|
409008 |
int ret;
|
|
|
409008 |
off_t cpos;
|
|
|
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 |
|
|
|
409008 |
cpos = tpax_get_driver_cpos(dctx);
|
|
|
409008 |
cpos += st->st_size + nbytes;
|
|
|
409008 |
|
|
|
409008 |
if (!(ret = tpax_archive_append_memory_data(fdout,buf,nbytes)))
|
|
|
409008 |
tpax_set_driver_cpos(dctx,cpos);
|
|
|
409008 |
|
|
|
409008 |
return ret;
|
|
|
3db888 |
}
|
|
|
3db888 |
|
|
|
022508 |
static struct tpax_dirent_buffer * tpax_dirent_buf_first_alloc(
|
|
|
022508 |
const struct tpax_driver_ctx * dctx)
|
|
|
022508 |
{
|
|
|
022508 |
void * addr;
|
|
|
022508 |
struct tpax_driver_ctx_impl * ictx;
|
|
|
022508 |
|
|
|
022508 |
addr = (struct tpax_dirent_buffer *)mmap(
|
|
|
022508 |
0,TPAX_DIRENT_BUFLEN,
|
|
|
022508 |
PROT_READ|PROT_WRITE,
|
|
|
022508 |
MAP_PRIVATE|MAP_ANONYMOUS,
|
|
|
022508 |
-1,0);
|
|
|
022508 |
|
|
|
022508 |
if (addr == MAP_FAILED)
|
|
|
022508 |
return 0;
|
|
|
022508 |
|
|
|
022508 |
ictx = tpax_get_driver_ictx(dctx);
|
|
|
022508 |
ictx->dirents = (struct tpax_dirent_buffer *)addr;
|
|
|
022508 |
ictx->dirents->cdent = ictx->dirents->dbuf;
|
|
|
022508 |
|
|
|
022508 |
ictx->dirents->size = TPAX_DIRENT_BUFLEN;
|
|
|
022508 |
ictx->dirents->next = 0;
|
|
|
022508 |
|
|
|
022508 |
ictx->dirents->nfree = TPAX_DIRENT_BUFLEN;
|
|
|
022508 |
ictx->dirents->nfree -= offsetof(struct tpax_dirent_buffer,dbuf);
|
|
|
022508 |
|
|
|
022508 |
return ictx->dirents;
|
|
|
022508 |
}
|
|
|
022508 |
|
|
|
022508 |
static struct tpax_dirent_buffer * tpax_dirent_buf_next_alloc(
|
|
|
022508 |
struct tpax_dirent_buffer * current)
|
|
|
022508 |
{
|
|
|
022508 |
void * addr;
|
|
|
022508 |
|
|
|
022508 |
addr = (struct tpax_dirent_buffer *)mmap(
|
|
|
022508 |
0,TPAX_DIRENT_BUFLEN,
|
|
|
022508 |
PROT_READ|PROT_WRITE,
|
|
|
022508 |
MAP_PRIVATE|MAP_ANONYMOUS,
|
|
|
022508 |
-1,0);
|
|
|
022508 |
|
|
|
022508 |
if (addr == MAP_FAILED)
|
|
|
022508 |
return 0;
|
|
|
022508 |
|
|
|
022508 |
current->next = (struct tpax_dirent_buffer *)addr;
|
|
|
022508 |
current->next->cdent = current->next->dbuf;
|
|
|
022508 |
|
|
|
022508 |
current->next->size = TPAX_DIRENT_BUFLEN;
|
|
|
022508 |
current->next->next = 0;
|
|
|
022508 |
|
|
|
022508 |
current->next->nfree = TPAX_DIRENT_BUFLEN;
|
|
|
022508 |
current->next->nfree -= offsetof(struct tpax_dirent_buffer,dbuf);
|
|
|
022508 |
|
|
|
022508 |
return current->next;
|
|
|
022508 |
}
|
|
|
022508 |
|
|
|
022508 |
static int tpax_archive_append_ret(
|
|
|
022508 |
int ret,
|
|
|
022508 |
struct tpax_unit_ctx * unit)
|
|
|
022508 |
{
|
|
|
022508 |
if (unit)
|
|
|
022508 |
tpax_free_unit_ctx(unit);
|
|
|
022508 |
|
|
|
022508 |
return ret;
|
|
|
022508 |
}
|
|
|
022508 |
|
|
|
022508 |
static int tpax_archive_append_one(
|
|
|
3db888 |
const struct tpax_driver_ctx * dctx,
|
|
|
022508 |
const struct tpax_unit_ctx * uctx,
|
|
|
022508 |
const struct dirent * dent,
|
|
|
022508 |
int fdat,
|
|
|
022508 |
const char * prefix,
|
|
|
022508 |
const struct tpax_dirent * parent,
|
|
|
022508 |
const char * pdir)
|
|
|
3db888 |
{
|
|
|
022508 |
struct tpax_unit_ctx * unit;
|
|
|
3db888 |
struct tpax_ustar_header uhdr;
|
|
|
409008 |
off_t hpos;
|
|
|
409008 |
off_t dpos;
|
|
|
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;
|
|
|
022508 |
size_t nlen;
|
|
|
022508 |
const char * path;
|
|
|
022508 |
const char * src;
|
|
|
022508 |
char * dst;
|
|
|
022508 |
char pbuf[1024];
|
|
|
3db888 |
|
|
|
022508 |
/* fake uctx for recursion items */
|
|
|
022508 |
unit = 0;
|
|
|
022508 |
|
|
|
022508 |
if (dent && tpax_get_unit_ctx(
|
|
|
022508 |
dctx,fdat,dent->d_name,
|
|
|
022508 |
&unit) < 0)
|
|
|
022508 |
return TPAX_NESTED_ERROR(dctx);
|
|
|
022508 |
|
|
|
022508 |
uctx = dent ? unit : uctx;
|
|
|
022508 |
|
|
|
022508 |
/* prefixed path */
|
|
|
022508 |
if (!prefix && !parent && !pdir) {
|
|
|
022508 |
path = *uctx->path;
|
|
|
022508 |
|
|
|
022508 |
} else {
|
|
|
022508 |
nlen = strlen(*uctx->path);
|
|
|
022508 |
nlen += prefix ? strlen(prefix) + 1 : 0;
|
|
|
022508 |
nlen += parent ? strlen(parent->dirent.d_name) + 1 : 0;
|
|
|
022508 |
|
|
|
022508 |
if (nlen >= sizeof(pbuf))
|
|
|
022508 |
return TPAX_BUFFER_ERROR(dctx);
|
|
|
022508 |
|
|
|
022508 |
dst = pbuf;
|
|
|
022508 |
|
|
|
022508 |
if (prefix) {
|
|
|
022508 |
src = prefix;
|
|
|
022508 |
|
|
|
022508 |
for (; *src; )
|
|
|
022508 |
*dst++ = *src++;
|
|
|
022508 |
|
|
|
022508 |
if (dst[-1] != '/')
|
|
|
022508 |
*dst++ = '/';
|
|
|
022508 |
}
|
|
|
022508 |
|
|
|
022508 |
if (parent) {
|
|
|
022508 |
src = parent->dirent.d_name;
|
|
|
022508 |
|
|
|
022508 |
for (; *src; )
|
|
|
022508 |
*dst++ = *src++;
|
|
|
022508 |
|
|
|
022508 |
*dst++ = '/';
|
|
|
022508 |
}
|
|
|
022508 |
|
|
|
022508 |
if (pdir) {
|
|
|
022508 |
src = pdir;
|
|
|
022508 |
|
|
|
022508 |
for (; *src; )
|
|
|
022508 |
*dst++ = *src++;
|
|
|
022508 |
|
|
|
022508 |
*dst++ = '/';
|
|
|
022508 |
}
|
|
|
022508 |
|
|
|
022508 |
src = *uctx->path;
|
|
|
022508 |
|
|
|
022508 |
for (; *src; )
|
|
|
022508 |
*dst++ = *src++;
|
|
|
022508 |
|
|
|
022508 |
*dst = 0;
|
|
|
022508 |
path = pbuf;
|
|
|
022508 |
}
|
|
|
022508 |
|
|
|
3db888 |
/* record errors */
|
|
|
3db888 |
tpax_driver_set_ectx(
|
|
|
022508 |
dctx,0,path);
|
|
|
3db888 |
|
|
|
3db888 |
/* driver */
|
|
|
3db888 |
fdout = tpax_driver_fdout(dctx);
|
|
|
3db888 |
|
|
|
409008 |
/* header and data offsets: todo pax and cpio */
|
|
|
409008 |
hpos = tpax_get_driver_cpos(dctx);
|
|
|
409008 |
dpos = hpos + sizeof(uhdr);
|
|
|
409008 |
|
|
|
3db888 |
/* header */
|
|
|
3db888 |
if (tpax_init_ustar_header(
|
|
|
022508 |
dctx,path,uctx->st,
|
|
|
3db888 |
*uctx->link,&uhdr) < 0)
|
|
|
022508 |
return tpax_archive_append_ret(
|
|
|
022508 |
TPAX_NESTED_ERROR(dctx),
|
|
|
022508 |
unit);
|
|
|
3db888 |
|
|
|
3db888 |
/* buffer */
|
|
|
3db888 |
membuf = 0;
|
|
|
3db888 |
fdtmp = -1;
|
|
|
3db888 |
|
|
|
af4988 |
/* associated data? */
|
|
|
af4988 |
if S_ISREG(uctx->st->st_mode) {
|
|
|
d816c0 |
buf = tpax_get_driver_anon_map_addr(
|
|
|
d816c0 |
dctx,&buflen);
|
|
|
af4988 |
|
|
|
d816c0 |
if (buflen >= (cmplen = uctx->st->st_size))
|
|
|
d816c0 |
membuf = buf;
|
|
|
af4988 |
|
|
|
af4988 |
/* snapshot */
|
|
|
af4988 |
if (membuf) {
|
|
|
af4988 |
if (tpax_file_create_memory_snapshot(
|
|
|
a2aed5 |
dctx,fdat,*uctx->path,
|
|
|
af4988 |
uctx->st,membuf) < 0)
|
|
|
022508 |
return tpax_archive_append_ret(
|
|
|
022508 |
TPAX_NESTED_ERROR(dctx),
|
|
|
022508 |
unit);
|
|
|
af4988 |
} else {
|
|
|
af4988 |
if ((fdtmp = tpax_file_create_tmpfs_snapshot(
|
|
|
a2aed5 |
dctx,fdat,*uctx->path,
|
|
|
af4988 |
uctx->st)) < 0)
|
|
|
022508 |
return tpax_archive_append_ret(
|
|
|
022508 |
TPAX_NESTED_ERROR(dctx),
|
|
|
022508 |
unit);
|
|
|
af4988 |
|
|
|
af4988 |
if (lseek(fdtmp,0,SEEK_SET) < 0)
|
|
|
022508 |
return tpax_archive_append_ret(
|
|
|
022508 |
TPAX_SYSTEM_ERROR(dctx),
|
|
|
022508 |
unit);
|
|
|
af4988 |
}
|
|
|
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 |
|
|
|
022508 |
return tpax_archive_append_ret(
|
|
|
022508 |
TPAX_SYSTEM_ERROR(dctx),
|
|
|
022508 |
unit);
|
|
|
3db888 |
}
|
|
|
3db888 |
|
|
|
409008 |
tpax_set_driver_cpos(dctx,dpos);
|
|
|
409008 |
|
|
|
af4988 |
/* all done? */
|
|
|
022508 |
if (!(S_ISREG(uctx->st->st_mode))) {
|
|
|
022508 |
tpax_archive_append_ret(0,unit);
|
|
|
af4988 |
return 0;
|
|
|
022508 |
}
|
|
|
af4988 |
|
|
|
3db888 |
/* append data from snapshot */
|
|
|
3db888 |
if (fdtmp >= 0) {
|
|
|
d816c0 |
buf = tpax_get_driver_anon_map_addr(
|
|
|
d816c0 |
dctx,&buflen);
|
|
|
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);
|
|
|
022508 |
return tpax_archive_append_ret(
|
|
|
022508 |
TPAX_SYSTEM_ERROR(dctx),
|
|
|
022508 |
unit);
|
|
|
3db888 |
|
|
|
3db888 |
} else if (nbytes == 0) {
|
|
|
3db888 |
close(fdtmp);
|
|
|
022508 |
return tpax_archive_append_ret(
|
|
|
022508 |
TPAX_CUSTOM_ERROR(dctx,TPAX_ERR_FLOW_ERROR),
|
|
|
022508 |
unit);
|
|
|
3db888 |
|
|
|
3db888 |
} else {
|
|
|
3db888 |
nread += nbytes;
|
|
|
3db888 |
}
|
|
|
3db888 |
|
|
|
3db888 |
if (tpax_archive_append_memory_data(fdout,buf,nbytes) < 0) {
|
|
|
3db888 |
close(fdtmp);
|
|
|
022508 |
return tpax_archive_append_ret(
|
|
|
022508 |
TPAX_SYSTEM_ERROR(dctx),
|
|
|
022508 |
unit);
|
|
|
3db888 |
}
|
|
|
3db888 |
}
|
|
|
3db888 |
|
|
|
3db888 |
close(fdtmp);
|
|
|
3db888 |
} else {
|
|
|
3db888 |
if (tpax_archive_append_memory_data(
|
|
|
3db888 |
fdout,membuf,
|
|
|
3db888 |
uctx->st->st_size) < 0)
|
|
|
022508 |
return tpax_archive_append_ret(
|
|
|
022508 |
TPAX_SYSTEM_ERROR(dctx),
|
|
|
022508 |
unit);
|
|
|
022508 |
}
|
|
|
022508 |
|
|
|
022508 |
return tpax_archive_append_ret(
|
|
|
022508 |
tpax_archive_append_pad(dctx,fdout,uctx->st),
|
|
|
022508 |
unit);
|
|
|
022508 |
}
|
|
|
022508 |
|
|
|
022508 |
static int tpax_archive_append_dir(
|
|
|
022508 |
const struct tpax_driver_ctx * dctx,
|
|
|
022508 |
const struct tpax_unit_ctx * uctx,
|
|
|
022508 |
struct tpax_dirent * dent,
|
|
|
022508 |
int fdat,
|
|
|
022508 |
int depth,
|
|
|
022508 |
const char * prefix,
|
|
|
022508 |
const struct tpax_dirent * parent)
|
|
|
022508 |
{
|
|
|
022508 |
int fd;
|
|
|
022508 |
bool fkeep;
|
|
|
022508 |
long nbytes;
|
|
|
022508 |
size_t needed;
|
|
|
022508 |
struct dirent * dirent;
|
|
|
022508 |
struct dirent * dirents;
|
|
|
022508 |
struct tpax_dirent_buffer * dentbuf;
|
|
|
022508 |
struct tpax_dirent * cdent;
|
|
|
022508 |
struct tpax_unit_ctx * unit;
|
|
|
022508 |
struct stat st;
|
|
|
022508 |
uintptr_t addr;
|
|
|
022508 |
char * src;
|
|
|
022508 |
char * dst;
|
|
|
022508 |
char * cap;
|
|
|
022508 |
|
|
|
022508 |
/* fake uctx for recursion items */
|
|
|
022508 |
unit = 0;
|
|
|
022508 |
|
|
|
022508 |
if (dent && tpax_get_unit_ctx(
|
|
|
022508 |
dctx,dent->fdat,dent->dirent.d_name,
|
|
|
022508 |
&unit) < 0)
|
|
|
022508 |
return TPAX_NESTED_ERROR(dctx);
|
|
|
022508 |
|
|
|
022508 |
uctx = dent ? unit : uctx;
|
|
|
022508 |
|
|
|
022508 |
/* verify that recursion item is still a directory */
|
|
|
022508 |
if (unit && !S_ISDIR(unit->st->st_mode))
|
|
|
022508 |
return tpax_archive_append_ret(
|
|
|
022508 |
TPAX_CUSTOM_ERROR(dctx,TPAX_ERR_FLOW_ERROR),
|
|
|
022508 |
unit);
|
|
|
022508 |
|
|
|
022508 |
/* append directory entry to archive */
|
|
|
022508 |
if (tpax_archive_append_one(
|
|
|
022508 |
dctx,uctx,0,
|
|
|
022508 |
tpax_driver_fdcwd(dctx),
|
|
|
022508 |
prefix,0,0) < 0)
|
|
|
022508 |
return tpax_archive_append_ret(
|
|
|
022508 |
TPAX_NESTED_ERROR(dctx),
|
|
|
022508 |
unit);
|
|
|
022508 |
|
|
|
022508 |
/* obtain buffer for file-system directory entries */
|
|
|
022508 |
dirents = tpax_get_driver_getdents_buffer(dctx);
|
|
|
022508 |
dirent = dirents;
|
|
|
022508 |
fkeep = false;
|
|
|
022508 |
nbytes = 0;
|
|
|
022508 |
depth++;
|
|
|
022508 |
|
|
|
022508 |
/* open directory and obtain first directory entries */
|
|
|
022508 |
if ((fd = openat(fdat,*uctx->path,O_RDONLY|O_DIRECTORY|O_CLOEXEC,0)) < 0)
|
|
|
022508 |
return tpax_archive_append_ret(
|
|
|
022508 |
TPAX_SYSTEM_ERROR(dctx),
|
|
|
022508 |
unit);
|
|
|
022508 |
|
|
|
022508 |
nbytes = tpax_getdents(fd,dirents,TPAX_DIRENT_BUFLEN);
|
|
|
022508 |
|
|
|
022508 |
while ((nbytes == -EINTR) || ((nbytes < 0) && (errno == EINTR)))
|
|
|
022508 |
nbytes = tpax_getdents(fd,dirents,TPAX_DIRENT_BUFLEN);
|
|
|
022508 |
|
|
|
022508 |
if (nbytes < 0)
|
|
|
022508 |
return tpax_archive_append_ret(
|
|
|
022508 |
TPAX_SYSTEM_ERROR(dctx),
|
|
|
022508 |
unit);
|
|
|
022508 |
|
|
|
022508 |
/* iterate */
|
|
|
022508 |
for (; nbytes>0; ) {
|
|
|
022508 |
if (!strcmp(dirent->d_name,".")) {
|
|
|
022508 |
(void)0;
|
|
|
022508 |
|
|
|
022508 |
} else if (!strcmp(dirent->d_name,"..")) {
|
|
|
022508 |
(void)0;
|
|
|
022508 |
|
|
|
022508 |
} else {
|
|
|
022508 |
if (dirent->d_type == DT_UNKNOWN) {
|
|
|
022508 |
if (fstatat(fd,dirent->d_name,&st,AT_SYMLINK_NOFOLLOW))
|
|
|
022508 |
return tpax_archive_append_ret(
|
|
|
022508 |
TPAX_SYSTEM_ERROR(dctx),
|
|
|
022508 |
unit);
|
|
|
022508 |
|
|
|
022508 |
if (S_ISDIR(st.st_mode)) {
|
|
|
022508 |
dirent->d_type = DT_DIR;
|
|
|
022508 |
}
|
|
|
022508 |
}
|
|
|
022508 |
|
|
|
022508 |
if (dirent->d_type == DT_DIR) {
|
|
|
022508 |
if (!(dentbuf = tpax_get_driver_dirents(dctx)))
|
|
|
022508 |
if (!(dentbuf = tpax_dirent_buf_first_alloc(dctx)))
|
|
|
022508 |
return tpax_archive_append_ret(
|
|
|
022508 |
TPAX_SYSTEM_ERROR(dctx),
|
|
|
022508 |
unit);
|
|
|
022508 |
|
|
|
022508 |
needed = dirent->d_reclen;
|
|
|
022508 |
needed += offsetof(struct tpax_dirent,dirent);
|
|
|
022508 |
needed += 0x7;
|
|
|
022508 |
needed |= 0x7;
|
|
|
022508 |
needed ^= 0x7;
|
|
|
022508 |
|
|
|
022508 |
for (; dentbuf->next && (dentbuf->nfree < needed); )
|
|
|
022508 |
dentbuf = dentbuf->next;
|
|
|
022508 |
|
|
|
022508 |
if (dentbuf->nfree < needed)
|
|
|
022508 |
if (!(dentbuf = tpax_dirent_buf_next_alloc(dentbuf)))
|
|
|
022508 |
return tpax_archive_append_ret(
|
|
|
022508 |
TPAX_SYSTEM_ERROR(dctx),
|
|
|
022508 |
unit);
|
|
|
022508 |
|
|
|
022508 |
fkeep = true;
|
|
|
022508 |
cdent = dentbuf->cdent;
|
|
|
022508 |
|
|
|
022508 |
cdent->fdat = fd;
|
|
|
022508 |
cdent->depth = depth;
|
|
|
022508 |
cdent->nsize = needed;
|
|
|
022508 |
cdent->parent = parent;
|
|
|
022508 |
|
|
|
022508 |
memset(&cdent->dirent,0,offsetof(struct dirent,d_name));
|
|
|
022508 |
|
|
|
022508 |
cdent->dirent.d_type = dirent->d_type;
|
|
|
022508 |
cdent->dirent.d_reclen = dirent->d_reclen;
|
|
|
022508 |
|
|
|
022508 |
src = dirent->d_name;
|
|
|
022508 |
dst = cdent->dirent.d_name;
|
|
|
022508 |
|
|
|
022508 |
cap = dst - offsetof(struct dirent,d_name);
|
|
|
022508 |
cap -= offsetof(struct tpax_dirent,dirent);
|
|
|
022508 |
cap += needed;
|
|
|
022508 |
|
|
|
022508 |
for (; *src; )
|
|
|
022508 |
*dst++ = *src++;
|
|
|
022508 |
|
|
|
022508 |
for (; dst
|
|
|
022508 |
*dst++ = 0;
|
|
|
022508 |
|
|
|
022508 |
dentbuf->cdent = (struct tpax_dirent *)cap;
|
|
|
022508 |
dentbuf->nfree -= needed;
|
|
|
022508 |
} else {
|
|
|
022508 |
if (tpax_archive_append_one(
|
|
|
022508 |
dctx,0,dirent,fd,prefix,
|
|
|
022508 |
0,*uctx->path) < 0)
|
|
|
022508 |
return tpax_archive_append_ret(
|
|
|
022508 |
TPAX_NESTED_ERROR(dctx),
|
|
|
022508 |
unit);
|
|
|
022508 |
}
|
|
|
022508 |
}
|
|
|
022508 |
|
|
|
022508 |
addr = (uintptr_t)dirent;
|
|
|
022508 |
addr += dirent->d_reclen;
|
|
|
022508 |
nbytes -= dirent->d_reclen;
|
|
|
022508 |
dirent = (struct dirent *)addr;
|
|
|
022508 |
|
|
|
022508 |
if (nbytes == 0) {
|
|
|
022508 |
nbytes = tpax_getdents(fd,dirents,TPAX_DIRENT_BUFLEN);
|
|
|
022508 |
|
|
|
022508 |
while ((nbytes == -EINTR) || ((nbytes < 0) && (errno == EINTR)))
|
|
|
022508 |
nbytes = tpax_getdents(fd,dirents,TPAX_DIRENT_BUFLEN);
|
|
|
022508 |
|
|
|
022508 |
if (nbytes < 0)
|
|
|
022508 |
tpax_archive_append_ret(
|
|
|
022508 |
TPAX_SYSTEM_ERROR(dctx),
|
|
|
022508 |
unit);
|
|
|
022508 |
|
|
|
022508 |
dirent = dirents;
|
|
|
022508 |
}
|
|
|
3db888 |
}
|
|
|
3db888 |
|
|
|
022508 |
/* all done */
|
|
|
022508 |
return tpax_archive_append_ret(
|
|
|
022508 |
fkeep ? 0 : close(fd),
|
|
|
022508 |
unit);
|
|
|
022508 |
}
|
|
|
022508 |
|
|
|
022508 |
static int tpax_archive_append_impl(
|
|
|
022508 |
const struct tpax_driver_ctx * dctx,
|
|
|
022508 |
const struct tpax_unit_ctx * uctx,
|
|
|
022508 |
int depth,
|
|
|
022508 |
const char * prefix,
|
|
|
022508 |
struct tpax_dirent * parent)
|
|
|
022508 |
{
|
|
|
022508 |
if (S_ISDIR(uctx->st->st_mode))
|
|
|
022508 |
if (dctx->cctx->drvflags & TPAX_DRIVER_DIR_MEMBER_RECURSE)
|
|
|
022508 |
return tpax_archive_append_dir(
|
|
|
022508 |
dctx,uctx,0,
|
|
|
022508 |
tpax_driver_fdcwd(dctx),
|
|
|
022508 |
depth,prefix,parent);
|
|
|
022508 |
|
|
|
022508 |
return tpax_archive_append_one(
|
|
|
022508 |
dctx,uctx,0,
|
|
|
022508 |
tpax_driver_fdcwd(dctx),
|
|
|
022508 |
prefix,0,0);
|
|
|
022508 |
}
|
|
|
022508 |
|
|
|
022508 |
int tpax_archive_append(
|
|
|
022508 |
const struct tpax_driver_ctx * dctx,
|
|
|
022508 |
const struct tpax_unit_ctx * uctx,
|
|
|
022508 |
const char * prefix)
|
|
|
022508 |
{
|
|
|
022508 |
struct tpax_dirent_buffer * dentbuf;
|
|
|
022508 |
struct tpax_dirent * cdent;
|
|
|
022508 |
struct tpax_dirent * cnext;
|
|
|
022508 |
const struct tpax_dirent * parent;
|
|
|
022508 |
uintptr_t addr;
|
|
|
022508 |
const char * rdir;
|
|
|
022508 |
const char * src;
|
|
|
022508 |
char * dst;
|
|
|
022508 |
char * cap;
|
|
|
022508 |
char * mark;
|
|
|
022508 |
int idx;
|
|
|
022508 |
const char * dirv[256];
|
|
|
022508 |
char pbuf[2048];
|
|
|
022508 |
|
|
|
022508 |
/* normalized prefix */
|
|
|
022508 |
if (prefix && (prefix[0] == '.') && (!prefix[1]))
|
|
|
022508 |
prefix = 0;
|
|
|
022508 |
|
|
|
022508 |
if (prefix && (prefix[0] == '.') && (prefix[1] == '/'))
|
|
|
022508 |
for (++prefix; *prefix=='/'; prefix++)
|
|
|
022508 |
(void)0;
|
|
|
022508 |
|
|
|
022508 |
/* append explicit item */
|
|
|
022508 |
tpax_archive_append_impl(dctx,uctx,0,prefix,0);
|
|
|
022508 |
|
|
|
022508 |
/* iterate through queued items */
|
|
|
022508 |
dentbuf = tpax_get_driver_dirents(dctx);
|
|
|
022508 |
cdent = dentbuf ? dentbuf->dbuf : 0;
|
|
|
022508 |
|
|
|
022508 |
if (cdent) {
|
|
|
022508 |
dst = pbuf;
|
|
|
022508 |
cap = &pbuf[sizeof(pbuf)];
|
|
|
022508 |
|
|
|
022508 |
if (prefix && prefix[0]) {
|
|
|
022508 |
for (; *src && dst
|
|
|
022508 |
*dst++ = *src++;
|
|
|
022508 |
|
|
|
022508 |
if (dst == cap)
|
|
|
022508 |
return TPAX_BUFFER_ERROR(dctx);
|
|
|
022508 |
|
|
|
022508 |
if (dst[-1] != '/')
|
|
|
022508 |
*dst++ = '/';
|
|
|
022508 |
}
|
|
|
022508 |
|
|
|
022508 |
src = *uctx->path;
|
|
|
022508 |
|
|
|
022508 |
for (; *src && dst
|
|
|
022508 |
*dst++ = *src++;
|
|
|
022508 |
|
|
|
022508 |
if (dst == cap)
|
|
|
022508 |
return TPAX_BUFFER_ERROR(dctx);
|
|
|
022508 |
|
|
|
022508 |
if (dst[-1] != '/')
|
|
|
022508 |
*dst++ = '/';
|
|
|
022508 |
|
|
|
022508 |
*dst = 0;
|
|
|
022508 |
mark = dst;
|
|
|
022508 |
rdir = pbuf;
|
|
|
022508 |
|
|
|
022508 |
(void)mark;
|
|
|
022508 |
}
|
|
|
022508 |
|
|
|
022508 |
for (; cdent; ) {
|
|
|
022508 |
switch (cdent->dirent.d_type) {
|
|
|
022508 |
case DT_DIR:
|
|
|
022508 |
if (tpax_archive_append_dir(
|
|
|
022508 |
dctx,0,cdent,cdent->fdat,
|
|
|
022508 |
cdent->depth,rdir,cdent) < 0)
|
|
|
022508 |
return TPAX_NESTED_ERROR(dctx);
|
|
|
022508 |
|
|
|
022508 |
break;
|
|
|
022508 |
|
|
|
022508 |
default:
|
|
|
022508 |
if (tpax_archive_append_one(
|
|
|
022508 |
dctx,0,&cdent->dirent,
|
|
|
022508 |
cdent->fdat,rdir,cdent,0) < 0)
|
|
|
022508 |
return TPAX_NESTED_ERROR(dctx);
|
|
|
022508 |
}
|
|
|
022508 |
|
|
|
022508 |
addr = (uintptr_t)cdent;
|
|
|
022508 |
addr += cdent->nsize;
|
|
|
022508 |
cnext = (struct tpax_dirent *)addr;
|
|
|
022508 |
|
|
|
022508 |
if (cnext == dentbuf->cdent) {
|
|
|
022508 |
dentbuf = dentbuf->next;
|
|
|
022508 |
cnext = dentbuf ? dentbuf->dbuf : 0;
|
|
|
022508 |
}
|
|
|
022508 |
|
|
|
022508 |
if (cnext && (cnext->parent != cdent->parent)) {
|
|
|
022508 |
if (cnext->depth > 256)
|
|
|
022508 |
return TPAX_BUFFER_ERROR(dctx);
|
|
|
022508 |
|
|
|
022508 |
for (parent=cnext->parent; parent; parent=parent->parent)
|
|
|
022508 |
dirv[parent->depth - 1] = parent->dirent.d_name;
|
|
|
022508 |
|
|
|
022508 |
for (idx=0,dst=mark; idx<cnext->parent->depth; idx++) {
|
|
|
022508 |
src = dirv[idx];
|
|
|
022508 |
|
|
|
022508 |
for (; *src; )
|
|
|
022508 |
*dst++ = *src++;
|
|
|
022508 |
|
|
|
022508 |
*dst++ = '/';
|
|
|
022508 |
}
|
|
|
022508 |
|
|
|
022508 |
*--dst = 0;
|
|
|
022508 |
}
|
|
|
022508 |
|
|
|
022508 |
cdent = cnext;
|
|
|
022508 |
}
|
|
|
022508 |
|
|
|
022508 |
return 0;
|
|
|
409008 |
}
|
|
|
409008 |
|
|
|
409008 |
int tpax_archive_seal(const struct tpax_driver_ctx * dctx)
|
|
|
409008 |
{
|
|
|
409008 |
int fdout;
|
|
|
409008 |
off_t cpos;
|
|
|
409008 |
ssize_t nbytes;
|
|
|
409008 |
ssize_t nwritten;
|
|
|
409008 |
ssize_t blksize;
|
|
|
409008 |
char buf[512];
|
|
|
409008 |
|
|
|
409008 |
blksize = tpax_get_archive_block_size(dctx);
|
|
|
409008 |
cpos = tpax_get_driver_cpos(dctx);
|
|
|
409008 |
|
|
|
409008 |
if (cpos % 512)
|
|
|
409008 |
return TPAX_CUSTOM_ERROR(dctx,TPAX_ERR_FLOW_ERROR);
|
|
|
409008 |
|
|
|
409008 |
fdout = tpax_driver_fdout(dctx);
|
|
|
409008 |
memset(buf,0,sizeof(buf));
|
|
|
409008 |
|
|
|
409008 |
switch (cpos % blksize) {
|
|
|
409008 |
case 0:
|
|
|
409008 |
nbytes = cpos + blksize;
|
|
|
409008 |
break;
|
|
|
409008 |
|
|
|
409008 |
default:
|
|
|
409008 |
nbytes = cpos / blksize;
|
|
|
409008 |
nbytes *= blksize;
|
|
|
409008 |
nbytes += blksize;
|
|
|
409008 |
|
|
|
409008 |
if (nbytes-cpos == 512)
|
|
|
409008 |
nbytes += blksize;
|
|
|
409008 |
}
|
|
|
409008 |
|
|
|
409008 |
for (nwritten=cpos; nwritten
|
|
|
409008 |
if (tpax_archive_append_memory_data(fdout,buf,512) < 0)
|
|
|
409008 |
return TPAX_SYSTEM_ERROR(dctx);
|
|
|
409008 |
|
|
|
409008 |
tpax_set_driver_cpos(dctx,nwritten);
|
|
|
409008 |
}
|
|
|
409008 |
|
|
|
409008 |
return 0;
|
|
|
3db888 |
}
|