librazor/atomic-ktm.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.
ali@416
     1
/*
ali@416
     2
 * Copyright (C) 2011-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 HAVE_WINDOWS_KTM
ali@416
    22
ali@416
    23
#include <stdlib.h>
ali@416
    24
#include <windows.h>
ali@416
    25
#include <stdio.h>
ali@416
    26
#include <limits.h>
ali@416
    27
#include <errno.h>
ali@416
    28
#include <unistd.h>
ali@416
    29
#include <fcntl.h>
ali@416
    30
#include <sys/stat.h>
ali@416
    31
#include <string.h>
ali@416
    32
#include <assert.h>
ali@416
    33
#include <wchar.h>
ali@416
    34
#include <ktmw32.h>
ali@416
    35
ali@416
    36
#include "razor.h"
ali@416
    37
#include "razor-internal.h"
ali@416
    38
ali@416
    39
#define RAZOR_ASCII_ISALPHA(c)	\
ali@416
    40
			((c) >= 'A' && (c) <= 'Z' || (c) >= 'a' && (c) <= 'z')
ali@416
    41
ali@416
    42
static int
ali@416
    43
razor_valid_root_name2(const wchar_t *name)
ali@416
    44
{
ali@416
    45
	if (razor_allow_all_root_names())
ali@416
    46
		return !wcschr(name, '/');
ali@416
    47
ali@416
    48
	return RAZOR_ASCII_ISALPHA(name[0]) && name[1] == ':' &&
ali@416
    49
	       name[2] == '\0';
ali@416
    50
}
ali@416
    51
ali@416
    52
struct razor_wstr {
ali@416
    53
	wchar_t *str;
ali@416
    54
	int len, allocated;
ali@416
    55
};
ali@416
    56
ali@416
    57
static struct razor_wstr *
ali@416
    58
razor_wstr_create(const char *init, int len)
ali@416
    59
{
ali@416
    60
	int n;
ali@416
    61
	struct razor_wstr *wstr;
ali@416
    62
ali@416
    63
	wstr = malloc(sizeof(struct razor_wstr));
ali@416
    64
ali@416
    65
	n = MultiByteToWideChar(CP_UTF8, 0, init, len, NULL, 0);
ali@416
    66
	if (len >= 0 && init[len])
ali@416
    67
		wstr->len = n++;
ali@416
    68
	else
ali@416
    69
		wstr->len = n - 1;
ali@416
    70
ali@416
    71
	wstr->allocated = n * 2;
ali@416
    72
	wstr->str = malloc(wstr->allocated * sizeof(wchar_t));
ali@416
    73
	if (!wstr->str) {
ali@416
    74
		free(wstr);
ali@416
    75
		return NULL;
ali@416
    76
	}
ali@416
    77
ali@416
    78
	(void)MultiByteToWideChar(CP_UTF8, 0, init, len, wstr->str, n);
ali@416
    79
	if (len >= 0 && init[len])
ali@416
    80
		wstr->str[wstr->len] = 0;
ali@416
    81
ali@416
    82
	return wstr;
ali@416
    83
}
ali@416
    84
ali@416
    85
static int
ali@416
    86
razor_wstr_append(struct razor_wstr *wstr, const char *s, int len)
ali@416
    87
{
ali@416
    88
	int n, allocated;
ali@416
    89
	wchar_t *str;
ali@416
    90
ali@416
    91
	n = MultiByteToWideChar(CP_UTF8, 0, s, len, NULL, 0);
ali@416
    92
	if (len < 0 || !s[len])
ali@416
    93
		n--;
ali@416
    94
ali@416
    95
	if (wstr->allocated <= wstr->len + n) {
ali@416
    96
		allocated = (wstr->len + n + 1) * 2;
ali@416
    97
		str = realloc(wstr->str, allocated * sizeof(wchar_t));
ali@416
    98
		if (!str)
ali@416
    99
			return -1;
ali@416
   100
		wstr->allocated = allocated;
ali@416
   101
		wstr->str = str;
ali@416
   102
	}
ali@416
   103
ali@416
   104
	(void)MultiByteToWideChar(CP_UTF8, 0, s, len, wstr->str + wstr->len, n);
ali@416
   105
	wstr->len += n;
ali@416
   106
	wstr->str[wstr->len] = 0;
ali@416
   107
ali@416
   108
	return 0;
ali@416
   109
}
ali@416
   110
ali@416
   111
static void
ali@416
   112
razor_wstr_destroy(struct razor_wstr *wstr)
ali@416
   113
{
ali@416
   114
	free(wstr->str);
ali@416
   115
	free(wstr);
ali@416
   116
}
ali@416
   117
ali@416
   118
RAZOR_EXPORT struct razor_atomic *
ali@416
   119
razor_atomic_open(const char *description)
ali@416
   120
{
ali@416
   121
	wchar_t *buf;
ali@416
   122
	struct razor_atomic *atomic;
ali@416
   123
ali@416
   124
	atomic = zalloc(sizeof *atomic);
ali@416
   125
	buf = razor_utf8_to_utf16(description, -1);
ali@416
   126
	atomic->transaction = CreateTransaction(NULL, 0,
ali@416
   127
						TRANSACTION_DO_NOT_PROMOTE,
ali@416
   128
						0, 0, 0, buf);
ali@416
   129
	free(buf);
ali@416
   130
ali@416
   131
	return atomic;
ali@416
   132
}
ali@416
   133
ali@416
   134
void
ali@416
   135
razor_atomic_set_error_str(struct razor_atomic *atomic, const wchar_t *path,
ali@416
   136
			   const char *str)
ali@416
   137
{
ali@416
   138
	assert(!atomic->error_str);
ali@416
   139
ali@416
   140
	free(atomic->error_path);
ali@416
   141
ali@416
   142
	if (path)
ali@416
   143
		atomic->error_path = razor_utf16_to_utf8(path, -1);
ali@416
   144
	else
ali@416
   145
		atomic->error_path = NULL;
ali@416
   146
ali@416
   147
	atomic->error_str = strdup(str);
ali@416
   148
}
ali@416
   149
ali@416
   150
static void
ali@416
   151
razor_atomic_set_error(struct razor_atomic *atomic, const wchar_t *path,
ali@416
   152
		       DWORD error)
ali@416
   153
{
ali@416
   154
	wchar_t *buf;
ali@416
   155
ali@416
   156
	assert(!atomic->error_str);
ali@416
   157
ali@416
   158
	free(atomic->error_path);
ali@416
   159
ali@416
   160
	if (path)
ali@416
   161
		atomic->error_path = razor_utf16_to_utf8(path, -1);
ali@416
   162
	else
ali@416
   163
		atomic->error_path = NULL;
ali@416
   164
ali@416
   165
	FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER|
ali@416
   166
		       FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS,
ali@416
   167
		       NULL, error, MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT),
ali@416
   168
		       (LPWSTR)&buf, 0, NULL);
ali@416
   169
	atomic->error_str = razor_utf16_to_utf8(buf, -1);
ali@416
   170
	LocalFree(buf);
ali@416
   171
}
ali@416
   172
ali@416
   173
RAZOR_EXPORT int
ali@416
   174
razor_atomic_commit(struct razor_atomic *atomic)
ali@416
   175
{
ali@416
   176
	int retval;
ali@416
   177
ali@416
   178
	if (razor_atomic_in_error_state(atomic))
ali@416
   179
		return -1;
ali@416
   180
ali@416
   181
	retval = !CommitTransaction(atomic->transaction);
ali@416
   182
ali@416
   183
	if (retval) {
ali@416
   184
		razor_atomic_set_error(atomic, NULL, GetLastError());
ali@416
   185
		RollbackTransaction(atomic->transaction);
ali@416
   186
	}
ali@416
   187
ali@416
   188
	CloseHandle(atomic->transaction);
ali@416
   189
	atomic->transaction = INVALID_HANDLE_VALUE;
ali@416
   190
ali@416
   191
	return retval;
ali@416
   192
}
ali@416
   193
ali@416
   194
RAZOR_EXPORT void
ali@416
   195
razor_atomic_destroy(struct razor_atomic *atomic)
ali@416
   196
{
ali@416
   197
	int i;
ali@416
   198
ali@416
   199
	for(i = 0; i < atomic->n_files; i++) {
ali@416
   200
		if (atomic->files[i].h != INVALID_HANDLE_VALUE) {
ali@416
   201
			CloseHandle(atomic->files[i].h);
ali@416
   202
			free(atomic->files[i].path);
ali@416
   203
		}
ali@416
   204
	}
ali@416
   205
	free(atomic->files);
ali@416
   206
	if (atomic->transaction != INVALID_HANDLE_VALUE) {
ali@416
   207
		RollbackTransaction(atomic->transaction);
ali@416
   208
		CloseHandle(atomic->transaction);
ali@416
   209
	}
ali@416
   210
	free(atomic->error_path);
ali@416
   211
	free(atomic->error_str);
ali@416
   212
	free(atomic->error_msg);
ali@416
   213
	free(atomic);
ali@416
   214
}
ali@416
   215
ali@416
   216
RAZOR_EXPORT int
ali@416
   217
razor_atomic_make_dirs(struct razor_atomic *atomic, const char *root,
ali@416
   218
		       const char *path)
ali@416
   219
{
ali@416
   220
	struct razor_wstr *buffer;
ali@416
   221
	const char *slash, *next;
ali@416
   222
	WIN32_FILE_ATTRIBUTE_DATA fa;
ali@416
   223
	DWORD err;
ali@416
   224
	int r, creating = 0;
ali@416
   225
ali@416
   226
	if (razor_atomic_in_error_state(atomic))
ali@416
   227
		return -1;
ali@416
   228
ali@416
   229
	buffer = razor_wstr_create(root, -1);
ali@416
   230
	slash = path;
ali@416
   231
ali@416
   232
	for (; *slash != '\0'; slash = next) {
ali@416
   233
		next = strpbrk(slash + 1, "/\\");
ali@416
   234
		if (next == NULL)
ali@416
   235
			break;
ali@416
   236
ali@416
   237
		razor_wstr_append(buffer, slash, next - slash);
ali@416
   238
ali@416
   239
		if (!creating) {
ali@416
   240
			if (razor_valid_root_name2(buffer->str))
ali@416
   241
				continue;
ali@416
   242
ali@416
   243
			r = GetFileAttributesTransactedW(buffer->str,
ali@416
   244
							 GetFileExInfoStandard,
ali@416
   245
							 &fa,
ali@416
   246
							 atomic->transaction);
ali@416
   247
ali@416
   248
			if (!r) {
ali@416
   249
				err = GetLastError();
ali@416
   250
				if (err == ERROR_FILE_NOT_FOUND) {
ali@416
   251
					creating = 1;
ali@416
   252
				} else {
ali@416
   253
					razor_atomic_set_error(atomic,
ali@416
   254
							       buffer->str,
ali@416
   255
							       err);
ali@416
   256
					razor_wstr_destroy(buffer);
ali@416
   257
					return -1;
ali@416
   258
				}
ali@416
   259
			} else if (!(fa.dwFileAttributes&
ali@416
   260
				     FILE_ATTRIBUTE_DIRECTORY)) {
ali@416
   261
				razor_atomic_set_error_str(atomic, buffer->str,
ali@416
   262
							   "Not a directory");
ali@416
   263
				razor_wstr_destroy(buffer);
ali@416
   264
				return -1;
ali@416
   265
			}
ali@416
   266
		}
ali@416
   267
		if (creating) {
ali@416
   268
			if (!CreateDirectoryTransactedW(NULL, buffer->str, NULL,
ali@416
   269
							atomic->transaction)) {
ali@416
   270
				razor_atomic_set_error(atomic, buffer->str,
ali@416
   271
						       GetLastError());
ali@416
   272
				razor_wstr_destroy(buffer);
ali@416
   273
				return -1;
ali@416
   274
			}
ali@416
   275
ali@416
   276
			/* FIXME: What to do about permissions for dirs we
ali@416
   277
			 * have to create but are not in the cpio archive? */
