Use Windows KTM (atomic transactions) where supported. 0.5
authorJ. Ali Harlow <ali@juiblex.co.uk>
Thu Nov 10 10:35:21 2011 +0000 (2011-11-10)
changeset 403e63951c1d0f8
parent 401 75dd38e0b472
child 404 bd740859c4a0
child 405 f960eb19dca2
Use Windows KTM (atomic transactions) where supported.
Increment current header version to 2
configure.ac
librazor/Makefile.am
librazor/atomic.c
librazor/merger.c
librazor/razor-internal.h
librazor/razor.c
librazor/razor.h
librazor/root.c
librazor/rpm.c
librazor/transaction.c
librazor/util.c
src/main.c
src/rpm.c
     1.1 --- a/configure.ac	Thu Aug 25 14:22:52 2011 +0100
     1.2 +++ b/configure.ac	Thu Nov 10 10:35:21 2011 +0000
     1.3 @@ -1,7 +1,7 @@
     1.4  dnl Process this file with autoconf to produce a configure script.
     1.5  
     1.6  AC_PREREQ(2.59c)
     1.7 -AC_INIT([razor], [0.4.1], [ali@juiblex.co.uk])
     1.8 +AC_INIT([razor], [0.5], [ali@juiblex.co.uk])
     1.9  AM_INIT_AUTOMAKE([])
    1.10  AM_CONFIG_HEADER([config.h])
    1.11  AM_MAINTAINER_MODE
    1.12 @@ -10,8 +10,8 @@
    1.13  #
    1.14  # See http://sources.redhat.com/autobook/autobook/autobook_91.html#SEC91 for details
    1.15  #
    1.16 -LT_CURRENT=1
    1.17 -LT_REVISION=2
    1.18 +LT_CURRENT=2
    1.19 +LT_REVISION=0
    1.20  LT_AGE=0
    1.21  AC_SUBST(LT_CURRENT)
    1.22  AC_SUBST(LT_REVISION)
    1.23 @@ -45,6 +45,25 @@
    1.24  AM_CONDITIONAL(MSWIN_API, test "$mswin_api" = "yes")
    1.25  AC_SUBST(EXTRA_LIBS)
    1.26  
    1.27 +if test "$mswin_api" = "yes"; then
    1.28 +    AC_MSG_CHECKING([for Microsoft Windows Kernel Transaction Manager])
    1.29 +    save_LIBS="$LIBS"
    1.30 +    LIBS="-lktmw32 $LIBS"
    1.31 +    AC_LINK_IFELSE([AC_LANG_PROGRAM([dnl
    1.32 +#include <windows.h>
    1.33 +#include <ktmw32.h>
    1.34 +], [(void)CreateTransaction(NULL,0,0,0,0,0,NULL);])],
    1.35 +      [have_windows_ktm="yes"; EXTRA_LIBS="-lktmw32 $EXTRA_LIBS"],
    1.36 +      [have_windows_ktm="no"])
    1.37 +    LIBS="$save_LIBS"
    1.38 +    AC_MSG_RESULT([$have_windows_ktm])
    1.39 +else
    1.40 +    have_windows_ktm="no"
    1.41 +fi
    1.42 +if test "$have_windows_ktm" = "yes"; then
    1.43 +    AC_DEFINE([HAVE_WINDOWS_KTM],[1],[Define if Windows KTM is available.])
    1.44 +fi
    1.45 +
    1.46  # Taken from dbus
    1.47  AC_ARG_ENABLE(ansi,             [  --enable-ansi           enable -ansi -pedantic gcc flags],enable_ansi=$enableval,enable_ansi=no)
    1.48  AC_ARG_ENABLE(verbose-mode,     [  --enable-verbose-mode   support verbose debug mode],enable_verbose_mode=$enableval,enable_verbose_mode=$USE_MAINTAINER_MODE)
     2.1 --- a/librazor/Makefile.am	Thu Aug 25 14:22:52 2011 +0100
     2.2 +++ b/librazor/Makefile.am	Thu Nov 10 10:35:21 2011 +0000
     2.3 @@ -33,6 +33,7 @@
     2.4  	iterator.c					\
     2.5  	importer.c					\
     2.6  	merger.c					\
     2.7 +	atomic.c					\
     2.8  	transaction.c
     2.9  
    2.10  if HAVE_LUA
     3.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     3.2 +++ b/librazor/atomic.c	Thu Nov 10 10:35:21 2011 +0000
     3.3 @@ -0,0 +1,1002 @@
     3.4 +/*
     3.5 + * Copyright (C) 2011  J. Ali Harlow <ali@juiblex.co.uk>
     3.6 + *
     3.7 + * This program is free software; you can redistribute it and/or modify
     3.8 + * it under the terms of the GNU General Public License as published by
     3.9 + * the Free Software Foundation; either version 2 of the License, or
    3.10 + * (at your option) any later version.
    3.11 + *
    3.12 + * This program is distributed in the hope that it will be useful,
    3.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
    3.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    3.15 + * GNU General Public License for more details.
    3.16 + *
    3.17 + * You should have received a copy of the GNU General Public License along
    3.18 + * with this program; if not, write to the Free Software Foundation, Inc.,
    3.19 + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
    3.20 + */
    3.21 +
    3.22 +#include "config.h"
    3.23 +
    3.24 +#include <stdlib.h>
    3.25 +#ifdef MSWIN_API
    3.26 +#include <windows.h>
    3.27 +#endif
    3.28 +#include <stdio.h>
    3.29 +#include <limits.h>
    3.30 +#include <errno.h>
    3.31 +#include <unistd.h>
    3.32 +#include <fcntl.h>
    3.33 +#include <sys/stat.h>
    3.34 +#include <string.h>
    3.35 +#include <assert.h>
    3.36 +#if HAVE_WINDOWS_KTM
    3.37 +#include <wchar.h>
    3.38 +#include <ktmw32.h>
    3.39 +#endif
    3.40 +
    3.41 +#include "razor.h"
    3.42 +#include "razor-internal.h"
    3.43 +
    3.44 +/*
    3.45 + * Atomic transactions
    3.46 + */
    3.47 +
    3.48 +#ifndef O_BINARY
    3.49 +#define O_BINARY	0
    3.50 +#endif
    3.51 +
    3.52 +#define RAZOR_ASCII_ISALPHA(c)	\
    3.53 +			((c) >= 'A' && (c) <= 'Z' || (c) >= 'a' && (c) <= 'z')
    3.54 +
    3.55 +static int allow_all_root_names = 0;
    3.56 +
    3.57 +/*
    3.58 + * Primarily intended for testing named roots under UNIX platforms.
    3.59 + */
    3.60 +RAZOR_EXPORT void
    3.61 +razor_disable_root_name_checks(int disable)
    3.62 +{
    3.63 +	allow_all_root_names = disable;
    3.64 +}
    3.65 +
    3.66 +#ifdef MSWIN_API
    3.67 +
    3.68 +static char *
    3.69 +razor_utf16_to_utf8(const wchar_t *utf16, int len)
    3.70 +{
    3.71 +	int n;
    3.72 +	char *utf8;
    3.73 +
    3.74 +	n = WideCharToMultiByte(CP_UTF8, 0, utf16, len, NULL, 0, NULL, NULL);
    3.75 +	if (len >= 0 && utf16[len])
    3.76 +		n++;
    3.77 +	utf8 = malloc(n);
    3.78 +	(void)WideCharToMultiByte(CP_UTF8, 0, utf16, len, utf8, n, NULL, NULL);
    3.79 +	if (len >= 0 && utf16[len])
    3.80 +		utf8[n - 1] = 0;
    3.81 +
    3.82 +	return utf8;
    3.83 +}
    3.84 +
    3.85 +static wchar_t *
    3.86 +razor_utf8_to_utf16(const char *utf8, int len)
    3.87 +{
    3.88 +	int n;
    3.89 +	wchar_t *utf16;
    3.90 +
    3.91 +	n = MultiByteToWideChar(CP_UTF8, 0, utf8, len, NULL, 0);
    3.92 +	if (len >= 0 && utf8[len])
    3.93 +		n++;
    3.94 +	utf16 = malloc(n * sizeof(wchar_t));
    3.95 +	(void)MultiByteToWideChar(CP_UTF8, 0, utf8, len, utf16, n);
    3.96 +	if (len >= 0 && utf8[len])
    3.97 +		utf16[n - 1] = 0;
    3.98 +
    3.99 +	return utf16;
   3.100 +}
   3.101 +
   3.102 +#endif	/* MSWIN_API */
   3.103 +
   3.104 +#if HAVE_WINDOWS_KTM
   3.105 +
   3.106 +static int
   3.107 +razor_valid_root_name(const wchar_t *name)
   3.108 +{
   3.109 +	if (allow_all_root_names)
   3.110 +		return !wcschr(name, '/');
   3.111 +
   3.112 +	return RAZOR_ASCII_ISALPHA(name[0]) && name[1] == ':' &&
   3.113 +	       name[2] == '\0';
   3.114 +}
   3.115 +
   3.116 +struct razor_atomic {
   3.117 +	HANDLE transaction;
   3.118 +	int n_files;
   3.119 +	struct razor_atomic_file {
   3.120 +		wchar_t *path;
   3.121 +		HANDLE h;
   3.122 +	} *files;
   3.123 +	char *error_path;
   3.124 +	char *error_str;
   3.125 +	char *error_msg;
   3.126 +};
   3.127 +
   3.128 +struct razor_wstr {
   3.129 +	wchar_t *str;
   3.130 +	int len, allocated;
   3.131 +};
   3.132 +
   3.133 +static struct razor_wstr *
   3.134 +razor_wstr_create(const char *init, int len)
   3.135 +{
   3.136 +	int n;
   3.137 +	struct razor_wstr *wstr;
   3.138 +
   3.139 +	wstr = malloc(sizeof(struct razor_wstr));
   3.140 +
   3.141 +	n = MultiByteToWideChar(CP_UTF8, 0, init, len, NULL, 0);
   3.142 +	if (len >= 0 && init[len])
   3.143 +		wstr->len = n++;
   3.144 +	else
   3.145 +		wstr->len = n - 1;
   3.146 +
   3.147 +	wstr->allocated = n * 2;
   3.148 +	wstr->str = malloc(wstr->allocated * sizeof(wchar_t));
   3.149 +	if (!wstr->str) {
   3.150 +		free(wstr);
   3.151 +		return NULL;
   3.152 +	}
   3.153 +
   3.154 +	(void)MultiByteToWideChar(CP_UTF8, 0, init, len, wstr->str, n);
   3.155 +	if (len >= 0 && init[len])
   3.156 +		wstr->str[wstr->len] = 0;
   3.157 +
   3.158 +	return wstr;
   3.159 +}
   3.160 +
   3.161 +static int
   3.162 +razor_wstr_append(struct razor_wstr *wstr, const char *s, int len)
   3.163 +{
   3.164 +	int n, allocated;
   3.165 +	wchar_t *str;
   3.166 +
   3.167 +	n = MultiByteToWideChar(CP_UTF8, 0, s, len, NULL, 0);
   3.168 +	if (len < 0 || !s[len])
   3.169 +		n--;
   3.170 +
   3.171 +	if (wstr->allocated <= wstr->len + n) {
   3.172 +		allocated = (wstr->len + n + 1) * 2;
   3.173 +		str = realloc(wstr->str, allocated * sizeof(wchar_t));
   3.174 +		if (!str)
   3.175 +			return -1;
   3.176 +		wstr->allocated = allocated;
   3.177 +		wstr->str = str;
   3.178 +	}
   3.179 +
   3.180 +	(void)MultiByteToWideChar(CP_UTF8, 0, s, len, wstr->str + wstr->len, n);
   3.181 +	wstr->len += n;
   3.182 +	wstr->str[wstr->len] = 0;
   3.183 +
   3.184 +	return 0;
   3.185 +}
   3.186 +
   3.187 +static void
   3.188 +razor_wstr_destroy(struct razor_wstr *wstr)
   3.189 +{
   3.190 +	free(wstr->str);
   3.191 +	free(wstr);
   3.192 +}
   3.193 +
   3.194 +RAZOR_EXPORT struct razor_atomic *
   3.195 +razor_atomic_open(const char *description)
   3.196 +{
   3.197 +	wchar_t *buf;
   3.198 +	struct razor_atomic *atomic;
   3.199 +
   3.200 +	atomic = zalloc(sizeof *atomic);
   3.201 +	buf = razor_utf8_to_utf16(description, -1);
   3.202 +	atomic->transaction = CreateTransaction(NULL, 0,
   3.203 +						TRANSACTION_DO_NOT_PROMOTE,
   3.204 +						0, 0, 0, buf);
   3.205 +	free(buf);
   3.206 +
   3.207 +	return atomic;
   3.208 +}
   3.209 +
   3.210 +static void
   3.211 +razor_atomic_set_error_str(struct razor_atomic *atomic, const wchar_t *path,
   3.212 +			   const char *str)
   3.213 +{
   3.214 +	assert(!atomic->error_str);
   3.215 +
   3.216 +	free(atomic->error_path);
   3.217 +
   3.218 +	if (path)
   3.219 +		atomic->error_path = razor_utf16_to_utf8(path, -1);
   3.220 +	else
   3.221 +		atomic->error_path = NULL;
   3.222 +
   3.223 +	atomic->error_str = strdup(str);
   3.224 +}
   3.225 +
   3.226 +static void
   3.227 +razor_atomic_set_error(struct razor_atomic *atomic, const wchar_t *path,
   3.228 +		       DWORD error)
   3.229 +{
   3.230 +	wchar_t *buf;
   3.231 +
   3.232 +	assert(!atomic->error_str);
   3.233 +
   3.234 +	free(atomic->error_path);
   3.235 +
   3.236 +	if (path)
   3.237 +		atomic->error_path = razor_utf16_to_utf8(path, -1);
   3.238 +	else
   3.239 +		atomic->error_path = NULL;
   3.240 +
   3.241 +	FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER|
   3.242 +		       FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS,
   3.243 +		       NULL, error, MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT),
   3.244 +		       (LPWSTR)&buf, 0, NULL);
   3.245 +	atomic->error_str = razor_utf16_to_utf8(buf, -1);
   3.246 +	LocalFree(buf);
   3.247 +}
   3.248 +
   3.249 +RAZOR_EXPORT int
   3.250 +razor_atomic_commit(struct razor_atomic *atomic)
   3.251 +{
   3.252 +	int retval;
   3.253 +
   3.254 +	if (atomic->error_str)
   3.255 +		return -1;
   3.256 +
   3.257 +	retval = !CommitTransaction(atomic->transaction);
   3.258 +
   3.259 +	if (retval) {
   3.260 +		razor_atomic_set_error(atomic, NULL, GetLastError());
   3.261 +		RollbackTransaction(atomic->transaction);
   3.262 +	}
   3.263 +
   3.264 +	CloseHandle(atomic->transaction);
   3.265 +	atomic->transaction = INVALID_HANDLE_VALUE;
   3.266 +
   3.267 +	return retval;
   3.268 +}
   3.269 +
   3.270 +RAZOR_EXPORT void
   3.271 +razor_atomic_destroy(struct razor_atomic *atomic)
   3.272 +{
   3.273 +	int i;
   3.274 +
   3.275 +	for(i = 0; i < atomic->n_files; i++) {
   3.276 +		if (atomic->files[i].h != INVALID_HANDLE_VALUE) {
   3.277 +			CloseHandle(atomic->files[i].h);
   3.278 +			free(atomic->files[i].path);
   3.279 +		}
   3.280 +	}
   3.281 +	free(atomic->files);
   3.282 +	if (atomic->transaction != INVALID_HANDLE_VALUE) {
   3.283 +		RollbackTransaction(atomic->transaction);
   3.284 +		CloseHandle(atomic->transaction);
   3.285 +	}
   3.286 +	free(atomic->error_path);
   3.287 +	free(atomic->error_str);
   3.288 +	free(atomic->error_msg);
   3.289 +	free(atomic);
   3.290 +}
   3.291 +
   3.292 +RAZOR_EXPORT int
   3.293 +razor_atomic_make_dirs(struct razor_atomic *atomic, const char *root,
   3.294 +		       const char *path)
   3.295 +{
   3.296 +	struct razor_wstr *buffer;
   3.297 +	const char *slash, *s, *next;
   3.298 +	WIN32_FILE_ATTRIBUTE_DATA fa;
   3.299 +	DWORD err;
   3.300 +	int r, creating = 0;
   3.301 +
   3.302 +	if (atomic->error_str)
   3.303 +		return -1;
   3.304 +
   3.305 +	buffer = razor_wstr_create(root, -1);
   3.306 +	slash = path;
   3.307 +
   3.308 +	for (; *slash != '\0'; slash = next) {
   3.309 +		next = strpbrk(slash + 1, "/\\");
   3.310 +		if (next == NULL)
   3.311 +			break;
   3.312 +
   3.313 +		razor_wstr_append(buffer, slash, next - slash);
   3.314 +
   3.315 +		if (!creating) {
   3.316 +			if (razor_valid_root_name(buffer->str))
   3.317 +				continue;
   3.318 +
   3.319 +			r = GetFileAttributesTransactedW(buffer->str,
   3.320 +							 GetFileExInfoStandard,
   3.321 +							 &fa,
   3.322 +							 atomic->transaction);
   3.323 +
   3.324 +			if (!r) {
   3.325 +				err = GetLastError();
   3.326 +				if (err == ERROR_FILE_NOT_FOUND) {
   3.327 +					creating = 1;
   3.328 +				} else {
   3.329 +					razor_atomic_set_error(atomic,
   3.330 +							       buffer->str,
   3.331 +							       err);
   3.332 +					razor_wstr_destroy(buffer);
   3.333 +					return -1;
   3.334 +				}
   3.335 +			} else if (!(fa.dwFileAttributes&
   3.336 +				     FILE_ATTRIBUTE_DIRECTORY)) {
   3.337 +				razor_atomic_set_error_str(atomic, buffer->str,
   3.338 +							   "Not a directory");
   3.339 +				razor_wstr_destroy(buffer);
   3.340 +				return -1;
   3.341 +			}
   3.342 +		}
   3.343 +		if (creating) {
   3.344 +			if (!CreateDirectoryTransactedW(NULL, buffer->str, NULL,
   3.345 +							atomic->transaction)) {
   3.346 +				razor_atomic_set_error(atomic, buffer->str,
   3.347 +						       GetLastError());
   3.348 +				razor_wstr_destroy(buffer);
   3.349 +				return -1;
   3.350 +			}
   3.351 +
   3.352 +			/* FIXME: What to do about permissions for dirs we
   3.353 +			 * have to create but are not in the cpio archive? */
   3.354 +		}
   3.355 +	}
   3.356 +
   3.357 +	razor_wstr_destroy(buffer);
   3.358 +
   3.359 +	return 0;
   3.360 +}
   3.361 +
   3.362 +RAZOR_EXPORT int
   3.363 +razor_atomic_remove(struct razor_atomic *atomic, const char *path)
   3.364 +{
   3.365 +	wchar_t *buf;
   3.366 +	DWORD err;
   3.367 +
   3.368 +	if (atomic->error_str)
   3.369 +		return -1;
   3.370 +
   3.371 +	buf = razor_utf8_to_utf16(path, -1);
   3.372 +
   3.373 +	if (DeleteFileTransactedW(buf, atomic->transaction)) {
   3.374 +		free(buf);
   3.375 +		return 0;
   3.376 +	}
   3.377 +
   3.378 +	err = GetLastError();
   3.379 +	if (err == ERROR_FILE_NOT_FOUND || err == ERROR_PATH_NOT_FOUND) {
   3.380 +		free(buf);
   3.381 +		return 0;
   3.382 +	}
   3.383 +
   3.384 +	if (SetFileAttributesTransactedW(buf, FILE_ATTRIBUTE_NORMAL,
   3.385 +					 atomic->transaction)) {
   3.386 +		if (DeleteFileTransactedW(buf, atomic->transaction)) {
   3.387 +			free(buf);
   3.388 +			return 0;
   3.389 +		}
   3.390 +		err = GetLastError();
   3.391 +	}
   3.392 +
   3.393 +	if (RemoveDirectoryTransactedW(buf, atomic->transaction) ||
   3.394 +	    GetLastError() == ERROR_DIR_NOT_EMPTY) {
   3.395 +		free(buf);
   3.396 +		return 0;
   3.397 +	}
   3.398 +
   3.399 +	/*
   3.400 +	 * It would be tempting to use:
   3.401 +	 * 	MoveFileEx(path, NULL, MOVEFILE_DELAY_UNTIL_REBOOT)
   3.402 +	 * but unless we can guarantee that the system will be rebooted
   3.403 +	 * before we (or some other application) write another file with the
   3.404 +	 * same path, this is likely to cause more problems than it solves.
   3.405 +	 */
   3.406 +
   3.407 +	razor_atomic_set_error(atomic, buf, err);
   3.408 +	free(buf);
   3.409 +	return -1;
   3.410 +}
   3.411 +
   3.412 +RAZOR_EXPORT int
   3.413 +razor_atomic_rename_file(struct razor_atomic *atomic, const char *oldpath,
   3.414 +			 const char *newpath)
   3.415 +{
   3.416 +	wchar_t *oldbuf, *newbuf;
   3.417 +	const DWORD flags = MOVEFILE_COPY_ALLOWED | MOVEFILE_REPLACE_EXISTING;
   3.418 +
   3.419 +	if (atomic->error_str)
   3.420 +		return -1;
   3.421 +
   3.422 +	newbuf = razor_utf8_to_utf16(newpath, -1);
   3.423 +	oldbuf = razor_utf8_to_utf16(oldpath, -1);
   3.424 +
   3.425 +	/*
   3.426 +	 * Passing MOVEFILE_REPLACE_EXISTING to MoveFileTransaction() will
   3.427 +	 * cover every case we care about _except_ replacing an empty
   3.428 +	 * directory with a file. Calling RemoveDirectoryTransacted() will deal
   3.429 +	 * with this case while having no effect in all other cases.
   3.430 +	 */
   3.431 +	(void)RemoveDirectoryTransactedW(newbuf, atomic->transaction);
   3.432 +
   3.433 +	if (!MoveFileTransactedW(oldbuf, newbuf, NULL, NULL, flags,
   3.434 +			         atomic->transaction))
   3.435 +		razor_atomic_set_error(atomic, newbuf, GetLastError());
   3.436 +
   3.437 +	free(newbuf);
   3.438 +	free(oldbuf);
   3.439 +
   3.440 +	return !!atomic->error_str;
   3.441 +}
   3.442 +
   3.443 +RAZOR_EXPORT int
   3.444 +razor_atomic_create_dir(struct razor_atomic *atomic, const char *dirname,
   3.445 +			mode_t mode)
   3.446 +{
   3.447 +	wchar_t *buf;
   3.448 +	DWORD err;
   3.449 +	WIN32_FILE_ATTRIBUTE_DATA fa;
   3.450 +
   3.451 +	if (atomic->error_str)
   3.452 +		return -1;
   3.453 +
   3.454 +	buf = razor_utf8_to_utf16(dirname, -1);
   3.455 +
   3.456 +	if (!CreateDirectoryTransactedW(NULL, buf, NULL, atomic->transaction)) {
   3.457 +		err = GetLastError();
   3.458 +		if (err != ERROR_FILE_EXISTS && err != ERROR_ALREADY_EXISTS) {
   3.459 +abort:
   3.460 +			razor_atomic_set_error(atomic, buf, err);
   3.461 +			free(buf);
   3.462 +			return -1;
   3.463 +		}
   3.464 +
   3.465 +		if (!GetFileAttributesTransactedW(buf, GetFileExInfoStandard,
   3.466 +						  &fa, atomic->transaction))
   3.467 +			goto abort;
   3.468 +
   3.469 +		if (!(fa.dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY)) {
   3.470 +			if (razor_atomic_remove(atomic, dirname)) {
   3.471 +				free(buf);
   3.472 +				return -1;
   3.473 +			}
   3.474 +			if (!CreateDirectoryTransactedW(NULL, buf, NULL,
   3.475 +							atomic->transaction)) {
   3.476 +				err = GetLastError();
   3.477 +				goto abort;
   3.478 +			}
   3.479 +		}
   3.480 +	}
   3.481 +
   3.482 +	free(buf);
   3.483 +
   3.484 +	return 0;
   3.485 +}
   3.486 +
   3.487 +RAZOR_EXPORT int
   3.488 +razor_atomic_create_symlink(struct razor_atomic *atomic, const char *target,
   3.489 +			    const char *path)
   3.490 +{
   3.491 +	if (atomic->error_str)
   3.492 +		return -1;
   3.493 +
   3.494 +	/*
   3.495 +	 * This isn't true, but symbolic links under Windows 7
   3.496 +	 * need to know whether the target is a directory or not
   3.497 +	 * and we don't always know that at the time when the
   3.498 +	 * link is created, so it's a convienent lie for now.
   3.499 +	 */
   3.500 +	razor_atomic_set_error_str(atomic, NULL, "Symbolic links not supported "
   3.501 +						 "on this platform");
   3.502 +
   3.503 +	return -1;
   3.504 +}
   3.505 +
   3.506 +RAZOR_EXPORT int
   3.507 +razor_atomic_create_file(struct razor_atomic *atomic, const char *filename,
   3.508 +			 mode_t mode)
   3.509 +{
   3.510 +	DWORD attribs;
   3.511 +	struct razor_atomic_file *files;
   3.512 +	int i = atomic->n_files;
   3.513 +
   3.514 +	if (atomic->error_str)
   3.515 +		return -1;
   3.516 +
   3.517 +	files = realloc(atomic->files,
   3.518 +			(atomic->n_files+1) * sizeof(struct razor_atomic_file));
   3.519 +	if (!files) {
   3.520 +		razor_atomic_set_error_str(atomic, NULL, "Not enough memory");
   3.521 +		return -1;
   3.522 +	}
   3.523 +	atomic->n_files++;
   3.524 +	atomic->files = files;
   3.525 +
   3.526 +	files[i].path = razor_utf8_to_utf16(filename, -1);
   3.527 +
   3.528 +	/*
   3.529 +	 * Passing CREATE_ALWAYS to CreateFileTransacted() will cover
   3.530 +	 * every case we care about _except_ replacing an empty directory
   3.531 +	 * with a file. Calling RemoveDirectoryTransacted() will deal
   3.532 +	 * with this case while having no effect in all other cases.
   3.533 +	 */
   3.534 +	(void)RemoveDirectoryTransactedW(files[i].path, atomic->transaction);
   3.535 +
   3.536 +	if (mode & S_IWUSR)
   3.537 +		attribs = FILE_ATTRIBUTE_NORMAL;
   3.538 +	else
   3.539 +		attribs = FILE_ATTRIBUTE_READONLY;
   3.540 +
   3.541 +	files[i].h = CreateFileTransactedW(files[i].path, GENERIC_WRITE,
   3.542 +					   0, NULL, CREATE_ALWAYS, attribs,
   3.543 +					   NULL, atomic->transaction, NULL,
   3.544 +					   NULL);
   3.545 +
   3.546 +	if (files[i].h == INVALID_HANDLE_VALUE) {
   3.547 +		razor_atomic_set_error(atomic, files[i].path, GetLastError());
   3.548 +		free(files[i].path);
   3.549 +		atomic->n_files--;
   3.550 +		return -1;
   3.551 +	}
   3.552 +
   3.553 +	return i;
   3.554 +}
   3.555 +
   3.556 +RAZOR_EXPORT int
   3.557 +razor_atomic_write(struct razor_atomic *atomic, int handle, const void *data,
   3.558 +		   size_t size)
   3.559 +{
   3.560 +	DWORD written;
   3.561 +
   3.562 +	if (atomic->error_str)
   3.563 +		return -1;
   3.564 +
   3.565 +	assert(handle < atomic->n_files);
   3.566 +	assert(atomic->files[handle].h != INVALID_HANDLE_VALUE);
   3.567 +
   3.568 +	while(size) {
   3.569 +		if (!WriteFile(atomic->files[handle].h, data, size, &written,
   3.570 +			       NULL)) {
   3.571 +			razor_atomic_set_error(atomic,
   3.572 +					       atomic->files[handle].path,
   3.573 +					       GetLastError());
   3.574 +
   3.575 +			(void)CloseHandle(atomic->files[handle].h);
   3.576 +			free(atomic->files[handle].path);
   3.577 +			atomic->files[handle].path = NULL;
   3.578 +			atomic->files[handle].h = INVALID_HANDLE_VALUE;
   3.579 +
   3.580 +			return -1;
   3.581 +		}
   3.582 +
   3.583 +		data += written;
   3.584 +		size -= written;
   3.585 +	}
   3.586 +
   3.587 +	return 0;
   3.588 +}
   3.589 +
   3.590 +RAZOR_EXPORT int
   3.591 +razor_atomic_sync(struct razor_atomic *atomic, int handle)
   3.592 +{
   3.593 +	HANDLE h;
   3.594 +
   3.595 +	if (atomic->error_str)
   3.596 +		return -1;
   3.597 +
   3.598 +	assert(handle < atomic->n_files);
   3.599 +	assert(atomic->files[handle].h != INVALID_HANDLE_VALUE);
   3.600 +
   3.601 +	if (!CloseHandle(atomic->files[handle].h)) {
   3.602 +		razor_atomic_set_error(atomic, atomic->files[handle].path,
   3.603 +				       GetLastError());
   3.604 +		free(atomic->files[handle].path);
   3.605 +		atomic->files[handle].path = NULL;
   3.606 +		atomic->files[handle].h = INVALID_HANDLE_VALUE;
   3.607 +		return -1;
   3.608 +	}
   3.609 +
   3.610 +	h = CreateFileTransactedW(atomic->files[handle].path, GENERIC_WRITE, 0,
   3.611 +				  NULL, OPEN_EXISTING, 0, NULL,
   3.612 +				  atomic->transaction, NULL, NULL);
   3.613 +	atomic->files[handle].h = h;
   3.614 +
   3.615 +	if (atomic->files[handle].h == INVALID_HANDLE_VALUE) {
   3.616 +		razor_atomic_set_error(atomic, atomic->files[handle].path,
   3.617 +				       GetLastError());
   3.618 +		free(atomic->files[handle].path);
   3.619 +		atomic->files[handle].path = NULL;
   3.620 +		return -1;
   3.621 +	}
   3.622 +
   3.623 +	return !!atomic->error_str;
   3.624 +}
   3.625 +
   3.626 +RAZOR_EXPORT int
   3.627 +razor_atomic_close(struct razor_atomic *atomic, int handle)
   3.628 +{
   3.629 +	if (atomic->error_str)
   3.630 +		return -1;
   3.631 +
   3.632 +	assert(handle < atomic->n_files);
   3.633 +	assert(atomic->files[handle].h != INVALID_HANDLE_VALUE);
   3.634 +
   3.635 +	if (!CloseHandle(atomic->files[handle].h))
   3.636 +		razor_atomic_set_error(atomic, atomic->files[handle].path,
   3.637 +				       GetLastError());
   3.638 +
   3.639 +	free(atomic->files[handle].path);
   3.640 +	atomic->files[handle].path = NULL;
   3.641 +	atomic->files[handle].h = INVALID_HANDLE_VALUE;
   3.642 +
   3.643 +	while(atomic->n_files > 0 &&
   3.644 +	      atomic->files[atomic->n_files-1].h == INVALID_HANDLE_VALUE)
   3.645 +		atomic->n_files--;
   3.646 +
   3.647 +	return !!atomic->error_str;
   3.648 +}
   3.649 +
   3.650 +#else		/* HAVE_WINDOWS_KVM */
   3.651 +
   3.652 +static int
   3.653 +razor_valid_root_name(const char *name)
   3.654 +{
   3.655 +	if (allow_all_root_names) {
   3.656 +#ifdef MSWIN_API
   3.657 +		return !strpbrk(name, "/\\");
   3.658 +#else
   3.659 +		return !strchr(name, '/');
   3.660 +#endif
   3.661 +	}
   3.662 +
   3.663 +#ifdef MSWIN_API
   3.664 +	return RAZOR_ASCII_ISALPHA(name[0]) && name[1] == ':' &&
   3.665 +	       name[2] == '\0';
   3.666 +#else
   3.667 +	return name[0] == '\0';
   3.668 +#endif
   3.669 +}
   3.670 +
   3.671 +struct razor_atomic {
   3.672 +	char *error_path;
   3.673 +	char *error_str;
   3.674 +	char *error_msg;
   3.675 +};
   3.676 +
   3.677 +RAZOR_EXPORT struct razor_atomic *
   3.678 +razor_atomic_open(const char *description)
   3.679 +{
   3.680 +	struct razor_atomic *atomic;
   3.681 +
   3.682 +	atomic = zalloc(sizeof *atomic);
   3.683 +
   3.684 +	return atomic;
   3.685 +}
   3.686 +
   3.687 +static void
   3.688 +razor_atomic_set_error_str(struct razor_atomic *atomic, const char *path,
   3.689 +			   const char *str)
   3.690 +{
   3.691 +	assert(!atomic->error_str);
   3.692 +
   3.693 +	atomic->error_path = path ? strdup(path) : NULL;
   3.694 +	atomic->error_str = strdup(str);
   3.695 +}
   3.696 +
   3.697 +#ifdef MSWIN_API
   3.698 +static void
   3.699 +razor_atomic_set_error_mswin(struct razor_atomic *atomic, const wchar_t *path,
   3.700 +		       DWORD error)
   3.701 +{
   3.702 +	wchar_t *buf;
   3.703 +
   3.704 +	assert(!atomic->error_str);
   3.705 +
   3.706 +	free(atomic->error_path);
   3.707 +
   3.708 +	if (path)
   3.709 +		atomic->error_path = razor_utf16_to_utf8(path, -1);
   3.710 +	else
   3.711 +		atomic->error_path = NULL;
   3.712 +
   3.713 +	FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER|
   3.714 +		       FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS,
   3.715 +		       NULL, error, MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT),
   3.716 +		       (LPWSTR)&buf, 0, NULL);
   3.717 +	atomic->error_str = razor_utf16_to_utf8(buf, -1);
   3.718 +	LocalFree(buf);
   3.719 +}
   3.720 +#endif
   3.721 +
   3.722 +RAZOR_EXPORT int
   3.723 +razor_atomic_commit(struct razor_atomic *atomic)
   3.724 +{
   3.725 +	return !!atomic->error_str;
   3.726 +}
   3.727 +
   3.728 +RAZOR_EXPORT void
   3.729 +razor_atomic_destroy(struct razor_atomic *atomic)
   3.730 +{
   3.731 +	free(atomic->error_path);
   3.732 +	free(atomic->error_str);
   3.733 +	free(atomic->error_msg);
   3.734 +	free(atomic);
   3.735 +}
   3.736 +
   3.737 +RAZOR_EXPORT int
   3.738 +razor_atomic_make_dirs(struct razor_atomic *atomic, const char *root,
   3.739 +		       const char *path)
   3.740 +{
   3.741 +	char buffer[PATH_MAX], *p;
   3.742 +	const char *slash, *next;
   3.743 +	struct stat buf;
   3.744 +
   3.745 +	if (atomic->error_str)
   3.746 +		return -1;
   3.747 +
   3.748 +	strcpy(buffer, root);
   3.749 +	p = buffer + strlen(buffer);
   3.750 +	slash = path;
   3.751 +	for (slash = path; *slash != '\0'; slash = next) {
   3.752 +#ifdef MSWIN_API
   3.753 +		next = strpbrk(slash + 1, "/\\");
   3.754 +#else
   3.755 +		next = strchr(slash + 1, '/');
   3.756 +#endif
   3.757 +		if (next == NULL)
   3.758 +			break;
   3.759 +
   3.760 +		memcpy(p, slash, next - slash);
   3.761 +		p += next - slash;
   3.762 +		*p = '\0';
   3.763 +
   3.764 +		if (razor_valid_root_name(buffer))
   3.765 +			continue;
   3.766 +
   3.767 +		if (stat(buffer, &buf) == 0) {
   3.768 +			if (!S_ISDIR(buf.st_mode)) {
   3.769 +				razor_atomic_set_error_str(atomic, buffer,
   3.770 +							   "Not a directory");
   3.771 +				return -1;
   3.772 +			}
   3.773 +		} else if (mkdir(buffer, 0777) < 0) {
   3.774 +			razor_atomic_set_error_str(atomic, buffer,
   3.775 +						   strerror(errno));
   3.776 +			return -1;
   3.777 +		}
   3.778 +	}
   3.779 +
   3.780 +	return 0;
   3.781 +}
   3.782 +
   3.783 +RAZOR_EXPORT int
   3.784 +razor_atomic_remove(struct razor_atomic *atomic, const char *path)
   3.785 +{
   3.786 +#ifdef MSWIN_API
   3.787 +	wchar_t *buf;
   3.788 +	DWORD err;
   3.789 +#endif
   3.790 +
   3.791 +	if (atomic->error_str)
   3.792 +		return -1;
   3.793 +
   3.794 +#ifdef MSWIN_API
   3.795 +	buf = razor_utf8_to_utf16(path, -1);
   3.796 +
   3.797 +	if (!DeleteFileW(buf)) {
   3.798 +		err = GetLastError();
   3.799 +		if (err != ERROR_FILE_NOT_FOUND &&
   3.800 +		    err != ERROR_PATH_NOT_FOUND &&
   3.801 +		    !(SetFileAttributesW(buf, FILE_ATTRIBUTE_NORMAL) &&
   3.802 +		      DeleteFileW(buf)) &&
   3.803 +		    !RemoveDirectoryW(buf) &&
   3.804 +		    GetLastError() != ERROR_DIR_NOT_EMPTY)
   3.805 +			razor_atomic_set_error_mswin(atomic, buf, err);
   3.806 +	}
   3.807 +
   3.808 +	free(buf);
   3.809 +#else
   3.810 +	if (remove(path))
   3.811 +		razor_atomic_set_error_str(atomic, path, strerror(errno));
   3.812 +#endif
   3.813 +
   3.814 +	return !!atomic->error_str;
   3.815 +}
   3.816 +
   3.817 +RAZOR_EXPORT int
   3.818 +razor_atomic_rename_file(struct razor_atomic *atomic, const char *oldpath,
   3.819 +			 const char *newpath)
   3.820 +{
   3.821 +#ifdef MSWIN_API
   3.822 +	wchar_t *oldbuf, *newbuf;
   3.823 +	const DWORD flags = MOVEFILE_COPY_ALLOWED | MOVEFILE_REPLACE_EXISTING;
   3.824 +#endif
   3.825 +
   3.826 +	if (atomic->error_str)
   3.827 +		return -1;
   3.828 +
   3.829 +#ifdef MSWIN_API
   3.830 +	newbuf = razor_utf8_to_utf16(newpath, -1);
   3.831 +	oldbuf = razor_utf8_to_utf16(oldpath, -1);
   3.832 +
   3.833 +	/*
   3.834 +	 * Passing MOVEFILE_REPLACE_EXISTING to MoveFileEx() will
   3.835 +	 * cover every case we care about _except_ replacing an empty
   3.836 +	 * directory with a file. Calling RemoveDirectory() will deal
   3.837 +	 * with this case while having no effect in all other cases.
   3.838 +	 */
   3.839 +	(void)RemoveDirectoryW(newbuf);
   3.840 +
   3.841 +	if (!MoveFileExW(oldbuf, newbuf, flags))
   3.842 +		razor_atomic_set_error_mswin(atomic, newbuf, GetLastError());
   3.843 +
   3.844 +	free(newbuf);
   3.845 +	free(oldbuf);
   3.846 +#else
   3.847 +	if (rename(oldpath, newpath))
   3.848 +		razor_atomic_set_error_str(atomic, newpath, strerror(errno));
   3.849 +#endif
   3.850 +
   3.851 +	return !!atomic->error_str;
   3.852 +}
   3.853 +
   3.854 +RAZOR_EXPORT int
   3.855 +razor_atomic_create_dir(struct razor_atomic *atomic, const char *dirname,
   3.856 +			mode_t mode)
   3.857 +{
   3.858 +	if (atomic->error_str)
   3.859 +		return -1;
   3.860 +
   3.861 +	if (!mkdir(dirname, mode & (S_IRWXU | S_IRWXG | S_IRWXO)))
   3.862 +		return 0;
   3.863 +
   3.864 +	if (errno != EEXIST) {
   3.865 +		razor_atomic_set_error_str(atomic, dirname, strerror(errno));
   3.866 +		return -1;
   3.867 +	}
   3.868 +
   3.869 +	if (chmod(dirname, mode & (S_IRWXU | S_IRWXG | S_IRWXO)) < 0) {
   3.870 +		razor_atomic_set_error_str(atomic, dirname, strerror(errno));
   3.871 +		return -1;
   3.872 +	}
   3.873 +
   3.874 +	return 0;
   3.875 +}
   3.876 +
   3.877 +RAZOR_EXPORT int
   3.878 +razor_atomic_create_symlink(struct razor_atomic *atomic, const char *target,
   3.879 +			    const char *path)
   3.880 +{
   3.881 +	if (atomic->error_str)
   3.882 +		return -1;
   3.883 +
   3.884 +#if HAVE_SYMLINK
   3.885 +	if (symlink(target, path) < 0) {
   3.886 +		razor_atomic_set_error_str(atomic, NULL, strerror(errno));
   3.887 +		return -1;
   3.888 +	}
   3.889 +#else
   3.890 +	razor_atomic_set_error_str(atomic, NULL, "Symbolic links not supported "
   3.891 +						 "on this platform");
   3.892 +#endif
   3.893 +
   3.894 +	return 0;
   3.895 +}
   3.896 +
   3.897 +RAZOR_EXPORT int
   3.898 +razor_atomic_create_file(struct razor_atomic *atomic, const char *filename,
   3.899 +			 mode_t mode)
   3.900 +{
   3.901 +	int fd;
   3.902 +
   3.903 +	if (atomic->error_str)
   3.904 +		return -1;
   3.905 +
   3.906 +	atomic->error_path = strdup(filename);
   3.907 +	fd = open(atomic->error_path, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
   3.908 +		  mode & (S_IRWXU | S_IRWXG | S_IRWXO));
   3.909 +
   3.910 +	if (fd == -1)
   3.911 +		razor_atomic_set_error_str(atomic, NULL, strerror(errno));
   3.912 +
   3.913 +	return fd;
   3.914 +}
   3.915 +
   3.916 +RAZOR_EXPORT int
   3.917 +razor_atomic_write(struct razor_atomic *atomic, int fd, const void *data,
   3.918 +		   size_t size)
   3.919 +{
   3.920 +	int written;
   3.921 +
   3.922 +	if (atomic->error_str)
   3.923 +		return -1;
   3.924 +
   3.925 +	while(size) {
   3.926 +		written = write(fd, data, size);
   3.927 +		if (written < 0) {
   3.928 +			razor_atomic_set_error_str(atomic, NULL, strerror(errno));
   3.929 +
   3.930 +			(void)close(fd);
   3.931 +
   3.932 +			return -1;
   3.933 +		}
   3.934 +
   3.935 +		data += written;
   3.936 +		size -= written;
   3.937 +	}
   3.938 +
   3.939 +	return 0;
   3.940 +}
   3.941 +
   3.942 +RAZOR_EXPORT int
   3.943 +razor_atomic_sync(struct razor_atomic *atomic, int handle)
   3.944 +{
   3.945 +	if (atomic->error_str)
   3.946 +		return -1;
   3.947 +
   3.948 +	if (fsync(handle) < 0) {
   3.949 +		razor_atomic_set_error_str(atomic, NULL, strerror(errno));
   3.950 +		return -1;
   3.951 +	}
   3.952 +
   3.953 +	free(atomic->error_path);
   3.954 +	atomic->error_path = NULL;
   3.955 +
   3.956 +	return 0;
   3.957 +}
   3.958 +
   3.959 +RAZOR_EXPORT int
   3.960 +razor_atomic_close(struct razor_atomic *atomic, int fd)
   3.961 +{
   3.962 +	if (atomic->error_str)
   3.963 +		return -1;
   3.964 +
   3.965 +	if (close(fd) < 0) {
   3.966 +		razor_atomic_set_error_str(atomic, NULL, strerror(errno));
   3.967 +		return -1;
   3.968 +	}
   3.969 +
   3.970 +	free(atomic->error_path);
   3.971 +	atomic->error_path = NULL;
   3.972 +
   3.973 +	return 0;
   3.974 +}
   3.975 +
   3.976 +#endif		/* HAVE_WINDOWS_KVM */
   3.977 +
   3.978 +RAZOR_EXPORT const char *
   3.979 +razor_atomic_get_error_msg(struct razor_atomic *atomic)
   3.980 +{
   3.981 +	if (!atomic->error_msg) {
   3.982 +		if (atomic->error_path)
   3.983 +			atomic->error_msg = razor_concat(atomic->error_path,
   3.984 +							 ": ",
   3.985 +							 atomic->error_str,
   3.986 +							 NULL);
   3.987 +		else
   3.988 +			atomic->error_msg = strdup(atomic->error_str);
   3.989 +	}
   3.990 +
   3.991 +	return atomic->error_msg;
   3.992 +}
   3.993 +
   3.994 +RAZOR_EXPORT void
   3.995 +razor_atomic_abort(struct razor_atomic *atomic, const char *error_msg)
   3.996 +{
   3.997 +	if (!atomic->error_str)
   3.998 +		razor_atomic_set_error_str(atomic, NULL, error_msg);
   3.999 +}
  3.1000 +
  3.1001 +RAZOR_EXPORT int
  3.1002 +razor_atomic_in_error_state(struct razor_atomic *atomic)
  3.1003 +{
  3.1004 +	return !!atomic->error_str;
  3.1005 +}
     4.1 --- a/librazor/merger.c	Thu Aug 25 14:22:52 2011 +0100
     4.2 +++ b/librazor/merger.c	Thu Nov 10 10:35:21 2011 +0000
     4.3 @@ -1,7 +1,7 @@
     4.4  /*
     4.5   * Copyright (C) 2008  Kristian Høgsberg <krh@redhat.com>
     4.6   * Copyright (C) 2008  Red Hat, Inc
     4.7 - * Copyright (C) 2009, 2010  J. Ali Harlow <ali@juiblex.co.uk>
     4.8 + * Copyright (C) 2009-2011  J. Ali Harlow <ali@juiblex.co.uk>
     4.9   *
    4.10   * This program is free software; you can redistribute it and/or modify
    4.11   * it under the terms of the GNU General Public License as published by
    4.12 @@ -47,9 +47,18 @@
    4.13  	struct razor_merger *merger;
    4.14  	int count;
    4.15  	size_t size;
    4.16 +	uint32_t header_version;
    4.17  
    4.18  	merger = zalloc(sizeof *merger);
    4.19  	merger->set = razor_set_create();
    4.20 +	if (set1->packages.size) {
    4.21 +		header_version = razor_set_get_header_version(set1);
    4.22 +		if (set2->packages.size &&
    4.23 +		    razor_set_get_header_version(set2) > header_version)
    4.24 +			header_version = razor_set_get_header_version(set2);
    4.25 +	} else
    4.26 +		header_version = razor_set_get_header_version(set2);
    4.27 +	razor_set_set_header_version(merger->set, header_version);
    4.28  	hashtable_init(&merger->table, &merger->set->string_pool);
    4.29  	hashtable_init(&merger->file_table, &merger->set->file_string_pool);
    4.30  	hashtable_init(&merger->details_table,
    4.31 @@ -592,16 +601,24 @@
    4.32  
    4.33  	switch (script) {
    4.34  	case RAZOR_PROPERTY_PREUN:
    4.35 -		assert(pool[package->preun.program] == '\0');
    4.36 -		assert(pool[package->preun.body] == '\0');
    4.37 -		package->preun.program = p;
    4.38 -		package->preun.body = b;
    4.39 +		if (package->preun.program != p) {
    4.40 +			assert(pool[package->preun.program] == '\0');
    4.41 +			package->preun.program = p;
    4.42 +		}
    4.43 +		if (package->preun.body != b) {
    4.44 +			assert(pool[package->preun.body] == '\0');
    4.45 +			package->preun.body = b;
    4.46 +		}
    4.47  		break;
    4.48  	case RAZOR_PROPERTY_POSTUN:
    4.49 -		assert(pool[package->postun.program] == '\0');
    4.50 -		assert(pool[package->postun.body] == '\0');
    4.51 -		package->postun.program = p;
    4.52 -		package->postun.body = b;
    4.53 +		if (package->postun.program != p) {
    4.54 +			assert(pool[package->postun.program] == '\0');
    4.55 +			package->postun.program = p;
    4.56 +		}
    4.57 +		if (package->postun.body != b) {
    4.58 +			assert(pool[package->postun.body] == '\0');
    4.59 +			package->postun.body = b;
    4.60 +		}
    4.61  		break;
    4.62  	default:
    4.63  		break;
     5.1 --- a/librazor/razor-internal.h	Thu Aug 25 14:22:52 2011 +0100
     5.2 +++ b/librazor/razor-internal.h	Thu Nov 10 10:35:21 2011 +0000
     5.3 @@ -1,7 +1,7 @@
     5.4  /*
     5.5   * Copyright (C) 2008  Kristian Høgsberg <krh@redhat.com>
     5.6   * Copyright (C) 2008  Red Hat, Inc
     5.7 - * Copyright (C) 2009  J. Ali Harlow <ali@juiblex.co.uk>
     5.8 + * Copyright (C) 2009, 2011  J. Ali Harlow <ali@juiblex.co.uk>
     5.9   *
    5.10   * This program is free software; you can redistribute it and/or modify
    5.11   * it under the terms of the GNU General Public License as published by
    5.12 @@ -29,7 +29,7 @@
    5.13  #include "razor.h"
    5.14  #include "types/types.h"
    5.15  
    5.16 -/* GCC visibility */
    5.17 +/* GCC extensions */
    5.18  #if defined(__GNUC__) && __GNUC__ >= 4
    5.19  #define RAZOR_EXPORT __attribute__ ((visibility("default")))
    5.20  #else
    5.21 @@ -54,7 +54,6 @@
    5.22  };
    5.23  
    5.24  #define RAZOR_MAGIC 	0x525a4442
    5.25 -#define RAZOR_VERSION	1
    5.26  
    5.27  #define RAZOR_STRING_POOL		"string_pool"
    5.28  #define RAZOR_PACKAGES			"packages"
    5.29 @@ -108,6 +107,7 @@
    5.30  #define RAZOR_ENTRY_LAST	0x80
    5.31  
    5.32  struct razor_set {
    5.33 +	uint32_t header_version;
    5.34  	struct array string_pool;
    5.35   	struct array packages;
    5.36   	struct array properties;
    5.37 @@ -119,7 +119,7 @@
    5.38  	struct array file_string_pool;
    5.39  	struct array details_string_pool;
    5.40  	struct razor_mapped_file *mapped_files;
    5.41 -	int lock_fd;
    5.42 +	int lock_fd, ref_count;
    5.43  };
    5.44  
    5.45  struct import_entry {
     6.1 --- a/librazor/razor.c	Thu Aug 25 14:22:52 2011 +0100
     6.2 +++ b/librazor/razor.c	Thu Nov 10 10:35:21 2011 +0000
     6.3 @@ -1,7 +1,7 @@
     6.4  /*
     6.5   * Copyright (C) 2008  Kristian Høgsberg <krh@redhat.com>
     6.6   * Copyright (C) 2008  Red Hat, Inc
     6.7 - * Copyright (C) 2009, 2010  J. Ali Harlow <ali@juiblex.co.uk>
     6.8 + * Copyright (C) 2009-2011  J. Ali Harlow <ali@juiblex.co.uk>
     6.9   *
    6.10   * This program is free software; you can redistribute it and/or modify
    6.11   * it under the terms of the GNU General Public License as published by
    6.12 @@ -93,10 +93,16 @@
    6.13  
    6.14  	set = zalloc(sizeof *set);
    6.15  
    6.16 -	empty = array_add(&set->string_pool, 1);
    6.17 -	*empty = '\0';
    6.18 +	if (set) {
    6.19 +		empty = array_add(&set->string_pool, 1);
    6.20 +		*empty = '\0';
    6.21  
    6.22 -	set->lock_fd = -1;
    6.23 +		set->lock_fd = -1;
    6.24 +
    6.25 +		set->ref_count = 1;
    6.26 +
    6.27 +		set->header_version = RAZOR_HEADER_VERSION;
    6.28 +	}
    6.29  
    6.30  	return set;
    6.31  }
    6.32 @@ -118,6 +124,24 @@
    6.33  	return set;
    6.34  }
    6.35  
    6.36 +RAZOR_EXPORT uint32_t
    6.37 +razor_set_get_header_version(struct razor_set *set)
    6.38 +{
    6.39 +	return set->header_version;
    6.40 +}
    6.41 +
    6.42 +RAZOR_EXPORT int
    6.43 +razor_set_set_header_version(struct razor_set *set, uint32_t header_version)
    6.44 +{
    6.45 +	if (header_version<RAZOR_HEADER_VERSION_MIN ||
    6.46 +	    header_version>RAZOR_HEADER_VERSION)
    6.47 +		return -1;
    6.48 +	else {
    6.49 +		set->header_version = header_version;
    6.50 +		return 0;
    6.51 +	}
    6.52 +}
    6.53 +
    6.54  struct razor_mapped_file {
    6.55  	struct razor_set_header *header;
    6.56  	size_t size;
    6.57 @@ -125,32 +149,52 @@
    6.58  };
    6.59  
    6.60  RAZOR_EXPORT int
    6.61 -razor_set_bind_sections(struct razor_set *set, const char *filename)
    6.62 +razor_set_bind_sections(struct razor_set *set, struct razor_atomic *atomic,
    6.63 +			const char *filename)
    6.64  {
    6.65  	struct razor_set_section *s, *sections;
    6.66  	struct razor_mapped_file *file;
    6.67 -	const char *pool;
    6.68 +	const char *pool, *reason;
    6.69 +	char *msg;
    6.70  	struct array *array;
    6.71  	int i, j;
    6.72  
    6.73  	file = zalloc(sizeof *file);
    6.74 -	if (file == NULL)
    6.75 +	if (file == NULL) {
    6.76 +		razor_atomic_abort(atomic, "Not enough memory");
    6.77  		return -1;
    6.78 +	}
    6.79  
    6.80  	file->header = razor_file_get_contents(filename, &file->size);
    6.81  	if (!file->header) {
    6.82 +		msg = razor_concat(filename, ": ", strerror(errno), NULL);
    6.83 +		razor_atomic_abort(atomic, msg);
    6.84 +		free(msg);
    6.85  		free(file);
    6.86  		return -1;
    6.87  	}
    6.88  
    6.89 -	if (file->size < sizeof *file->header ||
    6.90 -	    file->header->magic != RAZOR_MAGIC ||
    6.91 -	    file->header->version != RAZOR_VERSION) {
    6.92 +	if (file->size < sizeof *file->header)
    6.93 +		reason = "Premature EOF";
    6.94 +	else if (file->header->magic != RAZOR_MAGIC)
    6.95 +		reason = "Bad magic number";
    6.96 +	else if (file->header->version < RAZOR_HEADER_VERSION_MIN ||
    6.97 +		 file->header->version > RAZOR_HEADER_VERSION)
    6.98 +		reason = "Incompatible file version";
    6.99 +	else
   6.100 +		reason = NULL;
   6.101 +
   6.102 +	if (reason) {
   6.103 +		msg = razor_concat(filename, ": ", reason, NULL);
   6.104 +		razor_atomic_abort(atomic, msg);
   6.105 +		free(msg);
   6.106  		razor_file_free_contents(file->header, file->size);
   6.107  		free(file);
   6.108  		return -1;
   6.109  	}
   6.110  
   6.111 +	set->header_version = file->header->version;
   6.112 +
   6.113  	if (set->mapped_files == NULL) {
   6.114  		for (i = 0; i < ARRAY_SIZE(razor_sections); i++) {
   6.115  			array = (void *) set + razor_sections[i].offset;
   6.116 @@ -182,13 +226,18 @@
   6.117  }
   6.118  
   6.119  RAZOR_EXPORT struct razor_set *
   6.120 -razor_set_open(const char *filename)
   6.121 +razor_set_open(const char *filename, struct razor_atomic *atomic)
   6.122  {
   6.123  	struct razor_set *set;
   6.124  
   6.125  	set = zalloc(sizeof *set);
   6.126 +	if (!set) {
   6.127 +		razor_atomic_abort(atomic, "Not enough memory");
   6.128 +		return NULL;
   6.129 +	}
   6.130 +
   6.131  	set->lock_fd = -1;
   6.132 -	if (razor_set_bind_sections(set, filename)){
   6.133 +	if (razor_set_bind_sections(set, atomic, filename)) {
   6.134  		free(set);
   6.135  		return NULL;
   6.136  	}
   6.137 @@ -215,12 +264,14 @@
   6.138  
   6.139  	if (exclusive)
   6.140  		flags |= LOCKFILE_EXCLUSIVE_LOCK;
   6.141 -	if (fd >= 0 && !LockFileEx(_get_osfhandle(fd), flags, 0, 1, 0, &lock)) {
   6.142 +	if (fd >= 0 && !LockFileEx((HANDLE)_get_osfhandle(fd), flags, 0, 1, 0,
   6.143 +				   &lock)) {
   6.144  		close(fd);
   6.145  		return -1;
   6.146  	}
   6.147  	if (set->lock_fd >= 0)
   6.148 -		(void)UnlockFile(_get_osfhandle(set->lock_fd), 0, 0, 1, 0);
   6.149 +		(void)UnlockFile((HANDLE)_get_osfhandle(set->lock_fd), 0, 0, 1,
   6.150 +				 0);
   6.151  #else
   6.152  	struct flock lock = {0};
   6.153  
   6.154 @@ -245,7 +296,7 @@
   6.155  	return 0;
   6.156  }
   6.157  
   6.158 -RAZOR_EXPORT void
   6.159 +static void
   6.160  razor_set_destroy(struct razor_set *set)
   6.161  {
   6.162  	struct razor_mapped_file *file, *next;
   6.163 @@ -271,8 +322,24 @@
   6.164  	free(set);
   6.165  }
   6.166  
   6.167 -RAZOR_EXPORT int
   6.168 -razor_set_write_to_fd(struct razor_set *set, int fd, uint32_t section_mask)
   6.169 +RAZOR_EXPORT void
   6.170 +razor_set_unref(struct razor_set *set)
   6.171 +{
   6.172 +	if (set && !--set->ref_count)
   6.173 +		razor_set_destroy(set);
   6.174 +}
   6.175 +
   6.176 +RAZOR_EXPORT struct razor_set *
   6.177 +razor_set_ref(struct razor_set *set)
   6.178 +{
   6.179 +	if (set)
   6.180 +		set->ref_count++;
   6.181 +	return set;
   6.182 +}
   6.183 +
   6.184 +RAZOR_EXPORT void
   6.185 +razor_set_write_to_handle(struct razor_set *set, struct razor_atomic *atomic,
   6.186 +			  int handle, uint32_t section_mask)
   6.187  {
   6.188  	struct razor_set_header header;
   6.189  	struct razor_set_section sections[ARRAY_SIZE(razor_sections)];
   6.190 @@ -298,7 +365,7 @@
   6.191  
   6.192  	count = j;
   6.193  	header.magic = RAZOR_MAGIC;
   6.194 -	header.version = RAZOR_VERSION;
   6.195 +	header.version = set->header_version;
   6.196  	header.num_sections = count;
   6.197  	offset = sizeof header + count * sizeof *sections + ALIGN(pool.size, 4);
   6.198  
   6.199 @@ -308,38 +375,36 @@
   6.200  		offset += ALIGN(arrays[i]->size, 4);
   6.201  	}
   6.202  
   6.203 -	razor_write(fd, &header, sizeof header);
   6.204 -	razor_write(fd, sections, count * sizeof *sections);
   6.205 -	razor_write(fd, pool.data, pool.size);
   6.206 -	razor_write(fd, padding, PADDING(pool.size, 4));
   6.207 +	razor_atomic_write(atomic, handle, &header, sizeof header);
   6.208 +	razor_atomic_write(atomic, handle, sections, count * sizeof *sections);
   6.209 +	razor_atomic_write(atomic, handle, pool.data, pool.size);
   6.210 +	razor_atomic_write(atomic, handle, padding, PADDING(pool.size, 4));
   6.211  
   6.212  	for (i = 0; i < count; i++) {
   6.213 -		razor_write(fd, arrays[i]->data, arrays[i]->size);
   6.214 -		razor_write(fd, padding, PADDING(arrays[i]->size, 4));
   6.215 +		razor_atomic_write(atomic, handle, arrays[i]->data,
   6.216 +				   arrays[i]->size);
   6.217 +		razor_atomic_write(atomic, handle, padding,
   6.218 +				   PADDING(arrays[i]->size, 4));
   6.219  	}
   6.220  
   6.221  	array_release(&pool);
   6.222  	hashtable_release(&table);
   6.223 -
   6.224 -	return 0;
   6.225  }
   6.226  
   6.227  RAZOR_EXPORT int
   6.228 -razor_set_write(struct razor_set *set, const char *filename, uint32_t sections)
   6.229 +razor_set_write(struct razor_set *set, struct razor_atomic *atomic,
   6.230 +		const char *filename, uint32_t sections)
   6.231  {
   6.232 -	int fd, status;
   6.233 +	int h;
   6.234  
   6.235 -	fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC | O_BINARY, 0666);
   6.236 -	if (fd < 0)
   6.237 +	h = razor_atomic_create_file(atomic, filename,
   6.238 +				     S_IRWXU | S_IRWXG | S_IRWXO);
   6.239 +	if (h < 0)
   6.240  		return -1;
   6.241  
   6.242 -	status = razor_set_write_to_fd(set, fd, sections);
   6.243 -	if (status) {
   6.244 -	    close(fd);
   6.245 -	    return status;
   6.246 -	}
   6.247 +	razor_set_write_to_handle(set, atomic, h, sections);
   6.248  
   6.249 -	return close(fd);
   6.250 +	return razor_atomic_close(atomic, h);
   6.251  }
   6.252  
   6.253  RAZOR_EXPORT void
   6.254 @@ -554,74 +619,86 @@
   6.255   * @package: a %razor_package
   6.256   * @root: the root into which the package is currently installed
   6.257   * @install_count: the value to pass to uninstall scripts
   6.258 + * @stage: Limit the removal to just the scripts or the files
   6.259   *
   6.260   * Removes an installed package.
   6.261   **/
   6.262  RAZOR_EXPORT int
   6.263  razor_package_remove(struct razor_set *prev, struct razor_set *next,
   6.264 -		     struct razor_package *package, const char *root,
   6.265 -		     int install_count)
   6.266 +		     struct razor_atomic *atomic, struct razor_package *package,
   6.267 +		     const char *root, int install_count,
   6.268 +		     enum razor_stage_type stage)
   6.269  {
   6.270  	struct razor_file_iterator *fi;
   6.271  	struct razor_package_iterator *pi;
   6.272  	struct razor_package *p;
   6.273 -	char buffer[PATH_MAX];
   6.274 +	char *buffer;
   6.275  	const char *name, *program, *script;
   6.276 -	int retval = 0, i, count;
   6.277 +	int i, count;
   6.278  	struct environment env;
   6.279  	struct list *link;
   6.280  	const char *prefix;
   6.281  
   6.282 -	environment_init(&env);
   6.283 -	link = list_first(&package->install_prefixes, &prev->prefix_pool);
   6.284 -	for (i = 0; link; i++) {
   6.285 -		prefix = (const char *)prev->string_pool.data + link->data;
   6.286 -		sprintf(buffer, "RPM_INSTALL_PREFIX%d", i);
   6.287 -		environment_add_variable(&env, buffer, prefix);
   6.288 -		link = list_next(link);
   6.289 +	if (stage & RAZOR_STAGE_SCRIPTS) {
   6.290 +		environment_init(&env);
   6.291 +		link = list_first(&package->install_prefixes,
   6.292 +				  &prev->prefix_pool);
   6.293 +		for (i = 0; link; i++) {
   6.294 +			prefix = (const char *)prev->string_pool.data +
   6.295 +				 link->data;
   6.296 +			sprintf(buffer, "RPM_INSTALL_PREFIX%d", i);
   6.297 +			environment_add_variable(&env, buffer, prefix);
   6.298 +			link = list_next(link);
   6.299 +		}
   6.300 +		environment_set(&env);
   6.301  	}
   6.302 -	environment_set(&env);
   6.303  
   6.304 -	razor_package_get_details(prev, package,
   6.305 -				  RAZOR_DETAIL_PREUNPROG, &program,
   6.306 -				  RAZOR_DETAIL_PREUN, &script,
   6.307 -				  RAZOR_DETAIL_LAST);
   6.308 +	if (stage & RAZOR_STAGE_SCRIPTS_PRE) {
   6.309 +		razor_package_get_details(prev, package,
   6.310 +					  RAZOR_DETAIL_PREUNPROG, &program,
   6.311 +					  RAZOR_DETAIL_PREUN, &script,
   6.312 +					  RAZOR_DETAIL_LAST);
   6.313  
   6.314 -	retval = razor_run_script(root, RAZOR_PROPERTY_PREUN, program, script,
   6.315 -				  install_count);
   6.316 +		razor_run_script(root, RAZOR_PROPERTY_PREUN, program,
   6.317 +				 script, install_count);
   6.318 +	}
   6.319  
   6.320 -	fi = razor_file_iterator_create(prev, package, 1);
   6.321 +	if (stage & RAZOR_STAGE_FILES) {
   6.322 +		fi = razor_file_iterator_create(prev, package, 1);
   6.323  
   6.324 -	while (razor_file_iterator_next(fi, &name)) {
   6.325 -		pi = razor_package_iterator_create_for_file(next, name);
   6.326 -		count = 0;
   6.327 -		while (razor_package_iterator_next(pi, &p, RAZOR_DETAIL_LAST))
   6.328 -			count++;
   6.329 -		razor_package_iterator_destroy(pi);
   6.330 -		if (count <= 0) {
   6.331 -			snprintf(buffer, sizeof buffer, "%s%s", root, name);
   6.332 -			if (razor_remove(buffer) && errno != ENOENT) {
   6.333 -				perror(name);
   6.334 -				retval = -1;
   6.335 +		while (razor_file_iterator_next(fi, &name)) {
   6.336 +			pi = razor_package_iterator_create_for_file(next, name);
   6.337 +			count = 0;
   6.338 +			while (razor_package_iterator_next(pi, &p,
   6.339 +							   RAZOR_DETAIL_LAST))
   6.340 +				count++;
   6.341 +			razor_package_iterator_destroy(pi);
   6.342 +			if (count <= 0) {
   6.343 +				buffer = razor_concat(root, name, NULL);
   6.344 +				razor_atomic_remove(atomic, buffer);
   6.345 +				free(buffer);
   6.346  			}
   6.347  		}
   6.348 +
   6.349 +		razor_file_iterator_destroy(fi);
   6.350  	}
   6.351  
   6.352 -	razor_file_iterator_destroy(fi);
   6.353 +	if (stage & RAZOR_STAGE_SCRIPTS_POST) {
   6.354 +		razor_package_get_details(prev, package,
   6.355 +					  RAZOR_DETAIL_POSTUNPROG, &program,
   6.356 +					  RAZOR_DETAIL_POSTUN, &script,
   6.357 +					  RAZOR_DETAIL_LAST);
   6.358  
   6.359 -	razor_package_get_details(prev, package,
   6.360 -				  RAZOR_DETAIL_POSTUNPROG, &program,
   6.361 -				  RAZOR_DETAIL_POSTUN, &script,
   6.362 -				  RAZOR_DETAIL_LAST);
   6.363 +		razor_run_script(root, RAZOR_PROPERTY_POSTUN, program, script,
   6.364 +				 install_count);
   6.365 +	}
   6.366  
   6.367 -	if (razor_run_script(root, RAZOR_PROPERTY_POSTUN, program, script,
   6.368 -			     install_count))
   6.369 -		retval = -1;
   6.370 +	if (stage & RAZOR_STAGE_SCRIPTS) {
   6.371 +		environment_unset(&env);
   6.372 +		environment_release(&env);
   6.373 +	}
   6.374  
   6.375 -	environment_unset(&env);
   6.376 -	environment_release(&env);
   6.377 -
   6.378 -	return retval;
   6.379 +	return razor_atomic_in_error_state(atomic);
   6.380  }
   6.381  
   6.382  RAZOR_EXPORT const char *
   6.383 @@ -887,7 +964,7 @@
   6.384  	struct razor_set *set;
   6.385  	struct razor_set *next;
   6.386  	struct array actions;
   6.387 -	struct deque *order;
   6.388 +	struct deque *order, *left;
   6.389  };
   6.390  
   6.391  static void
   6.392 @@ -989,6 +1066,7 @@
   6.393  	}
   6.394  
   6.395  	ii->order = graph_sort(&follows);
   6.396 +	ii->left = deque_dup(ii->order);
   6.397  	graph_release(&follows);
   6.398  
   6.399  	return ii;
   6.400 @@ -1005,10 +1083,10 @@
   6.401  	struct razor_package *pkg;
   6.402  	const char *removing, *name;
   6.403  
   6.404 -	if (deque_empty(ii->order))
   6.405 +	if (deque_empty(ii->left))
   6.406  		return 0;
   6.407  
   6.408 -	a = (struct install_action *)ii->actions.data + deque_pop(ii->order);
   6.409 +	a = (struct install_action *)ii->actions.data + deque_pop(ii->left);
   6.410  	*package = a->package;
   6.411  	*action = a->action;
   6.412  	*count = 0;
   6.413 @@ -1026,15 +1104,24 @@
   6.414  				(*count)++;
   6.415  		}
   6.416  		razor_package_iterator_destroy(pi);
   6.417 -	}
   6.418 +	} else
   6.419 +		*count = 1;
   6.420  
   6.421  	return 1;
   6.422  }
   6.423  
   6.424  RAZOR_EXPORT void
   6.425 +razor_install_iterator_rewind(struct razor_install_iterator *ii)
   6.426 +{
   6.427 +	deque_free(ii->left);
   6.428 +	ii->left=deque_dup(ii->order);
   6.429 +}
   6.430 +
   6.431 +RAZOR_EXPORT void
   6.432  razor_install_iterator_destroy(struct razor_install_iterator *ii)
   6.433  {
   6.434  	array_release(&ii->actions);
   6.435  	deque_free(ii->order);
   6.436 +	deque_free(ii->left);
   6.437  	free(ii);
   6.438  }
     7.1 --- a/librazor/razor.h	Thu Aug 25 14:22:52 2011 +0100
     7.2 +++ b/librazor/razor.h	Thu Nov 10 10:35:21 2011 +0000
     7.3 @@ -1,7 +1,7 @@
     7.4  /*
     7.5   * Copyright (C) 2008  Kristian Høgsberg <krh@redhat.com>
     7.6   * Copyright (C) 2008  Red Hat, Inc
     7.7 - * Copyright (C) 2009  J. Ali Harlow <ali@juiblex.co.uk>
     7.8 + * Copyright (C) 2009, 2011  J. Ali Harlow <ali@juiblex.co.uk>
     7.9   *
    7.10   * This program is free software; you can redistribute it and/or modify
    7.11   * it under the terms of the GNU General Public License as published by
    7.12 @@ -22,6 +22,21 @@
    7.13  #define _RAZOR_H_
    7.14  
    7.15  #include <stdint.h>
    7.16 +#include <sys/types.h>
    7.17 +
    7.18 +/* GCC extensions */
    7.19 +#if defined(__GNUC__)
    7.20 +#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 96)
    7.21 +#define RAZOR_MALLOC __attribute__((__malloc__))
    7.22 +#else
    7.23 +#define RAZOR_MALLOC
    7.24 +#endif
    7.25 +#if __GNUC__ >= 4
    7.26 +#define RAZOR_NULL_TERMINATED __attribute__ ((__sentinel__))
    7.27 +#else
    7.28 +#define RAZOR_NULL_TERMINATED
    7.29 +#endif
    7.30 +#endif	/* __GNUC__ */
    7.31  
    7.32  enum razor_section_type {
    7.33  	RAZOR_SECTION_MAIN = 0x01,
    7.34 @@ -30,6 +45,14 @@
    7.35  	RAZOR_SECTION_ALL = 0x07
    7.36  };
    7.37  
    7.38 +enum razor_stage_type {
    7.39 +	RAZOR_STAGE_SCRIPTS_PRE = 0x1,
    7.40 +	RAZOR_STAGE_FILES = 0x2,
    7.41 +	RAZOR_STAGE_SCRIPTS_POST = 0x4,
    7.42 +	RAZOR_STAGE_SCRIPTS = 0x5,
    7.43 +	RAZOR_STAGE_ALL = 0x7
    7.44 +};
    7.45 +
    7.46  enum razor_detail_type {
    7.47  	RAZOR_DETAIL_LAST = 0,	/* the sentinel */
    7.48  	RAZOR_DETAIL_NAME,
    7.49 @@ -73,6 +96,85 @@
    7.50  };
    7.51  
    7.52  /**
    7.53 + * SECTION:atomic
    7.54 + * @title: Atomic transactions
    7.55 + * @short_description: File-based transactions that shouldn't half-succeed
    7.56 + *
    7.57 + * This is a helper object for issuing a sequence of file-based actions
    7.58 + * that should either all succeed or all fail.
    7.59 + *
    7.60 + * Note that currently only Windows 7 has a native implementation and that
    7.61 + * the fallback implementation will not rollback even if an error does occur.
    7.62 + * This could (and should) be improved.
    7.63 + **/
    7.64 +struct razor_atomic;
    7.65 +
    7.66 +struct razor_atomic *razor_atomic_open(const char *description);
    7.67 +int razor_atomic_commit(struct razor_atomic *atomic);
    7.68 +const char *razor_atomic_get_error_msg(struct razor_atomic *atomic);
    7.69 +void razor_atomic_destroy(struct razor_atomic *atomic);
    7.70 +
    7.71 +/**
    7.72 + * razor_atomic_make_dirs
    7.73 + * 
    7.74 + * Create all sub-directories leading up to path. We know root exists
    7.75 + * and is a dir, root does not end in a '/', and path either has a
    7.76 + * leading '/' or (on MS-Windows only) root is the empty string
    7.77 + * and path starts with drive (eg., "c:/windows").
    7.78 + * Note: path itself is not created, only the directory in which it
    7.79 + * (would) exist.
    7.80 + *
    7.81 + * Returns: non-zero on error.
    7.82 + **/
    7.83 +int razor_atomic_make_dirs(struct razor_atomic *atomic, const char *root,
    7.84 +  const char *path);
    7.85 +int razor_atomic_remove(struct razor_atomic *atomic, const char *path);
    7.86 +int razor_atomic_rename_file(struct razor_atomic *atomic, const char *oldpath,
    7.87 +			     const char *newpath);
    7.88 +
    7.89 +/**
    7.90 + * razor_atomic_create_dir
    7.91 + * 
    7.92 + * Create a directory, replacing any existing object at this path except
    7.93 + * an existing directory (which is not counted as a error).
    7.94 + *
    7.95 + * Returns: non-zero on error.
    7.96 + */
    7.97 +int razor_atomic_create_dir(struct razor_atomic *atomic, const char *dirname,
    7.98 +  mode_t mode);
    7.99 +
   7.100 +/**
   7.101 + * razor_atomic_create_symlink
   7.102 + * 
   7.103 + * Create a symbolic link, replacing any existing object at this path except
   7.104 + * a non-empty directory.
   7.105 + *
   7.106 + * Note: This function will always fail on platforms that don't support
   7.107 + * symbolic links.
   7.108 + *
   7.109 + * Returns: non-zero on error.
   7.110 + */
   7.111 +int razor_atomic_create_symlink(struct razor_atomic *atomic, const char *target,
   7.112 +  const char *path);
   7.113 +/**
   7.114 + * razor_atomic_create_file
   7.115 + * 
   7.116 + * Create a file, replacing any existing object at this path except
   7.117 + * a non-empty directory.
   7.118 + *
   7.119 + * Returns: A handle to be passed to razor_atomic_write() and
   7.120 + * razor_atomic_close() or a negative value on error.
   7.121 + */
   7.122 +int razor_atomic_create_file(struct razor_atomic *atomic, const char *filename,
   7.123 +  mode_t mode);
   7.124 +int razor_atomic_write(struct razor_atomic *atomic, int handle,
   7.125 +  const void *data, size_t size);
   7.126 +int razor_atomic_close(struct razor_atomic *atomic, int handle);
   7.127 +int razor_atomic_sync(struct razor_atomic *atomic, int handle);
   7.128 +void razor_atomic_abort(struct razor_atomic *atomic, const char *error_msg);
   7.129 +int razor_atomic_in_error_state(struct razor_atomic *atomic);
   7.130 +
   7.131 +/**
   7.132   * SECTION:set
   7.133   * @title: Package Set
   7.134   * @short_description: Represents a set of packages and their metadata.
   7.135 @@ -85,6 +187,9 @@
   7.136  struct razor_package;
   7.137  struct razor_property;
   7.138  
   7.139 +#define RAZOR_HEADER_VERSION		2	/* Current version */
   7.140 +#define RAZOR_HEADER_VERSION_MIN	1	/* Minimum version we support */
   7.141 +
   7.142  /**
   7.143   * razor_set_create:
   7.144   * 
   7.145 @@ -94,13 +199,20 @@
   7.146   **/
   7.147  struct razor_set *razor_set_create_without_root(void);
   7.148  struct razor_set *razor_set_create(void);
   7.149 -struct razor_set *razor_set_open(const char *filename);
   7.150 -void razor_set_destroy(struct razor_set *set);
   7.151 -int razor_set_write_to_fd(struct razor_set *set,
   7.152 -			  int fd, uint32_t section_mask);
   7.153 -int razor_set_write(struct razor_set *set,
   7.154 +struct razor_set *razor_set_open(const char *filename,
   7.155 +				 struct razor_atomic *atomic);
   7.156 +uint32_t razor_set_get_header_version(struct razor_set *set);
   7.157 +int razor_set_set_header_version(struct razor_set *set,
   7.158 +				 uint32_t header_version);
   7.159 +void razor_set_unref(struct razor_set *set);
   7.160 +struct razor_set *razor_set_ref(struct razor_set *set);
   7.161 +void razor_set_write_to_handle(struct razor_set *set,
   7.162 +			       struct razor_atomic *atomic, int handle,
   7.163 +			       uint32_t section_mask);
   7.164 +int razor_set_write(struct razor_set *set, struct razor_atomic *atomic,
   7.165  		    const char *filename, uint32_t setions);
   7.166 -int razor_set_bind_sections(struct razor_set *set, const char *filename);
   7.167 +int razor_set_bind_sections(struct razor_set *set, struct razor_atomic *atomic,
   7.168 +			    const char *filename);
   7.169  
   7.170  struct razor_package *
   7.171  razor_set_get_package(struct razor_set *set, const char *package);
   7.172 @@ -110,8 +222,9 @@
   7.173  			  struct razor_package *package, ...);
   7.174  int
   7.175  razor_package_remove(struct razor_set *prev, struct razor_set *next,
   7.176 -		     struct razor_package *package, const char *root,
   7.177 -		     int install_count);
   7.178 +		     struct razor_atomic *atomic, struct razor_package *package,
   7.179 +		     const char *root, int install_count,
   7.180 +		     enum razor_stage_type stage);
   7.181  
   7.182  /**
   7.183   * SECTION:iterator
   7.184 @@ -230,6 +343,7 @@
   7.185  				enum razor_install_action *action,
   7.186  				int *count);
   7.187  
   7.188 +void razor_install_iterator_rewind(struct razor_install_iterator *ii);
   7.189  void razor_install_iterator_destroy(struct razor_install_iterator *ii);
   7.190  
   7.191  /**
   7.192 @@ -286,12 +400,14 @@
   7.193  				    const char *path);
   7.194  void razor_relocations_destroy(struct razor_relocations *relocations);
   7.195  
   7.196 -struct razor_rpm *razor_rpm_open(const char *filename);
   7.197 +struct razor_rpm *razor_rpm_open(const char *filename,
   7.198 +				 struct razor_atomic *atomic);
   7.199  void razor_rpm_get_details(struct razor_rpm *rpm, ...);
   7.200  void razor_rpm_set_relocations(struct razor_rpm *rpm,
   7.201  			       struct razor_relocations *relocations);
   7.202 -int razor_rpm_install(struct razor_rpm *rpm, const char *root,
   7.203 -		      int install_count);
   7.204 +int razor_rpm_install(struct razor_rpm *rpm, struct razor_atomic *atomic,
   7.205 +		      const char *root, int install_count,
   7.206 +		      enum razor_stage_type stage);
   7.207  int razor_rpm_close(struct razor_rpm *rpm);
   7.208  
   7.209  /**
   7.210 @@ -378,14 +494,15 @@
   7.211  struct razor_root;
   7.212  
   7.213  int razor_root_create(const char *root);
   7.214 -struct razor_root *razor_root_open(const char *root);
   7.215 -struct razor_set *razor_root_open_read_only(const char *root);
   7.216 +struct razor_root *
   7.217 +razor_root_open(const char *root, struct razor_atomic *atomic);
   7.218 +struct razor_set *razor_root_open_read_only(const char *root,
   7.219 +					    struct razor_atomic *atomic);
   7.220  struct razor_set *razor_root_get_system_set(struct razor_root *root);
   7.221  int razor_root_close(struct razor_root *root);
   7.222  void razor_root_update(struct razor_root *root, struct razor_set *next);
   7.223  int razor_root_commit(struct razor_root *root);
   7.224  
   7.225 -
   7.226  /**
   7.227   * SECTION:misc
   7.228   * @title: Miscellaneous Functions
   7.229 @@ -408,5 +525,8 @@
   7.230  void razor_set_lua_loader(const char *modname, void (*loader)());
   7.231  void (*razor_get_lua_loader(const char *modname))();
   7.232  
   7.233 +char *razor_concat(const char *s, ...) RAZOR_MALLOC RAZOR_NULL_TERMINATED;
   7.234 +
   7.235 +const char *razor_system_arch(void);
   7.236  
   7.237  #endif /* _RAZOR_H_ */
     8.1 --- a/librazor/root.c	Thu Aug 25 14:22:52 2011 +0100
     8.2 +++ b/librazor/root.c	Thu Nov 10 10:35:21 2011 +0000
     8.3 @@ -1,7 +1,7 @@
     8.4  /*
     8.5   * Copyright (C) 2008  Kristian Høgsberg <krh@redhat.com>
     8.6   * Copyright (C) 2008  Red Hat, Inc
     8.7 - * Copyright (C) 2009  J. Ali Harlow <ali@juiblex.co.uk>
     8.8 + * Copyright (C) 2009, 2011  J. Ali Harlow <ali@juiblex.co.uk>
     8.9   *
    8.10   * This program is free software; you can redistribute it and/or modify
    8.11   * it under the terms of the GNU General Public License as published by
    8.12 @@ -60,9 +60,9 @@
    8.13  struct razor_root {
    8.14  	struct razor_set *system;
    8.15  	struct razor_set *next;
    8.16 -	int fd;
    8.17 -	char path[PATH_MAX];
    8.18 -	char new_path[PATH_MAX];
    8.19 +	struct razor_atomic *atomic;
    8.20 +	int handle;
    8.21 +	char *path, *new_path;
    8.22  };
    8.23  
    8.24  static void
    8.25 @@ -83,9 +83,11 @@
    8.26  RAZOR_EXPORT int
    8.27  razor_root_create(const char *root)
    8.28  {
    8.29 +	int retval;
    8.30  	struct stat buf;
    8.31  	struct razor_set *set;
    8.32 -	char path[PATH_MAX];
    8.33 +	struct razor_atomic *atomic;
    8.34 +	char *path;
    8.35  
    8.36  	assert (root != NULL);
    8.37  
    8.38 @@ -107,77 +109,90 @@
    8.39  		return -1;
    8.40  	}
    8.41  
    8.42 -	snprintf(path, sizeof path, "%s/%s",
    8.43 -		 razor_root_path, system_repo_filename);
    8.44 -	if (razor_create_dir(root, path) < 0) {
    8.45 -		fprintf(stderr, "could not create %s%s\n",
    8.46 -			root, razor_root_path);
    8.47 -		return -1;
    8.48 +	path = razor_concat(root, razor_root_path, "/", system_repo_filename,
    8.49 +			    NULL);
    8.50 +	retval = !stat(path, &buf);
    8.51 +	free(path);
    8.52 +	if (retval) {
    8.53 +		fprintf(stderr,
    8.54 +			"a razor install root is already initialized\n");
    8.55 +		return retval;
    8.56  	}
    8.57  
    8.58 +	atomic = razor_atomic_open("Create initial package set");
    8.59 +	path = razor_concat(razor_root_path, "/", system_repo_filename, NULL);
    8.60 +	razor_atomic_make_dirs(atomic, root, path);
    8.61  	set = razor_set_create();
    8.62 -	snprintf(path, sizeof path, "%s%s/%s",
    8.63 -		 root, razor_root_path, system_repo_filename);
    8.64 -	if (stat(path, &buf) == 0) {
    8.65 -		fprintf(stderr,
    8.66 -			"a razor install root is already initialized\n");
    8.67 -		return -1;
    8.68 -	}
    8.69 -	if (razor_set_write(set, path, RAZOR_SECTION_ALL) < 0) {
    8.70 +	razor_set_write(set, atomic, path, RAZOR_SECTION_ALL);
    8.71 +	free(path);
    8.72 +	retval = razor_atomic_commit(atomic);
    8.73 +	if (retval)
    8.74  		fprintf(stderr, "could not write initial package set\n");
    8.75 -		return -1;
    8.76 -	}
    8.77 -	razor_set_destroy(set);
    8.78 +	razor_set_unref(set);
    8.79 +	razor_atomic_destroy(atomic);
    8.80  
    8.81 -	return 0;
    8.82 +	return retval;
    8.83  }
    8.84  
    8.85  RAZOR_EXPORT struct razor_root *
    8.86 -razor_root_open(const char *root)
    8.87 +razor_root_open(const char *root, struct razor_atomic *atomic)
    8.88  {
    8.89  	struct razor_root *image;
    8.90 -	char lock_path[PATH_MAX];
    8.91 +	char *lock_path;
    8.92 +	int r;
    8.93  
    8.94  	assert (root != NULL);
    8.95  
    8.96  	razor_root_init();
    8.97  	image = malloc(sizeof *image);
    8.98 -	if (image == NULL)
    8.99 +	if (image == NULL) {
   8.100 +		razor_atomic_abort(atomic, "Not enough memory");
   8.101  		return NULL;
   8.102 +	}
   8.103 +
   8.104 +	image->atomic = atomic;
   8.105  
   8.106  	image->system = razor_set_create_without_root();
   8.107  	if (image->system == NULL) {
   8.108  		free(image);
   8.109 +		razor_atomic_abort(atomic, "Not enough memory");
   8.110  		return NULL;
   8.111  	}
   8.112  
   8.113 -	snprintf(lock_path, sizeof lock_path,
   8.114 -		 "%s%s/%s", root, razor_root_path, system_lock_filename);
   8.115 +	lock_path = razor_concat(root, razor_root_path, "/",
   8.116 +				 system_lock_filename, NULL);
   8.117  
   8.118 -	if (razor_set_aquire_lock(image->system, lock_path, 1) < 0) {
   8.119 -		razor_set_destroy(image->system);
   8.120 +	r = razor_set_aquire_lock(image->system, lock_path, 1);
   8.121 +
   8.122 +	free(lock_path);
   8.123 +
   8.124 +	if (r < 0) {
   8.125 +		razor_atomic_abort(atomic,
   8.126 +				   "Failed to aquire exclusive system lock");
   8.127 +		razor_set_unref(image->system);
   8.128  		free(image);
   8.129  		return NULL;
   8.130  	}
   8.131  
   8.132 -	snprintf(image->new_path, sizeof image->new_path,
   8.133 -		 "%s%s/%s", root, razor_root_path, system_tmp_filename);
   8.134 -	image->fd = open(image->new_path,
   8.135 -			 O_CREAT | O_WRONLY | O_TRUNC | O_BINARY,
   8.136 -			 0666);
   8.137 -	if (image->fd < 0) {
   8.138 -		razor_set_destroy(image->system);
   8.139 +	image->new_path = razor_concat(root, razor_root_path, "/",
   8.140 +				       system_tmp_filename, NULL);
   8.141 +	image->handle = razor_atomic_create_file(atomic, image->new_path,
   8.142 +						 S_IRWXU | S_IRWXG | S_IRWXO);
   8.143 +	if (image->handle < 0) {
   8.144 +		free(image->new_path);
   8.145 +		razor_set_unref(image->system);
   8.146  		free(image);
   8.147  		return NULL;
   8.148  	}
   8.149  
   8.150 -	snprintf(image->path, sizeof image->path,
   8.151 -		 "%s%s/%s", root, razor_root_path, system_repo_filename);
   8.152 +	image->path = razor_concat(root, razor_root_path, "/",
   8.153 +				   system_repo_filename, NULL);
   8.154  
   8.155 -	if (razor_set_bind_sections(image->system, image->path)) {
   8.156 -		close(image->fd);
   8.157 +	if (razor_set_bind_sections(image->system, atomic, image->path)) {
   8.158  		unlink(image->new_path);
   8.159 -		razor_set_destroy(image->system);
   8.160 +		free(image->new_path);
   8.161 +		free(image->path);
   8.162 +		razor_set_unref(image->system);
   8.163  		free(image);
   8.164  		return NULL;
   8.165  	}
   8.166 @@ -186,33 +201,41 @@
   8.167  }
   8.168  
   8.169  RAZOR_EXPORT struct razor_set *
   8.170 -razor_root_open_read_only(const char *root)
   8.171 +razor_root_open_read_only(const char *root, struct razor_atomic *atomic)
   8.172  {
   8.173 -	char path[PATH_MAX];
   8.174 +	char *path;
   8.175  	struct razor_set *set;
   8.176  
   8.177  	assert (root != NULL);
   8.178  
   8.179  	razor_root_init();
   8.180  	set = razor_set_create_without_root();
   8.181 -	if (set == NULL)
   8.182 -		return NULL;
   8.183 -
   8.184 -	snprintf(path, sizeof path,
   8.185 -		 "%s%s/%s", root, razor_root_path, system_lock_filename);
   8.186 -	if (razor_set_aquire_lock(set, path, 0) < 0) {
   8.187 -		razor_set_destroy(set);
   8.188 +	if (set == NULL) {
   8.189 +		razor_atomic_abort(atomic, "Not enough memory");
   8.190  		return NULL;
   8.191  	}
   8.192  
   8.193 -	snprintf(path, sizeof path, "%s%s/%s",
   8.194 -		 root, razor_root_path, system_repo_filename);
   8.195 -
   8.196 -	if (razor_set_bind_sections(set, path)) {
   8.197 -		razor_set_destroy(set);
   8.198 +	path = razor_concat(root, razor_root_path, "/", system_lock_filename,
   8.199 +			    NULL);
   8.200 +	if (razor_set_aquire_lock(set, path, 0) < 0) {
   8.201 +		razor_atomic_abort(atomic, "Failed to aquire non-exclusive "
   8.202 +					   "system lock");
   8.203 +		free(path);
   8.204 +		razor_set_unref(set);
   8.205  		return NULL;
   8.206  	}
   8.207  
   8.208 +	free(path);
   8.209 +	path = razor_concat(root, razor_root_path, "/", system_repo_filename,
   8.210 +			    NULL);
   8.211 +
   8.212 +	if (razor_set_bind_sections(set, atomic, path)) {
   8.213 +		razor_set_unref(set);
   8.214 +		set = NULL;
   8.215 +	}
   8.216 +
   8.217 +	free(path);
   8.218 +
   8.219  	return set;
   8.220  }
   8.221  
   8.222 @@ -229,9 +252,11 @@
   8.223  {
   8.224  	assert (root != NULL);
   8.225  
   8.226 -	razor_set_destroy(root->system);
   8.227 -	close(root->fd);
   8.228 -	unlink(root->new_path);
   8.229 +	razor_set_unref(root->system);
   8.230 +	razor_atomic_close(root->atomic, root->handle);
   8.231 +	razor_atomic_remove(root->atomic, root->new_path);
   8.232 +	free(root->path);
   8.233 +	free(root->new_path);
   8.234  	free(root);
   8.235  
   8.236  	return 0;
   8.237 @@ -244,13 +269,13 @@
   8.238  	assert (next != NULL);
   8.239  
   8.240  	razor_root_init();
   8.241 -	razor_set_write_to_fd(next, root->fd, RAZOR_SECTION_ALL);
   8.242 +	razor_set_write_to_handle(next, root->atomic, root->handle,
   8.243 +				  RAZOR_SECTION_ALL);
   8.244  	root->next = next;
   8.245  
   8.246  	/* Sync the new repo file so the new package set is on disk
   8.247  	 * before we start upgrading. */
   8.248 -	fsync(root->fd);
   8.249 -	printf("wrote %s\n", root->new_path);
   8.250 +	razor_atomic_sync(root->atomic, root->handle);
   8.251  }
   8.252  
   8.253  RAZOR_EXPORT int
   8.254 @@ -259,18 +284,12 @@
   8.255  	int retval;
   8.256  	assert (root != NULL);
   8.257  
   8.258 -	/* Make it so. */
   8.259 -	close(root->fd);
   8.260 -#ifdef MSWIN_API
   8.261 -	/* Rename is not atomic under MS-Windows */
   8.262 -	remove(root->path);
   8.263 -#endif
   8.264 -	retval = rename(root->new_path, root->path);
   8.265 -	if (retval)
   8.266 -		perror(root->path);
   8.267 -	else
   8.268 -		printf("renamed %s to %s\n", root->new_path, root->path);
   8.269 -	razor_set_destroy(root->system);
   8.270 +	razor_atomic_close(root->atomic, root->handle);
   8.271 +	retval = razor_atomic_rename_file(root->atomic, root->new_path,
   8.272 +					  root->path);
   8.273 +	razor_set_unref(root->system);
   8.274 +	free(root->path);
   8.275 +	free(root->new_path);
   8.276  	free(root);
   8.277  
   8.278  	return retval;
     9.1 --- a/librazor/rpm.c	Thu Aug 25 14:22:52 2011 +0100
     9.2 +++ b/librazor/rpm.c	Thu Nov 10 10:35:21 2011 +0000
     9.3 @@ -1,7 +1,7 @@
     9.4  /*
     9.5   * Copyright (C) 2008  Kristian Høgsberg <krh@redhat.com>
     9.6   * Copyright (C) 2008  Red Hat, Inc
     9.7 - * Copyright (C) 2009  J. Ali Harlow <ali@juiblex.co.uk>
     9.8 + * Copyright (C) 2009, 2011  J. Ali Harlow <ali@juiblex.co.uk>
     9.9   *
    9.10   * This program is free software; you can redistribute it and/or modify
    9.11   * it under the terms of the GNU General Public License as published by
    9.12 @@ -602,24 +602,29 @@
    9.13  }
    9.14  
    9.15  RAZOR_EXPORT struct razor_rpm *
    9.16 -razor_rpm_open(const char *filename)
    9.17 +razor_rpm_open(const char *filename, struct razor_atomic *atomic)
    9.18  {
    9.19  	struct razor_rpm *rpm;
    9.20  	struct rpm_header_index *base, *index;
    9.21  	unsigned int count, i, nindex, hsize;
    9.22  	const char *name, *prefix;
    9.23 +	char *s;
    9.24  
    9.25  	assert (filename != NULL);
    9.26  
    9.27 -	rpm = malloc(sizeof *rpm);
    9.28 -	if (rpm == NULL)
    9.29 +	rpm = zalloc(sizeof *rpm);
    9.30 +	if (rpm == NULL) {
    9.31 +		razor_atomic_abort(atomic, "Not enough memory");
    9.32  		return NULL;
    9.33 +	}
    9.34  	memset(rpm, 0, sizeof *rpm);
    9.35  
    9.36  	rpm->map = razor_file_get_contents(filename, &rpm->size);
    9.37  	if (!rpm->map) {
    9.38 -		fprintf(stderr, "couldn't get contents of %s (%s)\n", filename,
    9.39 -			strerror(errno));
    9.40 +		s = razor_concat(filename, ": ", strerror(errno), NULL);
    9.41 +		razor_atomic_abort(atomic, s);
    9.42 +		free(s);
    9.43 +		free(rpm);
    9.44  		return NULL;
    9.45  	}
    9.46  
    9.47 @@ -648,7 +653,11 @@
    9.48  		name = razor_rpm_get_indirect(rpm, RPMTAG_OLDFILENAMES,
    9.49  					      &count);
    9.50  		if (name) {
    9.51 -			fprintf(stderr, "old filenames not supported\n");
    9.52 +			razor_rpm_close(rpm);
    9.53 +			s = razor_concat(filename,
    9.54 +					 ": Old filenames not supported", NULL);
    9.55 +			razor_atomic_abort(atomic, s);
    9.56 +			free(s);
    9.57  			return NULL;
    9.58  		}
    9.59  	}
    9.60 @@ -666,7 +675,12 @@
    9.61  		prefix = razor_rpm_get_indirect(rpm, RPMTAG_DEFAULTPREFIX,
    9.62  						&count);
    9.63  		if (prefix) {
    9.64 -			fprintf(stderr, "default prefix not supported\n");
    9.65 +			razor_rpm_close(rpm);
    9.66 +			s = razor_concat(filename,
    9.67 +					 ": Default prefix not supported",
    9.68 +					 NULL);
    9.69 +			razor_atomic_abort(atomic, s);
    9.70 +			free(s);
    9.71  			return NULL;
    9.72  		}
    9.73  	}
    9.74 @@ -711,6 +725,7 @@
    9.75  struct installer {
    9.76  	const char *root;
    9.77  	struct razor_rpm *rpm;
    9.78 +	struct razor_atomic *atomic;
    9.79  	z_stream stream;
    9.80  	unsigned char buffer[32768];
    9.81  	size_t rest, length;
    9.82 @@ -731,8 +746,7 @@
    9.83  	installer->stream.avail_out = length;
    9.84  	err = inflate(&installer->stream, Z_SYNC_FLUSH);
    9.85  	if (err != Z_OK && err != Z_STREAM_END) {
    9.86 -		fprintf(stderr, "inflate error: %d (%s)\n", err,
    9.87 -			strerror(errno));
    9.88 +		razor_atomic_abort(installer->atomic, "Failed to inflate");
    9.89  		return -1;
    9.90  	}
    9.91  
    9.92 @@ -757,8 +771,7 @@
    9.93  
    9.94  	err = inflate(&installer->stream, Z_SYNC_FLUSH);
    9.95  	if (err != Z_OK && err != Z_STREAM_END) {
    9.96 -		fprintf(stderr, "inflate error: %d (%s)\n", err,
    9.97 -			strerror(errno));
    9.98 +		razor_atomic_abort(installer->atomic, "Failed to inflate");
    9.99  		return -1;
   9.100  	}
   9.101  
   9.102 @@ -768,80 +781,74 @@
   9.103  static int
   9.104  create_path(struct installer *installer, const char *path, unsigned int mode)
   9.105  {
   9.106 -	char buffer[PATH_MAX];
   9.107 -	struct stat buf;
   9.108 -	int fd, ret;
   9.109 +	char *s, *buffer;
   9.110 +	int h, ret;
   9.111  
   9.112 -	if (razor_create_dir(installer->root, path) < 0)
   9.113 +	if (razor_atomic_make_dirs(installer->atomic, installer->root, path))
   9.114  		return -1;
   9.115  
   9.116 -	snprintf(buffer, sizeof buffer, "%s%s", installer->root, path);
   9.117 +	buffer = razor_concat(installer->root, path, NULL);
   9.118  
   9.119  	switch (mode >> 12) {
   9.120  	case REG:
   9.121  		/* FIXME: handle the case where a file is already there. */
   9.122 -		fd = open(buffer, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
   9.123 -			  mode & 0x1ff);
   9.124 -		if (fd < 0){
   9.125 -			fprintf(stderr, "failed to create file %s\n", buffer);
   9.126 +		h = razor_atomic_create_file(installer->atomic, buffer, mode);
   9.127 +		free(buffer);
   9.128 +		if (h < 0)
   9.129  			return -1;
   9.130 +		while (installer->rest > 0) {
   9.131 +			if (installer_inflate(installer))
   9.132 +				return -1;
   9.133 +			if (razor_atomic_write(installer->atomic, h,
   9.134 +					       installer->buffer,
   9.135 +					       installer->length))
   9.136 +				return -1;
   9.137  		}
   9.138 -		while (installer->rest > 0) {
   9.139 -			if (installer_inflate(installer)) {
   9.140 -				fprintf(stderr, "failed to inflate\n");
   9.141 -				return -1;
   9.142 -			}
   9.143 -			if (razor_write(fd, installer->buffer,
   9.144 -					installer->length)) {
   9.145 -				fprintf(stderr, "failed to write payload\n");
   9.146 -				return -1;
   9.147 -			}
   9.148 -		}
   9.149 -		if (close(fd) < 0) {
   9.150 -			fprintf(stderr, "failed to close %s: %s\n", buffer,
   9.151 -				strerror(errno));
   9.152 -			return -1;
   9.153 -		}
   9.154 -		return 0;
   9.155 +		return razor_atomic_close(installer->atomic, h);
   9.156  	case XDIR:
   9.157 -		ret = mkdir(buffer, mode & 0x1ff);
   9.158 -		if (ret == 0 || errno != EEXIST)
   9.159 -			return ret;
   9.160 -		if (stat(buffer, &buf) || !S_ISDIR(buf.st_mode)) {
   9.161 -			/* FIXME: also check that mode match. */
   9.162 -			fprintf(stderr,
   9.163 -				"%s exists but is not a directory\n", buffer);
   9.164 -			return -1;
   9.165 -		}
   9.166 -		return 0;
   9.167 +		ret = razor_atomic_create_dir(installer->atomic, buffer, mode);
   9.168 +		free(buffer);
   9.169 +		return ret;
   9.170  	case LINK:
   9.171  #if HAVE_SYMLINK
   9.172 -		if (installer_inflate(installer)) {
   9.173 -			fprintf(stderr, "failed to inflate\n");
   9.174 +		if (installer_inflate(installer))
   9.175  			return -1;
   9.176 -		}
   9.177  		if (installer->length >= sizeof installer->buffer) {
   9.178 -			fprintf(stderr, "link name too long\n");
   9.179 +			razor_atomic_abort(installer->atomic,
   9.180 +			  "Link target too long");
   9.181  			return -1;
   9.182  		}
   9.183  		installer->buffer[installer->length] = '\0';
   9.184 -		if (symlink((const char *) installer->buffer, buffer)) {
   9.185 -			perror("failed to create symlink");
   9.186 -			return -1;
   9.187 -		}
   9.188 -		return 0;
   9.189 +		ret = razor_atomic_create_symlink(installer->atomic,
   9.190 +		  (const char *)installer->buffer, buffer);
   9.191 +		free(buffer);
   9.192 +		return ret;
   9.193  #else
   9.194 -		/* fall through */
   9.195 +		s = "Symbolic links";
   9.196 +		goto unsupported;
   9.197  #endif
   9.198  	case PIPE:
   9.199 +		s = "Named pipes";
   9.200 +unsupported:
   9.201 +		free(buffer);
   9.202 +		buffer = razor_concat(s, " are not supported on this platform",
   9.203 +		  NULL);
   9.204 +		razor_atomic_abort(installer->atomic, buffer);
   9.205 +		free(buffer);
   9.206 +		return -1;
   9.207  	case CDEV:
   9.208 +		s = "Character devices";
   9.209 +		goto unsupported;
   9.210  	case BDEV:
   9.211 +		s = "Block devices";
   9.212 +		goto unsupported;
   9.213  	case SOCK:
   9.214 -		printf("%s: unhandled file type %d\n", buffer, mode >> 12);
   9.215 -		return 0;
   9.216 +		s = "Named sockets";
   9.217 +		goto unsupported;
   9.218  	default:
   9.219 -		printf("%s: unknown file type %d\n", buffer, mode >> 12);
   9.220 -		return 0;
   9.221 +		free(buffer);
   9.222 +		razor_atomic_abort(installer->atomic, "Unknown file type");
   9.223 +		return -1;
   9.224  	}
   9.225  }
   9.226  
   9.227 @@ -1046,10 +1053,12 @@
   9.228  {
   9.229  	unsigned char *gz_header;
   9.230  	int method, flags, err;
   9.231 +	char buffer[32], *s;
   9.232  
   9.233  	gz_header = installer->rpm->payload;
   9.234  	if (gz_header[0] != 0x1f || gz_header[1] != 0x8b) {
   9.235 -		fprintf(stderr, "payload section doesn't have gz header\n");
   9.236 +		razor_atomic_abort(installer->atomic, 
   9.237 +				   "Payload section doesn't have gz header");
   9.238  		return -1;
   9.239  	}
   9.240  
   9.241 @@ -1057,8 +1066,9 @@
   9.242  	flags = gz_header[3];
   9.243  
   9.244  	if (method != Z_DEFLATED || flags != 0) {
   9.245 -		fprintf(stderr,
   9.246 -			"unknown payload compression method or flags set\n");
   9.247 +		razor_atomic_abort(installer->atomic, 
   9.248 +				   "Unknown payload compression method or "
   9.249 +				   "flags set");
   9.250  		return -1;
   9.251  	}
   9.252  
   9.253 @@ -1075,7 +1085,10 @@
   9.254  
   9.255  	err = inflateInit2(&installer->stream, -MAX_WBITS);
   9.256  	if (err != Z_OK) {
   9.257 -		fprintf(stderr, "inflateInit error: %d\n", err);
   9.258 +		sprintf(buffer, "%d", err);
   9.259 +		s = razor_concat("inflateEnd error: ", s, NULL);
   9.260 +		razor_atomic_abort(installer->atomic, s);
   9.261 +		free(s);
   9.262  		return -1;
   9.263  	}
   9.264  
   9.265 @@ -1086,15 +1099,18 @@
   9.266  installer_finish(struct installer *installer)
   9.267  {
   9.268  	int err;
   9.269 +	char buffer[32], *s;
   9.270  
   9.271  	err = inflateEnd(&installer->stream);
   9.272  
   9.273  	if (err != Z_OK) {
   9.274 -		fprintf(stderr, "inflateEnd error: %d\n", err);
   9.275 -		return -1;
   9.276 +		sprintf(buffer, "%d", err);
   9.277 +		s = razor_concat("inflateEnd error: ", s, NULL);
   9.278 +		razor_atomic_abort(installer->atomic, s);
   9.279 +		free(s);
   9.280  	}
   9.281  
   9.282 -	return 0;
   9.283 +	return razor_atomic_in_error_state(installer->atomic);
   9.284  }
   9.285  
   9.286  static unsigned long
   9.287 @@ -1114,73 +1130,86 @@
   9.288  }
   9.289  
   9.290  RAZOR_EXPORT int
   9.291 -razor_rpm_install(struct razor_rpm *rpm, const char *root, int install_count)
   9.292 +razor_rpm_install(struct razor_rpm *rpm, struct razor_atomic *atomic,
   9.293 +		  const char *root, int install_count,
   9.294 +		  enum razor_stage_type stage)
   9.295  {
   9.296  	struct installer installer;
   9.297  	struct cpio_file_header *header;
   9.298  	struct stat buf;
   9.299  	unsigned int mode;
   9.300 -	const char *path;
   9.301 +	const char *path, *name;
   9.302  	size_t filesize;
   9.303 +	char *s;
   9.304  
   9.305  	assert (rpm != NULL);
   9.306  	assert (root != NULL);
   9.307  
   9.308  	installer.rpm = rpm;
   9.309  	installer.root = root;
   9.310 +	installer.atomic = atomic;
   9.311  
   9.312  	/* FIXME: Only do this before a transaction, not per rpm. */
   9.313  	if (*root && (stat(root, &buf) < 0 || !S_ISDIR(buf.st_mode))) {
   9.314 -		fprintf(stderr,
   9.315 -			"root installation directory \"%s\" does not exist\n",
   9.316 -			root);
   9.317 +		s = razor_concat(root, ": Directory does not exist", NULL);
   9.318 +		razor_atomic_abort(stderr, s);
   9.319 +		free(s);
   9.320  		return -1;
   9.321  	}
   9.322  
   9.323  	if (rpm->relocations)
   9.324  		razor_relocations_set_rpm(rpm->relocations, rpm);
   9.325  
   9.326 -	if (installer_init(&installer))
   9.327 -		return -1;
   9.328 +	if (stage & RAZOR_STAGE_SCRIPTS_PRE)
   9.329 +		run_script(&installer, RPMTAG_PREINPROG, RPMTAG_PREIN,
   9.330 +			   install_count);
   9.331  
   9.332 -	run_script(&installer, RPMTAG_PREINPROG, RPMTAG_PREIN, install_count);
   9.333 -
   9.334 -	while (installer.stream.avail_in > 0) {
   9.335 -		installer.rest = sizeof *header;
   9.336 -		if (installer_inflate(&installer))
   9.337 +	if (stage & RAZOR_STAGE_FILES) {
   9.338 +		if (installer_init(&installer))
   9.339  			return -1;
   9.340  
   9.341 -		header = (struct cpio_file_header *) installer.buffer;
   9.342 -		mode = fixed_hex_to_ulong(header->mode, sizeof header->mode);
   9.343 -		filesize = fixed_hex_to_ulong(header->filesize,
   9.344 -					      sizeof header->filesize);
   9.345 +		while (installer.stream.avail_in > 0) {
   9.346 +			installer.rest = sizeof *header;
   9.347 +			if (installer_inflate(&installer))
   9.348 +				break;
   9.349  
   9.350 -		installer.rest = fixed_hex_to_ulong(header->namesize,
   9.351 -						    sizeof header->namesize);
   9.352 +			header = (struct cpio_file_header *) installer.buffer;
   9.353 +			mode = fixed_hex_to_ulong(header->mode,
   9.354 +						  sizeof header->mode);
   9.355 +			filesize = fixed_hex_to_ulong(header->filesize,
   9.356 +						      sizeof header->filesize);
   9.357  
   9.358 -		if (installer_inflate(&installer) ||
   9.359 -		    installer_align(&installer, 4))
   9.360 -			return -1;
   9.361 +			installer.rest =
   9.362 +			  fixed_hex_to_ulong(header->namesize,
   9.363 +					     sizeof header->namesize);
   9.364  
   9.365 -		path = (const char *) installer.buffer;
   9.366 -		/* This convention is so lame... */
   9.367 -		if (strcmp(path, "TRAILER!!!") == 0)
   9.368 -			break;
   9.369 +			if (installer_inflate(&installer) ||
   9.370 +			    installer_align(&installer, 4))
   9.371 +				break;
   9.372  
   9.373 -		installer.rest = filesize;
   9.374 -		path++;
   9.375 -		if (rpm->relocations)
   9.376 -			path = razor_relocations_apply(rpm->relocations, path);
   9.377 -		if (create_path(&installer, path, mode) < 0)
   9.378 -			return -1;
   9.379 -		if (installer_align(&installer, 4))
   9.380 +			path = (const char *) installer.buffer;
   9.381 +			/* This convention is so lame... */
   9.382 +			if (strcmp(path, "TRAILER!!!") == 0)
   9.383 +				break;
   9.384 +
   9.385 +			installer.rest = filesize;
   9.386 +			path++;
   9.387 +			if (rpm->relocations)
   9.388 +				path = razor_relocations_apply(rpm->relocations,
   9.389 +							       path);
   9.390 +			if (create_path(&installer, path, mode))
   9.391 +				break;
   9.392 +			if (installer_align(&installer, 4))
   9.393 +				break;
   9.394 +		}
   9.395 +
   9.396 +		if (installer_finish(&installer))
   9.397  			return -1;
   9.398  	}
   9.399  
   9.400 -	if (installer_finish(&installer))
   9.401 -		return -1;
   9.402 -
   9.403 -	run_script(&installer, RPMTAG_POSTINPROG, RPMTAG_POSTIN, install_count);
   9.404 +	if (stage & RAZOR_STAGE_SCRIPTS_POST)
   9.405 +		run_script(&installer, RPMTAG_POSTINPROG, RPMTAG_POSTIN,
   9.406 +			   install_count);
   9.407  
   9.408  	return 0;
   9.409  }
    10.1 --- a/librazor/transaction.c	Thu Aug 25 14:22:52 2011 +0100
    10.2 +++ b/librazor/transaction.c	Thu Nov 10 10:35:21 2011 +0000
    10.3 @@ -1,7 +1,7 @@
    10.4  /*
    10.5   * Copyright (C) 2008  Kristian Høgsberg <krh@redhat.com>
    10.6   * Copyright (C) 2008  Red Hat, Inc
    10.7 - * Copyright (C) 2009  J. Ali Harlow <ali@juiblex.co.uk>
    10.8 + * Copyright (C) 2009, 2011  J. Ali Harlow <ali@juiblex.co.uk>
    10.9   *
   10.10   * This program is free software; you can redistribute it and/or modify
   10.11   * it under the terms of the GNU General Public License as published by
   10.12 @@ -109,7 +109,7 @@
   10.13  {
   10.14  	int count;
   10.15  
   10.16 -	ts->set = set;
   10.17 +	ts->set = razor_set_ref(set);
   10.18  	count = set->packages.size / sizeof (struct razor_package);
   10.19  	ts->packages = zalloc(count * sizeof *ts->packages);
   10.20  	count = set->properties.size / sizeof (struct razor_property);
   10.21 @@ -119,6 +119,7 @@
   10.22  static void
   10.23  transaction_set_release(struct transaction_set *ts)
   10.24  {
   10.25 +	razor_set_unref(ts->set);
   10.26  	free(ts->packages);
   10.27  	free(ts->properties);
   10.28  }
   10.29 @@ -321,7 +322,9 @@
   10.30  						   RAZOR_DETAIL_NAME, &n,
   10.31  						   RAZOR_DETAIL_VERSION, &v,
   10.32  						   RAZOR_DETAIL_LAST)) {
   10.33 +#if 0
   10.34  			fprintf(stderr, "removing %s-%s\n", n, v);
   10.35 +#endif
   10.36  			razor_transaction_remove_package(trans, pkg);
   10.37  		}
   10.38  	}
   10.39 @@ -369,11 +372,13 @@
   10.40  						   RAZOR_DETAIL_VERSION, &version,
   10.41  						   RAZOR_DETAIL_LAST)) {
   10.42  
   10.43 +#if 0
   10.44  			fprintf(stderr, "flagging %s-%s for providing %s matching %s %s\n",
   10.45  				name, version,
   10.46  				ppi->pool + p->name,
   10.47  				rpi->pool + r->name,
   10.48  				rpi->pool + r->version);
   10.49 +#endif
   10.50  			flags[pkg - pkgs] |= flag;
   10.51  		}
   10.52  	}
   10.53 @@ -542,11 +547,13 @@
   10.54  		while (razor_package_iterator_next(&pkg_iter, &pkg,
   10.55  						   RAZOR_DETAIL_NAME, &name,
   10.56  						   RAZOR_DETAIL_LAST)) {
   10.57 +#if 0
   10.58  			fprintf(stderr, "updating %s because %s %s %s "
   10.59  				"isn't satisfied\n",
   10.60  				name, spi.pool + sp->name,
   10.61  				razor_property_relation_to_string(sp),
   10.62  				spi.pool + sp->version);
   10.63 +#endif
   10.64  			trans->system.packages[pkg - spkgs] |=
   10.65  				TRANS_PACKAGE_UPDATE;
   10.66  		}
   10.67 @@ -595,9 +602,11 @@
   10.68  						   RAZOR_DETAIL_NAME, &name,
   10.69  						   RAZOR_DETAIL_VERSION, &version,
   10.70  						   RAZOR_DETAIL_LAST)) {
   10.71 +#if 0
   10.72  			fprintf(stderr, "updating %s %s because it "
   10.73  				"conflicts with %s\n",
   10.74  				name, version, spi.pool + sp->name);
   10.75 +#endif
   10.76  			trans->system.packages[pkg - spkgs] |=
   10.77  				TRANS_PACKAGE_UPDATE;
   10.78  		}
   10.79 @@ -640,6 +649,7 @@
   10.80  
   10.81  		rpi->present[rp - rpi->start] |= TRANS_PROPERTY_SATISFIED;
   10.82  
   10.83 +#if 0
   10.84  		fprintf(stderr, "pulling in %s-%s.%s which provides %s %s %s "
   10.85  			"to satisfy %s %s %s\n",
   10.86  			ppi->pool + pkg->name,
   10.87 @@ -651,6 +661,7 @@
   10.88  			&rpi->pool[rp->name],
   10.89  			razor_property_relation_to_string(rp),
   10.90  			&rpi->pool[rp->version]);
   10.91 +#endif
   10.92  
   10.93  		trans->upstream.packages[pkg - upkgs] |= TRANS_PACKAGE_UPDATE;
   10.94  	}
   10.95 @@ -736,7 +747,9 @@
   10.96  						  RAZOR_PROPERTY_LESS,
   10.97  						  version);
   10.98  		razor_transaction_install_package(trans, p);
   10.99 +#if 0
  10.100  		fprintf(stderr, "installing %s-%s\n", name, version);
  10.101 +#endif
  10.102  	}
  10.103  }
  10.104  
    11.1 --- a/librazor/util.c	Thu Aug 25 14:22:52 2011 +0100
    11.2 +++ b/librazor/util.c	Thu Nov 10 10:35:21 2011 +0000
    11.3 @@ -1,7 +1,7 @@
    11.4  /*
    11.5   * Copyright (C) 2008  Kristian Høgsberg <krh@redhat.com>
    11.6   * Copyright (C) 2008  Red Hat, Inc
    11.7 - * Copyright (C) 2009  J. Ali Harlow <ali@juiblex.co.uk>
    11.8 + * Copyright (C) 2009, 2011  J. Ali Harlow <ali@juiblex.co.uk>
    11.9   *
   11.10   * This program is free software; you can redistribute it and/or modify
   11.11   * it under the terms of the GNU General Public License as published by
   11.12 @@ -33,6 +33,8 @@
   11.13  #ifdef MSWIN_API
   11.14  #include <windows.h>
   11.15  #include <direct.h>
   11.16 +#else
   11.17 +#include <sys/utsname.h>
   11.18  #endif
   11.19  #if HAVE_SYS_MMAN_H
   11.20  #include <sys/mman.h>
   11.21 @@ -46,137 +48,9 @@
   11.22  #define O_BINARY	0
   11.23  #endif
   11.24  
   11.25 -#define RAZOR_ASCII_ISALPHA(c)	\
   11.26 -			((c) >= 'A' && (c) <= 'Z' || (c) >= 'a' && (c) <= 'z')
   11.27 -
   11.28  /* Required by gnulib on non-libc platforms */
   11.29  char *program_name = "librazor";
   11.30  
   11.31 -static int allow_all_root_names = 0;
   11.32 -
   11.33 -/*
   11.34 - * Primarily intended for testing named roots under UNIX platforms.
   11.35 - */
   11.36 -RAZOR_EXPORT void razor_disable_root_name_checks(int disable)
   11.37 -{
   11.38 -	allow_all_root_names = disable;
   11.39 -}
   11.40 -
   11.41 -static int razor_valid_root_name(const char *name)
   11.42 -{
   11.43 -	if (allow_all_root_names)
   11.44 -		return !strchr(name,'/');
   11.45 -
   11.46 -#ifdef MSWIN_API
   11.47 -	return RAZOR_ASCII_ISALPHA(name[0]) && name[1] == ':' &&
   11.48 -	       name[2] == '\0';
   11.49 -#else
   11.50 -	return name[0] == '\0';
   11.51 -#endif
   11.52 -}
   11.53 -
   11.54 -int
   11.55 -razor_create_dir(const char *root, const char *path)
   11.56 -{
   11.57 -	char buffer[PATH_MAX], *p;
   11.58 -	const char *slash, *next;
   11.59 -	struct stat buf;
   11.60 -
   11.61 -	/* Create all sub-directories in dir. We know root exists and
   11.62 -	 * is a dir, root does not end in a '/', and path either has a
   11.63 -	 * leading '/' or (on MS-Windows only) root is the empty string
   11.64 -	 * and path starts with drive (eg., "c:/windows"). */
   11.65 -
   11.66 -	strcpy(buffer, root);
   11.67 -	p = buffer + strlen(buffer);
   11.68 -	slash = path;
   11.69 -	for (slash = path; *slash != '\0'; slash = next) {
   11.70 -		next = strchr(slash + 1, '/');
   11.71 -		if (next == NULL)
   11.72 -			break;
   11.73 -
   11.74 -		memcpy(p, slash, next - slash);
   11.75 -		p += next - slash;
   11.76 -		*p = '\0';
   11.77 -
   11.78 -		if (razor_valid_root_name(buffer))
   11.79 -			continue;
   11.80 -
   11.81 -		if (stat(buffer, &buf) == 0) {
   11.82 -			if (!S_ISDIR(buf.st_mode)) {
   11.83 -				fprintf(stderr,
   11.84 -					"%s exists but is not a directory\n",
   11.85 -					buffer);
   11.86 -				return -1;
   11.87 -			}
   11.88 -		} else if (mkdir(buffer, 0777) < 0) {
   11.89 -			fprintf(stderr, "failed to make directory %s: %s\n",
   11.90 -				buffer, strerror(errno));
   11.91 -			return -1;
   11.92 -		}
   11.93 -
   11.94 -		/* FIXME: What to do about permissions for dirs we
   11.95 -		 * have to create but are not in the cpio archive? */
   11.96 -	}
   11.97 -
   11.98 -	return 0;
   11.99 -}
  11.100 -
  11.101 -int
  11.102 -razor_remove(const char *path)
  11.103 -{
  11.104 -#ifdef MSWIN_API
  11.105 -	DWORD err;
  11.106 -
  11.107 -	if (DeleteFile(path))
  11.108 -		return 0;
  11.109 -
  11.110 -	err = GetLastError();
  11.111 -	if (err == ERROR_FILE_NOT_FOUND || err == ERROR_PATH_NOT_FOUND)
  11.112 -		return 0;
  11.113 -
  11.114 -	if (SetFileAttributes(path, FILE_ATTRIBUTE_NORMAL) && DeleteFile(path))
  11.115 -		return 0;
  11.116 -
  11.117 -	if (RemoveDirectory(path) || GetLastError() == ERROR_DIR_NOT_EMPTY)
  11.118 -		return 0;
  11.119 -
  11.120 -	/*
  11.121 -	 * It would be tempting to use:
  11.122 -	 * 	MoveFileEx(path, NULL, MOVEFILE_DELAY_UNTIL_REBOOT)
  11.123 -	 * but unless we can guarantee that the system will be rebooted
  11.124 -	 * before we (or some other application) write another file with the
  11.125 -	 * same path, this is likely to cause more problems than it solves.
  11.126 -	 */
  11.127 -
  11.128 -	/* Use remove() as a fallback so that errno is set appropriately */
  11.129 -#endif
  11.130 -
  11.131 -	return remove(path);
  11.132 -}
  11.133 -
  11.134 -int
  11.135 -razor_write(int fd, const void *data, size_t size)
  11.136 -{
  11.137 -	size_t rest;
  11.138 -	ssize_t written;
  11.139 -	const unsigned char *p;
  11.140 -
  11.141 -	rest = size;
  11.142 -	p = data;
  11.143 -	while (rest > 0) {
  11.144 -		written = write(fd, p, rest);
  11.145 -		if (written < 0) {
  11.146 -			perror("write error");
  11.147 -			return -1;
  11.148 -		}
  11.149 -		rest -= written;
  11.150 -		p += written;
  11.151 -	}
  11.152 -
  11.153 -	return 0;
  11.154 -}
  11.155 -
  11.156  void *
  11.157  razor_file_get_contents(const char *filename, size_t *length)
  11.158  {
  11.159 @@ -225,7 +99,6 @@
  11.160  	return addr;
  11.161  }
  11.162  
  11.163 -int
  11.164  razor_file_free_contents(void *addr, size_t length)
  11.165  {
  11.166  #if HAVE_SYS_MMAN_H
  11.167 @@ -396,3 +269,66 @@
  11.168  	array_release(&env->string_pool);
  11.169  	array_release(&env->vars);
  11.170  }
  11.171 +
  11.172 +RAZOR_EXPORT char *razor_concat(const char *s, ...)
  11.173 +{
  11.174 +	va_list args;
  11.175 +	const char *string;
  11.176 +	char *concat;
  11.177 +	size_t n, len;
  11.178 +
  11.179 +	va_start(args, s);
  11.180 +
  11.181 +	len = strlen(s);
  11.182 +	while((string = va_arg(args, const char *)))
  11.183 +		len += strlen(string);
  11.184 +
  11.185 +	va_end(args);
  11.186 +
  11.187 +	concat = malloc(len + 1);
  11.188 +
  11.189 +	if (!concat)
  11.190 +		return NULL;
  11.191 +
  11.192 +	va_start(args, s);
  11.193 +
  11.194 +	len = strlen(s);
  11.195 +	memcpy(concat, s, len);
  11.196 +	n = len;
  11.197 +	while((string = va_arg(args, const char *))) {
  11.198 +		len = strlen(string);
  11.199 +		memcpy(concat + n, string, len);
  11.200 +		n += len;
  11.201 +	}
  11.202 +
  11.203 +	va_end(args);
  11.204 +
  11.205 +	concat[n] = '\0';
  11.206 +
  11.207 +	return concat;
  11.208 +}
  11.209 +
  11.210 +RAZOR_EXPORT const char *razor_system_arch(void)
  11.211 +{
  11.212 +#ifdef MSWIN_API
  11.213 +	SYSTEM_INFO si;
  11.214 +
  11.215 +	GetNativeSystemInfo(&si);
  11.216 +	switch(si.wProcessorArchitecture)
  11.217 +	{
  11.218 +		case PROCESSOR_ARCHITECTURE_INTEL:
  11.219 +			return "i686";
  11.220 +		case PROCESSOR_ARCHITECTURE_AMD64:
  11.221 +			return "x86_64";
  11.222 +		default:
  11.223 +			return NULL;
  11.224 +	}
  11.225 +#else
  11.226 +	static struct utsname un;
  11.227 +
  11.228 +	if (uname(&un))
  11.229 +		return NULL;
  11.230 +	else
  11.231 +		return un.machine;
  11.232 +#endif
  11.233 +}
    12.1 --- a/src/main.c	Thu Aug 25 14:22:52 2011 +0100
    12.2 +++ b/src/main.c	Thu Nov 10 10:35:21 2011 +0000
    12.3 @@ -1,7 +1,7 @@
    12.4  /*
    12.5   * Copyright (C) 2008  Kristian Høgsberg <krh@redhat.com>
    12.6   * Copyright (C) 2008  Red Hat, Inc
    12.7 - * Copyright (C) 2009  J. Ali Harlow <ali@juiblex.co.uk>
    12.8 + * Copyright (C) 2009, 2011  J. Ali Harlow <ali@juiblex.co.uk>
    12.9   *
   12.10   * This program is free software; you can redistribute it and/or modify
   12.11   * it under the terms of the GNU General Public License as published by
   12.12 @@ -49,8 +49,11 @@
   12.13  #define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
   12.14  
   12.15  static int
   12.16 -update_packages(struct razor_transaction *trans, struct razor_set *system,
   12.17 -		struct razor_set *next, struct razor_relocations *relocations);
   12.18 +update_packages(struct razor_transaction *trans,
   12.19 +		struct razor_install_iterator *ii, struct razor_set *system,
   12.20 +		struct razor_set *next, struct razor_atomic *atomic,
   12.21 +		struct razor_relocations *relocations,
   12.22 +		enum razor_stage_type stage);
   12.23  
   12.24  static struct razor_package_iterator *
   12.25  create_iterator_from_argv(struct razor_set *set, int argc, const char *argv[])
   12.26 @@ -113,6 +116,7 @@
   12.27  command_list(int argc, const char *argv[])
   12.28  {
   12.29  	struct razor_package_iterator *pi;
   12.30 +	struct razor_atomic *atomic;
   12.31  	struct razor_set *set;
   12.32  	uint32_t flags = 0;
   12.33  	int i = 0;
   12.34 @@ -122,14 +126,19 @@
   12.35  		i++;
   12.36  	}
   12.37  
   12.38 -	set = razor_root_open_read_only(install_root);
   12.39 -	if (set == NULL)
   12.40 +	atomic = razor_atomic_open("List installed packages");
   12.41 +	set = razor_root_open_read_only(install_root, atomic);
   12.42 +	if (set == NULL) {
   12.43 +		fprintf(stderr, "%s\n", razor_atomic_get_error_msg(atomic));
   12.44 +		razor_atomic_destroy(atomic);
   12.45  		return 1;
   12.46 +	}
   12.47  
   12.48  	pi = create_iterator_from_argv(set, argc - i, argv + i);
   12.49  	list_packages(pi, flags);
   12.50  	razor_package_iterator_destroy(pi);
   12.51 -	razor_set_destroy(set);
   12.52 +	razor_set_unref(set);
   12.53 +	razor_atomic_destroy(atomic);
   12.54  
   12.55  	return 0;
   12.56  }
   12.57 @@ -175,13 +184,18 @@
   12.58  list_properties(int argc, const char *argv[], uint32_t type)
   12.59  {
   12.60  	struct razor_set *set;
   12.61 +	struct razor_atomic *atomic;
   12.62  	struct razor_package *package;
   12.63  	struct razor_package_iterator *pi;
   12.64  	const char *name, *version, *arch;
   12.65  
   12.66 -	set = razor_root_open_read_only(install_root);
   12.67 -	if (set == NULL)
   12.68 +	atomic = razor_atomic_open("List package properties");
   12.69 +	set = razor_root_open_read_only(install_root, atomic);
   12.70 +	if (set == NULL) {
   12.71 +		fprintf(stderr, "%s\n", razor_atomic_get_error_msg(atomic));
   12.72 +		razor_atomic_destroy(atomic);
   12.73  		return 1;
   12.74 +	}
   12.75  
   12.76  	pi = create_iterator_from_argv(set, argc, argv);
   12.77  	while (razor_package_iterator_next(pi, &package,
   12.78 @@ -191,7 +205,8 @@
   12.79  					   RAZOR_DETAIL_LAST))
   12.80  		list_package_properties(set, package, type);
   12.81  	razor_package_iterator_destroy(pi);
   12.82 -	razor_set_destroy(set);
   12.83 +	razor_set_unref(set);
   12.84 +	razor_atomic_destroy(atomic);
   12.85  
   12.86  	return 0;
   12.87  }
   12.88 @@ -224,13 +239,18 @@
   12.89  command_list_scripts(int argc, const char *argv[])
   12.90  {
   12.91  	struct razor_set *set;
   12.92 +	struct razor_atomic *atomic;
   12.93  	struct razor_package *package;
   12.94  	struct razor_package_iterator *pi;
   12.95  	const char *preunprog, *preun, *postunprog, *postun;
   12.96  
   12.97 -	set = razor_root_open_read_only(install_root);
   12.98 -	if (set == NULL)
   12.99 +	atomic = razor_atomic_open("List package scripts");
  12.100 +	set = razor_root_open_read_only(install_root, atomic);
  12.101 +	if (set == NULL) {
  12.102 +		fprintf(stderr, "%s\n", razor_atomic_get_error_msg(atomic));
  12.103 +		razor_atomic_destroy(atomic);
  12.104  		return 1;
  12.105 +	}
  12.106  
  12.107  	pi = create_iterator_from_argv(set, argc, argv);
  12.108  	while (razor_package_iterator_next(pi, &package,
  12.109 @@ -253,7 +273,8 @@
  12.110  		}
  12.111  	}
  12.112  	razor_package_iterator_destroy(pi);
  12.113 -	razor_set_destroy(set);
  12.114 +	razor_set_unref(set);
  12.115 +	razor_atomic_destroy(atomic);
  12.116  
  12.117  	return 0;
  12.118  }
  12.119 @@ -261,14 +282,20 @@
  12.120  static int
  12.121  command_list_files(int argc, const char *argv[])
  12.122  {
  12.123 +	struct razor_atomic *atomic;
  12.124  	struct razor_set *set;
  12.125  
  12.126 -	set = razor_root_open_read_only(install_root);
  12.127 -	if (set == NULL)
  12.128 +	atomic = razor_atomic_open("List package files");
  12.129 +	set = razor_root_open_read_only(install_root, atomic);
  12.130 +	if (set == NULL) {
  12.131 +		fprintf(stderr, "%s\n", razor_atomic_get_error_msg(atomic));
  12.132 +		razor_atomic_destroy(atomic);
  12.133  		return 1;
  12.134 +	}
  12.135  
  12.136  	razor_set_list_files(set, argv[0]);
  12.137 -	razor_set_destroy(set);
  12.138 +	razor_set_unref(set);
  12.139 +	razor_atomic_destroy(atomic);
  12.140  
  12.141  	return 0;
  12.142  }
  12.143 @@ -276,18 +303,24 @@
  12.144  static int
  12.145  command_list_file_packages(int argc, const char *argv[])
  12.146  {
  12.147 +	struct razor_atomic *atomic;
  12.148  	struct razor_set *set;
  12.149  	struct razor_package_iterator *pi;
  12.150  
  12.151 -	set = razor_root_open_read_only(install_root);
  12.152 -	if (set == NULL)
  12.153 +	atomic = razor_atomic_open("List file packages");
  12.154 +	set = razor_root_open_read_only(install_root, atomic);
  12.155 +	if (set == NULL) {
  12.156 +		fprintf(stderr, "%s\n", razor_atomic_get_error_msg(atomic));
  12.157 +		razor_atomic_destroy(atomic);
  12.158  		return 1;
  12.159 +	}
  12.160  
  12.161  	pi = razor_package_iterator_create_for_file(set, argv[0]);
  12.162  	list_packages(pi, 0);
  12.163  	razor_package_iterator_destroy(pi);
  12.164  
  12.165 -	razor_set_destroy(set);
  12.166 +	razor_set_unref(set);
  12.167 +	razor_atomic_destroy(atomic);
  12.168  
  12.169  	return 0;
  12.170  }
  12.171 @@ -295,14 +328,19 @@
  12.172  static int
  12.173  command_list_package_files(int argc, const char *argv[])
  12.174  {
  12.175 +	struct razor_atomic *atomic;
  12.176  	struct razor_set *set;
  12.177  	struct razor_package_iterator *pi;
  12.178  	struct razor_package *package;
  12.179  	const char *name, *version, *arch;
  12.180  
  12.181 -	set = razor_root_open_read_only(install_root);
  12.182 -	if (set == NULL)
  12.183 +	atomic = razor_atomic_open("List package files");
  12.184 +	set = razor_root_open_read_only(install_root, atomic);
  12.185 +	if (set == NULL) {
  12.186 +		fprintf(stderr, "%s\n", razor_atomic_get_error_msg(atomic));
  12.187 +		razor_atomic_destroy(atomic);
  12.188  		return 1;
  12.189 +	}
  12.190  
  12.191  	pi = create_iterator_from_argv(set, argc, argv);
  12.192  	while (razor_package_iterator_next(pi, &package,
  12.193 @@ -313,7 +351,8 @@
  12.194  		razor_set_list_package_files(set, package);
  12.195  	razor_package_iterator_destroy(pi);
  12.196  
  12.197 -	razor_set_destroy(set);
  12.198 +	razor_set_unref(set);
  12.199 +	razor_atomic_destroy(atomic);
  12.200  
  12.201  	return 0;
  12.202  }
  12.203 @@ -323,6 +362,7 @@
  12.204  		       const char *ref_version,
  12.205  		       uint32_t type)
  12.206  {
  12.207 +	struct razor_atomic *atomic;
  12.208  	struct razor_set *set;
  12.209  	struct razor_property *property;
  12.210  	struct razor_property_iterator *prop_iter;
  12.211 @@ -333,9 +373,13 @@
  12.212  	if (ref_name == NULL)
  12.213  		return 0;
  12.214  
  12.215 -	set = razor_root_open_read_only(install_root);
  12.216 -	if (set == NULL)
  12.217 +	atomic = razor_atomic_open("List package properties");
  12.218 +	set = razor_root_open_read_only(install_root, atomic);
  12.219 +	if (set == NULL) {
  12.220 +		fprintf(stderr, "%s\n", razor_atomic_get_error_msg(atomic));
  12.221 +		razor_atomic_destroy(atomic);
  12.222  		return 1;
  12.223 +	}
  12.224  
  12.225  	prop_iter = razor_property_iterator_create(set, NULL);
  12.226  	while (razor_property_iterator_next(prop_iter, &property,
  12.227 @@ -357,7 +401,8 @@
  12.228  	}
  12.229  	razor_property_iterator_destroy(prop_iter);
  12.230  
  12.231 -	razor_set_destroy(set);
  12.232 +	razor_set_unref(set);
  12.233 +	razor_atomic_destroy(atomic);
  12.234  
  12.235  	return 0;
  12.236  }
  12.237 @@ -454,7 +499,9 @@
  12.238  static int
  12.239  command_import_yum(int argc, const char *argv[])
  12.240  {
  12.241 +	int retval;
  12.242  	struct razor_set *set;
  12.243 +	struct razor_atomic *atomic;
  12.244  	char buffer[512];
  12.245  
  12.246  	printf("downloading from %s.\n", yum_url);
  12.247 @@ -470,14 +517,17 @@
  12.248  	set = razor_set_create_from_yum();
  12.249  	if (set == NULL)
  12.250  		return 1;
  12.251 -	if (razor_set_write(set, rawhide_repo_filename, RAZOR_SECTION_ALL)) {
  12.252 -		perror(rawhide_repo_filename);
  12.253 -		return -1;
  12.254 -	}
  12.255 -	razor_set_destroy(set);
  12.256 -	printf("wrote %s\n", rawhide_repo_filename);
  12.257 +	atomic = razor_atomic_open("Yum import repository");
  12.258 +	razor_set_write(set, atomic, rawhide_repo_filename, RAZOR_SECTION_ALL);
  12.259 +	retval = razor_atomic_commit(atomic);
  12.260 +	razor_set_unref(set);
  12.261 +	if (retval)
  12.262 +		fprintf(stderr, "%s\n", razor_atomic_get_error_msg(atomic));
  12.263 +	else
  12.264 +		printf("wrote %s\n", rawhide_repo_filename);
  12.265 +	razor_atomic_destroy(atomic);
  12.266  
  12.267 -	return 0;
  12.268 +	return retval;
  12.269  }
  12.270  
  12.271  #if HAVE_RPMLIB
  12.272 @@ -486,10 +536,17 @@
  12.273  {
  12.274  	struct razor_set *set;
  12.275  	struct razor_root *root;
  12.276 +	struct razor_atomic *atomic;
  12.277 +	int retval;
  12.278  
  12.279 -	root = razor_root_open(install_root);
  12.280 -	if (root == NULL)
  12.281 +	atomic = razor_atomic_open("Import RPM database");
  12.282 +
  12.283 +	root = razor_root_open(install_root, atomic);
  12.284 +	if (root == NULL) {
  12.285 +		fprintf(stderr, "%s\n", razor_atomic_get_error_msg(atomic));
  12.286 +		razor_atomic_destroy(atomic);
  12.287  		return 1;
  12.288 +	}
  12.289  
  12.290  	set = razor_set_create_from_rpmdb();
  12.291  	if (set == NULL)
  12.292 @@ -497,7 +554,13 @@
  12.293  
  12.294  	razor_root_update(root, set);
  12.295  
  12.296 -	return razor_root_commit(root);
  12.297 +	retval = razor_root_commit(root);
  12.298 +	if (retval)
  12.299 +		fprintf(stderr, "%s\n", razor_atomic_get_error_msg(atomic));
  12.300 +
  12.301 +	razor_atomic_destroy(atomic);
  12.302 +
  12.303 +	return retval;
  12.304  }
  12.305  #endif
  12.306  
  12.307 @@ -553,45 +616,69 @@
  12.308  	struct razor_root *root;
  12.309  	struct razor_set *system, *upstream, *next;
  12.310  	struct razor_transaction *trans;
  12.311 -	int i, errors;
  12.312 +	struct razor_atomic *atomic;
  12.313 +	struct razor_install_iterator *ii;
  12.314 +	int i, retval;
  12.315  
  12.316 -	root = razor_root_open(install_root);
  12.317 -	system = razor_root_get_system_set(root);
  12.318 +	atomic = razor_atomic_open("Remove packages");
  12.319 +
  12.320 +	root = razor_root_open(install_root, atomic);
  12.321 +	system = razor_set_ref(razor_root_get_system_set(root));
  12.322  	if (system == NULL) {
  12.323 +		fprintf(stderr, "%s\n", razor_atomic_get_error_msg(atomic));
  12.324  		razor_root_close(root);
  12.325 +		razor_atomic_destroy(atomic);
  12.326  		return 1;
  12.327  	}
  12.328  
  12.329  	upstream = razor_set_create_without_root();
  12.330  	trans = razor_transaction_create(system, upstream);
  12.331 +	razor_set_unref(upstream);
  12.332  	for (i = 0; i < argc; i++) {
  12.333  		if (mark_packages_for_removal(trans, system, argv[i]) == 0) {
  12.334  			fprintf(stderr, "no match for %s\n", argv[i]);
  12.335  			razor_transaction_destroy(trans);
  12.336 -			razor_set_destroy(upstream);
  12.337 +			razor_set_unref(system);
  12.338  			razor_root_close(root);
  12.339 +			razor_atomic_destroy(atomic);
  12.340  			return 1;
  12.341  		}
  12.342  	}
  12.343  
  12.344  	razor_transaction_resolve(trans);
  12.345 -	errors = razor_transaction_describe(trans);
  12.346 -	if (errors) {
  12.347 +	retval = razor_transaction_describe(trans);
  12.348 +	if (retval) {
  12.349  		razor_transaction_destroy(trans);
  12.350 -		razor_set_destroy(upstream);
  12.351 +		razor_set_unref(system);
  12.352  		razor_root_close(root);
  12.353 +		razor_atomic_destroy(atomic);
  12.354  		return 1;
  12.355  	}
  12.356  
  12.357  	next = razor_transaction_commit(trans);
  12.358 -	update_packages(trans, system, next, NULL);
  12.359 +	ii = razor_set_create_install_iterator(system, next);
  12.360 +	update_packages(trans, ii, system, next, atomic, NULL,
  12.361 +			RAZOR_STAGE_SCRIPTS_PRE);
  12.362 +	update_packages(trans, ii, system, next, atomic, NULL,
  12.363 +			RAZOR_STAGE_FILES);
  12.364 +
  12.365  	razor_root_update(root, next);
  12.366  
  12.367 +	(void)razor_root_commit(root);
  12.368 +	retval = razor_atomic_commit(atomic);
  12.369 +	if (retval)
  12.370 +		fprintf(stderr, "%s\n", razor_atomic_get_error_msg(atomic));
  12.371 +	else
  12.372 +		update_packages(trans, ii, system, next, atomic, NULL,
  12.373 +				RAZOR_STAGE_SCRIPTS_POST);
  12.374 +	razor_install_iterator_destroy(ii);
  12.375 +
  12.376  	razor_transaction_destroy(trans);
  12.377 -	razor_set_destroy(next);
  12.378 -	razor_set_destroy(upstream);
  12.379 +	razor_atomic_destroy(atomic);
  12.380 +	razor_set_unref(system);
  12.381 +	razor_set_unref(next);
  12.382  
  12.383 -	return razor_root_commit(root);
  12.384 +	return retval;
  12.385  }
  12.386  
  12.387  static void
  12.388 @@ -611,17 +698,23 @@
  12.389  static int
  12.390  command_diff(int argc, const char *argv[])
  12.391  {
  12.392 +	struct razor_atomic *atomic;
  12.393  	struct razor_set *set, *updated;
  12.394  
  12.395 -	set = razor_root_open_read_only(install_root);
  12.396 -	updated = razor_set_open(rawhide_repo_filename);
  12.397 -	if (set == NULL || updated == NULL)
  12.398 +	atomic = razor_atomic_open("Show package differences");
  12.399 +	set = razor_root_open_read_only(install_root, atomic);
  12.400 +	updated = razor_set_open(rawhide_repo_filename, atomic);
  12.401 +	if (set == NULL || updated == NULL) {
  12.402 +		fprintf(stderr, "%s\n", razor_atomic_get_error_msg(atomic));
  12.403 +		razor_atomic_destroy(atomic);
  12.404  		return 1;
  12.405 +	}
  12.406  
  12.407  	razor_set_diff(set, updated, print_diff, NULL);
  12.408  
  12.409 -	razor_set_destroy(set);
  12.410 -	razor_set_destroy(updated);
  12.411 +	razor_set_unref(set);
  12.412 +	razor_set_unref(updated);
  12.413 +	razor_atomic_destroy(atomic);
  12.414  
  12.415  	return 0;
  12.416  }
  12.417 @@ -634,9 +727,11 @@
  12.418  	struct razor_importer *importer;
  12.419  	struct razor_set *set;
  12.420  	struct razor_rpm *rpm;
  12.421 +	struct razor_atomic *atomic;
  12.422  	int len, imported_count = 0;
  12.423  	char filename[256];
  12.424  	const char *dirname = argv[0];
  12.425 +	int retval;
  12.426  
  12.427  	if (dirname == NULL) {
  12.428  		fprintf(stderr, "usage: razor import-rpms DIR\n");
  12.429 @@ -654,15 +749,17 @@
  12.430  	while (de = readdir(dir), de != NULL) {
  12.431  		len = strlen(de->d_name);
  12.432  		if (len < 5 || strcmp(de->d_name + len - 4, ".rpm") != 0)
  12.433 -		    continue;
  12.434 +			continue;
  12.435  		snprintf(filename, sizeof filename,
  12.436  			 "%s/%s", dirname, de->d_name);
  12.437 -		rpm = razor_rpm_open(filename);
  12.438 -		if (rpm == NULL) {
  12.439 -			fprintf(stderr,
  12.440 -				"failed to open rpm \"%s\"\n", filename);
  12.441 +		atomic = razor_atomic_open("Read RPM");
  12.442 +		rpm = razor_rpm_open(filename, atomic);
  12.443 +		if (rpm == NULL)
  12.444 +			fprintf(stderr, "%s\n",
  12.445 +				razor_atomic_get_error_msg(atomic));
  12.446 +		razor_atomic_destroy(atomic);
  12.447 +		if (rpm == NULL)
  12.448  			continue;
  12.449 -		}
  12.450  		if (razor_importer_add_rpm(importer, rpm)) {
  12.451  			fprintf(stderr, "couldn't import %s\n", filename);
  12.452  			break;
  12.453 @@ -681,17 +778,22 @@
  12.454  	printf("\nsaving\n");
  12.455  	set = razor_importer_finish(importer);
  12.456  
  12.457 -	razor_set_write(set, repo_filename, RAZOR_SECTION_ALL);
  12.458 -	razor_set_destroy(set);
  12.459 -	printf("wrote %s\n", repo_filename);
  12.460 +	atomic = razor_atomic_open("Update system database");
  12.461 +	razor_set_write(set, atomic, repo_filename, RAZOR_SECTION_ALL);
  12.462 +	razor_set_unref(set);
  12.463 +	retval = razor_atomic_commit(atomic);
  12.464 +	if (retval)
  12.465 +		fprintf(stderr, "%s\n", razor_atomic_get_error_msg(atomic));
  12.466 +	else
  12.467 +		printf("wrote %s\n", repo_filename);
  12.468 +	razor_atomic_destroy(atomic);
  12.469  
  12.470 -	return 0;
  12.471 +	return retval;
  12.472  }
  12.473  
  12.474 -static const char *
  12.475 +static char *
  12.476  rpm_filename(const char *name, const char *version, const char *arch)
  12.477  {
  12.478 -	static char file[PATH_MAX];
  12.479   	const char *v;
  12.480   
  12.481   	/* Skip epoch */
  12.482 @@ -701,9 +803,7 @@
  12.483   	else
  12.484  		v = version;
  12.485  
  12.486 -	snprintf(file, sizeof file, "%s-%s.%s.rpm", name, v, arch);
  12.487 -
  12.488 -	return file;
  12.489 +	return razor_concat(name, "-", v, ".", arch, ".rpm", NULL);
  12.490  }
  12.491  
  12.492  static int
  12.493 @@ -713,7 +813,7 @@
  12.494  	struct razor_package *package;
  12.495  	enum razor_install_action action;
  12.496  	const char *name, *version, *arch;
  12.497 -	char file[PATH_MAX], url[256];
  12.498 +	char *file, *url, *s;
  12.499  	int errors = 0, count;
  12.500  
  12.501  	ii = razor_set_create_install_iterator(system, next);
  12.502 @@ -727,13 +827,14 @@
  12.503  					  RAZOR_DETAIL_ARCH, &arch,
  12.504  					  RAZOR_DETAIL_LAST);
  12.505  		
  12.506 -		snprintf(url, sizeof url,
  12.507 -			 "%s/Packages/%s",
  12.508 -			 yum_url, rpm_filename(name, version, arch));
  12.509 -		snprintf(file, sizeof file,
  12.510 -			 "rpms/%s", rpm_filename(name, version, arch));
  12.511 +		s = rpm_filename(name, version, arch);
  12.512 +		url = razor_concat(yum_url, "/Packages/", s, NULL);
  12.513 +		file = razor_concat("rpms/", s, NULL);
  12.514 +		free(s);
  12.515  		if (download_if_missing(url, file) < 0)
  12.516  			errors++;
  12.517 +		free(file);
  12.518 +		free(url);
  12.519  	}
  12.520  	razor_install_iterator_destroy(ii);
  12.521  
  12.522 @@ -746,7 +847,8 @@
  12.523  }
  12.524  
  12.525  static struct razor_set *
  12.526 -relocate_packages(struct razor_set *set, struct razor_relocations *relocations)
  12.527 +relocate_packages(struct razor_set *set, struct razor_atomic *atomic,
  12.528 +		  struct razor_relocations *relocations)
  12.529  {
  12.530  	int i;
  12.531  	struct razor_importer *importer;
  12.532 @@ -760,7 +862,7 @@
  12.533  	const char *preunprog, *preun, *postunprog, *postun;
  12.534  	const char *install_prefix;
  12.535  	const char *const *prefixes;
  12.536 -	char file[PATH_MAX];
  12.537 +	char *file, *s;
  12.538  	uint32_t flags;
  12.539  
  12.540  	importer = razor_importer_create();
  12.541 @@ -779,11 +881,12 @@
  12.542  					   RAZOR_DETAIL_POSTUNPROG, &postunprog,
  12.543  					   RAZOR_DETAIL_POSTUN, &postun,
  12.544  					   RAZOR_DETAIL_LAST)) {
  12.545 -		snprintf(file, sizeof file,
  12.546 -			 "rpms/%s", rpm_filename(name, version, arch));
  12.547 -		rpm = razor_rpm_open(file);
  12.548 +		s = rpm_filename(name, version, arch);
  12.549 +		file = razor_concat("rpms/", s, NULL);
  12.550 +		free(s);
  12.551 +		rpm = razor_rpm_open(file, atomic);
  12.552 +		free(file);
  12.553  		if (rpm == NULL) {
  12.554 -			fprintf(stderr, "failed to open rpm %s\n", file);
  12.555  			razor_package_iterator_destroy(pkg_iter);
  12.556  			razor_importer_destroy(importer);
  12.557  			return NULL;
  12.558 @@ -834,12 +937,13 @@
  12.559  
  12.560  static int
  12.561  install_package(struct razor_transaction *trans, struct razor_set *set,
  12.562 -		struct razor_package *package,
  12.563 -		struct razor_relocations *relocations)
  12.564 +		struct razor_atomic *atomic, struct razor_package *package,
  12.565 +		struct razor_relocations *relocations, int install_count,
  12.566 +		enum razor_stage_type stage)
  12.567  {
  12.568  	int retval;
  12.569  	const char *name, *version, *arch;
  12.570 -	char file[PATH_MAX];
  12.571 +	char *file, *s;
  12.572  	struct razor_rpm *rpm;
  12.573  
  12.574  	razor_package_get_details(set, package,
  12.575 @@ -848,45 +952,57 @@
  12.576  				  RAZOR_DETAIL_ARCH, &arch,
  12.577  				  RAZOR_DETAIL_LAST);
  12.578  
  12.579 -	printf("install %s-%s\n", name, version);
  12.580 +	if (stage & RAZOR_STAGE_SCRIPTS_PRE)
  12.581 +		printf("install %s-%s\n", name, version);
  12.582  
  12.583 -	snprintf(file, sizeof file,
  12.584 -		 "rpms/%s", rpm_filename(name, version, arch));
  12.585 -	rpm = razor_rpm_open(file);
  12.586 +	s = rpm_filename(name, version, arch);
  12.587 +	file = razor_concat("rpms/", s, NULL);
  12.588 +	free(s);
  12.589 +	rpm = razor_rpm_open(file, atomic);
  12.590 +	free(file);
  12.591  	if (rpm == NULL) {
  12.592 -		fprintf(stderr, "failed to open rpm %s\n", file);
  12.593 +		fprintf(stderr, "%s\n",
  12.594 +			razor_atomic_get_error_msg(atomic));
  12.595  		return -1;
  12.596  	}
  12.597  	if (relocations)
  12.598  		razor_rpm_set_relocations(rpm, relocations);
  12.599  	razor_transaction_fixup_package(trans, package, rpm);
  12.600 -	retval = razor_rpm_install(rpm, install_root, 1);
  12.601 -	if (retval < 0)
  12.602 -		fprintf(stderr, "failed to install rpm %s\n", file);
  12.603 +	retval = razor_rpm_install(rpm, atomic, install_root, install_count,
  12.604 +				   stage);
  12.605 +	if (retval < 0) {
  12.606 +		s = rpm_filename(name, version, arch);
  12.607 +		fprintf(stderr, "%s: %s\n", s,
  12.608 +			razor_atomic_get_error_msg(atomic));
  12.609 +		free(s);
  12.610 +	}
  12.611  	razor_rpm_close(rpm);
  12.612  	return retval;
  12.613  }
  12.614  
  12.615  static int
  12.616 -update_packages(struct razor_transaction *trans, struct razor_set *system,
  12.617 -		struct razor_set *next, struct razor_relocations *relocations)
  12.618 +update_packages(struct razor_transaction *trans,
  12.619 +		struct razor_install_iterator *ii, struct razor_set *system,
  12.620 +		struct razor_set *next, struct razor_atomic *atomic,
  12.621 +		struct razor_relocations *relocations,
  12.622 +		enum razor_stage_type stage)
  12.623  {
  12.624 -	struct razor_install_iterator *ii;
  12.625  	struct razor_package *package;
  12.626  	enum razor_install_action action;
  12.627  	int retval = 0, count;
  12.628  
  12.629 -	ii = razor_set_create_install_iterator(system, next);
  12.630 +	razor_install_iterator_rewind(ii);
  12.631 +
  12.632  	while (!retval && razor_install_iterator_next(ii, &package,
  12.633  						      &action, &count)) {
  12.634  		if (action == RAZOR_INSTALL_ACTION_ADD)
  12.635 -			retval = install_package(trans, next, package,
  12.636 -						 relocations);
  12.637 +			retval = install_package(trans, next, atomic, package,
  12.638 +						 relocations, count, stage);
  12.639  		else if (action == RAZOR_INSTALL_ACTION_REMOVE)
  12.640 -			retval = razor_package_remove(system, next, package,
  12.641 -						      install_root, count);
  12.642 +			retval = razor_package_remove(system, next, atomic,
  12.643 +						      package, install_root,
  12.644 +						      count, stage);
  12.645  	}
  12.646 -	razor_install_iterator_destroy(ii);
  12.647  
  12.648  	return retval;
  12.649  }
  12.650 @@ -898,12 +1014,22 @@
  12.651  	struct razor_relocations *relocations=NULL;
  12.652  	struct razor_set *system, *upstream, *next, *set;
  12.653  	struct razor_transaction *trans;
  12.654 -	int i, len, dependencies = 1;
  12.655 +	struct razor_atomic *atomic;
  12.656 +	struct razor_install_iterator *ii;
  12.657 +	int i, retval, len, dependencies = 1;
  12.658  	char *oldpath;
  12.659  
  12.660 -	root = razor_root_open(install_root);
  12.661 -	if (root == NULL)
  12.662 +	if (do_update)
  12.663 +		atomic = razor_atomic_open("Update packages");
  12.664 +	else
  12.665 +		atomic = razor_atomic_open("Install packages");
  12.666 +
  12.667 +	root = razor_root_open(install_root, atomic);
  12.668 +	if (root == NULL) {
  12.669 +		fprintf(stderr, "%s\n", razor_atomic_get_error_msg(atomic));
  12.670 +		razor_atomic_destroy(atomic);
  12.671  		return 1;
  12.672 +	}
  12.673  
  12.674  	for (i = 0; i < argc; i++) {
  12.675  		if (strcmp(argv[i], "--no-dependencies") == 0)
  12.676 @@ -933,19 +1059,30 @@
  12.677  			break;
  12.678  	}
  12.679  
  12.680 -	system = razor_root_get_system_set(root);
  12.681 -	upstream = razor_set_open(rawhide_repo_filename);
  12.682 +	upstream = razor_set_open(rawhide_repo_filename, atomic);
  12.683  	if (upstream == NULL) {
  12.684 +		fprintf(stderr, "%s\n", razor_atomic_get_error_msg(atomic));
  12.685  		razor_root_close(root);
  12.686 +		razor_atomic_destroy(atomic);
  12.687  		return 1;
  12.688  	}
  12.689  
  12.690  	if (relocations) {
  12.691 -		set = relocate_packages(upstream, relocations);
  12.692 -		razor_set_destroy(upstream);
  12.693 +		set = relocate_packages(upstream, atomic, relocations);
  12.694 +		if (set == NULL) {
  12.695 +			fprintf(stderr, "%s\n",
  12.696 +				razor_atomic_get_error_msg(atomic));
  12.697 +			razor_root_close(root);
  12.698 +			razor_atomic_destroy(atomic);
  12.699 +			razor_set_unref(upstream);
  12.700 +			return 1;
  12.701 +		}
  12.702 +		razor_set_unref(upstream);
  12.703  		upstream = set;
  12.704  	}
  12.705  
  12.706 +	system = razor_set_ref(razor_root_get_system_set(root));
  12.707 +
  12.708  	trans = razor_transaction_create(system, upstream);
  12.709  
  12.710  	if (i == argc && do_update)
  12.711 @@ -957,8 +1094,10 @@
  12.712  		if (mark_packages_for_update(trans, upstream, argv[i]) == 0) {
  12.713  			fprintf(stderr, "no package matched %s\n", argv[i]);
  12.714  			razor_transaction_destroy(trans);
  12.715 -			razor_set_destroy(upstream);
  12.716 +			razor_set_unref(upstream);
  12.717 +			razor_set_unref(system);
  12.718  			razor_root_close(root);
  12.719 +			razor_atomic_destroy(atomic);
  12.720  			return 1;
  12.721  		}
  12.722  	}
  12.723 @@ -967,41 +1106,67 @@
  12.724  		razor_transaction_resolve(trans);
  12.725  		if (razor_transaction_describe(trans) > 0) {
  12.726  			razor_transaction_destroy(trans);
  12.727 -			razor_set_destroy(upstream);
  12.728 +			razor_set_unref(upstream);
  12.729 +			razor_set_unref(system);
  12.730  			razor_root_close(root);
  12.731 +			razor_atomic_destroy(atomic);
  12.732  			return 1;
  12.733  		}
  12.734  	}
  12.735  
  12.736 -	if (mkdir("rpms", 0777) && errno != EEXIST) {
  12.737 -		fprintf(stderr, "failed to create rpms directory.\n");
  12.738 +	if (razor_atomic_create_dir(atomic, "rpms",
  12.739 +				    S_IRWXU | S_IRWXG | S_IRWXO)) {
  12.740 +		fprintf(stderr, "%s\n", razor_atomic_get_error_msg(atomic));
  12.741  		razor_transaction_destroy(trans);
  12.742 -		razor_set_destroy(upstream);
  12.743 +		razor_set_unref(upstream);
  12.744 +		razor_set_unref(system);
  12.745  		razor_root_close(root);
  12.746 +		razor_atomic_destroy(atomic);
  12.747  		return 1;
  12.748  	}
  12.749  
  12.750  	next = razor_transaction_commit(trans);
  12.751  
  12.752  	if (download_packages(system, next) < 0) {
  12.753 -		razor_set_destroy(next);
  12.754 +		razor_set_unref(next);
  12.755  		razor_transaction_destroy(trans);
  12.756 -		razor_set_destroy(upstream);
  12.757 +		razor_set_unref(upstream);
  12.758 +		razor_set_unref(system);
  12.759  		razor_root_close(root);
  12.760 +		razor_atomic_destroy(atomic);
  12.761                  return 1;
  12.762          }
  12.763  
  12.764 -	update_packages(trans, system, next, relocations);
  12.765 +	ii = razor_set_create_install_iterator(system, next);
  12.766 +
  12.767 +	update_packages(trans, ii, system, next, atomic, relocations,
  12.768 +			RAZOR_STAGE_SCRIPTS_PRE);
  12.769 +	update_packages(trans, ii, system, next, atomic, relocations,
  12.770 +			RAZOR_STAGE_FILES);
  12.771  
  12.772  	razor_root_update(root, next);
  12.773  
  12.774 +	razor_set_unref(upstream);
  12.775 +
  12.776 +	(void)razor_root_commit(root);
  12.777 +	retval = razor_atomic_commit(atomic);
  12.778 +	if (retval)
  12.779 +		fprintf(stderr, "%s\n", razor_atomic_get_error_msg(atomic));
  12.780 +	else
  12.781 +		update_packages(trans, ii, system, next, atomic, relocations,
  12.782 +				RAZOR_STAGE_SCRIPTS_POST);
  12.783 +
  12.784  	razor_transaction_destroy(trans);
  12.785  	if (relocations)
  12.786  		razor_relocations_destroy(relocations);
  12.787 -	razor_set_destroy(next);
  12.788 -	razor_set_destroy(upstream);
  12.789 +	razor_install_iterator_destroy(ii);
  12.790  
  12.791 -	return razor_root_commit(root);
  12.792 +	razor_atomic_destroy(atomic);
  12.793 +
  12.794 +	razor_set_unref(next);
  12.795 +	razor_set_unref(system);
  12.796 +
  12.797 +	return retval;
  12.798  }
  12.799  
  12.800  static int
  12.801 @@ -1025,6 +1190,7 @@
  12.802  static int
  12.803  command_download(int argc, const char *argv[])
  12.804  {
  12.805 +	struct razor_atomic *atomic;
  12.806  	struct razor_set *set;
  12.807  	struct razor_package_iterator *pi;
  12.808  	struct razor_package *package;
  12.809 @@ -1032,12 +1198,24 @@
  12.810  	char url[256], file[256];
  12.811  	int matches = 0;
  12.812  
  12.813 -	if (mkdir("rpms", 0777) && errno != EEXIST) {
  12.814 -		fprintf(stderr, "failed to create rpms directory.\n");
  12.815 +	atomic = razor_atomic_open("Download packages");
  12.816 +
  12.817 +	if (razor_atomic_create_dir(atomic, "rpms", 
  12.818 +				    S_IRWXU | S_IRWXG | S_IRWXO)) {
  12.819 +		fprintf(stderr, "%s\n", razor_atomic_get_error_msg(atomic));
  12.820 +		razor_atomic_destroy(atomic);
  12.821  		return 1;
  12.822  	}
  12.823  
  12.824 -	set = razor_set_open(rawhide_repo_filename);
  12.825 +	set = razor_set_open(rawhide_repo_filename, atomic);
  12.826 +
  12.827 +	if (razor_atomic_commit(atomic)) {
  12.828 +		fprintf(stderr, "%s\n", razor_atomic_get_error_msg(atomic));
  12.829 +		razor_atomic_destroy(atomic);
  12.830 +		return 1;
  12.831 +	}
  12.832 +	razor_atomic_destroy(atomic);
  12.833 +
  12.834  	pi = razor_package_iterator_create(set);
  12.835  	while (razor_package_iterator_next(pi, &package,
  12.836  					   RAZOR_DETAIL_NAME, &name,
  12.837 @@ -1056,7 +1234,7 @@
  12.838  		download_if_missing(url, file);
  12.839  	}
  12.840  	razor_package_iterator_destroy(pi);
  12.841 -	razor_set_destroy(set);
  12.842 +	razor_set_unref(set);
  12.843  
  12.844  	if (matches == 0)
  12.845  		fprintf(stderr, "no packages matched \"%s\"\n", pattern);
  12.846 @@ -1071,15 +1249,20 @@
  12.847  static int
  12.848  command_info(int argc, const char *argv[])
  12.849  {
  12.850 +	struct razor_atomic *atomic;
  12.851  	struct razor_set *set;
  12.852  	struct razor_package_iterator *pi;
  12.853  	struct razor_package *package;
  12.854  	const char *pattern = argv[0], *name, *version, *arch;
  12.855  	const char *summary, *description, *url, *license;
  12.856  
  12.857 -	set = razor_root_open_read_only(install_root);
  12.858 -	if (set == NULL)
  12.859 +	atomic = razor_atomic_open("Package info");
  12.860 +	set = razor_root_open_read_only(install_root, atomic);
  12.861 +	if (set == NULL) {
  12.862 +		fprintf(stderr, "%s\n", razor_atomic_get_error_msg(atomic));
  12.863 +		razor_atomic_destroy(atomic);
  12.864  		return 1;
  12.865 +	}
  12.866  
  12.867  	pi = razor_package_iterator_create(set);
  12.868  	while (razor_package_iterator_next(pi, &package,
  12.869 @@ -1108,7 +1291,8 @@
  12.870  		printf ("\n");
  12.871  	}
  12.872  	razor_package_iterator_destroy(pi);
  12.873 -	razor_set_destroy(set);
  12.874 +	razor_set_unref(set);
  12.875 +	razor_atomic_destroy(atomic);
  12.876  
  12.877  	return 0;
  12.878  }
  12.879 @@ -1118,6 +1302,7 @@
  12.880  static int
  12.881  command_search(int argc, const char *argv[])
  12.882  {
  12.883 +	struct razor_atomic *atomic;
  12.884  	struct razor_set *set;
  12.885  	struct razor_package_iterator *pi;
  12.886  	struct razor_package *package;
  12.887 @@ -1132,9 +1317,14 @@
  12.888  
  12.889  	snprintf(pattern, sizeof pattern, "*%s*", argv[0]);
  12.890  
  12.891 -	set = razor_set_open(rawhide_repo_filename);
  12.892 -	if (set == NULL)
  12.893 +	atomic = razor_atomic_open("Search packages");
  12.894 +	set = razor_set_open(rawhide_repo_filename, atomic);
  12.895 +	if (set == NULL || razor_atomic_commit(atomic)) {
  12.896 +		fprintf(stderr, "%s\n", razor_atomic_get_error_msg(atomic));
  12.897 +		razor_atomic_destroy(atomic);
  12.898  		return 1;
  12.899 +	}
  12.900 +	razor_atomic_destroy(atomic);
  12.901  
  12.902  	pi = razor_package_iterator_create(set);
  12.903  	while (razor_package_iterator_next(pi, &package,
  12.904 @@ -1153,7 +1343,7 @@
  12.905  			printf("%s-%s.%s: %s\n", name, version, arch, summary);
  12.906  	}
  12.907  	razor_package_iterator_destroy(pi);
  12.908 -	razor_set_destroy(set);
  12.909 +	razor_set_unref(set);
  12.910  
  12.911  	return 0;
  12.912  }
    13.1 --- a/src/rpm.c	Thu Aug 25 14:22:52 2011 +0100
    13.2 +++ b/src/rpm.c	Thu Nov 10 10:35:21 2011 +0000
    13.3 @@ -1,7 +1,7 @@
    13.4  /*
    13.5   * Copyright (C) 2008  Kristian Høgsberg <krh@redhat.com>
    13.6   * Copyright (C) 2008  Red Hat, Inc
    13.7 - * Copyright (C) 2009  J. Ali Harlow <ali@juiblex.co.uk>
    13.8 + * Copyright (C) 2009, 2011  J. Ali Harlow <ali@juiblex.co.uk>
    13.9   *
   13.10   * This program is free software; you can redistribute it and/or modify
   13.11   * it under the terms of the GNU General Public License as published by
   13.12 @@ -441,13 +441,16 @@
   13.13  create_set_from_command_line(int argc, const char *argv[])
   13.14  {
   13.15  	struct razor_importer *importer;
   13.16 +	struct razor_atomic *atomic;
   13.17  	struct razor_rpm *rpm;
   13.18  	int i;
   13.19  
   13.20  	importer = razor_importer_create();
   13.21  
   13.22  	for (i = 0; i < argc; i++) {
   13.23 -		rpm = razor_rpm_open(argv[i]);
   13.24 +		atomic = razor_atomic_open("Read RPM");
   13.25 +		rpm = razor_rpm_open(argv[i], atomic);
   13.26 +		razor_atomic_destroy(atomic);
   13.27  		if (rpm == NULL)
   13.28  			continue;
   13.29  		if (razor_importer_add_rpm(importer, rpm))
   13.30 @@ -462,17 +465,25 @@
   13.31  static void
   13.32  command_query(int argc, const char *argv[])
   13.33  {
   13.34 +	struct razor_atomic *atomic;
   13.35  	struct razor_set *set;
   13.36  	struct razor_package_iterator *pi;
   13.37  	struct razor_package *package;
   13.38  	const char *name, *version, *arch;
   13.39  
   13.40 +	atomic = razor_atomic_open("Query packages");
   13.41  	if (option_package) {
   13.42  		set = create_set_from_command_line(argc, argv);
   13.43  		argc = 0;
   13.44  		option_all = 1;
   13.45  	} else {
   13.46 -		set = razor_root_open_read_only(option_root);
   13.47 +		set = razor_root_open_read_only(option_root, atomic);
   13.48 +		if (!set) {
   13.49 +			fprintf(stderr, "%s\n",
   13.50 +				razor_atomic_get_error_msg(atomic));
   13.51 +			razor_atomic_destroy(atomic);
   13.52 +			return;
   13.53 +		}
   13.54  	}
   13.55  
   13.56  	pi = get_query_packages(set, argc, argv);
   13.57 @@ -509,25 +520,32 @@
   13.58  
   13.59  	razor_package_iterator_destroy(pi);
   13.60  
   13.61 -	razor_set_destroy(set);
   13.62 -
   13.63 -	return;
   13.64 +	razor_set_unref(set);
   13.65 +	razor_atomic_destroy(atomic);
   13.66  }
   13.67  
   13.68  static void
   13.69  command_verify(int argc, const char *argv[])
   13.70  {
   13.71 +	struct razor_atomic *atomic;
   13.72  	struct razor_set *set;
   13.73  	struct razor_package_iterator *pi;
   13.74  	struct razor_package *package;
   13.75  	const char *name, *version, *arch;
   13.76  
   13.77 +	atomic = razor_atomic_open("Verify packages");
   13.78  	if (option_package) {
   13.79  		set = create_set_from_command_line(argc, argv);
   13.80  		argc = 0;
   13.81  		option_all = 1;
   13.82  	} else {
   13.83 -		set = razor_root_open_read_only(option_root);
   13.84 +		set = razor_root_open_read_only(option_root, atomic);
   13.85 +		if (!set) {
   13.86 +			fprintf(stderr, "%s\n",
   13.87 +				razor_atomic_get_error_msg(atomic));
   13.88 +			razor_atomic_destroy(atomic);
   13.89 +			return;
   13.90 +		}
   13.91  	}
   13.92  
   13.93  	pi = get_query_packages(set, argc, argv);
   13.94 @@ -542,6 +560,7 @@
   13.95  	}
   13.96  
   13.97  	razor_package_iterator_destroy(pi);
   13.98 +	razor_atomic_destroy(atomic);
   13.99  }
  13.100  
  13.101  static void
  13.102 @@ -561,6 +580,7 @@
  13.103  static void
  13.104  command_erase(int argc, const char *argv[])
  13.105  {
  13.106 +	struct razor_atomic *atomic;
  13.107  	struct razor_set *set, *upstream, *next;
  13.108  	struct razor_transaction *trans;
  13.109  	struct razor_package_query *query;
  13.110 @@ -572,7 +592,15 @@
  13.111  		exit(1);
  13.112  	}
  13.113  
  13.114 -	set = razor_set_open(repo_filename);
  13.115 +	atomic = razor_atomic_open("Erase packages");
  13.116 +
  13.117 +	set = razor_set_open(repo_filename, atomic);
  13.118 +	if (!set || razor_atomic_commit(atomic)) {
  13.119 +		fprintf(stderr, "%s\n", razor_atomic_get_error_msg(atomic));
  13.120 +		razor_atomic_destroy(atomic);
  13.121 +		exit(1);
  13.122 +	}
  13.123 +	razor_atomic_destroy(atomic);
  13.124  	upstream = razor_set_create();
  13.125  
  13.126  	trans = razor_transaction_create(set, upstream);
  13.127 @@ -602,15 +630,16 @@
  13.128  		razor_set_diff(set, next, update_package, NULL);
  13.129  
  13.130  	razor_transaction_destroy(trans);
  13.131 -	razor_set_destroy(set);
  13.132 -	razor_set_destroy(upstream);
  13.133 +	razor_set_unref(set);
  13.134 +	razor_set_unref(upstream);
  13.135  
  13.136 -	razor_set_destroy(next);
  13.137 +	razor_set_unref(next);
  13.138  }
  13.139  
  13.140  static void
  13.141  command_install(int argc, const char *argv[])
  13.142  {
  13.143 +	struct razor_atomic *atomic;
  13.144  	struct razor_set *set, *upstream, *next;
  13.145  	struct razor_transaction *trans;
  13.146  	struct razor_package_iterator *pi;
  13.147 @@ -621,7 +650,14 @@
  13.148  		exit(1);
  13.149  	}
  13.150  
  13.151 -	set = razor_set_open(repo_filename);
  13.152 +	atomic = razor_atomic_open("Install packages");
  13.153 +
  13.154 +	set = razor_set_open(repo_filename, atomic);
  13.155 +	if (!set || razor_atomic_commit(atomic)) {
  13.156 +		fprintf(stderr, "%s\n", razor_atomic_get_error_msg(atomic));
  13.157 +		razor_atomic_destroy(atomic);
  13.158 +	}
  13.159 +	razor_atomic_destroy(atomic);
  13.160  	upstream = create_set_from_command_line(argc, argv);
  13.161  
  13.162  	trans = razor_transaction_create(set, upstream);
  13.163 @@ -648,15 +684,16 @@
  13.164  		razor_set_diff(set, next, update_package, NULL);
  13.165  
  13.166  	razor_transaction_destroy(trans);
  13.167 -	razor_set_destroy(set);
  13.168 -	razor_set_destroy(upstream);
  13.169 +	razor_set_unref(set);
  13.170 +	razor_set_unref(upstream);
  13.171  
  13.172 -	razor_set_destroy(next);
  13.173 +	razor_set_unref(next);
  13.174  }
  13.175  
  13.176  static void
  13.177  command_update(int argc, const char *argv[])
  13.178  {
  13.179 +	struct razor_atomic *atomic;
  13.180  	struct razor_set *set, *upstream, *next;
  13.181  	struct razor_transaction *trans;
  13.182  	struct razor_package_iterator *pi;
  13.183 @@ -667,7 +704,14 @@
  13.184  		exit(1);
  13.185  	}
  13.186  
  13.187 -	set = razor_set_open(repo_filename);
  13.188 +	atomic = razor_atomic_open("Update packages");
  13.189 +
  13.190 +	set = razor_set_open(repo_filename, atomic);
  13.191 +	if (!set || razor_atomic_commit(atomic)) {
  13.192 +		fprintf(stderr, "%s\n", razor_atomic_get_error_msg(atomic));
  13.193 +		razor_atomic_destroy(atomic);
  13.194 +	}
  13.195 +	razor_atomic_destroy(atomic);
  13.196  	upstream = create_set_from_command_line(argc, argv);
  13.197  
  13.198  	trans = razor_transaction_create(set, upstream);
  13.199 @@ -694,10 +738,10 @@
  13.200  		razor_set_diff(set, next, update_package, NULL);
  13.201  
  13.202  	razor_transaction_destroy(trans);
  13.203 -	razor_set_destroy(set);
  13.204 -	razor_set_destroy(upstream);
  13.205 +	razor_set_unref(set);
  13.206 +	razor_set_unref(upstream);
  13.207  
  13.208 -	razor_set_destroy(next);
  13.209 +	razor_set_unref(next);
  13.210  }
  13.211  
  13.212  static int