/*
* This file is part of the Jikes RVM project (http://jikesrvm.org).
*
* This file is licensed to You under the Eclipse Public License (EPL);
* You may not use this file except in compliance with the License. You
* may obtain a copy of the License at
*
* http://www.opensource.org/licenses/eclipse-1.0.php
*
* See the COPYRIGHT.txt file distributed with this work for information
* regarding copyright ownership.
*/
package org.jikesrvm.runtime;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileDescriptor;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.PrintStream;
import org.jikesrvm.VM;
import org.jikesrvm.Callbacks;
import org.jikesrvm.scheduler.RVMThread;
import static org.jikesrvm.runtime.SysCall.sysCall;
import org.jikesrvm.util.StringUtilities;
import org.vmmagic.pragma.NoInline;
import org.vmmagic.pragma.NoOptCompile;
import org.vmmagic.pragma.BaselineSaveLSRegisters;
import org.vmmagic.pragma.Unpreemptible;
/**
* Interface to filesystem of underlying operating system. Historically
* this has provided a blocking IO abstraction on top of non-blocking IO,
* which was necessary for green threads. The current code contains only
* abstractions for dealing with things like file status.
*/
public class FileSystem {
// options for open()
public static final int OPEN_READ = 0; // open for read/only access
public static final int OPEN_WRITE = 1; // open for read/write access, create if doesn't already exist,
// truncate if already exists
public static final int OPEN_MODIFY = 2; // open for read/write access, create if doesn't already exist
public static final int OPEN_APPEND = 3; // open for read/write access, create if doesn't already exist, append writes
// options for seek()
public static final int SEEK_SET = 0; // set i/o position to start of file plus "offset"
public static final int SEEK_CUR = 1; // set i/o position to current position plus "offset"
public static final int SEEK_END = 2; // set i/o position to end of file plus "offset"
// options for stat()
public static final int STAT_EXISTS = 0;
public static final int STAT_IS_FILE = 1;
public static final int STAT_IS_DIRECTORY = 2;
public static final int STAT_IS_READABLE = 3;
public static final int STAT_IS_WRITABLE = 4;
public static final int STAT_LAST_MODIFIED = 5;
public static final int STAT_LENGTH = 6;
// options for access()
public static final int ACCESS_F_OK = 00;
public static final int ACCESS_R_OK = 04;
public static final int ACCESS_W_OK = 02;
public static final int ACCESS_X_OK = 01;
/**
* Get file status.
* @param fileName file name
* @param kind kind of info desired (one of STAT_XXX, above)
* @return desired info (-1 -> error)
* The boolean ones return 0 in case of non-true, 1 in case of
* true status.
*/
public static int stat(String fileName, int kind) {
// convert file name from unicode to filesystem character set
// (assume file name is ascii, for now)
byte[] asciiName = StringUtilities.stringToBytesNullTerminated(fileName);
int rc = sysCall.sysStat(asciiName, kind);
if (VM.TraceFileSystem) VM.sysWrite("FileSystem.stat: name=" + fileName + " kind=" + kind + " rc=" + rc + "\n");
return rc;
}
/**
* Get user's perms for a file.
* @param fileName file name
* @param kind kind of access perm(s) to check for (ACCESS_W_OK,...)
* @return 0 if access ok (-1 -> error)
*/
public static int access(String fileName, int kind) {
// convert file name from unicode to filesystem character set
// (assume file name is ascii, for now)
byte[] asciiName = StringUtilities.stringToBytesNullTerminated(fileName);
int rc = sysCall.sysAccess(asciiName, kind);
if (VM.TraceFileSystem) {
VM.sysWrite("FileSystem.access: name=" + fileName + " kind=" + kind + " rc=" + rc + "\n");
}
return rc;
}
/**
* Read single byte from file.
*
* @param fd file descriptor
* @return byte that was read (< -2: i/o error, -2: timeout, -1: eof, >= 0: data)
*/
@NoInline
@NoOptCompile
@BaselineSaveLSRegisters
@Unpreemptible
public static int readByte(int fd) {
RVMThread.saveThreadState();
RVMThread.enterNative();
int result=sysCall.sysReadByte(fd);
RVMThread.leaveNative();
return result;
}
/**
* Write single byte to file
*
* @param fd file descriptor
* @param b byte to be written
* @return -2: i/o error, -1: timeout, 0: ok
*/
@NoInline
@NoOptCompile
@BaselineSaveLSRegisters
@Unpreemptible
public static int writeByte(int fd, int b) {
RVMThread.saveThreadState();
RVMThread.enterNative();
int result=sysCall.sysWriteByte(fd,b);
RVMThread.leaveNative();
return result;
}
/**
* Read multiple bytes.
*
* @param buf a pinned byte array to read into
* @return -2: i/o error, -1: timeout, >=0: number of bytes read
*/
@NoInline
@NoOptCompile
@BaselineSaveLSRegisters
@Unpreemptible
public static int readBytes(int fd, byte[] buf, int off, int cnt) {
RVMThread.saveThreadState();
RVMThread.enterNative();
int result=sysCall.sysReadBytes(fd,Magic.objectAsAddress(buf).plus(off),cnt);
RVMThread.leaveNative();
return result;
}
/**
* Write multiple bytes.
*
* @param buf a pinned byte array to write from
* @return -2: i/o error, -1: timeout, >=0: number of bytes written
*/
@NoInline
@NoOptCompile
@BaselineSaveLSRegisters
@Unpreemptible
public static int writeBytes(int fd, byte[] buf, int off, int cnt) {
RVMThread.saveThreadState();
RVMThread.enterNative();
int result=sysCall.sysWriteBytes(fd,Magic.objectAsAddress(buf).plus(off),cnt);
RVMThread.leaveNative();
return result;
}
@NoInline
@NoOptCompile
@BaselineSaveLSRegisters
@Unpreemptible
public static boolean sync(int fd) {
RVMThread.saveThreadState();
RVMThread.enterNative();
boolean result=sysCall.sysSyncFile(fd) == 0;
RVMThread.leaveNative();
return result;
}
@NoInline
@NoOptCompile
@BaselineSaveLSRegisters
@Unpreemptible
public static int bytesAvailable(int fd) {
RVMThread.saveThreadState();
RVMThread.enterNative();
int result=sysCall.sysBytesAvailable(fd);
RVMThread.leaveNative();
return result;
}
// not sure if this is the right place to have this.
/**
* Called from VM.boot to set up java.lang.System.in, java.lang.System.out,
* and java.lang.System.err
*/
public static void initializeStandardStreams() {
FileInputStream fdIn = new FileInputStream(FileDescriptor.in);
FileOutputStream fdOut = new FileOutputStream(FileDescriptor.out);
FileOutputStream fdErr = new FileOutputStream(FileDescriptor.err);
System.setIn(new BufferedInputStream(fdIn));
System.setOut(new PrintStream(new BufferedOutputStream(fdOut, 128), true));
System.setErr(new PrintStream(new BufferedOutputStream(fdErr, 128), true));
Callbacks.addExitMonitor(new Callbacks.ExitMonitor() {
public void notifyExit(int value) {
try {
System.err.flush();
System.out.flush();
} catch (Throwable e) {
VM.sysWriteln("vm: error flushing stdout, stderr");
}
}
});
}
}