]> granicus.if.org Git - llvm/commitdiff
[Support, Windows] Handle long paths with unix separators
authorPirama Arumuga Nainar <pirama@google.com>
Mon, 21 Aug 2017 20:49:44 +0000 (20:49 +0000)
committerPirama Arumuga Nainar <pirama@google.com>
Mon, 21 Aug 2017 20:49:44 +0000 (20:49 +0000)
Summary:
The function widenPath() for Windows also normalizes long path names by
iterating over the path's components and calling append().  The
assumption during the iteration that separators are not returned by the
iterator doesn't hold because the iterators do return a separator when
the path has a drive name.  Handle this case by ignoring separators
during iteration.

Reviewers: rnk

Subscribers: danalbert, srhines

Differential Revision: https://reviews.llvm.org/D36752

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@311382 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Support/Windows/Path.inc
unittests/Support/Path.cpp

index 8dac0e4482bd6050e34b1b608537ff1a17eb9593..f82a6bc07bdf5204911919729c881b328efe01b3 100644 (file)
@@ -94,13 +94,16 @@ std::error_code widenPath(const Twine &Path8,
         return EC;
       FullPath.append(CurPath);
     }
-    // Traverse the requested path, canonicalizing . and .. as we go (because
-    // the \\?\ prefix is documented to treat them as real components).
-    // The iterators don't report separators and append() always attaches
-    // preferred_separator so we don't need to call native() on the result.
+    // Traverse the requested path, canonicalizing . and .. (because the \\?\
+    // prefix is documented to treat them as real components).  Ignore
+    // separators, which can be returned from the iterator if the path has a
+    // drive name.  We don't need to call native() on the result since append()
+    // always attaches preferred_separator.
     for (llvm::sys::path::const_iterator I = llvm::sys::path::begin(Path8Str),
                                          E = llvm::sys::path::end(Path8Str);
                                          I != E; ++I) {
+      if (I->size() == 1 && is_separator((*I)[0]))
+        continue;
       if (I->size() == 1 && *I == ".")
         continue;
       if (I->size() == 2 && *I == "..")
index f1c8e7f1bdc3f72a00156c35acbdeff24a16e806..4de2e648259bd1712894c9f2e3b133d1ca76a72e 100644 (file)
@@ -699,6 +699,21 @@ TEST_F(FileSystemTest, CreateDir) {
     ThisDir = path::parent_path(ThisDir);
   }
 
+  // Also verify that paths with Unix separators are handled correctly.
+  std::string LongPathWithUnixSeparators(TestDirectory.str());
+  // Add at least one subdirectory to TestDirectory, and replace slashes with
+  // backslashes
+  do {
+    LongPathWithUnixSeparators.append("/DirNameWith19Charss");
+  } while (LongPathWithUnixSeparators.size() < 260);
+  std::replace(LongPathWithUnixSeparators.begin(),
+               LongPathWithUnixSeparators.end(),
+               '\\', '/');
+  ASSERT_NO_ERROR(fs::create_directories(Twine(LongPathWithUnixSeparators)));
+  // cleanup
+  ASSERT_NO_ERROR(fs::remove_directories(Twine(TestDirectory) +
+                                         "/DirNameWith19Charss"));
+
   // Similarly for a relative pathname.  Need to set the current directory to
   // TestDirectory so that the one we create ends up in the right place.
   char PreviousDir[260];