Add facility to specify razor command when running tests.
This makes it easy to run under eg., valgrind as:
./details "libtool --mode=execute valgrind --leak-check=yes ../src/razor"
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 */