Skip to content

Commit eb07fde

Browse files
authored
Merge pull request #2589 from mgreter/bugfix/unc-relative-paths
Fix win UNC path handling for dot and dotdot directories
2 parents 6ee62bd + 1420c11 commit eb07fde

File tree

1 file changed

+19
-2
lines changed

1 file changed

+19
-2
lines changed

src/file.cpp

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,8 @@ namespace Sass {
5656
#ifndef _WIN32
5757
char wd[wd_len];
5858
char* pwd = getcwd(wd, wd_len);
59+
// we should check error for more detailed info (e.g. ENOENT)
60+
// http://man7.org/linux/man-pages/man2/getcwd.2.html#ERRORS
5961
if (pwd == NULL) throw Exception::OperationError("cwd gone missing");
6062
std::string cwd = pwd;
6163
#else
@@ -74,11 +76,15 @@ namespace Sass {
7476
bool file_exists(const std::string& path)
7577
{
7678
#ifdef _WIN32
79+
wchar_t resolved[32768];
7780
// windows unicode filepaths are encoded in utf16
7881
std::string abspath(join_paths(get_cwd(), path));
7982
std::wstring wpath(UTF_8::convert_to_utf16("\\\\?\\" + abspath));
8083
std::replace(wpath.begin(), wpath.end(), '/', '\\');
81-
DWORD dwAttrib = GetFileAttributesW(wpath.c_str());
84+
DWORD rv = GetFullPathNameW(wpath.c_str(), 32767, resolved, NULL);
85+
if (rv > 32767) throw Exception::OperationError("Path is too long");
86+
if (rv == 0) throw Exception::OperationError("Path could not be resolved");
87+
DWORD dwAttrib = GetFileAttributesW(resolved);
8288
return (dwAttrib != INVALID_FILE_ATTRIBUTES &&
8389
(!(dwAttrib & FILE_ATTRIBUTE_DIRECTORY)));
8490
#else
@@ -200,6 +206,13 @@ namespace Sass {
200206
if (is_absolute_path(r)) return r;
201207
if (l[l.length()-1] != '/') l += '/';
202208

209+
// this does a logical cleanup of the right hand path
210+
// Note that this does collapse x/../y sections into y.
211+
// This is by design. If /foo on your system is a symlink
212+
// to /bar/baz, then /foo/../cd is actually /bar/cd,
213+
// not /cd as a naive ../ removal would give you.
214+
// will only work on leading double dot dirs on rhs
215+
// therefore it is safe if lhs is already resolved cwd
203216
while ((r.length() > 3) && ((r.substr(0, 3) == "../") || (r.substr(0, 3)) == "..\\")) {
204217
size_t L = l.length(), pos = find_last_folder_separator(l, L - 2);
205218
bool is_slash = pos + 2 == L && (l[pos+1] == '/' || l[pos+1] == '\\');
@@ -395,11 +408,15 @@ namespace Sass {
395408
#ifdef _WIN32
396409
BYTE* pBuffer;
397410
DWORD dwBytes;
411+
wchar_t resolved[32768];
398412
// windows unicode filepaths are encoded in utf16
399413
std::string abspath(join_paths(get_cwd(), path));
400414
std::wstring wpath(UTF_8::convert_to_utf16("\\\\?\\" + abspath));
401415
std::replace(wpath.begin(), wpath.end(), '/', '\\');
402-
HANDLE hFile = CreateFileW(wpath.c_str(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
416+
DWORD rv = GetFullPathNameW(wpath.c_str(), 32767, resolved, NULL);
417+
if (rv > 32767) throw Exception::OperationError("Path is too long");
418+
if (rv == 0) throw Exception::OperationError("Path could not be resolved");
419+
HANDLE hFile = CreateFileW(resolved, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
403420
if (hFile == INVALID_HANDLE_VALUE) return 0;
404421
DWORD dwFileLength = GetFileSize(hFile, NULL);
405422
if (dwFileLength == INVALID_FILE_SIZE) return 0;

0 commit comments

Comments
 (0)