/******************************************************/ /* tpax: a topological pax implementation */ /* Copyright (C) 2020 Z. Gilboa */ /* Released under GPLv2 and GPLv3; see COPYING.TPAX. */ /******************************************************/ #include #include #include #include #include #include #include #include #include #include #include #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; nreadst->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); }