/**************************************************************/ /* tpax: a topological pax implementation */ /* Copyright (C) 2020--2021 SysDeer Technologies, LLC */ /* 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 int tpax_file_create_tmpfs_snapshot( const struct tpax_driver_ctx * dctx, int fdat, const char * path, const struct stat * srcst) { int fdsrc; int fdtmp; char * ch; ssize_t nread; ssize_t nbytes; ssize_t ret; void * buf; size_t buflen; struct stat dstst; /* record errors */ tpax_driver_set_ectx( dctx,0,path); /* tmpfile */ if ((fdtmp = tpax_tmpfile()) < 0) return TPAX_SYSTEM_ERROR(dctx); /* buffer */ buf = tpax_get_driver_anon_map_addr( dctx,&buflen); /* open */ if ((fdsrc = openat(fdat,path,O_CLOEXEC|O_NOCTTY|O_NOFOLLOW,0)) < 0) { close(fdtmp); return TPAX_SYSTEM_ERROR(dctx); } /* stat compare */ if ((fstat(fdsrc,&dstst)) < 0) { close(fdsrc); close(fdtmp); return TPAX_SYSTEM_ERROR(dctx); } else if (tpax_stat_compare(srcst,&dstst)) { close(fdsrc); close(fdtmp); return TPAX_CUSTOM_ERROR(dctx,TPAX_ERR_FILE_CHANGED); } /* read/write loop */ for (nread=0; nreadst_size; ) { nbytes = read(fdsrc,buf,buflen); while ((nbytes < 0) && (errno == EINTR)) nbytes = read(fdsrc,buf,buflen); if (nbytes < 0) { close(fdsrc); close(fdtmp); return TPAX_SYSTEM_ERROR(dctx); } else if (nbytes == 0) { close(fdsrc); close(fdtmp); return TPAX_CUSTOM_ERROR(dctx,TPAX_ERR_FLOW_ERROR); } else { nread += nbytes; } for (ch=buf; nbytes; ch+=ret) { ret = write(fdtmp,ch,nbytes); while ((ret < 0) && (errno == EINTR)) ret = write(fdtmp,ch,nbytes); if (ret < 0) { close(fdsrc); close(fdtmp); return TPAX_SYSTEM_ERROR(dctx); } else { nbytes -= ret; } } } /* stat compare */ if ((fstat(fdsrc,&dstst)) < 0) { close(fdsrc); close(fdtmp); return TPAX_SYSTEM_ERROR(dctx); } else if (tpax_stat_compare(srcst,&dstst)) { close(fdsrc); close(fdtmp); return TPAX_CUSTOM_ERROR(dctx,TPAX_ERR_FILE_CHANGED); } /* yay */ close(fdsrc); return fdtmp; }