summaryrefslogtreecommitdiff
path: root/src/logic/tpax_archive_append.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/logic/tpax_archive_append.c')
-rw-r--r--src/logic/tpax_archive_append.c709
1 files changed, 0 insertions, 709 deletions
diff --git a/src/logic/tpax_archive_append.c b/src/logic/tpax_archive_append.c
deleted file mode 100644
index 76ac436..0000000
--- a/src/logic/tpax_archive_append.c
+++ /dev/null
@@ -1,709 +0,0 @@
-/**************************************************************/
-/* tpax: a topological pax implementation */
-/* Copyright (C) 2020--2021 SysDeer Technologies, LLC */
-/* Released under GPLv2 and GPLv3; see COPYING.TPAX. */
-/**************************************************************/
-
-#include <stdint.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <grp.h>
-#include <pwd.h>
-#include <sys/mman.h>
-#include <sys/stat.h>
-
-#include <tpax/tpax.h>
-#include <tpax/tpax_specs.h>
-#include "tpax_driver_impl.h"
-#include "tpax_getdents_impl.h"
-#include "tpax_tmpfile_impl.h"
-#include "tpax_errinfo_impl.h"
-
-#ifndef ssizeof
-#define ssizeof(x) (ssize_t)(sizeof(x))
-#endif
-
-static int tpax_archive_append_memory_data(
- int fdout,
- void * buf,
- ssize_t nbytes)
-{
- ssize_t ret;
- char * ch;
-
- for (ch=buf; nbytes; ch+=ret) {
- ret = write(fdout,ch,nbytes);
-
- while ((ret < 0) && (errno == EINTR))
- ret = write(fdout,ch,nbytes);
-
- if (ret < 0)
- return ret;
-
- nbytes -= ret;
- }
-
- return 0;
-}
-
-static int tpax_archive_append_pad(
- const struct tpax_driver_ctx * dctx,
- int fdout,
- const struct stat * st)
-{
- int ret;
- off_t cpos;
- ssize_t nbytes;
- char buf[512];
-
- nbytes = st->st_size;
- nbytes += 0x1ff;
- nbytes |= 0x1ff;
- nbytes ^= 0x1ff;
- nbytes -= st->st_size;
-
- memset(buf,0,nbytes);
-
- cpos = tpax_get_driver_cpos(dctx);
- cpos += st->st_size + nbytes;
-
- if (!(ret = tpax_archive_append_memory_data(fdout,buf,nbytes)))
- tpax_set_driver_cpos(dctx,cpos);
-
- return ret;
-}
-
-static struct tpax_dirent_buffer * tpax_dirent_buf_first_alloc(
- const struct tpax_driver_ctx * dctx)
-{
- void * addr;
- struct tpax_driver_ctx_impl * ictx;
-
- addr = (struct tpax_dirent_buffer *)mmap(
- 0,TPAX_DIRENT_BUFLEN,
- PROT_READ|PROT_WRITE,
- MAP_PRIVATE|MAP_ANONYMOUS,
- -1,0);
-
- if (addr == MAP_FAILED)
- return 0;
-
- ictx = tpax_get_driver_ictx(dctx);
- ictx->dirents = (struct tpax_dirent_buffer *)addr;
- ictx->dirents->cdent = ictx->dirents->dbuf;
-
- ictx->dirents->size = TPAX_DIRENT_BUFLEN;
- ictx->dirents->next = 0;
-
- ictx->dirents->nfree = TPAX_DIRENT_BUFLEN;
- ictx->dirents->nfree -= offsetof(struct tpax_dirent_buffer,dbuf);
-
- return ictx->dirents;
-}
-
-static struct tpax_dirent_buffer * tpax_dirent_buf_next_alloc(
- struct tpax_dirent_buffer * current)
-{
- void * addr;
-
- addr = (struct tpax_dirent_buffer *)mmap(
- 0,TPAX_DIRENT_BUFLEN,
- PROT_READ|PROT_WRITE,
- MAP_PRIVATE|MAP_ANONYMOUS,
- -1,0);
-
- if (addr == MAP_FAILED)
- return 0;
-
- current->next = (struct tpax_dirent_buffer *)addr;
- current->next->cdent = current->next->dbuf;
-
- current->next->size = TPAX_DIRENT_BUFLEN;
- current->next->next = 0;
-
- current->next->nfree = TPAX_DIRENT_BUFLEN;
- current->next->nfree -= offsetof(struct tpax_dirent_buffer,dbuf);
-
- return current->next;
-}
-
-static int tpax_archive_append_ret(
- int ret,
- struct tpax_unit_ctx * unit)
-{
- if (unit)
- tpax_free_unit_ctx(unit);
-
- return ret;
-}
-
-static int tpax_archive_append_one(
- const struct tpax_driver_ctx * dctx,
- const struct tpax_unit_ctx * uctx,
- const struct dirent * dent,
- int fdat,
- const char * prefix,
- const struct tpax_dirent * parent,
- const char * pdir)
-{
- struct tpax_unit_ctx * unit;
- struct tpax_ustar_header uhdr;
- off_t hpos;
- off_t dpos;
- int fdout;
- int fdtmp;
- ssize_t nread;
- ssize_t nbytes;
- void * buf;
- size_t buflen;
- size_t cmplen;
- void * membuf;
- size_t nlen;
- const char * path;
- const char * src;
- char * dst;
- char pbuf[1024];
-
- /* fake uctx for recursion items */
- unit = 0;
-
- if (dent && tpax_get_unit_ctx(
- dctx,fdat,dent->d_name,
- &unit) < 0)
- return TPAX_NESTED_ERROR(dctx);
-
- uctx = dent ? unit : uctx;
-
- /* prefixed path */
- if (!prefix && !parent && !pdir) {
- path = *uctx->path;
-
- } else {
- nlen = strlen(*uctx->path);
- nlen += prefix ? strlen(prefix) + 1 : 0;
- nlen += parent ? strlen(parent->dirent.d_name) + 1 : 0;
-
- if (nlen >= sizeof(pbuf))
- return TPAX_BUFFER_ERROR(dctx);
-
- dst = pbuf;
-
- if (prefix) {
- src = prefix;
-
- for (; *src; )
- *dst++ = *src++;
-
- if (dst[-1] != '/')
- *dst++ = '/';
- }
-
- if (parent) {
- src = parent->dirent.d_name;
-
- for (; *src; )
- *dst++ = *src++;
-
- *dst++ = '/';
- }
-
- if (pdir) {
- src = pdir;
-
- for (; *src; )
- *dst++ = *src++;
-
- *dst++ = '/';
- }
-
- src = *uctx->path;
-
- for (; *src; )
- *dst++ = *src++;
-
- *dst = 0;
- path = pbuf;
- }
-
- /* record errors */
- tpax_driver_set_ectx(
- dctx,0,path);
-
- /* driver */
- fdout = tpax_driver_fdout(dctx);
-
- /* header and data offsets: todo pax and cpio */
- hpos = tpax_get_driver_cpos(dctx);
- dpos = hpos + sizeof(uhdr);
-
- /* header */
- if (tpax_init_ustar_header(
- dctx,path,uctx->st,
- *uctx->link,&uhdr) < 0)
- return tpax_archive_append_ret(
- TPAX_NESTED_ERROR(dctx),
- unit);
-
- /* buffer */
- membuf = 0;
- fdtmp = -1;
-
- /* associated data? */
- if S_ISREG(uctx->st->st_mode) {
- buf = tpax_get_driver_anon_map_addr(
- dctx,&buflen);
-
- if (buflen >= (cmplen = uctx->st->st_size))
- membuf = buf;
-
- /* snapshot */
- if (membuf) {
- if (tpax_file_create_memory_snapshot(
- dctx,fdat,*uctx->path,
- uctx->st,membuf) < 0)
- return tpax_archive_append_ret(
- TPAX_NESTED_ERROR(dctx),
- unit);
- } else {
- if ((fdtmp = tpax_file_create_tmpfs_snapshot(
- dctx,fdat,*uctx->path,
- uctx->st)) < 0)
- return tpax_archive_append_ret(
- TPAX_NESTED_ERROR(dctx),
- unit);
-
- if (lseek(fdtmp,0,SEEK_SET) < 0)
- return tpax_archive_append_ret(
- TPAX_SYSTEM_ERROR(dctx),
- unit);
- }
- }
-
- /* append header */
- if (tpax_archive_append_memory_data(fdout,&uhdr,ssizeof(uhdr)) < 0) {
- if (fdtmp >= 0)
- close(fdtmp);
-
- return tpax_archive_append_ret(
- TPAX_SYSTEM_ERROR(dctx),
- unit);
- }
-
- tpax_set_driver_cpos(dctx,dpos);
-
- /* all done? */
- if (!(S_ISREG(uctx->st->st_mode))) {
- tpax_archive_append_ret(0,unit);
- return 0;
- }
-
- /* append data from snapshot */
- if (fdtmp >= 0) {
- buf = tpax_get_driver_anon_map_addr(
- dctx,&buflen);
-
- for (nread=0; nread<uctx->st->st_size; ) {
- nbytes = read(fdtmp,buf,buflen);
-
- while ((nbytes < 0) && (errno == EINTR))
- nbytes = read(fdtmp,buf,buflen);
-
- if (nbytes < 0) {
- close(fdtmp);
- return tpax_archive_append_ret(
- TPAX_SYSTEM_ERROR(dctx),
- unit);
-
- } else if (nbytes == 0) {
- close(fdtmp);
- return tpax_archive_append_ret(
- TPAX_CUSTOM_ERROR(dctx,TPAX_ERR_FLOW_ERROR),
- unit);
-
- } else {
- nread += nbytes;
- }
-
- if (tpax_archive_append_memory_data(fdout,buf,nbytes) < 0) {
- close(fdtmp);
- return tpax_archive_append_ret(
- TPAX_SYSTEM_ERROR(dctx),
- unit);
- }
- }
-
- close(fdtmp);
- } else {
- if (tpax_archive_append_memory_data(
- fdout,membuf,
- uctx->st->st_size) < 0)
- return tpax_archive_append_ret(
- TPAX_SYSTEM_ERROR(dctx),
- unit);
- }
-
- return tpax_archive_append_ret(
- tpax_archive_append_pad(dctx,fdout,uctx->st),
- unit);
-}
-
-static int tpax_archive_append_dir(
- const struct tpax_driver_ctx * dctx,
- const struct tpax_unit_ctx * uctx,
- struct tpax_dirent * dent,
- int fdat,
- int depth,
- const char * prefix,
- const struct tpax_dirent * parent)
-{
- int fd;
- bool fkeep;
- long nbytes;
- size_t needed;
- struct dirent * dirent;
- struct dirent * dirents;
- struct tpax_dirent_buffer * dentbuf;
- struct tpax_dirent * cdent;
- struct tpax_unit_ctx * unit;
- struct stat st;
- uintptr_t addr;
- char * src;
- char * dst;
- char * cap;
-
- /* fake uctx for recursion items */
- unit = 0;
-
- if (dent && tpax_get_unit_ctx(
- dctx,dent->fdat,dent->dirent.d_name,
- &unit) < 0)
- return TPAX_NESTED_ERROR(dctx);
-
- uctx = dent ? unit : uctx;
-
- /* verify that recursion item is still a directory */
- if (unit && !S_ISDIR(unit->st->st_mode))
- return tpax_archive_append_ret(
- TPAX_CUSTOM_ERROR(dctx,TPAX_ERR_FLOW_ERROR),
- unit);
-
- /* append directory entry to archive */
- if (tpax_archive_append_one(
- dctx,uctx,0,
- tpax_driver_fdcwd(dctx),
- prefix,0,0) < 0)
- return tpax_archive_append_ret(
- TPAX_NESTED_ERROR(dctx),
- unit);
-
- /* obtain buffer for file-system directory entries */
- dirents = tpax_get_driver_getdents_buffer(dctx);
- dirent = dirents;
- fkeep = false;
- nbytes = 0;
- depth++;
-
- /* open directory and obtain first directory entries */
- if ((fd = openat(fdat,*uctx->path,O_RDONLY|O_DIRECTORY|O_CLOEXEC,0)) < 0)
- return tpax_archive_append_ret(
- TPAX_SYSTEM_ERROR(dctx),
- unit);
-
- nbytes = tpax_getdents(fd,dirents,TPAX_DIRENT_BUFLEN);
-
- while ((nbytes == -EINTR) || ((nbytes < 0) && (errno == EINTR)))
- nbytes = tpax_getdents(fd,dirents,TPAX_DIRENT_BUFLEN);
-
- if (nbytes < 0)
- return tpax_archive_append_ret(
- TPAX_SYSTEM_ERROR(dctx),
- unit);
-
- /* iterate */
- for (; nbytes>0; ) {
- if (!strcmp(dirent->d_name,".")) {
- (void)0;
-
- } else if (!strcmp(dirent->d_name,"..")) {
- (void)0;
-
- } else {
- if (dirent->d_type == DT_UNKNOWN) {
- if (fstatat(fd,dirent->d_name,&st,AT_SYMLINK_NOFOLLOW))
- return tpax_archive_append_ret(
- TPAX_SYSTEM_ERROR(dctx),
- unit);
-
- if (S_ISDIR(st.st_mode)) {
- dirent->d_type = DT_DIR;
- }
- }
-
- if (dirent->d_type == DT_DIR) {
- if (!(dentbuf = tpax_get_driver_dirents(dctx)))
- if (!(dentbuf = tpax_dirent_buf_first_alloc(dctx)))
- return tpax_archive_append_ret(
- TPAX_SYSTEM_ERROR(dctx),
- unit);
-
- needed = dirent->d_reclen;
- needed += offsetof(struct tpax_dirent,dirent);
- needed += 0x7;
- needed |= 0x7;
- needed ^= 0x7;
-
- for (; dentbuf->next && (dentbuf->nfree < needed); )
- dentbuf = dentbuf->next;
-
- if (dentbuf->nfree < needed)
- if (!(dentbuf = tpax_dirent_buf_next_alloc(dentbuf)))
- return tpax_archive_append_ret(
- TPAX_SYSTEM_ERROR(dctx),
- unit);
-
- fkeep = true;
- cdent = dentbuf->cdent;
-
- cdent->fdat = fd;
- cdent->depth = depth;
- cdent->nsize = needed;
- cdent->parent = parent;
-
- memset(&cdent->dirent,0,offsetof(struct dirent,d_name));
-
- cdent->dirent.d_type = dirent->d_type;
- cdent->dirent.d_reclen = dirent->d_reclen;
-
- src = dirent->d_name;
- dst = cdent->dirent.d_name;
-
- cap = dst - offsetof(struct dirent,d_name);
- cap -= offsetof(struct tpax_dirent,dirent);
- cap += needed;
-
- for (; *src; )
- *dst++ = *src++;
-
- for (; dst<cap; )
- *dst++ = 0;
-
- dentbuf->cdent = (struct tpax_dirent *)cap;
- dentbuf->nfree -= needed;
- } else {
- if (tpax_archive_append_one(
- dctx,0,dirent,fd,prefix,
- 0,*uctx->path) < 0)
- return tpax_archive_append_ret(
- TPAX_NESTED_ERROR(dctx),
- unit);
- }
- }
-
- addr = (uintptr_t)dirent;
- addr += dirent->d_reclen;
- nbytes -= dirent->d_reclen;
- dirent = (struct dirent *)addr;
-
- if (nbytes == 0) {
- nbytes = tpax_getdents(fd,dirents,TPAX_DIRENT_BUFLEN);
-
- while ((nbytes == -EINTR) || ((nbytes < 0) && (errno == EINTR)))
- nbytes = tpax_getdents(fd,dirents,TPAX_DIRENT_BUFLEN);
-
- if (nbytes < 0)
- tpax_archive_append_ret(
- TPAX_SYSTEM_ERROR(dctx),
- unit);
-
- dirent = dirents;
- }
- }
-
- /* all done */
- return tpax_archive_append_ret(
- fkeep ? 0 : close(fd),
- unit);
-}
-
-static int tpax_archive_append_impl(
- const struct tpax_driver_ctx * dctx,
- const struct tpax_unit_ctx * uctx,
- int depth,
- const char * prefix,
- struct tpax_dirent * parent)
-{
- if (S_ISDIR(uctx->st->st_mode))
- if (dctx->cctx->drvflags & TPAX_DRIVER_DIR_MEMBER_RECURSE)
- return tpax_archive_append_dir(
- dctx,uctx,0,
- tpax_driver_fdcwd(dctx),
- depth,prefix,parent);
-
- return tpax_archive_append_one(
- dctx,uctx,0,
- tpax_driver_fdcwd(dctx),
- prefix,0,0);
-}
-
-int tpax_archive_append(
- const struct tpax_driver_ctx * dctx,
- const struct tpax_unit_ctx * uctx,
- const char * prefix)
-{
- struct tpax_dirent_buffer * dentbuf;
- struct tpax_dirent * cdent;
- struct tpax_dirent * cnext;
- const struct tpax_dirent * parent;
- uintptr_t addr;
- const char * rdir;
- const char * src;
- char * dst;
- char * cap;
- char * mark;
- int idx;
- const char * dirv[256];
- char pbuf[2048];
-
- /* normalized prefix */
- if (prefix && (prefix[0] == '.') && (!prefix[1]))
- prefix = 0;
-
- if (prefix && (prefix[0] == '.') && (prefix[1] == '/'))
- for (++prefix; *prefix=='/'; prefix++)
- (void)0;
-
- /* append explicit item */
- tpax_archive_append_impl(dctx,uctx,0,prefix,0);
-
- /* iterate through queued items */
- dentbuf = tpax_get_driver_dirents(dctx);
- cdent = dentbuf ? dentbuf->dbuf : 0;
-
- if (cdent) {
- dst = pbuf;
- cap = &pbuf[sizeof(pbuf)];
-
- if (prefix && prefix[0]) {
- for (; *src && dst<cap; )
- *dst++ = *src++;
-
- if (dst == cap)
- return TPAX_BUFFER_ERROR(dctx);
-
- if (dst[-1] != '/')
- *dst++ = '/';
- }
-
- src = *uctx->path;
-
- for (; *src && dst<cap; )
- *dst++ = *src++;
-
- if (dst == cap)
- return TPAX_BUFFER_ERROR(dctx);
-
- if (dst[-1] != '/')
- *dst++ = '/';
-
- *dst = 0;
- mark = dst;
- rdir = pbuf;
-
- (void)mark;
- }
-
- for (; cdent; ) {
- switch (cdent->dirent.d_type) {
- case DT_DIR:
- if (tpax_archive_append_dir(
- dctx,0,cdent,cdent->fdat,
- cdent->depth,rdir,cdent) < 0)
- return TPAX_NESTED_ERROR(dctx);
-
- break;
-
- default:
- if (tpax_archive_append_one(
- dctx,0,&cdent->dirent,
- cdent->fdat,rdir,cdent,0) < 0)
- return TPAX_NESTED_ERROR(dctx);
- }
-
- addr = (uintptr_t)cdent;
- addr += cdent->nsize;
- cnext = (struct tpax_dirent *)addr;
-
- if (cnext == dentbuf->cdent) {
- dentbuf = dentbuf->next;
- cnext = dentbuf ? dentbuf->dbuf : 0;
- }
-
- if (cnext && (cnext->parent != cdent->parent)) {
- if (cnext->depth > 256)
- return TPAX_BUFFER_ERROR(dctx);
-
- for (parent=cnext->parent; parent; parent=parent->parent)
- dirv[parent->depth - 1] = parent->dirent.d_name;
-
- for (idx=0,dst=mark; idx<cnext->parent->depth; idx++) {
- src = dirv[idx];
-
- for (; *src; )
- *dst++ = *src++;
-
- *dst++ = '/';
- }
-
- *--dst = 0;
- }
-
- cdent = cnext;
- }
-
- return 0;
-}
-
-int tpax_archive_seal(const struct tpax_driver_ctx * dctx)
-{
- int fdout;
- off_t cpos;
- ssize_t nbytes;
- ssize_t nwritten;
- ssize_t blksize;
- char buf[512];
-
- blksize = tpax_get_archive_block_size(dctx);
- cpos = tpax_get_driver_cpos(dctx);
-
- if (cpos % 512)
- return TPAX_CUSTOM_ERROR(dctx,TPAX_ERR_FLOW_ERROR);
-
- fdout = tpax_driver_fdout(dctx);
- memset(buf,0,sizeof(buf));
-
- switch (cpos % blksize) {
- case 0:
- nbytes = cpos + blksize;
- break;
-
- default:
- nbytes = cpos / blksize;
- nbytes *= blksize;
- nbytes += blksize;
-
- if (nbytes-cpos == 512)
- nbytes += blksize;
- }
-
- for (nwritten=cpos; nwritten<nbytes; nwritten+=512) {
- if (tpax_archive_append_memory_data(fdout,buf,512) < 0)
- return TPAX_SYSTEM_ERROR(dctx);
-
- tpax_set_driver_cpos(dctx,nwritten);
- }
-
- return 0;
-}