diff options
Diffstat (limited to 'src/logic/tpax_archive_append.c')
-rw-r--r-- | src/logic/tpax_archive_append.c | 709 |
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; -} |