librazor/atomic-ktm.c
author J. Ali Harlow <ali@juiblex.co.uk>
Thu Oct 09 17:27:41 2014 +0100 (2014-10-09)
changeset 455 df914f383f5c
parent 441 cf499fd51df7
child 475 008c75a5e08d
permissions -rw-r--r--
Support downloading from local repository even without libcurl

Using the --url option of the razor executable, it is possible
to specify a yum repository on the local machine (eg., on installation
media) and import from there, eg.,:

C> razor --url file:///d:/ import-yum

This will be handled by libcurl if available but if not, an internal
copy routine will be used.

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