summaryrefslogtreecommitdiff
path: root/tar/bsdtar_windows.c
diff options
context:
space:
mode:
authorMichihiro NAKAJIMA <ggcueroad@gmail.com>2009-02-25 01:53:34 -0500
committerMichihiro NAKAJIMA <ggcueroad@gmail.com>2009-02-25 01:53:34 -0500
commit45dc32d5c0fbd235bf24fb86f8d97cebdab56053 (patch)
tree7603652c43f09f8191346c3fa1976c9fa3e6950c /tar/bsdtar_windows.c
parent6cf83ca0343c85f7099d926d06e7d7e457211bc7 (diff)
downloadlibarchive-45dc32d5c0fbd235bf24fb86f8d97cebdab56053.tar.gz
On Windows, rewrite permissive_name function.
GetFullPathName Windows API does not always return a full path name start with drive letters such as "c:\". It wasn't that permissive_name function had expected. e.g. When we changed a current directory by "//./c:/path-to" and got a full path name of "file" by GetFullPathName, GetFullPathName API returned "\\.\c:\path-to\file" not "c:\path-to\file". And then permissive_name returned "\\?\\\.\c:\path-to\file" (wrong path). SVN-Revision: 708
Diffstat (limited to 'tar/bsdtar_windows.c')
-rw-r--r--tar/bsdtar_windows.c113
1 files changed, 57 insertions, 56 deletions
diff --git a/tar/bsdtar_windows.c b/tar/bsdtar_windows.c
index b92b6696..25bdab34 100644
--- a/tar/bsdtar_windows.c
+++ b/tar/bsdtar_windows.c
@@ -94,90 +94,91 @@ permissive_name(const char *name)
{
wchar_t *wn, *wnp;
wchar_t *ws, *wsp;
- size_t len, slen;
- int i, n, unc;
+ size_t l, len, slen;
+ int unc;
len = strlen(name);
- wn = wnp = malloc((len + 1) * sizeof(wchar_t));
+ wn = malloc((len + 1) * sizeof(wchar_t));
if (wn == NULL)
return (NULL);
- n = MultiByteToWideChar(CP_ACP, 0, name, len, wn, len);
- if (n == 0) {
+ l = MultiByteToWideChar(CP_ACP, 0, name, len, wn, len);
+ if (l == 0) {
free(wn);
return (NULL);
}
- wn[n] = L'\0';
+ wn[l] = L'\0';
+
+ /* Get a full path names */
+ l = GetFullPathNameW(wn, 0, NULL, NULL);
+ if (l == 0) {
+ free(wn);
+ return (NULL);
+ }
+ wnp = malloc(l * sizeof(wchar_t));
+ if (wnp == NULL) {
+ free(wn);
+ return (NULL);
+ }
+ len = GetFullPathNameW(wn, l, wnp, NULL);
+ free(wn);
+ wn = wnp;
+
+ if (wnp[0] == L'\\' && wnp[1] == L'\\' &&
+ wnp[2] == L'?' && wnp[3] == L'\\')
+ /* We have already permissive names. */
+ return (wn);
+
+ if (wnp[0] == L'\\' && wnp[1] == L'\\' &&
+ wnp[2] == L'.' && wnp[3] == L'\\') {
+ /* Device names */
+ if (((wnp[4] >= L'a' && wnp[4] <= L'z') ||
+ (wnp[4] >= L'A' && wnp[4] <= L'Z')) &&
+ wnp[5] == L':' && wnp[6] == L'\\')
+ wnp[2] = L'?';/* Not device names. */
+ return (wn);
+ }
- /* When we use "\\?\" prefix, a path name cannot be used with '/'. */
- for (i = 0; i < n; i++)
- if (wn[i] == L'/')
- wn[i] = L'\\';
unc = 0;
- if (wnp[0] == L'\\' && wnp[1] == L'\\') {
- /* UNC: start characters are "\\"*/
- wnp += 2;
- len -= 2;
- if (wnp[0] == L'.' && wnp[1] == L'\\' && iswalpha(wnp[2])
- && wnp[3] == L':' && wnp[4] == L'\\') {
- /* start characters are "\\.\[drive]:\", feed a pointer more */
- wnp += 2;
- len -= 2;
- /* now start characters of wnp are "C:" or "D:" or.... */
- } else
- unc = 1;
- } else if (wnp[1] == L':' && iswalpha(wnp[0]))
- /* start characters are "C:","D:"...: already full path */
- ;
- else {
- size_t l;
- wchar_t *full;
-
- /* getting a full path name */
- full = malloc((len + MAX_PATH) * sizeof(wchar_t));
- if (full == NULL) {
- free(wn);
- return (NULL);
- }
- l = GetFullPathNameW(wnp, len + MAX_PATH, full, NULL);
- if (l >= len + MAX_PATH) {
- /* buffer size is smaller */
- full = realloc(full, l * sizeof(wchar_t));
- if (full == NULL) {
- free(wn);
- return (NULL);
+ if (wnp[0] == L'\\' && wnp[1] == L'\\' && wnp[2] != L'\\') {
+ wchar_t *p = &wnp[2];
+
+ /* Skip server-name letters. */
+ while (*p != L'\\' && *p != L'\0')
+ ++p;
+ if (*p == L'\\') {
+ wchar_t *rp = ++p;
+ /* Skip share-name letters. */
+ while (*p != L'\\' && *p != L'\0')
+ ++p;
+ if (*p == L'\\' && p != rp) {
+ /* Now, match patterns such as
+ * "\\server-name\share-name\" */
+ wnp += 2;
+ len -= 2;
+ unc = 1;
}
- l = GetFullPathNameW(wnp, l, full, NULL);
}
- if (l != 0) {
- full[l] = L'\0';
- free(wn);
- wn = wnp = full;
- len = l;
- } else
- free(full);
}
-
+
slen = 4 + (unc * 4) + len + 1;
ws = wsp = malloc(slen * sizeof(wchar_t));
if (ws == NULL) {
free(wn);
return (NULL);
}
-
/* prepend "\\?\" */
wcsncpy(wsp, L"\\\\?\\", 4);
wsp += 4;
slen -= 4;
if (unc) {
- /* append "UNC\" ---> "\\?\UNC\"*/
+ /* append "UNC\" ---> "\\?\UNC\" */
wcsncpy(wsp, L"UNC\\", 4);
wsp += 4;
slen -= 4;
}
- wcsncpy_s(wsp, slen, wnp, len);
+ wcsncpy_s(wsp, slen, wnp, _TRUNCATE);
free(wn);
- wn = ws;
- return (wn);
+ return (ws);
}
static HANDLE