librazor/atomic-ktm.c
author J. Ali Harlow <ali@juiblex.co.uk>
Fri Apr 15 16:58:07 2016 +0100 (2016-04-15)
changeset 469 4aaa4b4b29e5
parent 441 cf499fd51df7
child 475 008c75a5e08d
permissions -rw-r--r--
Added tag 0.6.2 for changeset 45e2bb06c88d
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 */