diff options
author | Martin Matuska <mm@FreeBSD.org> | 2012-02-08 12:53:14 +0000 |
---|---|---|
committer | Martin Matuska <mm@FreeBSD.org> | 2012-02-08 12:53:14 +0000 |
commit | 17993d47e9beebea021707962fcdf2387b27cae9 (patch) | |
tree | 28a8e9d81eb7ed48e286dfc384e2e0ffccc238b5 /libarchive/archive_write_open_filename.c | |
parent | d8b2811c01ad218932b237af23558ab000e58265 (diff) | |
download | src-17993d47e9beebea021707962fcdf2387b27cae9.tar.gz src-17993d47e9beebea021707962fcdf2387b27cae9.zip |
Notes
Diffstat (limited to 'libarchive/archive_write_open_filename.c')
-rw-r--r-- | libarchive/archive_write_open_filename.c | 106 |
1 files changed, 94 insertions, 12 deletions
diff --git a/libarchive/archive_write_open_filename.c b/libarchive/archive_write_open_filename.c index 8a4cd3522196..8689866311c6 100644 --- a/libarchive/archive_write_open_filename.c +++ b/libarchive/archive_write_open_filename.c @@ -46,6 +46,7 @@ __FBSDID("$FreeBSD: head/lib/libarchive/archive_write_open_filename.c 191165 200 #endif #include "archive.h" +#include "archive_string.h" #ifndef O_BINARY #define O_BINARY 0 @@ -53,7 +54,11 @@ __FBSDID("$FreeBSD: head/lib/libarchive/archive_write_open_filename.c 191165 200 struct write_file_data { int fd; - char filename[1]; + char mbs_filename; + union { + char m[1]; + wchar_t w[1]; + } filename; /* Must be last! */ }; static int file_close(struct archive *, void *); @@ -79,12 +84,60 @@ archive_write_open_filename(struct archive *a, const char *filename) archive_set_error(a, ENOMEM, "No memory"); return (ARCHIVE_FATAL); } - strcpy(mine->filename, filename); + strcpy(mine->filename.m, filename); + mine->mbs_filename = 1; mine->fd = -1; return (archive_write_open(a, mine, file_open, file_write, file_close)); } +int +archive_write_open_filename_w(struct archive *a, const wchar_t *filename) +{ +#if defined(_WIN32) && !defined(__CYGWIN__) + struct write_file_data *mine; + + if (filename == NULL || filename[0] == L'\0') + return (archive_write_open_fd(a, 1)); + + mine = malloc(sizeof(*mine) + wcslen(filename) * sizeof(wchar_t)); + if (mine == NULL) { + archive_set_error(a, ENOMEM, "No memory"); + return (ARCHIVE_FATAL); + } + wcscpy(mine->filename.w, filename); + mine->mbs_filename = 0; + mine->fd = -1; + return (archive_write_open(a, mine, + file_open, file_write, file_close)); +#else + /* + * POSIX system does not support a wchar_t interface for + * open() system call, so we have to translate a wchar_t + * filename to multi-byte one and use it. + */ + struct archive_string fn; + int r; + + if (filename == NULL || filename[0] == L'\0') + return (archive_write_open_fd(a, 1)); + + archive_string_init(&fn); + if (archive_string_append_from_wcs(&fn, filename, + wcslen(filename)) != 0) { + archive_set_error(a, EINVAL, + "Failed to convert a wide-character filename to" + " a multi-byte filename"); + archive_string_free(&fn); + return (ARCHIVE_FATAL); + } + r = archive_write_open_filename(a, fn.s); + archive_string_free(&fn); + return (r); +#endif +} + + static int file_open(struct archive *a, void *client_data) { @@ -98,17 +151,46 @@ file_open(struct archive *a, void *client_data) /* * Open the file. */ - mine->fd = open(mine->filename, flags, 0666); - if (mine->fd < 0) { - archive_set_error(a, errno, "Failed to open '%s'", - mine->filename); - return (ARCHIVE_FATAL); - } + if (mine->mbs_filename) { + mine->fd = open(mine->filename.m, flags, 0666); + if (mine->fd < 0) { + archive_set_error(a, errno, "Failed to open '%s'", + mine->filename.m); + return (ARCHIVE_FATAL); + } + + if (fstat(mine->fd, &st) != 0) { + archive_set_error(a, errno, "Couldn't stat '%s'", + mine->filename.m); + return (ARCHIVE_FATAL); + } + } else { +#if defined(_WIN32) && !defined(__CYGWIN__) + mine->fd = _wopen(mine->filename.w, flags, 0666); + if (mine->fd < 0 && errno == ENOENT) { + wchar_t *fullpath; + fullpath = __la_win_permissive_name_w(mine->filename.w); + if (fullpath != NULL) { + mine->fd = _wopen(fullpath, flags, 0666); + free(fullpath); + } + } + if (mine->fd < 0) { + archive_set_error(a, errno, "Failed to open '%S'", + mine->filename.w); + return (ARCHIVE_FATAL); + } - if (fstat(mine->fd, &st) != 0) { - archive_set_error(a, errno, "Couldn't stat '%s'", - mine->filename); - return (ARCHIVE_FATAL); + if (fstat(mine->fd, &st) != 0) { + archive_set_error(a, errno, "Couldn't stat '%S'", + mine->filename.w); + return (ARCHIVE_FATAL); + } +#else + archive_set_error(a, ARCHIVE_ERRNO_MISC, + "Unexpedted operation in archive_write_open_filename"); + return (ARCHIVE_FATAL); +#endif } /* |