ali@416: /* ali@416: * Copyright (C) 2011-2012 J. Ali Harlow ali@416: * ali@416: * This program is free software; you can redistribute it and/or modify ali@416: * it under the terms of the GNU General Public License as published by ali@416: * the Free Software Foundation; either version 2 of the License, or ali@416: * (at your option) any later version. ali@416: * ali@416: * This program is distributed in the hope that it will be useful, ali@416: * but WITHOUT ANY WARRANTY; without even the implied warranty of ali@416: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ali@416: * GNU General Public License for more details. ali@416: * ali@416: * You should have received a copy of the GNU General Public License along ali@416: * with this program; if not, write to the Free Software Foundation, Inc., ali@416: * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. ali@416: */ ali@416: ali@416: #include "config.h" ali@416: ali@416: #if !ENABLE_ATOMIC ali@416: ali@416: #include ali@416: #ifdef MSWIN_API ali@416: #include ali@416: #endif ali@416: #include ali@416: #include ali@416: #include ali@416: #include ali@416: #include ali@416: #include ali@416: #include ali@416: #include ali@416: ali@416: #include "razor.h" ali@416: #include "razor-internal.h" ali@416: ali@416: #ifndef O_BINARY ali@416: #define O_BINARY 0 ali@416: #endif ali@416: ali@416: RAZOR_EXPORT struct razor_atomic * ali@416: razor_atomic_open(const char *description) ali@416: { ali@416: struct razor_atomic *atomic; ali@416: ali@416: atomic = zalloc(sizeof *atomic); ali@416: ali@416: return atomic; ali@416: } ali@416: ali@416: RAZOR_EXPORT int ali@416: razor_atomic_commit(struct razor_atomic *atomic) ali@416: { ali@416: return razor_atomic_in_error_state(atomic); ali@416: } ali@416: ali@416: RAZOR_EXPORT void ali@416: razor_atomic_destroy(struct razor_atomic *atomic) ali@416: { ali@423: if (atomic->error) ali@423: razor_error_free(atomic->error); ali@423: ali@416: free(atomic); ali@416: } ali@416: ali@416: RAZOR_EXPORT int ali@416: razor_atomic_make_dirs(struct razor_atomic *atomic, const char *root, ali@416: const char *path) ali@416: { ali@416: char buffer[PATH_MAX], *p; ali@416: const char *slash, *next; ali@416: struct stat buf; ali@416: ali@416: if (razor_atomic_in_error_state(atomic)) ali@416: return -1; ali@416: ali@416: strcpy(buffer, root); ali@416: p = buffer + strlen(buffer); ali@416: slash = path; ali@416: for (slash = path; *slash != '\0'; slash = next) { ali@416: #ifdef MSWIN_API ali@416: next = strpbrk(slash + 1, "/\\"); ali@416: #else ali@416: next = strchr(slash + 1, '/'); ali@416: #endif ali@416: if (next == NULL) ali@416: break; ali@416: ali@416: memcpy(p, slash, next - slash); ali@416: p += next - slash; ali@416: *p = '\0'; ali@416: ali@416: if (razor_valid_root_name(buffer)) ali@416: continue; ali@416: ali@416: if (stat(buffer, &buf) == 0) { ali@416: if (!S_ISDIR(buf.st_mode)) { ali@423: atomic->error = razor_error_new_str(buffer, ali@423: "Not a directory"); ali@416: return -1; ali@416: } ali@416: } else if (mkdir(buffer, 0777) < 0) { ali@423: atomic->error = razor_error_new_str(buffer, ali@423: strerror(errno)); ali@416: return -1; ali@416: } ali@416: } ali@416: ali@416: return 0; ali@416: } ali@416: ali@416: RAZOR_EXPORT int ali@416: razor_atomic_remove(struct razor_atomic *atomic, const char *path) ali@416: { ali@416: #ifdef MSWIN_API ali@416: wchar_t *buf; ali@416: DWORD err; ali@416: #endif ali@416: ali@416: if (razor_atomic_in_error_state(atomic)) ali@416: return -1; ali@416: ali@416: #ifdef MSWIN_API ali@416: buf = razor_utf8_to_utf16(path, -1); ali@416: ali@416: if (!DeleteFileW(buf)) { ali@416: err = GetLastError(); ali@416: if (err != ERROR_FILE_NOT_FOUND && ali@416: err != ERROR_PATH_NOT_FOUND && ali@416: !(SetFileAttributesW(buf, FILE_ATTRIBUTE_NORMAL) && ali@416: DeleteFileW(buf)) && ali@416: !RemoveDirectoryW(buf) && ali@416: GetLastError() != ERROR_DIR_NOT_EMPTY) ali@423: atomic->error = razor_error_new_mswin(buf, err); ali@416: } ali@416: ali@416: free(buf); ali@416: #else ali@416: if (remove(path)) ali@423: atomic->error = razor_error_new_str(path, strerror(errno)); ali@416: #endif ali@416: ali@423: return razor_atomic_in_error_state(atomic); ali@416: } ali@416: ali@416: RAZOR_EXPORT int ali@416: razor_atomic_rename_file(struct razor_atomic *atomic, const char *oldpath, ali@416: const char *newpath) ali@416: { ali@416: #ifdef MSWIN_API ali@416: wchar_t *oldbuf, *newbuf; ali@416: const DWORD flags = MOVEFILE_COPY_ALLOWED | MOVEFILE_REPLACE_EXISTING; ali@416: #endif ali@416: ali@416: if (razor_atomic_in_error_state(atomic)) ali@416: return -1; ali@416: ali@416: #ifdef MSWIN_API ali@416: newbuf = razor_utf8_to_utf16(newpath, -1); ali@416: oldbuf = razor_utf8_to_utf16(oldpath, -1); ali@416: ali@416: /* ali@416: * Passing MOVEFILE_REPLACE_EXISTING to MoveFileEx() will ali@416: * cover every case we care about _except_ replacing an empty ali@416: * directory with a file. Calling RemoveDirectory() will deal ali@416: * with this case while having no effect in all other cases. ali@416: */ ali@416: (void)RemoveDirectoryW(newbuf); ali@416: ali@416: if (!MoveFileExW(oldbuf, newbuf, flags)) ali@423: atomic->error = razor_error_new_mswin(newbuf, GetLastError()); ali@416: ali@416: free(newbuf); ali@416: free(oldbuf); ali@416: #else ali@416: if (rename(oldpath, newpath)) ali@423: atomic->error = razor_error_new_str(newpath, strerror(errno)); ali@416: #endif ali@416: ali@423: return razor_atomic_in_error_state(atomic); ali@416: } ali@416: ali@416: RAZOR_EXPORT int ali@416: razor_atomic_create_dir(struct razor_atomic *atomic, const char *dirname, ali@416: mode_t mode) ali@416: { ali@416: if (razor_atomic_in_error_state(atomic)) ali@416: return -1; ali@416: ali@416: if (!mkdir(dirname, mode & (S_IRWXU | S_IRWXG | S_IRWXO))) ali@416: return 0; ali@416: ali@416: if (errno != EEXIST) { ali@423: atomic->error = razor_error_new_str(dirname, strerror(errno)); ali@416: return -1; ali@416: } ali@416: ali@416: if (chmod(dirname, mode & (S_IRWXU | S_IRWXG | S_IRWXO)) < 0) { ali@423: atomic->error = razor_error_new_str(dirname, strerror(errno)); ali@416: return -1; ali@416: } ali@416: ali@416: return 0; ali@416: } ali@416: ali@416: RAZOR_EXPORT int ali@416: razor_atomic_create_symlink(struct razor_atomic *atomic, const char *target, ali@416: const char *path) ali@416: { ali@416: if (razor_atomic_in_error_state(atomic)) ali@416: return -1; ali@416: ali@416: #if HAVE_SYMLINK ali@416: if (symlink(target, path) < 0) { ali@423: atomic->error = razor_error_new_str(path, strerror(errno)); ali@416: return -1; ali@416: } ali@416: ali@416: return 0; ali@416: #else ali@423: atomic->error = razor_error_new_str(NULL, ali@423: "Symbolic links not supported " ali@423: "on this platform"); ali@416: ali@416: return -1; ali@416: #endif ali@416: } ali@416: ali@416: RAZOR_EXPORT int ali@416: razor_atomic_create_file(struct razor_atomic *atomic, const char *filename, ali@416: mode_t mode) ali@416: { ali@416: int fd; ali@416: ali@416: if (razor_atomic_in_error_state(atomic)) ali@416: return -1; ali@416: ali@423: fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, ali@416: mode & (S_IRWXU | S_IRWXG | S_IRWXO)); ali@416: ali@416: if (fd == -1) ali@423: atomic->error = razor_error_new_str(filename, strerror(errno)); ali@416: ali@416: return fd; ali@416: } ali@416: ali@416: #endif /* !ENABLE_ATOMIC */