1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/librazor/atomic-emulate.c Sat Feb 11 09:30:23 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 */