summaryrefslogtreecommitdiffhomepage
path: root/src/logic
diff options
context:
space:
mode:
Diffstat (limited to 'src/logic')
-rw-r--r--src/logic/tpax_archive_append.c174
1 files changed, 174 insertions, 0 deletions
diff --git a/src/logic/tpax_archive_append.c b/src/logic/tpax_archive_append.c
new file mode 100644
index 0000000..ce357b5
--- /dev/null
+++ b/src/logic/tpax_archive_append.c
@@ -0,0 +1,174 @@
+/******************************************************/
+/* tpax: a topological pax implementation */
+/* Copyright (C) 2020 Z. Gilboa */
+/* 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/stat.h>
+
+#include <tpax/tpax.h>
+#include <tpax/tpax_specs.h>
+#include "tpax_driver_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(
+ int fdout,
+ const struct stat * st)
+{
+ ssize_t nbytes;
+ char buf[512];
+
+ nbytes = st->st_size;
+ nbytes += 0x1ff;
+ nbytes |= 0x1ff;
+ nbytes ^= 0x1ff;
+ nbytes -= st->st_size;
+
+ memset(buf,0,nbytes);
+
+ return tpax_archive_append_memory_data(
+ fdout,buf,nbytes);
+}
+
+int tpax_archive_append(
+ const struct tpax_driver_ctx * dctx,
+ const struct tpax_unit_ctx * uctx)
+{
+ struct tpax_ustar_header uhdr;
+ int fdout;
+ int fdtmp;
+ ssize_t nread;
+ ssize_t nbytes;
+ void * buf;
+ size_t buflen;
+ size_t cmplen;
+ void * membuf;
+ char sbuf[2048];
+
+ /* record errors */
+ tpax_driver_set_ectx(
+ dctx,0,
+ *uctx->path);
+
+ /* driver */
+ fdout = tpax_driver_fdout(dctx);
+
+ /* header */
+ if (tpax_init_ustar_header(
+ dctx,*uctx->path,uctx->st,
+ *uctx->link,&uhdr) < 0)
+ return TPAX_NESTED_ERROR(dctx);
+
+ /* buffer */
+ membuf = 0;
+ fdtmp = -1;
+
+ if ((buf = tpax_get_driver_anon_map_addr(dctx,&buflen)))
+ if (buflen >= (cmplen = uctx->st->st_size))
+ membuf = buf;
+
+ if (ssizeof(sbuf) >= (uctx->st->st_size))
+ membuf = sbuf;
+
+ /* snapshot */
+ if (membuf) {
+ if (tpax_file_create_memory_snapshot(
+ dctx,*uctx->path,
+ uctx->st,membuf) < 0)
+ return TPAX_NESTED_ERROR(dctx);
+ } else {
+ if ((fdtmp = tpax_file_create_tmpfs_snapshot(
+ dctx,*uctx->path,
+ uctx->st)) < 0)
+ return TPAX_NESTED_ERROR(dctx);
+
+ if (lseek(fdtmp,0,SEEK_SET) < 0)
+ return TPAX_SYSTEM_ERROR(dctx);
+ }
+
+ /* append header */
+ if (tpax_archive_append_memory_data(fdout,&uhdr,ssizeof(uhdr)) < 0) {
+ if (fdtmp >= 0)
+ close(fdtmp);
+
+ return TPAX_SYSTEM_ERROR(dctx);
+ }
+
+ /* append data from snapshot */
+ if (fdtmp >= 0) {
+ if (!buf) {
+ buf = sbuf;
+ buflen = sizeof(sbuf);
+ }
+
+ 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_SYSTEM_ERROR(dctx);
+
+ } else if (nbytes == 0) {
+ close(fdtmp);
+ return TPAX_CUSTOM_ERROR(dctx,TPAX_ERR_FLOW_ERROR);
+
+ } else {
+ nread += nbytes;
+ }
+
+ if (tpax_archive_append_memory_data(fdout,buf,nbytes) < 0) {
+ close(fdtmp);
+ return TPAX_SYSTEM_ERROR(dctx);
+ }
+ }
+
+ close(fdtmp);
+ } else {
+ if (tpax_archive_append_memory_data(
+ fdout,membuf,
+ uctx->st->st_size) < 0)
+ return TPAX_SYSTEM_ERROR(dctx);
+ }
+
+ return tpax_archive_append_pad(
+ fdout,uctx->st);
+}