Merge remote-tracking branch 'aosp/upstream' into master

* aosp/upstream:
  Fail find parsing for \*

Bug: 73143444
Test: ckati_tests/find_test (part of build-prebuilts.sh now)
Test: Manually check failing find commands on AOSP
Change-Id: I18497e20bc8788cbe2a38845102537ab241d1d52
diff --git a/find.cc b/find.cc
index 1bf0b9e..a31adce 100644
--- a/find.cc
+++ b/find.cc
@@ -449,6 +449,16 @@
         return false;
       *tok = tok->substr(1, tok->size() - 2);
       return true;
+    } else {
+      // Support stripping off a leading backslash
+      if (c == '\\') {
+        *tok = tok->substr(1);
+      }
+      // But if there are any others, we can't support it, as unescaping would
+      // require allocation
+      if (tok->find("\\") != string::npos) {
+        return false;
+      }
     }
 
     return true;
@@ -473,18 +483,18 @@
   }
 
   FindCond* ParseFact(StringPiece tok) {
-    if (tok == "-not" || tok == "\\!") {
+    if (tok == "-not" || tok == "!") {
       if (!GetNextToken(&tok) || tok.empty())
         return NULL;
       unique_ptr<FindCond> c(ParseFact(tok));
       if (!c.get())
         return NULL;
       return new NotCond(c.release());
-    } else if (tok == "\\(") {
+    } else if (tok == "(") {
       if (!GetNextToken(&tok) || tok.empty())
         return NULL;
       unique_ptr<FindCond> c(ParseExpr(tok));
-      if (!GetNextToken(&tok) || tok != "\\)") {
+      if (!GetNextToken(&tok) || tok != ")") {
         return NULL;
       }
       return c.release();
@@ -530,7 +540,7 @@
         if (!GetNextToken(&tok) || tok.empty())
           return NULL;
       } else {
-        if (tok != "-not" && tok != "\\!" && tok != "\\(" && tok != "-name" &&
+        if (tok != "-not" && tok != "!" && tok != "(" && tok != "-name" &&
             tok != "-type") {
           UngetToken(tok);
           return c.release();
@@ -567,8 +577,8 @@
 
   // <expr> ::= <term> {<or> <term>}
   // <term> ::= <fact> {[<and>] <fact>}
-  // <fact> ::= <not> <fact> | '\(' <expr> '\)' | <pred>
-  // <not> ::= '-not' | '\!'
+  // <fact> ::= <not> <fact> | '(' <expr> ')' | <pred>
+  // <not> ::= '-not' | '!'
   // <and> ::= '-and' | '-a'
   // <or> ::= '-or' | '-o'
   // <pred> ::= <name> | <type> | <maxdepth>
@@ -609,7 +619,7 @@
           return false;
         }
         fc_->depth = d;
-      } else if (tok[0] == '-' || tok == "\\(") {
+      } else if (tok[0] == '-' || tok == "(" || tok == "!") {
         if (fc_->print_cond.get())
           return false;
         FindCond* c = ParseFindCond(tok);
diff --git a/find_test.cc b/find_test.cc
index 10f865c..d7d44bd 100644
--- a/find_test.cc
+++ b/find_test.cc
@@ -107,6 +107,17 @@
   }
 }
 
+void ExpectParseFailure(const string& cmd) {
+  Run(cmd);
+
+  FindCommand fc;
+  if (fc.Parse(cmd)) {
+    fprintf(stderr, "Expected parse failure for `%s`\n", cmd.c_str());
+    fprintf(stderr, "------------------------------------------\n");
+    unit_test_failed = true;
+  }
+}
+
 int FindUnitTests() {
   Run("rm -rf out/find");
   Run("mkdir -p out/find");
@@ -149,5 +160,11 @@
 
   CompareFind("find .//top");
 
+  CompareFind("find top -type f -name 'a*' -o -name \\*b");
+  CompareFind("find top \\! -name 'a*'");
+  CompareFind("find top \\( -name 'a*' \\)");
+
+  ExpectParseFailure("find top -name a\\*");
+
   return unit_test_failed ? 1 : 0;
 }