librazor/atomic-none.c
author J. Ali Harlow <ali@juiblex.co.uk>
Tue Jun 05 11:07:53 2018 +0100 (2018-06-05)
changeset 498 5a49f274ab2d
parent 450 f969505e9265
permissions -rw-r--r--
Fix bug with handling empty root in KTM version of make_dirs
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 !ENABLE_ATOMIC
ali@416
    22
ali@416
    23
#include <stdlib.h>
ali@416
    24
#ifdef MSWIN_API
ali@416
    25
#include <windows.h>
ali@416
    26
#endif
ali@416
    27
#include <stdio.h>
ali@416
    28
#include <limits.h>
ali@416
    29
#include <errno.h>
ali@416
    30
#include <unistd.h>
ali@416
    31
#include <fcntl.h>
ali@416
    32
#include <sys/stat.h>
ali@416
    33
#include <string.h>
ali@416
    34
#include <assert.h>
ali@416
    35
ali@416
    36
#include "razor.h"
ali@416
    37
#include "razor-internal.h"
ali@416
    38
ali@416
    39
#ifndef O_BINARY
ali@416
    40
#define O_BINARY	0
ali@416
    41
#endif
ali@416
    42
ali@416
    43
RAZOR_EXPORT struct razor_atomic *
ali@416
    44
razor_atomic_open(const char *description)
ali@416
    45
{
ali@416
    46
	struct razor_atomic *atomic;
ali@416
    47
ali@416
    48
	atomic = zalloc(sizeof *atomic);
ali@416
    49
ali@416
    50
	return atomic;
ali@416
    51
}
ali@416
    52
ali@416
    53
RAZOR_EXPORT int
ali@416
    54
razor_atomic_commit(struct razor_atomic *atomic)
ali@416
    55
{
ali@416
    56
	return razor_atomic_in_error_state(atomic);
ali@416
    57
}
ali@416
    58
ali@416
    59
RAZOR_EXPORT void
ali@416
    60
razor_atomic_destroy(struct razor_atomic *atomic)
ali@416
    61
{
ali@423
    62
	if (atomic->error)
ali@423
    63
		razor_error_free(atomic->error);
ali@423
    64
ali@416
    65
	free(atomic);
ali@416
    66
}
ali@416
    67
ali@416
    68
RAZOR_EXPORT int
ali@416
    69
razor_atomic_make_dirs(struct razor_atomic *atomic, const char *root,
ali@416
    70
		       const char *path)
ali@416
    71
{
ali@416
    72
	char buffer[PATH_MAX], *p;
ali@416
    73
	const char *slash, *next;
ali@416
    74
	struct stat buf;
ali@416
    75
ali@416
    76
	if (razor_atomic_in_error_state(atomic))
ali@416
    77
		return -1;
ali@416
    78
ali@416
    79
	strcpy(buffer, root);
ali@416
    80
	p = buffer + strlen(buffer);
ali@441
    81
	slash = (p > buffer) ? SKIP_DRIVE_PATH(path) : path;
ali@441
    82
ali@416
    83
	for (slash = path; *slash != '\0'; slash = next) {
ali@416
    84
#ifdef MSWIN_API
ali@416
    85
		next = strpbrk(slash + 1, "/\\");
ali@416
    86
#else
ali@416
    87
		next = strchr(slash + 1, '/');
ali@416
    88
#endif
ali@416
    89
		if (next == NULL)
ali@416
    90
			break;
ali@416
    91
ali@416
    92
		memcpy(p, slash, next - slash);
ali@416
    93
		p += next - slash;
ali@416
    94
		*p = '\0';
ali@416
    95
ali@416
    96
		if (razor_valid_root_name(buffer))
ali@416
    97
			continue;
ali@416
    98
ali@416
    99
		if (stat(buffer, &buf) == 0) {
ali@416
   100
			if (!S_ISDIR(buf.st_mode)) {
ali@450
   101
				atomic->error = razor_error_new_str(RAZOR_POSIX_ERROR,
ali@450
   102
								    EEXIST,
ali@450
   103
								    buffer,
ali@423
   104
								    "Not a directory");
ali@416
   105
				return -1;
ali@416
   106
			}
ali@416
   107
		} else if (mkdir(buffer, 0777) < 0) {
ali@450
   108
			atomic->error = razor_error_new_posix(buffer);
ali@416
   109
			return -1;
ali@416
   110
		}
ali@416
   111
	}
ali@416
   112
ali@416
   113
	return 0;
ali@416
   114
}
ali@416
   115
ali@416
   116
RAZOR_EXPORT int
ali@416
   117
razor_atomic_remove(struct razor_atomic *atomic, const char *path)
ali@416
   118
{
ali@416
   119
#ifdef MSWIN_API
ali@416
   120
	wchar_t *buf;
ali@416
   121
	DWORD err;
ali@416
   122
#endif
ali@416
   123
ali@416
   124
	if (razor_atomic_in_error_state(atomic))
ali@416
   125
		return -1;
ali@416
   126
ali@416
   127
#ifdef MSWIN_API
ali@416
   128
	buf = razor_utf8_to_utf16(path, -1);
ali@416
   129
ali@416
   130
	if (!DeleteFileW(buf)) {
ali@416
   131
		err = GetLastError();
ali@416
   132
		if (err != ERROR_FILE_NOT_FOUND &&
ali@416
   133
		    err != ERROR_PATH_NOT_FOUND &&
ali@416
   134
		    !(SetFileAttributesW(buf, FILE_ATTRIBUTE_NORMAL) &&
ali@416
   135
		      DeleteFileW(buf)) &&
ali@416
   136
		    !RemoveDirectoryW(buf) &&
ali@416
   137
		    GetLastError() != ERROR_DIR_NOT_EMPTY)
ali@423
   138
			atomic->error = razor_error_new_mswin(buf, err);
ali@416
   139
	}
ali@416
   140
ali@416
   141
	free(buf);
ali@416
   142
#else
ali@416
   143
	if (remove(path))
ali@450
   144
		atomic->error = razor_error_new_posix(path);
ali@416
   145
#endif
ali@416
   146
ali@423
   147
	return razor_atomic_in_error_state(atomic);
ali@416
   148
}
ali@416
   149
