From 28a3b2aeb48fac0391b328eb1822b3fefe228a05 Mon Sep 17 00:00:00 2001 From: Owen Reynolds Date: Wed, 16 Oct 2019 14:07:57 +0000 Subject: [PATCH] [llvm-ar] Make paths case insensitive when on windows When on windows gnu-ar treats member names as case insensitive. This commit implements the same behaviour. Differential Revision: https://reviews.llvm.org/D68033 llvm-svn: 375002 --- llvm/docs/CommandGuide/llvm-ar.rst | 6 ++++ llvm/test/tools/llvm-ar/Inputs/path-names.a | 8 +++++ llvm/test/tools/llvm-ar/non-windows-name-case.test | 27 ++++++++++++++++ llvm/test/tools/llvm-ar/path-names.test | 9 ++++++ llvm/test/tools/llvm-ar/windows-name-case.test | 29 +++++++++++++++++ llvm/tools/llvm-ar/llvm-ar.cpp | 37 +++++++++++++++++----- 6 files changed, 108 insertions(+), 8 deletions(-) create mode 100644 llvm/test/tools/llvm-ar/Inputs/path-names.a create mode 100644 llvm/test/tools/llvm-ar/non-windows-name-case.test create mode 100644 llvm/test/tools/llvm-ar/path-names.test create mode 100644 llvm/test/tools/llvm-ar/windows-name-case.test diff --git a/llvm/docs/CommandGuide/llvm-ar.rst b/llvm/docs/CommandGuide/llvm-ar.rst index 8067f7e..1073d96 100644 --- a/llvm/docs/CommandGuide/llvm-ar.rst +++ b/llvm/docs/CommandGuide/llvm-ar.rst @@ -35,6 +35,12 @@ Here's where **llvm-ar** departs from previous ``ar`` implementations: Currently **llvm-ar** can read GNU and BSD long file names, but only writes archives with the GNU format. + +*Windows Paths* + + When on Windows **llvm-ar** treats the names of archived *files* in the same + case sensitive manner as the operating system. When on a non-Windows machine + **llvm-ar** does not consider character case. OPTIONS ------- diff --git a/llvm/test/tools/llvm-ar/Inputs/path-names.a b/llvm/test/tools/llvm-ar/Inputs/path-names.a new file mode 100644 index 0000000..d739b0a --- /dev/null +++ b/llvm/test/tools/llvm-ar/Inputs/path-names.a @@ -0,0 +1,8 @@ +! +// 22 ` +a/foo.txt/ +b/foo.txt/ +/0 0 0 0 644 8 ` +hello-a +/11 0 0 0 644 8 ` +hello-b diff --git a/llvm/test/tools/llvm-ar/non-windows-name-case.test b/llvm/test/tools/llvm-ar/non-windows-name-case.test new file mode 100644 index 0000000..37c5302 --- /dev/null +++ b/llvm/test/tools/llvm-ar/non-windows-name-case.test @@ -0,0 +1,27 @@ +## Test that on windows, members are case insensitive. +# UNSUPPORTED: system-windows + +# RUN: mkdir -p %t +# RUN: rm -rf %t/lowerCase %t/UPPERCASE && mkdir %t/lowerCase %t/UPPERCASE +# RUN: echo lowerCase > %t/lowerCase/file.txt +# RUN: echo UPPERCASE > %t/UPPERCASE/FILE.TXT + +# RUN: rm -f %t/archive.a +# RUN: llvm-ar rc %t/archive.a %t/lowerCase/file.txt +# RUN: llvm-ar rc %t/archive.a %t/UPPERCASE/FILE.TXT +# RUN: FileCheck %s -input-file=%t/archive.a --check-prefix=ARCHIVE + +# ARCHIVE: file.txt +# ARCHIVE: FILE.TXT + +# RUN: rm -f %t/thin-archive.a +# RUN: llvm-ar Trc %t/thin-archive.a %t/lowerCase/file.txt %t/UPPERCASE/FILE.TXT +# RUN: llvm-ar dTP %t/thin-archive.a %t/uppercase/file.txt + +# RUN: FileCheck %s -input-file=%t/thin-archive.a --check-prefix=THIN-ARCHIVE -DPATH=%/t + +# RUN: llvm-ar dTP %t/thin-archive.a %t/LOWERCASE/FILE.TXT +# RUN: FileCheck %s -input-file=%t/thin-archive.a --check-prefix=THIN-ARCHIVE -DPATH=%/t + +# THIN-ARCHIVE: [[PATH]]/lowerCase/file.txt +# THIN-ARCHIVE: [[PATH]]/UPPERCASE/FILE.TXT diff --git a/llvm/test/tools/llvm-ar/path-names.test b/llvm/test/tools/llvm-ar/path-names.test new file mode 100644 index 0000000..eef6a69 --- /dev/null +++ b/llvm/test/tools/llvm-ar/path-names.test @@ -0,0 +1,9 @@ +RUN: llvm-ar t %S/Inputs/path-names.a | FileCheck %s --check-prefix=CONTENTS --implicit-check-not {{.}} +CONTENTS: a/foo.txt +CONTENTS-NEXT: b/foo.txt + +RUN: llvm-ar p %S/Inputs/path-names.a b/foo.txt | FileCheck %s --check-prefix=NO-FULL-PATH --implicit-check-not {{.}} +NO-FULL-PATH: hello-a + +RUN: llvm-ar Pp %S/Inputs/path-names.a b/foo.txt | FileCheck %s --check-prefix=FULL-PATH --implicit-check-not {{.}} +FULL-PATH: hello-b diff --git a/llvm/test/tools/llvm-ar/windows-name-case.test b/llvm/test/tools/llvm-ar/windows-name-case.test new file mode 100644 index 0000000..970a3e6 --- /dev/null +++ b/llvm/test/tools/llvm-ar/windows-name-case.test @@ -0,0 +1,29 @@ +## Test that on windows, members are case insensitive. +# REQUIRES: system-windows + +# RUN: mkdir -p %t +# RUN: rm -rf %t/lowerCase %t/UPPERCASE && mkdir %t/lowerCase %t/UPPERCASE +# RUN: echo lowerCase > %t/lowerCase/file.txt +# RUN: echo UPPERCASE > %t/UPPERCASE/FILE.TXT + +# RUN: rm -f %t/archive.a +# RUN: llvm-ar rc %t/archive.a %t/lowerCase/file.txt +# RUN: FileCheck %s -input-file=%t/archive.a --check-prefix=LOWER --implicit-check-not=FILE.TXT +# RUN: llvm-ar rc %t/archive.a %t/UPPERCASE/FILE.TXT +# RUN: FileCheck %s -input-file=%t/archive.a --check-prefix=UPPER --implicit-check-not=file.txt + +# LOWER: file.txt +# UPPER: FILE.TXT + +# RUN: rm -f %t/thin-archive.a +# RUN: llvm-ar Trc %t/thin-archive.a %t/lowerCase/file.txt %t/UPPERCASE/FILE.txt +# RUN: llvm-ar dTP %t/thin-archive.a %t/uppercase/file.txt + +# RUN: FileCheck %s -input-file=%t/thin-archive.a --check-prefix=THIN-ARCHIVE -DPATH=%/t +# THIN-ARCHIVE-NOT: [[PATH]]/UPPERCASE/FILE.TXT +# THIN-ARCHIVE: [[PATH]]/lowerCase/file.txt + +# RUN: llvm-ar dTP %t/thin-archive.a %t/LOWERCASE/FILE.TXT +# RUN: FileCheck %s -input-file=%t/thin-archive.a --check-prefix=EMPTY --implicit-check-not {{.}} + +EMPTY: ! diff --git a/llvm/tools/llvm-ar/llvm-ar.cpp b/llvm/tools/llvm-ar/llvm-ar.cpp index 4eb50a1..67f70e97 100644 --- a/llvm/tools/llvm-ar/llvm-ar.cpp +++ b/llvm/tools/llvm-ar/llvm-ar.cpp @@ -43,6 +43,11 @@ #include #endif +#ifdef _WIN32 +#define WIN32_LEAN_AND_MEAN +#include +#endif + using namespace llvm; // The name this program was invoked as. @@ -488,6 +493,23 @@ static std::string normalizePath(StringRef Path) { : std::string(sys::path::filename(Path)); } +static bool comparePaths(StringRef Path1, StringRef Path2) { +// When on Windows this function calls CompareStringOrdinal +// as Windows file paths are case-insensitive. +// CompareStringOrdinal compares two Unicode strings for +// binary equivalence and allows for case insensitivity. +#ifdef _WIN32 + SmallVector WPath1, WPath2; + failIfError(sys::path::widenPath(normalizePath(Path1), WPath1)); + failIfError(sys::path::widenPath(normalizePath(Path2), WPath2)); + + return CompareStringOrdinal(WPath1.data(), WPath1.size(), WPath2.data(), + WPath2.size(), true) == CSTR_EQUAL; +#else + return normalizePath(Path1) == normalizePath(Path2); +#endif +} + // Implement the 'x' operation. This function extracts files back to the file // system. static void doExtract(StringRef Name, const object::Archive::Child &C) { @@ -561,7 +583,7 @@ static void performReadOperation(ArchiveOperation Operation, if (Filter) { auto I = find_if(Members, [Name](StringRef Path) { - return Name == normalizePath(Path); + return comparePaths(Name, Path); }); if (I == Members.end()) continue; @@ -691,7 +713,7 @@ static InsertAction computeInsertAction(ArchiveOperation Operation, if (Operation == QuickAppend || Members.empty()) return IA_AddOldMember; auto MI = find_if( - Members, [Name](StringRef Path) { return Name == normalizePath(Path); }); + Members, [Name](StringRef Path) { return comparePaths(Name, Path); }); if (MI == Members.end()) return IA_AddOldMember; @@ -742,15 +764,14 @@ computeNewArchiveMembers(ArchiveOperation Operation, std::vector Moved; int InsertPos = -1; if (OldArchive) { - std::string PosName = normalizePath(RelPos); Error Err = Error::success(); StringMap MemberCount; for (auto &Child : OldArchive->children(Err)) { int Pos = Ret.size(); Expected NameOrErr = Child.getName(); failIfError(NameOrErr.takeError()); - StringRef Name = NameOrErr.get(); - if (Name == PosName) { + std::string Name = NameOrErr.get(); + if (comparePaths(Name, RelPos)) { assert(AddAfter || AddBefore); if (AddBefore) InsertPos = Pos; @@ -1018,9 +1039,9 @@ static void runMRIScript() { ArchiveName = Rest; break; case MRICommand::Delete: { - std::string Name = normalizePath(Rest); - llvm::erase_if(NewMembers, - [=](NewArchiveMember &M) { return M.MemberName == Name; }); + llvm::erase_if(NewMembers, [=](NewArchiveMember &M) { + return comparePaths(M.MemberName, Rest); + }); break; } case MRICommand::Save: -- 2.7.4