librazor/atomic-emulate.c
author ali <j.a.harlow@letterboxes.org>
Thu Feb 09 20:45:27 2012 +0000 (2012-02-09)
changeset 419 891991677a7f
child 423 6112bcc5d1cf
permissions -rw-r--r--
Release version 0.5.3
ali@416
     1
/*
ali@416
     2
 * Copyright (C) 2012  J. Ali Harlow <ali@juiblex.co.uk>
ali@416
     3
 *
ali@416
     4
 * This program is free software; you can redistribute it and/or modify
ali@416
     5
 * it under the terms of the GNU General Public License as published by
ali@416
     6
 * the Free Software Foundation; either version 2 of the License, or
ali@416
     7
 * (at your option) any later version.
ali@416
     8
 *
ali@416
     9
 * This program is distributed in the hope that it will be useful,
ali@416
    10
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
ali@416
    11
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
ali@416
    12
 * GNU General Public License for more details.
ali@416
    13
 *
ali@416
    14
 * You should have received a copy of the GNU General Public License along
ali@416
    15
 * with this program; if not, write to the Free Software Foundation, Inc.,
ali@416
    16
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
ali@416
    17
 */
ali@416
    18
ali@416
    19
#include "config.h"
ali@416
    20
ali@416
    21
#if ENABLE_ATOMIC && !HAVE_WINDOWS_KTM
ali@416
    22
ali@416
    23
#include <stdlib.h>
ali@416
    24
#include <string.h>
ali@416
    25
#include <unistd.h>
ali@416
    26
#include <sys/types.h>
ali@416
    27
#include <sys/stat.h>
ali@416
    28
#include <fcntl.h>
ali@416
    29
#include <dirent.h>
ali@416
    30
#include <errno.h>
ali@416
    31
#include "razor-internal.h"
ali@416
    32
ali@416
    33
/*
ali@416
    34
 * Emulated atomic support
ali@416
    35
 *
ali@416
    36
 * This implementation is better than nothing, but is certainly not atomic.
ali@416
    37
 * It does have a couple of advantages over atomic-none:
ali@416
    38
 *	- If a file operation fails while a package is being installed we
ali@416
    39
 *	  have a good chance of being able to rollback the transaction to
ali@416
    40
 *	  a well-known state.
ali@416
    41
 *	- We behave similarly to atomic-ktm in that changes are not visible
ali@416
    42
 *	  on disk to non-atomic operations (eg., scripts) until the atomic
ali@416
    43
 *	  is committed. This makes the testsuite more likely to pick up
ali@416
    44
 *	  problems that would otherwise only be found when using razor on
ali@416
    45
 *	  an MS-Windows system which supports KTM.
ali@416
    46
 */
ali@416
    47
ali@416
    48
#ifndef O_BINARY
ali@416
    49
#define O_BINARY	0
ali@416
    50
#endif
ali@416
    51
ali@416
    52
static void recursive_remove(const char *directory)
ali@416
    53
{
ali@416
    54
	DIR *dp;
ali@416
    55
	struct dirent *dirp;
ali@416
    56
	char *buf;
ali@416
    57
ali@416
    58
	dp = opendir(directory);
ali@416
    59
	while((dirp = readdir(dp))) {
ali@416
    60
		if (strcmp(dirp->d_name, ".") && strcmp(dirp->d_name, "..")) {
ali@416
    61
			buf = malloc(strlen(directory) + strlen(dirp->d_name)
ali@416
    62
				     + 2);
ali@416
    63
			sprintf(buf, "%s/%s", directory, dirp->d_name);
ali@416
    64
			if (remove(buf) < 0)
ali@416
    65
				recursive_remove(buf);
ali@416
    66
			free(buf);
ali@416
    67
		}
ali@416
    68
	}
ali@416
    69
ali@416
    70
	rmdir(directory);
ali@416
    71
}
ali@416
    72
ali@416
    73
