From 62473627258b7b51bf23fcb22fcd1c1a97a60cb2 Mon Sep 17 00:00:00 2001 From: Ethan Atkins Date: Mon, 21 Sep 2020 10:58:36 -0700 Subject: [PATCH] Abort thin client on access denied exception There are situations in windows where it is possible that a client attempts to connect to a portfile that it did not have access to. This can happen if, for example, the server is started in administrator mode but the client is started as a regular user. When this happens, the client would try to remove the portfile and start a new server. This new server would not actually be able to start a server though becuase it would not be able to open the named point because the other server had it open. As a result, the client would just hang. The fix is to just abort the thin client if it gets an access denied exception. --- .../sbt/internal/client/NetworkClient.scala | 42 +++++++++++-------- 1 file changed, 25 insertions(+), 17 deletions(-) diff --git a/main-command/src/main/scala/sbt/internal/client/NetworkClient.scala b/main-command/src/main/scala/sbt/internal/client/NetworkClient.scala index b961aab5d..cb107dc04 100644 --- a/main-command/src/main/scala/sbt/internal/client/NetworkClient.scala +++ b/main-command/src/main/scala/sbt/internal/client/NetworkClient.scala @@ -181,8 +181,13 @@ class NetworkClient( catch { // This catches a pipe busy exception which can happen if two windows clients // attempt to connect in rapid succession - case e: IOException if e.getMessage.contains("Couldn't open") && attempt < 10 => None - case e: IOException => throw new ConnectionRefusedException(e) + case e: IOException if e.getMessage.contains("Couldn't open") && attempt < 10 => + if (e.getMessage.contains("Access is denied") || e.getMessage.contains("(5)")) { + errorStream.println(s"Access denied for portfile $portfile") + throw new NetworkClient.AccessDeniedException + } + None + case e: IOException => throw new ConnectionRefusedException(e) } res match { case Some(r) => r @@ -1093,7 +1098,7 @@ object NetworkClient { System.exit(Terminal.withStreams(false) { val term = Terminal.console try client(base, restOfArgs, term.inputStream, System.err, term, useJNI) - finally { + catch { case _: AccessDeniedException => 1 } finally { Runtime.getRuntime.removeShutdownHook(hook) hook.run() } @@ -1124,21 +1129,23 @@ object NetworkClient { val sbtArgs = args.takeWhile(!_.startsWith(NetworkClient.completions)) val arguments = NetworkClient.parseArgs(sbtArgs) val noTab = args.contains("--no-tab") - val client = - simpleClient( - arguments.withBaseDirectory(baseDirectory), - inputStream = in, - errorStream = errorStream, - printStream = errorStream, - useJNI = useJNI, - ) try { - val results = - if (client.connect(log = false, promptCompleteUsers = true)) client.getCompletions(cmd) - else Nil - out.println(results.sorted.distinct mkString "\n") - 0 - } catch { case _: Exception => 1 } finally client.close() + val client = + simpleClient( + arguments.withBaseDirectory(baseDirectory), + inputStream = in, + errorStream = errorStream, + printStream = errorStream, + useJNI = useJNI, + ) + try { + val results = + if (client.connect(log = false, promptCompleteUsers = true)) client.getCompletions(cmd) + else Nil + out.println(results.sorted.distinct mkString "\n") + 0 + } catch { case _: Exception => 1 } finally client.close() + } catch { case _: AccessDeniedException => 1 } } def run(configuration: xsbti.AppConfiguration, arguments: List[String]): Int = @@ -1153,4 +1160,5 @@ object NetworkClient { e.printStackTrace() 1 } + private class AccessDeniedException extends Throwable }