librazor/atomic-emulate.c
changeset 421 408c66ad463d
child 423 6112bcc5d1cf
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/librazor/atomic-emulate.c	Sat Feb 11 09:34:40 2012 +0000
     1.3 @@ -0,0 +1,249 @@
     1.4 +/*
     1.5 + * Copyright (C) 2012  J. Ali Harlow <ali@juiblex.co.uk>
     1.6 + *
     1.7 + * This program is free software; you can redistribute it and/or modify
     1.8 + * it under the terms of the GNU General Public License as published by
     1.9 + * the Free Software Foundation; either version 2 of the License, or
    1.10 + * (at your option) any later version.
    1.11 + *
    1.12 + * This program is distributed in the hope that it will be useful,
    1.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
    1.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    1.15 + * GNU General Public License for more details.
    1.16 + *
    1.17 + * You should have received a copy of the GNU General Public License along
    1.18 + * with this program; if not, write to the Free Software Foundation, Inc.,
    1.19 + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
    1.20 + */
    1.21 +
    1.22 +#include "config.h"
    1.23 +
    1.24 +#if ENABLE_ATOMIC && !HAVE_WINDOWS_KTM
    1.25 +
    1.26 +#include <stdlib.h>
    1.27 +#include <string.h>
    1.28 +#include <unistd.h>
    1.29 +#include <sys/types.h>
    1.30 +#include <sys/stat.h>
    1.31 +#include <fcntl.h>
    1.32 +#include <dirent.h>
    1.33 +#include <errno.h>
    1.34 +#include "razor-internal.h"
    1.35 +
    1.36 +/*
    1.37 + * Emulated atomic support
    1.38 + *
    1.39 + * This implementation is better than nothing, but is certainly not atomic.
    1.40 + * It does have a couple of advantages over atomic-none:
    1.41 + *	- If a file operation fails while a package is being installed we
    1.42 + *	  have a good chance of being able to rollback the transaction to
    1.43 + *	  a well-known state.
    1.44 + *	- We behave similarly to atomic-ktm in that changes are not visible
    1.45 + *	  on disk to non-atomic operations (eg., scripts) until the atomic
    1.46 + *	  is committed. This makes the testsuite more likely to pick up
    1.47 + *	  problems that would otherwise only be found when using razor on
    1.48 + *	  an MS-Windows system which supports KTM.
    1.49 + */
    1.50 +
    1.51 +#ifndef O_BINARY
    1.52 +#define O_BINARY	0
    1.53 +#endif
    1.54 +
    1.55 +static void recursive_remove(const char *directory)
    1.56 +{
    1.57 +	DIR *dp;
    1.58 +	struct dirent *dirp;
    1.59 +	char *buf;
    1.60 +
    1.61 +	dp = opendir(directory);
    1.62 +	while((dirp = readdir(dp))) {
    1.63 +		if (strcmp(dirp->d_name, ".") && strcmp(dirp->d_name, "..")) {
    1.64 +			buf = malloc(strlen(directory) + strlen(dirp->d_name)
    1.65 +				     + 2);
    1.66 +			sprintf(buf, "%s/%s", directory, dirp->d_name);
    1.67 +			if (remove(buf) < 0)
    1.68 +				recursive_remove(buf);
    1.69 +			free(buf);
    1.70 +		}
    1.71 +	}
    1.72 +
    1.73 +	rmdir(directory);
    1.74 +}
    1.75 +
    1.76 +RAZOR_EXPORT struct razor_atomic *razor_atomic_open(const char *description)
    1.77 +{
    1.78 +	struct razor_atomic *atomic;
    1.79 +
    1.80 +	atomic = zalloc(sizeof *atomic);
    1.81 +
    1.82 +	atomic->toplevel = strdup(".atomic-XXXXXX");
    1.83 +	if (!mkdtemp(atomic->toplevel)) {
    1.84 +		free(atomic->toplevel);
    1.85 +		free(atomic);
    1.86 +		return NULL;
    1.87 +	}
    1.88 +
    1.89 +	atomic->description = strdup(description);
    1.90 +
    1.91 +	return atomic;
    1.92 +}
    1.93 +
    1.94 +RAZOR_EXPORT int razor_atomic_commit(struct razor_atomic *atomic)
    1.95 +{
    1.96 +	struct atomic_action *actions;
    1.97 +
    1.98 +	if (razor_atomic_in_error_state(atomic))
    1.99 +		return -1;
   1.100 +
   1.101 +	if (atomic->actions) {
   1.102 +		actions = atomic_action_list_reverse(atomic->actions);
   1.103 +		atomic->actions = NULL;
   1.104 +		actions = atomic_action_do(atomic, actions);
   1.105 +		atomic_action_free(actions);
   1.106 +	}
   1.107 +
   1.108 +	if (atomic->toplevel) {
   1.109 +		recursive_remove(atomic->toplevel);
   1.110 +		free(atomic->toplevel);
   1.111 +		atomic->toplevel = NULL;
   1.112 +	}
   1.113 +
   1.114 +	return !!atomic->error_str;
   1.115 +}
   1.116 +
   1.117 +RAZOR_EXPORT void razor_atomic_destroy(struct razor_atomic *atomic)
   1.118 +{
   1.119 +	if (atomic->toplevel) {
   1.120 +		recursive_remove(atomic->toplevel);
   1.121 +		free(atomic->toplevel);
   1.122 +		atomic->toplevel = NULL;
   1.123 +	}
   1.124 +
   1.125 +	free(atomic->error_path);
   1.126 +	free(atomic->error_str);
   1.127 +	free(atomic->error_msg);
   1.128 +	free(atomic);
   1.129 +}
   1.130 +
   1.131 +RAZOR_EXPORT int
   1.132 +razor_atomic_make_dirs(struct razor_atomic *atomic, const char *root,
   1.133 +		       const char *path)
   1.134 +{
   1.135 +	struct atomic_action *a;
   1.136 +
   1.137 +	if (razor_atomic_in_error_state(atomic))
   1.138 +		return -1;
   1.139 +
   1.140 +	a = atomic_action_new(ACTION_MAKE_DIRS);
   1.141 +	a->args.path = strdup(path);
   1.142 +	a->args.u.make_dirs.root = strdup(root);
   1.143 +	atomic->actions = atomic_action_list_prepend(atomic->actions, a);
   1.144 +
   1.145 +	return 0;
   1.146 +}
   1.147 +
   1.148 +RAZOR_EXPORT int
   1.149 +razor_atomic_remove(struct razor_atomic *atomic, const char *path)
   1.150 +{
   1.151 +	struct atomic_action *a;
   1.152 +
   1.153 +	if (razor_atomic_in_error_state(atomic))
   1.154 +		return -1;
   1.155 +
   1.156 +	a = atomic_action_new(ACTION_REMOVE);
   1.157 +	a->args.path = strdup(path);
   1.158 +	atomic->actions = atomic_action_list_prepend(atomic->actions, a);
   1.159 +
   1.160 +	return 0;
   1.161 +}
   1.162 +
   1.163 +RAZOR_EXPORT int
   1.164 +razor_atomic_rename_file(struct razor_atomic *atomic, const char *oldpath,
   1.165 +			 const char *newpath)
   1.166 +{
   1.167 +	struct atomic_action *a;
   1.168 +
   1.169 +	if (razor_atomic_in_error_state(atomic))
   1.170 +		return -1;
   1.171 +
   1.172 +	a = atomic_action_new(ACTION_MOVE);
   1.173 +	a->args.path = strdup(oldpath);
   1.174 +	a->args.u.move.dest = strdup(newpath);
   1.175 +	atomic->actions = atomic_action_list_prepend(atomic->actions, a);
   1.176 +
   1.177 +	return 0;
   1.178 +}
   1.179 +
   1.180 +RAZOR_EXPORT int
   1.181 +razor_atomic_create_dir(struct razor_atomic *atomic, const char *dirname,
   1.182 +			mode_t mode)
   1.183 +{
   1.184 +	struct atomic_action *a;
   1.185 +
   1.186 +	if (razor_atomic_in_error_state(atomic))
   1.187 +		return -1;
   1.188 +
   1.189 +	a = atomic_action_new(ACTION_CREATE_DIR);
   1.190 +	a->args.path = strdup(dirname);
   1.191 +	a->args.u.create_dir.mode = mode;
   1.192 +	atomic->actions = atomic_action_list_prepend(atomic->actions, a);
   1.193 +
   1.194 +	return 0;
   1.195 +}
   1.196 +
   1.197 +RAZOR_EXPORT int
   1.198 +razor_atomic_create_symlink(struct razor_atomic *atomic, const char *target,
   1.199 +			    const char *path)
   1.200 +{
   1.201 +#if HAVE_SYMLINK
   1.202 +	struct atomic_action *a;
   1.203 +#endif
   1.204 +
   1.205 +	if (razor_atomic_in_error_state(atomic))
   1.206 +		return -1;
   1.207 +
   1.208 +#if HAVE_SYMLINK
   1.209 +	a = atomic_action_new(ACTION_CREATE_SYMLINK);
   1.210 +	a->args.path = strdup(path);
   1.211 +	a->args.u.create_symlink.target = strdup(target);
   1.212 +	atomic->actions = atomic_action_list_prepend(atomic->actions, a);
   1.213 +
   1.214 +	return 0;
   1.215 +#else
   1.216 +	razor_atomic_set_error_str(atomic, NULL, "Symbolic links not supported "
   1.217 +						 "on this platform");
   1.218 +
   1.219 +	return -1;
   1.220 +#endif
   1.221 +}
   1.222 +
   1.223 +RAZOR_EXPORT int
   1.224 +razor_atomic_create_file(struct razor_atomic *atomic, const char *filename,
   1.225 +                         mode_t mode)
   1.226 +{
   1.227 +	int fd;
   1.228 +	struct atomic_action *a;
   1.229 +	char *tmpnam;
   1.230 +
   1.231 +	if (razor_atomic_in_error_state(atomic))
   1.232 +		return -1;
   1.233 +
   1.234 +	atomic->error_path = strdup(filename);
   1.235 +	tmpnam = atomic_action_attic_tmpnam(atomic);
   1.236 +	fd = open(tmpnam, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
   1.237 +		  mode & (S_IRWXU | S_IRWXG | S_IRWXO));
   1.238 +
   1.239 +	if (fd == -1)
   1.240 +		razor_atomic_set_error_str(atomic, NULL, strerror(errno));
   1.241 +	else {
   1.242 +		a = atomic_action_new(ACTION_MOVE);
   1.243 +		a->args.path = tmpnam;
   1.244 +		a->args.u.move.dest = strdup(filename);
   1.245 +		atomic->actions = atomic_action_list_prepend(atomic->actions,
   1.246 +							     a);
   1.247 +	}
   1.248 +
   1.249 +	return fd;
   1.250 +}
   1.251 +
   1.252 +#endif	/* ENABLE_ATOMIC && !HAVE_WINDOWS_KTM */