RAZOR_EXPORT struct razor_atomic *razor_atomic_open(const char *description)
ali@416
    74
{
ali@416
    75
	struct razor_atomic *atomic;
ali@416
    76
ali@416
    77
	atomic = zalloc(sizeof *atomic);
ali@416
    78
ali@416
    79
	atomic->toplevel = strdup(".atomic-XXXXXX");
ali@416
    80
	if (!mkdtemp(atomic->toplevel)) {
ali@416
    81
		free(atomic->toplevel);
ali@416
    82
		free(atomic);
ali@416
    83
		return NULL;
ali@416
    84
	}
ali@416
    85
ali@416
    86
	atomic->description = strdup(description);
ali@416
    87
ali@416
    88
	return atomic;
ali@416
    89
}
ali@416
    90
ali@416
    91
RAZOR_EXPORT int razor_atomic_commit(struct razor_atomic *atomic)
ali@416
    92
{
ali@416
    93
	struct atomic_action *actions;
ali@416
    94
ali@416
    95
	if (razor_atomic_in_error_state(atomic))
ali@416
    96
		return -1;
ali@416
    97
ali@416
    98
	if (atomic->actions) {
ali@416
    99
		actions = atomic_action_list_reverse(atomic->actions);
ali@416
   100
		atomic->actions = NULL;
ali@416
   101
		actions = atomic_action_do(atomic, actions);
ali@416
   102
		atomic_action_free(actions);
ali@416
   103
	}
ali@416
   104
ali@416
   105
	if (atomic->toplevel) {
ali@416
   106
		recursive_remove(atomic->toplevel);
ali@416
   107
		free(atomic->toplevel);
ali@416
   108
		atomic->toplevel = NULL;
ali@416
   109
	}
ali@416
   110
ali@416
   111
	return !!atomic->error_str;
ali@416
   112
}
ali@416
   113
ali@416
   114
RAZOR_EXPORT void razor_atomic_destroy(struct razor_atomic *atomic)
ali@416
   115
{
ali@416
   116
	if (atomic->toplevel) {
ali@416
   117
		recursive_remove(atomic->toplevel);
ali@416
   118
		free(atomic->toplevel);
ali@416
   119
		atomic->toplevel = NULL;
ali@416
   120
	}
ali@416
   121
ali@416
   122
	free(atomic->error_path);
ali@416
   123
	free(atomic->error_str);
ali@416
   124
	free(atomic->error_msg);
ali@416
   125
	free(atomic);
ali@416
   126
}
ali@416
   127
ali@416
   128
RAZOR_EXPORT int
ali@416
   129
razor_atomic_make_dirs(struct razor_atomic *atomic, const char *root,
ali@416
   130
		       const char *path)
ali@416
   131
{
ali@416
   132
	struct atomic_action *a;
ali@416
   133
ali@416
   134
	if (razor_atomic_in_error_state(atomic))
ali@416
   135
		return -1;
ali@416
   136
ali@416
   137
	a = atomic_action_new(ACTION_MAKE_DIRS);
ali@416
   138
	a->args.path = strdup(path);
ali@416
   139
	a->args.u.make_dirs.root = strdup(root);
ali@416
   140
	atomic->actions = atomic_action_list_prepend(atomic->actions, a);
ali@416
   141
ali@416
   142
	return 0;
ali@416
   143
}
ali@416
   144
ali@416
   145
RAZOR_EXPORT int
ali@416
   146
razor_atomic_remove(struct razor_atomic *atomic, const char *path)
ali@416
   147
{
ali@416
   148
	struct atomic_action *a;
ali@416
   149
ali@416
   150
	if (razor_atomic_in_error_state(atomic))
ali@416
   151
		return -1;
ali@416
   152
ali@416
   153
	a = atomic_action_new(ACTION_REMOVE);
ali@416
   154
	a->args.path = strdup(path);
ali@416
   155
	atomic->actions = atomic_action_list_prepend(atomic->actions, a);
ali@416
   156
ali@416
   157
	return 0;
ali@416
   158
}
ali@416
   159
ali@416
   160
RAZOR_EXPORT int
ali@416
   161
razor_atomic_rename_file(struct razor_atomic *atomic, const char *oldpath,
ali@416
   162
			 const char *newpath)
