2 * Copyright (C) 2014, United States Government, as represented by the
3 * Administrator of the National Aeronautics and Space Administration.
6 * The Java Pathfinder core (jpf-core) platform is licensed under the
7 * Apache License, Version 2.0 (the "License"); you may not use this file except
8 * in compliance with the License. You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0.
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
19 package gov.nasa.jpf.vm;
21 import gov.nasa.jpf.Config;
22 import gov.nasa.jpf.JPF;
23 import gov.nasa.jpf.annotation.MJI;
24 import gov.nasa.jpf.util.DynamicObjectArray;
25 import gov.nasa.jpf.util.JPFLogger;
26 import gov.nasa.jpf.vm.MJIEnv;
27 import gov.nasa.jpf.vm.NativePeer;
30 import java.io.FileInputStream;
31 import java.io.FileOutputStream;
32 import java.io.IOException;
33 import java.nio.channels.FileChannel;
36 * native peer for file descriptors, which are our basic interface to
37 * access file contents. The implementation used here just forwards
38 * to FileInputStreams, which is terribly inefficient for frequent
39 * restores (in which case a simple byte[] buffer would be more efficient)
41 public class JPF_java_io_FileDescriptor extends NativePeer {
43 static JPFLogger logger = JPF.getLogger("java.io.FileDescriptor");
46 // NOTE: keep those in sync with the model class
47 static final int FD_READ = 0;
48 static final int FD_WRITE = 1;
50 static final int FD_NEW = 0;
51 static final int FD_OPENED = 1;
52 static final int FD_CLOSED = 2;
55 int count=2; // count out std handles
56 DynamicObjectArray<Object> content;
58 public JPF_java_io_FileDescriptor (Config conf){
59 content = new DynamicObjectArray<Object>();
64 public int open__Ljava_lang_String_2I__I (MJIEnv env, int objref,
65 int fnameRef, int mode){
66 String fname = env.getStringObject(fnameRef);
68 return openRead(fname);
69 } else if (mode == FD_WRITE){
70 return openWrite(fname);
72 env.throwException("java.io.IOException", "illegal open mode: " + mode);
78 public int openRead (String fname) {
79 File file = new File(fname);
82 FileInputStream fis = new FileInputStream(file);
83 fis.getChannel(); // just to allocate one
86 content.set(count, fis);
88 logger.info("opening ", fname, " (read) => ", count);
92 } catch (IOException x) {
93 logger.warning("failed to open ", fname, " (read) : ", x);
96 logger.info("cannot open ", fname, " (read) : file not found");
103 public int openWrite (String fname){
104 File file = new File(fname);
106 FileOutputStream fos = new FileOutputStream(file);
107 fos.getChannel(); // just to allocate one
110 content.set(count, fos);
112 logger.info("opening ", fname, " (write) => ", count);
116 } catch (IOException x) {
117 logger.warning("failed to open ", fname, " (write) : ", x);
124 public void close0 (MJIEnv env, int objref) {
125 int fd = env.getIntField(objref, "fd");
128 Object fs = content.get(fd);
131 logger.info("closing ", fd);
133 if (fs instanceof FileInputStream){
134 ((FileInputStream)fs).close();
136 ((FileOutputStream)fs).close();
139 logger.warning("cannot close ", fd, " : no such stream");
141 content.set(fd, null);
143 } catch (ArrayIndexOutOfBoundsException aobx){
144 env.throwException("java.io.IOException", "file not open");
145 } catch (IOException iox) {
146 env.throwException("java.io.IOException", iox.getMessage());
150 // that's a JPF specific thing - we backrack into
151 // a state where the file was still open, and hence don't want to
152 // change the FileDescriptor identify
153 void reopen (MJIEnv env, int objref) throws IOException {
154 int fd = env.getIntField(objref, "fd");
155 long off = env.getLongField(objref,"off");
157 if (content.get(fd) == null){
158 int mode = env.getIntField(objref, "mode");
159 int fnRef = env.getReferenceField(objref, "fileName");
160 String fname = env.getStringObject(fnRef);
162 if (mode == FD_READ){
163 FileInputStream fis = new FileInputStream(fname);
164 FileChannel fc = fis.getChannel(); // just to allocate one
166 content.set(fd, fis);
168 } else if (mode == FD_WRITE){
169 FileOutputStream fos = new FileOutputStream(fname);
170 FileChannel fc = fos.getChannel(); // just to allocate one
172 content.set(fd, fos);
175 env.throwException("java.io.IOException", "illegal mode: " + mode);
181 public void write__I__ (MJIEnv env, int objref, int b){
182 int fd = env.getIntField(objref, "fd");
183 long off = env.getLongField(objref,"off");
186 // this is terrible overhead
187 Object fs = content.get(fd);
189 if (fs instanceof FileOutputStream){
190 FileOutputStream fos = (FileOutputStream)fs;
191 FileChannel fc = fos.getChannel();
194 env.setLongField(objref, "off", fc.position());
197 env.throwException("java.io.IOException", "write attempt on file opened for read access");
201 if (env.getIntField(objref, "state") == FD_OPENED){ // backtracked
203 write__I__(env,objref,b); // try again
205 env.throwException("java.io.IOException", "write attempt on closed file");
208 } catch (ArrayIndexOutOfBoundsException aobx){
209 env.throwException("java.io.IOException", "file not open");
210 } catch (IOException iox) {
211 env.throwException("java.io.IOException", iox.getMessage());
216 public void write___3BII__ (MJIEnv env, int objref,
217 int bref, int offset, int len){
218 int fd = env.getIntField(objref, "fd");
219 long off = env.getLongField(objref,"off");
222 // this is terrible overhead
223 Object fs = content.get(fd);
225 if (fs instanceof FileOutputStream){
226 FileOutputStream fos = (FileOutputStream)fs;
227 FileChannel fc = fos.getChannel();
230 byte[] buf = new byte[len]; // <2do> make this a permanent buffer
231 for (int i=0, j=offset; i<len; i++, j++){
232 buf[i] = env.getByteArrayElement(bref, j);
236 env.setLongField(objref, "off", fc.position());
239 env.throwException("java.io.IOException", "write attempt on file opened for read access");
243 if (env.getIntField(objref, "state") == FD_OPENED){ // backtracked
245 write___3BII__(env,objref,bref,offset,len); // try again
247 env.throwException("java.io.IOException", "write attempt on closed file");
250 } catch (ArrayIndexOutOfBoundsException aobx){
251 env.throwException("java.io.IOException", "file not open");
252 } catch (IOException iox) {
253 env.throwException("java.io.IOException", iox.getMessage());
258 public int read____I (MJIEnv env, int objref) {
259 int fd = env.getIntField(objref, "fd");
260 long off = env.getLongField(objref,"off");
263 // this is terrible overhead
264 Object fs = content.get(fd);
266 if (fs instanceof FileInputStream){
267 FileInputStream fis = (FileInputStream)fs;
268 FileChannel fc = fis.getChannel();
271 env.setLongField(objref, "off", fc.position());
275 env.throwException("java.io.IOException", "read attempt on file opened for write access");
280 if (env.getIntField(objref, "state") == FD_OPENED){ // backtracked
282 return read____I(env,objref); // try again
284 env.throwException("java.io.IOException", "read attempt on closed file");
288 } catch (ArrayIndexOutOfBoundsException aobx){
289 env.throwException("java.io.IOException", "file not open");
291 } catch (IOException iox) {
292 env.throwException("java.io.IOException", iox.getMessage());
298 public int read___3BII__I (MJIEnv env, int objref, int bufref, int offset, int len) {
299 int fd = env.getIntField(objref, "fd");
300 long off = env.getLongField(objref,"off");
303 Object fs = content.get(fd);
305 if (fs instanceof FileInputStream){
306 FileInputStream fis = (FileInputStream)fs;
307 FileChannel fc = fis.getChannel();
310 byte[] buf = new byte[len]; // <2do> make this a permanent buffer
312 int r = fis.read(buf);
313 for (int i=0, j=offset; i<len; i++, j++) {
314 env.setByteArrayElement(bufref, j, buf[i]);
316 env.setLongField(objref, "off", fc.position());
320 env.throwException("java.io.IOException", "read attempt on file opened for write access");
325 if (env.getIntField(objref, "state") == FD_OPENED){ // backtracked
327 return read___3BII__I(env,objref,bufref,offset,len); // try again
329 env.throwException("java.io.IOException", "read attempt on closed file");
333 } catch (ArrayIndexOutOfBoundsException aobx){
334 env.throwException("java.io.IOException", "file not open");
336 } catch (IOException iox) {
337 env.throwException("java.io.IOException", iox.getMessage());
343 public long skip__J__J (MJIEnv env, int objref, long nBytes) {
344 int fd = env.getIntField(objref, "fd");
345 long off = env.getLongField(objref,"off");
348 Object fs = content.get(fd);
350 if (fs instanceof FileInputStream){
351 FileInputStream fis = (FileInputStream)fs;
352 FileChannel fc = fis.getChannel();
355 long r = fis.skip(nBytes);
356 env.setLongField(objref, "off", fc.position());
360 env.throwException("java.io.IOException", "skip attempt on file opened for write access");
365 env.throwException("java.io.IOException", "skip attempt on closed file");
369 } catch (ArrayIndexOutOfBoundsException aobx){
370 env.throwException("java.io.IOException", "file not open");
372 } catch (IOException iox) {
373 env.throwException("java.io.IOException", iox.getMessage());
379 public void sync____ (MJIEnv env, int objref){
380 int fd = env.getIntField(objref, "fd");
383 Object fs = content.get(fd);
385 if (fs instanceof FileOutputStream){
386 ((FileOutputStream)fs).flush();
392 env.throwException("java.io.IOException", "sync attempt on closed file");
395 } catch (ArrayIndexOutOfBoundsException aobx){
396 env.throwException("java.io.IOException", "file not open");
397 } catch (IOException iox) {
398 env.throwException("java.io.IOException", iox.getMessage());
403 public int available____I (MJIEnv env, int objref) {
404 int fd = env.getIntField(objref, "fd");
405 long off = env.getLongField(objref,"off");
408 Object fs = content.get(fd);
410 if (fs instanceof FileInputStream){
411 FileInputStream fis = (FileInputStream)fs;
412 FileChannel fc = fis.getChannel();
414 return fis.available();
417 env.throwException("java.io.IOException", "available() on file opened for write access");
422 env.throwException("java.io.IOException", "available() on closed file");
426 } catch (ArrayIndexOutOfBoundsException aobx){
427 env.throwException("java.io.IOException", "file not open");
429 } catch (IOException iox) {
430 env.throwException("java.io.IOException", iox.getMessage());