ali@416
   278
		}
ali@416
   279
	}
ali@416
   280
ali@416
   281
	razor_wstr_destroy(buffer);
ali@416
   282
ali@416
   283
	return 0;
ali@416
   284
}
ali@416
   285
ali@416
   286
RAZOR_EXPORT int
ali@416
   287
razor_atomic_remove(struct razor_atomic *atomic, const char *path)
ali@416
   288
{
ali@416
   289
	wchar_t *buf;
ali@416
   290
	DWORD err;
ali@416
   291
ali@416
   292
	if (razor_atomic_in_error_state(atomic))
ali@416
   293
		return -1;
ali@416
   294
ali@416
   295
	buf = razor_utf8_to_utf16(path, -1);
ali@416
   296
ali@416
   297
	if (DeleteFileTransactedW(buf, atomic->transaction)) {
ali@416
   298
		free(buf);
ali@416
   299
		return 0;
ali@416
   300
	}
ali@416
   301
ali@416
   302
	err = GetLastError();
ali@416
   303
	if (err == ERROR_FILE_NOT_FOUND || err == ERROR_PATH_NOT_FOUND) {
ali@416
   304
		free(buf);
ali@416
   305
		return 0;
ali@416
   306
	}
ali@416
   307
ali@416
   308
	if (SetFileAttributesTransactedW(buf, FILE_ATTRIBUTE_NORMAL,
ali@416
   309
					 atomic->transaction)) {
ali@416
   310
		if (DeleteFileTransactedW(buf, atomic->transaction)) {
ali@416
   311
			free(buf);
ali@416
   312
			return 0;
ali@416
   313
		}
ali@416
   314
		err = GetLastError();
ali@416
   315
	}
ali@416
   316
ali@416
   317
	if (RemoveDirectoryTransactedW(buf, atomic->transaction) ||
ali@416
   318
	    GetLastError() == ERROR_DIR_NOT_EMPTY) {
ali@416
   319
		free(buf);
ali@416
   320
		return 0;
ali@416
   321
	}
ali@416
   322
ali@416
   323
	/*
ali@416
   324
	 * It would be tempting to use:
ali@416
   325
	 * 	MoveFileEx(path, NULL, MOVEFILE_DELAY_UNTIL_REBOOT)
ali@416
   326
	 * but unless we can guarantee that the system will be rebooted
ali@416
   327
	 * before we (or some other application) write another file with the
ali@416
   328
	 * same path, this is likely to cause more problems than it solves.
ali@416
   329
	 */
ali@416
   330
ali@416
   331
	razor_atomic_set_error(atomic, buf, err);
ali@416
   332
	free(buf);
ali@416
   333
	return -1;
ali@416
   334
}
ali@416
   335
