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 public void notifyExit(int value) {
213 try {
214 System.err.flush();
215 System.out.flush();
216 } catch (Throwable e) {
217 VM.sysWriteln("vm: error flushing stdout, stderr");
218 }
219 }
220 });
221 }
222 }
223
224