Only export symbols starting with razor_ in dynamic library.
Apart from being good practice to avoid clashes with higher-level
libraries and the application, this also fixes an obscure bug: The
gnulib library is used both by librazor (the dynamic library) and
by razor (the executable). In doing so, we want to have two separate
copies of the library despite the code duplication this involves.
Without the explicit limit to export only razor_ symbols, the razor
executable under mingw64 was picking up the getopt_long function
from librazor and the optind variable from libgnu which meant that
it did not see optind changing. Hiding librazor's copy of getopt
causes the linker to find libgnu's copy and everything works.
Note that under mingw librazor-#.dll still contains undocumented
(private) razor_ symbols but these will do no harm as long as nobody
tries to use them.
2 * Copyright (C) 2011, 2012, 2014 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"
40 razor_valid_root_name2(const wchar_t *name)
42 if (razor_allow_all_root_names())
43 return !wcschr(name, '/');
45 return RAZOR_ASCII_ISALPHA(name[0]) && name[1] == ':' &&
54 static struct razor_wstr *
55 razor_wstr_create(const char *init, int len)
58 struct razor_wstr *wstr;
60 wstr = malloc(sizeof(struct razor_wstr));
62 n = MultiByteToWideChar(CP_UTF8, 0, init, len, NULL, 0);
63 if (len >= 0 && init[len])
68 wstr->allocated = n * 2;
69 wstr->str = malloc(wstr->allocated * sizeof(wchar_t));
75 (void)MultiByteToWideChar(CP_UTF8, 0, init, len, wstr->str, n);
76 if (len >= 0 && init[len])
77 wstr->str[wstr->len] = 0;
83 razor_wstr_append(struct razor_wstr *wstr, const char *s, int len)
88 n = MultiByteToWideChar(CP_UTF8, 0, s, len, NULL, 0);
89 if (len < 0 || !s[len])
92 if (wstr->allocated <= wstr->len + n) {
93 allocated = (wstr->len + n + 1) * 2;
94 str = realloc(wstr->str, allocated * sizeof(wchar_t));
97 wstr->allocated = allocated;
101 (void)MultiByteToWideChar(CP_UTF8, 0, s, len, wstr->str + wstr->len, n);
103 wstr->str[wstr->len] = 0;
109 razor_wstr_destroy(struct razor_wstr *wstr)
115 RAZOR_EXPORT struct razor_atomic *
116 razor_atomic_open(const char *description)
119 struct razor_atomic *atomic;
121 atomic = zalloc(sizeof *atomic);
122 buf = razor_utf8_to_utf16(description, -1);
123 atomic->transaction = CreateTransaction(NULL, 0,
124 TRANSACTION_DO_NOT_PROMOTE,
132 razor_atomic_commit(struct razor_atomic *atomic)
136 if (razor_atomic_in_error_state(atomic))
139 retval = !CommitTransaction(atomic->transaction);
142 razor_set_error_mswin(&atomic->error, NULL, GetLastError());
143 RollbackTransaction(atomic->transaction);
146 CloseHandle(atomic->transaction);
147 atomic->transaction = INVALID_HANDLE_VALUE;
153 razor_atomic_destroy(struct razor_atomic *atomic)
157 for(i = 0; i < atomic->n_files; i++) {
158 if (atomic->files[i].h != INVALID_HANDLE_VALUE) {
159 CloseHandle(atomic->files[i].h);
160 free(atomic->files[i].path);
164 if (atomic->transaction != INVALID_HANDLE_VALUE) {
165 RollbackTransaction(atomic->transaction);
166 CloseHandle(atomic->transaction);
169 razor_error_free(atomic->error);
174 razor_atomic_make_dirs(struct razor_atomic *atomic, const char *root,
177 struct razor_wstr *buffer;
178 const char *slash, *next;
179 WIN32_FILE_ATTRIBUTE_DATA fa;
183 if (razor_atomic_in_error_state(atomic))
186 buffer = razor_wstr_create(root, -1);
187 slash = buffer->len ? SKIP_DRIVE_LETTER(path) : path;
189 for (; *slash != '\0'; slash = next) {
190 next = strpbrk(slash + 1, "/\\");
194 razor_wstr_append(buffer, slash, next - slash);
197 if (razor_valid_root_name2(buffer->str))
200 r = GetFileAttributesTransactedW(buffer->str,
201 GetFileExInfoStandard,
203 atomic->transaction);
206 err = GetLastError();
207 if (err == ERROR_FILE_NOT_FOUND) {
210 razor_set_error_mswin(&atomic->error,
212 razor_wstr_destroy(buffer);
215 } else if (!(fa.dwFileAttributes&
216 FILE_ATTRIBUTE_DIRECTORY)) {
217 razor_set_error2(&atomic->error,
219 ERROR_DIRECTORY, buffer->str,
221 razor_wstr_destroy(buffer);
226 if (!CreateDirectoryTransactedW(NULL, buffer->str, NULL,
227 atomic->transaction)) {
228 razor_set_error_mswin(&atomic->error,
231 razor_wstr_destroy(buffer);
235 /* FIXME: What to do about permissions for dirs we
236 * have to create but are not in the cpio archive? */
240 razor_wstr_destroy(buffer);
246 razor_atomic_remove(struct razor_atomic *atomic, const char *path)
251 if (razor_atomic_in_error_state(atomic))
254 buf = razor_utf8_to_utf16(path, -1);
256 if (DeleteFileTransactedW(buf, atomic->transaction)) {
261 err = GetLastError();
262 if (err == ERROR_FILE_NOT_FOUND || err == ERROR_PATH_NOT_FOUND) {
267 if (SetFileAttributesTransactedW(buf, FILE_ATTRIBUTE_NORMAL,
268 atomic->transaction)) {
269 if (DeleteFileTransactedW(buf, atomic->transaction)) {
273 err = GetLastError();
276 if (RemoveDirectoryTransactedW(buf, atomic->transaction) ||
277 GetLastError() == ERROR_DIR_NOT_EMPTY) {
283 * It would be tempting to use:
284 * MoveFileEx(path, NULL, MOVEFILE_DELAY_UNTIL_REBOOT)
285 * but unless we can guarantee that the system will be rebooted
286 * before we (or some other application) write another file with the
287 * same path, this is likely to cause more problems than it solves.
290 razor_set_error_mswin(&atomic->error, buf, err);
296 razor_atomic_rename_file(struct razor_atomic *atomic, const char *oldpath,
299 wchar_t *oldbuf, *newbuf;
300 const DWORD flags = MOVEFILE_COPY_ALLOWED | MOVEFILE_REPLACE_EXISTING;
302 if (razor_atomic_in_error_state(atomic))
305 newbuf = razor_utf8_to_utf16(newpath, -1);
306 oldbuf = razor_utf8_to_utf16(oldpath, -1);
309 * Passing MOVEFILE_REPLACE_EXISTING to MoveFileTransaction() will
310 * cover every case we care about _except_ replacing an empty
311 * directory with a file. Calling RemoveDirectoryTransacted() will deal
312 * with this case while having no effect in all other cases.
314 (void)RemoveDirectoryTransactedW(newbuf, atomic->transaction);
316 if (!MoveFileTransactedW(oldbuf, newbuf, NULL, NULL, flags,
317 atomic->transaction))
318 razor_set_error_mswin(&atomic->error, newbuf, GetLastError());
323 return razor_atomic_in_error_state(atomic);
327 razor_atomic_create_dir(struct razor_atomic *atomic, const char *dirname,
332 WIN32_FILE_ATTRIBUTE_DATA fa;
334 if (razor_atomic_in_error_state(atomic))
337 buf = razor_utf8_to_utf16(dirname, -1);
339 if (!CreateDirectoryTransactedW(NULL, buf, NULL, atomic->transaction)) {
340 err = GetLastError();
341 if (err != ERROR_FILE_EXISTS && err != ERROR_ALREADY_EXISTS) {
343 razor_set_error_mswin(&atomic->error, buf, err);
348 if (!GetFileAttributesTransactedW(buf, GetFileExInfoStandard,
349 &fa, atomic->transaction))
352 if (!(fa.dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY)) {
353 if (razor_atomic_remove(atomic, dirname)) {
357 if (!CreateDirectoryTransactedW(NULL, buf, NULL,
358 atomic->transaction)) {
359 err = GetLastError();
371 razor_atomic_create_symlink(struct razor_atomic *atomic, const char *target,
374 if (razor_atomic_in_error_state(atomic))
378 * This isn't true, but symbolic links under Windows 7
379 * need to know whether the target is a directory or not
380 * and we don't always know that at the time when the
381 * link is created, so it's a convienent lie for now.
383 razor_set_error(&atomic->error, RAZOR_MSWIN_ERROR, ERROR_NOT_SUPPORTED,
384 NULL, "Symbolic links not supported on this platform");
390 razor_atomic_create_file(struct razor_atomic *atomic, const char *filename,
394 struct razor_atomic_file *files;
395 int i = atomic->n_files;
397 if (razor_atomic_in_error_state(atomic))
400 files = realloc(atomic->files,
401 (atomic->n_files+1) * sizeof(struct razor_atomic_file));
403 razor_set_error(&atomic->error, RAZOR_POSIX_ERROR, ENOMEM, NULL,
404 "Not enough memory");
408 atomic->files = files;
410 files[i].path = razor_utf8_to_utf16(filename, -1);
413 * Passing CREATE_ALWAYS to CreateFileTransacted() will cover
414 * every case we care about _except_ replacing an empty directory
415 * with a file. Calling RemoveDirectoryTransacted() will deal
416 * with this case while having no effect in all other cases.
418 (void)RemoveDirectoryTransactedW(files[i].path, atomic->transaction);
421 attribs = FILE_ATTRIBUTE_NORMAL;
423 attribs = FILE_ATTRIBUTE_READONLY;
425 files[i].h = CreateFileTransactedW(files[i].path, GENERIC_WRITE,
426 0, NULL, CREATE_ALWAYS, attribs,
427 NULL, atomic->transaction, NULL,
430 if (files[i].h == INVALID_HANDLE_VALUE) {
431 razor_set_error_mswin(&atomic->error, files[i].path,
442 razor_atomic_write(struct razor_atomic *atomic, int handle, const void *data,
447 if (razor_atomic_in_error_state(atomic))
450 assert(handle < atomic->n_files);
451 assert(atomic->files[handle].h != INVALID_HANDLE_VALUE);
454 if (!WriteFile(atomic->files[handle].h, data, size, &written,
456 razor_set_error_mswin(&atomic->error,
457 atomic->files[handle].path,
460 (void)CloseHandle(atomic->files[handle].h);
461 free(atomic->files[handle].path);
462 atomic->files[handle].path = NULL;
463 atomic->files[handle].h = INVALID_HANDLE_VALUE;
476 razor_atomic_sync(struct razor_atomic *atomic, int handle)
480 if (razor_atomic_in_error_state(atomic))
483 assert(handle < atomic->n_files);
484 assert(atomic->files[handle].h != INVALID_HANDLE_VALUE);
486 if (!CloseHandle(atomic->files[handle].h)) {
487 razor_set_error_mswin(&atomic->error,
488 atomic->files[handle].path,
490 free(atomic->files[handle].path);
491 atomic->files[handle].path = NULL;
492 atomic->files[handle].h = INVALID_HANDLE_VALUE;
496 h = CreateFileTransactedW(atomic->files[handle].path, GENERIC_WRITE, 0,
497 NULL, OPEN_EXISTING, 0, NULL,
498 atomic->transaction, NULL, NULL);
499 atomic->files[handle].h = h;
501 if (atomic->files[handle].h == INVALID_HANDLE_VALUE) {
502 razor_set_error_mswin(&atomic->error,
503 atomic->files[handle].path,
505 free(atomic->files[handle].path);
506 atomic->files[handle].path = NULL;
510 return razor_atomic_in_error_state(atomic);
514 razor_atomic_close(struct razor_atomic *atomic, int handle)
516 if (razor_atomic_in_error_state(atomic))
519 assert(handle < atomic->n_files);
520 assert(atomic->files[handle].h != INVALID_HANDLE_VALUE);
522 if (!CloseHandle(atomic->files[handle].h))
523 razor_set_error_mswin(&atomic->error,
524 atomic->files[handle].path,
527 free(atomic->files[handle].path);
528 atomic->files[handle].path = NULL;
529 atomic->files[handle].h = INVALID_HANDLE_VALUE;
531 while(atomic->n_files > 0 &&
532 atomic->files[atomic->n_files-1].h == INVALID_HANDLE_VALUE)
535 return razor_atomic_in_error_state(atomic);
538 #endif /* HAVE_WINDOWS_KTM */