1 32 package org.jruby; 33 34 import java.io.File ; 35 import java.io.IOException ; 36 import java.util.ArrayList ; 37 import java.util.List ; 38 39 import org.jruby.javasupport.JavaUtil; 40 import org.jruby.runtime.Block; 41 import org.jruby.runtime.CallbackFactory; 42 import org.jruby.runtime.ObjectAllocator; 43 import org.jruby.runtime.ThreadContext; 44 import org.jruby.runtime.builtin.IRubyObject; 45 import org.jruby.util.Glob; 46 import org.jruby.util.JRubyFile; 47 48 53 public class RubyDir extends RubyObject { 54 private RubyString path; 56 protected JRubyFile dir; 57 private String [] snapshot; private int pos; private boolean isOpen = true; 60 61 public RubyDir(Ruby runtime, RubyClass type) { 62 super(runtime, type); 63 } 64 65 private static ObjectAllocator DIR_ALLOCATOR = new ObjectAllocator() { 66 public IRubyObject allocate(Ruby runtime, RubyClass klass) { 67 return new RubyDir(runtime, klass); 68 } 69 }; 70 71 public static RubyClass createDirClass(Ruby runtime) { 72 RubyClass dirClass = runtime.defineClass("Dir", runtime.getObject(), DIR_ALLOCATOR); 73 74 dirClass.includeModule(runtime.getModule("Enumerable")); 75 76 CallbackFactory callbackFactory = runtime.callbackFactory(RubyDir.class); 77 78 dirClass.getMetaClass().defineMethod("glob", callbackFactory.getSingletonMethod("glob", RubyKernel.IRUBY_OBJECT)); 79 dirClass.getMetaClass().defineFastMethod("entries", callbackFactory.getFastSingletonMethod("entries", RubyKernel.IRUBY_OBJECT)); 80 dirClass.getMetaClass().defineMethod("[]", callbackFactory.getSingletonMethod("glob", RubyKernel.IRUBY_OBJECT)); 81 dirClass.getMetaClass().defineMethod("chdir", callbackFactory.getOptSingletonMethod("chdir")); 83 dirClass.getMetaClass().defineFastMethod("chroot", callbackFactory.getFastSingletonMethod("chroot", RubyKernel.IRUBY_OBJECT)); 84 dirClass.getMetaClass().defineMethod("foreach", callbackFactory.getSingletonMethod("foreach", RubyKernel.IRUBY_OBJECT)); 86 dirClass.getMetaClass().defineFastMethod("getwd", callbackFactory.getFastSingletonMethod("getwd")); 87 dirClass.getMetaClass().defineFastMethod("pwd", callbackFactory.getFastSingletonMethod("getwd")); 88 dirClass.getMetaClass().defineFastMethod("mkdir", callbackFactory.getFastOptSingletonMethod("mkdir")); 90 dirClass.getMetaClass().defineMethod("open", callbackFactory.getSingletonMethod("open", RubyKernel.IRUBY_OBJECT)); 91 dirClass.getMetaClass().defineFastMethod("rmdir", callbackFactory.getFastSingletonMethod("rmdir", RubyKernel.IRUBY_OBJECT)); 92 dirClass.getMetaClass().defineFastMethod("unlink", callbackFactory.getFastSingletonMethod("rmdir", RubyKernel.IRUBY_OBJECT)); 93 dirClass.getMetaClass().defineFastMethod("delete", callbackFactory.getFastSingletonMethod("rmdir", RubyKernel.IRUBY_OBJECT)); 94 97 dirClass.defineFastMethod("close", callbackFactory.getFastMethod("close")); 98 dirClass.defineMethod("each", callbackFactory.getMethod("each")); 99 dirClass.defineFastMethod("entries", callbackFactory.getFastMethod("entries")); 100 dirClass.defineFastMethod("path", callbackFactory.getFastMethod("path")); 101 dirClass.defineFastMethod("tell", callbackFactory.getFastMethod("tell")); 102 dirClass.defineAlias("pos", "tell"); 103 dirClass.defineFastMethod("seek", callbackFactory.getFastMethod("seek", RubyKernel.IRUBY_OBJECT)); 104 dirClass.defineFastMethod("pos=", callbackFactory.getFastMethod("setPos", RubyKernel.IRUBY_OBJECT)); 105 dirClass.defineFastMethod("read", callbackFactory.getFastMethod("read")); 106 dirClass.defineFastMethod("rewind", callbackFactory.getFastMethod("rewind")); 107 dirClass.defineMethod("initialize", callbackFactory.getMethod("initialize", RubyKernel.IRUBY_OBJECT)); 108 109 return dirClass; 110 } 111 112 119 public IRubyObject initialize(IRubyObject _newPath, Block unusedBlock) { 120 RubyString newPath = _newPath.convertToString(); 121 newPath.checkSafeString(); 122 dir = JRubyFile.create(getRuntime().getCurrentDirectory(),newPath.toString()); 123 if (!dir.isDirectory()) { 124 dir = null; 125 throw getRuntime().newErrnoENOENTError(newPath.toString() + " is not a directory"); 126 } 127 path = newPath; 128 List snapshotList = new ArrayList (); 129 snapshotList.add("."); 130 snapshotList.add(".."); 131 snapshotList.addAll(getContents(dir)); 132 snapshot = (String []) snapshotList.toArray(new String [snapshotList.size()]); 133 pos = 0; 134 135 return this; 136 } 137 138 140 146 public static IRubyObject glob(IRubyObject recv, IRubyObject pat, Block block) { 147 String pattern = pat.convertToString().toString(); 148 String [] files = new Glob(recv.getRuntime().getCurrentDirectory(), pattern).getNames(); 149 if (block.isGiven()) { 150 ThreadContext context = recv.getRuntime().getCurrentContext(); 151 152 for (int i = 0; i < files.length; i++) { 153 context.yield(JavaUtil.convertJavaToRuby(recv.getRuntime(), files[i]), block); 154 } 155 return recv.getRuntime().getNil(); 156 } 157 return recv.getRuntime().newArrayNoCopy(JavaUtil.convertJavaArrayToRuby(recv.getRuntime(), files)); 158 } 159 160 163 public RubyArray entries() { 164 return getRuntime().newArrayNoCopy(JavaUtil.convertJavaArrayToRuby(getRuntime(), snapshot)); 165 } 166 167 170 public static RubyArray entries(IRubyObject recv, IRubyObject path) { 171 final JRubyFile directory = JRubyFile.create(recv.getRuntime().getCurrentDirectory(),path.convertToString().toString()); 172 173 if (!directory.isDirectory()) { 174 throw recv.getRuntime().newErrnoENOENTError("No such directory"); 175 } 176 List fileList = getContents(directory); 177 fileList.add(0,"."); 178 fileList.add(1,".."); 179 Object [] files = fileList.toArray(); 180 return recv.getRuntime().newArrayNoCopy(JavaUtil.convertJavaArrayToRuby(recv.getRuntime(), files)); 181 } 182 183 184 public static IRubyObject chdir(IRubyObject recv, IRubyObject[] args, Block block) { 185 recv.checkArgumentCount(args, 0, 1); 186 RubyString path = args.length == 1 ? 187 (RubyString) args[0].convertToString() : getHomeDirectoryPath(recv); 188 JRubyFile dir = getDir(recv.getRuntime(), path.toString(), true); 189 String realPath = null; 190 String oldCwd = recv.getRuntime().getCurrentDirectory(); 191 192 try { 196 realPath = dir.getCanonicalPath(); 197 } catch (IOException e) { 198 realPath = dir.getAbsolutePath(); 199 } 200 201 IRubyObject result = null; 202 if (block.isGiven()) { 203 recv.getRuntime().setCurrentDirectory(realPath); 205 try { 206 result = recv.getRuntime().getCurrentContext().yield(path, block); 207 } finally { 208 recv.getRuntime().setCurrentDirectory(oldCwd); 209 } 210 } else { 211 recv.getRuntime().setCurrentDirectory(realPath); 212 result = recv.getRuntime().newFixnum(0); 213 } 214 215 return result; 216 } 217 218 222 public static IRubyObject chroot(IRubyObject recv, IRubyObject path) { 223 throw recv.getRuntime().newNotImplementedError("chroot not implemented: chroot is non-portable and is not supported."); 224 } 225 226 230 public static IRubyObject rmdir(IRubyObject recv, IRubyObject path) { 231 JRubyFile directory = getDir(recv.getRuntime(), path.convertToString().toString(), true); 232 233 if (!directory.delete()) { 234 throw recv.getRuntime().newSystemCallError("No such directory"); 235 } 236 237 return recv.getRuntime().newFixnum(0); 238 } 239 240 244 public static IRubyObject foreach(IRubyObject recv, IRubyObject _path, Block block) { 245 RubyString path = _path.convertToString(); 246 path.checkSafeString(); 247 248 RubyClass dirClass = recv.getRuntime().getClass("Dir"); 249 RubyDir dir = (RubyDir) dirClass.newInstance(new IRubyObject[] { path }, block); 250 251 dir.each(block); 252 return recv.getRuntime().getNil(); 253 } 254 255 256 public static RubyString getwd(IRubyObject recv) { 257 return recv.getRuntime().newString(recv.getRuntime().getCurrentDirectory()); 258 } 259 260 265 public static IRubyObject mkdir(IRubyObject recv, IRubyObject[] args) { 266 if (args.length < 1) { 267 throw recv.getRuntime().newArgumentError(args.length, 1); 268 } 269 if (args.length > 2) { 270 throw recv.getRuntime().newArgumentError(args.length, 2); 271 } 272 273 args[0].checkSafeString(); 274 String path = args[0].toString(); 275 276 File newDir = getDir(recv.getRuntime(), path, false); 277 if (File.separatorChar == '\\') { 278 newDir = new File (newDir.getPath()); 279 } 280 281 return newDir.mkdirs() ? RubyFixnum.zero(recv.getRuntime()) : 282 RubyFixnum.one(recv.getRuntime()); 283 } 284 285 290 public static IRubyObject open(IRubyObject recv, IRubyObject path, Block block) { 291 RubyDir directory = 292 (RubyDir) recv.getRuntime().getClass("Dir").newInstance( 293 new IRubyObject[] { path }, Block.NULL_BLOCK); 294 295 if (!block.isGiven()) return directory; 296 297 try { 298 recv.getRuntime().getCurrentContext().yield(directory, block); 299 } finally { 300 directory.close(); 301 } 302 303 return recv.getRuntime().getNil(); 304 } 305 306 308 311 public IRubyObject close() { 312 isOpen = false; 314 315 return getRuntime().getNil(); 316 } 317 318 321 public IRubyObject each(Block block) { 322 String [] contents = snapshot; 323 ThreadContext context = getRuntime().getCurrentContext(); 324 for (int i=0; i<contents.length; i++) { 325 context.yield(getRuntime().newString(contents[i]), block); 326 } 327 return this; 328 } 329 330 333 public RubyInteger tell() { 334 return getRuntime().newFixnum(pos); 335 } 336 337 341 public IRubyObject seek(IRubyObject newPos) { 342 setPos(newPos); 343 return this; 344 } 345 346 public IRubyObject setPos(IRubyObject newPos) { 347 this.pos = RubyNumeric.fix2int(newPos); 348 return newPos; 349 } 350 351 public IRubyObject path() { 352 if (!isOpen) { 353 throw getRuntime().newIOError("closed directory"); 354 } 355 356 return path; 357 } 358 359 360 public IRubyObject read() { 361 if (!isOpen) { 362 throw getRuntime().newIOError("Directory already closed"); 363 } 364 365 if (pos >= snapshot.length) { 366 return getRuntime().getNil(); 367 } 368 RubyString result = getRuntime().newString(snapshot[pos]); 369 pos++; 370 return result; 371 } 372 373 374 public IRubyObject rewind() { 375 pos = 0; 376 return getRuntime().newFixnum(pos); 377 } 378 379 381 388 protected static JRubyFile getDir(final Ruby runtime, final String path, final boolean mustExist) { 389 JRubyFile result = JRubyFile.create(runtime.getCurrentDirectory(),path); 390 boolean isDirectory = result.isDirectory(); 391 392 if (mustExist && !isDirectory) { 393 throw runtime.newErrnoENOENTError(path + " is not a directory"); 394 } else if (!mustExist && isDirectory) { 395 throw runtime.newErrnoEEXISTError("File exists - " + path); 396 } 397 398 return result; 399 } 400 401 405 protected static List getContents(File directory) { 406 String [] contents = directory.list(); 407 List result = new ArrayList (); 408 409 if (contents != null) { 412 for (int i=0; i<contents.length; i++) { 413 result.add(contents[i]); 414 } 415 } 416 return result; 417 } 418 419 423 protected static List getContents(File directory, Ruby runtime) { 424 List result = new ArrayList (); 425 String [] contents = directory.list(); 426 427 for (int i = 0; i < contents.length; i++) { 428 result.add(runtime.newString(contents[i])); 429 } 430 return result; 431 } 432 433 438 public static IRubyObject getHomeDirectoryPath(IRubyObject recv, String user) { 439 return recv.getRuntime().evalScript("File.open('/etc/passwd') do |f| f.readlines.each do" + 442 "|l| f = l.split(':'); return f[5] if f[0] == '" + user + "'; end; end; nil"); 443 } 444 445 public static RubyString getHomeDirectoryPath(IRubyObject recv) { 446 RubyHash hash = (RubyHash) recv.getRuntime().getObject().getConstant("ENV_JAVA"); 447 IRubyObject home = hash.aref(recv.getRuntime().newString("user.home")); 448 449 if (home == null || home.isNil()) { 450 home = hash.aref(recv.getRuntime().newString("LOGDIR")); 451 } 452 453 if (home == null || home.isNil()) { 454 throw recv.getRuntime().newArgumentError("user.home/LOGDIR not set"); 455 } 456 457 return (RubyString) home; 458 } 459 } 460 | Popular Tags |