Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rethrow permissions error when opening source file #22639

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 1 addition & 7 deletions compiler/src/dotty/tools/dotc/util/SourceFile.scala
Original file line number Diff line number Diff line change
Expand Up @@ -275,13 +275,7 @@ object SourceFile {
ScriptSourceFile.hasScriptHeader(content)

def apply(file: AbstractFile | Null, codec: Codec): SourceFile =
// Files.exists is slow on Java 8 (https://rules.sonarsource.com/java/tag/performance/RSPEC-3725),
// so cope with failure.
val chars =
try new String(file.toByteArray, codec.charSet).toCharArray
catch
case _: FileSystemException => Array.empty[Char]

val chars = file.toCharArray(using codec.charSet)
if isScript(file, chars) then
ScriptSourceFile(file, chars)
else
Expand Down
24 changes: 15 additions & 9 deletions compiler/src/dotty/tools/io/AbstractFile.scala
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,14 @@
package dotty.tools.io

import scala.language.unsafeNulls
import scala.io.Codec

import java.io.{
IOException, InputStream, OutputStream, BufferedOutputStream,
ByteArrayOutputStream
}
import java.net.URL
import java.nio.file.{FileAlreadyExistsException, Files, Paths}
import java.nio.file.{AccessDeniedException, FileAlreadyExistsException, FileSystemException, Files, Paths}

/**
* An abstraction over files for use in the reflection/compiler libraries.
Expand Down Expand Up @@ -112,7 +113,7 @@ abstract class AbstractFile extends Iterable[AbstractFile] {
def absolute: AbstractFile

/** Returns the containing directory of this abstract file */
def container : AbstractFile
def container: AbstractFile

/** Returns the underlying File if any and null otherwise. */
def file: JFile = try {
Expand Down Expand Up @@ -159,18 +160,23 @@ abstract class AbstractFile extends Iterable[AbstractFile] {

def toURL: URL = if (jpath == null) null else jpath.toUri.toURL

/** Returns contents of file (if applicable) in a Char array.
* warning: use `Global.getSourceFile()` to use the proper
* encoding when converting to the char array.
/** Returns contents of `input` in a Char array.
*/
@throws(classOf[IOException])
def toCharArray: Array[Char] = new String(toByteArray).toCharArray
def toCharArray(using codec: Codec): Array[Char] = new String(toByteArray, codec.charSet).toCharArray

/** Returns contents of file (if applicable) in a byte array.
/** Returns contents of `input` in a Byte array.
*
* Files.exists is slow on Java 8 (https://rules.sonarsource.com/java/tag/performance/RSPEC-3725),
* so cope with failure by defaulting to empty array. Rethrow `AccessDeniedException` as helpful.
* See #14664 for limits on probing for other conditions such as path prefix is existing regular file.
*/
@throws(classOf[IOException])
def toByteArray: Array[Byte] = {
val in = input
val in =
try input catch
case e: AccessDeniedException => throw e
case _: FileSystemException => return Array.empty[Byte]
sizeOption match {
case Some(size) =>
var rest = size
Expand All @@ -186,7 +192,7 @@ abstract class AbstractFile extends Iterable[AbstractFile] {
case None =>
val out = new ByteArrayOutputStream()
var c = in.read()
while(c != -1) {
while (c != -1) {
out.write(c)
c = in.read()
}
Expand Down
33 changes: 28 additions & 5 deletions compiler/test/dotty/tools/io/AbstractFileTest.scala
Original file line number Diff line number Diff line change
@@ -1,14 +1,22 @@
package dotty.tools.io
package dotty.tools
package io

import scala.language.unsafeNulls

import org.junit.Test
import org.junit.Assert.assertTrue

import dotty.tools.io.AbstractFile
import java.nio.file.Files._
import java.nio.file.AccessDeniedException
import java.nio.file.Files.*
import java.nio.file.attribute.PosixFilePermissions

class AbstractFileTest {
import Directory.inTempDirectory

def permitted(rwx: String = "rwxrwxrwx") =
val permissions = PosixFilePermissions.fromString(rwx)
PosixFilePermissions.asFileAttribute(permissions)

//
// Cope with symbolic links. Exercised by -d output.
//
Expand Down Expand Up @@ -43,8 +51,23 @@ class AbstractFileTest {
assert(dir.subdirectoryNamed("link").exists)
}
@Test def t6450(): Unit =
try Directory.inTempDirectory(exerciseSymbolicLinks)
catch { case _: UnsupportedOperationException => () }
try inTempDirectory(exerciseSymbolicLinks)
catch case _: UnsupportedOperationException => ()

@Test def i14664 = inTempDirectory: d =>
val f = createTempFile(d.jpath, "i14664", "test", permitted("-w--w--w-"))
val p = PlainFile(d / Path(f))
assertThrows[AccessDeniedException](_ => true):
p.toCharArray

@Test def `i14664 ENOENT` = inTempDirectory: d =>
val p = PlainFile(d / "random")
assertTrue(p.toCharArray.isEmpty) // would be NoSuchFileException

@Test def `i14664 ENOTDIR` = inTempDirectory: d =>
val f = createTempFile(d.jpath, "i14664", "test", permitted())
val p = PlainFile(d / Path(f) / "random")
assertTrue(p.toCharArray.isEmpty) // would be FileSystemException
}

/* Was:
Expand Down
Loading