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.
2 * Copyright (C) 2012, 2014 J. Ali Harlow <ali@juiblex.co.uk>
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.
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.
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.
21 #if ENABLE_ATOMIC && !HAVE_WINDOWS_KTM
27 #include <sys/types.h>
33 #include "razor-internal.h"
36 * Emulated atomic support
38 * This implementation is better than nothing, but is certainly not atomic.
39 * It does have a couple of advantages over atomic-none:
40 * - If a file operation fails while a package is being installed we
41 * have a good chance of being able to rollback the transaction to
43 * - We behave similarly to atomic-ktm in that changes are not visible
44 * on disk to non-atomic operations (eg., scripts) until the atomic
45 * is committed. This makes the testsuite more likely to pick up
46 * problems that would otherwise only be found when using razor on
47 * an MS-Windows system which supports KTM.
54 static void recursive_remove(const char *directory)
60 dp = opendir(directory);
61 while((dirp = readdir(dp))) {
62 if (strcmp(dirp->d_name, ".") && strcmp(dirp->d_name, "..")) {
63 buf = malloc(strlen(directory) + strlen(dirp->d_name)
65 sprintf(buf, "%s/%s", directory, dirp->d_name);
67 recursive_remove(buf);
75 RAZOR_EXPORT struct razor_atomic *razor_atomic_open(const char *description)
77 struct razor_atomic *atomic;
79 atomic = zalloc(sizeof *atomic);
81 atomic->description = strdup(description);
86 RAZOR_EXPORT int razor_atomic_commit(struct razor_atomic *atomic)
88 struct atomic_action *actions;
90 if (razor_atomic_in_error_state(atomic))
93 if (atomic->actions) {
94 actions = atomic_action_list_reverse(atomic->actions);
95 atomic->actions = NULL;
96 actions = atomic_action_do(atomic, actions);
97 atomic_action_free(actions);
100 if (atomic->toplevel) {
101 recursive_remove(atomic->toplevel);
102 free(atomic->toplevel);
103 atomic->toplevel = NULL;
106 return razor_atomic_in_error_state(atomic);
109 RAZOR_EXPORT void razor_atomic_destroy(struct razor_atomic *atomic)
111 if (atomic->toplevel) {
112 recursive_remove(atomic->toplevel);
113 free(atomic->toplevel);
114 atomic->toplevel = NULL;
118 razor_error_free(atomic->error);
124 static char *absolute_path(const char *path)
127 char *result, *subpath, *p, *s, *t;
129 result = realpath(path, NULL);
131 if (!result && errno == ENOENT) {
137 result = strdup("/");
142 subpath = realpath(p, NULL);
146 len = strlen(subpath);
147 result = malloc(len + strlen(s) + 1);
148 memcpy(result, subpath, len);
149 strcpy(result + len, s);
151 } else if (errno != ENOENT)
160 result = realpath(".", NULL);
170 * We need a toplevel directory in which to hold temporary files
171 * before they are committed. Since we can generally assume that
172 * we have write permissions anywhere on the filesystem in
173 * question, the best location is at the relevant mount point.
174 * The most common case where this assumption fails is when
175 * testing, when the current directory is a good choice.
179 razor_atomic_set_toplevel_from_path(struct razor_atomic *atomic,
187 if (razor_atomic_in_error_state(atomic))
190 if (atomic->toplevel)
194 if (path[0]=='\\' && path[1]=='\\' && path[2] && path[2]!='\\'
195 && strchr(path+3,'\\')) {
196 /* We have a UNC path: \\servername\sharename... */
197 const char *sharename, *root;
200 sharename = strchr(path+3,'\\')+1;
201 root = strchr(sharename,'\\');
203 disklen = root - path;
205 disklen = strlen(path);
208 malloc(disklen + strlen("\\atomic-XXXXXX") + 1);
209 memcpy(atomic->toplevel, path, disklen);
210 strcpy(atomic->toplevel + disklen, "\\atomic-XXXXXX");
211 } else if ((*path>='A' && *path<='Z' || *path>='a' && *path<='z') &&
213 atomic->toplevel = strdup("X:\\atomic-XXXXXX");
214 *atomic->toplevel = *path;
220 n = GetCurrentDirectoryW(0, NULL);
221 buf = malloc(n * sizeof(wchar_t));
223 if (GetCurrentDirectoryW(n, buf)) {
224 dir = razor_utf16_to_utf8(buf, n - 1);
225 razor_atomic_set_toplevel_from_path(atomic, dir);
231 atomic->toplevel = strdup("C:\\atomic-XXXXXX");
238 * Find the mount point (assuming we can write to the
239 * whole filesystem). Otherwise stop at the first
240 * unwritable directory and take one step back.
242 char *s, *abspath, saved;
243 int len, can_step_back = 0;
245 abspath = absolute_path(path);
247 atomic->error = razor_error_new_posix(path);
251 if (stat(abspath, &buf) < 0) {
255 atomic->error = razor_error_new_posix(abspath);
260 filesystem = buf.st_dev;
262 len = strlen(abspath);
263 while(len > 1 && (s = strrchr(abspath, '/'))) {
267 len = s + 1 - abspath;
273 if (stat(abspath, &buf) < 0) {
277 atomic->error = razor_error_new_posix(abspath);
281 } else if (!filesystem)
282 filesystem = buf.st_dev;
284 if (buf.st_dev != filesystem || access(abspath, W_OK)) {
291 len = strlen(abspath);
298 len = 0; /* Avoid an unslightly double slash. */
299 atomic->toplevel = malloc(len + strlen("/.atomic-XXXXXX") + 1);
300 memcpy(atomic->toplevel, abspath, len);
301 strcpy(atomic->toplevel + len, "/.atomic-XXXXXX");
307 if (!mkdtemp(atomic->toplevel)) {
312 char *s = strdup("atomic-XXXXXX");
315 if (stat(".", &buf) < 0) {
316 atomic->error = razor_error_new_posix(".");
318 free(atomic->toplevel);
319 atomic->toplevel = NULL;
322 if (buf.st_dev != filesystem)
324 * Don't use a different filesystem. It will
325 * only fail later on (in rename) and cause
326 * an unhelpful error message (EXDEV).
332 free(atomic->toplevel);
333 atomic->toplevel = s;
340 atomic->error = razor_error_new_str(RAZOR_POSIX_ERROR, err,
344 free(atomic->toplevel);
345 atomic->toplevel = NULL;
348 return !atomic->toplevel;
352 razor_atomic_make_dirs(struct razor_atomic *atomic, const char *root,
355 struct atomic_action *a;
357 razor_atomic_set_toplevel_from_path(atomic, *root ? root : path);
359 if (razor_atomic_in_error_state(atomic))
362 a = atomic_action_new(ACTION_MAKE_DIRS);
363 a->args.path = strdup(path);
364 a->args.u.make_dirs.root = strdup(root);
365 atomic->actions = atomic_action_list_prepend(atomic->actions, a);
371 razor_atomic_remove(struct razor_atomic *atomic, const char *path)
373 struct atomic_action *a;
375 razor_atomic_set_toplevel_from_path(atomic, path);
377 if (razor_atomic_in_error_state(atomic))
380 a = atomic_action_new(ACTION_REMOVE);
381 a->args.path = strdup(path);
382 atomic->actions = atomic_action_list_prepend(atomic->actions, a);
388 razor_atomic_rename_file(struct razor_atomic *atomic, const char *oldpath,
391 struct atomic_action *a;
393 razor_atomic_set_toplevel_from_path(atomic, newpath);
395 if (razor_atomic_in_error_state(atomic))
398 a = atomic_action_new(ACTION_MOVE);
399 a->args.path = strdup(oldpath);
400 a->args.u.move.dest = strdup(newpath);
401 atomic->actions = atomic_action_list_prepend(atomic->actions, a);
407 razor_atomic_create_dir(struct razor_atomic *atomic, const char *dirname,
410 struct atomic_action *a;
412 razor_atomic_set_toplevel_from_path(atomic, dirname);
414 if (razor_atomic_in_error_state(atomic))
417 a = atomic_action_new(ACTION_CREATE_DIR);
418 a->args.path = strdup(dirname);
419 a->args.u.create_dir.mode = mode;
420 atomic->actions = atomic_action_list_prepend(atomic->actions, a);
426 razor_atomic_create_symlink(struct razor_atomic *atomic, const char *target,
430 struct atomic_action *a;
432 razor_atomic_set_toplevel_from_path(atomic, path);
435 if (razor_atomic_in_error_state(atomic))
439 a = atomic_action_new(ACTION_CREATE_SYMLINK);
440 a->args.path = strdup(path);
441 a->args.u.create_symlink.target = strdup(target);
442 atomic->actions = atomic_action_list_prepend(atomic->actions, a);
446 atomic->error = razor_error_new_str(RAZOR_POSIX_ERROR, ENOSYS, NULL,
447 "Symbolic links not supported "
455 razor_atomic_create_file(struct razor_atomic *atomic, const char *filename,
459 struct atomic_action *a;
462 razor_atomic_set_toplevel_from_path(atomic, filename);
464 if (razor_atomic_in_error_state(atomic))
467 tmpnam = atomic_action_attic_tmpnam(atomic);
468 fd = open(tmpnam, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
469 mode & (S_IRWXU | S_IRWXG | S_IRWXO));
472 atomic->error = razor_error_new_posix(filename);
474 a = atomic_action_new(ACTION_MOVE);
475 a->args.path = tmpnam;
476 a->args.u.move.dest = strdup(filename);
477 atomic->actions = atomic_action_list_prepend(atomic->actions,
484 #endif /* ENABLE_ATOMIC && !HAVE_WINDOWS_KTM */