1 cananian 1.1.2.1 // INFileSystem.java, created Thu Jan 27 04:36:13 1999 by cananian
  2 cananian 1.1.2.1 // Copyright (C) 1999 C. Scott Ananian <cananian@alumni.princeton.edu>
  3 cananian 1.1.2.1 // Licensed under the terms of the GNU GPL; see COPYING for details.
  4 cananian 1.1.2.1 package harpoon.Interpret.Quads;
  5 cananian 1.1.2.1 
  6 cananian 1.1.2.2 import harpoon.ClassFile.HClass;
  7 cananian 1.1.2.2 import harpoon.ClassFile.HClassMutator;
  8 cananian 1.1.2.2 import harpoon.ClassFile.HField;
  9 cananian 1.1.2.2 import harpoon.ClassFile.HMethod;
 10 cananian 1.1.2.2 import harpoon.ClassFile.NoSuchClassException;
 11 cananian 1.1.2.2 
 12 cananian 1.1.2.1 import java.lang.reflect.Modifier;
 13 cananian 1.1.2.2 import java.lang.reflect.InvocationTargetException;
 14 cananian 1.1.2.1 
 15 cananian 1.1.2.1 /**
 16 cananian 1.1.2.1  * <code>INFileSystem</code> provides implementations for (some of) the native
 17 cananian 1.1.2.1  * methods in <code>java.io.FileSystem</code>.  Actually,
 18 cananian 1.1.2.1  * <code>java.io.FileSystem</code> is a JDK 1.2 abstract class, so this
 19 cananian 1.1.2.1  * class actually provides an implementation of *our* instantiation of
 20 cananian 1.1.2.1  * <code>java.io.FileSystem</code>, which happens to be
 21 cananian 1.1.2.1  * <code>harpoon.Interpret.Quads.InterpretedFileSystem</code>, a completely
 22 cananian 1.1.2.1  * synthetic class.
 23 cananian 1.1.2.1  * 
 24 cananian 1.1.2.1  * @author  C. Scott Ananian <cananian@alumni.princeton.edu>
 25 cananian 1.2      * @version $Id: INFileSystem.java,v 1.2 2002/02/25 21:05:46 cananian Exp $
 26 cananian 1.1.2.1  */
 27 cananian 1.1.2.1 public class INFileSystem {
 28 cananian 1.1.2.1     static final void register(StaticState ss) {
 29 cananian 1.1.2.1         try { // JDK 1.2 only
 30 cananian 1.1.2.1             ss.register(getFileSystem(ss));
 31 cananian 1.1.2.1             ss.register(constructor(ss));
 32 cananian 1.1.2.3             ss.register(canonicalize(ss));
 33 cananian 1.1.2.1             ss.register(getBooleanAttributes(ss));
 34 cananian 1.1.2.1             ss.register(getPathSeparator(ss));
 35 cananian 1.1.2.1             ss.register(getSeparator(ss));
 36 cananian 1.1.2.1             ss.register(isAbsolute(ss));
 37 cananian 1.1.2.1             ss.register(normalize(ss));
 38 cananian 1.1.2.3             ss.register(prefixLength(ss));
 39 cananian 1.1.2.3             ss.register(resolve(ss));
 40 cananian 1.1.2.3             ss.register(resolve2(ss));
 41 cananian 1.1.2.1         } catch (NoSuchMethodError e) { // ignore
 42 cananian 1.1.2.1         } catch (NoSuchClassException e) { // ignore
 43 cananian 1.1.2.1         }
 44 cananian 1.1.2.1     }
 45 cananian 1.1.2.1 
 46 cananian 1.1.2.1     // return the synthetic FileSystem class. Make it if we haven't already.
 47 cananian 1.1.2.1     static final HClass getInterpretedFileSystem(StaticState ss) {
 48 cananian 1.1.2.1         final String IFSNAME = "harpoon.Interpret.Quads.InterpretedFileSystem";
 49 cananian 1.1.2.1         try {
 50 cananian 1.1.2.1             return ss.linker.forName(IFSNAME);
 51 cananian 1.1.2.1         } catch (NoSuchClassException e) {
 52 cananian 1.1.2.1             // okay, we've got to build it ourselves.
 53 cananian 1.1.2.1             HClass fs = ss.linker.forName("java.io.FileSystem");
 54 cananian 1.1.2.1             HClass ifs = ss.linker.createMutableClass(IFSNAME, fs);
 55 cananian 1.1.2.1             HClassMutator cm = ifs.getMutator();
 56 cananian 1.1.2.1             // make class non-abstract, with the proper superclass
 57 cananian 1.1.2.1             cm.setSuperclass(fs);
 58 cananian 1.1.2.1             cm.removeModifiers(Modifier.ABSTRACT);
 59 cananian 1.1.2.1             // make all methods native & non-abstract
 60 cananian 1.1.2.1             HMethod[] hm = ifs.getDeclaredMethods();
 61 cananian 1.1.2.1             for (int i=0; i < hm.length; i++) {
 62 cananian 1.1.2.1                 hm[i].getMutator().removeModifiers(Modifier.ABSTRACT);
 63 cananian 1.1.2.1                 hm[i].getMutator().addModifiers(Modifier.NATIVE);
 64 cananian 1.1.2.1             }
 65 cananian 1.1.2.1             // remove inherited fields
 66 cananian 1.1.2.1             HField[] hf = ifs.getDeclaredFields();
 67 cananian 1.1.2.1             for (int i=0; i < hf.length; i++)
 68 cananian 1.1.2.1                 cm.removeDeclaredField(hf[i]);
 69 cananian 1.1.2.1             // make a field to help implement this as a singleton
 70 cananian 1.1.2.1             HField f = cm.addDeclaredField("singleton", fs);
 71 cananian 1.1.2.1             f.getMutator().setModifiers(Modifier.PUBLIC | Modifier.STATIC);
 72 cananian 1.1.2.1             // done!
 73 cananian 1.1.2.1             return ifs;
 74 cananian 1.1.2.1         }
 75 cananian 1.1.2.1     }
 76 cananian 1.1.2.1     // convenience method: make a non-interpreted File object from an
 77 cananian 1.1.2.1     // interpreted File object.
 78 cananian 1.1.2.1     private static final java.io.File resolveFile(StaticState ss,
 79 cananian 1.1.2.1                                                   ObjectRef fileobj) {
 80 cananian 1.1.2.1         // check safety
 81 cananian 1.1.2.1         if (fileobj==null) {
 82 cananian 1.1.2.1             ObjectRef ex_obj = ss.makeThrowable(ss.HCnullpointerE);
 83 cananian 1.1.2.1             throw new InterpretedThrowable(ex_obj, ss);
 84 cananian 1.1.2.1         }
 85 cananian 1.1.2.1         // get the string corresponding to the file path.
 86 cananian 1.1.2.1         String path = ss.ref2str
 87 cananian 1.1.2.1             ((ObjectRef)Method.invoke
 88 cananian 1.1.2.1              (ss, ss.HCfile.getMethod("getPath",new HClass[0]),
 89 cananian 1.1.2.1               new Object[] { fileobj } ));
 90 cananian 1.1.2.1         // now play with it.
 91 cananian 1.1.2.1         return new java.io.File(path);
 92 cananian 1.1.2.1     }
 93 cananian 1.1.2.1 
 94 cananian 1.1.2.1     // get the native FileSystem object
 95 cananian 1.1.2.1     private static final NativeMethod getFileSystem(StaticState ss0) {
 96 cananian 1.1.2.1         final HMethod hm =
 97 cananian 1.1.2.1             ss0.linker.forName("java.io.FileSystem")
 98 cananian 1.1.2.1             .getMethod("getFileSystem", new HClass[0]);
 99 cananian 1.1.2.1         return new NativeMethod() {
100 cananian 1.1.2.1             HMethod getMethod() { return hm; }
101 cananian 1.1.2.1             Object invoke(StaticState ss, Object[] params) {
102 cananian 1.1.2.1                 HClass hc = getInterpretedFileSystem(ss);
103 cananian 1.1.2.1                 HField hf = hc.getDeclaredField("singleton");
104 cananian 1.1.2.1                 ObjectRef obj = (ObjectRef) ss.get(hf);
105 cananian 1.1.2.1                 if (obj!=null) return obj; // return already-created singleton
106 cananian 1.1.2.1                 // else, make singleton object.
107 cananian 1.1.2.1                 obj = new ObjectRef(ss, hc);
108 cananian 1.1.2.1                 Method.invoke(ss, hc.getConstructor(new HClass[0]),
109 cananian 1.1.2.1                               new Object[] { obj } );
110 cananian 1.1.2.1                 // stash it away in field.
111 cananian 1.1.2.1                 ss.update(hf, obj);
112 cananian 1.1.2.1                 // return it
113 cananian 1.1.2.1                 return obj;
114 cananian 1.1.2.1             }
115 cananian 1.1.2.1         };
116 cananian 1.1.2.1     }
117 cananian 1.1.2.1     // constructor for the synthetic interpreted file system class.
118 cananian 1.1.2.1     private static final NativeMethod constructor(StaticState ss0) {
119 cananian 1.1.2.1         final HMethod hm =
120 cananian 1.1.2.1             getInterpretedFileSystem(ss0).getConstructor(new HClass[0]);
121 cananian 1.1.2.1         return new NativeMethod() {
122 cananian 1.1.2.1             HMethod getMethod() { return hm; }
123 cananian 1.1.2.1             Object invoke(StaticState ss, Object[] params) {
124 cananian 1.1.2.1                 ObjectRef _this = (ObjectRef) params[0];
125 cananian 1.1.2.1                 // invoke superclass constructor.  that's all.
126 cananian 1.1.2.1                 HMethod scM = ss.linker.forName("java.io.FileSystem")
127 cananian 1.1.2.1                     .getConstructor(new HClass[0]);
128 cananian 1.1.2.1                 Method.invoke(ss, scM, new Object[] { _this } );
129 cananian 1.1.2.1                 return null; // done.
130 cananian 1.1.2.1             }
131 cananian 1.1.2.1         };
132 cananian 1.1.2.1     }
133 cananian 1.1.2.3     // canonicalize
134 cananian 1.1.2.3     private static final NativeMethod canonicalize(StaticState ss0) {
135 cananian 1.1.2.3         final HClass ifs = getInterpretedFileSystem(ss0);
136 cananian 1.1.2.3         final HMethod hm = ifs.getMethod
137 cananian 1.1.2.3             ("canonicalize", new HClass[] { ss0.HCstring } );
138 cananian 1.1.2.3         return new NativeMethod() {
139 cananian 1.1.2.3             HMethod getMethod() { return hm; }
140 cananian 1.1.2.3             Object invoke(StaticState ss, Object[] params) 
141 cananian 1.1.2.3                 throws InterpretedThrowable {
142 cananian 1.1.2.3                 ObjectRef _this = (ObjectRef) params[0];
143 cananian 1.1.2.3                 ObjectRef _path = (ObjectRef) params[1];
144 cananian 1.1.2.3                 String path = ss.ref2str(_path);
145 cananian 1.1.2.3                 try {
146 cananian 1.1.2.3                     String canon = new java.io.File(path).getCanonicalPath();
147 cananian 1.1.2.3                     return ss.makeString(canon);
148 cananian 1.1.2.3                 } catch (java.io.IOException e) {
149 cananian 1.1.2.3                     ObjectRef obj = ss.makeThrowable(ss.HCioE, e.toString());
150 cananian 1.1.2.3                     throw new InterpretedThrowable(obj, ss);
151 cananian 1.1.2.3                 }
152 cananian 1.1.2.3             }
153 cananian 1.1.2.3         };
154 cananian 1.1.2.3     }
155 cananian 1.1.2.1     // getBooleanAttributes -- return the simple boolean attributes for
156 cananian 1.1.2.1     // the file or directory denoted by the given abstract pathname.
157 cananian 1.1.2.1     private static final NativeMethod getBooleanAttributes(StaticState ss0) {
158 cananian 1.1.2.1         final HClass ifs = getInterpretedFileSystem(ss0);
159 cananian 1.1.2.1         final HMethod hm =
160 cananian 1.1.2.1             ifs.getMethod("getBooleanAttributes", new HClass[] { ss0.HCfile });
161 cananian 1.1.2.1         return new NativeMethod() {
162 cananian 1.1.2.1             HMethod getMethod() { return hm; }
163 cananian 1.1.2.1             Object invoke(StaticState ss, Object[] params) {
164 cananian 1.1.2.1                 ObjectRef _this = (ObjectRef) params[0];
165 cananian 1.1.2.1                 ObjectRef _file = (ObjectRef) params[1];
166 cananian 1.1.2.1                 // resolve interpreted file object into native File
167 cananian 1.1.2.1                 java.io.File f = resolveFile(ss, _file);
168 cananian 1.1.2.1                 // get the attribute values
169 cananian 1.1.2.1                 int BA_EXISTS =
170 cananian 1.1.2.1                     ((Integer)ss.get(ifs.getField("BA_EXISTS"))).intValue();
171 cananian 1.1.2.1                 int BA_REGULAR =
172 cananian 1.1.2.1                     ((Integer)ss.get(ifs.getField("BA_REGULAR"))).intValue();
173 cananian 1.1.2.1                 int BA_DIRECTORY =
174 cananian 1.1.2.1                     ((Integer)ss.get(ifs.getField("BA_DIRECTORY"))).intValue();
175 cananian 1.1.2.1                 int BA_HIDDEN =
176 cananian 1.1.2.1                     ((Integer)ss.get(ifs.getField("BA_HIDDEN"))).intValue();
177 cananian 1.1.2.1                 // okay, compute return value.
178 cananian 1.1.2.1                 int retval = 0;
179 cananian 1.1.2.1                 if (f.exists()) retval |= BA_EXISTS;
180 cananian 1.1.2.1                 if (f.isFile()) retval |= BA_REGULAR;
181 cananian 1.1.2.1                 if (f.isDirectory()) retval |= BA_DIRECTORY;
182 cananian 1.1.2.2                 // have to use reflection for the 'hidden' attribute,
183 cananian 1.1.2.2                 // since File.isHidden isn't present before JDK 1.2
184 cananian 1.1.2.2                 try {
185 cananian 1.1.2.2                     Boolean hidden = (Boolean) 
186 cananian 1.1.2.2                         (f.getClass().getMethod("isHidden", new Class[0])
187 cananian 1.1.2.2                          .invoke(f, new Object[0]));
188 cananian 1.1.2.2                     if (hidden.booleanValue()) retval |= BA_HIDDEN;
189 cananian 1.1.2.2                 } catch (NoSuchMethodException e) { // ignore
190 cananian 1.1.2.2                 } catch (Exception e) { // this shouldn't happen.
191 cananian 1.1.2.2                     throw new RuntimeException(e.toString());
192 cananian 1.1.2.2                 }
193 cananian 1.1.2.1                 return new Integer(retval);
194 cananian 1.1.2.1             }
195 cananian 1.1.2.1         };
196 cananian 1.1.2.1     }
197 cananian 1.1.2.1     // Return the local filesystem's name-separator character.
198 cananian 1.1.2.1     private static final NativeMethod getSeparator(StaticState ss0) {
199 cananian 1.1.2.1         final HClass ifs = getInterpretedFileSystem(ss0);
200 cananian 1.1.2.1         final HMethod hm = ifs.getMethod("getSeparator", new HClass[0]);
201 cananian 1.1.2.1         return new NativeMethod() {
202 cananian 1.1.2.1             HMethod getMethod() { return hm; }
203 cananian 1.1.2.1             Object invoke(StaticState ss, Object[] params) {
204 cananian 1.1.2.1                 return new Character(java.io.File.separatorChar);
205 cananian 1.1.2.1             }
206 cananian 1.1.2.1         };
207 cananian 1.1.2.1     }
208 cananian 1.1.2.1     // Return the local filesystem's path-separator character.
209 cananian 1.1.2.1     private static final NativeMethod getPathSeparator(StaticState ss0) {
210 cananian 1.1.2.1         final HClass ifs = getInterpretedFileSystem(ss0);
211 cananian 1.1.2.1         final HMethod hm = ifs.getMethod("getPathSeparator", new HClass[0]);
212 cananian 1.1.2.1         return new NativeMethod() {
213 cananian 1.1.2.1             HMethod getMethod() { return hm; }
214 cananian 1.1.2.1             Object invoke(StaticState ss, Object[] params) {
215 cananian 1.1.2.1                 return new Character(java.io.File.pathSeparatorChar);
216 cananian 1.1.2.1             }
217 cananian 1.1.2.1         };
218 cananian 1.1.2.1     }
219 cananian 1.1.2.1     //
220 cananian 1.1.2.1     private static final NativeMethod isAbsolute(StaticState ss0) {
221 cananian 1.1.2.1         final HClass ifs = getInterpretedFileSystem(ss0);
222 cananian 1.1.2.1         final HMethod hm = ifs.getMethod("isAbsolute",
223 cananian 1.1.2.1                                          new HClass[] { ss0.HCfile } );
224 cananian 1.1.2.1         return new NativeMethod() {
225 cananian 1.1.2.1             HMethod getMethod() { return hm; }
226 cananian 1.1.2.1             Object invoke(StaticState ss, Object[] params) {
227 cananian 1.1.2.1                 ObjectRef _this = (ObjectRef) params[0];
228 cananian 1.1.2.1                 ObjectRef _file = (ObjectRef) params[1];
229 cananian 1.1.2.1                 // resolve interpreted file object into native File
230 cananian 1.1.2.1                 java.io.File f = resolveFile(ss, _file);
231 cananian 1.1.2.1                 return new Boolean(f.isAbsolute());
232 cananian 1.1.2.1             }
233 cananian 1.1.2.1         };
234 cananian 1.1.2.1     }
235 cananian 1.1.2.1     // Convert the given pathname string to normal form.
236 cananian 1.1.2.1     private static final NativeMethod normalize(StaticState ss0) {
237 cananian 1.1.2.1         final HClass ifs = getInterpretedFileSystem(ss0);
238 cananian 1.1.2.1         final HMethod hm = ifs.getMethod("normalize",
239 cananian 1.1.2.1                                          new HClass[] { ss0.HCstring } );
240 cananian 1.1.2.1         return new NativeMethod() {
241 cananian 1.1.2.1             HMethod getMethod() { return hm; }
242 cananian 1.1.2.1             Object invoke(StaticState ss, Object[] params) {
243 cananian 1.1.2.1                 ObjectRef _this = (ObjectRef) params[0];
244 cananian 1.1.2.1                 ObjectRef _path = (ObjectRef) params[1];
245 cananian 1.1.2.1                 String path = ss.ref2str(_path);
246 cananian 1.1.2.1                 String normal = new java.io.File(path).getPath();
247 cananian 1.1.2.1                 return path.equals(normal) ? _path : ss.makeString(normal);
248 cananian 1.1.2.3             }
249 cananian 1.1.2.3         };
250 cananian 1.1.2.3     }
251 cananian 1.1.2.3     // Compute the length of this pathname string's prefix.
252 cananian 1.1.2.3     private static final NativeMethod prefixLength(StaticState ss0) {
253 cananian 1.1.2.3         final HClass ifs = getInterpretedFileSystem(ss0);
254 cananian 1.1.2.3         final HMethod hm = ifs.getMethod("prefixLength",
255 cananian 1.1.2.3                                          new HClass[] { ss0.HCstring } );
256 cananian 1.1.2.3         return new NativeMethod() {
257 cananian 1.1.2.3             HMethod getMethod() { return hm; }
258 cananian 1.1.2.3             Object invoke(StaticState ss, Object[] params) {
259 cananian 1.1.2.3                 // I hope this implementation is correct.
260 cananian 1.1.2.3                 ObjectRef _this = (ObjectRef) params[0];
261 cananian 1.1.2.3                 ObjectRef _path = (ObjectRef) params[1];
262 cananian 1.1.2.3                 String path = ss.ref2str(_path);
263 cananian 1.1.2.3                 String parent = new java.io.File(path).getParent();
264 cananian 1.1.2.3                 if (parent==null) parent="";
265 cananian 1.1.2.3                 int index = path.lastIndexOf(java.io.File.separatorChar);
266 cananian 1.1.2.3                 int plen  = parent.length();
267 cananian 1.1.2.3                 int prefixLength = (plen > index) ? plen : index;
268 cananian 1.1.2.3                 return new Integer(prefixLength);
269 cananian 1.1.2.3             }
270 cananian 1.1.2.3         };
271 cananian 1.1.2.3     }
272 cananian 1.1.2.3     // Resolve the child pathname string against the parent.
273 cananian 1.1.2.3     private static final NativeMethod resolve(StaticState ss0) {
274 cananian 1.1.2.3         final HClass ifs = getInterpretedFileSystem(ss0);
275 cananian 1.1.2.3         final HMethod hm = ifs.getMethod
276 cananian 1.1.2.3             ("resolve", new HClass[] { ss0.HCstring, ss0.HCstring } );
277 cananian 1.1.2.3         return new NativeMethod() {
278 cananian 1.1.2.3             HMethod getMethod() { return hm; }
279 cananian 1.1.2.3             Object invoke(StaticState ss, Object[] params) {
280 cananian 1.1.2.3                 ObjectRef _this = (ObjectRef) params[0];
281 cananian 1.1.2.3                 ObjectRef _parent = (ObjectRef) params[1];
282 cananian 1.1.2.3                 ObjectRef _child = (ObjectRef) params[2];
283 cananian 1.1.2.3                 String parent = ss.ref2str(_parent);
284 cananian 1.1.2.3                 String child  = ss.ref2str(_child);
285 cananian 1.1.2.3                 String resolved = new java.io.File(parent, child).getPath();
286 cananian 1.1.2.3                 return ss.makeString(resolved);
287 cananian 1.1.2.3             }
288 cananian 1.1.2.3         };
289 cananian 1.1.2.3     }
290 cananian 1.1.2.3     // Resolve the given abstract pathname into absolute form.
291 cananian 1.1.2.3     private static final NativeMethod resolve2(StaticState ss0) {
292 cananian 1.1.2.3         final HClass ifs = getInterpretedFileSystem(ss0);
293 cananian 1.1.2.3         final HMethod hm = ifs.getMethod
294 cananian 1.1.2.3             ("resolve", new HClass[] { ss0.HCfile } );
295 cananian 1.1.2.3         return new NativeMethod() {
296 cananian 1.1.2.3             HMethod getMethod() { return hm; }
297 cananian 1.1.2.3             Object invoke(StaticState ss, Object[] params) {
298 cananian 1.1.2.3                 ObjectRef _this = (ObjectRef) params[0];
299 cananian 1.1.2.3                 ObjectRef _file = (ObjectRef) params[1];
300 cananian 1.1.2.3                 java.io.File f = resolveFile(ss, _file);
301 cananian 1.1.2.3                 return ss.makeString(f.getAbsolutePath());
302 cananian 1.1.2.1             }
303 cananian 1.1.2.1         };
304 cananian 1.1.2.1     }
305 cananian 1.1.2.1 }
306 cananian 1.2