ali@416
   336
RAZOR_EXPORT int
ali@416
   337
razor_atomic_rename_file(struct razor_atomic *atomic, const char *oldpath,
ali@416
   338
			 const char *newpath)
ali@416
   339
{
ali@416
   340
	wchar_t *oldbuf, *newbuf;
ali@416
   341
	const DWORD flags = MOVEFILE_COPY_ALLOWED | MOVEFILE_REPLACE_EXISTING;
ali@416
   342
ali@416
   343
	if (razor_atomic_in_error_state(atomic))
ali@416
   344
		return -1;
ali@416
   345
ali@416
   346
	newbuf = razor_utf8_to_utf16(newpath, -1);
ali@416
   347
	oldbuf = razor_utf8_to_utf16(oldpath, -1);
ali@416
   348
ali@416
   349
	/*
ali@416
   350
	 * Passing MOVEFILE_REPLACE_EXISTING to MoveFileTransaction() will
ali@416
   351
	 * cover every case we care about _except_ replacing an empty
ali@416
   352
	 * directory with a file. Calling RemoveDirectoryTransacted() will deal
ali@416
   353
	 * with this case while having no effect in all other cases.
ali@416
   354
	 */
ali@416
   355
	(void)RemoveDirectoryTransactedW(newbuf, atomic->transaction);
ali@416
   356
ali@416
   357
	if (!MoveFileTransactedW(oldbuf, newbuf, NULL, NULL, flags,
ali@416
   358
			         atomic->transaction))
ali@416
   359
		razor_atomic_set_error(atomic, newbuf, GetLastError());
ali@416
   360
ali@416
   361
	free(newbuf);
ali@416
   362
	free(oldbuf);
ali@416
   363
ali@416
   364
	return !!atomic->error_str;
ali@416
   365
}
ali@416
   366
