Allow multiple atomic transactions to be used with one root object.
This allows transactions that include barriers to be performed
while holding an exclusive system lock.
2 * Copyright (C) 2011-2012 J. Ali Harlow <ali@juiblex.co.uk>
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License along
15 * with this program; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
37 #include "razor-internal.h"
43 RAZOR_EXPORT struct razor_atomic *
44 razor_atomic_open(const char *description)
46 struct razor_atomic *atomic;
48 atomic = zalloc(sizeof *atomic);
54 razor_atomic_commit(struct razor_atomic *atomic)
56 return razor_atomic_in_error_state(atomic);
60 razor_atomic_destroy(struct razor_atomic *atomic)
63 razor_error_free(atomic->error);
69 razor_atomic_make_dirs(struct razor_atomic *atomic, const char *root,
72 char buffer[PATH_MAX], *p;
73 const char *slash, *next;
76 if (razor_atomic_in_error_state(atomic))
80 p = buffer + strlen(buffer);
82 for (slash = path; *slash != '\0'; slash = next) {
84 next = strpbrk(slash + 1, "/\\");
86 next = strchr(slash + 1, '/');
91 memcpy(p, slash, next - slash);
95 if (razor_valid_root_name(buffer))
98 if (stat(buffer, &buf) == 0) {
99 if (!S_ISDIR(buf.st_mode)) {
100 atomic->error = razor_error_new_str(buffer,
104 } else if (mkdir(buffer, 0777) < 0) {
105 atomic->error = razor_error_new_str(buffer,
115 razor_atomic_remove(struct razor_atomic *atomic, const char *path)
122 if (razor_atomic_in_error_state(atomic))
126 buf = razor_utf8_to_utf16(path, -1);
128 if (!DeleteFileW(buf)) {
129 err = GetLastError();
130 if (err != ERROR_FILE_NOT_FOUND &&
131 err != ERROR_PATH_NOT_FOUND &&
132 !(SetFileAttributesW(buf, FILE_ATTRIBUTE_NORMAL) &&
134 !RemoveDirectoryW(buf) &&
135 GetLastError() != ERROR_DIR_NOT_EMPTY)
136 atomic->error = razor_error_new_mswin(buf, err);
142 atomic->error = razor_error_new_str(path, strerror(errno));
145 return razor_atomic_in_error_state(atomic);
149 razor_atomic_rename_file(struct razor_atomic *atomic, const char *oldpath,
153 wchar_t *oldbuf, *newbuf;
154 const DWORD flags = MOVEFILE_COPY_ALLOWED | MOVEFILE_REPLACE_EXISTING;
157 if (razor_atomic_in_error_state(atomic))
161 newbuf = razor_utf8_to_utf16(newpath, -1);
162 oldbuf = razor_utf8_to_utf16(oldpath, -1);
165 * Passing MOVEFILE_REPLACE_EXISTING to MoveFileEx() will
166 * cover every case we care about _except_ replacing an empty
167 * directory with a file. Calling RemoveDirectory() will deal
168 * with this case while having no effect in all other cases.
170 (void)RemoveDirectoryW(newbuf);
172 if (!MoveFileExW(oldbuf, newbuf, flags))
173 atomic->error = razor_error_new_mswin(newbuf, GetLastError());
178 if (rename(oldpath, newpath))
179 atomic->error = razor_error_new_str(newpath, strerror(errno));
182 return razor_atomic_in_error_state(atomic);
186 razor_atomic_create_dir(struct razor_atomic *atomic, const char *dirname,
189 if (razor_atomic_in_error_state(atomic))
192 if (!mkdir(dirname, mode & (S_IRWXU | S_IRWXG | S_IRWXO)))
195 if (errno != EEXIST) {
196 atomic->error = razor_error_new_str(dirname, strerror(errno));
200 if (chmod(dirname, mode & (S_IRWXU | S_IRWXG | S_IRWXO)) < 0) {
201 atomic->error = razor_error_new_str(dirname, strerror(errno));
209 razor_atomic_create_symlink(struct razor_atomic *atomic, const char *target,
212 if (razor_atomic_in_error_state(atomic))
216 if (symlink(target, path) < 0) {
217 atomic->error = razor_error_new_str(path, strerror(errno));
223 atomic->error = razor_error_new_str(NULL,
224 "Symbolic links not supported "
232 razor_atomic_create_file(struct razor_atomic *atomic, const char *filename,
237 if (razor_atomic_in_error_state(atomic))
240 fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
241 mode & (S_IRWXU | S_IRWXG | S_IRWXO));
244 atomic->error = razor_error_new_str(filename, strerror(errno));
249 #endif /* !ENABLE_ATOMIC */