Blame src/io/tpax_create_tmpfs_snapshot.c

5874a9
/**************************************************************/
5874a9
/*  tpax: a topological pax implementation                    */
bef28d
/*  Copyright (C) 2020--2024  SysDeer Technologies, LLC       */
5874a9
/*  Released under GPLv2 and GPLv3; see COPYING.TPAX.         */
5874a9
/**************************************************************/
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"
ee80f8
#include "tpax_ftime_impl.h"
f6b26d
f6b26d
#ifndef ssizeof
f6b26d
#define ssizeof(x) (ssize_t)(sizeof(x))
f6b26d
#endif
f6b26d
0ee4a8
int tpax_io_create_tmpfs_snapshot(
f6b26d
	const struct tpax_driver_ctx *  dctx,
a2aed5
	int                             fdat,
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
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 */
67ad73
	buf = tpax_get_driver_anon_map_addr(
67ad73
		dctx,&buflen);
f6b26d
f6b26d
	/* open */
a2aed5
	if ((fdsrc = openat(fdat,path,O_CLOEXEC|O_NOCTTY|O_NOFOLLOW,0)) < 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
6c8a81
	} else if (tpax_util_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) {
ee80f8
			tpax_ftime_restore_and_close(dctx,fdsrc,&dstst);
f6b26d
			close(fdtmp);
f6b26d
			return TPAX_SYSTEM_ERROR(dctx);
f6b26d
f6b26d
		} else if (nbytes == 0) {
ee80f8
			tpax_ftime_restore_and_close(dctx,fdsrc,&dstst);
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) {
ee80f8
				tpax_ftime_restore_and_close(dctx,fdsrc,&dstst);
f6b26d
				close(fdtmp);
f6b26d
				return TPAX_SYSTEM_ERROR(dctx);
f6b26d
f6b26d
			} else {
f6b26d
				nbytes -= ret;
f6b26d
			}
f6b26d
		}
f6b26d
	}
f6b26d
ee80f8
	/* preserve last data access time as needed */
ee80f8
	tpax_ftime_restore(dctx,fdsrc,&dstst);
ee80f8
f6b26d
	/* stat compare */
f6b26d
	if ((fstat(fdsrc,&dstst)) < 0) {
f6b26d
		close(fdsrc);
f6b26d
		close(fdtmp);
f6b26d
		return TPAX_SYSTEM_ERROR(dctx);
f6b26d
6c8a81
	} else if (tpax_util_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
}