|
|
f6b26d |
/******************************************************/
|
|
|
f6b26d |
/* tpax: a topological pax implementation */
|
|
|
f6b26d |
/* Copyright (C) 2020 Z. Gilboa */
|
|
|
f6b26d |
/* Released under GPLv2 and GPLv3; see COPYING.TPAX. */
|
|
|
f6b26d |
/******************************************************/
|
|
|
f6b26d |
|
|
|
f6b26d |
#include <stdint.h>
|
|
|
f6b26d |
#include <stdlib.h>
|
|
|
f6b26d |
#include <string.h>
|
|
|
f6b26d |
#include <unistd.h>
|
|
|
f6b26d |
#include <fcntl.h>
|
|
|
f6b26d |
#include <errno.h>
|
|
|
f6b26d |
#include <grp.h>
|
|
|
f6b26d |
#include <pwd.h>
|
|
|
f6b26d |
#include <sys/stat.h>
|
|
|
f6b26d |
|
|
|
f6b26d |
#include <tpax/tpax.h>
|
|
|
f6b26d |
#include <tpax/tpax_specs.h>
|
|
|
f6b26d |
#include "tpax_driver_impl.h"
|
|
|
f6b26d |
#include "tpax_tmpfile_impl.h"
|
|
|
f6b26d |
#include "tpax_errinfo_impl.h"
|
|
|
f6b26d |
|
|
|
f6b26d |
#ifndef ssizeof
|
|
|
f6b26d |
#define ssizeof(x) (ssize_t)(sizeof(x))
|
|
|
f6b26d |
#endif
|
|
|
f6b26d |
|
|
|
f6b26d |
int tpax_file_create_tmpfs_snapshot(
|
|
|
f6b26d |
const struct tpax_driver_ctx * dctx,
|
|
|
f6b26d |
const char * path,
|
|
|
f6b26d |
const struct stat * srcst)
|
|
|
f6b26d |
{
|
|
|
f6b26d |
int fdsrc;
|
|
|
f6b26d |
int fdtmp;
|
|
|
f6b26d |
char * ch;
|
|
|
f6b26d |
ssize_t nread;
|
|
|
f6b26d |
ssize_t nbytes;
|
|
|
f6b26d |
ssize_t ret;
|
|
|
f6b26d |
void * buf;
|
|
|
f6b26d |
size_t buflen;
|
|
|
f6b26d |
struct stat dstst;
|
|
|
f6b26d |
char sbuf[2048];
|
|
|
f6b26d |
|
|
|
f6b26d |
/* record errors */
|
|
|
f6b26d |
tpax_driver_set_ectx(
|
|
|
f6b26d |
dctx,0,path);
|
|
|
f6b26d |
|
|
|
f6b26d |
/* tmpfile */
|
|
|
f6b26d |
if ((fdtmp = tpax_tmpfile()) < 0)
|
|
|
f6b26d |
return TPAX_SYSTEM_ERROR(dctx);
|
|
|
f6b26d |
|
|
|
f6b26d |
/* buffer */
|
|
|
f6b26d |
if (!(buf = tpax_get_driver_anon_map_addr(dctx,&buflen))) {
|
|
|
f6b26d |
buf = sbuf;
|
|
|
f6b26d |
buflen = sizeof(sbuf);
|
|
|
f6b26d |
}
|
|
|
f6b26d |
|
|
|
f6b26d |
/* open */
|
|
|
f6b26d |
fdsrc = openat(
|
|
|
f6b26d |
tpax_driver_fdcwd(dctx),path,
|
|
|
f6b26d |
O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
|
|
|
f6b26d |
|
|
|
f6b26d |
if (fdsrc < 0) {
|
|
|
f6b26d |
close(fdtmp);
|
|
|
f6b26d |
return TPAX_SYSTEM_ERROR(dctx);
|
|
|
f6b26d |
}
|
|
|
f6b26d |
|
|
|
f6b26d |
/* stat compare */
|
|
|
f6b26d |
if ((fstat(fdsrc,&dstst)) < 0) {
|
|
|
f6b26d |
close(fdsrc);
|
|
|
f6b26d |
close(fdtmp);
|
|
|
f6b26d |
return TPAX_SYSTEM_ERROR(dctx);
|
|
|
f6b26d |
|
|
|
f6b26d |
} else if (tpax_stat_compare(srcst,&dstst)) {
|
|
|
f6b26d |
close(fdsrc);
|
|
|
f6b26d |
close(fdtmp);
|
|
|
f6b26d |
return TPAX_CUSTOM_ERROR(dctx,TPAX_ERR_FILE_CHANGED);
|
|
|
f6b26d |
}
|
|
|
f6b26d |
|
|
|
f6b26d |
/* read/write loop */
|
|
|
f6b26d |
for (nread=0; nread<srcst->st_size; ) {
|
|
|
f6b26d |
nbytes = read(fdsrc,buf,buflen);
|
|
|
f6b26d |
|
|
|
f6b26d |
while ((nbytes < 0) && (errno == EINTR))
|
|
|
f6b26d |
nbytes = read(fdsrc,buf,buflen);
|
|
|
f6b26d |
|
|
|
f6b26d |
if (nbytes < 0) {
|
|
|
f6b26d |
close(fdsrc);
|
|
|
f6b26d |
close(fdtmp);
|
|
|
f6b26d |
return TPAX_SYSTEM_ERROR(dctx);
|
|
|
f6b26d |
|
|
|
f6b26d |
} else if (nbytes == 0) {
|
|
|
f6b26d |
close(fdsrc);
|
|
|
f6b26d |
close(fdtmp);
|
|
|
f6b26d |
return TPAX_CUSTOM_ERROR(dctx,TPAX_ERR_FLOW_ERROR);
|
|
|
f6b26d |
|
|
|
f6b26d |
} else {
|
|
|
f6b26d |
nread += nbytes;
|
|
|
f6b26d |
}
|
|
|
f6b26d |
|
|
|
f6b26d |
for (ch=buf; nbytes; ch+=ret) {
|
|
|
f6b26d |
ret = write(fdtmp,ch,nbytes);
|
|
|
f6b26d |
|
|
|
f6b26d |
while ((ret < 0) && (errno == EINTR))
|
|
|
f6b26d |
ret = write(fdtmp,ch,nbytes);
|
|
|
f6b26d |
|
|
|
f6b26d |
if (ret < 0) {
|
|
|
f6b26d |
close(fdsrc);
|
|
|
f6b26d |
close(fdtmp);
|
|
|
f6b26d |
return TPAX_SYSTEM_ERROR(dctx);
|
|
|
f6b26d |
|
|
|
f6b26d |
} else {
|
|
|
f6b26d |
nbytes -= ret;
|
|
|
f6b26d |
}
|
|
|
f6b26d |
}
|
|
|
f6b26d |
}
|
|
|
f6b26d |
|
|
|
f6b26d |
/* stat compare */
|
|
|
f6b26d |
if ((fstat(fdsrc,&dstst)) < 0) {
|
|
|
f6b26d |
close(fdsrc);
|
|
|
f6b26d |
close(fdtmp);
|
|
|
f6b26d |
return TPAX_SYSTEM_ERROR(dctx);
|
|
|
f6b26d |
|
|
|
f6b26d |
} else if (tpax_stat_compare(srcst,&dstst)) {
|
|
|
f6b26d |
close(fdsrc);
|
|
|
f6b26d |
close(fdtmp);
|
|
|
f6b26d |
return TPAX_CUSTOM_ERROR(dctx,TPAX_ERR_FILE_CHANGED);
|
|
|
f6b26d |
}
|
|
|
f6b26d |
|
|
|
f6b26d |
/* yay */
|
|
|
f6b26d |
close(fdsrc);
|
|
|
f6b26d |
|
|
|
f6b26d |
return fdtmp;
|
|
|
f6b26d |
}
|