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 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
29 #include <sys/types.h>
32 #include "razor-internal.h"
34 char *atomic_action_attic_tmpnam(struct razor_atomic *atomic)
37 sprintf(filename,"%03X",atomic->next_file_tag++);
38 return razor_concat(atomic->toplevel, "/", filename, NULL);
41 static struct atomic_action *
42 atomic_action_list_pop_head(struct atomic_action **list)
44 struct atomic_action *head;
55 struct atomic_action *
56 atomic_action_list_prepend(struct atomic_action *list,
57 struct atomic_action *action)
59 assert(action->next == NULL);
66 static struct atomic_action *
67 atomic_action_list_concat(struct atomic_action *list1,
68 struct atomic_action *list2)
70 struct atomic_action *action;
75 for(action=list1;action->next;action=action->next)
83 void atomic_action_free(struct atomic_action *action)
85 struct atomic_action *a;
88 a = atomic_action_list_pop_head(&action);
93 case ACTION_MAKE_DIRS:
94 free(a->args.u.make_dirs.root);
97 free(a->args.u.move.dest);
100 case ACTION_CREATE_SYMLINK:
101 free(a->args.u.create_symlink.target);
105 case ACTION_CREATE_DIR:
113 struct atomic_action *atomic_action_new(enum atomic_action_type type)
115 struct atomic_action *action;
117 action = zalloc(sizeof *action);
123 struct atomic_action *atomic_action_list_reverse(struct atomic_action *list)
125 struct atomic_action *prev = NULL, *next;
138 * All action_ functions take 1 action and return a list of primitive
139 * actions they took (such that the first action in the list is the
140 * last action they took). Primitive actions are always reversable.
142 * On failure, an error should be set on the atomic object (if it is
143 * not already set), the action freed and NULL returned.
145 * Whether they succeed or fail, they take ownership of the passed
146 * action and should thus either free it or return it back to their
147 * caller as appropriate.
149 * A NULL return means that nothing was done which may, or may not,
153 static struct atomic_action *
154 atomic_action_make_dirs(struct razor_atomic *atomic,
155 struct atomic_action *action)
157 char buffer[PATH_MAX], *p;
158 const char *slash, *next;
159 struct atomic_action *primitives = NULL;
160 struct atomic_action *prim;
162 if (razor_atomic_in_error_state(atomic)) {
163 atomic_action_free(action);
167 strcpy(buffer, action->args.u.make_dirs.root);
168 p = buffer + strlen(buffer);
169 slash = action->args.path;
170 for (; *slash != '\0'; slash = next) {
172 next = strpbrk(slash + 1, "/\\");
174 next = strchr(slash + 1, '/');
179 memcpy(p, slash, next - slash);
183 if (razor_valid_root_name(buffer))
186 prim = atomic_action_new(ACTION_CREATE_DIR);
187 prim->args.path = strdup(buffer);
188 prim->args.u.create_dir.mode = S_IRWXU | S_IRWXG | S_IRWXO;
189 primitives = atomic_action_list_prepend(primitives, prim);
191 primitives = atomic_action_list_reverse(primitives);
193 return atomic_action_do(atomic, primitives);
196 static struct atomic_action *
197 atomic_action_remove(struct razor_atomic *atomic, struct atomic_action *action)
205 struct atomic_action *prim;
207 if (razor_atomic_in_error_state(atomic)) {
208 atomic_action_free(action);
213 * Non-empty directories should NOT be removed
216 path = razor_utf8_to_utf16(action->args.path, -1);
218 dir = _wopendir(path);
219 if (dir && _wreaddir(dir)) {
220 atomic_action_free(action);
225 dir = opendir(action->args.path);
226 if (dir && readdir(dir)) {
227 atomic_action_free(action);
234 prim = atomic_action_new(ACTION_MOVE);
235 prim->args.path = strdup(action->args.path);
236 prim->args.u.move.dest = atomic_action_attic_tmpnam(atomic);
238 atomic_action_free(action);
242 return prim ? atomic_action_do(atomic, prim) : NULL;
245 static struct atomic_action *
246 atomic_action_create_dir(struct razor_atomic *atomic,
247 struct atomic_action *action)
252 if (razor_atomic_in_error_state(atomic)) {
253 atomic_action_free(action);
257 mode = action->args.u.create_dir.mode & (S_IRWXU | S_IRWXG | S_IRWXO);
259 if (!mkdir(action->args.path, mode))
262 if (errno != EEXIST || stat(action->args.path, &buf)) {
264 atomic->error = razor_error_new_posix(action->args.path);
265 atomic_action_free(action);
269 if (!S_ISDIR(buf.st_mode) && !atomic->error)
270 atomic->error = razor_error_new_str(RAZOR_POSIX_ERROR, EEXIST,
274 atomic_action_free(action);
278 static struct atomic_action *atomic_action_rmdir(struct razor_atomic *atomic,
279 struct atomic_action *action)
281 if (razor_atomic_in_error_state(atomic)) {
282 atomic_action_free(action);
286 if (rmdir(action->args.path) < 0) {
288 atomic->error = razor_error_new_posix(action->args.path);
289 atomic_action_free(action);
296 static struct atomic_action *
297 atomic_action_create_symlink(struct razor_atomic *atomic,
298 struct atomic_action *action)
302 if (razor_atomic_in_error_state(atomic)) {
303 atomic_action_free(action);
307 r = symlink(action->args.u.create_symlink.target, action->args.path);
310 atomic->error = razor_error_new_posix(action->args.path);
311 atomic_action_free(action);
318 static struct atomic_action *
319 atomic_action_remove_symlink(struct razor_atomic *atomic,
320 struct atomic_action *action)
322 if (razor_atomic_in_error_state(atomic)) {
323 atomic_action_free(action);
327 if (unlink(action->args.path) < 0) {
329 atomic->error = razor_error_new_posix(action->args.path);
330 atomic_action_free(action);
339 move_file(struct razor_atomic *atomic, const char *path, const char *dest)
342 wchar_t *oldbuf, *newbuf;
343 const DWORD flags = MOVEFILE_COPY_ALLOWED | MOVEFILE_REPLACE_EXISTING;
345 newbuf = razor_utf8_to_utf16(dest, -1);
346 oldbuf = razor_utf8_to_utf16(path, -1);
349 * Passing MOVEFILE_REPLACE_EXISTING to MoveFileEx() will
350 * cover every case we care about _except_ replacing an empty
351 * directory with a file. Calling RemoveDirectory() will deal
352 * with this case while having no effect in all other cases.
354 (void)RemoveDirectoryW(newbuf);
356 if (!MoveFileExW(oldbuf, newbuf, flags)) {
358 atomic->error = razor_error_new_mswin(newbuf,
366 if (rename(path, dest)) {
368 atomic->error = razor_error_new_posix(dest);
376 static struct atomic_action *
377 atomic_action_move(struct razor_atomic *atomic, struct atomic_action *action)
379 if (razor_atomic_in_error_state(atomic)) {
380 atomic_action_free(action);
384 if (move_file(atomic, action->args.path, action->args.u.move.dest)) {
385 atomic_action_free(action);
392 static struct atomic_action *
393 atomic_action_unmove(struct razor_atomic *atomic, struct atomic_action *action)
395 if (razor_atomic_in_error_state(atomic)) {
396 atomic_action_free(action);
400 if (move_file(atomic, action->args.u.move.dest, action->args.path)) {
401 atomic_action_free(action);
408 static struct atomic_action *atomic_action_apply(struct razor_atomic *atomic,
409 struct atomic_action *action)
411 switch(action->type) {
412 case ACTION_MAKE_DIRS:
413 action = atomic_action_make_dirs(atomic, action);
416 action = atomic_action_remove(atomic, action);
418 case ACTION_CREATE_DIR:
419 action = atomic_action_create_dir(atomic, action);
422 action = atomic_action_move(atomic, action);
425 case ACTION_CREATE_SYMLINK:
426 action = atomic_action_create_symlink(atomic, action);
433 static struct atomic_action *atomic_action_reverse(struct razor_atomic *atomic,
434 struct atomic_action *action)
436 switch(action->type) {
437 case ACTION_MAKE_DIRS:
439 /* Complex actions: should never happen */
441 case ACTION_CREATE_DIR:
442 action = atomic_action_rmdir(atomic, action);
445 action = atomic_action_unmove(atomic, action);
448 case ACTION_CREATE_SYMLINK:
449 action = atomic_action_remove_symlink(atomic, action);
457 * Note that undo has no error checking.
460 void atomic_action_undo(struct razor_atomic *atomic,
461 struct atomic_action *actions)
463 struct atomic_action *a;
468 a = atomic_action_list_pop_head(&actions);
469 a = atomic_action_reverse(atomic, a);
470 atomic_action_free(a);
476 struct atomic_action *atomic_action_do(struct razor_atomic *atomic,
477 struct atomic_action *actions)
479 struct atomic_action *done = NULL, *a;
481 if (razor_atomic_in_error_state(atomic)) {
482 atomic_action_free(actions);
487 a = atomic_action_list_pop_head(&actions);
488 a = atomic_action_apply(atomic, a);
490 done = atomic_action_list_concat(a, done);
491 if (razor_atomic_in_error_state(atomic)) {
492 atomic_action_undo(atomic, done);
494 atomic_action_free(a);
501 #endif /* ENABLE_ATOMIC && !HAVE_WINDOWS_KTM */