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