dnl Process this file with autoconf to produce a configure script.
AC_PREREQ(2.59c)
-AC_INIT([razor], [0.4.1], [ali@juiblex.co.uk])
+AC_INIT([razor], [0.5], [ali@juiblex.co.uk])
AM_INIT_AUTOMAKE([])
AM_CONFIG_HEADER([config.h])
AM_MAINTAINER_MODE
#
# See http://sources.redhat.com/autobook/autobook/autobook_91.html#SEC91 for details
#
-LT_CURRENT=1
-LT_REVISION=2
+LT_CURRENT=2
+LT_REVISION=0
LT_AGE=0
AC_SUBST(LT_CURRENT)
AC_SUBST(LT_REVISION)
AM_CONDITIONAL(MSWIN_API, test "$mswin_api" = "yes")
AC_SUBST(EXTRA_LIBS)
+if test "$mswin_api" = "yes"; then
+ AC_MSG_CHECKING([for Microsoft Windows Kernel Transaction Manager])
+ save_LIBS="$LIBS"
+ LIBS="-lktmw32 $LIBS"
+ AC_LINK_IFELSE([AC_LANG_PROGRAM([dnl
+#include <windows.h>
+#include <ktmw32.h>
+], [(void)CreateTransaction(NULL,0,0,0,0,0,NULL);])],
+ [have_windows_ktm="yes"; EXTRA_LIBS="-lktmw32 $EXTRA_LIBS"],
+ [have_windows_ktm="no"])
+ LIBS="$save_LIBS"
+ AC_MSG_RESULT([$have_windows_ktm])
+else
+ have_windows_ktm="no"
+fi
+if test "$have_windows_ktm" = "yes"; then
+ AC_DEFINE([HAVE_WINDOWS_KTM],[1],[Define if Windows KTM is available.])
+fi
+
# Taken from dbus
AC_ARG_ENABLE(ansi, [ --enable-ansi enable -ansi -pedantic gcc flags],enable_ansi=$enableval,enable_ansi=no)
AC_ARG_ENABLE(verbose-mode, [ --enable-verbose-mode support verbose debug mode],enable_verbose_mode=$enableval,enable_verbose_mode=$USE_MAINTAINER_MODE)
iterator.c \
importer.c \
merger.c \
+ atomic.c \
transaction.c
if HAVE_LUA
--- /dev/null
+/*
+ * Copyright (C) 2011 J. Ali Harlow <ali@juiblex.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "config.h"
+
+#include <stdlib.h>
+#ifdef MSWIN_API
+#include <windows.h>
+#endif
+#include <stdio.h>
+#include <limits.h>
+#include <errno.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <string.h>
+#include <assert.h>
+#if HAVE_WINDOWS_KTM
+#include <wchar.h>
+#include <ktmw32.h>
+#endif
+
+#include "razor.h"
+#include "razor-internal.h"
+
+/*
+ * Atomic transactions
+ */
+
+#ifndef O_BINARY
+#define O_BINARY 0
+#endif
+
+#define RAZOR_ASCII_ISALPHA(c) \
+ ((c) >= 'A' && (c) <= 'Z' || (c) >= 'a' && (c) <= 'z')
+
+static int allow_all_root_names = 0;
+
+/*
+ * Primarily intended for testing named roots under UNIX platforms.
+ */
+RAZOR_EXPORT void
+razor_disable_root_name_checks(int disable)
+{
+ allow_all_root_names = disable;
+}
+
+#ifdef MSWIN_API
+
+static char *
+razor_utf16_to_utf8(const wchar_t *utf16, int len)
+{
+ int n;
+ char *utf8;
+
+ n = WideCharToMultiByte(CP_UTF8, 0, utf16, len, NULL, 0, NULL, NULL);
+ if (len >= 0 && utf16[len])
+ n++;
+ utf8 = malloc(n);
+ (void)WideCharToMultiByte(CP_UTF8, 0, utf16, len, utf8, n, NULL, NULL);
+ if (len >= 0 && utf16[len])
+ utf8[n - 1] = 0;
+
+ return utf8;
+}
+
+static wchar_t *
+razor_utf8_to_utf16(const char *utf8, int len)
+{
+ int n;
+ wchar_t *utf16;
+
+ n = MultiByteToWideChar(CP_UTF8, 0, utf8, len, NULL, 0);
+ if (len >= 0 && utf8[len])
+ n++;
+ utf16 = malloc(n * sizeof(wchar_t));
+ (void)MultiByteToWideChar(CP_UTF8, 0, utf8, len, utf16, n);
+ if (len >= 0 && utf8[len])
+ utf16[n - 1] = 0;
+
+ return utf16;
+}
+
+#endif /* MSWIN_API */
+
+#if HAVE_WINDOWS_KTM
+
+static int
+razor_valid_root_name(const wchar_t *name)
+{
+ if (allow_all_root_names)
+ return !wcschr(name, '/');
+
+ return RAZOR_ASCII_ISALPHA(name[0]) && name[1] == ':' &&
+ name[2] == '\0';
+}
+
+struct razor_atomic {
+ HANDLE transaction;
+ int n_files;
+ struct razor_atomic_file {
+ wchar_t *path;
+ HANDLE h;
+ } *files;
+ char *error_path;
+ char *error_str;
+ char *error_msg;
+};
+
+struct razor_wstr {
+ wchar_t *str;
+ int len, allocated;
+};
+
+static struct razor_wstr *
+razor_wstr_create(const char *init, int len)
+{
+ int n;
+ struct razor_wstr *wstr;
+
+ wstr = malloc(sizeof(struct razor_wstr));
+
+ n = MultiByteToWideChar(CP_UTF8, 0, init, len, NULL, 0);
+ if (len >= 0 && init[len])
+ wstr->len = n++;
+ else
+ wstr->len = n - 1;
+
+ wstr->allocated = n * 2;
+ wstr->str = malloc(wstr->allocated * sizeof(wchar_t));
+ if (!wstr->str) {
+ free(wstr);
+ return NULL;
+ }
+
+ (void)MultiByteToWideChar(CP_UTF8, 0, init, len, wstr->str, n);
+ if (len >= 0 && init[len])
+ wstr->str[wstr->len] = 0;
+
+ return wstr;
+}
+
+static int
+razor_wstr_append(struct razor_wstr *wstr, const char *s, int len)
+{
+ int n, allocated;
+ wchar_t *str;
+
+ n = MultiByteToWideChar(CP_UTF8, 0, s, len, NULL, 0);
+ if (len < 0 || !s[len])
+ n--;
+
+ if (wstr->allocated <= wstr->len + n) {
+ allocated = (wstr->len + n + 1) * 2;
+ str = realloc(wstr->str, allocated * sizeof(wchar_t));
+ if (!str)
+ return -1;
+ wstr->allocated = allocated;
+ wstr->str = str;
+ }
+
+ (void)MultiByteToWideChar(CP_UTF8, 0, s, len, wstr->str + wstr->len, n);
+ wstr->len += n;
+ wstr->str[wstr->len] = 0;
+
+ return 0;
+}
+
+static void
+razor_wstr_destroy(struct razor_wstr *wstr)
+{
+ free(wstr->str);
+ free(wstr);
+}
+
+RAZOR_EXPORT struct razor_atomic *
+razor_atomic_open(const char *description)
+{
+ wchar_t *buf;
+ struct razor_atomic *atomic;
+
+ atomic = zalloc(sizeof *atomic);
+ buf = razor_utf8_to_utf16(description, -1);
+ atomic->transaction = CreateTransaction(NULL, 0,
+ TRANSACTION_DO_NOT_PROMOTE,
+ 0, 0, 0, buf);
+ free(buf);
+
+ return atomic;
+}
+
+static void
+razor_atomic_set_error_str(struct razor_atomic *atomic, const wchar_t *path,
+ const char *str)
+{
+ assert(!atomic->error_str);
+
+ free(atomic->error_path);
+
+ if (path)
+ atomic->error_path = razor_utf16_to_utf8(path, -1);
+ else
+ atomic->error_path = NULL;
+
+ atomic->error_str = strdup(str);
+}
+
+static void
+razor_atomic_set_error(struct razor_atomic *atomic, const wchar_t *path,
+ DWORD error)
+{
+ wchar_t *buf;
+
+ assert(!atomic->error_str);
+
+ free(atomic->error_path);
+
+ if (path)
+ atomic->error_path = razor_utf16_to_utf8(path, -1);
+ else
+ atomic->error_path = NULL;
+
+ FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER|
+ FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS,
+ NULL, error, MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT),
+ (LPWSTR)&buf, 0, NULL);
+ atomic->error_str = razor_utf16_to_utf8(buf, -1);
+ LocalFree(buf);
+}
+
+RAZOR_EXPORT int
+razor_atomic_commit(struct razor_atomic *atomic)
+{
+ int retval;
+
+ if (atomic->error_str)
+ return -1;
+
+ retval = !CommitTransaction(atomic->transaction);
+
+ if (retval) {
+ razor_atomic_set_error(atomic, NULL, GetLastError());
+ RollbackTransaction(atomic->transaction);
+ }
+
+ CloseHandle(atomic->transaction);
+ atomic->transaction = INVALID_HANDLE_VALUE;
+
+ return retval;
+}
+
+RAZOR_EXPORT void
+razor_atomic_destroy(struct razor_atomic *atomic)
+{
+ int i;
+
+ for(i = 0; i < atomic->n_files; i++) {
+ if (atomic->files[i].h != INVALID_HANDLE_VALUE) {
+ CloseHandle(atomic->files[i].h);
+ free(atomic->files[i].path);
+ }
+ }
+ free(atomic->files);
+ if (atomic->transaction != INVALID_HANDLE_VALUE) {
+ RollbackTransaction(atomic->transaction);
+ CloseHandle(atomic->transaction);
+ }
+ free(atomic->error_path);
+ free(atomic->error_str);
+ free(atomic->error_msg);
+ free(atomic);
+}
+
+RAZOR_EXPORT int
+razor_atomic_make_dirs(struct razor_atomic *atomic, const char *root,
+ const char *path)
+{
+ struct razor_wstr *buffer;
+ const char *slash, *s, *next;
+ WIN32_FILE_ATTRIBUTE_DATA fa;
+ DWORD err;
+ int r, creating = 0;
+
+ if (atomic->error_str)
+ return -1;
+
+ buffer = razor_wstr_create(root, -1);
+ slash = path;
+
+ for (; *slash != '\0'; slash = next) {
+ next = strpbrk(slash + 1, "/\\");
+ if (next == NULL)
+ break;
+
+ razor_wstr_append(buffer, slash, next - slash);
+
+ if (!creating) {
+ if (razor_valid_root_name(buffer->str))
+ continue;
+
+ r = GetFileAttributesTransactedW(buffer->str,
+ GetFileExInfoStandard,
+ &fa,
+ atomic->transaction);
+
+ if (!r) {
+ err = GetLastError();
+ if (err == ERROR_FILE_NOT_FOUND) {
+ creating = 1;
+ } else {
+ razor_atomic_set_error(atomic,
+ buffer->str,
+ err);
+ razor_wstr_destroy(buffer);
+ return -1;
+ }
+ } else if (!(fa.dwFileAttributes&
+ FILE_ATTRIBUTE_DIRECTORY)) {
+ razor_atomic_set_error_str(atomic, buffer->str,
+ "Not a directory");
+ razor_wstr_destroy(buffer);
+ return -1;
+ }
+ }
+ if (creating) {
+ if (!CreateDirectoryTransactedW(NULL, buffer->str, NULL,
+ atomic->transaction)) {
+ razor_atomic_set_error(atomic, buffer->str,
+ GetLastError());
+ razor_wstr_destroy(buffer);
+ return -1;
+ }
+
+ /* FIXME: What to do about permissions for dirs we
+ * have to create but are not in the cpio archive? */
+ }
+ }
+
+ razor_wstr_destroy(buffer);
+
+ return 0;
+}
+
+RAZOR_EXPORT int
+razor_atomic_remove(struct razor_atomic *atomic, const char *path)
+{
+ wchar_t *buf;
+ DWORD err;
+
+ if (atomic->error_str)
+ return -1;
+
+ buf = razor_utf8_to_utf16(path, -1);
+
+ if (DeleteFileTransactedW(buf, atomic->transaction)) {
+ free(buf);
+ return 0;
+ }
+
+ err = GetLastError();
+ if (err == ERROR_FILE_NOT_FOUND || err == ERROR_PATH_NOT_FOUND) {
+ free(buf);
+ return 0;
+ }
+
+ if (SetFileAttributesTransactedW(buf, FILE_ATTRIBUTE_NORMAL,
+ atomic->transaction)) {
+ if (DeleteFileTransactedW(buf, atomic->transaction)) {
+ free(buf);
+ return 0;
+ }
+ err = GetLastError();
+ }
+
+ if (RemoveDirectoryTransactedW(buf, atomic->transaction) ||
+ GetLastError() == ERROR_DIR_NOT_EMPTY) {
+ free(buf);
+ return 0;
+ }
+
+ /*
+ * It would be tempting to use:
+ * MoveFileEx(path, NULL, MOVEFILE_DELAY_UNTIL_REBOOT)
+ * but unless we can guarantee that the system will be rebooted
+ * before we (or some other application) write another file with the
+ * same path, this is likely to cause more problems than it solves.
+ */
+
+ razor_atomic_set_error(atomic, buf, err);
+ free(buf);
+ return -1;
+}
+
+RAZOR_EXPORT int
+razor_atomic_rename_file(struct razor_atomic *atomic, const char *oldpath,
+ const char *newpath)
+{
+ wchar_t *oldbuf, *newbuf;
+ const DWORD flags = MOVEFILE_COPY_ALLOWED | MOVEFILE_REPLACE_EXISTING;
+
+ if (atomic->error_str)
+ return -1;
+
+ newbuf = razor_utf8_to_utf16(newpath, -1);
+ oldbuf = razor_utf8_to_utf16(oldpath, -1);
+
+ /*
+ * Passing MOVEFILE_REPLACE_EXISTING to MoveFileTransaction() will
+ * cover every case we care about _except_ replacing an empty
+ * directory with a file. Calling RemoveDirectoryTransacted() will deal
+ * with this case while having no effect in all other cases.
+ */
+ (void)RemoveDirectoryTransactedW(newbuf, atomic->transaction);
+
+ if (!MoveFileTransactedW(oldbuf, newbuf, NULL, NULL, flags,
+ atomic->transaction))
+ razor_atomic_set_error(atomic, newbuf, GetLastError());
+
+ free(newbuf);
+ free(oldbuf);
+
+ return !!atomic->error_str;
+}
+
+RAZOR_EXPORT int
+razor_atomic_create_dir(struct razor_atomic *atomic, const char *dirname,
+ mode_t mode)
+{
+ wchar_t *buf;
+ DWORD err;
+ WIN32_FILE_ATTRIBUTE_DATA fa;
+
+ if (atomic->error_str)
+ return -1;
+
+ buf = razor_utf8_to_utf16(dirname, -1);
+
+ if (!CreateDirectoryTransactedW(NULL, buf, NULL, atomic->transaction)) {
+ err = GetLastError();
+ if (err != ERROR_FILE_EXISTS && err != ERROR_ALREADY_EXISTS) {
+abort:
+ razor_atomic_set_error(atomic, buf, err);
+ free(buf);
+ return -1;
+ }
+
+ if (!GetFileAttributesTransactedW(buf, GetFileExInfoStandard,
+ &fa, atomic->transaction))
+ goto abort;
+
+ if (!(fa.dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY)) {
+ if (razor_atomic_remove(atomic, dirname)) {
+ free(buf);
+ return -1;
+ }
+ if (!CreateDirectoryTransactedW(NULL, buf, NULL,
+ atomic->transaction)) {
+ err = GetLastError();
+ goto abort;
+ }
+ }
+ }
+
+ free(buf);
+
+ return 0;
+}
+
+RAZOR_EXPORT int
+razor_atomic_create_symlink(struct razor_atomic *atomic, const char *target,
+ const char *path)
+{
+ if (atomic->error_str)
+ return -1;
+
+ /*
+ * This isn't true, but symbolic links under Windows 7
+ * need to know whether the target is a directory or not
+ * and we don't always know that at the time when the
+ * link is created, so it's a convienent lie for now.
+ */
+ razor_atomic_set_error_str(atomic, NULL, "Symbolic links not supported "
+ "on this platform");
+
+ return -1;
+}
+
+RAZOR_EXPORT int
+razor_atomic_create_file(struct razor_atomic *atomic, const char *filename,
+ mode_t mode)
+{
+ DWORD attribs;
+ struct razor_atomic_file *files;
+ int i = atomic->n_files;
+
+ if (atomic->error_str)
+ return -1;
+
+ files = realloc(atomic->files,
+ (atomic->n_files+1) * sizeof(struct razor_atomic_file));
+ if (!files) {
+ razor_atomic_set_error_str(atomic, NULL, "Not enough memory");
+ return -1;
+ }
+ atomic->n_files++;
+ atomic->files = files;
+
+ files[i].path = razor_utf8_to_utf16(filename, -1);
+
+ /*
+ * Passing CREATE_ALWAYS to CreateFileTransacted() will cover
+ * every case we care about _except_ replacing an empty directory
+ * with a file. Calling RemoveDirectoryTransacted() will deal
+ * with this case while having no effect in all other cases.
+ */
+ (void)RemoveDirectoryTransactedW(files[i].path, atomic->transaction);
+
+ if (mode & S_IWUSR)
+ attribs = FILE_ATTRIBUTE_NORMAL;
+ else
+ attribs = FILE_ATTRIBUTE_READONLY;
+
+ files[i].h = CreateFileTransactedW(files[i].path, GENERIC_WRITE,
+ 0, NULL, CREATE_ALWAYS, attribs,
+ NULL, atomic->transaction, NULL,
+ NULL);
+
+ if (files[i].h == INVALID_HANDLE_VALUE) {
+ razor_atomic_set_error(atomic, files[i].path, GetLastError());
+ free(files[i].path);
+ atomic->n_files--;
+ return -1;
+ }
+
+ return i;
+}
+
+RAZOR_EXPORT int
+razor_atomic_write(struct razor_atomic *atomic, int handle, const void *data,
+ size_t size)
+{
+ DWORD written;
+
+ if (atomic->error_str)
+ return -1;
+
+ assert(handle < atomic->n_files);
+ assert(atomic->files[handle].h != INVALID_HANDLE_VALUE);
+
+ while(size) {
+ if (!WriteFile(atomic->files[handle].h, data, size, &written,
+ NULL)) {
+ razor_atomic_set_error(atomic,
+ atomic->files[handle].path,
+ GetLastError());
+
+ (void)CloseHandle(atomic->files[handle].h);
+ free(atomic->files[handle].path);
+ atomic->files[handle].path = NULL;
+ atomic->files[handle].h = INVALID_HANDLE_VALUE;
+
+ return -1;
+ }
+
+ data += written;
+ size -= written;
+ }
+
+ return 0;
+}
+
+RAZOR_EXPORT int
+razor_atomic_sync(struct razor_atomic *atomic, int handle)
+{
+ HANDLE h;
+
+ if (atomic->error_str)
+ return -1;
+
+ assert(handle < atomic->n_files);
+ assert(atomic->files[handle].h != INVALID_HANDLE_VALUE);
+
+ if (!CloseHandle(atomic->files[handle].h)) {
+ razor_atomic_set_error(atomic, atomic->files[handle].path,
+ GetLastError());
+ free(atomic->files[handle].path);
+ atomic->files[handle].path = NULL;
+ atomic->files[handle].h = INVALID_HANDLE_VALUE;
+ return -1;
+ }
+
+ h = CreateFileTransactedW(atomic->files[handle].path, GENERIC_WRITE, 0,
+ NULL, OPEN_EXISTING, 0, NULL,
+ atomic->transaction, NULL, NULL);
+ atomic->files[handle].h = h;
+
+ if (atomic->files[handle].h == INVALID_HANDLE_VALUE) {
+ razor_atomic_set_error(atomic, atomic->files[handle].path,
+ GetLastError());
+ free(atomic->files[handle].path);
+ atomic->files[handle].path = NULL;
+ return -1;
+ }
+
+ return !!atomic->error_str;
+}
+
+RAZOR_EXPORT int
+razor_atomic_close(struct razor_atomic *atomic, int handle)
+{
+ if (atomic->error_str)
+ return -1;
+
+ assert(handle < atomic->n_files);
+ assert(atomic->files[handle].h != INVALID_HANDLE_VALUE);
+
+ if (!CloseHandle(atomic->files[handle].h))
+ razor_atomic_set_error(atomic, atomic->files[handle].path,
+ GetLastError());
+
+ free(atomic->files[handle].path);
+ atomic->files[handle].path = NULL;
+ atomic->files[handle].h = INVALID_HANDLE_VALUE;
+
+ while(atomic->n_files > 0 &&
+ atomic->files[atomic->n_files-1].h == INVALID_HANDLE_VALUE)
+ atomic->n_files--;
+
+ return !!atomic->error_str;
+}
+
+#else /* HAVE_WINDOWS_KVM */
+
+static int
+razor_valid_root_name(const char *name)
+{
+ if (allow_all_root_names) {
+#ifdef MSWIN_API
+ return !strpbrk(name, "/\\");
+#else
+ return !strchr(name, '/');
+#endif
+ }
+
+#ifdef MSWIN_API
+ return RAZOR_ASCII_ISALPHA(name[0]) && name[1] == ':' &&
+ name[2] == '\0';
+#else
+ return name[0] == '\0';
+#endif
+}
+
+struct razor_atomic {
+ char *error_path;
+ char *error_str;
+ char *error_msg;
+};
+
+RAZOR_EXPORT struct razor_atomic *
+razor_atomic_open(const char *description)
+{
+ struct razor_atomic *atomic;
+
+ atomic = zalloc(sizeof *atomic);
+
+ return atomic;
+}
+
+static void
+razor_atomic_set_error_str(struct razor_atomic *atomic, const char *path,
+ const char *str)
+{
+ assert(!atomic->error_str);
+
+ atomic->error_path = path ? strdup(path) : NULL;
+ atomic->error_str = strdup(str);
+}
+
+#ifdef MSWIN_API
+static void
+razor_atomic_set_error_mswin(struct razor_atomic *atomic, const wchar_t *path,
+ DWORD error)
+{
+ wchar_t *buf;
+
+ assert(!atomic->error_str);
+
+ free(atomic->error_path);
+
+ if (path)
+ atomic->error_path = razor_utf16_to_utf8(path, -1);
+ else
+ atomic->error_path = NULL;
+
+ FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER|
+ FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS,
+ NULL, error, MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT),
+ (LPWSTR)&buf, 0, NULL);
+ atomic->error_str = razor_utf16_to_utf8(buf, -1);
+ LocalFree(buf);
+}
+#endif
+
+RAZOR_EXPORT int
+razor_atomic_commit(struct razor_atomic *atomic)
+{
+ return !!atomic->error_str;
+}
+
+RAZOR_EXPORT void
+razor_atomic_destroy(struct razor_atomic *atomic)
+{
+ free(atomic->error_path);
+ free(atomic->error_str);
+ free(atomic->error_msg);
+ free(atomic);
+}
+
+RAZOR_EXPORT int
+razor_atomic_make_dirs(struct razor_atomic *atomic, const char *root,
+ const char *path)
+{
+ char buffer[PATH_MAX], *p;
+ const char *slash, *next;
+ struct stat buf;
+
+ if (atomic->error_str)
+ return -1;
+
+ strcpy(buffer, root);
+ p = buffer + strlen(buffer);
+ slash = path;
+ for (slash = path; *slash != '\0'; slash = next) {
+#ifdef MSWIN_API
+ next = strpbrk(slash + 1, "/\\");
+#else
+ next = strchr(slash + 1, '/');
+#endif
+ if (next == NULL)
+ break;
+
+ memcpy(p, slash, next - slash);
+ p += next - slash;
+ *p = '\0';
+
+ if (razor_valid_root_name(buffer))
+ continue;
+
+ if (stat(buffer, &buf) == 0) {
+ if (!S_ISDIR(buf.st_mode)) {
+ razor_atomic_set_error_str(atomic, buffer,
+ "Not a directory");
+ return -1;
+ }
+ } else if (mkdir(buffer, 0777) < 0) {
+ razor_atomic_set_error_str(atomic, buffer,
+ strerror(errno));
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+RAZOR_EXPORT int
+razor_atomic_remove(struct razor_atomic *atomic, const char *path)
+{
+#ifdef MSWIN_API
+ wchar_t *buf;
+ DWORD err;
+#endif
+
+ if (atomic->error_str)
+ return -1;
+
+#ifdef MSWIN_API
+ buf = razor_utf8_to_utf16(path, -1);
+
+ if (!DeleteFileW(buf)) {
+ err = GetLastError();
+ if (err != ERROR_FILE_NOT_FOUND &&
+ err != ERROR_PATH_NOT_FOUND &&
+ !(SetFileAttributesW(buf, FILE_ATTRIBUTE_NORMAL) &&
+ DeleteFileW(buf)) &&
+ !RemoveDirectoryW(buf) &&
+ GetLastError() != ERROR_DIR_NOT_EMPTY)
+ razor_atomic_set_error_mswin(atomic, buf, err);
+ }
+
+ free(buf);
+#else
+ if (remove(path))
+ razor_atomic_set_error_str(atomic, path, strerror(errno));
+#endif
+
+ return !!atomic->error_str;
+}
+
+RAZOR_EXPORT int
+razor_atomic_rename_file(struct razor_atomic *atomic, const char *oldpath,
+ const char *newpath)
+{
+#ifdef MSWIN_API
+ wchar_t *oldbuf, *newbuf;
+ const DWORD flags = MOVEFILE_COPY_ALLOWED | MOVEFILE_REPLACE_EXISTING;
+#endif
+
+ if (atomic->error_str)
+ return -1;
+
+#ifdef MSWIN_API
+ newbuf = razor_utf8_to_utf16(newpath, -1);
+ oldbuf = razor_utf8_to_utf16(oldpath, -1);
+
+ /*
+ * Passing MOVEFILE_REPLACE_EXISTING to MoveFileEx() will
+ * cover every case we care about _except_ replacing an empty
+ * directory with a file. Calling RemoveDirectory() will deal
+ * with this case while having no effect in all other cases.
+ */
+ (void)RemoveDirectoryW(newbuf);
+
+ if (!MoveFileExW(oldbuf, newbuf, flags))
+ razor_atomic_set_error_mswin(atomic, newbuf, GetLastError());
+
+ free(newbuf);
+ free(oldbuf);
+#else
+ if (rename(oldpath, newpath))
+ razor_atomic_set_error_str(atomic, newpath, strerror(errno));
+#endif
+
+ return !!atomic->error_str;
+}
+
+RAZOR_EXPORT int
+razor_atomic_create_dir(struct razor_atomic *atomic, const char *dirname,
+ mode_t mode)
+{
+ if (atomic->error_str)
+ return -1;
+
+ if (!mkdir(dirname, mode & (S_IRWXU | S_IRWXG | S_IRWXO)))
+ return 0;
+
+ if (errno != EEXIST) {
+ razor_atomic_set_error_str(atomic, dirname, strerror(errno));
+ return -1;
+ }
+
+ if (chmod(dirname, mode & (S_IRWXU | S_IRWXG | S_IRWXO)) < 0) {
+ razor_atomic_set_error_str(atomic, dirname, strerror(errno));
+ return -1;
+ }
+
+ return 0;
+}
+
+RAZOR_EXPORT int
+razor_atomic_create_symlink(struct razor_atomic *atomic, const char *target,
+ const char *path)
+{
+ if (atomic->error_str)
+ return -1;
+
+#if HAVE_SYMLINK
+ if (symlink(target, path) < 0) {
+ razor_atomic_set_error_str(atomic, NULL, strerror(errno));
+ return -1;
+ }
+#else
+ razor_atomic_set_error_str(atomic, NULL, "Symbolic links not supported "
+ "on this platform");
+#endif
+
+ return 0;
+}
+
+RAZOR_EXPORT int
+razor_atomic_create_file(struct razor_atomic *atomic, const char *filename,
+ mode_t mode)
+{
+ int fd;
+
+ if (atomic->error_str)
+ return -1;
+
+ atomic->error_path = strdup(filename);
+ fd = open(atomic->error_path, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
+ mode & (S_IRWXU | S_IRWXG | S_IRWXO));
+
+ if (fd == -1)
+ razor_atomic_set_error_str(atomic, NULL, strerror(errno));
+
+ return fd;
+}
+
+RAZOR_EXPORT int
+razor_atomic_write(struct razor_atomic *atomic, int fd, const void *data,
+ size_t size)
+{
+ int written;
+
+ if (atomic->error_str)
+ return -1;
+
+ while(size) {
+ written = write(fd, data, size);
+ if (written < 0) {
+ razor_atomic_set_error_str(atomic, NULL, strerror(errno));
+
+ (void)close(fd);
+
+ return -1;
+ }
+
+ data += written;
+ size -= written;
+ }
+
+ return 0;
+}
+
+RAZOR_EXPORT int
+razor_atomic_sync(struct razor_atomic *atomic, int handle)
+{
+ if (atomic->error_str)
+ return -1;
+
+ if (fsync(handle) < 0) {
+ razor_atomic_set_error_str(atomic, NULL, strerror(errno));
+ return -1;
+ }
+
+ free(atomic->error_path);
+ atomic->error_path = NULL;
+
+ return 0;
+}
+
+RAZOR_EXPORT int
+razor_atomic_close(struct razor_atomic *atomic, int fd)
+{
+ if (atomic->error_str)
+ return -1;
+
+ if (close(fd) < 0) {
+ razor_atomic_set_error_str(atomic, NULL, strerror(errno));
+ return -1;
+ }
+
+ free(atomic->error_path);
+ atomic->error_path = NULL;
+
+ return 0;
+}
+
+#endif /* HAVE_WINDOWS_KVM */
+
+RAZOR_EXPORT const char *
+razor_atomic_get_error_msg(struct razor_atomic *atomic)
+{
+ if (!atomic->error_msg) {
+ if (atomic->error_path)
+ atomic->error_msg = razor_concat(atomic->error_path,
+ ": ",
+ atomic->error_str,
+ NULL);
+ else
+ atomic->error_msg = strdup(atomic->error_str);
+ }
+
+ return atomic->error_msg;
+}
+
+RAZOR_EXPORT void
+razor_atomic_abort(struct razor_atomic *atomic, const char *error_msg)
+{
+ if (!atomic->error_str)
+ razor_atomic_set_error_str(atomic, NULL, error_msg);
+}
+
+RAZOR_EXPORT int
+razor_atomic_in_error_state(struct razor_atomic *atomic)
+{
+ return !!atomic->error_str;
+}
/*
* Copyright (C) 2008 Kristian Høgsberg <krh@redhat.com>
* Copyright (C) 2008 Red Hat, Inc
- * Copyright (C) 2009, 2010 J. Ali Harlow <ali@juiblex.co.uk>
+ * Copyright (C) 2009-2011 J. Ali Harlow <ali@juiblex.co.uk>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
struct razor_merger *merger;
int count;
size_t size;
+ uint32_t header_version;
merger = zalloc(sizeof *merger);
merger->set = razor_set_create();
+ if (set1->packages.size) {
+ header_version = razor_set_get_header_version(set1);
+ if (set2->packages.size &&
+ razor_set_get_header_version(set2) > header_version)
+ header_version = razor_set_get_header_version(set2);
+ } else
+ header_version = razor_set_get_header_version(set2);
+ razor_set_set_header_version(merger->set, header_version);
hashtable_init(&merger->table, &merger->set->string_pool);
hashtable_init(&merger->file_table, &merger->set->file_string_pool);
hashtable_init(&merger->details_table,
switch (script) {
case RAZOR_PROPERTY_PREUN:
- assert(pool[package->preun.program] == '\0');
- assert(pool[package->preun.body] == '\0');
- package->preun.program = p;
- package->preun.body = b;
+ if (package->preun.program != p) {
+ assert(pool[package->preun.program] == '\0');
+ package->preun.program = p;
+ }
+ if (package->preun.body != b) {
+ assert(pool[package->preun.body] == '\0');
+ package->preun.body = b;
+ }
break;
case RAZOR_PROPERTY_POSTUN:
- assert(pool[package->postun.program] == '\0');
- assert(pool[package->postun.body] == '\0');
- package->postun.program = p;
- package->postun.body = b;
+ if (package->postun.program != p) {
+ assert(pool[package->postun.program] == '\0');
+ package->postun.program = p;
+ }
+ if (package->postun.body != b) {
+ assert(pool[package->postun.body] == '\0');
+ package->postun.body = b;
+ }
break;
default:
break;
/*
* Copyright (C) 2008 Kristian Høgsberg <krh@redhat.com>
* Copyright (C) 2008 Red Hat, Inc
- * Copyright (C) 2009 J. Ali Harlow <ali@juiblex.co.uk>
+ * Copyright (C) 2009, 2011 J. Ali Harlow <ali@juiblex.co.uk>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
#include "razor.h"
#include "types/types.h"
-/* GCC visibility */
+/* GCC extensions */
#if defined(__GNUC__) && __GNUC__ >= 4
#define RAZOR_EXPORT __attribute__ ((visibility("default")))
#else
};
#define RAZOR_MAGIC 0x525a4442
-#define RAZOR_VERSION 1
#define RAZOR_STRING_POOL "string_pool"
#define RAZOR_PACKAGES "packages"
#define RAZOR_ENTRY_LAST 0x80
struct razor_set {
+ uint32_t header_version;
struct array string_pool;
struct array packages;
struct array properties;
struct array file_string_pool;
struct array details_string_pool;
struct razor_mapped_file *mapped_files;
- int lock_fd;
+ int lock_fd, ref_count;
};
struct import_entry {
/*
* Copyright (C) 2008 Kristian Høgsberg <krh@redhat.com>
* Copyright (C) 2008 Red Hat, Inc
- * Copyright (C) 2009, 2010 J. Ali Harlow <ali@juiblex.co.uk>
+ * Copyright (C) 2009-2011 J. Ali Harlow <ali@juiblex.co.uk>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
set = zalloc(sizeof *set);
- empty = array_add(&set->string_pool, 1);
- *empty = '\0';
+ if (set) {
+ empty = array_add(&set->string_pool, 1);
+ *empty = '\0';
- set->lock_fd = -1;
+ set->lock_fd = -1;
+
+ set->ref_count = 1;
+
+ set->header_version = RAZOR_HEADER_VERSION;
+ }
return set;
}
return set;
}
+RAZOR_EXPORT uint32_t
+razor_set_get_header_version(struct razor_set *set)
+{
+ return set->header_version;
+}
+
+RAZOR_EXPORT int
+razor_set_set_header_version(struct razor_set *set, uint32_t header_version)
+{
+ if (header_version<RAZOR_HEADER_VERSION_MIN ||
+ header_version>RAZOR_HEADER_VERSION)
+ return -1;
+ else {
+ set->header_version = header_version;
+ return 0;
+ }
+}
+
struct razor_mapped_file {
struct razor_set_header *header;
size_t size;
};
RAZOR_EXPORT int
-razor_set_bind_sections(struct razor_set *set, const char *filename)
+razor_set_bind_sections(struct razor_set *set, struct razor_atomic *atomic,
+ const char *filename)
{
struct razor_set_section *s, *sections;
struct razor_mapped_file *file;
- const char *pool;
+ const char *pool, *reason;
+ char *msg;
struct array *array;
int i, j;
file = zalloc(sizeof *file);
- if (file == NULL)
+ if (file == NULL) {
+ razor_atomic_abort(atomic, "Not enough memory");
return -1;
+ }
file->header = razor_file_get_contents(filename, &file->size);
if (!file->header) {
+ msg = razor_concat(filename, ": ", strerror(errno), NULL);
+ razor_atomic_abort(atomic, msg);
+ free(msg);
free(file);
return -1;
}
- if (file->size < sizeof *file->header ||
- file->header->magic != RAZOR_MAGIC ||
- file->header->version != RAZOR_VERSION) {
+ if (file->size < sizeof *file->header)
+ reason = "Premature EOF";
+ else if (file->header->magic != RAZOR_MAGIC)
+ reason = "Bad magic number";
+ else if (file->header->version < RAZOR_HEADER_VERSION_MIN ||
+ file->header->version > RAZOR_HEADER_VERSION)
+ reason = "Incompatible file version";
+ else
+ reason = NULL;
+
+ if (reason) {
+ msg = razor_concat(filename, ": ", reason, NULL);
+ razor_atomic_abort(atomic, msg);
+ free(msg);
razor_file_free_contents(file->header, file->size);
free(file);
return -1;
}
+ set->header_version = file->header->version;
+
if (set->mapped_files == NULL) {
for (i = 0; i < ARRAY_SIZE(razor_sections); i++) {
array = (void *) set + razor_sections[i].offset;
}
RAZOR_EXPORT struct razor_set *
-razor_set_open(const char *filename)
+razor_set_open(const char *filename, struct razor_atomic *atomic)
{
struct razor_set *set;
set = zalloc(sizeof *set);
+ if (!set) {
+ razor_atomic_abort(atomic, "Not enough memory");
+ return NULL;
+ }
+
set->lock_fd = -1;
- if (razor_set_bind_sections(set, filename)){
+ if (razor_set_bind_sections(set, atomic, filename)) {
free(set);
return NULL;
}
if (exclusive)
flags |= LOCKFILE_EXCLUSIVE_LOCK;
- if (fd >= 0 && !LockFileEx(_get_osfhandle(fd), flags, 0, 1, 0, &lock)) {
+ if (fd >= 0 && !LockFileEx((HANDLE)_get_osfhandle(fd), flags, 0, 1, 0,
+ &lock)) {
close(fd);
return -1;
}
if (set->lock_fd >= 0)
- (void)UnlockFile(_get_osfhandle(set->lock_fd), 0, 0, 1, 0);
+ (void)UnlockFile((HANDLE)_get_osfhandle(set->lock_fd), 0, 0, 1,
+ 0);
#else
struct flock lock = {0};
return 0;
}
-RAZOR_EXPORT void
+static void
razor_set_destroy(struct razor_set *set)
{
struct razor_mapped_file *file, *next;
free(set);
}
-RAZOR_EXPORT int
-razor_set_write_to_fd(struct razor_set *set, int fd, uint32_t section_mask)
+RAZOR_EXPORT void
+razor_set_unref(struct razor_set *set)
+{
+ if (set && !--set->ref_count)
+ razor_set_destroy(set);
+}
+
+RAZOR_EXPORT struct razor_set *
+razor_set_ref(struct razor_set *set)
+{
+ if (set)
+ set->ref_count++;
+ return set;
+}
+
+RAZOR_EXPORT void
+razor_set_write_to_handle(struct razor_set *set, struct razor_atomic *atomic,
+ int handle, uint32_t section_mask)
{
struct razor_set_header header;
struct razor_set_section sections[ARRAY_SIZE(razor_sections)];
count = j;
header.magic = RAZOR_MAGIC;
- header.version = RAZOR_VERSION;
+ header.version = set->header_version;
header.num_sections = count;
offset = sizeof header + count * sizeof *sections + ALIGN(pool.size, 4);
offset += ALIGN(arrays[i]->size, 4);
}
- razor_write(fd, &header, sizeof header);
- razor_write(fd, sections, count * sizeof *sections);
- razor_write(fd, pool.data, pool.size);
- razor_write(fd, padding, PADDING(pool.size, 4));
+ razor_atomic_write(atomic, handle, &header, sizeof header);
+ razor_atomic_write(atomic, handle, sections, count * sizeof *sections);
+ razor_atomic_write(atomic, handle, pool.data, pool.size);
+ razor_atomic_write(atomic, handle, padding, PADDING(pool.size, 4));
for (i = 0; i < count; i++) {
- razor_write(fd, arrays[i]->data, arrays[i]->size);
- razor_write(fd, padding, PADDING(arrays[i]->size, 4));
+ razor_atomic_write(atomic, handle, arrays[i]->data,
+ arrays[i]->size);
+ razor_atomic_write(atomic, handle, padding,
+ PADDING(arrays[i]->size, 4));
}
array_release(&pool);
hashtable_release(&table);
-
- return 0;
}
RAZOR_EXPORT int
-razor_set_write(struct razor_set *set, const char *filename, uint32_t sections)
+razor_set_write(struct razor_set *set, struct razor_atomic *atomic,
+ const char *filename, uint32_t sections)
{
- int fd, status;
+ int h;
- fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC | O_BINARY, 0666);
- if (fd < 0)
+ h = razor_atomic_create_file(atomic, filename,
+ S_IRWXU | S_IRWXG | S_IRWXO);
+ if (h < 0)
return -1;
- status = razor_set_write_to_fd(set, fd, sections);
- if (status) {
- close(fd);
- return status;
- }
+ razor_set_write_to_handle(set, atomic, h, sections);
- return close(fd);
+ return razor_atomic_close(atomic, h);
}
RAZOR_EXPORT void
* @package: a %razor_package
* @root: the root into which the package is currently installed
* @install_count: the value to pass to uninstall scripts
+ * @stage: Limit the removal to just the scripts or the files
*
* Removes an installed package.
**/
RAZOR_EXPORT int
razor_package_remove(struct razor_set *prev, struct razor_set *next,
- struct razor_package *package, const char *root,
- int install_count)
+ struct razor_atomic *atomic, struct razor_package *package,
+ const char *root, int install_count,
+ enum razor_stage_type stage)
{
struct razor_file_iterator *fi;
struct razor_package_iterator *pi;
struct razor_package *p;
- char buffer[PATH_MAX];
+ char *buffer;
const char *name, *program, *script;
- int retval = 0, i, count;
+ int i, count;
struct environment env;
struct list *link;
const char *prefix;
- environment_init(&env);
- link = list_first(&package->install_prefixes, &prev->prefix_pool);
- for (i = 0; link; i++) {
- prefix = (const char *)prev->string_pool.data + link->data;
- sprintf(buffer, "RPM_INSTALL_PREFIX%d", i);
- environment_add_variable(&env, buffer, prefix);
- link = list_next(link);
+ if (stage & RAZOR_STAGE_SCRIPTS) {
+ environment_init(&env);
+ link = list_first(&package->install_prefixes,
+ &prev->prefix_pool);
+ for (i = 0; link; i++) {
+ prefix = (const char *)prev->string_pool.data +
+ link->data;
+ sprintf(buffer, "RPM_INSTALL_PREFIX%d", i);
+ environment_add_variable(&env, buffer, prefix);
+ link = list_next(link);
+ }
+ environment_set(&env);
}
- environment_set(&env);
- razor_package_get_details(prev, package,
- RAZOR_DETAIL_PREUNPROG, &program,
- RAZOR_DETAIL_PREUN, &script,
- RAZOR_DETAIL_LAST);
-
- retval = razor_run_script(root, RAZOR_PROPERTY_PREUN, program, script,
- install_count);
+ if (stage & RAZOR_STAGE_SCRIPTS_PRE) {
+ razor_package_get_details(prev, package,
+ RAZOR_DETAIL_PREUNPROG, &program,
+ RAZOR_DETAIL_PREUN, &script,
+ RAZOR_DETAIL_LAST);
- fi = razor_file_iterator_create(prev, package, 1);
+ razor_run_script(root, RAZOR_PROPERTY_PREUN, program,
+ script, install_count);
+ }
- while (razor_file_iterator_next(fi, &name)) {
- pi = razor_package_iterator_create_for_file(next, name);
- count = 0;
- while (razor_package_iterator_next(pi, &p, RAZOR_DETAIL_LAST))
- count++;
- razor_package_iterator_destroy(pi);
- if (count <= 0) {
- snprintf(buffer, sizeof buffer, "%s%s", root, name);
- if (razor_remove(buffer) && errno != ENOENT) {
- perror(name);
- retval = -1;
+ if (stage & RAZOR_STAGE_FILES) {
+ fi = razor_file_iterator_create(prev, package, 1);
+
+ while (razor_file_iterator_next(fi, &name)) {
+ pi = razor_package_iterator_create_for_file(next, name);
+ count = 0;
+ while (razor_package_iterator_next(pi, &p,
+ RAZOR_DETAIL_LAST))
+ count++;
+ razor_package_iterator_destroy(pi);
+ if (count <= 0) {
+ buffer = razor_concat(root, name, NULL);
+ razor_atomic_remove(atomic, buffer);
+ free(buffer);
}
}
- }
- razor_file_iterator_destroy(fi);
+ razor_file_iterator_destroy(fi);
+ }
- razor_package_get_details(prev, package,
- RAZOR_DETAIL_POSTUNPROG, &program,
- RAZOR_DETAIL_POSTUN, &script,
- RAZOR_DETAIL_LAST);
+ if (stage & RAZOR_STAGE_SCRIPTS_POST) {
+ razor_package_get_details(prev, package,
+ RAZOR_DETAIL_POSTUNPROG, &program,
+ RAZOR_DETAIL_POSTUN, &script,
+ RAZOR_DETAIL_LAST);
- if (razor_run_script(root, RAZOR_PROPERTY_POSTUN, program, script,
- install_count))
- retval = -1;
+ razor_run_script(root, RAZOR_PROPERTY_POSTUN, program, script,
+ install_count);
+ }
- environment_unset(&env);
- environment_release(&env);
+ if (stage & RAZOR_STAGE_SCRIPTS) {
+ environment_unset(&env);
+ environment_release(&env);
+ }
- return retval;
+ return razor_atomic_in_error_state(atomic);
}
RAZOR_EXPORT const char *
struct razor_set *set;
struct razor_set *next;
struct array actions;
- struct deque *order;
+ struct deque *order, *left;
};
static void
}
ii->order = graph_sort(&follows);
+ ii->left = deque_dup(ii->order);
graph_release(&follows);
return ii;
struct razor_package *pkg;
const char *removing, *name;
- if (deque_empty(ii->order))
+ if (deque_empty(ii->left))
return 0;
- a = (struct install_action *)ii->actions.data + deque_pop(ii->order);
+ a = (struct install_action *)ii->actions.data + deque_pop(ii->left);
*package = a->package;
*action = a->action;
*count = 0;
(*count)++;
}
razor_package_iterator_destroy(pi);
- }
+ } else
+ *count = 1;
return 1;
}
RAZOR_EXPORT void
+razor_install_iterator_rewind(struct razor_install_iterator *ii)
+{
+ deque_free(ii->left);
+ ii->left=deque_dup(ii->order);
+}
+
+RAZOR_EXPORT void
razor_install_iterator_destroy(struct razor_install_iterator *ii)
{
array_release(&ii->actions);
deque_free(ii->order);
+ deque_free(ii->left);
free(ii);
}
/*
* Copyright (C) 2008 Kristian Høgsberg <krh@redhat.com>
* Copyright (C) 2008 Red Hat, Inc
- * Copyright (C) 2009 J. Ali Harlow <ali@juiblex.co.uk>
+ * Copyright (C) 2009, 2011 J. Ali Harlow <ali@juiblex.co.uk>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
#define _RAZOR_H_
#include <stdint.h>
+#include <sys/types.h>
+
+/* GCC extensions */
+#if defined(__GNUC__)
+#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 96)
+#define RAZOR_MALLOC __attribute__((__malloc__))
+#else
+#define RAZOR_MALLOC
+#endif
+#if __GNUC__ >= 4
+#define RAZOR_NULL_TERMINATED __attribute__ ((__sentinel__))
+#else
+#define RAZOR_NULL_TERMINATED
+#endif
+#endif /* __GNUC__ */
enum razor_section_type {
RAZOR_SECTION_MAIN = 0x01,
RAZOR_SECTION_ALL = 0x07
};
+enum razor_stage_type {
+ RAZOR_STAGE_SCRIPTS_PRE = 0x1,
+ RAZOR_STAGE_FILES = 0x2,
+ RAZOR_STAGE_SCRIPTS_POST = 0x4,
+ RAZOR_STAGE_SCRIPTS = 0x5,
+ RAZOR_STAGE_ALL = 0x7
+};
+
enum razor_detail_type {
RAZOR_DETAIL_LAST = 0, /* the sentinel */
RAZOR_DETAIL_NAME,
};
/**
+ * SECTION:atomic
+ * @title: Atomic transactions
+ * @short_description: File-based transactions that shouldn't half-succeed
+ *
+ * This is a helper object for issuing a sequence of file-based actions
+ * that should either all succeed or all fail.
+ *
+ * Note that currently only Windows 7 has a native implementation and that
+ * the fallback implementation will not rollback even if an error does occur.
+ * This could (and should) be improved.
+ **/
+struct razor_atomic;
+
+struct razor_atomic *razor_atomic_open(const char *description);
+int razor_atomic_commit(struct razor_atomic *atomic);
+const char *razor_atomic_get_error_msg(struct razor_atomic *atomic);
+void razor_atomic_destroy(struct razor_atomic *atomic);
+
+/**
+ * razor_atomic_make_dirs
+ *
+ * Create all sub-directories leading up to path. We know root exists
+ * and is a dir, root does not end in a '/', and path either has a
+ * leading '/' or (on MS-Windows only) root is the empty string
+ * and path starts with drive (eg., "c:/windows").
+ * Note: path itself is not created, only the directory in which it
+ * (would) exist.
+ *
+ * Returns: non-zero on error.
+ **/
+int razor_atomic_make_dirs(struct razor_atomic *atomic, const char *root,
+ const char *path);
+int razor_atomic_remove(struct razor_atomic *atomic, const char *path);
+int razor_atomic_rename_file(struct razor_atomic *atomic, const char *oldpath,
+ const char *newpath);
+
+/**
+ * razor_atomic_create_dir
+ *
+ * Create a directory, replacing any existing object at this path except
+ * an existing directory (which is not counted as a error).
+ *
+ * Returns: non-zero on error.
+ */
+int razor_atomic_create_dir(struct razor_atomic *atomic, const char *dirname,
+ mode_t mode);
+
+/**
+ * razor_atomic_create_symlink
+ *
+ * Create a symbolic link, replacing any existing object at this path except
+ * a non-empty directory.
+ *
+ * Note: This function will always fail on platforms that don't support
+ * symbolic links.
+ *
+ * Returns: non-zero on error.
+ */
+int razor_atomic_create_symlink(struct razor_atomic *atomic, const char *target,
+ const char *path);
+/**
+ * razor_atomic_create_file
+ *
+ * Create a file, replacing any existing object at this path except
+ * a non-empty directory.
+ *
+ * Returns: A handle to be passed to razor_atomic_write() and
+ * razor_atomic_close() or a negative value on error.
+ */
+int razor_atomic_create_file(struct razor_atomic *atomic, const char *filename,
+ mode_t mode);
+int razor_atomic_write(struct razor_atomic *atomic, int handle,
+ const void *data, size_t size);
+int razor_atomic_close(struct razor_atomic *atomic, int handle);
+int razor_atomic_sync(struct razor_atomic *atomic, int handle);
+void razor_atomic_abort(struct razor_atomic *atomic, const char *error_msg);
+int razor_atomic_in_error_state(struct razor_atomic *atomic);
+
+/**
* SECTION:set
* @title: Package Set
* @short_description: Represents a set of packages and their metadata.
struct razor_package;
struct razor_property;
+#define RAZOR_HEADER_VERSION 2 /* Current version */
+#define RAZOR_HEADER_VERSION_MIN 1 /* Minimum version we support */
+
/**
* razor_set_create:
*
**/
struct razor_set *razor_set_create_without_root(void);
struct razor_set *razor_set_create(void);
-struct razor_set *razor_set_open(const char *filename);
-void razor_set_destroy(struct razor_set *set);
-int razor_set_write_to_fd(struct razor_set *set,
- int fd, uint32_t section_mask);
-int razor_set_write(struct razor_set *set,
+struct razor_set *razor_set_open(const char *filename,
+ struct razor_atomic *atomic);
+uint32_t razor_set_get_header_version(struct razor_set *set);
+int razor_set_set_header_version(struct razor_set *set,
+ uint32_t header_version);
+void razor_set_unref(struct razor_set *set);
+struct razor_set *razor_set_ref(struct razor_set *set);
+void razor_set_write_to_handle(struct razor_set *set,
+ struct razor_atomic *atomic, int handle,
+ uint32_t section_mask);
+int razor_set_write(struct razor_set *set, struct razor_atomic *atomic,
const char *filename, uint32_t setions);
-int razor_set_bind_sections(struct razor_set *set, const char *filename);
+int razor_set_bind_sections(struct razor_set *set, struct razor_atomic *atomic,
+ const char *filename);
struct razor_package *
razor_set_get_package(struct razor_set *set, const char *package);
struct razor_package *package, ...);
int
razor_package_remove(struct razor_set *prev, struct razor_set *next,
- struct razor_package *package, const char *root,
- int install_count);
+ struct razor_atomic *atomic, struct razor_package *package,
+ const char *root, int install_count,
+ enum razor_stage_type stage);
/**
* SECTION:iterator
enum razor_install_action *action,
int *count);
+void razor_install_iterator_rewind(struct razor_install_iterator *ii);
void razor_install_iterator_destroy(struct razor_install_iterator *ii);
/**
const char *path);
void razor_relocations_destroy(struct razor_relocations *relocations);
-struct razor_rpm *razor_rpm_open(const char *filename);
+struct razor_rpm *razor_rpm_open(const char *filename,
+ struct razor_atomic *atomic);
void razor_rpm_get_details(struct razor_rpm *rpm, ...);
void razor_rpm_set_relocations(struct razor_rpm *rpm,
struct razor_relocations *relocations);
-int razor_rpm_install(struct razor_rpm *rpm, const char *root,
- int install_count);
+int razor_rpm_install(struct razor_rpm *rpm, struct razor_atomic *atomic,
+ const char *root, int install_count,
+ enum razor_stage_type stage);
int razor_rpm_close(struct razor_rpm *rpm);
/**
struct razor_root;
int razor_root_create(const char *root);
-struct razor_root *razor_root_open(const char *root);
-struct razor_set *razor_root_open_read_only(const char *root);
+struct razor_root *
+razor_root_open(const char *root, struct razor_atomic *atomic);
+struct razor_set *razor_root_open_read_only(const char *root,
+ struct razor_atomic *atomic);
struct razor_set *razor_root_get_system_set(struct razor_root *root);
int razor_root_close(struct razor_root *root);
void razor_root_update(struct razor_root *root, struct razor_set *next);
int razor_root_commit(struct razor_root *root);
-
/**
* SECTION:misc
* @title: Miscellaneous Functions
void razor_set_lua_loader(const char *modname, void (*loader)());
void (*razor_get_lua_loader(const char *modname))();
+char *razor_concat(const char *s, ...) RAZOR_MALLOC RAZOR_NULL_TERMINATED;
+
+const char *razor_system_arch(void);
#endif /* _RAZOR_H_ */
/*
* Copyright (C) 2008 Kristian Høgsberg <krh@redhat.com>
* Copyright (C) 2008 Red Hat, Inc
- * Copyright (C) 2009 J. Ali Harlow <ali@juiblex.co.uk>
+ * Copyright (C) 2009, 2011 J. Ali Harlow <ali@juiblex.co.uk>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
struct razor_root {
struct razor_set *system;
struct razor_set *next;
- int fd;
- char path[PATH_MAX];
- char new_path[PATH_MAX];
+ struct razor_atomic *atomic;
+ int handle;
+ char *path, *new_path;
};
static void
RAZOR_EXPORT int
razor_root_create(const char *root)
{
+ int retval;
struct stat buf;
struct razor_set *set;
- char path[PATH_MAX];
+ struct razor_atomic *atomic;
+ char *path;
assert (root != NULL);
return -1;
}
- snprintf(path, sizeof path, "%s/%s",
- razor_root_path, system_repo_filename);
- if (razor_create_dir(root, path) < 0) {
- fprintf(stderr, "could not create %s%s\n",
- root, razor_root_path);
- return -1;
- }
-
- set = razor_set_create();
- snprintf(path, sizeof path, "%s%s/%s",
- root, razor_root_path, system_repo_filename);
- if (stat(path, &buf) == 0) {
+ path = razor_concat(root, razor_root_path, "/", system_repo_filename,
+ NULL);
+ retval = !stat(path, &buf);
+ free(path);
+ if (retval) {
fprintf(stderr,
"a razor install root is already initialized\n");
- return -1;
+ return retval;
}
- if (razor_set_write(set, path, RAZOR_SECTION_ALL) < 0) {
+
+ atomic = razor_atomic_open("Create initial package set");
+ path = razor_concat(razor_root_path, "/", system_repo_filename, NULL);
+ razor_atomic_make_dirs(atomic, root, path);
+ set = razor_set_create();
+ razor_set_write(set, atomic, path, RAZOR_SECTION_ALL);
+ free(path);
+ retval = razor_atomic_commit(atomic);
+ if (retval)
fprintf(stderr, "could not write initial package set\n");
- return -1;
- }
- razor_set_destroy(set);
+ razor_set_unref(set);
+ razor_atomic_destroy(atomic);
- return 0;
+ return retval;
}
RAZOR_EXPORT struct razor_root *
-razor_root_open(const char *root)
+razor_root_open(const char *root, struct razor_atomic *atomic)
{
struct razor_root *image;
- char lock_path[PATH_MAX];
+ char *lock_path;
+ int r;
assert (root != NULL);
razor_root_init();
image = malloc(sizeof *image);
- if (image == NULL)
+ if (image == NULL) {
+ razor_atomic_abort(atomic, "Not enough memory");
return NULL;
+ }
+
+ image->atomic = atomic;
image->system = razor_set_create_without_root();
if (image->system == NULL) {
free(image);
+ razor_atomic_abort(atomic, "Not enough memory");
return NULL;
}
- snprintf(lock_path, sizeof lock_path,
- "%s%s/%s", root, razor_root_path, system_lock_filename);
+ lock_path = razor_concat(root, razor_root_path, "/",
+ system_lock_filename, NULL);
- if (razor_set_aquire_lock(image->system, lock_path, 1) < 0) {
- razor_set_destroy(image->system);
+ r = razor_set_aquire_lock(image->system, lock_path, 1);
+
+ free(lock_path);
+
+ if (r < 0) {
+ razor_atomic_abort(atomic,
+ "Failed to aquire exclusive system lock");
+ razor_set_unref(image->system);
free(image);
return NULL;
}
- snprintf(image->new_path, sizeof image->new_path,
- "%s%s/%s", root, razor_root_path, system_tmp_filename);
- image->fd = open(image->new_path,
- O_CREAT | O_WRONLY | O_TRUNC | O_BINARY,
- 0666);
- if (image->fd < 0) {
- razor_set_destroy(image->system);
+ image->new_path = razor_concat(root, razor_root_path, "/",
+ system_tmp_filename, NULL);
+ image->handle = razor_atomic_create_file(atomic, image->new_path,
+ S_IRWXU | S_IRWXG | S_IRWXO);
+ if (image->handle < 0) {
+ free(image->new_path);
+ razor_set_unref(image->system);
free(image);
return NULL;
}
- snprintf(image->path, sizeof image->path,
- "%s%s/%s", root, razor_root_path, system_repo_filename);
+ image->path = razor_concat(root, razor_root_path, "/",
+ system_repo_filename, NULL);
- if (razor_set_bind_sections(image->system, image->path)) {
- close(image->fd);
+ if (razor_set_bind_sections(image->system, atomic, image->path)) {
unlink(image->new_path);
- razor_set_destroy(image->system);
+ free(image->new_path);
+ free(image->path);
+ razor_set_unref(image->system);
free(image);
return NULL;
}
}
RAZOR_EXPORT struct razor_set *
-razor_root_open_read_only(const char *root)
+razor_root_open_read_only(const char *root, struct razor_atomic *atomic)
{
- char path[PATH_MAX];
+ char *path;
struct razor_set *set;
assert (root != NULL);
razor_root_init();
set = razor_set_create_without_root();
- if (set == NULL)
+ if (set == NULL) {
+ razor_atomic_abort(atomic, "Not enough memory");
return NULL;
+ }
- snprintf(path, sizeof path,
- "%s%s/%s", root, razor_root_path, system_lock_filename);
+ path = razor_concat(root, razor_root_path, "/", system_lock_filename,
+ NULL);
if (razor_set_aquire_lock(set, path, 0) < 0) {
- razor_set_destroy(set);
+ razor_atomic_abort(atomic, "Failed to aquire non-exclusive "
+ "system lock");
+ free(path);
+ razor_set_unref(set);
return NULL;
}
- snprintf(path, sizeof path, "%s%s/%s",
- root, razor_root_path, system_repo_filename);
+ free(path);
+ path = razor_concat(root, razor_root_path, "/", system_repo_filename,
+ NULL);
- if (razor_set_bind_sections(set, path)) {
- razor_set_destroy(set);
- return NULL;
+ if (razor_set_bind_sections(set, atomic, path)) {
+ razor_set_unref(set);
+ set = NULL;
}
+ free(path);
+
return set;
}
{
assert (root != NULL);
- razor_set_destroy(root->system);
- close(root->fd);
- unlink(root->new_path);
+ razor_set_unref(root->system);
+ razor_atomic_close(root->atomic, root->handle);
+ razor_atomic_remove(root->atomic, root->new_path);
+ free(root->path);
+ free(root->new_path);
free(root);
return 0;
assert (next != NULL);
razor_root_init();
- razor_set_write_to_fd(next, root->fd, RAZOR_SECTION_ALL);
+ razor_set_write_to_handle(next, root->atomic, root->handle,
+ RAZOR_SECTION_ALL);
root->next = next;
/* Sync the new repo file so the new package set is on disk
* before we start upgrading. */
- fsync(root->fd);
- printf("wrote %s\n", root->new_path);
+ razor_atomic_sync(root->atomic, root->handle);
}
RAZOR_EXPORT int
int retval;
assert (root != NULL);
- /* Make it so. */
- close(root->fd);
-#ifdef MSWIN_API
- /* Rename is not atomic under MS-Windows */
- remove(root->path);
-#endif
- retval = rename(root->new_path, root->path);
- if (retval)
- perror(root->path);
- else
- printf("renamed %s to %s\n", root->new_path, root->path);
- razor_set_destroy(root->system);
+ razor_atomic_close(root->atomic, root->handle);
+ retval = razor_atomic_rename_file(root->atomic, root->new_path,
+ root->path);
+ razor_set_unref(root->system);
+ free(root->path);
+ free(root->new_path);
free(root);
return retval;
/*
* Copyright (C) 2008 Kristian Høgsberg <krh@redhat.com>
* Copyright (C) 2008 Red Hat, Inc
- * Copyright (C) 2009 J. Ali Harlow <ali@juiblex.co.uk>
+ * Copyright (C) 2009, 2011 J. Ali Harlow <ali@juiblex.co.uk>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
}
RAZOR_EXPORT struct razor_rpm *
-razor_rpm_open(const char *filename)
+razor_rpm_open(const char *filename, struct razor_atomic *atomic)
{
struct razor_rpm *rpm;
struct rpm_header_index *base, *index;
unsigned int count, i, nindex, hsize;
const char *name, *prefix;
+ char *s;
assert (filename != NULL);
- rpm = malloc(sizeof *rpm);
- if (rpm == NULL)
+ rpm = zalloc(sizeof *rpm);
+ if (rpm == NULL) {
+ razor_atomic_abort(atomic, "Not enough memory");
return NULL;
+ }
memset(rpm, 0, sizeof *rpm);
rpm->map = razor_file_get_contents(filename, &rpm->size);
if (!rpm->map) {
- fprintf(stderr, "couldn't get contents of %s (%s)\n", filename,
- strerror(errno));
+ s = razor_concat(filename, ": ", strerror(errno), NULL);
+ razor_atomic_abort(atomic, s);
+ free(s);
+ free(rpm);
return NULL;
}
name = razor_rpm_get_indirect(rpm, RPMTAG_OLDFILENAMES,
&count);
if (name) {
- fprintf(stderr, "old filenames not supported\n");
+ razor_rpm_close(rpm);
+ s = razor_concat(filename,
+ ": Old filenames not supported", NULL);
+ razor_atomic_abort(atomic, s);
+ free(s);
return NULL;
}
}
prefix = razor_rpm_get_indirect(rpm, RPMTAG_DEFAULTPREFIX,
&count);
if (prefix) {
- fprintf(stderr, "default prefix not supported\n");
+ razor_rpm_close(rpm);
+ s = razor_concat(filename,
+ ": Default prefix not supported",
+ NULL);
+ razor_atomic_abort(atomic, s);
+ free(s);
return NULL;
}
}
struct installer {
const char *root;
struct razor_rpm *rpm;
+ struct razor_atomic *atomic;
z_stream stream;
unsigned char buffer[32768];
size_t rest, length;
installer->stream.avail_out = length;
err = inflate(&installer->stream, Z_SYNC_FLUSH);
if (err != Z_OK && err != Z_STREAM_END) {
- fprintf(stderr, "inflate error: %d (%s)\n", err,
- strerror(errno));
+ razor_atomic_abort(installer->atomic, "Failed to inflate");
return -1;
}
err = inflate(&installer->stream, Z_SYNC_FLUSH);
if (err != Z_OK && err != Z_STREAM_END) {
- fprintf(stderr, "inflate error: %d (%s)\n", err,
- strerror(errno));
+ razor_atomic_abort(installer->atomic, "Failed to inflate");
return -1;
}
static int
create_path(struct installer *installer, const char *path, unsigned int mode)
{
- char buffer[PATH_MAX];
- struct stat buf;
- int fd, ret;
+ char *s, *buffer;
+ int h, ret;
- if (razor_create_dir(installer->root, path) < 0)
+ if (razor_atomic_make_dirs(installer->atomic, installer->root, path))
return -1;
- snprintf(buffer, sizeof buffer, "%s%s", installer->root, path);
+ buffer = razor_concat(installer->root, path, NULL);
switch (mode >> 12) {
case REG:
/* FIXME: handle the case where a file is already there. */
- fd = open(buffer, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
- mode & 0x1ff);
- if (fd < 0){
- fprintf(stderr, "failed to create file %s\n", buffer);
+ h = razor_atomic_create_file(installer->atomic, buffer, mode);
+ free(buffer);
+ if (h < 0)
return -1;
- }
while (installer->rest > 0) {
- if (installer_inflate(installer)) {
- fprintf(stderr, "failed to inflate\n");
+ if (installer_inflate(installer))
return -1;
- }
- if (razor_write(fd, installer->buffer,
- installer->length)) {
- fprintf(stderr, "failed to write payload\n");
+ if (razor_atomic_write(installer->atomic, h,
+ installer->buffer,
+ installer->length))
return -1;
- }
}
- if (close(fd) < 0) {
- fprintf(stderr, "failed to close %s: %s\n", buffer,
- strerror(errno));
- return -1;
- }
- return 0;
+ return razor_atomic_close(installer->atomic, h);
case XDIR:
- ret = mkdir(buffer, mode & 0x1ff);
- if (ret == 0 || errno != EEXIST)
- return ret;
- if (stat(buffer, &buf) || !S_ISDIR(buf.st_mode)) {
- /* FIXME: also check that mode match. */
- fprintf(stderr,
- "%s exists but is not a directory\n", buffer);
- return -1;
- }
- return 0;
+ ret = razor_atomic_create_dir(installer->atomic, buffer, mode);
+ free(buffer);
+ return ret;
case LINK:
#if HAVE_SYMLINK
- if (installer_inflate(installer)) {
- fprintf(stderr, "failed to inflate\n");
+ if (installer_inflate(installer))
return -1;
- }
if (installer->length >= sizeof installer->buffer) {
- fprintf(stderr, "link name too long\n");
+ razor_atomic_abort(installer->atomic,
+ "Link target too long");
return -1;
}
installer->buffer[installer->length] = '\0';
- if (symlink((const char *) installer->buffer, buffer)) {
- perror("failed to create symlink");
- return -1;
- }
- return 0;
+ ret = razor_atomic_create_symlink(installer->atomic,
+ (const char *)installer->buffer, buffer);
+ free(buffer);
+ return ret;
#else
- /* fall through */
+ s = "Symbolic links";
+ goto unsupported;
#endif
case PIPE:
+ s = "Named pipes";
+unsupported:
+ free(buffer);
+ buffer = razor_concat(s, " are not supported on this platform",
+ NULL);
+ razor_atomic_abort(installer->atomic, buffer);
+ free(buffer);
+ return -1;
case CDEV:
+ s = "Character devices";
+ goto unsupported;
case BDEV:
+ s = "Block devices";
+ goto unsupported;
case SOCK:
- printf("%s: unhandled file type %d\n", buffer, mode >> 12);
- return 0;
+ s = "Named sockets";
+ goto unsupported;
default:
- printf("%s: unknown file type %d\n", buffer, mode >> 12);
- return 0;
+ free(buffer);
+ razor_atomic_abort(installer->atomic, "Unknown file type");
+ return -1;
}
}
{
unsigned char *gz_header;
int method, flags, err;
+ char buffer[32], *s;
gz_header = installer->rpm->payload;
if (gz_header[0] != 0x1f || gz_header[1] != 0x8b) {
- fprintf(stderr, "payload section doesn't have gz header\n");
+ razor_atomic_abort(installer->atomic,
+ "Payload section doesn't have gz header");
return -1;
}
flags = gz_header[3];
if (method != Z_DEFLATED || flags != 0) {
- fprintf(stderr,
- "unknown payload compression method or flags set\n");
+ razor_atomic_abort(installer->atomic,
+ "Unknown payload compression method or "
+ "flags set");
return -1;
}
err = inflateInit2(&installer->stream, -MAX_WBITS);
if (err != Z_OK) {
- fprintf(stderr, "inflateInit error: %d\n", err);
+ sprintf(buffer, "%d", err);
+ s = razor_concat("inflateEnd error: ", s, NULL);
+ razor_atomic_abort(installer->atomic, s);
+ free(s);
return -1;
}
installer_finish(struct installer *installer)
{
int err;
+ char buffer[32], *s;
err = inflateEnd(&installer->stream);
if (err != Z_OK) {
- fprintf(stderr, "inflateEnd error: %d\n", err);
- return -1;
+ sprintf(buffer, "%d", err);
+ s = razor_concat("inflateEnd error: ", s, NULL);
+ razor_atomic_abort(installer->atomic, s);
+ free(s);
}
- return 0;
+ return razor_atomic_in_error_state(installer->atomic);
}
static unsigned long
}
RAZOR_EXPORT int
-razor_rpm_install(struct razor_rpm *rpm, const char *root, int install_count)
+razor_rpm_install(struct razor_rpm *rpm, struct razor_atomic *atomic,
+ const char *root, int install_count,
+ enum razor_stage_type stage)
{
struct installer installer;
struct cpio_file_header *header;
struct stat buf;
unsigned int mode;
- const char *path;
+ const char *path, *name;
size_t filesize;
+ char *s;
assert (rpm != NULL);
assert (root != NULL);
installer.rpm = rpm;
installer.root = root;
+ installer.atomic = atomic;
/* FIXME: Only do this before a transaction, not per rpm. */
if (*root && (stat(root, &buf) < 0 || !S_ISDIR(buf.st_mode))) {
- fprintf(stderr,
- "root installation directory \"%s\" does not exist\n",
- root);
+ s = razor_concat(root, ": Directory does not exist", NULL);
+ razor_atomic_abort(stderr, s);
+ free(s);
return -1;
}
if (rpm->relocations)
razor_relocations_set_rpm(rpm->relocations, rpm);
- if (installer_init(&installer))
- return -1;
-
- run_script(&installer, RPMTAG_PREINPROG, RPMTAG_PREIN, install_count);
+ if (stage & RAZOR_STAGE_SCRIPTS_PRE)
+ run_script(&installer, RPMTAG_PREINPROG, RPMTAG_PREIN,
+ install_count);
- while (installer.stream.avail_in > 0) {
- installer.rest = sizeof *header;
- if (installer_inflate(&installer))
+ if (stage & RAZOR_STAGE_FILES) {
+ if (installer_init(&installer))
return -1;
- header = (struct cpio_file_header *) installer.buffer;
- mode = fixed_hex_to_ulong(header->mode, sizeof header->mode);
- filesize = fixed_hex_to_ulong(header->filesize,
- sizeof header->filesize);
+ while (installer.stream.avail_in > 0) {
+ installer.rest = sizeof *header;
+ if (installer_inflate(&installer))
+ break;
- installer.rest = fixed_hex_to_ulong(header->namesize,
- sizeof header->namesize);
+ header = (struct cpio_file_header *) installer.buffer;
+ mode = fixed_hex_to_ulong(header->mode,
+ sizeof header->mode);
+ filesize = fixed_hex_to_ulong(header->filesize,
+ sizeof header->filesize);
- if (installer_inflate(&installer) ||
- installer_align(&installer, 4))
- return -1;
+ installer.rest =
+ fixed_hex_to_ulong(header->namesize,
+ sizeof header->namesize);
- path = (const char *) installer.buffer;
- /* This convention is so lame... */
- if (strcmp(path, "TRAILER!!!") == 0)
- break;
+ if (installer_inflate(&installer) ||
+ installer_align(&installer, 4))
+ break;
- installer.rest = filesize;
- path++;
- if (rpm->relocations)
- path = razor_relocations_apply(rpm->relocations, path);
- if (create_path(&installer, path, mode) < 0)
- return -1;
- if (installer_align(&installer, 4))
+ path = (const char *) installer.buffer;
+ /* This convention is so lame... */
+ if (strcmp(path, "TRAILER!!!") == 0)
+ break;
+
+ installer.rest = filesize;
+ path++;
+ if (rpm->relocations)
+ path = razor_relocations_apply(rpm->relocations,
+ path);
+ if (create_path(&installer, path, mode))
+ break;
+ if (installer_align(&installer, 4))
+ break;
+ }
+
+ if (installer_finish(&installer))
return -1;
}
- if (installer_finish(&installer))
- return -1;
-
- run_script(&installer, RPMTAG_POSTINPROG, RPMTAG_POSTIN, install_count);
+ if (stage & RAZOR_STAGE_SCRIPTS_POST)
+ run_script(&installer, RPMTAG_POSTINPROG, RPMTAG_POSTIN,
+ install_count);
return 0;
}
/*
* Copyright (C) 2008 Kristian Høgsberg <krh@redhat.com>
* Copyright (C) 2008 Red Hat, Inc
- * Copyright (C) 2009 J. Ali Harlow <ali@juiblex.co.uk>
+ * Copyright (C) 2009, 2011 J. Ali Harlow <ali@juiblex.co.uk>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
{
int count;
- ts->set = set;
+ ts->set = razor_set_ref(set);
count = set->packages.size / sizeof (struct razor_package);
ts->packages = zalloc(count * sizeof *ts->packages);
count = set->properties.size / sizeof (struct razor_property);
static void
transaction_set_release(struct transaction_set *ts)
{
+ razor_set_unref(ts->set);
free(ts->packages);
free(ts->properties);
}
RAZOR_DETAIL_NAME, &n,
RAZOR_DETAIL_VERSION, &v,
RAZOR_DETAIL_LAST)) {
+#if 0
fprintf(stderr, "removing %s-%s\n", n, v);
+#endif
razor_transaction_remove_package(trans, pkg);
}
}
RAZOR_DETAIL_VERSION, &version,
RAZOR_DETAIL_LAST)) {
+#if 0
fprintf(stderr, "flagging %s-%s for providing %s matching %s %s\n",
name, version,
ppi->pool + p->name,
rpi->pool + r->name,
rpi->pool + r->version);
+#endif
flags[pkg - pkgs] |= flag;
}
}
while (razor_package_iterator_next(&pkg_iter, &pkg,
RAZOR_DETAIL_NAME, &name,
RAZOR_DETAIL_LAST)) {
+#if 0
fprintf(stderr, "updating %s because %s %s %s "
"isn't satisfied\n",
name, spi.pool + sp->name,
razor_property_relation_to_string(sp),
spi.pool + sp->version);
+#endif
trans->system.packages[pkg - spkgs] |=
TRANS_PACKAGE_UPDATE;
}
RAZOR_DETAIL_NAME, &name,
RAZOR_DETAIL_VERSION, &version,
RAZOR_DETAIL_LAST)) {
+#if 0
fprintf(stderr, "updating %s %s because it "
"conflicts with %s\n",
name, version, spi.pool + sp->name);
+#endif
trans->system.packages[pkg - spkgs] |=
TRANS_PACKAGE_UPDATE;
}
rpi->present[rp - rpi->start] |= TRANS_PROPERTY_SATISFIED;
+#if 0
fprintf(stderr, "pulling in %s-%s.%s which provides %s %s %s "
"to satisfy %s %s %s\n",
ppi->pool + pkg->name,
&rpi->pool[rp->name],
razor_property_relation_to_string(rp),
&rpi->pool[rp->version]);
+#endif
trans->upstream.packages[pkg - upkgs] |= TRANS_PACKAGE_UPDATE;
}
RAZOR_PROPERTY_LESS,
version);
razor_transaction_install_package(trans, p);
+#if 0
fprintf(stderr, "installing %s-%s\n", name, version);
+#endif
}
}
/*
* Copyright (C) 2008 Kristian Høgsberg <krh@redhat.com>
* Copyright (C) 2008 Red Hat, Inc
- * Copyright (C) 2009 J. Ali Harlow <ali@juiblex.co.uk>
+ * Copyright (C) 2009, 2011 J. Ali Harlow <ali@juiblex.co.uk>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
#ifdef MSWIN_API
#include <windows.h>
#include <direct.h>
+#else
+#include <sys/utsname.h>
#endif
#if HAVE_SYS_MMAN_H
#include <sys/mman.h>
#define O_BINARY 0
#endif
-#define RAZOR_ASCII_ISALPHA(c) \
- ((c) >= 'A' && (c) <= 'Z' || (c) >= 'a' && (c) <= 'z')
-
/* Required by gnulib on non-libc platforms */
char *program_name = "librazor";
-static int allow_all_root_names = 0;
-
-/*
- * Primarily intended for testing named roots under UNIX platforms.
- */
-RAZOR_EXPORT void razor_disable_root_name_checks(int disable)
-{
- allow_all_root_names = disable;
-}
-
-static int razor_valid_root_name(const char *name)
-{
- if (allow_all_root_names)
- return !strchr(name,'/');
-
-#ifdef MSWIN_API
- return RAZOR_ASCII_ISALPHA(name[0]) && name[1] == ':' &&
- name[2] == '\0';
-#else
- return name[0] == '\0';
-#endif
-}
-
-int
-razor_create_dir(const char *root, const char *path)
-{
- char buffer[PATH_MAX], *p;
- const char *slash, *next;
- struct stat buf;
-
- /* Create all sub-directories in dir. We know root exists and
- * is a dir, root does not end in a '/', and path either has a
- * leading '/' or (on MS-Windows only) root is the empty string
- * and path starts with drive (eg., "c:/windows"). */
-
- strcpy(buffer, root);
- p = buffer + strlen(buffer);
- slash = path;
- for (slash = path; *slash != '\0'; slash = next) {
- next = strchr(slash + 1, '/');
- if (next == NULL)
- break;
-
- memcpy(p, slash, next - slash);
- p += next - slash;
- *p = '\0';
-
- if (razor_valid_root_name(buffer))
- continue;
-
- if (stat(buffer, &buf) == 0) {
- if (!S_ISDIR(buf.st_mode)) {
- fprintf(stderr,
- "%s exists but is not a directory\n",
- buffer);
- return -1;
- }
- } else if (mkdir(buffer, 0777) < 0) {
- fprintf(stderr, "failed to make directory %s: %s\n",
- buffer, strerror(errno));
- return -1;
- }
-
- /* FIXME: What to do about permissions for dirs we
- * have to create but are not in the cpio archive? */
- }
-
- return 0;
-}
-
-int
-razor_remove(const char *path)
-{
-#ifdef MSWIN_API
- DWORD err;
-
- if (DeleteFile(path))
- return 0;
-
- err = GetLastError();
- if (err == ERROR_FILE_NOT_FOUND || err == ERROR_PATH_NOT_FOUND)
- return 0;
-
- if (SetFileAttributes(path, FILE_ATTRIBUTE_NORMAL) && DeleteFile(path))
- return 0;
-
- if (RemoveDirectory(path) || GetLastError() == ERROR_DIR_NOT_EMPTY)
- return 0;
-
- /*
- * It would be tempting to use:
- * MoveFileEx(path, NULL, MOVEFILE_DELAY_UNTIL_REBOOT)
- * but unless we can guarantee that the system will be rebooted
- * before we (or some other application) write another file with the
- * same path, this is likely to cause more problems than it solves.
- */
-
- /* Use remove() as a fallback so that errno is set appropriately */
-#endif
-
- return remove(path);
-}
-
-int
-razor_write(int fd, const void *data, size_t size)
-{
- size_t rest;
- ssize_t written;
- const unsigned char *p;
-
- rest = size;
- p = data;
- while (rest > 0) {
- written = write(fd, p, rest);
- if (written < 0) {
- perror("write error");
- return -1;
- }
- rest -= written;
- p += written;
- }
-
- return 0;
-}
-
void *
razor_file_get_contents(const char *filename, size_t *length)
{
return addr;
}
-int
razor_file_free_contents(void *addr, size_t length)
{
#if HAVE_SYS_MMAN_H
array_release(&env->string_pool);
array_release(&env->vars);
}
+
+RAZOR_EXPORT char *razor_concat(const char *s, ...)
+{
+ va_list args;
+ const char *string;
+ char *concat;
+ size_t n, len;
+
+ va_start(args, s);
+
+ len = strlen(s);
+ while((string = va_arg(args, const char *)))
+ len += strlen(string);
+
+ va_end(args);
+
+ concat = malloc(len + 1);
+
+ if (!concat)
+ return NULL;
+
+ va_start(args, s);
+
+ len = strlen(s);
+ memcpy(concat, s, len);
+ n = len;
+ while((string = va_arg(args, const char *))) {
+ len = strlen(string);
+ memcpy(concat + n, string, len);
+ n += len;
+ }
+
+ va_end(args);
+
+ concat[n] = '\0';
+
+ return concat;
+}
+
+RAZOR_EXPORT const char *razor_system_arch(void)
+{
+#ifdef MSWIN_API
+ SYSTEM_INFO si;
+
+ GetNativeSystemInfo(&si);
+ switch(si.wProcessorArchitecture)
+ {
+ case PROCESSOR_ARCHITECTURE_INTEL:
+ return "i686";
+ case PROCESSOR_ARCHITECTURE_AMD64:
+ return "x86_64";
+ default:
+ return NULL;
+ }
+#else
+ static struct utsname un;
+
+ if (uname(&un))
+ return NULL;
+ else
+ return un.machine;
+#endif
+}
/*
* Copyright (C) 2008 Kristian Høgsberg <krh@redhat.com>
* Copyright (C) 2008 Red Hat, Inc
- * Copyright (C) 2009 J. Ali Harlow <ali@juiblex.co.uk>
+ * Copyright (C) 2009, 2011 J. Ali Harlow <ali@juiblex.co.uk>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
static int
-update_packages(struct razor_transaction *trans, struct razor_set *system,
- struct razor_set *next, struct razor_relocations *relocations);
+update_packages(struct razor_transaction *trans,
+ struct razor_install_iterator *ii, struct razor_set *system,
+ struct razor_set *next, struct razor_atomic *atomic,
+ struct razor_relocations *relocations,
+ enum razor_stage_type stage);
static struct razor_package_iterator *
create_iterator_from_argv(struct razor_set *set, int argc, const char *argv[])
command_list(int argc, const char *argv[])
{
struct razor_package_iterator *pi;
+ struct razor_atomic *atomic;
struct razor_set *set;
uint32_t flags = 0;
int i = 0;
i++;
}
- set = razor_root_open_read_only(install_root);
- if (set == NULL)
+ atomic = razor_atomic_open("List installed packages");
+ set = razor_root_open_read_only(install_root, atomic);
+ if (set == NULL) {
+ fprintf(stderr, "%s\n", razor_atomic_get_error_msg(atomic));
+ razor_atomic_destroy(atomic);
return 1;
+ }
pi = create_iterator_from_argv(set, argc - i, argv + i);
list_packages(pi, flags);
razor_package_iterator_destroy(pi);
- razor_set_destroy(set);
+ razor_set_unref(set);
+ razor_atomic_destroy(atomic);
return 0;
}
list_properties(int argc, const char *argv[], uint32_t type)
{
struct razor_set *set;
+ struct razor_atomic *atomic;
struct razor_package *package;
struct razor_package_iterator *pi;
const char *name, *version, *arch;
- set = razor_root_open_read_only(install_root);
- if (set == NULL)
+ atomic = razor_atomic_open("List package properties");
+ set = razor_root_open_read_only(install_root, atomic);
+ if (set == NULL) {
+ fprintf(stderr, "%s\n", razor_atomic_get_error_msg(atomic));
+ razor_atomic_destroy(atomic);
return 1;
+ }
pi = create_iterator_from_argv(set, argc, argv);
while (razor_package_iterator_next(pi, &package,
RAZOR_DETAIL_LAST))
list_package_properties(set, package, type);
razor_package_iterator_destroy(pi);
- razor_set_destroy(set);
+ razor_set_unref(set);
+ razor_atomic_destroy(atomic);
return 0;
}
command_list_scripts(int argc, const char *argv[])
{
struct razor_set *set;
+ struct razor_atomic *atomic;
struct razor_package *package;
struct razor_package_iterator *pi;
const char *preunprog, *preun, *postunprog, *postun;
- set = razor_root_open_read_only(install_root);
- if (set == NULL)
+ atomic = razor_atomic_open("List package scripts");
+ set = razor_root_open_read_only(install_root, atomic);
+ if (set == NULL) {
+ fprintf(stderr, "%s\n", razor_atomic_get_error_msg(atomic));
+ razor_atomic_destroy(atomic);
return 1;
+ }
pi = create_iterator_from_argv(set, argc, argv);
while (razor_package_iterator_next(pi, &package,
}
}
razor_package_iterator_destroy(pi);
- razor_set_destroy(set);
+ razor_set_unref(set);
+ razor_atomic_destroy(atomic);
return 0;
}
static int
command_list_files(int argc, const char *argv[])
{
+ struct razor_atomic *atomic;
struct razor_set *set;
- set = razor_root_open_read_only(install_root);
- if (set == NULL)
+ atomic = razor_atomic_open("List package files");
+ set = razor_root_open_read_only(install_root, atomic);
+ if (set == NULL) {
+ fprintf(stderr, "%s\n", razor_atomic_get_error_msg(atomic));
+ razor_atomic_destroy(atomic);
return 1;
+ }
razor_set_list_files(set, argv[0]);
- razor_set_destroy(set);
+ razor_set_unref(set);
+ razor_atomic_destroy(atomic);
return 0;
}
static int
command_list_file_packages(int argc, const char *argv[])
{
+ struct razor_atomic *atomic;
struct razor_set *set;
struct razor_package_iterator *pi;
- set = razor_root_open_read_only(install_root);
- if (set == NULL)
+ atomic = razor_atomic_open("List file packages");
+ set = razor_root_open_read_only(install_root, atomic);
+ if (set == NULL) {
+ fprintf(stderr, "%s\n", razor_atomic_get_error_msg(atomic));
+ razor_atomic_destroy(atomic);
return 1;
+ }
pi = razor_package_iterator_create_for_file(set, argv[0]);
list_packages(pi, 0);
razor_package_iterator_destroy(pi);
- razor_set_destroy(set);
+ razor_set_unref(set);
+ razor_atomic_destroy(atomic);
return 0;
}
static int
command_list_package_files(int argc, const char *argv[])
{
+ struct razor_atomic *atomic;
struct razor_set *set;
struct razor_package_iterator *pi;
struct razor_package *package;
const char *name, *version, *arch;
- set = razor_root_open_read_only(install_root);
- if (set == NULL)
+ atomic = razor_atomic_open("List package files");
+ set = razor_root_open_read_only(install_root, atomic);
+ if (set == NULL) {
+ fprintf(stderr, "%s\n", razor_atomic_get_error_msg(atomic));
+ razor_atomic_destroy(atomic);
return 1;
+ }
pi = create_iterator_from_argv(set, argc, argv);
while (razor_package_iterator_next(pi, &package,
razor_set_list_package_files(set, package);
razor_package_iterator_destroy(pi);
- razor_set_destroy(set);
+ razor_set_unref(set);
+ razor_atomic_destroy(atomic);
return 0;
}
const char *ref_version,
uint32_t type)
{
+ struct razor_atomic *atomic;
struct razor_set *set;
struct razor_property *property;
struct razor_property_iterator *prop_iter;
if (ref_name == NULL)
return 0;
- set = razor_root_open_read_only(install_root);
- if (set == NULL)
+ atomic = razor_atomic_open("List package properties");
+ set = razor_root_open_read_only(install_root, atomic);
+ if (set == NULL) {
+ fprintf(stderr, "%s\n", razor_atomic_get_error_msg(atomic));
+ razor_atomic_destroy(atomic);
return 1;
+ }
prop_iter = razor_property_iterator_create(set, NULL);
while (razor_property_iterator_next(prop_iter, &property,
}
razor_property_iterator_destroy(prop_iter);
- razor_set_destroy(set);
+ razor_set_unref(set);
+ razor_atomic_destroy(atomic);
return 0;
}
static int
command_import_yum(int argc, const char *argv[])
{
+ int retval;
struct razor_set *set;
+ struct razor_atomic *atomic;
char buffer[512];
printf("downloading from %s.\n", yum_url);
set = razor_set_create_from_yum();
if (set == NULL)
return 1;
- if (razor_set_write(set, rawhide_repo_filename, RAZOR_SECTION_ALL)) {
- perror(rawhide_repo_filename);
- return -1;
- }
- razor_set_destroy(set);
- printf("wrote %s\n", rawhide_repo_filename);
+ atomic = razor_atomic_open("Yum import repository");
+ razor_set_write(set, atomic, rawhide_repo_filename, RAZOR_SECTION_ALL);
+ retval = razor_atomic_commit(atomic);
+ razor_set_unref(set);
+ if (retval)
+ fprintf(stderr, "%s\n", razor_atomic_get_error_msg(atomic));
+ else
+ printf("wrote %s\n", rawhide_repo_filename);
+ razor_atomic_destroy(atomic);
- return 0;
+ return retval;
}
#if HAVE_RPMLIB
{
struct razor_set *set;
struct razor_root *root;
+ struct razor_atomic *atomic;
+ int retval;
+
+ atomic = razor_atomic_open("Import RPM database");
- root = razor_root_open(install_root);
- if (root == NULL)
+ root = razor_root_open(install_root, atomic);
+ if (root == NULL) {
+ fprintf(stderr, "%s\n", razor_atomic_get_error_msg(atomic));
+ razor_atomic_destroy(atomic);
return 1;
+ }
set = razor_set_create_from_rpmdb();
if (set == NULL)
razor_root_update(root, set);
- return razor_root_commit(root);
+ retval = razor_root_commit(root);
+ if (retval)
+ fprintf(stderr, "%s\n", razor_atomic_get_error_msg(atomic));
+
+ razor_atomic_destroy(atomic);
+
+ return retval;
}
#endif
struct razor_root *root;
struct razor_set *system, *upstream, *next;
struct razor_transaction *trans;
- int i, errors;
+ struct razor_atomic *atomic;
+ struct razor_install_iterator *ii;
+ int i, retval;
+
+ atomic = razor_atomic_open("Remove packages");
- root = razor_root_open(install_root);
- system = razor_root_get_system_set(root);
+ root = razor_root_open(install_root, atomic);
+ system = razor_set_ref(razor_root_get_system_set(root));
if (system == NULL) {
+ fprintf(stderr, "%s\n", razor_atomic_get_error_msg(atomic));
razor_root_close(root);
+ razor_atomic_destroy(atomic);
return 1;
}
upstream = razor_set_create_without_root();
trans = razor_transaction_create(system, upstream);
+ razor_set_unref(upstream);
for (i = 0; i < argc; i++) {
if (mark_packages_for_removal(trans, system, argv[i]) == 0) {
fprintf(stderr, "no match for %s\n", argv[i]);
razor_transaction_destroy(trans);
- razor_set_destroy(upstream);
+ razor_set_unref(system);
razor_root_close(root);
+ razor_atomic_destroy(atomic);
return 1;
}
}
razor_transaction_resolve(trans);
- errors = razor_transaction_describe(trans);
- if (errors) {
+ retval = razor_transaction_describe(trans);
+ if (retval) {
razor_transaction_destroy(trans);
- razor_set_destroy(upstream);
+ razor_set_unref(system);
razor_root_close(root);
+ razor_atomic_destroy(atomic);
return 1;
}
next = razor_transaction_commit(trans);
- update_packages(trans, system, next, NULL);
+ ii = razor_set_create_install_iterator(system, next);
+ update_packages(trans, ii, system, next, atomic, NULL,
+ RAZOR_STAGE_SCRIPTS_PRE);
+ update_packages(trans, ii, system, next, atomic, NULL,
+ RAZOR_STAGE_FILES);
+
razor_root_update(root, next);
+ (void)razor_root_commit(root);
+ retval = razor_atomic_commit(atomic);
+ if (retval)
+ fprintf(stderr, "%s\n", razor_atomic_get_error_msg(atomic));
+ else
+ update_packages(trans, ii, system, next, atomic, NULL,
+ RAZOR_STAGE_SCRIPTS_POST);
+ razor_install_iterator_destroy(ii);
+
razor_transaction_destroy(trans);
- razor_set_destroy(next);
- razor_set_destroy(upstream);
+ razor_atomic_destroy(atomic);
+ razor_set_unref(system);
+ razor_set_unref(next);
- return razor_root_commit(root);
+ return retval;
}
static void
static int
command_diff(int argc, const char *argv[])
{
+ struct razor_atomic *atomic;
struct razor_set *set, *updated;
- set = razor_root_open_read_only(install_root);
- updated = razor_set_open(rawhide_repo_filename);
- if (set == NULL || updated == NULL)
+ atomic = razor_atomic_open("Show package differences");
+ set = razor_root_open_read_only(install_root, atomic);
+ updated = razor_set_open(rawhide_repo_filename, atomic);
+ if (set == NULL || updated == NULL) {
+ fprintf(stderr, "%s\n", razor_atomic_get_error_msg(atomic));
+ razor_atomic_destroy(atomic);
return 1;
+ }
razor_set_diff(set, updated, print_diff, NULL);
- razor_set_destroy(set);
- razor_set_destroy(updated);
+ razor_set_unref(set);
+ razor_set_unref(updated);
+ razor_atomic_destroy(atomic);
return 0;
}
struct razor_importer *importer;
struct razor_set *set;
struct razor_rpm *rpm;
+ struct razor_atomic *atomic;
int len, imported_count = 0;
char filename[256];
const char *dirname = argv[0];
+ int retval;
if (dirname == NULL) {
fprintf(stderr, "usage: razor import-rpms DIR\n");
while (de = readdir(dir), de != NULL) {
len = strlen(de->d_name);
if (len < 5 || strcmp(de->d_name + len - 4, ".rpm") != 0)
- continue;
+ continue;
snprintf(filename, sizeof filename,
"%s/%s", dirname, de->d_name);
- rpm = razor_rpm_open(filename);
- if (rpm == NULL) {
- fprintf(stderr,
- "failed to open rpm \"%s\"\n", filename);
+ atomic = razor_atomic_open("Read RPM");
+ rpm = razor_rpm_open(filename, atomic);
+ if (rpm == NULL)
+ fprintf(stderr, "%s\n",
+ razor_atomic_get_error_msg(atomic));
+ razor_atomic_destroy(atomic);
+ if (rpm == NULL)
continue;
- }
if (razor_importer_add_rpm(importer, rpm)) {
fprintf(stderr, "couldn't import %s\n", filename);
break;
printf("\nsaving\n");
set = razor_importer_finish(importer);
- razor_set_write(set, repo_filename, RAZOR_SECTION_ALL);
- razor_set_destroy(set);
- printf("wrote %s\n", repo_filename);
+ atomic = razor_atomic_open("Update system database");
+ razor_set_write(set, atomic, repo_filename, RAZOR_SECTION_ALL);
+ razor_set_unref(set);
+ retval = razor_atomic_commit(atomic);
+ if (retval)
+ fprintf(stderr, "%s\n", razor_atomic_get_error_msg(atomic));
+ else
+ printf("wrote %s\n", repo_filename);
+ razor_atomic_destroy(atomic);
- return 0;
+ return retval;
}
-static const char *
+static char *
rpm_filename(const char *name, const char *version, const char *arch)
{
- static char file[PATH_MAX];
const char *v;
/* Skip epoch */
else
v = version;
- snprintf(file, sizeof file, "%s-%s.%s.rpm", name, v, arch);
-
- return file;
+ return razor_concat(name, "-", v, ".", arch, ".rpm", NULL);
}
static int
struct razor_package *package;
enum razor_install_action action;
const char *name, *version, *arch;
- char file[PATH_MAX], url[256];
+ char *file, *url, *s;
int errors = 0, count;
ii = razor_set_create_install_iterator(system, next);
RAZOR_DETAIL_ARCH, &arch,
RAZOR_DETAIL_LAST);
- snprintf(url, sizeof url,
- "%s/Packages/%s",
- yum_url, rpm_filename(name, version, arch));
- snprintf(file, sizeof file,
- "rpms/%s", rpm_filename(name, version, arch));
+ s = rpm_filename(name, version, arch);
+ url = razor_concat(yum_url, "/Packages/", s, NULL);
+ file = razor_concat("rpms/", s, NULL);
+ free(s);
if (download_if_missing(url, file) < 0)
errors++;
+ free(file);
+ free(url);
}
razor_install_iterator_destroy(ii);
}
static struct razor_set *
-relocate_packages(struct razor_set *set, struct razor_relocations *relocations)
+relocate_packages(struct razor_set *set, struct razor_atomic *atomic,
+ struct razor_relocations *relocations)
{
int i;
struct razor_importer *importer;
const char *preunprog, *preun, *postunprog, *postun;
const char *install_prefix;
const char *const *prefixes;
- char file[PATH_MAX];
+ char *file, *s;
uint32_t flags;
importer = razor_importer_create();
RAZOR_DETAIL_POSTUNPROG, &postunprog,
RAZOR_DETAIL_POSTUN, &postun,
RAZOR_DETAIL_LAST)) {
- snprintf(file, sizeof file,
- "rpms/%s", rpm_filename(name, version, arch));
- rpm = razor_rpm_open(file);
+ s = rpm_filename(name, version, arch);
+ file = razor_concat("rpms/", s, NULL);
+ free(s);
+ rpm = razor_rpm_open(file, atomic);
+ free(file);
if (rpm == NULL) {
- fprintf(stderr, "failed to open rpm %s\n", file);
razor_package_iterator_destroy(pkg_iter);
razor_importer_destroy(importer);
return NULL;
static int
install_package(struct razor_transaction *trans, struct razor_set *set,
- struct razor_package *package,
- struct razor_relocations *relocations)
+ struct razor_atomic *atomic, struct razor_package *package,
+ struct razor_relocations *relocations, int install_count,
+ enum razor_stage_type stage)
{
int retval;
const char *name, *version, *arch;
- char file[PATH_MAX];
+ char *file, *s;
struct razor_rpm *rpm;
razor_package_get_details(set, package,
RAZOR_DETAIL_ARCH, &arch,
RAZOR_DETAIL_LAST);
- printf("install %s-%s\n", name, version);
+ if (stage & RAZOR_STAGE_SCRIPTS_PRE)
+ printf("install %s-%s\n", name, version);
- snprintf(file, sizeof file,
- "rpms/%s", rpm_filename(name, version, arch));
- rpm = razor_rpm_open(file);
+ s = rpm_filename(name, version, arch);
+ file = razor_concat("rpms/", s, NULL);
+ free(s);
+ rpm = razor_rpm_open(file, atomic);
+ free(file);
if (rpm == NULL) {
- fprintf(stderr, "failed to open rpm %s\n", file);
+ fprintf(stderr, "%s\n",
+ razor_atomic_get_error_msg(atomic));
return -1;
}
if (relocations)
razor_rpm_set_relocations(rpm, relocations);
razor_transaction_fixup_package(trans, package, rpm);
- retval = razor_rpm_install(rpm, install_root, 1);
- if (retval < 0)
- fprintf(stderr, "failed to install rpm %s\n", file);
+ retval = razor_rpm_install(rpm, atomic, install_root, install_count,
+ stage);
+ if (retval < 0) {
+ s = rpm_filename(name, version, arch);
+ fprintf(stderr, "%s: %s\n", s,
+ razor_atomic_get_error_msg(atomic));
+ free(s);
+ }
razor_rpm_close(rpm);
return retval;
}
static int
-update_packages(struct razor_transaction *trans, struct razor_set *system,
- struct razor_set *next, struct razor_relocations *relocations)
+update_packages(struct razor_transaction *trans,
+ struct razor_install_iterator *ii, struct razor_set *system,
+ struct razor_set *next, struct razor_atomic *atomic,
+ struct razor_relocations *relocations,
+ enum razor_stage_type stage)
{
- struct razor_install_iterator *ii;
struct razor_package *package;
enum razor_install_action action;
int retval = 0, count;
- ii = razor_set_create_install_iterator(system, next);
+ razor_install_iterator_rewind(ii);
+
while (!retval && razor_install_iterator_next(ii, &package,
&action, &count)) {
if (action == RAZOR_INSTALL_ACTION_ADD)
- retval = install_package(trans, next, package,
- relocations);
+ retval = install_package(trans, next, atomic, package,
+ relocations, count, stage);
else if (action == RAZOR_INSTALL_ACTION_REMOVE)
- retval = razor_package_remove(system, next, package,
- install_root, count);
+ retval = razor_package_remove(system, next, atomic,
+ package, install_root,
+ count, stage);
}
- razor_install_iterator_destroy(ii);
return retval;
}
struct razor_relocations *relocations=NULL;
struct razor_set *system, *upstream, *next, *set;
struct razor_transaction *trans;
- int i, len, dependencies = 1;
+ struct razor_atomic *atomic;
+ struct razor_install_iterator *ii;
+ int i, retval, len, dependencies = 1;
char *oldpath;
- root = razor_root_open(install_root);
- if (root == NULL)
+ if (do_update)
+ atomic = razor_atomic_open("Update packages");
+ else
+ atomic = razor_atomic_open("Install packages");
+
+ root = razor_root_open(install_root, atomic);
+ if (root == NULL) {
+ fprintf(stderr, "%s\n", razor_atomic_get_error_msg(atomic));
+ razor_atomic_destroy(atomic);
return 1;
+ }
for (i = 0; i < argc; i++) {
if (strcmp(argv[i], "--no-dependencies") == 0)
break;
}
- system = razor_root_get_system_set(root);
- upstream = razor_set_open(rawhide_repo_filename);
+ upstream = razor_set_open(rawhide_repo_filename, atomic);
if (upstream == NULL) {
+ fprintf(stderr, "%s\n", razor_atomic_get_error_msg(atomic));
razor_root_close(root);
+ razor_atomic_destroy(atomic);
return 1;
}
if (relocations) {
- set = relocate_packages(upstream, relocations);
- razor_set_destroy(upstream);
+ set = relocate_packages(upstream, atomic, relocations);
+ if (set == NULL) {
+ fprintf(stderr, "%s\n",
+ razor_atomic_get_error_msg(atomic));
+ razor_root_close(root);
+ razor_atomic_destroy(atomic);
+ razor_set_unref(upstream);
+ return 1;
+ }
+ razor_set_unref(upstream);
upstream = set;
}
+ system = razor_set_ref(razor_root_get_system_set(root));
+
trans = razor_transaction_create(system, upstream);
if (i == argc && do_update)
if (mark_packages_for_update(trans, upstream, argv[i]) == 0) {
fprintf(stderr, "no package matched %s\n", argv[i]);
razor_transaction_destroy(trans);
- razor_set_destroy(upstream);
+ razor_set_unref(upstream);
+ razor_set_unref(system);
razor_root_close(root);
+ razor_atomic_destroy(atomic);
return 1;
}
}
razor_transaction_resolve(trans);
if (razor_transaction_describe(trans) > 0) {
razor_transaction_destroy(trans);
- razor_set_destroy(upstream);
+ razor_set_unref(upstream);
+ razor_set_unref(system);
razor_root_close(root);
+ razor_atomic_destroy(atomic);
return 1;
}
}
- if (mkdir("rpms", 0777) && errno != EEXIST) {
- fprintf(stderr, "failed to create rpms directory.\n");
+ if (razor_atomic_create_dir(atomic, "rpms",
+ S_IRWXU | S_IRWXG | S_IRWXO)) {
+ fprintf(stderr, "%s\n", razor_atomic_get_error_msg(atomic));
razor_transaction_destroy(trans);
- razor_set_destroy(upstream);
+ razor_set_unref(upstream);
+ razor_set_unref(system);
razor_root_close(root);
+ razor_atomic_destroy(atomic);
return 1;
}
next = razor_transaction_commit(trans);
if (download_packages(system, next) < 0) {
- razor_set_destroy(next);
+ razor_set_unref(next);
razor_transaction_destroy(trans);
- razor_set_destroy(upstream);
+ razor_set_unref(upstream);
+ razor_set_unref(system);
razor_root_close(root);
+ razor_atomic_destroy(atomic);
return 1;
}
- update_packages(trans, system, next, relocations);
+ ii = razor_set_create_install_iterator(system, next);
+
+ update_packages(trans, ii, system, next, atomic, relocations,
+ RAZOR_STAGE_SCRIPTS_PRE);
+ update_packages(trans, ii, system, next, atomic, relocations,
+ RAZOR_STAGE_FILES);
razor_root_update(root, next);
+ razor_set_unref(upstream);
+
+ (void)razor_root_commit(root);
+ retval = razor_atomic_commit(atomic);
+ if (retval)
+ fprintf(stderr, "%s\n", razor_atomic_get_error_msg(atomic));
+ else
+ update_packages(trans, ii, system, next, atomic, relocations,
+ RAZOR_STAGE_SCRIPTS_POST);
+
razor_transaction_destroy(trans);
if (relocations)
razor_relocations_destroy(relocations);
- razor_set_destroy(next);
- razor_set_destroy(upstream);
+ razor_install_iterator_destroy(ii);
+
+ razor_atomic_destroy(atomic);
- return razor_root_commit(root);
+ razor_set_unref(next);
+ razor_set_unref(system);
+
+ return retval;
}
static int
static int
command_download(int argc, const char *argv[])
{
+ struct razor_atomic *atomic;
struct razor_set *set;
struct razor_package_iterator *pi;
struct razor_package *package;
char url[256], file[256];
int matches = 0;
- if (mkdir("rpms", 0777) && errno != EEXIST) {
- fprintf(stderr, "failed to create rpms directory.\n");
+ atomic = razor_atomic_open("Download packages");
+
+ if (razor_atomic_create_dir(atomic, "rpms",
+ S_IRWXU | S_IRWXG | S_IRWXO)) {
+ fprintf(stderr, "%s\n", razor_atomic_get_error_msg(atomic));
+ razor_atomic_destroy(atomic);
+ return 1;
+ }
+
+ set = razor_set_open(rawhide_repo_filename, atomic);
+
+ if (razor_atomic_commit(atomic)) {
+ fprintf(stderr, "%s\n", razor_atomic_get_error_msg(atomic));
+ razor_atomic_destroy(atomic);
return 1;
}
+ razor_atomic_destroy(atomic);
- set = razor_set_open(rawhide_repo_filename);
pi = razor_package_iterator_create(set);
while (razor_package_iterator_next(pi, &package,
RAZOR_DETAIL_NAME, &name,
download_if_missing(url, file);
}
razor_package_iterator_destroy(pi);
- razor_set_destroy(set);
+ razor_set_unref(set);
if (matches == 0)
fprintf(stderr, "no packages matched \"%s\"\n", pattern);
static int
command_info(int argc, const char *argv[])
{
+ struct razor_atomic *atomic;
struct razor_set *set;
struct razor_package_iterator *pi;
struct razor_package *package;
const char *pattern = argv[0], *name, *version, *arch;
const char *summary, *description, *url, *license;
- set = razor_root_open_read_only(install_root);
- if (set == NULL)
+ atomic = razor_atomic_open("Package info");
+ set = razor_root_open_read_only(install_root, atomic);
+ if (set == NULL) {
+ fprintf(stderr, "%s\n", razor_atomic_get_error_msg(atomic));
+ razor_atomic_destroy(atomic);
return 1;
+ }
pi = razor_package_iterator_create(set);
while (razor_package_iterator_next(pi, &package,
printf ("\n");
}
razor_package_iterator_destroy(pi);
- razor_set_destroy(set);
+ razor_set_unref(set);
+ razor_atomic_destroy(atomic);
return 0;
}
static int
command_search(int argc, const char *argv[])
{
+ struct razor_atomic *atomic;
struct razor_set *set;
struct razor_package_iterator *pi;
struct razor_package *package;
snprintf(pattern, sizeof pattern, "*%s*", argv[0]);
- set = razor_set_open(rawhide_repo_filename);
- if (set == NULL)
+ atomic = razor_atomic_open("Search packages");
+ set = razor_set_open(rawhide_repo_filename, atomic);
+ if (set == NULL || razor_atomic_commit(atomic)) {
+ fprintf(stderr, "%s\n", razor_atomic_get_error_msg(atomic));
+ razor_atomic_destroy(atomic);
return 1;
+ }
+ razor_atomic_destroy(atomic);
pi = razor_package_iterator_create(set);
while (razor_package_iterator_next(pi, &package,
printf("%s-%s.%s: %s\n", name, version, arch, summary);
}
razor_package_iterator_destroy(pi);
- razor_set_destroy(set);
+ razor_set_unref(set);
return 0;
}
/*
* Copyright (C) 2008 Kristian Høgsberg <krh@redhat.com>
* Copyright (C) 2008 Red Hat, Inc
- * Copyright (C) 2009 J. Ali Harlow <ali@juiblex.co.uk>
+ * Copyright (C) 2009, 2011 J. Ali Harlow <ali@juiblex.co.uk>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
create_set_from_command_line(int argc, const char *argv[])
{
struct razor_importer *importer;
+ struct razor_atomic *atomic;
struct razor_rpm *rpm;
int i;
importer = razor_importer_create();
for (i = 0; i < argc; i++) {
- rpm = razor_rpm_open(argv[i]);
+ atomic = razor_atomic_open("Read RPM");
+ rpm = razor_rpm_open(argv[i], atomic);
+ razor_atomic_destroy(atomic);
if (rpm == NULL)
continue;
if (razor_importer_add_rpm(importer, rpm))
static void
command_query(int argc, const char *argv[])
{
+ struct razor_atomic *atomic;
struct razor_set *set;
struct razor_package_iterator *pi;
struct razor_package *package;
const char *name, *version, *arch;
+ atomic = razor_atomic_open("Query packages");
if (option_package) {
set = create_set_from_command_line(argc, argv);
argc = 0;
option_all = 1;
} else {
- set = razor_root_open_read_only(option_root);
+ set = razor_root_open_read_only(option_root, atomic);
+ if (!set) {
+ fprintf(stderr, "%s\n",
+ razor_atomic_get_error_msg(atomic));
+ razor_atomic_destroy(atomic);
+ return;
+ }
}
pi = get_query_packages(set, argc, argv);
razor_package_iterator_destroy(pi);
- razor_set_destroy(set);
-
- return;
+ razor_set_unref(set);
+ razor_atomic_destroy(atomic);
}
static void
command_verify(int argc, const char *argv[])
{
+ struct razor_atomic *atomic;
struct razor_set *set;
struct razor_package_iterator *pi;
struct razor_package *package;
const char *name, *version, *arch;
+ atomic = razor_atomic_open("Verify packages");
if (option_package) {
set = create_set_from_command_line(argc, argv);
argc = 0;
option_all = 1;
} else {
- set = razor_root_open_read_only(option_root);
+ set = razor_root_open_read_only(option_root, atomic);
+ if (!set) {
+ fprintf(stderr, "%s\n",
+ razor_atomic_get_error_msg(atomic));
+ razor_atomic_destroy(atomic);
+ return;
+ }
}
pi = get_query_packages(set, argc, argv);
}
razor_package_iterator_destroy(pi);
+ razor_atomic_destroy(atomic);
}
static void
static void
command_erase(int argc, const char *argv[])
{
+ struct razor_atomic *atomic;
struct razor_set *set, *upstream, *next;
struct razor_transaction *trans;
struct razor_package_query *query;
exit(1);
}
- set = razor_set_open(repo_filename);
+ atomic = razor_atomic_open("Erase packages");
+
+ set = razor_set_open(repo_filename, atomic);
+ if (!set || razor_atomic_commit(atomic)) {
+ fprintf(stderr, "%s\n", razor_atomic_get_error_msg(atomic));
+ razor_atomic_destroy(atomic);
+ exit(1);
+ }
+ razor_atomic_destroy(atomic);
upstream = razor_set_create();
trans = razor_transaction_create(set, upstream);
razor_set_diff(set, next, update_package, NULL);
razor_transaction_destroy(trans);
- razor_set_destroy(set);
- razor_set_destroy(upstream);
+ razor_set_unref(set);
+ razor_set_unref(upstream);
- razor_set_destroy(next);
+ razor_set_unref(next);
}
static void
command_install(int argc, const char *argv[])
{
+ struct razor_atomic *atomic;
struct razor_set *set, *upstream, *next;
struct razor_transaction *trans;
struct razor_package_iterator *pi;
exit(1);
}
- set = razor_set_open(repo_filename);
+ atomic = razor_atomic_open("Install packages");
+
+ set = razor_set_open(repo_filename, atomic);
+ if (!set || razor_atomic_commit(atomic)) {
+ fprintf(stderr, "%s\n", razor_atomic_get_error_msg(atomic));
+ razor_atomic_destroy(atomic);
+ }
+ razor_atomic_destroy(atomic);
upstream = create_set_from_command_line(argc, argv);
trans = razor_transaction_create(set, upstream);
razor_set_diff(set, next, update_package, NULL);
razor_transaction_destroy(trans);
- razor_set_destroy(set);
- razor_set_destroy(upstream);
+ razor_set_unref(set);
+ razor_set_unref(upstream);
- razor_set_destroy(next);
+ razor_set_unref(next);
}
static void
command_update(int argc, const char *argv[])
{
+ struct razor_atomic *atomic;
struct razor_set *set, *upstream, *next;
struct razor_transaction *trans;
struct razor_package_iterator *pi;
exit(1);
}
- set = razor_set_open(repo_filename);
+ atomic = razor_atomic_open("Update packages");
+
+ set = razor_set_open(repo_filename, atomic);
+ if (!set || razor_atomic_commit(atomic)) {
+ fprintf(stderr, "%s\n", razor_atomic_get_error_msg(atomic));
+ razor_atomic_destroy(atomic);
+ }
+ razor_atomic_destroy(atomic);
upstream = create_set_from_command_line(argc, argv);
trans = razor_transaction_create(set, upstream);
razor_set_diff(set, next, update_package, NULL);
razor_transaction_destroy(trans);
- razor_set_destroy(set);
- razor_set_destroy(upstream);
+ razor_set_unref(set);
+ razor_set_unref(upstream);
- razor_set_destroy(next);
+ razor_set_unref(next);
}
static int