1 35 package org.jruby; 36 37 import java.io.File ; 38 import java.io.FileInputStream ; 39 import java.io.FileNotFoundException ; 40 import java.io.IOException ; 41 import java.io.InputStream ; 42 import java.io.Reader ; 43 import java.nio.channels.FileChannel ; 44 import java.nio.channels.FileLock ; 45 46 import org.jruby.exceptions.RaiseException; 47 import org.jruby.runtime.Block; 48 import org.jruby.runtime.builtin.IRubyObject; 49 import org.jruby.runtime.builtin.meta.FileMetaClass; 50 import org.jruby.util.IOHandler; 51 import org.jruby.util.IOHandlerNull; 52 import org.jruby.util.IOHandlerSeekable; 53 import org.jruby.util.IOHandlerUnseekable; 54 import org.jruby.util.IOModes; 55 import org.jruby.util.JRubyFile; 56 import org.jruby.util.IOHandler.InvalidValueException; 57 58 63 public class RubyFile extends RubyIO { 64 public static final int LOCK_SH = 1; 65 public static final int LOCK_EX = 2; 66 public static final int LOCK_NB = 4; 67 public static final int LOCK_UN = 8; 68 69 protected String path; 70 private FileLock currentLock; 71 72 public RubyFile(Ruby runtime, RubyClass type) { 73 super(runtime, type); 74 } 75 76 public RubyFile(Ruby runtime, String path) { 77 this(runtime, path, open(runtime, path)); 78 } 79 80 private static InputStream open(Ruby runtime, String path) { 82 try { 83 return new FileInputStream (path); 84 } catch (FileNotFoundException e) { 85 throw runtime.newIOError(e.getMessage()); 86 } 87 } 88 89 public RubyFile(Ruby runtime, String path, final Reader reader) { 92 this(runtime, path, new InputStream () { 93 public int read() throws IOException { 94 return reader.read(); 95 } 96 }); 97 } 98 99 private RubyFile(Ruby runtime, String path, InputStream in) { 100 super(runtime, runtime.getClass("File")); 101 this.path = path; 102 try { 103 this.handler = new IOHandlerUnseekable(runtime, in, null); 104 } catch (IOException e) { 105 throw runtime.newIOError(e.getMessage()); 106 } 107 this.modes = handler.getModes(); 108 registerIOHandler(handler); 109 } 110 111 public void openInternal(String newPath, IOModes newModes) { 112 this.path = newPath; 113 this.modes = newModes; 114 115 try { 116 if (newPath.equals("/dev/null")) { 117 handler = new IOHandlerNull(getRuntime(), newModes); 118 } else { 119 handler = new IOHandlerSeekable(getRuntime(), newPath, newModes); 120 } 121 122 registerIOHandler(handler); 123 } catch (InvalidValueException e) { 124 throw getRuntime().newErrnoEINVALError(); 125 } catch (FileNotFoundException e) { 126 throw getRuntime().newErrnoENOENTError(); 127 } catch (IOException e) { 128 throw getRuntime().newIOError(e.getMessage()); 129 } 130 } 131 132 public IRubyObject close() { 133 if (currentLock != null) { 135 try { 136 currentLock.release(); 137 } catch (IOException e) { 138 throw getRuntime().newIOError(e.getMessage()); 139 } 140 } 141 return super.close(); 142 } 143 144 public IRubyObject flock(IRubyObject lockingConstant) { 145 FileChannel fileChannel = handler.getFileChannel(); 146 int lockMode = (int) ((RubyFixnum) lockingConstant.convertToType("Fixnum", "to_int", 147 true)).getLongValue(); 148 149 try { 150 switch(lockMode) { 151 case LOCK_UN: 152 if (currentLock != null) { 153 currentLock.release(); 154 currentLock = null; 155 156 return getRuntime().newFixnum(0); 157 } 158 break; 159 case LOCK_EX: 160 case LOCK_EX | LOCK_NB: 161 if (currentLock != null) { 162 currentLock.release(); 163 currentLock = null; 164 } 165 currentLock = fileChannel.tryLock(); 166 if (currentLock != null) { 167 return getRuntime().newFixnum(0); 168 } 169 170 break; 171 case LOCK_SH: 172 case LOCK_SH | LOCK_NB: 173 if (currentLock != null) { 174 currentLock.release(); 175 currentLock = null; 176 } 177 178 currentLock = fileChannel.tryLock(0L, Long.MAX_VALUE, true); 179 if (currentLock != null) { 180 return getRuntime().newFixnum(0); 181 } 182 183 break; 184 default: 185 } 186 } catch (IOException ioe) { 187 throw new RaiseException(new NativeException(getRuntime(), getRuntime().getClass("IOError"), ioe)); 188 } 189 190 return getRuntime().getFalse(); 191 } 192 193 public IRubyObject initialize(IRubyObject[] args, Block block) { 194 if (args.length == 0) { 195 throw getRuntime().newArgumentError(0, 1); 196 } 197 198 args[0].checkSafeString(); 199 path = args[0].toString(); 200 modes = args.length > 1 ? getModes(args[1]) : 201 new IOModes(getRuntime(), IOModes.RDONLY); 202 203 if (handler != null) { 207 close(); 208 } 209 openInternal(path, modes); 210 211 if (block.isGiven()) { 212 } 214 return this; 215 } 216 217 public IRubyObject chmod(IRubyObject[] args) { 218 checkArgumentCount(args, 1, 1); 219 220 RubyInteger mode = args[0].convertToInteger(); 221 222 if (!new File (path).exists()) { 223 throw getRuntime().newErrnoENOENTError("No such file or directory - " + path); 224 } 225 226 try { 227 Process chown = Runtime.getRuntime().exec("chmod " + FileMetaClass.OCTAL_FORMATTER.sprintf(mode.getLongValue()) + " " + path); 228 chown.waitFor(); 229 } catch (IOException ioe) { 230 } catch (InterruptedException ie) { 232 } 234 235 return getRuntime().newFixnum(0); 236 } 237 238 public IRubyObject chown(IRubyObject[] args) { 239 checkArgumentCount(args, 1, 1); 240 241 RubyInteger owner = args[0].convertToInteger(); 242 if (!new File (path).exists()) { 243 throw getRuntime().newErrnoENOENTError("No such file or directory - " + path); 244 } 245 246 try { 247 Process chown = Runtime.getRuntime().exec("chown " + owner + " " + path); 248 chown.waitFor(); 249 } catch (IOException ioe) { 250 } catch (InterruptedException ie) { 252 } 254 255 return getRuntime().newFixnum(0); 256 } 257 258 public IRubyObject ctime() { 259 return getRuntime().newTime(JRubyFile.create(getRuntime().getCurrentDirectory(),this.path).getParentFile().lastModified()); 260 } 261 262 public RubyString path() { 263 return getRuntime().newString(path); 264 } 265 266 public IRubyObject stat() { 267 return getRuntime().newRubyFileStat(path); 268 } 269 270 public IRubyObject truncate(IRubyObject arg) { 271 RubyFixnum newLength = (RubyFixnum) arg.convertToType("Fixnum", "to_int", true); 272 try { 273 handler.truncate(newLength.getLongValue()); 274 } catch (IOHandler.PipeException e) { 275 throw getRuntime().newErrnoESPIPEError(); 276 } catch (IOException e) { 277 } 279 280 return RubyFixnum.zero(getRuntime()); 281 } 282 283 public String toString() { 284 return "RubyFile(" + path + ", " + modes + ", " + fileno + ")"; 285 } 286 287 private IOModes getModes(IRubyObject object) { 289 if (object instanceof RubyString) { 290 return new IOModes(getRuntime(), ((RubyString)object).toString()); 291 } else if (object instanceof RubyFixnum) { 292 return new IOModes(getRuntime(), ((RubyFixnum)object).getLongValue()); 293 } 294 295 throw getRuntime().newTypeError("Invalid type for modes"); 296 } 297 298 public IRubyObject inspect() { 299 StringBuffer val = new StringBuffer (); 300 val.append("#<File:").append(path); 301 if(!isOpen()) { 302 val.append(" (closed)"); 303 } 304 val.append(">"); 305 return getRuntime().newString(val.toString()); 306 } 307 } 308 | Popular Tags |