1.1 --- a/librazor/atomic-emulate.c Tue Nov 11 15:57:14 2014 +0000
1.2 +++ b/librazor/atomic-emulate.c Mon Mar 05 20:35:27 2018 +0000
1.3 @@ -1,5 +1,5 @@
1.4 /*
1.5 - * Copyright (C) 2012, 2014 J. Ali Harlow <ali@juiblex.co.uk>
1.6 + * Copyright (C) 2012, 2014, 2016 J. Ali Harlow <ali@juiblex.co.uk>
1.7 *
1.8 * This program is free software; you can redistribute it and/or modify
1.9 * it under the terms of the GNU General Public License as published by
1.10 @@ -24,12 +24,7 @@
1.11 #include <stdio.h>
1.12 #include <string.h>
1.13 #include <unistd.h>
1.14 -#include <sys/types.h>
1.15 -#include <sys/stat.h>
1.16 #include <fcntl.h>
1.17 -#include <dirent.h>
1.18 -#include <errno.h>
1.19 -#include <unistd.h>
1.20 #include "razor-internal.h"
1.21
1.22 /*
1.23 @@ -53,24 +48,23 @@
1.24
1.25 static void recursive_remove(const char *directory)
1.26 {
1.27 - DIR *dp;
1.28 - struct dirent *dirp;
1.29 - char *buf;
1.30 + void *dp;
1.31 + char *name, *buf;
1.32
1.33 - dp = opendir(directory);
1.34 - while((dirp = readdir(dp))) {
1.35 - if (strcmp(dirp->d_name, ".") && strcmp(dirp->d_name, "..")) {
1.36 - buf = malloc(strlen(directory) + strlen(dirp->d_name)
1.37 - + 2);
1.38 - sprintf(buf, "%s/%s", directory, dirp->d_name);
1.39 - if (remove(buf) < 0)
1.40 + dp = razor_uri_opendir(directory, NULL);
1.41 +
1.42 + if (dp) {
1.43 + while((name = razor_uri_readdir(dp, NULL))) {
1.44 + buf = razor_concat(directory, "/", name, NULL);
1.45 + free(name);
1.46 + if (razor_uri_unlink(buf, NULL) < 0)
1.47 recursive_remove(buf);
1.48 free(buf);
1.49 }
1.50 +
1.51 + razor_uri_closedir(dp, NULL);
1.52 }
1.53
1.54 - closedir(dp);
1.55 -
1.56 rmdir(directory);
1.57 }
1.58
1.59 @@ -129,53 +123,6 @@
1.60 free(atomic);
1.61 }
1.62
1.63 -#ifndef MSWIN_API
1.64 -static char *absolute_path(const char *path)
1.65 -{
1.66 - int len;
1.67 - char *result, *subpath, *p, *s, *t;
1.68 -
1.69 - result = realpath(path, NULL);
1.70 -
1.71 - if (!result && errno == ENOENT) {
1.72 - p = strdup(path);
1.73 - s = strrchr(p, '/');
1.74 -
1.75 - while (s) {
1.76 - if (s == p) {
1.77 - result = strdup("/");
1.78 - break;
1.79 - }
1.80 -
1.81 - *s = '\0';
1.82 - subpath = realpath(p, NULL);
1.83 -
1.84 - if (subpath) {
1.85 - *s = '/';
1.86 - len = strlen(subpath);
1.87 - result = malloc(len + strlen(s) + 1);
1.88 - memcpy(result, subpath, len);
1.89 - strcpy(result + len, s);
1.90 - free(subpath);
1.91 - break;
1.92 - } else if (errno != ENOENT)
1.93 - break;
1.94 -
1.95 - t = strrchr(p, '/');
1.96 - *s = '/';
1.97 - s = t;
1.98 - }
1.99 -
1.100 - if (!s)
1.101 - result = realpath(".", NULL);
1.102 -
1.103 - free(p);
1.104 - }
1.105 -
1.106 - return result;
1.107 -}
1.108 -#endif
1.109 -
1.110 /*
1.111 * We need a toplevel directory in which to hold temporary files
1.112 * before they are committed. Since we can generally assume that
1.113 @@ -186,14 +133,9 @@
1.114 */
1.115
1.116 static int
1.117 -razor_atomic_set_toplevel_from_path(struct razor_atomic *atomic,
1.118 - const char *path)
1.119 +razor_atomic_set_toplevel_from_uri(struct razor_atomic *atomic,
1.120 + const char *uri)
1.121 {
1.122 -#ifndef MSWIN_API
1.123 - dev_t filesystem;
1.124 - struct stat buf;
1.125 -#endif
1.126 -
1.127 if (razor_atomic_in_error_state(atomic))
1.128 return -1;
1.129
1.130 @@ -201,231 +143,113 @@
1.131 return 0;
1.132
1.133 #ifdef MSWIN_API
1.134 - if (path[0]=='\\' && path[1]=='\\' && path[2] && path[2]!='\\'
1.135 - && strchr(path+3,'\\')) {
1.136 - /* We have a UNC path: \\servername\sharename... */
1.137 - const char *sharename, *root;
1.138 - int disklen;
1.139 -
1.140 - sharename = strchr(path+3,'\\')+1;
1.141 - root = strchr(sharename,'\\');
1.142 - if (root)
1.143 - disklen = root - path;
1.144 - else
1.145 - disklen = strlen(path);
1.146 -
1.147 - atomic->toplevel =
1.148 - malloc(disklen + strlen("\\atomic-XXXXXX") + 1);
1.149 - memcpy(atomic->toplevel, path, disklen);
1.150 - strcpy(atomic->toplevel + disklen, "\\atomic-XXXXXX");
1.151 - } else if ((*path>='A' && *path<='Z' || *path>='a' && *path<='z') &&
1.152 - path[1]==':') {
1.153 - atomic->toplevel = strdup("X:\\atomic-XXXXXX");
1.154 - *atomic->toplevel = *path;
1.155 - } else {
1.156 - DWORD n;
1.157 - wchar_t *buf;
1.158 - char *dir;
1.159 -
1.160 - n = GetCurrentDirectoryW(0, NULL);
1.161 - buf = malloc(n * sizeof(wchar_t));
1.162 -
1.163 - if (GetCurrentDirectoryW(n, buf)) {
1.164 - dir = razor_utf16_to_utf8(buf, n - 1);
1.165 - razor_atomic_set_toplevel_from_path(atomic, dir);
1.166 -
1.167 - free(dir);
1.168 - free(buf);
1.169 - return;
1.170 - } else
1.171 - atomic->toplevel = strdup("C:\\atomic-XXXXXX");
1.172 -
1.173 - free(buf);
1.174 - }
1.175 + atomic->toplevel = razor_uri_mkdtemp_near(uri, "atomic-XXXXXX",
1.176 + &atomic->error);
1.177 #else
1.178 - {
1.179 - /*
1.180 - * Find the mount point (assuming we can write to the
1.181 - * whole filesystem). Otherwise stop at the first
1.182 - * unwritable directory and take one step back.
1.183 - */
1.184 - char *s, *abspath, saved;
1.185 - int len, can_step_back = 0;
1.186 -
1.187 - abspath = absolute_path(path);
1.188 - if (!abspath) {
1.189 - atomic->error = razor_error_new_posix(path);
1.190 - return -1;
1.191 - }
1.192 -
1.193 - if (stat(abspath, &buf) < 0) {
1.194 - if (errno == ENOENT)
1.195 - filesystem = 0;
1.196 - else {
1.197 - atomic->error = razor_error_new_posix(abspath);
1.198 - free(abspath);
1.199 - return -1;
1.200 - }
1.201 - } else
1.202 - filesystem = buf.st_dev;
1.203 -
1.204 - len = strlen(abspath);
1.205 - while(len > 1 && (s = strrchr(abspath, '/'))) {
1.206 - if (s == abspath) {
1.207 - saved = s[1];
1.208 - s[1] = '\0';
1.209 - len = s + 1 - abspath;
1.210 - } else {
1.211 - s[0] = '\0';
1.212 - len = s - abspath;
1.213 - }
1.214 -
1.215 - if (stat(abspath, &buf) < 0) {
1.216 - if (errno == ENOENT)
1.217 - continue;
1.218 - else {
1.219 - atomic->error = razor_error_new_posix(abspath);
1.220 - free(abspath);
1.221 - return -1;
1.222 - }
1.223 - } else if (!filesystem)
1.224 - filesystem = buf.st_dev;
1.225 -
1.226 - if (buf.st_dev != filesystem || access(abspath, W_OK)) {
1.227 - if (can_step_back) {
1.228 - if (s == abspath)
1.229 - s[1] = saved;
1.230 - else
1.231 - s[0] = '/';
1.232 - }
1.233 - len = strlen(abspath);
1.234 - break;
1.235 - } else
1.236 - can_step_back = 1;
1.237 - }
1.238 -
1.239 - if (len == 1)
1.240 - len = 0; /* Avoid an unslightly double slash. */
1.241 - atomic->toplevel = malloc(len + strlen("/.atomic-XXXXXX") + 1);
1.242 - memcpy(atomic->toplevel, abspath, len);
1.243 - strcpy(atomic->toplevel + len, "/.atomic-XXXXXX");
1.244 -
1.245 - free(abspath);
1.246 - }
1.247 + atomic->toplevel = razor_uri_mkdtemp_near(uri, ".atomic-XXXXXX",
1.248 + &atomic->error);
1.249 #endif
1.250
1.251 - if (!mkdtemp(atomic->toplevel)) {
1.252 - int err = errno;
1.253 -
1.254 -#ifdef EACCES
1.255 - if (err == EACCES) {
1.256 - char *s = strdup("atomic-XXXXXX");
1.257 -
1.258 -#ifndef MSWIN_API
1.259 - if (stat(".", &buf) < 0) {
1.260 - atomic->error = razor_error_new_posix(".");
1.261 - free(s);
1.262 - free(atomic->toplevel);
1.263 - atomic->toplevel = NULL;
1.264 - return -1;
1.265 - }
1.266 - if (buf.st_dev != filesystem)
1.267 - /*
1.268 - * Don't use a different filesystem. It will
1.269 - * only fail later on (in rename) and cause
1.270 - * an unhelpful error message (EXDEV).
1.271 - */
1.272 - free(s);
1.273 - else
1.274 -#endif
1.275 - if (mkdtemp(s)) {
1.276 - free(atomic->toplevel);
1.277 - atomic->toplevel = s;
1.278 - return 0;
1.279 - } else
1.280 - free(s);
1.281 - }
1.282 -#endif
1.283 -
1.284 - atomic->error = razor_error_new_str(RAZOR_POSIX_ERROR, err,
1.285 - atomic->toplevel,
1.286 - strerror(err));
1.287 -
1.288 - free(atomic->toplevel);
1.289 - atomic->toplevel = NULL;
1.290 - }
1.291 -
1.292 return !atomic->toplevel;
1.293 }
1.294
1.295 +/*
1.296 + * If root_uri is empty, then uri can be a URI (but not a relative-ref; ie.,
1.297 + * a scheme must be specified). If root_uri is non-empty, then it must be a
1.298 + * URI (but not a relative-ref) and uri must be a non-empty path.
1.299 + */
1.300 RAZOR_EXPORT int
1.301 -razor_atomic_make_dirs(struct razor_atomic *atomic, const char *root,
1.302 - const char *path)
1.303 +razor_atomic_make_dirs(struct razor_atomic *atomic, const char *root_uri,
1.304 + const char *uri)
1.305 {
1.306 struct atomic_action *a;
1.307 + struct razor_uri ru;
1.308 + struct razor_error *tmp_error = NULL;
1.309 + char *fakeroot = NULL;
1.310
1.311 - razor_atomic_set_toplevel_from_path(atomic, *root ? root : path);
1.312 + razor_atomic_set_toplevel_from_uri(atomic, *root_uri ? root_uri : uri);
1.313
1.314 if (razor_atomic_in_error_state(atomic))
1.315 return -1;
1.316
1.317 + if (!*root_uri) {
1.318 + if (razor_uri_parse(&ru, uri, &tmp_error)) {
1.319 + razor_atomic_propagate_error(atomic, tmp_error, NULL);
1.320 + return -1;
1.321 + }
1.322 + if (*ru.path == '/') {
1.323 + free(ru.path);
1.324 + ru.path = strdup("/");
1.325 + } else {
1.326 + free(ru.path);
1.327 + ru.path = strdup("");
1.328 + }
1.329 + fakeroot = razor_uri_recompose(&ru);
1.330 + razor_uri_destroy(&ru);
1.331 + root_uri = fakeroot;
1.332 + uri += strlen(fakeroot);
1.333 + }
1.334 +
1.335 a = atomic_action_new(ACTION_MAKE_DIRS);
1.336 - a->args.path = strdup(path);
1.337 - a->args.u.make_dirs.root = strdup(root);
1.338 + a->args.uri = strdup(uri);
1.339 + a->args.u.make_dirs.root = strdup(root_uri);
1.340 + atomic->actions = atomic_action_list_prepend(atomic->actions, a);
1.341 +
1.342 + if (fakeroot)
1.343 + free(fakeroot);
1.344 +
1.345 + return 0;
1.346 +}
1.347 +
1.348 +RAZOR_EXPORT int
1.349 +razor_atomic_remove(struct razor_atomic *atomic, const char *uri)
1.350 +{
1.351 + struct atomic_action *a;
1.352 +
1.353 + razor_atomic_set_toplevel_from_uri(atomic, uri);
1.354 +
1.355 + if (razor_atomic_in_error_state(atomic))
1.356 + return -1;
1.357 +
1.358 + a = atomic_action_new(ACTION_REMOVE);
1.359 + a->args.uri = strdup(uri);
1.360 atomic->actions = atomic_action_list_prepend(atomic->actions, a);
1.361
1.362 return 0;
1.363 }
1.364
1.365 RAZOR_EXPORT int
1.366 -razor_atomic_remove(struct razor_atomic *atomic, const char *path)
1.367 +razor_atomic_rename_file(struct razor_atomic *atomic, const char *old_uri,
1.368 + const char *new_uri)
1.369 {
1.370 struct atomic_action *a;
1.371
1.372 - razor_atomic_set_toplevel_from_path(atomic, path);
1.373 + razor_atomic_set_toplevel_from_uri(atomic, new_uri);
1.374
1.375 if (razor_atomic_in_error_state(atomic))
1.376 return -1;
1.377
1.378 - a = atomic_action_new(ACTION_REMOVE);
1.379 - a->args.path = strdup(path);
1.380 + a = atomic_action_new(ACTION_MOVE);
1.381 + a->args.uri = strdup(old_uri);
1.382 + a->args.u.move.dest = strdup(new_uri);
1.383 atomic->actions = atomic_action_list_prepend(atomic->actions, a);
1.384
1.385 return 0;
1.386 }
1.387
1.388 RAZOR_EXPORT int
1.389 -razor_atomic_rename_file(struct razor_atomic *atomic, const char *oldpath,
1.390 - const char *newpath)
1.391 -{
1.392 - struct atomic_action *a;
1.393 -
1.394 - razor_atomic_set_toplevel_from_path(atomic, newpath);
1.395 -
1.396 - if (razor_atomic_in_error_state(atomic))
1.397 - return -1;
1.398 -
1.399 - a = atomic_action_new(ACTION_MOVE);
1.400 - a->args.path = strdup(oldpath);
1.401 - a->args.u.move.dest = strdup(newpath);
1.402 - atomic->actions = atomic_action_list_prepend(atomic->actions, a);
1.403 -
1.404 - return 0;
1.405 -}
1.406 -
1.407 -RAZOR_EXPORT int
1.408 -razor_atomic_create_dir(struct razor_atomic *atomic, const char *dirname,
1.409 +razor_atomic_create_dir(struct razor_atomic *atomic, const char *uri,
1.410 mode_t mode)
1.411 {
1.412 struct atomic_action *a;
1.413
1.414 - razor_atomic_set_toplevel_from_path(atomic, dirname);
1.415 + razor_atomic_set_toplevel_from_uri(atomic, uri);
1.416
1.417 if (razor_atomic_in_error_state(atomic))
1.418 return -1;
1.419
1.420 a = atomic_action_new(ACTION_CREATE_DIR);
1.421 - a->args.path = strdup(dirname);
1.422 + a->args.uri = strdup(uri);
1.423 a->args.u.create_dir.mode = mode;
1.424 atomic->actions = atomic_action_list_prepend(atomic->actions, a);
1.425
1.426 @@ -434,12 +258,12 @@
1.427
1.428 RAZOR_EXPORT int
1.429 razor_atomic_create_symlink(struct razor_atomic *atomic, const char *target,
1.430 - const char *path)
1.431 + const char *uri)
1.432 {
1.433 #if HAVE_SYMLINK
1.434 struct atomic_action *a;
1.435
1.436 - razor_atomic_set_toplevel_from_path(atomic, path);
1.437 + razor_atomic_set_toplevel_from_uri(atomic, uri);
1.438 #endif
1.439
1.440 if (razor_atomic_in_error_state(atomic))
1.441 @@ -447,7 +271,7 @@
1.442
1.443 #if HAVE_SYMLINK
1.444 a = atomic_action_new(ACTION_CREATE_SYMLINK);
1.445 - a->args.path = strdup(path);
1.446 + a->args.uri = strdup(uri);
1.447 a->args.u.create_symlink.target = strdup(target);
1.448 atomic->actions = atomic_action_list_prepend(atomic->actions, a);
1.449
1.450 @@ -462,28 +286,27 @@
1.451 }
1.452
1.453 RAZOR_EXPORT int
1.454 -razor_atomic_create_file(struct razor_atomic *atomic, const char *filename,
1.455 +razor_atomic_create_file(struct razor_atomic *atomic, const char *uri,
1.456 mode_t mode)
1.457 {
1.458 int fd;
1.459 struct atomic_action *a;
1.460 char *tmpnam;
1.461
1.462 - razor_atomic_set_toplevel_from_path(atomic, filename);
1.463 + razor_atomic_set_toplevel_from_uri(atomic, uri);
1.464
1.465 if (razor_atomic_in_error_state(atomic))
1.466 return -1;
1.467
1.468 tmpnam = atomic_action_attic_tmpnam(atomic);
1.469 - fd = open(tmpnam, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
1.470 - mode & (S_IRWXU | S_IRWXG | S_IRWXO));
1.471 + fd = razor_uri_open(tmpnam, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
1.472 + mode & (S_IRWXU | S_IRWXG | S_IRWXO),
1.473 + &atomic->error);
1.474
1.475 - if (fd == -1)
1.476 - atomic->error = razor_error_new_posix(filename);
1.477 - else {
1.478 + if (fd >= 0) {
1.479 a = atomic_action_new(ACTION_MOVE);
1.480 - a->args.path = tmpnam;
1.481 - a->args.u.move.dest = strdup(filename);
1.482 + a->args.uri = tmpnam;
1.483 + a->args.u.move.dest = strdup(uri);
1.484 atomic->actions = atomic_action_list_prepend(atomic->actions,
1.485 a);
1.486 }