ali@416
   367
RAZOR_EXPORT int
ali@416
   368
razor_atomic_create_dir(struct razor_atomic *atomic, const char *dirname,
ali@416
   369
			mode_t mode)
ali@416
   370
{
ali@416
   371
	wchar_t *buf;
ali@416
   372
	DWORD err;
ali@416
   373
	WIN32_FILE_ATTRIBUTE_DATA fa;
ali@416
   374
ali@416
   375
	if (razor_atomic_in_error_state(atomic))
ali@416
   376
		return -1;
ali@416
   377
ali@416
   378
	buf = razor_utf8_to_utf16(dirname, -1);
ali@416
   379
ali@416
   380
	if (!CreateDirectoryTransactedW(NULL, buf, NULL, atomic->transaction)) {
ali@416
   381
		err = GetLastError();
ali@416
   382
		if (err != ERROR_FILE_EXISTS && err != ERROR_ALREADY_EXISTS) {
ali@416
   383
abort:
ali@416
   384
			razor_atomic_set_error(atomic, buf, err);
ali@416
   385
			free(buf);
ali@416
   386
			return -1;
ali@416
   387
		}
ali@416
   388
ali@416
   389
		if (!GetFileAttributesTransactedW(buf, GetFileExInfoStandard,
ali@416
   390
						  &fa, atomic->transaction))
ali@416
   391
			goto abort;
ali@416
   392
ali@416
   393
		if (!(fa.dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY)) {
ali@416
   394
			if (razor_atomic_remove(atomic, dirname)) {
ali@416
   395
				free(buf);
ali@416
   396
				return -1;
ali@416
   397
			}
ali@416
   398
			if (!CreateDirectoryTransactedW(NULL, buf, NULL,
ali@416
   399
							atomic->transaction)) {
ali@416
   400
				err = GetLastError();
ali@416
   401
				goto abort;
ali@416
   402
			}
ali@416
   403
		}
ali@416
   404
	}
ali@416
   405
ali@416
   406
	free(buf);
ali@416
   407
ali@416
   408
	return 0;
ali@416
   409
}
ali@416
   410
