summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAaron Ballman <aaron@aaronballman.com>2013-06-19 21:03:50 +0000
committerAaron Ballman <aaron@aaronballman.com>2013-06-19 21:03:50 +0000
commit4655485eb7dc1d137595149b9bd58eb73e11bb19 (patch)
tree491409b3cdc3810bc088ef129469167e7c999d01
parent7032c883cdf8da579fbf9bf499d36a711eef676f (diff)
downloadllvm-4655485eb7dc1d137595149b9bd58eb73e11bb19.tar.gz
llvm-4655485eb7dc1d137595149b9bd58eb73e11bb19.tar.bz2
llvm-4655485eb7dc1d137595149b9bd58eb73e11bb19.tar.xz
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.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@184351 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--include/llvm/Support/FileSystem.h1
-rw-r--r--lib/Support/Windows/PathV2.inc23
-rw-r--r--unittests/Support/Path.cpp36
3 files changed, 51 insertions, 9 deletions
diff --git a/include/llvm/Support/FileSystem.h b/include/llvm/Support/FileSystem.h
index 21159dd264..9497e4de1d 100644
--- a/include/llvm/Support/FileSystem.h
+++ b/include/llvm/Support/FileSystem.h
@@ -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:
diff --git a/lib/Support/Windows/PathV2.inc b/lib/Support/Windows/PathV2.inc
index bec95e36cc..e6888f93e6 100644
--- a/lib/Support/Windows/PathV2.inc
+++ b/lib/Support/Windows/PathV2.inc
@@ -426,15 +426,20 @@ error_code file_size(const Twine &path, uint64_t &result) {
}
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();
}
diff --git a/unittests/Support/Path.cpp b/unittests/Support/Path.cpp
index 2f820b9181..4f9d146c46 100644
--- a/unittests/Support/Path.cpp
+++ b/unittests/Support/Path.cpp
@@ -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;