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.
     1 /*
     2  * Copyright (C) 2011, 2012, 2014  J. Ali Harlow <ali@juiblex.co.uk>
     3  *
     4  * This program is free software; you can redistribute it and/or modify
     5  * it under the terms of the GNU General Public License as published by
     6  * the Free Software Foundation; either version 2 of the License, or
     7  * (at your option) any later version.
     8  *
     9  * This program is distributed in the hope that it will be useful,
    10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    12  * GNU General Public License for more details.
    13  *
    14  * You should have received a copy of the GNU General Public License along
    15  * with this program; if not, write to the Free Software Foundation, Inc.,
    16  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
    17  */
    18 
    19 #include "config.h"
    20 
    21 #if !ENABLE_ATOMIC
    22 
    23 #include <stdlib.h>
    24 #ifdef MSWIN_API
    25 #include <windows.h>
    26 #endif
    27 #include <stdio.h>
    28 #include <limits.h>
    29 #include <errno.h>
    30 #include <unistd.h>
    31 #include <fcntl.h>
    32 #include <sys/stat.h>
    33 #include <string.h>
    34 #include <assert.h>
    35 
    36 #include "razor.h"
    37 #include "razor-internal.h"
    38 
    39 #ifndef O_BINARY
    40 #define O_BINARY	0
    41 #endif
    42 
    43 RAZOR_EXPORT struct razor_atomic *
    44 razor_atomic_open(const char *description)
    45 {
    46 	struct razor_atomic *atomic;
    47 
    48 	atomic = zalloc(sizeof *atomic);
    49 
    50 	return atomic;
    51 }
    52 
    53 RAZOR_EXPORT int
    54 razor_atomic_commit(struct razor_atomic *atomic)
    55 {
    56 	return razor_atomic_in_error_state(atomic);
    57 }
    58 
    59 RAZOR_EXPORT void
    60 razor_atomic_destroy(struct razor_atomic *atomic)
    61 {
    62 	if (atomic->error)
    63 		razor_error_free(atomic->error);
    64 
    65 	free(atomic);
    66 }
    67 
    68 RAZOR_EXPORT int
    69 razor_atomic_make_dirs(struct razor_atomic *atomic, const char *root,
    70 		       const char *path)
    71 {
    72 	char buffer[PATH_MAX], *p;
    73 	const char *slash, *next;
    74 	struct stat buf;
    75 
    76 	if (razor_atomic_in_error_state(atomic))
    77 		return -1;
    78 
    79 	strcpy(buffer, root);
    80 	p = buffer + strlen(buffer);
    81 	slash = (p > buffer) ? SKIP_DRIVE_PATH(path) : path;
    82 
    83 	for (slash = path; *slash != '\0'; slash = next) {
    84 #ifdef MSWIN_API
    85 		next = strpbrk(slash + 1, "/\\");
    86 #else
    87 		next = strchr(slash + 1, '/');
    88 #endif
    89 		if (next == NULL)
    90 			break;
    91 
    92 		memcpy(p, slash, next - slash);
    93 		p += next - slash;
    94 		*p = '\0';
    95 
    96 		if (razor_valid_root_name(buffer))
    97 			continue;
    98 
    99 		if (stat(buffer, &buf) == 0) {
   100 			if (!S_ISDIR(buf.st_mode)) {
   101 				atomic->error = razor_error_new_str(RAZOR_POSIX_ERROR,
   102 								    EEXIST,
   103 								    buffer,
   104 								    "Not a directory");
   105 				return -1;
   106 			}
   107 		} else if (mkdir(buffer, 0777) < 0) {
   108 			atomic->error = razor_error_new_posix(buffer);
   109 			return -1;
   110 		}
   111 	}
   112 
   113 	return 0;
   114 }
   115 
   116 RAZOR_EXPORT int
   117 razor_atomic_remove(struct razor_atomic *atomic, const char *path)
   118 {
   119 #ifdef MSWIN_API
   120 	wchar_t *buf;
   121 	DWORD err;
   122 #endif
   123 
   124 	if (razor_atomic_in_error_state(atomic))
   125 		return -1;
   126 
   127 #ifdef MSWIN_API
   128 	buf = razor_utf8_to_utf16(path, -1);
   129 
   130 	if (!DeleteFileW(buf)) {
   131 		err = GetLastError();
   132 		if (err != ERROR_FILE_NOT_FOUND &&
   133 		    err != ERROR_PATH_NOT_FOUND &&
   134 		    !(SetFileAttributesW(buf, FILE_ATTRIBUTE_NORMAL) &&
   135 		      DeleteFileW(buf)) &&
   136 		    !RemoveDirectoryW(buf) &&
   137 		    GetLastError() != ERROR_DIR_NOT_EMPTY)
   138 			atomic->error = razor_error_new_mswin(buf, err);
   139 	}
   140 
   141 	free(buf);
   142 #else
   143 	if (remove(path))
   144 		atomic->error = razor_error_new_posix(path);
   145 #endif
   146 
   147 	return razor_atomic_in_error_state(atomic);
   148 }
   149 
   150 RAZOR_EXPORT int
   151 razor_atomic_rename_file(struct razor_atomic *atomic, const char *oldpath,
   152 			 const char *newpath)
   153 {
   154 #ifdef MSWIN_API
   155 	wchar_t *oldbuf, *newbuf;
   156 	const DWORD flags = MOVEFILE_COPY_ALLOWED | MOVEFILE_REPLACE_EXISTING;
   157 #endif
   158 
   159 	if (razor_atomic_in_error_state(atomic))
   160 		return -1;
   161 
   162 #ifdef MSWIN_API
   163 	newbuf = razor_utf8_to_utf16(newpath, -1);
   164 	oldbuf = razor_utf8_to_utf16(oldpath, -1);
   165 
   166 	/*
   167 	 * Passing MOVEFILE_REPLACE_EXISTING to MoveFileEx() will
   168 	 * cover every case we care about _except_ replacing an empty
   169 	 * directory with a file. Calling RemoveDirectory() will deal
   170 	 * with this case while having no effect in all other cases.
   171 	 */
   172 	(void)RemoveDirectoryW(newbuf);
   173 
   174 	if (!MoveFileExW(oldbuf, newbuf, flags))
   175 		atomic->error = razor_error_new_mswin(newbuf, GetLastError());
   176 
   177 	free(newbuf);
   178 	free(oldbuf);
   179 #else
   180 	if (rename(oldpath, newpath))
   181 		atomic->error = razor_error_new_posix(newpath);
   182 #endif
   183 
   184 	return razor_atomic_in_error_state(atomic);
   185 }
   186 
   187 RAZOR_EXPORT int
   188 razor_atomic_create_dir(struct razor_atomic *atomic, const char *dirname,
   189 			mode_t mode)
   190 {
   191 	struct stat buf;
   192 
   193 	if (razor_atomic_in_error_state(atomic))
   194 		return -1;
   195 
   196 	if (!mkdir(dirname, mode & (S_IRWXU | S_IRWXG | S_IRWXO)))
   197 		return 0;
   198 
   199 	if (errno != EEXIST || stat(dirname, &buf)) {
   200 		atomic->error = razor_error_new_posix(dirname);
   201 		return -1;
   202 	}
   203 
   204 	if (!S_ISDIR(buf.st_mode)) {
   205 		atomic->error = razor_error_new_str(RAZOR_POSIX_ERROR, EEXIST,
   206 						    action->args.path,
   207 						    "Not a directory");
   208 		return -1;
   209 	}
   210 
   211 	return 0;
   212 }
   213 
   214 RAZOR_EXPORT int
   215 razor_atomic_create_symlink(struct razor_atomic *atomic, const char *target,
   216 			    const char *path)
   217 {
   218 	if (razor_atomic_in_error_state(atomic))
   219 		return -1;
   220 
   221 #if HAVE_SYMLINK
   222 	if (symlink(target, path) < 0) {
   223 		atomic->error = razor_error_new_posix(path);
   224 		return -1;
   225 	}
   226 
   227 	return 0;
   228 #else
   229 	atomic->error = razor_error_new_str(RAZOR_GENERAL_ERROR,
   230 					    RAZOR_GENERAL_ERROR_FAILED, NULL,
   231 					    "Symbolic links not supported "
   232 					    "on this platform");
   233 
   234 	return -1;
   235 #endif
   236 }
   237 
   238 RAZOR_EXPORT int
   239 razor_atomic_create_file(struct razor_atomic *atomic, const char *filename,
   240 			 mode_t mode)
   241 {
   242 	int fd;
   243 
   244 	if (razor_atomic_in_error_state(atomic))
   245 		return -1;
   246 
   247 	fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
   248 		  mode & (S_IRWXU | S_IRWXG | S_IRWXO));
   249 
   250 	if (fd == -1)
   251 		atomic->error = razor_error_new_posix(filename);
   252 
   253 	return fd;
   254 }
   255 
   256 #endif	/* !ENABLE_ATOMIC */