diff -r 6112bcc5d1cf -r b9cc58992572 librazor/atomic-emulate.c --- a/librazor/atomic-emulate.c Sat Feb 11 23:50:26 2012 +0000 +++ b/librazor/atomic-emulate.c Wed Aug 20 18:56:17 2014 +0100 @@ -77,13 +77,6 @@ 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; @@ -126,12 +119,107 @@ 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; @@ -148,6 +236,8 @@ { struct atomic_action *a; + razor_atomic_set_toplevel_from_path(atomic, path); + if (razor_atomic_in_error_state(atomic)) return -1; @@ -164,6 +254,8 @@ { struct atomic_action *a; + razor_atomic_set_toplevel_from_path(atomic, newpath); + if (razor_atomic_in_error_state(atomic)) return -1; @@ -181,6 +273,8 @@ { struct atomic_action *a; + razor_atomic_set_toplevel_from_path(atomic, dirname); + if (razor_atomic_in_error_state(atomic)) return -1; @@ -198,6 +292,8 @@ { #if HAVE_SYMLINK struct atomic_action *a; + + razor_atomic_set_toplevel_from_path(atomic, path); #endif if (razor_atomic_in_error_state(atomic)) @@ -227,6 +323,8 @@ struct atomic_action *a; char *tmpnam; + razor_atomic_set_toplevel_from_path(atomic, filename); + if (razor_atomic_in_error_state(atomic)) return -1;