librazor/atomic-none.c
author J. Ali Harlow <ali@juiblex.co.uk>
Sat Oct 04 18:12:58 2014 +0100 (2014-10-04)
changeset 454 56ff755c268c
parent 441 cf499fd51df7
child 475 008c75a5e08d
permissions -rw-r--r--
Only export symbols starting with razor_ in dynamic library.

Apart from being good practice to avoid clashes with higher-level
libraries and the application, this also fixes an obscure bug: The
gnulib library is used both by librazor (the dynamic library) and
by razor (the executable). In doing so, we want to have two separate
copies of the library despite the code duplication this involves.
Without the explicit limit to export only razor_ symbols, the razor
executable under mingw64 was picking up the getopt_long function
from librazor and the optind variable from libgnu which meant that
it did not see optind changing. Hiding librazor's copy of getopt
causes the linker to find libgnu's copy and everything works.

Note that under mingw librazor-#.dll still contains undocumented
(private) razor_ symbols but these will do no harm as long as nobody
tries to use them.
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@423
   247
	fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
ali@416
   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 */