atomic = zalloc(sizeof *atomic);
- atomic->toplevel = strdup(".atomic-XXXXXX");
- if (!mkdtemp(atomic->toplevel)) {
- free(atomic->toplevel);
- free(atomic);
- return NULL;
- }
-
atomic->description = strdup(description);
return atomic;
free(atomic);
}
+/*
+ * We need a toplevel directory in which to hold temporary files
+ * before they are committed. Since we can generally assume that
+ * we have write permissions anywhere on the disk in question,
+ * the best location is in the relevant root directory. The most
+ * common case where this assumption fails is when testing, when
+ * the current directory is a good choice.
+ * It might be even better to find a mount point above path instead
+ * but this is hard to do, and probably not worth the effort.
+ */
+
+static int
+razor_atomic_set_toplevel_from_path(struct razor_atomic *atomic,
+ const char *path)
+{
+ if (razor_atomic_in_error_state(atomic))
+ return -1;
+
+ if (atomic->toplevel)
+ 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);
+ }
+#else
+ atomic->toplevel = strdup("/.atomic-XXXXXX");
+#endif
+
+ if (!mkdtemp(atomic->toplevel)) {
+ int err = errno;
+
+#ifdef EACCES
+ if (err == EACCES) {
+ char *s = strdup("atomic-XXXXXX");
+
+ if (mkdtemp(s)) {
+ free(atomic->toplevel);
+ atomic->toplevel = s;
+ return 0;
+ } else
+ free(s);
+ }
+#endif
+
+ atomic->error = razor_error_new_str(atomic->toplevel,
+ strerror(err));
+
+ free(atomic->toplevel);
+ atomic->toplevel = NULL;
+ }
+
+ return !atomic->toplevel;
+}
+
RAZOR_EXPORT int
razor_atomic_make_dirs(struct razor_atomic *atomic, const char *root,
const char *path)
{
struct atomic_action *a;
+ razor_atomic_set_toplevel_from_path(atomic, *root ? root : path);
+
if (razor_atomic_in_error_state(atomic))
return -1;
{
struct atomic_action *a;
+ razor_atomic_set_toplevel_from_path(atomic, path);
+
if (razor_atomic_in_error_state(atomic))
return -1;
{
struct atomic_action *a;
+ razor_atomic_set_toplevel_from_path(atomic, newpath);
+
if (razor_atomic_in_error_state(atomic))
return -1;
{
struct atomic_action *a;
+ razor_atomic_set_toplevel_from_path(atomic, dirname);
+
if (razor_atomic_in_error_state(atomic))
return -1;
{
#if HAVE_SYMLINK
struct atomic_action *a;
+
+ razor_atomic_set_toplevel_from_path(atomic, path);
#endif
if (razor_atomic_in_error_state(atomic))
struct atomic_action *a;
char *tmpnam;
+ razor_atomic_set_toplevel_from_path(atomic, filename);
+
if (razor_atomic_in_error_state(atomic))
return -1;