librazor/atomic-none.c
author J. Ali Harlow <ali@juiblex.co.uk>
Thu Feb 09 20:45:27 2012 +0000 (2012-02-09)
changeset 418 33b825d3128d
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 #if !ENABLE_ATOMIC
    22 
    23 #include <stdlib.h>
    24 #ifdef MSWIN_API
    25 #include <windows.h>
    26 #endif
    27 #include <stdio.h>
    28 #include <limits.h>
    29 #include <errno.h>
    30 #include <unistd.h>
    31 #include <fcntl.h>
    32 #include <sys/stat.h>
    33 #include <string.h>
    34 #include <assert.h>
    35 
    36 #include "razor.h"
    37 #include "razor-internal.h"
    38 
    39 #ifndef O_BINARY
    40 #define O_BINARY	0
    41 #endif
    42 
    43 RAZOR_EXPORT struct razor_atomic *
    44 razor_atomic_open(const char *description)
    45 {
    46 	struct razor_atomic *atomic;
    47 
    48 	atomic = zalloc(sizeof *atomic);
    49 
    50 	return atomic;
    51 }
    52 
    53 RAZOR_EXPORT int
    54 razor_atomic_commit(struct razor_atomic *atomic)
    55 {
    56 	return razor_atomic_in_error_state(atomic);
    57 }
    58 
    59 RAZOR_EXPORT void
    60 razor_atomic_destroy(struct razor_atomic *atomic)
    61 {
    62 	free(atomic->error_path);
    63 	free(atomic->error_str);
    64 	free(atomic->error_msg);
    65 	free(atomic);
    66 }
    67 
    68 RAZOR_EXPORT int
    69 razor_atomic_make_dirs(struct razor_atomic *atomic, const char *root,
    70 		       const char *path)
    71 {
    72 	char buffer[PATH_MAX], *p;
    73 	const char *slash, *next;
    74 	struct stat buf;
    75 
    76 	if (razor_atomic_in_error_state(atomic))
    77 		return -1;
    78 
    79 	strcpy(buffer, root);
    80 	p = buffer + strlen(buffer);
    81 	slash = path;
    82 	for (slash = path; *slash != '\0'; slash = next) {
    83 #ifdef MSWIN_API
    84 		next = strpbrk(slash + 1, "/\\");
    85 #else
    86 		next = strchr(slash + 1, '/');
    87 #endif
    88 		if (next == NULL)
    89 			break;
    90 
    91 		memcpy(p, slash, next - slash);
    92 		p += next - slash;
    93 		*p = '\0';
    94 
    95 		if (razor_valid_root_name(buffer))
    96 			continue;
    97 
    98 		if (stat(buffer, &buf) == 0) {
    99 			if (!S_ISDIR(buf.st_mode)) {
   100 				razor_atomic_set_error_str(atomic, buffer,
   101 							   "Not a directory");
   102 				return -1;
   103 			}
   104 		} else if (mkdir(buffer, 0777) < 0) {
   105 			razor_atomic_set_error_str(atomic, buffer,
   106 						   strerror(errno));
   107 			return -1;
   108 		}
   109 	}
   110 
   111 	return 0;
   112 }
   113 
   114 RAZOR_EXPORT int
   115 razor_atomic_remove(struct razor_atomic *atomic, const char *path)
   116 {
   117 #ifdef MSWIN_API
   118 	wchar_t *buf;
   119 	DWORD err;
   120 #endif
   121 
   122 	if (razor_atomic_in_error_state(atomic))
   123 		return -1;
   124 
   125 #ifdef MSWIN_API
   126 	buf = razor_utf8_to_utf16(path, -1);
   127 
   128 	if (!DeleteFileW(buf)) {
   129 		err = GetLastError();
   130 		if (err != ERROR_FILE_NOT_FOUND &&
   131 		    err != ERROR_PATH_NOT_FOUND &&
   132 		    !(SetFileAttributesW(buf, FILE_ATTRIBUTE_NORMAL) &&
   133 		      DeleteFileW(buf)) &&
   134 		    !RemoveDirectoryW(buf) &&
   135 		    GetLastError() != ERROR_DIR_NOT_EMPTY)
   136 			razor_atomic_set_error_mswin(atomic, buf, err);
   137 	}
   138 
   139 	free(buf);
   140 #else
   141 	if (remove(path))
   142 		razor_atomic_set_error_str(atomic, path, strerror(errno));
   143 #endif
   144 
   145 	return !!atomic->error_str;
   146 }
   147 
   148 RAZOR_EXPORT int
   149 razor_atomic_rename_file(struct razor_atomic *atomic, const char *oldpath,
   150 			 const char *newpath)
   151 {
   152 #ifdef MSWIN_API
   153 	wchar_t *oldbuf, *newbuf;
   154 	const DWORD flags = MOVEFILE_COPY_ALLOWED | MOVEFILE_REPLACE_EXISTING;
   155 #endif
   156 
   157 	if (razor_atomic_in_error_state(atomic))
   158 		return -1;
   159 
   160 #ifdef MSWIN_API
   161 	newbuf = razor_utf8_to_utf16(newpath, -1);
   162 	oldbuf = razor_utf8_to_utf16(oldpath, -1);
   163 
   164 	/*
   165 	 * Passing MOVEFILE_REPLACE_EXISTING to MoveFileEx() will
   166 	 * cover every case we care about _except_ replacing an empty
   167 	 * directory with a file. Calling RemoveDirectory() will deal
   168 	 * with this case while having no effect in all other cases.
   169 	 */
   170 	(void)RemoveDirectoryW(newbuf);
   171 
   172 	if (!MoveFileExW(oldbuf, newbuf, flags))
   173 		razor_atomic_set_error_mswin(atomic, newbuf, GetLastError());
   174 
   175 	free(newbuf);
   176 	free(oldbuf);
   177 #else
   178 	if (rename(oldpath, newpath))
   179 		razor_atomic_set_error_str(atomic, newpath, strerror(errno));
   180 #endif
   181 
   182 	return !!atomic->error_str;
   183 }
   184 
   185 RAZOR_EXPORT int
   186 razor_atomic_create_dir(struct razor_atomic *atomic, const char *dirname,
   187 			mode_t mode)
   188 {
   189 	if (razor_atomic_in_error_state(atomic))
   190 		return -1;
   191 
   192 	if (!mkdir(dirname, mode & (S_IRWXU | S_IRWXG | S_IRWXO)))
   193 		return 0;
   194 
   195 	if (errno != EEXIST) {
   196 		razor_atomic_set_error_str(atomic, dirname, strerror(errno));
   197 		return -1;
   198 	}
   199 
   200 	if (chmod(dirname, mode & (S_IRWXU | S_IRWXG | S_IRWXO)) < 0) {
   201 		razor_atomic_set_error_str(atomic, dirname, strerror(errno));
   202 		return -1;
   203 	}
   204 
   205 	return 0;
   206 }
   207 
   208 RAZOR_EXPORT int
   209 razor_atomic_create_symlink(struct razor_atomic *atomic, const char *target,
   210 			    const char *path)
   211 {
   212 	if (razor_atomic_in_error_state(atomic))
   213 		return -1;
   214 
   215 #if HAVE_SYMLINK
   216 	if (symlink(target, path) < 0) {
   217 		razor_atomic_set_error_str(atomic, NULL, strerror(errno));
   218 		return -1;
   219 	}
   220 
   221 	return 0;
   222 #else
   223 	razor_atomic_set_error_str(atomic, NULL, "Symbolic links not supported "
   224 						 "on this platform");
   225 
   226 	return -1;
   227 #endif
   228 }
   229 
   230 RAZOR_EXPORT int
   231 razor_atomic_create_file(struct razor_atomic *atomic, const char *filename,
   232 			 mode_t mode)
   233 {
   234 	int fd;
   235 
   236 	if (razor_atomic_in_error_state(atomic))
   237 		return -1;
   238 
   239 	atomic->error_path = strdup(filename);
   240 	fd = open(atomic->error_path, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
   241 		  mode & (S_IRWXU | S_IRWXG | S_IRWXO));
   242 
   243 	if (fd == -1)
   244 		razor_atomic_set_error_str(atomic, NULL, strerror(errno));
   245 
   246 	return fd;
   247 }
   248 
   249 #endif	/* !ENABLE_ATOMIC */