librazor/atomic-ktm.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) 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 */