[llvm] r184351 - Modified the implementation of fs::GetUniqueID on Windows such that it actually finds a unique identifier for a file. Also adds unit tests for GetUniqueID.

Aaron Ballman aaron at aaronballman.com
Wed Jun 19 14:03:51 PDT 2013


Author: aaronballman
Date: Wed Jun 19 16:03:50 2013
New Revision: 184351

URL: http://llvm.org/viewvc/llvm-project?rev=184351&view=rev
Log:
Modified the implementation of fs::GetUniqueID on Windows such that it actually finds a unique identifier for a file.  Also adds unit tests for GetUniqueID.

Modified:
    llvm/trunk/include/llvm/Support/FileSystem.h
    llvm/trunk/lib/Support/Windows/PathV2.inc
    llvm/trunk/unittests/Support/Path.cpp

Modified: llvm/trunk/include/llvm/Support/FileSystem.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Support/FileSystem.h?rev=184351&r1=184350&r2=184351&view=diff
==============================================================================
--- llvm/trunk/include/llvm/Support/FileSystem.h (original)
+++ llvm/trunk/include/llvm/Support/FileSystem.h Wed Jun 19 16:03:50 2013
@@ -162,6 +162,7 @@ class file_status
   #endif
   friend bool equivalent(file_status A, file_status B);
   friend error_code status(const Twine &path, file_status &result);
+  friend error_code GetUniqueID(const Twine Path, uint64_t &Result);
   file_type Type;
   perms Perms;
 public:

Modified: llvm/trunk/lib/Support/Windows/PathV2.inc
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Support/Windows/PathV2.inc?rev=184351&r1=184350&r2=184351&view=diff
==============================================================================
--- llvm/trunk/lib/Support/Windows/PathV2.inc (original)
+++ llvm/trunk/lib/Support/Windows/PathV2.inc Wed Jun 19 16:03:50 2013
@@ -426,15 +426,20 @@ error_code file_size(const Twine &path,
 }
 
 error_code GetUniqueID(const Twine Path, uint64_t &Result) {
-  // FIXME: this is only unique if the file is accessed by the same file path.
-  // How do we do this for C:\dir\file and ..\dir\file ? Unix has inode
-  // numbers, but the concept doesn't exist in Windows.
-  SmallString<128> Storage;
-  StringRef P = Path.toStringRef(Storage);
-  uint64_t UniqueID = 0;
-  for (StringRef::iterator I = P.begin(), E = P.end(); I != E; ++I)
-    UniqueID += *I;
-  Result = UniqueID;
+  file_status Status;
+  if (error_code E = status(Path, Status))
+    return E;
+
+  // The file is uniquely identified by the volume serial number along
+  // with the 64-bit file identifier.
+  Result = (static_cast<uint64_t>(Status.FileIndexHigh) << 32ULL) |
+           static_cast<uint64_t>(Status.FileIndexLow);
+  
+  // Because the serial number is 32-bits, but we've already used up all 64
+  // bits for the file index, XOR the serial number into the high 32 bits of
+  // the resulting value.  We could potentially get collisons from this, but
+  // the likelihood is low.
+  Result ^= (static_cast<uint64_t>(Status.VolumeSerialNumber) << 32ULL);
 
   return error_code::success();
 }

Modified: llvm/trunk/unittests/Support/Path.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/Support/Path.cpp?rev=184351&r1=184350&r2=184351&view=diff
==============================================================================
--- llvm/trunk/unittests/Support/Path.cpp (original)
+++ llvm/trunk/unittests/Support/Path.cpp Wed Jun 19 16:03:50 2013
@@ -164,6 +164,42 @@ protected:
   }
 };
 
+TEST_F(FileSystemTest, Unique) {
+  // Create a temp file.
+  int FileDescriptor;
+  SmallString<64> TempPath;
+  ASSERT_NO_ERROR(
+    fs::unique_file("%%-%%-%%-%%.temp", FileDescriptor, TempPath));
+
+  // The same file should return an identical unique id.
+  uint64_t F1, F2;
+  ASSERT_NO_ERROR(fs::GetUniqueID(Twine(TempPath), F1));
+  ASSERT_NO_ERROR(fs::GetUniqueID(Twine(TempPath), F2));
+  ASSERT_EQ(F1, F2);
+
+  // Different files should return different unique ids.
+  int FileDescriptor2;
+  SmallString<64> TempPath2;
+  ASSERT_NO_ERROR(
+    fs::unique_file("%%-%%-%%-%%.temp", FileDescriptor2, TempPath2));
+  
+  uint64_t D;
+  ASSERT_NO_ERROR(fs::GetUniqueID(Twine(TempPath2), D));
+  ASSERT_NE(D, F1);
+  ::close(FileDescriptor2);
+
+  ASSERT_NO_ERROR(fs::remove(Twine(TempPath2)));
+
+  // Two paths representing the same file on disk should still provide the
+  // same unique id.  We can test this by making a hard link.
+  ASSERT_NO_ERROR(fs::create_hard_link(Twine(TempPath), Twine(TempPath2)));
+  uint64_t D2;
+  ASSERT_NO_ERROR(fs::GetUniqueID(Twine(TempPath2), D2));
+  ASSERT_EQ(D2, F1);
+
+  ::close(FileDescriptor);
+}
+
 TEST_F(FileSystemTest, TempFiles) {
   // Create a temp file.
   int FileDescriptor;





More information about the llvm-commits mailing list