001 /* 002 * This file is part of the Jikes RVM project (http://jikesrvm.org). 003 * 004 * This file is licensed to You under the Eclipse Public License (EPL); 005 * You may not use this file except in compliance with the License. You 006 * may obtain a copy of the License at 007 * 008 * http://www.opensource.org/licenses/eclipse-1.0.php 009 * 010 * See the COPYRIGHT.txt file distributed with this work for information 011 * regarding copyright ownership. 012 */ 013 package org.jikesrvm.runtime; 014 015 import java.io.BufferedInputStream; 016 import java.io.BufferedOutputStream; 017 import java.io.FileDescriptor; 018 import java.io.FileInputStream; 019 import java.io.FileOutputStream; 020 import java.io.PrintStream; 021 import org.jikesrvm.VM; 022 import org.jikesrvm.Callbacks; 023 import org.jikesrvm.scheduler.RVMThread; 024 import static org.jikesrvm.runtime.SysCall.sysCall; 025 import org.jikesrvm.util.StringUtilities; 026 import org.vmmagic.pragma.NoInline; 027 import org.vmmagic.pragma.NoOptCompile; 028 import org.vmmagic.pragma.BaselineSaveLSRegisters; 029 import org.vmmagic.pragma.Unpreemptible; 030 031 /** 032 * Interface to filesystem of underlying operating system. Historically 033 * this has provided a blocking IO abstraction on top of non-blocking IO, 034 * which was necessary for green threads. The current code contains only 035 * abstractions for dealing with things like file status. 036 */ 037 public class FileSystem { 038 039 // options for open() 040 public static final int OPEN_READ = 0; // open for read/only access 041 public static final int OPEN_WRITE = 1; // open for read/write access, create if doesn't already exist, 042 // truncate if already exists 043 public static final int OPEN_MODIFY = 2; // open for read/write access, create if doesn't already exist 044 public static final int OPEN_APPEND = 3; // open for read/write access, create if doesn't already exist, append writes 045 046 // options for seek() 047 public static final int SEEK_SET = 0; // set i/o position to start of file plus "offset" 048 public static final int SEEK_CUR = 1; // set i/o position to current position plus "offset" 049 public static final int SEEK_END = 2; // set i/o position to end of file plus "offset" 050 051 // options for stat() 052 public static final int STAT_EXISTS = 0; 053 public static final int STAT_IS_FILE = 1; 054 public static final int STAT_IS_DIRECTORY = 2; 055 public static final int STAT_IS_READABLE = 3; 056 public static final int STAT_IS_WRITABLE = 4; 057 public static final int STAT_LAST_MODIFIED = 5; 058 public static final int STAT_LENGTH = 6; 059 060 // options for access() 061 public static final int ACCESS_F_OK = 00; 062 public static final int ACCESS_R_OK = 04; 063 public static final int ACCESS_W_OK = 02; 064 public static final int ACCESS_X_OK = 01; 065 066 /** 067 * Get file status. 068 * @param fileName file name 069 * @param kind kind of info desired (one of STAT_XXX, above) 070 * @return desired info (-1 -> error) 071 * The boolean ones return 0 in case of non-true, 1 in case of 072 * true status. 073 */ 074 public static int stat(String fileName, int kind) { 075 // convert file name from unicode to filesystem character set 076 // (assume file name is ascii, for now) 077 byte[] asciiName = StringUtilities.stringToBytesNullTerminated(fileName); 078 int rc = sysCall.sysStat(asciiName, kind); 079 if (VM.TraceFileSystem) VM.sysWrite("FileSystem.stat: name=" + fileName + " kind=" + kind + " rc=" + rc + "\n"); 080 return rc; 081 } 082 083 /** 084 * Get user's perms for a file. 085 * @param fileName file name 086 * @param kind kind of access perm(s) to check for (ACCESS_W_OK,...) 087 * @return 0 if access ok (-1 -> error) 088 */ 089 public static int access(String fileName, int kind) { 090 // convert file name from unicode to filesystem character set 091 // (assume file name is ascii, for now) 092 byte[] asciiName = StringUtilities.stringToBytesNullTerminated(fileName); 093 094 int rc = sysCall.sysAccess(asciiName, kind); 095 096 if (VM.TraceFileSystem) { 097 VM.sysWrite("FileSystem.access: name=" + fileName + " kind=" + kind + " rc=" + rc + "\n"); 098 } 099 return rc; 100 } 101 102 /** 103 * Read single byte from file. 104 * 105 * @param fd file descriptor 106 * @return byte that was read (< -2: i/o error, -2: timeout, -1: eof, >= 0: data) 107 */ 108 @NoInline 109 @NoOptCompile 110 @BaselineSaveLSRegisters 111 @Unpreemptible 112 public static int readByte(int fd) { 113 RVMThread.saveThreadState(); 114 RVMThread.enterNative(); 115 int result=sysCall.sysReadByte(fd); 116 RVMThread.leaveNative(); 117 return result; 118 } 119 120 /** 121 * Write single byte to file 122 * 123 * @param fd file descriptor 124 * @param b byte to be written 125 * @return -2: i/o error, -1: timeout, 0: ok 126 */ 127 @NoInline 128 @NoOptCompile 129 @BaselineSaveLSRegisters 130 @Unpreemptible 131 public static int writeByte(int fd, int b) { 132 RVMThread.saveThreadState(); 133 RVMThread.enterNative(); 134 int result=sysCall.sysWriteByte(fd,b); 135 RVMThread.leaveNative(); 136 return result; 137 } 138 139 /** 140 * Read multiple bytes. 141 * 142 * @param buf a pinned byte array to read into 143 * @return -2: i/o error, -1: timeout, >=0: number of bytes read 144 */ 145 @NoInline 146 @NoOptCompile 147 @BaselineSaveLSRegisters 148 @Unpreemptible 149 public static int readBytes(int fd, byte[] buf, int off, int cnt) { 150 RVMThread.saveThreadState(); 151 RVMThread.enterNative(); 152 int result=sysCall.sysReadBytes(fd,Magic.objectAsAddress(buf).plus(off),cnt); 153 RVMThread.leaveNative(); 154 return result; 155 } 156 157 /** 158 * Write multiple bytes. 159 * 160 * @param buf a pinned byte array to write from 161 * @return -2: i/o error, -1: timeout, >=0: number of bytes written 162 */ 163 @NoInline 164 @NoOptCompile 165 @BaselineSaveLSRegisters 166 @Unpreemptible 167 public static int writeBytes(int fd, byte[] buf, int off, int cnt) { 168 RVMThread.saveThreadState(); 169 RVMThread.enterNative(); 170 int result=sysCall.sysWriteBytes(fd,Magic.objectAsAddress(buf).plus(off),cnt); 171 RVMThread.leaveNative(); 172 return result; 173 } 174 175 @NoInline 176 @NoOptCompile 177 @BaselineSaveLSRegisters 178 @Unpreemptible 179 public static boolean sync(int fd) { 180 RVMThread.saveThreadState(); 181 RVMThread.enterNative(); 182 boolean result=sysCall.sysSyncFile(fd) == 0; 183 RVMThread.leaveNative(); 184 return result; 185 } 186 187 @NoInline 188 @NoOptCompile 189 @BaselineSaveLSRegisters 190 @Unpreemptible 191 public static int bytesAvailable(int fd) { 192 RVMThread.saveThreadState(); 193 RVMThread.enterNative(); 194 int result=sysCall.sysBytesAvailable(fd); 195 RVMThread.leaveNative(); 196 return result; 197 } 198 199 // not sure if this is the right place to have this. 200 /** 201 * Called from VM.boot to set up java.lang.System.in, java.lang.System.out, 202 * and java.lang.System.err 203 */ 204 public static void initializeStandardStreams() { 205 FileInputStream fdIn = new FileInputStream(FileDescriptor.in); 206 FileOutputStream fdOut = new FileOutputStream(FileDescriptor.out); 207 FileOutputStream fdErr = new FileOutputStream(FileDescriptor.err); 208 System.setIn(new BufferedInputStream(fdIn)); 209 System.setOut(new PrintStream(new BufferedOutputStream(fdOut, 128), true)); 210 System.setErr(new PrintStream(new BufferedOutputStream(fdErr, 128), true)); 211 Callbacks.addExitMonitor(new Callbacks.ExitMonitor() { 212 @Override 213 public void notifyExit(int value) { 214 try { 215 System.err.flush(); 216 System.out.flush(); 217 } catch (Throwable e) { 218 VM.sysWriteln("vm: error flushing stdout, stderr"); 219 } 220 } 221 }); 222 } 223 } 224 225