diff -r e63951c1d0f8 -r d0aa9e0a6d04 librazor/atomic.c --- a/librazor/atomic.c Thu Nov 10 10:35:21 2011 +0000 +++ b/librazor/atomic.c Thu Feb 09 20:42:08 2012 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011 J. Ali Harlow + * Copyright (C) 2011-2012 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 @@ -19,21 +19,15 @@ #include "config.h" #include -#ifdef MSWIN_API -#include -#endif #include #include #include #include +#include +#include #include -#include #include #include -#if HAVE_WINDOWS_KTM -#include -#include -#endif #include "razor.h" #include "razor-internal.h" @@ -42,13 +36,6 @@ * Atomic transactions */ -#ifndef O_BINARY -#define O_BINARY 0 -#endif - -#define RAZOR_ASCII_ISALPHA(c) \ - ((c) >= 'A' && (c) <= 'Z' || (c) >= 'a' && (c) <= 'z') - static int allow_all_root_names = 0; /* @@ -60,918 +47,12 @@ allow_all_root_names = disable; } -#ifdef MSWIN_API - -static char * -razor_utf16_to_utf8(const wchar_t *utf16, int len) +int +razor_allow_all_root_names(void) { - int n; - char *utf8; - - n = WideCharToMultiByte(CP_UTF8, 0, utf16, len, NULL, 0, NULL, NULL); - if (len >= 0 && utf16[len]) - n++; - utf8 = malloc(n); - (void)WideCharToMultiByte(CP_UTF8, 0, utf16, len, utf8, n, NULL, NULL); - if (len >= 0 && utf16[len]) - utf8[n - 1] = 0; - - return utf8; + return allow_all_root_names; } -static wchar_t * -razor_utf8_to_utf16(const char *utf8, int len) -{ - int n; - wchar_t *utf16; - - n = MultiByteToWideChar(CP_UTF8, 0, utf8, len, NULL, 0); - if (len >= 0 && utf8[len]) - n++; - utf16 = malloc(n * sizeof(wchar_t)); - (void)MultiByteToWideChar(CP_UTF8, 0, utf8, len, utf16, n); - if (len >= 0 && utf8[len]) - utf16[n - 1] = 0; - - return utf16; -} - -#endif /* MSWIN_API */ - -#if HAVE_WINDOWS_KTM - -static int -razor_valid_root_name(const wchar_t *name) -{ - if (allow_all_root_names) - return !wcschr(name, '/'); - - return RAZOR_ASCII_ISALPHA(name[0]) && name[1] == ':' && - name[2] == '\0'; -} - -struct razor_atomic { - HANDLE transaction; - int n_files; - struct razor_atomic_file { - wchar_t *path; - HANDLE h; - } *files; - char *error_path; - char *error_str; - char *error_msg; -}; - -struct razor_wstr { - wchar_t *str; - int len, allocated; -}; - -static struct razor_wstr * -razor_wstr_create(const char *init, int len) -{ - int n; - struct razor_wstr *wstr; - - wstr = malloc(sizeof(struct razor_wstr)); - - n = MultiByteToWideChar(CP_UTF8, 0, init, len, NULL, 0); - if (len >= 0 && init[len]) - wstr->len = n++; - else - wstr->len = n - 1; - - wstr->allocated = n * 2; - wstr->str = malloc(wstr->allocated * sizeof(wchar_t)); - if (!wstr->str) { - free(wstr); - return NULL; - } - - (void)MultiByteToWideChar(CP_UTF8, 0, init, len, wstr->str, n); - if (len >= 0 && init[len]) - wstr->str[wstr->len] = 0; - - return wstr; -} - -static int -razor_wstr_append(struct razor_wstr *wstr, const char *s, int len) -{ - int n, allocated; - wchar_t *str; - - n = MultiByteToWideChar(CP_UTF8, 0, s, len, NULL, 0); - if (len < 0 || !s[len]) - n--; - - if (wstr->allocated <= wstr->len + n) { - allocated = (wstr->len + n + 1) * 2; - str = realloc(wstr->str, allocated * sizeof(wchar_t)); - if (!str) - return -1; - wstr->allocated = allocated; - wstr->str = str; - } - - (void)MultiByteToWideChar(CP_UTF8, 0, s, len, wstr->str + wstr->len, n); - wstr->len += n; - wstr->str[wstr->len] = 0; - - return 0; -} - -static void -razor_wstr_destroy(struct razor_wstr *wstr) -{ - free(wstr->str); - free(wstr); -} - -RAZOR_EXPORT struct razor_atomic * -razor_atomic_open(const char *description) -{ - wchar_t *buf; - struct razor_atomic *atomic; - - atomic = zalloc(sizeof *atomic); - buf = razor_utf8_to_utf16(description, -1); - atomic->transaction = CreateTransaction(NULL, 0, - TRANSACTION_DO_NOT_PROMOTE, - 0, 0, 0, buf); - free(buf); - - return atomic; -} - -static void -razor_atomic_set_error_str(struct razor_atomic *atomic, const wchar_t *path, - const char *str) -{ - assert(!atomic->error_str); - - free(atomic->error_path); - - if (path) - atomic->error_path = razor_utf16_to_utf8(path, -1); - else - atomic->error_path = NULL; - - atomic->error_str = strdup(str); -} - -static void -razor_atomic_set_error(struct razor_atomic *atomic, const wchar_t *path, - DWORD error) -{ - wchar_t *buf; - - assert(!atomic->error_str); - - free(atomic->error_path); - - if (path) - atomic->error_path = razor_utf16_to_utf8(path, -1); - else - atomic->error_path = NULL; - - FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER| - FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS, - NULL, error, MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT), - (LPWSTR)&buf, 0, NULL); - atomic->error_str = razor_utf16_to_utf8(buf, -1); - LocalFree(buf); -} - -RAZOR_EXPORT int -razor_atomic_commit(struct razor_atomic *atomic) -{ - int retval; - - if (atomic->error_str) - return -1; - - retval = !CommitTransaction(atomic->transaction); - - if (retval) { - razor_atomic_set_error(atomic, NULL, GetLastError()); - RollbackTransaction(atomic->transaction); - } - - CloseHandle(atomic->transaction); - atomic->transaction = INVALID_HANDLE_VALUE; - - return retval; -} - -RAZOR_EXPORT void -razor_atomic_destroy(struct razor_atomic *atomic) -{ - int i; - - for(i = 0; i < atomic->n_files; i++) { - if (atomic->files[i].h != INVALID_HANDLE_VALUE) { - CloseHandle(atomic->files[i].h); - free(atomic->files[i].path); - } - } - free(atomic->files); - if (atomic->transaction != INVALID_HANDLE_VALUE) { - RollbackTransaction(atomic->transaction); - CloseHandle(atomic->transaction); - } - free(atomic->error_path); - free(atomic->error_str); - free(atomic->error_msg); - free(atomic); -} - -RAZOR_EXPORT int -razor_atomic_make_dirs(struct razor_atomic *atomic, const char *root, - const char *path) -{ - struct razor_wstr *buffer; - const char *slash, *s, *next; - WIN32_FILE_ATTRIBUTE_DATA fa; - DWORD err; - int r, creating = 0; - - if (atomic->error_str) - return -1; - - buffer = razor_wstr_create(root, -1); - slash = path; - - for (; *slash != '\0'; slash = next) { - next = strpbrk(slash + 1, "/\\"); - if (next == NULL) - break; - - razor_wstr_append(buffer, slash, next - slash); - - if (!creating) { - if (razor_valid_root_name(buffer->str)) - continue; - - r = GetFileAttributesTransactedW(buffer->str, - GetFileExInfoStandard, - &fa, - atomic->transaction); - - if (!r) { - err = GetLastError(); - if (err == ERROR_FILE_NOT_FOUND) { - creating = 1; - } else { - razor_atomic_set_error(atomic, - buffer->str, - err); - razor_wstr_destroy(buffer); - return -1; - } - } else if (!(fa.dwFileAttributes& - FILE_ATTRIBUTE_DIRECTORY)) { - razor_atomic_set_error_str(atomic, buffer->str, - "Not a directory"); - razor_wstr_destroy(buffer); - return -1; - } - } - if (creating) { - if (!CreateDirectoryTransactedW(NULL, buffer->str, NULL, - atomic->transaction)) { - razor_atomic_set_error(atomic, buffer->str, - GetLastError()); - razor_wstr_destroy(buffer); - return -1; - } - - /* FIXME: What to do about permissions for dirs we - * have to create but are not in the cpio archive? */ - } - } - - razor_wstr_destroy(buffer); - - return 0; -} - -RAZOR_EXPORT int -razor_atomic_remove(struct razor_atomic *atomic, const char *path) -{ - wchar_t *buf; - DWORD err; - - if (atomic->error_str) - return -1; - - buf = razor_utf8_to_utf16(path, -1); - - if (DeleteFileTransactedW(buf, atomic->transaction)) { - free(buf); - return 0; - } - - err = GetLastError(); - if (err == ERROR_FILE_NOT_FOUND || err == ERROR_PATH_NOT_FOUND) { - free(buf); - return 0; - } - - if (SetFileAttributesTransactedW(buf, FILE_ATTRIBUTE_NORMAL, - atomic->transaction)) { - if (DeleteFileTransactedW(buf, atomic->transaction)) { - free(buf); - return 0; - } - err = GetLastError(); - } - - if (RemoveDirectoryTransactedW(buf, atomic->transaction) || - GetLastError() == ERROR_DIR_NOT_EMPTY) { - free(buf); - return 0; - } - - /* - * It would be tempting to use: - * MoveFileEx(path, NULL, MOVEFILE_DELAY_UNTIL_REBOOT) - * but unless we can guarantee that the system will be rebooted - * before we (or some other application) write another file with the - * same path, this is likely to cause more problems than it solves. - */ - - razor_atomic_set_error(atomic, buf, err); - free(buf); - return -1; -} - -RAZOR_EXPORT int -razor_atomic_rename_file(struct razor_atomic *atomic, const char *oldpath, - const char *newpath) -{ - wchar_t *oldbuf, *newbuf; - const DWORD flags = MOVEFILE_COPY_ALLOWED | MOVEFILE_REPLACE_EXISTING; - - if (atomic->error_str) - return -1; - - newbuf = razor_utf8_to_utf16(newpath, -1); - oldbuf = razor_utf8_to_utf16(oldpath, -1); - - /* - * Passing MOVEFILE_REPLACE_EXISTING to MoveFileTransaction() will - * cover every case we care about _except_ replacing an empty - * directory with a file. Calling RemoveDirectoryTransacted() will deal - * with this case while having no effect in all other cases. - */ - (void)RemoveDirectoryTransactedW(newbuf, atomic->transaction); - - if (!MoveFileTransactedW(oldbuf, newbuf, NULL, NULL, flags, - atomic->transaction)) - razor_atomic_set_error(atomic, newbuf, GetLastError()); - - free(newbuf); - free(oldbuf); - - return !!atomic->error_str; -} - -RAZOR_EXPORT int -razor_atomic_create_dir(struct razor_atomic *atomic, const char *dirname, - mode_t mode) -{ - wchar_t *buf; - DWORD err; - WIN32_FILE_ATTRIBUTE_DATA fa; - - if (atomic->error_str) - return -1; - - buf = razor_utf8_to_utf16(dirname, -1); - - if (!CreateDirectoryTransactedW(NULL, buf, NULL, atomic->transaction)) { - err = GetLastError(); - if (err != ERROR_FILE_EXISTS && err != ERROR_ALREADY_EXISTS) { -abort: - razor_atomic_set_error(atomic, buf, err); - free(buf); - return -1; - } - - if (!GetFileAttributesTransactedW(buf, GetFileExInfoStandard, - &fa, atomic->transaction)) - goto abort; - - if (!(fa.dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY)) { - if (razor_atomic_remove(atomic, dirname)) { - free(buf); - return -1; - } - if (!CreateDirectoryTransactedW(NULL, buf, NULL, - atomic->transaction)) { - err = GetLastError(); - goto abort; - } - } - } - - free(buf); - - return 0; -} - -RAZOR_EXPORT int -razor_atomic_create_symlink(struct razor_atomic *atomic, const char *target, - const char *path) -{ - if (atomic->error_str) - return -1; - - /* - * This isn't true, but symbolic links under Windows 7 - * need to know whether the target is a directory or not - * and we don't always know that at the time when the - * link is created, so it's a convienent lie for now. - */ - razor_atomic_set_error_str(atomic, NULL, "Symbolic links not supported " - "on this platform"); - - return -1; -} - -RAZOR_EXPORT int -razor_atomic_create_file(struct razor_atomic *atomic, const char *filename, - mode_t mode) -{ - DWORD attribs; - struct razor_atomic_file *files; - int i = atomic->n_files; - - if (atomic->error_str) - return -1; - - files = realloc(atomic->files, - (atomic->n_files+1) * sizeof(struct razor_atomic_file)); - if (!files) { - razor_atomic_set_error_str(atomic, NULL, "Not enough memory"); - return -1; - } - atomic->n_files++; - atomic->files = files; - - files[i].path = razor_utf8_to_utf16(filename, -1); - - /* - * Passing CREATE_ALWAYS to CreateFileTransacted() will cover - * every case we care about _except_ replacing an empty directory - * with a file. Calling RemoveDirectoryTransacted() will deal - * with this case while having no effect in all other cases. - */ - (void)RemoveDirectoryTransactedW(files[i].path, atomic->transaction); - - if (mode & S_IWUSR) - attribs = FILE_ATTRIBUTE_NORMAL; - else - attribs = FILE_ATTRIBUTE_READONLY; - - files[i].h = CreateFileTransactedW(files[i].path, GENERIC_WRITE, - 0, NULL, CREATE_ALWAYS, attribs, - NULL, atomic->transaction, NULL, - NULL); - - if (files[i].h == INVALID_HANDLE_VALUE) { - razor_atomic_set_error(atomic, files[i].path, GetLastError()); - free(files[i].path); - atomic->n_files--; - return -1; - } - - return i; -} - -RAZOR_EXPORT int -razor_atomic_write(struct razor_atomic *atomic, int handle, const void *data, - size_t size) -{ - DWORD written; - - if (atomic->error_str) - return -1; - - assert(handle < atomic->n_files); - assert(atomic->files[handle].h != INVALID_HANDLE_VALUE); - - while(size) { - if (!WriteFile(atomic->files[handle].h, data, size, &written, - NULL)) { - razor_atomic_set_error(atomic, - atomic->files[handle].path, - GetLastError()); - - (void)CloseHandle(atomic->files[handle].h); - free(atomic->files[handle].path); - atomic->files[handle].path = NULL; - atomic->files[handle].h = INVALID_HANDLE_VALUE; - - return -1; - } - - data += written; - size -= written; - } - - return 0; -} - -RAZOR_EXPORT int -razor_atomic_sync(struct razor_atomic *atomic, int handle) -{ - HANDLE h; - - if (atomic->error_str) - return -1; - - assert(handle < atomic->n_files); - assert(atomic->files[handle].h != INVALID_HANDLE_VALUE); - - if (!CloseHandle(atomic->files[handle].h)) { - razor_atomic_set_error(atomic, atomic->files[handle].path, - GetLastError()); - free(atomic->files[handle].path); - atomic->files[handle].path = NULL; - atomic->files[handle].h = INVALID_HANDLE_VALUE; - return -1; - } - - h = CreateFileTransactedW(atomic->files[handle].path, GENERIC_WRITE, 0, - NULL, OPEN_EXISTING, 0, NULL, - atomic->transaction, NULL, NULL); - atomic->files[handle].h = h; - - if (atomic->files[handle].h == INVALID_HANDLE_VALUE) { - razor_atomic_set_error(atomic, atomic->files[handle].path, - GetLastError()); - free(atomic->files[handle].path); - atomic->files[handle].path = NULL; - return -1; - } - - return !!atomic->error_str; -} - -RAZOR_EXPORT int -razor_atomic_close(struct razor_atomic *atomic, int handle) -{ - if (atomic->error_str) - return -1; - - assert(handle < atomic->n_files); - assert(atomic->files[handle].h != INVALID_HANDLE_VALUE); - - if (!CloseHandle(atomic->files[handle].h)) - razor_atomic_set_error(atomic, atomic->files[handle].path, - GetLastError()); - - free(atomic->files[handle].path); - atomic->files[handle].path = NULL; - atomic->files[handle].h = INVALID_HANDLE_VALUE; - - while(atomic->n_files > 0 && - atomic->files[atomic->n_files-1].h == INVALID_HANDLE_VALUE) - atomic->n_files--; - - return !!atomic->error_str; -} - -#else /* HAVE_WINDOWS_KVM */ - -static int -razor_valid_root_name(const char *name) -{ - if (allow_all_root_names) { -#ifdef MSWIN_API - return !strpbrk(name, "/\\"); -#else - return !strchr(name, '/'); -#endif - } - -#ifdef MSWIN_API - return RAZOR_ASCII_ISALPHA(name[0]) && name[1] == ':' && - name[2] == '\0'; -#else - return name[0] == '\0'; -#endif -} - -struct razor_atomic { - char *error_path; - char *error_str; - char *error_msg; -}; - -RAZOR_EXPORT struct razor_atomic * -razor_atomic_open(const char *description) -{ - struct razor_atomic *atomic; - - atomic = zalloc(sizeof *atomic); - - return atomic; -} - -static void -razor_atomic_set_error_str(struct razor_atomic *atomic, const char *path, - const char *str) -{ - assert(!atomic->error_str); - - atomic->error_path = path ? strdup(path) : NULL; - atomic->error_str = strdup(str); -} - -#ifdef MSWIN_API -static void -razor_atomic_set_error_mswin(struct razor_atomic *atomic, const wchar_t *path, - DWORD error) -{ - wchar_t *buf; - - assert(!atomic->error_str); - - free(atomic->error_path); - - if (path) - atomic->error_path = razor_utf16_to_utf8(path, -1); - else - atomic->error_path = NULL; - - FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER| - FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS, - NULL, error, MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT), - (LPWSTR)&buf, 0, NULL); - atomic->error_str = razor_utf16_to_utf8(buf, -1); - LocalFree(buf); -} -#endif - -RAZOR_EXPORT int -razor_atomic_commit(struct razor_atomic *atomic) -{ - return !!atomic->error_str; -} - -RAZOR_EXPORT void -razor_atomic_destroy(struct razor_atomic *atomic) -{ - free(atomic->error_path); - free(atomic->error_str); - free(atomic->error_msg); - free(atomic); -} - -RAZOR_EXPORT int -razor_atomic_make_dirs(struct razor_atomic *atomic, const char *root, - const char *path) -{ - char buffer[PATH_MAX], *p; - const char *slash, *next; - struct stat buf; - - if (atomic->error_str) - return -1; - - strcpy(buffer, root); - p = buffer + strlen(buffer); - slash = path; - for (slash = path; *slash != '\0'; slash = next) { -#ifdef MSWIN_API - next = strpbrk(slash + 1, "/\\"); -#else - next = strchr(slash + 1, '/'); -#endif - if (next == NULL) - break; - - memcpy(p, slash, next - slash); - p += next - slash; - *p = '\0'; - - if (razor_valid_root_name(buffer)) - continue; - - if (stat(buffer, &buf) == 0) { - if (!S_ISDIR(buf.st_mode)) { - razor_atomic_set_error_str(atomic, buffer, - "Not a directory"); - return -1; - } - } else if (mkdir(buffer, 0777) < 0) { - razor_atomic_set_error_str(atomic, buffer, - strerror(errno)); - return -1; - } - } - - return 0; -} - -RAZOR_EXPORT int -razor_atomic_remove(struct razor_atomic *atomic, const char *path) -{ -#ifdef MSWIN_API - wchar_t *buf; - DWORD err; -#endif - - if (atomic->error_str) - return -1; - -#ifdef MSWIN_API - buf = razor_utf8_to_utf16(path, -1); - - if (!DeleteFileW(buf)) { - err = GetLastError(); - if (err != ERROR_FILE_NOT_FOUND && - err != ERROR_PATH_NOT_FOUND && - !(SetFileAttributesW(buf, FILE_ATTRIBUTE_NORMAL) && - DeleteFileW(buf)) && - !RemoveDirectoryW(buf) && - GetLastError() != ERROR_DIR_NOT_EMPTY) - razor_atomic_set_error_mswin(atomic, buf, err); - } - - free(buf); -#else - if (remove(path)) - razor_atomic_set_error_str(atomic, path, strerror(errno)); -#endif - - return !!atomic->error_str; -} - -RAZOR_EXPORT int -razor_atomic_rename_file(struct razor_atomic *atomic, const char *oldpath, - const char *newpath) -{ -#ifdef MSWIN_API - wchar_t *oldbuf, *newbuf; - const DWORD flags = MOVEFILE_COPY_ALLOWED | MOVEFILE_REPLACE_EXISTING; -#endif - - if (atomic->error_str) - return -1; - -#ifdef MSWIN_API - newbuf = razor_utf8_to_utf16(newpath, -1); - oldbuf = razor_utf8_to_utf16(oldpath, -1); - - /* - * Passing MOVEFILE_REPLACE_EXISTING to MoveFileEx() will - * cover every case we care about _except_ replacing an empty - * directory with a file. Calling RemoveDirectory() will deal - * with this case while having no effect in all other cases. - */ - (void)RemoveDirectoryW(newbuf); - - if (!MoveFileExW(oldbuf, newbuf, flags)) - razor_atomic_set_error_mswin(atomic, newbuf, GetLastError()); - - free(newbuf); - free(oldbuf); -#else - if (rename(oldpath, newpath)) - razor_atomic_set_error_str(atomic, newpath, strerror(errno)); -#endif - - return !!atomic->error_str; -} - -RAZOR_EXPORT int -razor_atomic_create_dir(struct razor_atomic *atomic, const char *dirname, - mode_t mode) -{ - if (atomic->error_str) - return -1; - - if (!mkdir(dirname, mode & (S_IRWXU | S_IRWXG | S_IRWXO))) - return 0; - - if (errno != EEXIST) { - razor_atomic_set_error_str(atomic, dirname, strerror(errno)); - return -1; - } - - if (chmod(dirname, mode & (S_IRWXU | S_IRWXG | S_IRWXO)) < 0) { - razor_atomic_set_error_str(atomic, dirname, strerror(errno)); - return -1; - } - - return 0; -} - -RAZOR_EXPORT int -razor_atomic_create_symlink(struct razor_atomic *atomic, const char *target, - const char *path) -{ - if (atomic->error_str) - return -1; - -#if HAVE_SYMLINK - if (symlink(target, path) < 0) { - razor_atomic_set_error_str(atomic, NULL, strerror(errno)); - return -1; - } -#else - razor_atomic_set_error_str(atomic, NULL, "Symbolic links not supported " - "on this platform"); -#endif - - return 0; -} - -RAZOR_EXPORT int -razor_atomic_create_file(struct razor_atomic *atomic, const char *filename, - mode_t mode) -{ - int fd; - - if (atomic->error_str) - return -1; - - atomic->error_path = strdup(filename); - fd = open(atomic->error_path, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, - mode & (S_IRWXU | S_IRWXG | S_IRWXO)); - - if (fd == -1) - razor_atomic_set_error_str(atomic, NULL, strerror(errno)); - - return fd; -} - -RAZOR_EXPORT int -razor_atomic_write(struct razor_atomic *atomic, int fd, const void *data, - size_t size) -{ - int written; - - if (atomic->error_str) - return -1; - - while(size) { - written = write(fd, data, size); - if (written < 0) { - razor_atomic_set_error_str(atomic, NULL, strerror(errno)); - - (void)close(fd); - - return -1; - } - - data += written; - size -= written; - } - - return 0; -} - -RAZOR_EXPORT int -razor_atomic_sync(struct razor_atomic *atomic, int handle) -{ - if (atomic->error_str) - return -1; - - if (fsync(handle) < 0) { - razor_atomic_set_error_str(atomic, NULL, strerror(errno)); - return -1; - } - - free(atomic->error_path); - atomic->error_path = NULL; - - return 0; -} - -RAZOR_EXPORT int -razor_atomic_close(struct razor_atomic *atomic, int fd) -{ - if (atomic->error_str) - return -1; - - if (close(fd) < 0) { - razor_atomic_set_error_str(atomic, NULL, strerror(errno)); - return -1; - } - - free(atomic->error_path); - atomic->error_path = NULL; - - return 0; -} - -#endif /* HAVE_WINDOWS_KVM */ - RAZOR_EXPORT const char * razor_atomic_get_error_msg(struct razor_atomic *atomic) { @@ -998,5 +79,131 @@ RAZOR_EXPORT int razor_atomic_in_error_state(struct razor_atomic *atomic) { - return !!atomic->error_str; + return atomic->error_str && !atomic->in_undo; } + +#if !HAVE_WINDOWS_KTM + +/* + * Common code with atomic-none and atomic-emulate + */ + +#define RAZOR_ASCII_ISALPHA(c) \ + ((c) >= 'A' && (c) <= 'Z' || (c) >= 'a' && (c) <= 'z') + +int +razor_valid_root_name(const char *name) +{ + if (razor_allow_all_root_names()) { +#ifdef MSWIN_API + return !strpbrk(name, "/\\"); +#else + return !strchr(name, '/'); +#endif + } + +#ifdef MSWIN_API + return RAZOR_ASCII_ISALPHA(name[0]) && name[1] == ':' && + name[2] == '\0'; +#else + return name[0] == '\0'; +#endif +} + +#ifdef MSWIN_API +void +razor_atomic_set_error_mswin(struct razor_atomic *atomic, const wchar_t *path, + DWORD error) +{ + wchar_t *buf; + + assert(!atomic->error_str); + + free(atomic->error_path); + + if (path) + atomic->error_path = razor_utf16_to_utf8(path, -1); + else + atomic->error_path = NULL; + + FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER| + FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, error, MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT), + (LPWSTR)&buf, 0, NULL); + atomic->error_str = razor_utf16_to_utf8(buf, -1); + LocalFree(buf); +} +#endif + +void +razor_atomic_set_error_str(struct razor_atomic *atomic, const char *path, + const char *str) +{ + assert(!atomic->error_str); + + atomic->error_path = path ? strdup(path) : NULL; + atomic->error_str = strdup(str); +} + +RAZOR_EXPORT int +razor_atomic_write(struct razor_atomic *atomic, int fd, const void *data, + size_t size) +{ + int written; + + if (razor_atomic_in_error_state(atomic)) + return -1; + + while(size) { + written = write(fd, data, size); + if (written < 0) { + razor_atomic_set_error_str(atomic, NULL, + strerror(errno)); + + (void)close(fd); + + return -1; + } + + data += written; + size -= written; + } + + return 0; +} + +RAZOR_EXPORT int +razor_atomic_sync(struct razor_atomic *atomic, int handle) +{ + if (razor_atomic_in_error_state(atomic)) + return -1; + + if (fsync(handle) < 0) { + razor_atomic_set_error_str(atomic, NULL, strerror(errno)); + return -1; + } + + free(atomic->error_path); + atomic->error_path = NULL; + + return 0; +} + +RAZOR_EXPORT int +razor_atomic_close(struct razor_atomic *atomic, int fd) +{ + if (razor_atomic_in_error_state(atomic)) + return -1; + + if (close(fd) < 0) { + razor_atomic_set_error_str(atomic, NULL, strerror(errno)); + return -1; + } + + free(atomic->error_path); + atomic->error_path = NULL; + + return 0; +} + +#endif /* !HAVE_WINDOWS_KTM */