mgorny created this revision.
mgorny added reviewers: labath, emaste, krytarowski, jasonmolenda, JDevlieghere.
mgorny requested review of this revision.

Add two new commands 'platform get-file-permissions' and 'platform
file-exists' for the respective bits of LLDB protocol.  Add tests for
them.  Fix error handling in GetFilePermissions().


https://reviews.llvm.org/D107809

Files:
  lldb/source/Commands/CommandObjectPlatform.cpp
  lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp
  lldb/test/API/functionalities/gdb_remote_client/TestGDBRemotePlatformFile.py

Index: lldb/test/API/functionalities/gdb_remote_client/TestGDBRemotePlatformFile.py
===================================================================
--- lldb/test/API/functionalities/gdb_remote_client/TestGDBRemotePlatformFile.py
+++ lldb/test/API/functionalities/gdb_remote_client/TestGDBRemotePlatformFile.py
@@ -132,3 +132,72 @@
                 ])
         finally:
             self.dbg.GetSelectedPlatform().DisconnectRemote()
+
+    def test_file_permissions(self):
+        """Test 'platform get-permissions'"""
+
+        class Responder(MockGDBServerResponder):
+            def vFile(self, packet):
+                return "F1a4"
+
+        self.server.responder = Responder()
+
+        try:
+            self.runCmd("platform select remote-gdb-server")
+            self.runCmd("platform connect connect://" +
+                        self.server.get_connect_address())
+            self.assertTrue(self.dbg.GetSelectedPlatform().IsConnected())
+
+            self.match("platform get-permissions /some/file.txt",
+                       [r"File permissions of /some/file\.txt \(remote\): 0o0644"])
+            self.assertPacketLogContains([
+                "vFile:mode:2f736f6d652f66696c652e747874",
+                ])
+        finally:
+            self.dbg.GetSelectedPlatform().DisconnectRemote()
+
+    def test_file_exists(self):
+        """Test 'platform file-exists'"""
+
+        class Responder(MockGDBServerResponder):
+            def vFile(self, packet):
+                return "F,1"
+
+        self.server.responder = Responder()
+
+        try:
+            self.runCmd("platform select remote-gdb-server")
+            self.runCmd("platform connect connect://" +
+                        self.server.get_connect_address())
+            self.assertTrue(self.dbg.GetSelectedPlatform().IsConnected())
+
+            self.match("platform file-exists /some/file.txt",
+                       [r"File /some/file\.txt \(remote\) exists"])
+            self.assertPacketLogContains([
+                "vFile:exists:2f736f6d652f66696c652e747874",
+                ])
+        finally:
+            self.dbg.GetSelectedPlatform().DisconnectRemote()
+
+    def test_file_exists(self):
+        """Test 'platform file-exists' with non-existing file"""
+
+        class Responder(MockGDBServerResponder):
+            def vFile(self, packet):
+                return "F,0"
+
+        self.server.responder = Responder()
+
+        try:
+            self.runCmd("platform select remote-gdb-server")
+            self.runCmd("platform connect connect://" +
+                        self.server.get_connect_address())
+            self.assertTrue(self.dbg.GetSelectedPlatform().IsConnected())
+
+            self.match("platform file-exists /some/file.txt",
+                       [r"File /some/file\.txt \(remote\) does not exist"])
+            self.assertPacketLogContains([
+                "vFile:exists:2f736f6d652f66696c652e747874",
+                ])
+        finally:
+            self.dbg.GetSelectedPlatform().DisconnectRemote()
Index: lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp
===================================================================
--- lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp
+++ lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp
@@ -658,9 +658,10 @@
     std::error_code ec;
     const uint32_t mode = FileSystem::Instance().GetPermissions(file_spec, ec);
     StreamString response;
-    response.Printf("F%x", mode);
-    if (mode == 0 || ec)
-      response.Printf(",%x", (int)Status(ec).GetError());
+    if (mode != llvm::sys::fs::perms_not_known)
+      response.Printf("F%x", mode);
+    else
+      response.Printf("F-1,%x", (int)Status(ec).GetError());
     return SendPacketNoLock(response.GetString());
   }
   return SendErrorResponse(23);
Index: lldb/source/Commands/CommandObjectPlatform.cpp
===================================================================
--- lldb/source/Commands/CommandObjectPlatform.cpp
+++ lldb/source/Commands/CommandObjectPlatform.cpp
@@ -926,6 +926,141 @@
   }
 };
 
