Skip to content

Commit

Permalink
Use TruffleFile in FilePlugin
Browse files Browse the repository at this point in the history
This avoids compilation errors as TruffleFiles have appropriate boundaries and adds support for Truffle's filesystem sandboxing
  • Loading branch information
fniephaus committed Jun 11, 2018
1 parent 1844574 commit 4da622b
Showing 1 changed file with 46 additions and 31 deletions.
Original file line number Diff line number Diff line change
@@ -1,15 +1,18 @@
package de.hpi.swa.graal.squeak.nodes.plugins;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.channels.SeekableByteChannel;
import java.nio.file.StandardOpenOption;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
import com.oracle.truffle.api.TruffleFile;
import com.oracle.truffle.api.dsl.GenerateNodeFactory;
import com.oracle.truffle.api.dsl.NodeFactory;
import com.oracle.truffle.api.dsl.Specialization;
Expand All @@ -27,7 +30,7 @@
import de.hpi.swa.graal.squeak.nodes.primitives.SqueakPrimitive;

public final class FilePlugin extends AbstractPrimitiveFactoryHolder {
@CompilationFinal private static final Map<Long, RandomAccessFile> files = new HashMap<>();
@CompilationFinal private static final Map<Long, SeekableByteChannel> files = new HashMap<>();

private static final class STDIO_HANDLES {
private static final long IN = 0;
Expand All @@ -41,8 +44,8 @@ public List<? extends NodeFactory<? extends AbstractPrimitiveNode>> getFactories
}

@TruffleBoundary
private static RandomAccessFile getFileOrPrimFail(final long fileDescriptor) {
final RandomAccessFile handle = files.get(fileDescriptor);
private static SeekableByteChannel getFileOrPrimFail(final long fileDescriptor) {
final SeekableByteChannel handle = files.get(fileDescriptor);
if (handle == null) {
throw new PrimitiveFailed();
}
Expand All @@ -65,6 +68,10 @@ protected final byte[] asBytes(final NativeObject obj) {
protected final String asString(final NativeObject obj) {
return new String(asBytes(obj));
}

protected final TruffleFile asTruffleFile(final NativeObject obj) {
return code.image.env.getTruffleFile(asString(obj));
}
}

@GenerateNodeFactory
Expand All @@ -77,11 +84,12 @@ protected PrimDirectoryCreateNode(final CompiledMethodObject method, final int n

@Specialization(guards = "fullPath.isByteType()")
protected final Object doCreate(final PointersObject receiver, final NativeObject fullPath) {
final File directory = new File(asString(fullPath));
if (directory.mkdir()) {
try {
asTruffleFile(fullPath).createDirectory();
return receiver;
} catch (IOException | UnsupportedOperationException | SecurityException e) {
throw new PrimitiveFailed();
}
throw new PrimitiveFailed();
}
}

Expand All @@ -95,11 +103,12 @@ protected PrimDirectoryDeleteNode(final CompiledMethodObject method, final int n

@Specialization(guards = "fullPath.isByteType()")
protected final Object doDelete(final PointersObject receiver, final NativeObject fullPath) {
final File directory = new File(asString(fullPath));
if (directory.delete()) {
try {
asTruffleFile(fullPath).delete();
return receiver;
} catch (IOException | UnsupportedOperationException | SecurityException e) {
throw new PrimitiveFailed();
}
throw new PrimitiveFailed();
}
}

Expand Down Expand Up @@ -186,8 +195,8 @@ protected PrimFileAtEndNode(final CompiledMethodObject method, final int numArgu
@Specialization
protected final Object doAtEnd(@SuppressWarnings("unused") final PointersObject receiver, final long fileDescriptor) {
try {
final RandomAccessFile file = getFileOrPrimFail(fileDescriptor);
return code.image.wrap(file.getFilePointer() >= file.length() - 1);
final SeekableByteChannel file = getFileOrPrimFail(fileDescriptor);
return code.image.wrap(file.position() >= file.size() - 1);
} catch (IOException e) {
throw new PrimitiveFailed();
}
Expand Down Expand Up @@ -256,7 +265,7 @@ protected PrimFileGetPositionNode(final CompiledMethodObject method, final int n
@Specialization
protected final Object doGet(@SuppressWarnings("unused") final PointersObject receiver, final long fileDescriptor) {
try {
return code.image.wrap(getFileOrPrimFail(fileDescriptor).getFilePointer());
return code.image.wrap(getFileOrPrimFail(fileDescriptor).position());
} catch (IOException e) {
throw new PrimitiveFailed();
}
Expand All @@ -274,14 +283,19 @@ protected PrimFileOpenNode(final CompiledMethodObject method, final int numArgum
@TruffleBoundary
@Specialization(guards = "nativeFileName.isByteType()")
protected final Object doOpen(@SuppressWarnings("unused") final PointersObject receiver, final NativeObject nativeFileName, final Boolean writableFlag) {
final String fileName = asString(nativeFileName);
final String mode = writableFlag ? "rw" : "r";
try {
final RandomAccessFile file = new RandomAccessFile(fileName, mode);
final EnumSet<StandardOpenOption> options;
final TruffleFile truffleFile = asTruffleFile(nativeFileName);
if (writableFlag) {
options = EnumSet.<StandardOpenOption> of(StandardOpenOption.WRITE, StandardOpenOption.READ, StandardOpenOption.CREATE);
} else {
options = EnumSet.<StandardOpenOption> of(StandardOpenOption.READ);
}
final SeekableByteChannel file = truffleFile.newByteChannel(options);
final long fileId = file.hashCode();
files.put(fileId, file);
return fileId;
} catch (FileNotFoundException e) {
} catch (IOException | UnsupportedOperationException | SecurityException e) {
throw new PrimitiveFailed();
}
}
Expand All @@ -300,11 +314,11 @@ protected PrimFileReadNode(final CompiledMethodObject method, final int numArgum
protected final Object doRead(@SuppressWarnings("unused") final PointersObject receiver, final long fileDescriptor, final AbstractSqueakObject target, final long startIndex,
final long longCount) {
final int count = (int) longCount;
final byte[] buffer = new byte[count];
final ByteBuffer dst = ByteBuffer.allocate(count);
try {
final long read = getFileOrPrimFail(fileDescriptor).read(buffer, 0, count);
final long read = getFileOrPrimFail(fileDescriptor).read(dst);
for (int index = 0; index < read; index++) {
atPut0Node.execute(target, startIndex - 1 + index, buffer[index] & 0xffL);
atPut0Node.execute(target, startIndex - 1 + index, dst.get(index) & 0xFFL);
}
return read;
} catch (IOException e) {
Expand All @@ -323,11 +337,12 @@ protected PrimFileRenameNode(final CompiledMethodObject method, final int numArg

@Specialization(guards = {"oldName.isByteType()", "newName.isByteType()"})
protected final Object doRename(final PointersObject receiver, final NativeObject oldName, final NativeObject newName) {
final File file = new File(asString(oldName));
if (file.renameTo(new File(asString(newName)))) {
return receiver;
try {
asTruffleFile(oldName).move(asTruffleFile(newName));
} catch (IOException e) {
throw new PrimitiveFailed();
}
throw new PrimitiveFailed();
return receiver;
}
}

Expand All @@ -342,8 +357,8 @@ protected PrimFileSetPositionNode(final CompiledMethodObject method, final int n
@Specialization
protected static final Object doSet(final PointersObject receiver, final long fileDescriptor, final long position) {
try {
getFileOrPrimFail(fileDescriptor).seek(position);
} catch (IOException e) {
getFileOrPrimFail(fileDescriptor).position(position);
} catch (IllegalArgumentException | IOException e) {
throw new PrimitiveFailed();
}
return receiver;
Expand All @@ -361,7 +376,7 @@ protected PrimFileSizeNode(final CompiledMethodObject method, final int numArgum
@Specialization
protected final Object doSize(@SuppressWarnings("unused") final PointersObject receiver, final long fileDescriptor) {
try {
return code.image.wrap(getFileOrPrimFail(fileDescriptor).length());
return code.image.wrap(getFileOrPrimFail(fileDescriptor).size());
} catch (IOException e) {
throw new PrimitiveFailed();
}
Expand Down Expand Up @@ -391,8 +406,8 @@ protected PrimFileTruncateNode(final CompiledMethodObject method, final int numA
@Specialization
protected static final Object doTruncate(final PointersObject receiver, final long fileDescriptor, final long to) {
try {
getFileOrPrimFail(fileDescriptor).setLength(to);
} catch (IOException e) {
getFileOrPrimFail(fileDescriptor).truncate(to);
} catch (IllegalArgumentException | IOException e) {
throw new PrimitiveFailed();
}
return receiver;
Expand Down Expand Up @@ -425,7 +440,7 @@ protected final long doWrite(final PointersObject receiver, final long fileDescr
doWrite(receiver, STDIO_HANDLES.ERROR, content, startIndex, count);
}
try {
getFileOrPrimFail(fileDescriptor).write(bytes);
getFileOrPrimFail(fileDescriptor).write(ByteBuffer.wrap(bytes));
} catch (IOException e) {
throw new PrimitiveFailed();
}
Expand Down

0 comments on commit 4da622b

Please sign in to comment.