summaryrefslogtreecommitdiff
path: root/libarchive/archive_write_set_format_ustar.c
diff options
context:
space:
mode:
authorMichihiro NAKAJIMA <ggcueroad@gmail.com>2012-02-21 17:18:32 +0900
committerMichihiro NAKAJIMA <ggcueroad@gmail.com>2012-02-21 17:18:32 +0900
commit6c8b32616fcd6ea1e14529dbeb503eb8357b225b (patch)
tree1f8fb4eafbc9f4f494e356b1b541b30bef5b5235 /libarchive/archive_write_set_format_ustar.c
parent8eb4c87a87d4ae5e74848541460b366cabf863f2 (diff)
downloadlibarchive-6c8b32616fcd6ea1e14529dbeb503eb8357b225b.tar.gz
On Windows, make sure libarchive does not store the Windows style path
separator '\' character into cpio, pax, ustar, gtar and zip archives, because it is not interoperable between Windows and POSIX platform, so we should replace '\' character in the pathnames with '/'.
Diffstat (limited to 'libarchive/archive_write_set_format_ustar.c')
-rw-r--r--libarchive/archive_write_set_format_ustar.c94
1 files changed, 82 insertions, 12 deletions
diff --git a/libarchive/archive_write_set_format_ustar.c b/libarchive/archive_write_set_format_ustar.c
index 1bc2372c..484ab34b 100644
--- a/libarchive/archive_write_set_format_ustar.c
+++ b/libarchive/archive_write_set_format_ustar.c
@@ -239,6 +239,7 @@ archive_write_ustar_header(struct archive_write *a, struct archive_entry *entry)
char buff[512];
int ret, ret2;
struct ustar *ustar;
+ struct archive_entry *entry_main;
struct archive_string_conv *sconv;
ustar = (struct ustar *)a->format_data;
@@ -269,37 +270,106 @@ archive_write_ustar_header(struct archive_write *a, struct archive_entry *entry)
if (AE_IFDIR == archive_entry_filetype(entry)) {
const char *p;
- char *t;
+ size_t path_length;
/*
* Ensure a trailing '/'. Modify the entry so
* the client sees the change.
*/
- p = archive_entry_pathname(entry);
- if (p[strlen(p) - 1] != '/') {
- t = (char *)malloc(strlen(p) + 2);
- if (t == NULL) {
+#if defined(_WIN32) && !defined(__CYGWIN__)
+ const wchar_t *wp;
+
+ wp = archive_entry_pathname_w(entry);
+ if (wp != NULL && wp[wcslen(wp) -1] != L'/') {
+ struct archive_wstring ws;
+
+ archive_string_init(&ws);
+ path_length = wcslen(wp);
+ if (archive_wstring_ensure(&ws,
+ path_length + 2) == NULL) {
+ archive_set_error(&a->archive, ENOMEM,
+ "Can't allocate ustar data");
+ archive_wstring_free(&ws);
+ return(ARCHIVE_FATAL);
+ }
+ /* Should we keep '\' ? */
+ if (wp[path_length -1] == L'\\')
+ path_length--;
+ archive_wstrncpy(&ws, wp, path_length);
+ archive_wstrappend_wchar(&ws, L'/');
+ archive_entry_copy_pathname_w(entry, ws.s);
+ archive_wstring_free(&ws);
+ p = NULL;
+ } else
+#endif
+ p = archive_entry_pathname(entry);
+ /*
+ * On Windows, this is a backup operation just in
+ * case getting WCS failed. On POSIX, this is a
+ * normal operation.
+ */
+ if (p != NULL && p[strlen(p) - 1] != '/') {
+ struct archive_string as;
+
+ archive_string_init(&as);
+ path_length = strlen(p);
+ if (archive_string_ensure(&as,
+ path_length + 2) == NULL) {
archive_set_error(&a->archive, ENOMEM,
- "Can't allocate ustar data");
+ "Can't allocate ustar data");
+ archive_string_free(&as);
return(ARCHIVE_FATAL);
}
- strcpy(t, p);
- strcat(t, "/");
- archive_entry_copy_pathname(entry, t);
- free(t);
+#if defined(_WIN32) && !defined(__CYGWIN__)
+ /* NOTE: This might break the pathname
+ * if the current code page is CP932 and
+ * the pathname includes a character '\'
+ * as a part of its multibyte pathname. */
+ if (p[strlen(p) -1] == '\\')
+ path_length--;
+ else
+#endif
+ archive_strncpy(&as, p, path_length);
+ archive_strappend_char(&as, '/');
+ archive_entry_copy_pathname(entry, as.s);
+ archive_string_free(&as);
}
}
+#if defined(_WIN32) && !defined(__CYGWIN__)
+ /* Make sure the path separators in pahtname, hardlink and symlink
+ * are all slash '/', not the Windows path separator '\'. */
+ entry_main = __la_win_entry_in_posix_pathseparator(entry);
+ if (entry_main == NULL) {
+ archive_set_error(&a->archive, ENOMEM,
+ "Can't allocate ustar data");
+ return(ARCHIVE_FATAL);
+ }
+ if (entry != entry_main)
+ entry = entry_main;
+ else
+ entry_main = NULL;
+#else
+ entry_main = NULL;
+#endif
ret = __archive_write_format_header_ustar(a, buff, entry, -1, 1, sconv);
- if (ret < ARCHIVE_WARN)
+ if (ret < ARCHIVE_WARN) {
+ if (entry_main)
+ archive_entry_free(entry_main);
return (ret);
+ }
ret2 = __archive_write_output(a, buff, 512);
- if (ret2 < ARCHIVE_WARN)
+ if (ret2 < ARCHIVE_WARN) {
+ if (entry_main)
+ archive_entry_free(entry_main);
return (ret2);
+ }
if (ret2 < ret)
ret = ret2;
ustar->entry_bytes_remaining = archive_entry_size(entry);
ustar->entry_padding = 0x1ff & (-(int64_t)ustar->entry_bytes_remaining);
+ if (entry_main)
+ archive_entry_free(entry_main);
return (ret);
}