+// "platform get-permissions remote-file-path"
+class CommandObjectPlatformGetPermissions : public CommandObjectParsed {
+public:
+  CommandObjectPlatformGetPermissions(CommandInterpreter &interpreter)
+      : CommandObjectParsed(interpreter, "platform get-permissions",
+                            "Get the file permission bits from the remote end.",
+                            "platform get-permissions <remote-file-spec>", 0) {
+    SetHelpLong(
+        R"(Examples:
+
+(lldb) platform get-permissions /the/remote/file/path
+
+    Get the file permissions from the remote end with path /the/remote/file/path.)");
+
+    CommandArgumentEntry arg1;
+    CommandArgumentData file_arg_remote;
+
+    // Define the first (and only) variant of this arg.
+    file_arg_remote.arg_type = eArgTypeFilename;
+    file_arg_remote.arg_repetition = eArgRepeatPlain;
+    // There is only one variant this argument could be; put it into the
+    // argument entry.
+    arg1.push_back(file_arg_remote);
+
+    // Push the data for the first argument into the m_arguments vector.
+    m_arguments.push_back(arg1);
+  }
+
+  ~CommandObjectPlatformGetPermissions() override = default;
+
+  void
+  HandleArgumentCompletion(CompletionRequest &request,
+                           OptionElementVector &opt_element_vector) override {
+    if (request.GetCursorIndex() != 0)
+      return;
+
+    CommandCompletions::InvokeCommonCompletionCallbacks(
+        GetCommandInterpreter(), CommandCompletions::eRemoteDiskFileCompletion,
+        request, nullptr);
+  }
+
+  bool DoExecute(Args &args, CommandReturnObject &result) override {
+    // If the number of arguments is incorrect, issue an error message.
+    if (args.GetArgumentCount() != 1) {
+      result.AppendError("required argument missing; specify the source file "
+                         "path as the only argument");
+      return false;
+    }
+
+    PlatformSP platform_sp(
+        GetDebugger().GetPlatformList().GetSelectedPlatform());
+    if (platform_sp) {
+      std::string remote_file_path(args.GetArgumentAtIndex(0));
+      uint32_t permissions;
+      Status error = platform_sp->GetFilePermissions(FileSpec(remote_file_path),
+                                                     permissions);
+      if (error.Success()) {
+        result.AppendMessageWithFormat(
+            "File permissions of %s (remote): 0o%04" PRIo32 "\n",
+            remote_file_path.c_str(), permissions);
+        result.SetStatus(eReturnStatusSuccessFinishResult);
+      } else
+        result.AppendError(error.AsCString());
+    } else {
+      result.AppendError("no platform currently selected\n");
+    }
+    return result.Succeeded();
+  }
+};
+
+// "platform file-exists remote-file-path"
+class CommandObjectPlatformFileExists : public CommandObjectParsed {
+public:
+  CommandObjectPlatformFileExists(CommandInterpreter &interpreter)
+      : CommandObjectParsed(interpreter, "platform file-exists",
+                            "Check if the file exists on the remote end.",
+                            "platform file-exists <remote-file-spec>", 0) {
+    SetHelpLong(
+        R"(Examples:
+
+(lldb) platform file-exists /the/remote/file/path
+
+    Check if /the/remote/file/path exists on the remote end.)");
+
+    CommandArgumentEntry arg1;
+    CommandArgumentData file_arg_remote;
+
+    // Define the first (and only) variant of this arg.
+    file_arg_remote.arg_type = eArgTypeFilename;
+    file_arg_remote.arg_repetition = eArgRepeatPlain;
+    // There is only one variant this argument could be; put it into the
+    // argument entry.
+    arg1.push_back(file_arg_remote);
+
+    // Push the data for the first argument into the m_arguments vector.
+    m_arguments.push_back(arg1);
+  }
+
+  ~CommandObjectPlatformFileExists() override = default;
+
+  void
+  HandleArgumentCompletion(CompletionRequest &request,
+                           OptionElementVector &opt_element_vector) override {
+    if (request.GetCursorIndex() != 0)
+      return;
+
+    CommandCompletions::InvokeCommonCompletionCallbacks(
+        GetCommandInterpreter(), CommandCompletions::eRemoteDiskFileCompletion,
+        request, nullptr);
+  }
+
+  bool DoExecute(Args &args, CommandReturnObject &result) override {
+    // If the number of arguments is incorrect, issue an error message.
+    if (args.GetArgumentCount() != 1) {
+      result.AppendError("required argument missing; specify the source file "
+                         "path as the only argument");
+      return false;
+    }
+
+    PlatformSP platform_sp(
+        GetDebugger().GetPlatformList().GetSelectedPlatform());
+    if (platform_sp) {
+      std::string remote_file_path(args.GetArgumentAtIndex(0));
+      bool exists = platform_sp->GetFileExists(FileSpec(remote_file_path));
+      result.AppendMessageWithFormat(
+          "File %s (remote) %s\n",
+          remote_file_path.c_str(), exists ? "exists" : "does not exist");
+      result.SetStatus(eReturnStatusSuccessFinishResult);
+    } else {
+      result.AppendError("no platform currently selected\n");
+    }
+    return result.Succeeded();
+  }
+};
+
 // "platform put-file"
 class CommandObjectPlatformPutFile : public CommandObjectParsed {
 public:
@@ -1759,8 +1894,12 @@
                  CommandObjectSP(new CommandObjectPlatformMkDir(interpreter)));
   LoadSubCommand("file",
                  CommandObjectSP(new CommandObjectPlatformFile(interpreter)));
+  LoadSubCommand("file-exists",
+      CommandObjectSP(new CommandObjectPlatformFileExists(interpreter)));
   LoadSubCommand("get-file", CommandObjectSP(new CommandObjectPlatformGetFile(
                                  interpreter)));
+  LoadSubCommand("get-permissions",
+      CommandObjectSP(new CommandObjectPlatformGetPermissions(interpreter)));
   LoadSubCommand("get-size", CommandObjectSP(new CommandObjectPlatformGetSize(
                                  interpreter)));
   LoadSubCommand("put-file", CommandObjectSP(new CommandObjectPlatformPutFile(
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to