ali@416
   411
RAZOR_EXPORT int
ali@416
   412
razor_atomic_create_symlink(struct razor_atomic *atomic, const char *target,
ali@416
   413
			    const char *path)
ali@416
   414
{
ali@416
   415
	if (razor_atomic_in_error_state(atomic))
ali@416
   416
		return -1;
ali@416
   417
ali@416
   418
	/*
ali@416
   419
	 * This isn't true, but symbolic links under Windows 7
ali@416
   420
	 * need to know whether the target is a directory or not
ali@416
   421
	 * and we don't always know that at the time when the
ali@416
   422
	 * link is created, so it's a convienent lie for now.
ali@416
   423
	 */
ali@416
   424
	razor_atomic_set_error_str(atomic, NULL, "Symbolic links not supported "
ali@416
   425
						 "on this platform");
ali@416
   426
ali@416
   427
	return -1;
ali@416
   428
}
ali@416
   429
ali@416
   430
RAZOR_EXPORT int
ali@416
   431
razor_atomic_create_file(struct razor_atomic *atomic, const char *filename,
ali@416
   432
			 mode_t mode)
ali@416
   433
{
ali@416
   434
	DWORD attribs;
ali@416
   435
	struct razor_atomic_file *files;
ali@416
   436
	int i = atomic->n_files;
ali@416
   437
ali@416
   438
	if (razor_atomic_in_error_state(atomic))
ali@416
   439
		return -1;
ali@416
   440
ali@416
   441
	files = realloc(atomic->files,
ali@416
   442
			(atomic->n_files+1) * sizeof(struct razor_atomic_file));
ali@416
   443
	if (!files) {
ali@416
   444
		razor_atomic_set_error_str(atomic, NULL, "Not enough memory");
ali@416
   445
		return -1;
ali@416
   446
	}
ali@416
   447
	atomic->n_files++;
ali@416
   448
	atomic->files = files;
ali@416
   449
ali@416
   450
	files[i].path = razor_utf8_to_utf16(filename, -1);
ali@416
   451
ali@416
   452
	/*
ali@416
   453
	 * Passing CREATE_ALWAYS to CreateFileTransacted() will cover
ali@416
   454
	 * every case we care about _except_ replacing an empty directory
ali@416
   455
	 * with a file. Calling RemoveDirectoryTransacted() will deal
ali@416
   456
	 * with this case while having no effect in all other cases.
ali@416
   457
	 */
ali@416
   458
	(void)RemoveDirectoryTransactedW(files[i].path, atomic->transaction);
ali@416
   459
ali@416
   460
	if (mode & S_IWUSR)
ali@416
   461
		attribs = FILE_ATTRIBUTE_NORMAL;
ali@416
   462
	else
ali@416
   463
		attribs = FILE_ATTRIBUTE_READONLY;
ali@416
   464
ali@416
   465
	files[i].h = CreateFileTransactedW(files[i].path, GENERIC_WRITE,
ali@416
   466
					   0, NULL, CREATE_ALWAYS, attribs,
ali@416
   467
					   NULL, atomic->transaction, NULL,
ali@416
   468
					   NULL);
ali@416
   469
ali@416
   470
	if (files[i].h == INVALID_HANDLE_VALUE) {
ali@416
   471
		razor_atomic_set_error(atomic, files[i].path, GetLastError());
ali@416
   472
		free(files[i].path);
ali@416
   473
		atomic->n_files--;
ali@416
   474
		return -1;
ali@416
   475
	}
ali@416
   476
ali@416
   477
	return i;
ali@416
   478
}
ali@416
   479
