librazor/atomic-emulate.c
author J. Ali Harlow <ali@juiblex.co.uk>
Sat Feb 11 23:50:26 2012 +0000 (2012-02-11)
changeset 423 6112bcc5d1cf
parent 416 d0aa9e0a6d04
child 435 275a4428c13b
permissions -rw-r--r--
Add an error object.
This is intended to dis-entangle the two roles that the atomic
object has evolved into so that atomic need only be used where
atomic actions are actually being undertaken.
     1 /*
     2  * Copyright (C) 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 && !HAVE_WINDOWS_KTM
    22 
    23 #include <stdlib.h>
    24 #include <stdio.h>
    25 #include <string.h>
    26 #include <unistd.h>
    27 #include <sys/types.h>
    28 #include <sys/stat.h>
    29 #include <fcntl.h>
    30 #include <dirent.h>
    31 #include <errno.h>
    32 #include "razor-internal.h"
    33 
    34 /*
    35  * Emulated atomic support
    36  *
    37  * This implementation is better than nothing, but is certainly not atomic.
    38  * It does have a couple of advantages over atomic-none:
    39  *	- If a file operation fails while a package is being installed we
    40  *	  have a good chance of being able to rollback the transaction to
    41  *	  a well-known state.
    42  *	- We behave similarly to atomic-ktm in that changes are not visible
    43  *	  on disk to non-atomic operations (eg., scripts) until the atomic
    44  *	  is committed. This makes the testsuite more likely to pick up
    45  *	  problems that would otherwise only be found when using razor on
    46  *	  an MS-Windows system which supports KTM.
    47  */
    48 
    49 #ifndef O_BINARY
    50 #define O_BINARY	0
    51 #endif
    52 
    53 static void recursive_remove(const char *directory)
    54 {
    55 	DIR *dp;
    56 	struct dirent *dirp;
    57 	char *buf;
    58 
    59 	dp = opendir(directory);
    60 	while((dirp = readdir(dp))) {
    61 		if (strcmp(dirp->d_name, ".") && strcmp(dirp->d_name, "..")) {
    62 			buf = malloc(strlen(directory) + strlen(dirp->d_name)
    63 				     + 2);
    64 			sprintf(buf, "%s/%s", directory, dirp->d_name);
    65 			if (remove(buf) < 0)
    66 				recursive_remove(buf);
    67 			free(buf);
    68 		}
    69 	}
    70 
    71 	rmdir(directory);
    72 }
    73 
    74 RAZOR_EXPORT struct razor_atomic *razor_atomic_open(const char *description)
    75 {
    76 	struct razor_atomic *atomic;
    77 
    78 	atomic = zalloc(sizeof *atomic);
    79 
    80 	atomic->toplevel = strdup(".atomic-XXXXXX");
    81 	if (!mkdtemp(atomic->toplevel)) {
    82 		free(atomic->toplevel);
    83 		free(atomic);
    84 		return NULL;
    85 	}
    86 
    87 	atomic->description = strdup(description);
    88 
    89 	return atomic;
    90 }
    91 
    92 RAZOR_EXPORT int razor_atomic_commit(struct razor_atomic *atomic)
    93 {
    94 	struct atomic_action *actions;
    95 
    96 	if (razor_atomic_in_error_state(atomic))
    97 		return -1;
    98 
    99 	if (atomic->actions) {
   100 		actions = atomic_action_list_reverse(atomic->actions);
   101 		atomic->actions = NULL;
   102 		actions = atomic_action_do(atomic, actions);
   103 		atomic_action_free(actions);
   104 	}
   105 
   106 	if (atomic->toplevel) {
   107 		recursive_remove(atomic->toplevel);
   108 		free(atomic->toplevel);
   109 		atomic->toplevel = NULL;
   110 	}
   111 
   112 	return razor_atomic_in_error_state(atomic);
   113 }
   114 
   115 RAZOR_EXPORT void razor_atomic_destroy(struct razor_atomic *atomic)
   116 {
   117 	if (atomic->toplevel) {
   118 		recursive_remove(atomic->toplevel);
   119 		free(atomic->toplevel);
   120 		atomic->toplevel = NULL;
   121 	}
   122 
   123 	if (atomic->error)
   124 		razor_error_free(atomic->error);
   125 
   126 	free(atomic);
   127 }
   128 
   129 RAZOR_EXPORT int
   130 razor_atomic_make_dirs(struct razor_atomic *atomic, const char *root,
   131 		       const char *path)
   132 {
   133 	struct atomic_action *a;
   134 
   135 	if (razor_atomic_in_error_state(atomic))
   136 		return -1;
   137 
   138 	a = atomic_action_new(ACTION_MAKE_DIRS);
   139 	a->args.path = strdup(path);
   140 	a->args.u.make_dirs.root = strdup(root);
   141 	atomic->actions = atomic_action_list_prepend(atomic->actions, a);
   142 
   143 	return 0;
   144 }
   145 
   146 RAZOR_EXPORT int
   147 razor_atomic_remove(struct razor_atomic *atomic, const char *path)
   148 {
   149 	struct atomic_action *a;
   150 
   151 	if (razor_atomic_in_error_state(atomic))
   152 		return -1;
   153 
   154 	a = atomic_action_new(ACTION_REMOVE);
   155 	a->args.path = strdup(path);
   156 	atomic->actions = atomic_action_list_prepend(atomic->actions, a);
   157 
   158 	return 0;
   159 }
   160 
   161 RAZOR_EXPORT int
   162 razor_atomic_rename_file(struct razor_atomic *atomic, const char *oldpath,
   163 			 const char *newpath)
   164 {
   165 	struct atomic_action *a;
   166 
   167 	if (razor_atomic_in_error_state(atomic))
   168 		return -1;
   169 
   170 	a = atomic_action_new(ACTION_MOVE);
   171 	a->args.path = strdup(oldpath);
   172 	a->args.u.move.dest = strdup(newpath);
   173 	atomic->actions = atomic_action_list_prepend(atomic->actions, a);
   174 
   175 	return 0;
   176 }
   177 
   178 RAZOR_EXPORT int
   179 razor_atomic_create_dir(struct razor_atomic *atomic, const char *dirname,
   180 			mode_t mode)
   181 {
   182 	struct atomic_action *a;
   183 
   184 	if (razor_atomic_in_error_state(atomic))
   185 		return -1;
   186 
   187 	a = atomic_action_new(ACTION_CREATE_DIR);
   188 	a->args.path = strdup(dirname);
   189 	a->args.u.create_dir.mode = mode;
   190 	atomic->actions = atomic_action_list_prepend(atomic->actions, a);
   191 
   192 	return 0;
   193 }
   194 
   195 RAZOR_EXPORT int
   196 razor_atomic_create_symlink(struct razor_atomic *atomic, const char *target,
   197 			    const char *path)
   198 {
   199 #if HAVE_SYMLINK
   200 	struct atomic_action *a;
   201 #endif
   202 
   203 	if (razor_atomic_in_error_state(atomic))
   204 		return -1;
   205 
   206 #if HAVE_SYMLINK
   207 	a = atomic_action_new(ACTION_CREATE_SYMLINK);
   208 	a->args.path = strdup(path);
   209 	a->args.u.create_symlink.target = strdup(target);
   210 	atomic->actions = atomic_action_list_prepend(atomic->actions, a);
   211 
   212 	return 0;
   213 #else
   214 	atomic->error = razor_error_new_str(NULL,
   215 					    "Symbolic links not supported "
   216 					    "on this platform");
   217 
   218 	return -1;
   219 #endif
   220 }
   221 
   222 RAZOR_EXPORT int
   223 razor_atomic_create_file(struct razor_atomic *atomic, const char *filename,
   224                          mode_t mode)
   225 {
   226 	int fd;
   227 	struct atomic_action *a;
   228 	char *tmpnam;
   229 
   230 	if (razor_atomic_in_error_state(atomic))
   231 		return -1;
   232 
   233 	tmpnam = atomic_action_attic_tmpnam(atomic);
   234 	fd = open(tmpnam, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
   235 		  mode & (S_IRWXU | S_IRWXG | S_IRWXO));
   236 
   237 	if (fd == -1)
   238 		atomic->error = razor_error_new_str(filename, strerror(errno));
   239 	else {
   240 		a = atomic_action_new(ACTION_MOVE);
   241 		a->args.path = tmpnam;
   242 		a->args.u.move.dest = strdup(filename);
   243 		atomic->actions = atomic_action_list_prepend(atomic->actions,
   244 							     a);
   245 	}
   246 
   247 	return fd;
   248 }
   249 
   250 #endif	/* ENABLE_ATOMIC && !HAVE_WINDOWS_KTM */