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