ali@416
   480
RAZOR_EXPORT int
ali@416
   481
razor_atomic_write(struct razor_atomic *atomic, int handle, const void *data,
ali@416
   482
		   size_t size)
ali@416
   483
{
ali@416
   484
	DWORD written;
ali@416
   485
ali@416
   486
	if (razor_atomic_in_error_state(atomic))
ali@416
   487
		return -1;
ali@416
   488
ali@416
   489
	assert(handle < atomic->n_files);
ali@416
   490
	assert(atomic->files[handle].h != INVALID_HANDLE_VALUE);
ali@416
   491
ali@416
   492
	while(size) {
ali@416
   493
		if (!WriteFile(atomic->files[handle].h, data, size, &written,
ali@416
   494
			       NULL)) {
ali@416
   495
			razor_atomic_set_error(atomic,
ali@416
   496
					       atomic->files[handle].path,
ali@416
   497
					       GetLastError());
ali@416
   498
ali@416
   499
			(void)CloseHandle(atomic->files[handle].h);
ali@416
   500
			free(atomic->files[handle].path);
ali@416
   501
			atomic->files[handle].path = NULL;
ali@416
   502
			atomic->files[handle].h = INVALID_HANDLE_VALUE;
ali@416
   503
ali@416
   504
			return -1;
ali@416
   505
		}
ali@416
   506
ali@416
   507
		data += written;
ali@416
   508
		size -= written;
ali@416
   509
	}
ali@416
   510
ali@416
   511
	return 0;
ali@416
   512
}
ali@416
   513
