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