diff options
author | Michihiro NAKAJIMA <ggcueroad@gmail.com> | 2009-02-25 01:53:34 -0500 |
---|---|---|
committer | Michihiro NAKAJIMA <ggcueroad@gmail.com> | 2009-02-25 01:53:34 -0500 |
commit | 45dc32d5c0fbd235bf24fb86f8d97cebdab56053 (patch) | |
tree | 7603652c43f09f8191346c3fa1976c9fa3e6950c /tar/bsdtar_windows.c | |
parent | 6cf83ca0343c85f7099d926d06e7d7e457211bc7 (diff) | |
download | libarchive-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.c | 113 |
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 |