ali@416
   150
RAZOR_EXPORT int
ali@416
   151
razor_atomic_rename_file(struct razor_atomic *atomic, const char *oldpath,
ali@416
   152
			 const char *newpath)
ali@416
   153
{
ali@416
   154
#ifdef MSWIN_API
ali@416
   155
	wchar_t *oldbuf, *newbuf;
ali@416
   156
	const DWORD flags = MOVEFILE_COPY_ALLOWED | MOVEFILE_REPLACE_EXISTING;
ali@416
   157
#endif
ali@416
   158
ali@416
   159
	if (razor_atomic_in_error_state(atomic))
ali@416
   160
		return -1;
ali@416
   161
ali@416
   162
#ifdef MSWIN_API
ali@416
   163
	newbuf = razor_utf8_to_utf16(newpath, -1);
ali@416
   164
	oldbuf = razor_utf8_to_utf16(oldpath, -1);
ali@416
   165
ali@416
   166
	/*
ali@416
   167
	 * Passing MOVEFILE_REPLACE_EXISTING to MoveFileEx() will
ali@416
   168
	 * cover every case we care about _except_ replacing an empty
ali@416
   169
	 * directory with a file. Calling RemoveDirectory() will deal
ali@416
   170
	 * with this case while having no effect in all other cases.
ali@416
   171
	 */
ali@416
   172
	(void)RemoveDirectoryW(newbuf);
ali@416
   173
ali@416
   174
	if (!MoveFileExW(oldbuf, newbuf, flags))
ali@423
   175
		atomic->error = razor_error_new_mswin(newbuf, GetLastError());
ali@416
   176
ali@416
   177
	free(newbuf);
ali@416
   178
	free(oldbuf);
ali@416
   179
#else
ali@416
   180
	if (rename(oldpath, newpath))
ali@450
   181
		atomic->error = razor_error_new_posix(newpath);
ali@416
   182
#endif
ali@416
   183
ali@423
   184
	return razor_atomic_in_error_state(atomic);
ali@416
   185
}
ali@416
   186
ali@416
   187
RAZOR_EXPORT int
ali@416
   188
razor_atomic_create_dir(struct razor_atomic *atomic, const char *dirname,
ali@416
   189
			mode_t mode)
ali@416
   190
{
ali@450
   191
	struct stat buf;
ali@450
   192
ali@416
   193
	if (razor_atomic_in_error_state(atomic))
ali@416
   194
		return -1;
ali@416
   195
ali@416
   196
	if (!mkdir(dirname, mode & (S_IRWXU | S_IRWXG | S_IRWXO)))
ali@416
   197
		return 0;
ali@416
   198
ali@450
   199
	if (errno != EEXIST || stat(dirname, &buf)) {
ali@450
   200
		atomic->error = razor_error_new_posix(dirname);
ali@416
   201
		return -1;
ali@416
   202
	}
ali@416
   203
ali@450
   204
	if (!S_ISDIR(buf.st_mode)) {
ali@450
   205
		atomic->error = razor_error_new_str(RAZOR_POSIX_ERROR, EEXIST,
ali@450
   206
						    action->args.path,
ali@450
   207
						    "Not a directory");
ali@416
   208
		return -1;
ali@416
   209
	}
ali@416
   210
ali@416
   211
	return 0;
ali@416
   212
}
ali@416
   213
ali@416
   214
RAZOR_EXPORT int
ali@416
   215
razor_atomic_create_symlink(struct razor_atomic *atomic, const char *target,
ali@416
   216
			    const char *path)
ali@416
   217
{
ali@416
   218
	if (razor_atomic_in_error_state(atomic))
ali@416
   219
		return -1;
ali@416
   220
ali@416
   221
#if HAVE_SYMLINK
ali@416
   222
	if (symlink(target, path) < 0) {
ali@450
   223
		atomic->error = razor_error_new_posix(path);
ali@416
   224
		return -1;
ali@416
   225
	}
ali@416
   226
ali@416
   227
	return 0;
ali@416
   228
#else
ali@450
   229
	atomic->error = razor_error_new_str(RAZOR_GENERAL_ERROR,
ali@450
   230
					    RAZOR_GENERAL_ERROR_FAILED, NULL,
ali@423
   231
					    "Symbolic links not supported "
ali@423
   232
					    "on this platform");
ali@416
   233
ali@416
   234
	return -1;
ali@416
   235
#endif
ali@416
   236
}
ali@416
   237
ali@416
   238
RAZOR_EXPORT int
ali@416
   239
razor_atomic_create_file(struct razor_atomic *atomic, const char *filename,
ali@416
   240
			 mode_t mode)
ali@416
   241
{
ali@416
   242
	int fd;
ali@416
   243
ali@416
   244
	if (razor_atomic_in_error_state(atomic))
ali@416
   245
		return -1;
ali@416
   246
ali@475
   247
	fd = razor_uri_open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
ali@475
   248
			    mode & (S_IRWXU | S_IRWXG | S_IRWXO));
ali@416
   249
ali@416
   250
	if (fd == -1)
ali@450
   251
		atomic->error = razor_error_new_posix(filename);
ali@416
   252
ali@416
   253
	return fd;
ali@416
   254
}
ali@416
   255
ali@416
   256
#endif	/* !ENABLE_ATOMIC */