summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/tpax/tpax.h2
-rw-r--r--src/driver/tpax_amain.c17
-rw-r--r--src/logic/tpax_archive_write.c185
3 files changed, 200 insertions, 4 deletions
diff --git a/include/tpax/tpax.h b/include/tpax/tpax.h
index 993352b..323b65c 100644
--- a/include/tpax/tpax.h
+++ b/include/tpax/tpax.h
@@ -152,6 +152,8 @@ tpax_api int tpax_set_driver_fdctx (struct tpax_driver_ctx *, const struct
/* core api */
tpax_api int tpax_archive_append_item (const struct tpax_driver_ctx *, const struct tpax_unit_ctx *);
+tpax_api int tpax_archive_write (const struct tpax_driver_ctx *);
+
tpax_api int tpax_archive_seal (const struct tpax_driver_ctx *);
/* helper api */
diff --git a/src/driver/tpax_amain.c b/src/driver/tpax_amain.c
index 293535a..9e76d08 100644
--- a/src/driver/tpax_amain.c
+++ b/src/driver/tpax_amain.c
@@ -57,6 +57,20 @@ static void tpax_perform_unit_actions(
tpax_archive_append_item(dctx,uctx);
}
+static void tpax_archive_write_and_seal(
+ const struct tpax_driver_ctx * dctx)
+{
+ if (tpax_archive_write(dctx) == TPAX_OK)
+ tpax_archive_seal(dctx);
+}
+
+static void tpax_perform_archive_actions(
+ const struct tpax_driver_ctx * dctx)
+{
+ if (dctx->cctx->drvflags & TPAX_DRIVER_EXEC_MODE_WRITE)
+ tpax_archive_write_and_seal(dctx);
+}
+
static int tpax_exit(struct tpax_driver_ctx * dctx, int ret)
{
tpax_output_error_vector(dctx);
@@ -94,8 +108,7 @@ int tpax_main(char ** argv, char ** envp, const struct tpax_fd_ctx * fdctx)
}
}
- if ((dctx->cctx->drvflags & TPAX_DRIVER_EXEC_MODE_WRITE) && dctx->units[0])
- tpax_archive_seal(dctx);
+ tpax_perform_archive_actions(dctx);
return tpax_exit(dctx,dctx->errv[0] ? TPAX_ERROR : TPAX_OK);
}
diff --git a/src/logic/tpax_archive_write.c b/src/logic/tpax_archive_write.c
index b4dcf2a..272f9b9 100644
--- a/src/logic/tpax_archive_write.c
+++ b/src/logic/tpax_archive_write.c
@@ -9,6 +9,10 @@
#include "tpax_errinfo_impl.h"
#include "tpax_visibility_impl.h"
+#ifndef ssizeof
+#define ssizeof(x) (ssize_t)(sizeof(x))
+#endif
+
static int tpax_archive_append_memory_data(
int fdout,
void * buf,
@@ -59,6 +63,185 @@ static int tpax_archive_append_pad(
return ret;
}
+static int tpax_archive_write_ret(
+ int ret,
+ struct tpax_unit_ctx * uctx)
+{
+ tpax_free_unit_ctx(uctx);
+ return ret;
+}
+
+static int tpax_archive_write_impl(
+ const struct tpax_driver_ctx * dctx,
+ const struct tpax_dirent * cdent,
+ int fdcwd,
+ int fdout)
+{
+ struct tpax_unit_ctx * uctx;
+ struct tpax_ustar_header uhdr;
+ const char * path;
+ off_t hpos;
+ off_t dpos;
+ int fdtmp;
+ ssize_t nread;
+ ssize_t nbytes;
+ void * buf;
+ size_t buflen;
+ size_t cmplen;
+ void * membuf;
+
+ /* full path */
+ if (!(path = tpax_queue_item_full_path(dctx,cdent)))
+ return TPAX_CUSTOM_ERROR(
+ dctx,
+ TPAX_ERR_FLOW_ERROR);
+
+ /* uctx */
+ if (tpax_get_unit_ctx(dctx,fdcwd,path,&uctx) < 0)
+ return TPAX_NESTED_ERROR(dctx);
+
+ /* record errors */
+ tpax_driver_set_ectx(
+ dctx,0,path);
+
+ /* 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_write_ret(
+ TPAX_NESTED_ERROR(dctx),
+ uctx);
+
+ /* 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,fdcwd,path,
+ uctx->st,membuf) < 0)
+ return tpax_archive_write_ret(
+ TPAX_NESTED_ERROR(dctx),
+ uctx);
+ } else {
+ if ((fdtmp = tpax_file_create_tmpfs_snapshot(
+ dctx,fdcwd,path,
+ uctx->st)) < 0)
+ return tpax_archive_write_ret(
+ TPAX_NESTED_ERROR(dctx),
+ uctx);
+
+ if (lseek(fdtmp,0,SEEK_SET) < 0)
+ return tpax_archive_write_ret(
+ TPAX_SYSTEM_ERROR(dctx),
+ uctx);
+ }
+ }
+
+ /* append header */
+ if (tpax_archive_append_memory_data(fdout,&uhdr,ssizeof(uhdr)) < 0) {
+ if (fdtmp >= 0)
+ close(fdtmp);
+
+ return tpax_archive_write_ret(
+ TPAX_SYSTEM_ERROR(dctx),
+ uctx);
+ }
+
+ tpax_set_driver_cpos(dctx,dpos);
+
+ /* all done? */
+ if (!(S_ISREG(uctx->st->st_mode))) {
+ tpax_free_unit_ctx(uctx);
+ 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_write_ret(
+ TPAX_SYSTEM_ERROR(dctx),
+ uctx);
+
+ } else if (nbytes == 0) {
+ close(fdtmp);
+ return tpax_archive_write_ret(
+ TPAX_CUSTOM_ERROR(dctx,TPAX_ERR_FLOW_ERROR),
+ uctx);
+
+ } else {
+ nread += nbytes;
+ }
+
+ if (tpax_archive_append_memory_data(fdout,buf,nbytes) < 0) {
+ close(fdtmp);
+ return tpax_archive_write_ret(
+ TPAX_SYSTEM_ERROR(dctx),
+ uctx);
+ }
+ }
+
+ close(fdtmp);
+ } else {
+ if (tpax_archive_append_memory_data(
+ fdout,membuf,
+ uctx->st->st_size) < 0)
+ return tpax_archive_write_ret(
+ TPAX_SYSTEM_ERROR(dctx),
+ uctx);
+ }
+
+ return tpax_archive_write_ret(
+ tpax_archive_append_pad(dctx,fdout,uctx->st),
+ uctx);
+}
+
+int tpax_archive_write(const struct tpax_driver_ctx * dctx)
+{
+ struct tpax_driver_ctx_impl * ictx;
+ struct tpax_dirent ** direntv;
+ int fdcwd;
+ int fdout;
+
+ /* driver */
+ ictx = tpax_get_driver_ictx(dctx);
+ fdcwd = tpax_driver_fdcwd(dctx);
+ fdout = tpax_driver_fdout(dctx);
+
+ /* quote to archive */
+ if (tpax_update_queue_vector(dctx) < 0)
+ return TPAX_NESTED_ERROR(dctx);
+
+ for (direntv=ictx->direntv; *direntv; direntv++)
+ if (tpax_archive_write_impl(dctx,*direntv,fdcwd,fdout) < 0)
+ return TPAX_NESTED_ERROR(dctx);
+
+ return 0;
+}
+
int tpax_archive_seal(const struct tpax_driver_ctx * dctx)
{
int fdout;
@@ -98,7 +281,5 @@ int tpax_archive_seal(const struct tpax_driver_ctx * dctx)
tpax_set_driver_cpos(dctx,nwritten);
}
- (void)tpax_archive_append_pad;
-
return 0;
}