Blame src/logic/tpax_archive_append.c

409008
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(
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
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;
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;
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
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(
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
af4988
	/* associated data? */
af4988
	if S_ISREG(uctx->st->st_mode) {
af4988
		if ((buf = tpax_get_driver_anon_map_addr(dctx,&buflen)))
af4988
			if (buflen >= (cmplen = uctx->st->st_size))
af4988
				membuf = buf;
af4988
af4988
		if (ssizeof(sbuf) >= (uctx->st->st_size))
af4988
			membuf = sbuf;
af4988
af4988
		/* snapshot */
af4988
		if (membuf) {
af4988
			if (tpax_file_create_memory_snapshot(
a2aed5
					dctx,fdat,*uctx->path,
af4988
					uctx->st,membuf) < 0)
af4988
				return TPAX_NESTED_ERROR(dctx);
af4988
		} else {
af4988
			if ((fdtmp = tpax_file_create_tmpfs_snapshot(
a2aed5
					dctx,fdat,*uctx->path,
af4988
					uctx->st)) < 0)
af4988
				return TPAX_NESTED_ERROR(dctx);
af4988
af4988
			if (lseek(fdtmp,0,SEEK_SET) < 0)
af4988
				return TPAX_SYSTEM_ERROR(dctx);
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
3db888
		return TPAX_SYSTEM_ERROR(dctx);
3db888
	}
3db888
409008
	tpax_set_driver_cpos(dctx,dpos);
409008
af4988
	/* all done? */
af4988
	if (!(S_ISREG(uctx->st->st_mode)))
af4988
		return 0;
af4988
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(
409008
		dctx,fdout,uctx->st);
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
}