librazor/atomic.c
author J. Ali Harlow <ali@juiblex.co.uk>
Thu Feb 09 20:45:27 2012 +0000 (2012-02-09)
changeset 418 33b825d3128d
parent 403 e63951c1d0f8
child 423 6112bcc5d1cf
permissions -rw-r--r--
Add transaction barriers
These allow packages to be installed and removed which have scripts
that depend on each other when atomic transactions are involved.
Note that yum supports pre, but not other requires flags. post will
need similar support to the post scripts themselves pulling in the
requires flags from the rpms. Likewise preun and postun will need
similar handling to those scrips since the requires flags will need
to be stored in the razor database.
     1 /*
     2  * Copyright (C) 2011-2012  J. Ali Harlow <ali@juiblex.co.uk>
     3  *
     4  * This program is free software; you can redistribute it and/or modify
     5  * it under the terms of the GNU General Public License as published by
     6  * the Free Software Foundation; either version 2 of the License, or
     7  * (at your option) any later version.
     8  *
     9  * This program is distributed in the hope that it will be useful,
    10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    12  * GNU General Public License for more details.
    13  *
    14  * You should have received a copy of the GNU General Public License along
    15  * with this program; if not, write to the Free Software Foundation, Inc.,
    16  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
    17  */
    18 
    19 #include "config.h"
    20 
    21 #include <stdlib.h>
    22 #include <stdio.h>
    23 #include <limits.h>
    24 #include <errno.h>
    25 #include <unistd.h>
    26 #include <sys/types.h>
    27 #include <sys/stat.h>
    28 #include <fcntl.h>
    29 #include <string.h>
    30 #include <assert.h>
    31 
    32 #include "razor.h"
    33 #include "razor-internal.h"
    34 
    35 /*
    36  * Atomic transactions
    37  */
    38 
    39 static int allow_all_root_names = 0;
    40 
    41 /*
    42  * Primarily intended for testing named roots under UNIX platforms.
    43  */
    44 RAZOR_EXPORT void
    45 razor_disable_root_name_checks(int disable)
    46 {
    47 	allow_all_root_names = disable;
    48 }
    49 
    50 int
    51 razor_allow_all_root_names(void)
    52 {
    53 	return allow_all_root_names;
    54 }
    55 
    56 RAZOR_EXPORT const char *
    57 razor_atomic_get_error_msg(struct razor_atomic *atomic)
    58 {
    59 	if (!atomic->error_msg) {
    60 		if (atomic->error_path)
    61 			atomic->error_msg = razor_concat(atomic->error_path,
    62 							 ": ",
    63 							 atomic->error_str,
    64 							 NULL);
    65 		else
    66 			atomic->error_msg = strdup(atomic->error_str);
    67 	}
    68 
    69 	return atomic->error_msg;
    70 }
    71 
    72 RAZOR_EXPORT void
    73 razor_atomic_abort(struct razor_atomic *atomic, const char *error_msg)
    74 {
    75 	if (!atomic->error_str)
    76 		razor_atomic_set_error_str(atomic, NULL, error_msg);
    77 }
    78 
    79 RAZOR_EXPORT int
    80 razor_atomic_in_error_state(struct razor_atomic *atomic)
    81 {
    82 	return atomic->error_str && !atomic->in_undo;
    83 }
    84 
    85 #if !HAVE_WINDOWS_KTM
    86 
    87 /*
    88  * Common code with atomic-none and atomic-emulate
    89  */
    90 
    91 #define RAZOR_ASCII_ISALPHA(c)	\
    92 			((c) >= 'A' && (c) <= 'Z' || (c) >= 'a' && (c) <= 'z')
    93 
    94 int
    95 razor_valid_root_name(const char *name)
    96 {
    97 	if (razor_allow_all_root_names()) {
    98 #ifdef MSWIN_API
    99 		return !strpbrk(name, "/\\");
   100 #else
   101 		return !strchr(name, '/');
   102 #endif
   103 	}
   104 
   105 #ifdef MSWIN_API
   106 	return RAZOR_ASCII_ISALPHA(name[0]) && name[1] == ':' &&
   107 	       name[2] == '\0';
   108 #else
   109 	return name[0] == '\0';
   110 #endif
   111 }
   112 
   113 #ifdef MSWIN_API
   114 void
   115 razor_atomic_set_error_mswin(struct razor_atomic *atomic, const wchar_t *path,
   116 			     DWORD error)
   117 {
   118 	wchar_t *buf;
   119 
   120 	assert(!atomic->error_str);
   121 
   122 	free(atomic->error_path);
   123 
   124 	if (path)
   125 		atomic->error_path = razor_utf16_to_utf8(path, -1);
   126 	else
   127 		atomic->error_path = NULL;
   128 
   129 	FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER|
   130 		       FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS,
   131 		       NULL, error, MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT),
   132 		       (LPWSTR)&buf, 0, NULL);
   133 	atomic->error_str = razor_utf16_to_utf8(buf, -1);
   134 	LocalFree(buf);
   135 }
   136 #endif
   137 
   138 void
   139 razor_atomic_set_error_str(struct razor_atomic *atomic, const char *path,
   140 			   const char *str)
   141 {
   142 	assert(!atomic->error_str);
   143 
   144 	atomic->error_path = path ? strdup(path) : NULL;
   145 	atomic->error_str = strdup(str);
   146 }
   147 
   148 RAZOR_EXPORT int
   149 razor_atomic_write(struct razor_atomic *atomic, int fd, const void *data,
   150 		   size_t size)
   151 {
   152 	int written;
   153 
   154 	if (razor_atomic_in_error_state(atomic))
   155 		return -1;
   156 
   157 	while(size) {
   158 		written = write(fd, data, size);
   159 		if (written < 0) {
   160 			razor_atomic_set_error_str(atomic, NULL,
   161 						   strerror(errno));
   162 
   163 			(void)close(fd);
   164 
   165 			return -1;
   166 		}
   167 
   168 		data += written;
   169 		size -= written;
   170 	}
   171 
   172 	return 0;
   173 }
   174 
   175 RAZOR_EXPORT int
   176 razor_atomic_sync(struct razor_atomic *atomic, int handle)
   177 {
   178 	if (razor_atomic_in_error_state(atomic))
   179 		return -1;
   180 
   181 	if (fsync(handle) < 0) {
   182 		razor_atomic_set_error_str(atomic, NULL, strerror(errno));
   183 		return -1;
   184 	}
   185 
   186 	free(atomic->error_path);
   187 	atomic->error_path = NULL;
   188 
   189 	return 0;
   190 }
   191 
   192 RAZOR_EXPORT int
   193 razor_atomic_close(struct razor_atomic *atomic, int fd)
   194 {
   195 	if (razor_atomic_in_error_state(atomic))
   196 		return -1;
   197 
   198 	if (close(fd) < 0) {
   199 		razor_atomic_set_error_str(atomic, NULL, strerror(errno));
   200 		return -1;
   201 	}
   202 
   203 	free(atomic->error_path);
   204 	atomic->error_path = NULL;
   205 
   206 	return 0;
   207 }
   208 
   209 #endif	/* !HAVE_WINDOWS_KTM */