ali@416
   163
{
ali@416
   164
	struct atomic_action *a;
ali@416
   165
ali@416
   166
	if (razor_atomic_in_error_state(atomic))
ali@416
   167
		return -1;
ali@416
   168
ali@416
   169
	a = atomic_action_new(ACTION_MOVE);
ali@416
   170
	a->args.path = strdup(oldpath);
ali@416
   171
	a->args.u.move.dest = strdup(newpath);
ali@416
   172
	atomic->actions = atomic_action_list_prepend(atomic->actions, a);
ali@416
   173
ali@416
   174
	return 0;
ali@416
   175
}
ali@416
   176
ali@416
   177
RAZOR_EXPORT int
ali@416
   178
razor_atomic_create_dir(struct razor_atomic *atomic, const char *dirname,
ali@416
   179
			mode_t mode)
ali@416
   180
{
ali@416
   181
	struct atomic_action *a;
ali@416
   182
ali@416
   183
	if (razor_atomic_in_error_state(atomic))
ali@416
   184
		return -1;
ali@416
   185
ali@416
   186
	a = atomic_action_new(ACTION_CREATE_DIR);
ali@416
   187
	a->args.path = strdup(dirname);
ali@416
   188
	a->args.u.create_dir.mode = mode;
ali@416
   189
	atomic->actions = atomic_action_list_prepend(atomic->actions, a);
ali@416
   190
ali@416
   191
	return 0;
ali@416
   192
}
ali@416
   193
ali@416
   194
RAZOR_EXPORT int
ali@416
   195
razor_atomic_create_symlink(struct razor_atomic *atomic, const char *target,
ali@416
   196
			    const char *path)
ali@416
   197
{
ali@416
   198
#if HAVE_SYMLINK
ali@416
   199
	struct atomic_action *a;
ali@416
   200
#endif
ali@416
   201
ali@416
   202
	if (razor_atomic_in_error_state(atomic))
ali@416
   203
		return -1;
ali@416
   204
ali@416
   205
#if HAVE_SYMLINK
ali@416
   206
	a = atomic_action_new(ACTION_CREATE_SYMLINK);
ali@416
   207
	a->args.path = strdup(path);
ali@416
   208
	a->args.u.create_symlink.target = strdup(target);
ali@416
   209
	atomic->actions = atomic_action_list_prepend(atomic->actions, a);
ali@416
   210
ali@416
   211
	return 0;
ali@416
   212
#else
ali@416
   213
	razor_atomic_set_error_str(atomic, NULL, "Symbolic links not supported "
ali@416
   214
						 "on this platform");
ali@416
   215
ali@416
   216
	return -1;
ali@416
   217
#endif
ali@416
   218
}
ali@416
   219
ali@416
   220
RAZOR_EXPORT int
ali@416
   221
razor_atomic_create_file(struct razor_atomic *atomic, const char *filename,
ali@416
   222
                         mode_t mode)
ali@416
   223
{
ali@416
   224
	int fd;
ali@416
   225
	struct atomic_action *a;
ali@416
   226
	char *tmpnam;
ali@416
   227
ali@416
   228
	if (razor_atomic_in_error_state(atomic))
ali@416
   229
		return -1;
ali@416
   230
ali@416
   231
	atomic->error_path = strdup(filename);
ali@416
   232
	tmpnam = atomic_action_attic_tmpnam(atomic);
ali@416
   233
	fd = open(tmpnam, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
ali@416
   234
		  mode & (S_IRWXU | S_IRWXG | S_IRWXO));
ali@416
   235
ali@416
   236
	if (fd == -1)
ali@416
   237
		razor_atomic_set_error_str(atomic, NULL, strerror(errno));
ali@416
   238
	else {
ali@416
   239
		a = atomic_action_new(ACTION_MOVE);
ali@416
   240
		a->args.path = tmpnam;
ali@416
   241
		a->args.u.move.dest = strdup(filename);
ali@416
   242
		atomic->actions = atomic_action_list_prepend(atomic->actions,
ali@416
   243
							     a);
ali@416
   244
	}
ali@416
   245
ali@416
   246
	return fd;
ali@416
   247
}
ali@416
   248
ali@416
   249
#endif	/* ENABLE_ATOMIC && !HAVE_WINDOWS_KTM */