Blame src/logic/tpax_file_create_tmpfs_snapshot.c

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,
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
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
}