ali@416
   514
RAZOR_EXPORT int
ali@416
   515
razor_atomic_sync(struct razor_atomic *atomic, int handle)
ali@416
   516
{
ali@416
   517
	HANDLE h;
ali@416
   518
ali@416
   519
	if (razor_atomic_in_error_state(atomic))
ali@416
   520
		return -1;
ali@416
   521
ali@416
   522
	assert(handle < atomic->n_files);
ali@416
   523
	assert(atomic->files[handle].h != INVALID_HANDLE_VALUE);
ali@416
   524
ali@416
   525
	if (!CloseHandle(atomic->files[handle].h)) {
ali@416
   526
		razor_atomic_set_error(atomic, atomic->files[handle].path,
ali@416
   527
				       GetLastError());
ali@416
   528
		free(atomic->files[handle].path);
ali@416
   529
		atomic->files[handle].path = NULL;
ali@416
   530
		atomic->files[handle].h = INVALID_HANDLE_VALUE;
ali@416
   531
		return -1;
ali@416
   532
	}
ali@416
   533
ali@416
   534
	h = CreateFileTransactedW(atomic->files[handle].path, GENERIC_WRITE, 0,
ali@416
   535
				  NULL, OPEN_EXISTING, 0, NULL,
ali@416
   536
				  atomic->transaction, NULL, NULL);
ali@416
   537
	atomic->files[handle].h = h;
ali@416
   538
ali@416
   539
	if (atomic->files[handle].h == INVALID_HANDLE_VALUE) {
ali@416
   540
		razor_atomic_set_error(atomic, atomic->files[handle].path,
ali@416
   541
				       GetLastError());
ali@416
   542
		free(atomic->files[handle].path);
ali@416
   543
		atomic->files[handle].path = NULL;
ali@416
   544
		return -1;
ali@416
   545
	}
ali@416
   546
ali@416
   547
	return !!atomic->error_str;
ali@416
   548
}
ali@416
   549
ali@416
   550
RAZOR_EXPORT int
ali@416
   551
razor_atomic_close(struct razor_atomic *atomic, int handle)
ali@416
   552
{
ali@416
   553
	if (razor_atomic_in_error_state(atomic))
ali@416
   554
		return -1;
ali@416
   555
ali@416
   556
	assert(handle < atomic->n_files);
ali@416
   557
	assert(atomic->files[handle].h != INVALID_HANDLE_VALUE);
ali@416
   558
ali@416
   559
	if (!CloseHandle(atomic->files[handle].h))
ali@416
   560
		razor_atomic_set_error(atomic, atomic->files[handle].path,
ali@416
   561
				       GetLastError());
ali@416
   562
ali@416
   563
	free(atomic->files[handle].path);
ali@416
   564
	atomic->files[handle].path = NULL;
ali@416
   565
	atomic->files[handle].h = INVALID_HANDLE_VALUE;
ali@416
   566
ali@416
   567
	while(atomic->n_files > 0 &&
ali@416
   568
	      atomic->files[atomic->n_files-1].h == INVALID_HANDLE_VALUE)
ali@416
   569
		atomic->n_files--;
ali@416
   570
ali@416
   571
	return !!atomic->error_str;
ali@416
   572
}
ali@416
   573
ali@416
   574
#endif		/* HAVE_WINDOWS_KTM */