diff -r e1b95d57dd54 -r c89e5edb8eae librazor/atomic-emulate.c --- a/librazor/atomic-emulate.c Tue Nov 11 15:57:14 2014 +0000 +++ b/librazor/atomic-emulate.c Thu Jun 07 18:36:20 2018 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012, 2014 J. Ali Harlow + * Copyright (C) 2012, 2014, 2016 J. Ali Harlow * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -24,12 +24,7 @@ #include #include #include -#include -#include #include -#include -#include -#include #include "razor-internal.h" /* @@ -53,24 +48,23 @@ static void recursive_remove(const char *directory) { - DIR *dp; - struct dirent *dirp; - char *buf; + void *dp; + char *name, *buf; - dp = opendir(directory); - while((dirp = readdir(dp))) { - if (strcmp(dirp->d_name, ".") && strcmp(dirp->d_name, "..")) { - buf = malloc(strlen(directory) + strlen(dirp->d_name) - + 2); - sprintf(buf, "%s/%s", directory, dirp->d_name); - if (remove(buf) < 0) + dp = razor_uri_opendir(directory, NULL); + + if (dp) { + while((name = razor_uri_readdir(dp, NULL))) { + buf = razor_concat(directory, "/", name, NULL); + free(name); + if (razor_uri_unlink(buf, NULL) < 0) recursive_remove(buf); free(buf); } + + razor_uri_closedir(dp, NULL); } - closedir(dp); - rmdir(directory); } @@ -129,53 +123,6 @@ free(atomic); } -#ifndef MSWIN_API -static char *absolute_path(const char *path) -{ - int len; - char *result, *subpath, *p, *s, *t; - - result = realpath(path, NULL); - - if (!result && errno == ENOENT) { - p = strdup(path); - s = strrchr(p, '/'); - - while (s) { - if (s == p) { - result = strdup("/"); - break; - } - - *s = '\0'; - subpath = realpath(p, NULL); - - if (subpath) { - *s = '/'; - len = strlen(subpath); - result = malloc(len + strlen(s) + 1); - memcpy(result, subpath, len); - strcpy(result + len, s); - free(subpath); - break; - } else if (errno != ENOENT) - break; - - t = strrchr(p, '/'); - *s = '/'; - s = t; - } - - if (!s) - result = realpath(".", NULL); - - free(p); - } - - return result; -} -#endif - /* * We need a toplevel directory in which to hold temporary files * before they are committed. Since we can generally assume that @@ -186,14 +133,9 @@ */ static int -razor_atomic_set_toplevel_from_path(struct razor_atomic *atomic, - const char *path) +razor_atomic_set_toplevel_from_uri(struct razor_atomic *atomic, + const char *uri) { -#ifndef MSWIN_API - dev_t filesystem; - struct stat buf; -#endif - if (razor_atomic_in_error_state(atomic)) return -1; @@ -201,231 +143,113 @@ return 0; #ifdef MSWIN_API - if (path[0]=='\\' && path[1]=='\\' && path[2] && path[2]!='\\' - && strchr(path+3,'\\')) { - /* We have a UNC path: \\servername\sharename... */ - const char *sharename, *root; - int disklen; - - sharename = strchr(path+3,'\\')+1; - root = strchr(sharename,'\\'); - if (root) - disklen = root - path; - else - disklen = strlen(path); - - atomic->toplevel = - malloc(disklen + strlen("\\atomic-XXXXXX") + 1); - memcpy(atomic->toplevel, path, disklen); - strcpy(atomic->toplevel + disklen, "\\atomic-XXXXXX"); - } else if ((*path>='A' && *path<='Z' || *path>='a' && *path<='z') && - path[1]==':') { - atomic->toplevel = strdup("X:\\atomic-XXXXXX"); - *atomic->toplevel = *path; - } else { - DWORD n; - wchar_t *buf; - char *dir; - - n = GetCurrentDirectoryW(0, NULL); - buf = malloc(n * sizeof(wchar_t)); - - if (GetCurrentDirectoryW(n, buf)) { - dir = razor_utf16_to_utf8(buf, n - 1); - razor_atomic_set_toplevel_from_path(atomic, dir); - - free(dir); - free(buf); - return; - } else - atomic->toplevel = strdup("C:\\atomic-XXXXXX"); - - free(buf); - } + atomic->toplevel = razor_uri_mkdtemp_near(uri, "atomic-XXXXXX", + &atomic->error); #else - { - /* - * Find the mount point (assuming we can write to the - * whole filesystem). Otherwise stop at the first - * unwritable directory and take one step back. - */ - char *s, *abspath, saved; - int len, can_step_back = 0; - - abspath = absolute_path(path); - if (!abspath) { - atomic->error = razor_error_new_posix(path); - return -1; - } - - if (stat(abspath, &buf) < 0) { - if (errno == ENOENT) - filesystem = 0; - else { - atomic->error = razor_error_new_posix(abspath); - free(abspath); - return -1; - } - } else - filesystem = buf.st_dev; - - len = strlen(abspath); - while(len > 1 && (s = strrchr(abspath, '/'))) { - if (s == abspath) { - saved = s[1]; - s[1] = '\0'; - len = s + 1 - abspath; - } else { - s[0] = '\0'; - len = s - abspath; - } - - if (stat(abspath, &buf) < 0) { - if (errno == ENOENT) - continue; - else { - atomic->error = razor_error_new_posix(abspath); - free(abspath); - return -1; - } - } else if (!filesystem) - filesystem = buf.st_dev; - - if (buf.st_dev != filesystem || access(abspath, W_OK)) { - if (can_step_back) { - if (s == abspath) - s[1] = saved; - else - s[0] = '/'; - } - len = strlen(abspath); - break; - } else - can_step_back = 1; - } - - if (len == 1) - len = 0; /* Avoid an unslightly double slash. */ - atomic->toplevel = malloc(len + strlen("/.atomic-XXXXXX") + 1); - memcpy(atomic->toplevel, abspath, len); - strcpy(atomic->toplevel + len, "/.atomic-XXXXXX"); - - free(abspath); - } + atomic->toplevel = razor_uri_mkdtemp_near(uri, ".atomic-XXXXXX", + &atomic->error); #endif - if (!mkdtemp(atomic->toplevel)) { - int err = errno; - -#ifdef EACCES - if (err == EACCES) { - char *s = strdup("atomic-XXXXXX"); - -#ifndef MSWIN_API - if (stat(".", &buf) < 0) { - atomic->error = razor_error_new_posix("."); - free(s); - free(atomic->toplevel); - atomic->toplevel = NULL; - return -1; - } - if (buf.st_dev != filesystem) - /* - * Don't use a different filesystem. It will - * only fail later on (in rename) and cause - * an unhelpful error message (EXDEV). - */ - free(s); - else -#endif - if (mkdtemp(s)) { - free(atomic->toplevel); - atomic->toplevel = s; - return 0; - } else - free(s); - } -#endif - - atomic->error = razor_error_new_str(RAZOR_POSIX_ERROR, err, - atomic->toplevel, - strerror(err)); - - free(atomic->toplevel); - atomic->toplevel = NULL; - } - return !atomic->toplevel; } +/* + * If root_uri is empty, then uri can be a URI (but not a relative-ref; ie., + * a scheme must be specified). If root_uri is non-empty, then it must be a + * URI (but not a relative-ref) and uri must be a non-empty path. + */ RAZOR_EXPORT int -razor_atomic_make_dirs(struct razor_atomic *atomic, const char *root, - const char *path) +razor_atomic_make_dirs(struct razor_atomic *atomic, const char *root_uri, + const char *uri) { struct atomic_action *a; + struct razor_uri ru; + struct razor_error *tmp_error = NULL; + char *fakeroot = NULL; - razor_atomic_set_toplevel_from_path(atomic, *root ? root : path); + razor_atomic_set_toplevel_from_uri(atomic, *root_uri ? root_uri : uri); if (razor_atomic_in_error_state(atomic)) return -1; + if (!*root_uri) { + if (razor_uri_parse(&ru, uri, &tmp_error)) { + razor_atomic_propagate_error(atomic, tmp_error, NULL); + return -1; + } + if (*ru.path == '/') { + free(ru.path); + ru.path = strdup("/"); + } else { + free(ru.path); + ru.path = strdup(""); + } + fakeroot = razor_uri_recompose(&ru); + razor_uri_destroy(&ru); + root_uri = fakeroot; + uri += strlen(fakeroot); + } + a = atomic_action_new(ACTION_MAKE_DIRS); - a->args.path = strdup(path); - a->args.u.make_dirs.root = strdup(root); + a->args.uri = strdup(uri); + a->args.u.make_dirs.root = strdup(root_uri); + atomic->actions = atomic_action_list_prepend(atomic->actions, a); + + if (fakeroot) + free(fakeroot); + + return 0; +} + +RAZOR_EXPORT int +razor_atomic_remove(struct razor_atomic *atomic, const char *uri) +{ + struct atomic_action *a; + + razor_atomic_set_toplevel_from_uri(atomic, uri); + + if (razor_atomic_in_error_state(atomic)) + return -1; + + a = atomic_action_new(ACTION_REMOVE); + a->args.uri = strdup(uri); atomic->actions = atomic_action_list_prepend(atomic->actions, a); return 0; } RAZOR_EXPORT int -razor_atomic_remove(struct razor_atomic *atomic, const char *path) +razor_atomic_rename_file(struct razor_atomic *atomic, const char *old_uri, + const char *new_uri) { struct atomic_action *a; - razor_atomic_set_toplevel_from_path(atomic, path); + razor_atomic_set_toplevel_from_uri(atomic, new_uri); if (razor_atomic_in_error_state(atomic)) return -1; - a = atomic_action_new(ACTION_REMOVE); - a->args.path = strdup(path); + a = atomic_action_new(ACTION_MOVE); + a->args.uri = strdup(old_uri); + a->args.u.move.dest = strdup(new_uri); atomic->actions = atomic_action_list_prepend(atomic->actions, a); return 0; } RAZOR_EXPORT int -razor_atomic_rename_file(struct razor_atomic *atomic, const char *oldpath, - const char *newpath) -{ - struct atomic_action *a; - - razor_atomic_set_toplevel_from_path(atomic, newpath); - - if (razor_atomic_in_error_state(atomic)) - return -1; - - a = atomic_action_new(ACTION_MOVE); - a->args.path = strdup(oldpath); - a->args.u.move.dest = strdup(newpath); - atomic->actions = atomic_action_list_prepend(atomic->actions, a); - - return 0; -} - -RAZOR_EXPORT int -razor_atomic_create_dir(struct razor_atomic *atomic, const char *dirname, +razor_atomic_create_dir(struct razor_atomic *atomic, const char *uri, mode_t mode) { struct atomic_action *a; - razor_atomic_set_toplevel_from_path(atomic, dirname); + razor_atomic_set_toplevel_from_uri(atomic, uri); if (razor_atomic_in_error_state(atomic)) return -1; a = atomic_action_new(ACTION_CREATE_DIR); - a->args.path = strdup(dirname); + a->args.uri = strdup(uri); a->args.u.create_dir.mode = mode; atomic->actions = atomic_action_list_prepend(atomic->actions, a); @@ -434,12 +258,12 @@ RAZOR_EXPORT int razor_atomic_create_symlink(struct razor_atomic *atomic, const char *target, - const char *path) + const char *uri) { #if HAVE_SYMLINK struct atomic_action *a; - razor_atomic_set_toplevel_from_path(atomic, path); + razor_atomic_set_toplevel_from_uri(atomic, uri); #endif if (razor_atomic_in_error_state(atomic)) @@ -447,7 +271,7 @@ #if HAVE_SYMLINK a = atomic_action_new(ACTION_CREATE_SYMLINK); - a->args.path = strdup(path); + a->args.uri = strdup(uri); a->args.u.create_symlink.target = strdup(target); atomic->actions = atomic_action_list_prepend(atomic->actions, a); @@ -462,28 +286,27 @@ } RAZOR_EXPORT int -razor_atomic_create_file(struct razor_atomic *atomic, const char *filename, +razor_atomic_create_file(struct razor_atomic *atomic, const char *uri, mode_t mode) { int fd; struct atomic_action *a; char *tmpnam; - razor_atomic_set_toplevel_from_path(atomic, filename); + razor_atomic_set_toplevel_from_uri(atomic, uri); if (razor_atomic_in_error_state(atomic)) return -1; tmpnam = atomic_action_attic_tmpnam(atomic); - fd = open(tmpnam, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, - mode & (S_IRWXU | S_IRWXG | S_IRWXO)); + fd = razor_uri_open(tmpnam, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, + mode & (S_IRWXU | S_IRWXG | S_IRWXO), + &atomic->error); - if (fd == -1) - atomic->error = razor_error_new_posix(filename); - else { + if (fd >= 0) { a = atomic_action_new(ACTION_MOVE); - a->args.path = tmpnam; - a->args.u.move.dest = strdup(filename); + a->args.uri = tmpnam; + a->args.u.move.dest = strdup(uri); atomic->actions = atomic_action_list_prepend(atomic->actions, a); }