Add -lole32 to link libraries.
This fixes a problem when compiling with mingw-headers version 3.3
where the use of SHGetFolderPath() expands to a call to CoTaskMemFree()
which is defined in libole32.dll:
/usr/x86_64-w64-mingw32/sys-root/mingw/include/shobjidl.h:29954: undefined reference to `__imp_CoTaskMemFree'
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 atomic_action_free(action);
195 return atomic_action_do(atomic, primitives);
198 static struct atomic_action *
199 atomic_action_remove(struct razor_atomic *atomic, struct atomic_action *action)
207 struct atomic_action *prim;
209 if (razor_atomic_in_error_state(atomic)) {
210 atomic_action_free(action);
215 * Non-empty directories should NOT be removed
218 path = razor_utf8_to_utf16(action->args.path, -1);
220 dir = _wopendir(path);
221 if (dir && _wreaddir(dir)) {
222 atomic_action_free(action);
227 dir = opendir(action->args.path);
228 if (dir && readdir(dir)) {
229 atomic_action_free(action);
236 prim = atomic_action_new(ACTION_MOVE);
237 prim->args.path = strdup(action->args.path);
238 prim->args.u.move.dest = atomic_action_attic_tmpnam(atomic);
240 atomic_action_free(action);
244 return prim ? atomic_action_do(atomic, prim) : NULL;
247 static struct atomic_action *
248 atomic_action_create_dir(struct razor_atomic *atomic,
249 struct atomic_action *action)
254 if (razor_atomic_in_error_state(atomic)) {
255 atomic_action_free(action);
259 mode = action->args.u.create_dir.mode & (S_IRWXU | S_IRWXG | S_IRWXO);
261 if (!mkdir(action->args.path, mode))
264 if (errno != EEXIST || stat(action->args.path, &buf)) {
266 atomic->error = razor_error_new_posix(action->args.path);
267 atomic_action_free(action);
271 if (!S_ISDIR(buf.st_mode) && !atomic->error)
272 atomic->error = razor_error_new_str(RAZOR_POSIX_ERROR, EEXIST,
276 atomic_action_free(action);
280 static struct atomic_action *atomic_action_rmdir(struct razor_atomic *atomic,
281 struct atomic_action *action)
283 if (razor_atomic_in_error_state(atomic)) {
284 atomic_action_free(action);
288 if (rmdir(action->args.path) < 0) {
290 atomic->error = razor_error_new_posix(action->args.path);
291 atomic_action_free(action);
298 static struct atomic_action *
299 atomic_action_create_symlink(struct razor_atomic *atomic,
300 struct atomic_action *action)
304 if (razor_atomic_in_error_state(atomic)) {
305 atomic_action_free(action);
309 r = symlink(action->args.u.create_symlink.target, action->args.path);
312 atomic->error = razor_error_new_posix(action->args.path);
313 atomic_action_free(action);
320 static struct atomic_action *
321 atomic_action_remove_symlink(struct razor_atomic *atomic,
322 struct atomic_action *action)
324 if (razor_atomic_in_error_state(atomic)) {
325 atomic_action_free(action);
329 if (unlink(action->args.path) < 0) {
331 atomic->error = razor_error_new_posix(action->args.path);
332 atomic_action_free(action);
341 move_file(struct razor_atomic *atomic, const char *path, const char *dest)
344 wchar_t *oldbuf, *newbuf;
345 const DWORD flags = MOVEFILE_COPY_ALLOWED | MOVEFILE_REPLACE_EXISTING;
347 newbuf = razor_utf8_to_utf16(dest, -1);
348 oldbuf = razor_utf8_to_utf16(path, -1);
351 * Passing MOVEFILE_REPLACE_EXISTING to MoveFileEx() will
352 * cover every case we care about _except_ replacing an empty
353 * directory with a file. Calling RemoveDirectory() will deal
354 * with this case while having no effect in all other cases.
356 (void)RemoveDirectoryW(newbuf);
358 if (!MoveFileExW(oldbuf, newbuf, flags)) {
360 atomic->error = razor_error_new_mswin(newbuf,
368 if (rename(path, dest)) {
370 atomic->error = razor_error_new_posix(dest);
378 static struct atomic_action *
379 atomic_action_move(struct razor_atomic *atomic, struct atomic_action *action)
381 if (razor_atomic_in_error_state(atomic)) {
382 atomic_action_free(action);
386 if (move_file(atomic, action->args.path, action->args.u.move.dest)) {
387 atomic_action_free(action);
394 static struct atomic_action *
395 atomic_action_unmove(struct razor_atomic *atomic, struct atomic_action *action)
397 if (razor_atomic_in_error_state(atomic)) {
398 atomic_action_free(action);
402 if (move_file(atomic, action->args.u.move.dest, action->args.path)) {
403 atomic_action_free(action);
410 static struct atomic_action *atomic_action_apply(struct razor_atomic *atomic,
411 struct atomic_action *action)
413 switch(action->type) {
414 case ACTION_MAKE_DIRS:
415 action = atomic_action_make_dirs(atomic, action);
418 action = atomic_action_remove(atomic, action);
420 case ACTION_CREATE_DIR:
421 action = atomic_action_create_dir(atomic, action);
424 action = atomic_action_move(atomic, action);
427 case ACTION_CREATE_SYMLINK:
428 action = atomic_action_create_symlink(atomic, action);
435 static struct atomic_action *atomic_action_reverse(struct razor_atomic *atomic,
436 struct atomic_action *action)
438 switch(action->type) {
439 case ACTION_MAKE_DIRS:
441 /* Complex actions: should never happen */
443 case ACTION_CREATE_DIR:
444 action = atomic_action_rmdir(atomic, action);
447 action = atomic_action_unmove(atomic, action);
450 case ACTION_CREATE_SYMLINK:
451 action = atomic_action_remove_symlink(atomic, action);
459 * Note that undo has no error checking.
462 void atomic_action_undo(struct razor_atomic *atomic,
463 struct atomic_action *actions)
465 struct atomic_action *a;
470 a = atomic_action_list_pop_head(&actions);
471 a = atomic_action_reverse(atomic, a);
472 atomic_action_free(a);
478 struct atomic_action *atomic_action_do(struct razor_atomic *atomic,
479 struct atomic_action *actions)
481 struct atomic_action *done = NULL, *a;
483 if (razor_atomic_in_error_state(atomic)) {
484 atomic_action_free(actions);
489 a = atomic_action_list_pop_head(&actions);
490 a = atomic_action_apply(atomic, a);
492 done = atomic_action_list_concat(a, done);
493 if (razor_atomic_in_error_state(atomic)) {
494 atomic_action_undo(atomic, done);
496 atomic_action_free(a);
503 #endif /* ENABLE_ATOMIC && !HAVE_WINDOWS_KTM */