Skip to content
Browse files

Use MRI logic for generating tempfile names in Tempfile.

This change does the following:

* Adds missing Ruby logic by defining Tempfile.create and
  including Dir::Tmpname into Tempfile. These changes happen in
  the new lib/ruby/shared/tempfile.rb.
* Invokes #create included from Tmpname to generate the filename,
  rather than using our own filename logic. This allows overriding
  both #create and #make_tempname. It also abstracts all name
  logic to Ruby's tmpdir.rb.
* Eliminate unused Reaper logic.
* Eliminate unused temp dir finding logic.
* Fixes #677
  • Loading branch information...
1 parent f6a9649 commit 607c6d5f27f229011e740517e51793e19852f062 @headius headius committed Apr 29, 2013
View
146 lib/ruby/1.8/tmpdir.rb
@@ -1,146 +0,0 @@
-#
-# tmpdir - retrieve temporary directory path
-#
-# $Id$
-#
-
-require 'fileutils'
-
-class Dir
-
- @@systmpdir = '/tmp'
-
- begin
- require 'Win32API'
- CSIDL_LOCAL_APPDATA = 0x001c
- max_pathlen = 260
- windir = "\0"*(max_pathlen+1)
- begin
- getdir = Win32API.new('shell32', 'SHGetFolderPath', 'LLLLP', 'L')
- raise RuntimeError if getdir.call(0, CSIDL_LOCAL_APPDATA, 0, 0, windir) != 0
- windir = File.expand_path(windir.rstrip)
- rescue RuntimeError
- begin
- getdir = Win32API.new('kernel32', 'GetSystemWindowsDirectory', 'PL', 'L')
- rescue RuntimeError
- getdir = Win32API.new('kernel32', 'GetWindowsDirectory', 'PL', 'L')
- end
- len = getdir.call(windir, windir.size)
- windir = File.expand_path(windir[0, len])
- end
- temp = File.join(windir.untaint, 'temp')
- @@systmpdir = temp if File.directory?(temp) and File.writable?(temp)
- rescue LoadError
- end
-
- ##
- # Returns the operating system's temporary file path.
-
- def Dir::tmpdir
- tmp = '.'
- if $SAFE > 0
- tmp = @@systmpdir
- else
- # Search a directory which isn't world-writable first. In JRuby,
- # FileUtils.remove_entry_secure(dir) crashes when a dir is under
- # a world-writable directory because it tries to open directory.
- # Opening directory is not allowed in Java.
- dirs = [ENV['TMPDIR'], ENV['TMP'], ENV['TEMP'], ENV['USERPROFILE'], @@systmpdir, '/tmp', tmp]
- for dir in dirs
- if dir and File.directory?(dir) and File.writable?(dir) and (File.stat(dir).mode & 0002) == 0
- return File.expand_path(dir)
- end
- end
- for dir in dirs
- if dir and File.directory?(dir) and File.writable?(dir)
- tmp = dir
- break
- end
- end
- File.expand_path(tmp)
- end
- end
-
- # Dir.mktmpdir creates a temporary directory.
- #
- # The directory is created with 0700 permission.
- #
- # The prefix and suffix of the name of the directory is specified by
- # the optional first argument, <i>prefix_suffix</i>.
- # - If it is not specified or nil, "d" is used as the prefix and no suffix is used.
- # - If it is a string, it is used as the prefix and no suffix is used.
- # - If it is an array, first element is used as the prefix and second element is used as a suffix.
- #
- # Dir.mktmpdir {|dir| dir is ".../d..." }
- # Dir.mktmpdir("foo") {|dir| dir is ".../foo..." }
- # Dir.mktmpdir(["foo", "bar"]) {|dir| dir is ".../foo...bar" }
- #
- # The directory is created under Dir.tmpdir or
- # the optional second argument <i>tmpdir</i> if non-nil value is given.
- #
- # Dir.mktmpdir {|dir| dir is "#{Dir.tmpdir}/d..." }
- # Dir.mktmpdir(nil, "/var/tmp") {|dir| dir is "/var/tmp/d..." }
- #
- # If a block is given,
- # it is yielded with the path of the directory.
- # The directory and its contents are removed
- # using FileUtils.remove_entry_secure before Dir.mktmpdir returns.
- # The value of the block is returned.
- #
- # Dir.mktmpdir {|dir|
- # # use the directory...
- # open("#{dir}/foo", "w") { ... }
- # }
- #
- # If a block is not given,
- # The path of the directory is returned.
- # In this case, Dir.mktmpdir doesn't remove the directory.
- #
- # dir = Dir.mktmpdir
- # begin
- # # use the directory...
- # open("#{dir}/foo", "w") { ... }
- # ensure
- # # remove the directory.
- # FileUtils.remove_entry_secure dir
- # end
- #
- def Dir.mktmpdir(prefix_suffix=nil, tmpdir=nil)
- case prefix_suffix
- when nil
- prefix = "d"
- suffix = ""
- when String
- prefix = prefix_suffix
- suffix = ""
- when Array
- prefix = prefix_suffix[0]
- suffix = prefix_suffix[1]
- else
- raise ArgumentError, "unexpected prefix_suffix: #{prefix_suffix.inspect}"
- end
- tmpdir ||= Dir.tmpdir
- t = Time.now.strftime("%Y%m%d")
- n = nil
- begin
- path = "#{tmpdir}/#{prefix}#{t}-#{$$}-#{rand(0x100000000).to_s(36)}"
- path << "-#{n}" if n
- path << suffix
- Dir.mkdir(path, 0700)
- rescue Errno::EEXIST
- n ||= 0
- n += 1
- retry
- end
-
- if block_given?
- begin
- yield path
- ensure
- FileUtils.remove_entry_secure path
- end
- else
- path
- end
- end
-end
View
59 lib/ruby/shared/tempfile.rb
@@ -0,0 +1,59 @@
+# JRuby 1.7.x and lower implements most of tempfile as a JRuby ext. This
+# file simple loads that ext and then adds the additional functions that
+# control how tempfile name is generated.
+
+require 'delegate' # Unused; here for compatibility
+require 'tmpdir'
+require 'thread' # Unused; here for compatibility
+
+require 'tempfile.jar'
+
+class Tempfile
+ include Dir::Tmpname
+end
+
+# Creates a temporally file as usual File object (not Tempfile).
+# It don't use finalizer and delegation.
+#
+# If no block is given, this is similar to Tempfile.new except
+# creating File instead of Tempfile.
+# The created file is not removed automatically.
+# You should use File.unlink to remove it.
+#
+# If a block is given, then a File object will be constructed,
+# and the block is invoked with the object as the argument.
+# The File object will be automatically closed and
+# the temporally file is removed after the block terminates.
+# The call returns the value of the block.
+#
+# In any case, all arguments (+*args+) will be treated as Tempfile.new.
+#
+# Tempfile.create('foo', '/home/temp') do |f|
+# ... do something with f ...
+# end
+#
+def Tempfile.create(basename, *rest)
+ tmpfile = nil
+ Dir::Tmpname.create(basename, *rest) do |tmpname, n, opts|
+ mode = File::RDWR|File::CREAT|File::EXCL
+ perm = 0600
+ if opts
+ mode |= opts.delete(:mode) || 0
+ opts[:perm] = perm
+ perm = nil
+ else
+ opts = perm
+ end
+ tmpfile = File.open(tmpname, mode, opts)
+ end
+ if block_given?
+ begin
+ yield tmpfile
+ ensure
+ tmpfile.close if !tmpfile.closed?
+ File.unlink tmpfile
+ end
+ else
+ tmpfile
+ end
+end
View
7 lib/ruby/1.9/tmpdir.rb → lib/ruby/shared/tmpdir.rb
@@ -11,6 +11,7 @@
end
class Dir
+ @@using_19 = Hash.respond_to? :try_convert
@@systmpdir ||= defined?(Etc.systmpdir) ? Etc.systmpdir : '/tmp'
@@ -28,13 +29,13 @@ def Dir::tmpdir
# Opening directory is not allowed in Java.
dirs = [ENV['TMPDIR'], ENV['TMP'], ENV['TEMP'], @@systmpdir, '/tmp', tmp]
for dir in dirs
- if dir and stat = File.stat(dir) and stat.directory? and stat.writable? and !stat.world_writable?
+ if dir and stat = File.stat(dir) and stat.directory? and stat.writable? and !(@@using_19 && stat.world_writable?)
return File.expand_path(dir)
end
end
# Some OS sets the environment variables to '/tmp', which we may reject.
- warn "Unable to find a non world-writable directory for #{__method__}. Consider setting ENV['TMPDIR'], ENV['TMP'] or ENV['TEMP'] to a non world-writable directory."
+ warn "Unable to find a non world-writable directory for Dir::tmpdir. Consider setting ENV['TMPDIR'], ENV['TMP'] or ENV['TEMP'] to a non world-writable directory."
for dir in dirs
if dir and stat = File.stat(dir) and stat.directory? and stat.writable?
@@ -128,7 +129,7 @@ def make_tmpname(prefix_suffix, n)
end
def create(basename, *rest)
- if opts = Hash.try_convert(rest[-1])
+ if Hash.respond_to?(:try_convert) && opts = Hash.try_convert(rest[-1])
opts = opts.dup if rest.pop.equal?(opts)
max_try = opts.delete(:max_try)
opts = [opts]
View
2 src/org/jruby/Ruby.java
@@ -1617,7 +1617,7 @@ private void initBuiltins() {
addLazyBuiltin("rbconfig.rb", "rbconfig", "org.jruby.ext.rbconfig.RbConfigLibrary");
addLazyBuiltin("jruby/serialization.rb", "serialization", "org.jruby.ext.jruby.JRubySerializationLibrary");
addLazyBuiltin("ffi-internal.jar", "ffi-internal", "org.jruby.ext.ffi.FFIService");
- addLazyBuiltin("tempfile.rb", "tempfile", "org.jruby.ext.tempfile.TempfileLibrary");
+ addLazyBuiltin("tempfile.jar", "tempfile", "org.jruby.ext.tempfile.TempfileLibrary");
addLazyBuiltin("fcntl.rb", "fcntl", "org.jruby.ext.fcntl.FcntlLibrary");
addLazyBuiltin("rubinius.jar", "rubinius", "org.jruby.ext.rubinius.RubiniusLibrary");
addLazyBuiltin("yecht.jar", "yecht", "YechtService");
View
67 src/org/jruby/RubyTempfile.java
@@ -1,67 +0,0 @@
-/*
- ***** BEGIN LICENSE BLOCK *****
- * Version: EPL 1.0/GPL 2.0/LGPL 2.1
- *
- * The contents of this file are subject to the Eclipse Public
- * License Version 1.0 (the "License"); you may not use this file
- * except in compliance with the License. You may obtain a copy of
- * the License at http://www.eclipse.org/legal/epl-v10.html
- *
- * Software distributed under the License is distributed on an "AS
- * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
- * implied. See the License for the specific language governing
- * rights and limitations under the License.
- *
- * Copyright (C) 2004-2009 Thomas E Enebo <enebo@acm.org>
- *
- * Alternatively, the contents of this file may be used under the terms of
- * either of the GNU General Public License Version 2 or later (the "GPL"),
- * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
- * in which case the provisions of the GPL or the LGPL are applicable instead
- * of those above. If you wish to allow use of your version of this file only
- * under the terms of either the GPL or the LGPL, and not to allow others to
- * use your version of this file under the terms of the EPL, indicate your
- * decision by deleting the provisions above and replace them with the notice
- * and other provisions required by the GPL or the LGPL. If you do not delete
- * the provisions above, a recipient may use your version of this file under
- * the terms of any one of the EPL, the GPL or the LGPL.
- ***** END LICENSE BLOCK *****/
-package org.jruby;
-
-import org.jruby.ext.tempfile.*;
-
-import org.jruby.anno.JRubyClass;
-import org.jruby.runtime.Block;
-import org.jruby.runtime.ThreadContext;
-import org.jruby.runtime.builtin.IRubyObject;
-
-/**
- * A temporary stub superclass installed to handle existing code that references
- * "RubyTempfile" directly.
- */
-@JRubyClass(name="Tempfile", parent="File")
-public abstract class RubyTempfile extends RubyFile {
- public static RubyClass createTempfileClass(Ruby runtime) {
- return Tempfile.createTempfileClass(runtime);
- }
-
- // This should only be called by this and RubyFile.
- // It allows this object to be created without a IOHandler.
- public RubyTempfile(Ruby runtime, RubyClass type) {
- super(runtime, type);
- }
-
- @Override
- public abstract IRubyObject initialize(IRubyObject[] args, Block block);
- public abstract IRubyObject make_tmpname(ThreadContext context, IRubyObject basename, IRubyObject n, Block block);
- public abstract IRubyObject open();
- public abstract IRubyObject _close(ThreadContext context);
- public abstract IRubyObject close(ThreadContext context, IRubyObject[] args, Block block);
- public abstract IRubyObject close_bang(ThreadContext context);
- public abstract IRubyObject unlink(ThreadContext context);
- @Override
- public abstract IRubyObject size(ThreadContext context);
- public static IRubyObject open(ThreadContext context, IRubyObject recv, IRubyObject[] args, Block block) {
- return Tempfile.open(context, recv, args, block);
- }
-}
View
284 src/org/jruby/ext/tempfile/Tempfile.java
@@ -30,44 +30,32 @@
import java.io.File;
import java.io.IOException;
-import java.util.Arrays;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ConcurrentMap;
import org.jruby.CompatVersion;
import org.jruby.Ruby;
-import org.jruby.RubyArray;
import org.jruby.RubyClass;
import org.jruby.RubyFile;
import org.jruby.RubyFixnum;
import org.jruby.RubyHash;
-import org.jruby.RubyKernel;
import org.jruby.anno.JRubyClass;
import org.jruby.anno.JRubyMethod;
-import org.jruby.platform.Platform;
+import org.jruby.runtime.Arity;
import org.jruby.runtime.Block;
+import org.jruby.runtime.BlockCallback;
+import org.jruby.runtime.CallBlock19;
import org.jruby.runtime.ObjectAllocator;
import org.jruby.runtime.ThreadContext;
import static org.jruby.runtime.Visibility.*;
import org.jruby.runtime.builtin.IRubyObject;
-import org.jruby.util.JRubyFile;
-import org.jruby.util.PhantomReferenceReaper;
import org.jruby.util.io.EncodingUtils;
import org.jruby.util.io.IOOptions;
import org.jruby.util.io.ModeFlags;
-import org.jruby.util.io.OpenFile;
/**
* An implementation of tempfile.rb in Java.
*/
@JRubyClass(name="Tempfile", parent="File")
-public class Tempfile extends org.jruby.RubyTempfile {
-
- /** Keep strong references to the Reaper until cleanup */
- private static final ConcurrentMap<Reaper, Boolean> referenceSet
- = new ConcurrentHashMap<Reaper, Boolean>();
- private transient volatile Reaper reaper;
-
+public class Tempfile extends org.jruby.RubyFile {
private static ObjectAllocator TEMPFILE_ALLOCATOR = new ObjectAllocator() {
@Override
public IRubyObject allocate(Ruby runtime, RubyClass klass) {
@@ -80,32 +68,13 @@ public IRubyObject allocate(Ruby runtime, RubyClass klass) {
public static RubyClass createTempfileClass(Ruby runtime) {
RubyClass tempfileClass = runtime.defineClass("Tempfile", runtime.getFile(), TEMPFILE_ALLOCATOR);
- RubyKernel.require(tempfileClass, runtime.newString("tmpdir"), Block.NULL_BLOCK);
-
tempfileClass.defineAnnotatedMethods(Tempfile.class);
return tempfileClass;
}
- private final static String DEFAULT_TMP_DIR;
- private static final Object tmpFileLock = new Object();
- private static int counter = -1;
- private final static java.util.Random RND = new java.util.Random();
-
- static {
- String tmpDir;
- if (Platform.IS_WINDOWS) {
- tmpDir = System.getProperty("java.io.tmpdir");
- if (tmpDir == null) tmpDir = System.getenv("TEMP");
- if (tmpDir == null) tmpDir = System.getenv("TMP");
- if (tmpDir == null) tmpDir = "C:\\Windows\\Temp";
- } else {
- tmpDir = "/tmp";
- }
- DEFAULT_TMP_DIR = tmpDir;
- }
-
private File tmpFile = null;
+ protected IRubyObject opts;
// This should only be called by this and RubyFile.
// It allows this object to be created without a IOHandler.
@@ -116,164 +85,79 @@ public Tempfile(Ruby runtime, RubyClass type) {
@JRubyMethod(required = 1, optional = 1, visibility = PRIVATE, compat = CompatVersion.RUBY1_8)
@Override
public IRubyObject initialize(IRubyObject[] args, Block block) {
- Ruby runtime = getRuntime();
- IRubyObject basename = args[0];
- IRubyObject dir = defaultTmpDir(runtime, args);
-
- File tmp;
- synchronized(tmpFileLock) {
- while (true) {
- try {
- if (counter == -1) {
- counter = RND.nextInt() & 0xffff;
- }
- counter++;
-
- // We do this b/c make_tmpname might be overridden
- IRubyObject tmpname = callMethod(runtime.getCurrentContext(),
- "make_tmpname", new IRubyObject[] {basename, runtime.newFixnum(counter)});
- tmp = JRubyFile.create(getRuntime().getCurrentDirectory(),
- new File(dir.convertToString().toString(), tmpname.convertToString().toString()).getPath());
- if (tmp.createNewFile()) {
- tmpFile = tmp;
- path = tmp.getPath();
- try {
- tmpFile.deleteOnExit();
- } catch (NullPointerException npe) {
- // See JRUBY-4624.
- // Due to JDK bug, NPE could be thrown
- // when shutdown is in progress.
- // Do nothing.
- } catch (IllegalStateException ise) {
- // do nothing, shutdown in progress
- }
- initializeOpen();
- referenceSet.put(reaper = new Reaper(this, runtime, tmpFile, openFile), Boolean.TRUE);
- return this;
- }
- } catch (IOException e) {
- throw runtime.newIOErrorFromException(e);
- }
- }
- }
+ return initializeCommon(getRuntime().getCurrentContext(), args);
}
@JRubyMethod(required = 1, optional = 2, visibility = PRIVATE, compat = CompatVersion.RUBY1_9)
@Override
public IRubyObject initialize19(ThreadContext context, IRubyObject[] args, Block block) {
- Ruby runtime = getRuntime();
- RubyHash options = null;
-
- // check for trailing hash
- if (args.length > 1) {
- if (args[args.length - 1] instanceof RubyHash) {
- options = (RubyHash)args[args.length - 1];
- args = Arrays.copyOfRange(args, 0, args.length - 1);
- }
- }
-
- IOOptions ioOptions = newIOOptions(runtime, ModeFlags.RDWR | ModeFlags.EXCL);
-
- if (options != null) {
- ioOptions = updateIOOptionsFromOptions(context, options, ioOptions);
- EncodingUtils.getEncodingOptionFromObject(context, this, options);
-
- }
+ return initializeCommon(context, args);
+ }
+
+ private IRubyObject initializeCommon(ThreadContext context, IRubyObject[] args) {
+ BlockCallback body = new TempfileCallback();
- IRubyObject basename = args[0];
- IRubyObject dir = defaultTmpDir(runtime, args);
-
- File tmp;
- synchronized(tmpFileLock) {
- while (true) {
- try {
- if (counter == -1) {
- counter = RND.nextInt() & 0xffff;
+ // #create and #make_tmpname come from Dir::Tmpname, included into
+ // tempfile in lib/ruby/shared/tempfile.rb. We use create here to
+ // match filename algorithm and allow them to be overridden.
+ callMethod(context, "create", args, CallBlock19.newCallClosure(this, this.getMetaClass(), Arity.OPTIONAL, body, context));
+
+ return context.nil;
+ }
+
+ private class TempfileCallback implements BlockCallback {
+ @Override
+ public IRubyObject call(ThreadContext context, IRubyObject[] args, Block block) {
+ Ruby runtime = context.runtime;
+
+ IRubyObject tmpname = args[0];
+ IOOptions ioOptions = newIOOptions(runtime, ModeFlags.RDWR | ModeFlags.EXCL);
+
+ if (context.is19) {
+ // check for trailing hash
+ if (args.length > 1) {
+ if (args[args.length - 1] instanceof RubyHash) {
+ // TODO: encoding options do not appear to actually get passed through to file init logic
+ RubyHash options = (RubyHash)args[args.length - 1];
+ ioOptions = updateIOOptionsFromOptions(context, options, ioOptions);
+ EncodingUtils.getEncodingOptionFromObject(context, Tempfile.this, options);
}
- counter++;
+ }
+ }
- // We do this b/c make_tmpname might be overridden
- IRubyObject tmpname = callMethod(runtime.getCurrentContext(),
- "make_tmpname", new IRubyObject[] {basename, runtime.newFixnum(counter)});
- tmp = JRubyFile.create(getRuntime().getCurrentDirectory(),
- new File(dir.convertToString().toString(), tmpname.convertToString().toString()).getPath());
- if (tmp.createNewFile()) {
- tmpFile = tmp;
- path = tmp.getPath();
- try {
- tmpFile.deleteOnExit();
- } catch (NullPointerException npe) {
- // See JRUBY-4624.
- // Due to JDK bug, NPE could be thrown
- // when shutdown is in progress.
- // Do nothing.
- } catch (IllegalStateException ise) {
- // do nothing, shutdown in progress
- }
- runtime.getPosix().chmod(path, 0600);
- sysopenInternal(path, ioOptions.getModeFlags(), 0600);
- referenceSet.put(reaper = new Reaper(this, runtime, tmpFile, openFile), Boolean.TRUE);
- return this;
+ try {
+ File tmp = new File(tmpname.convertToString().toString());
+ if (tmp.createNewFile()) {
+ tmpFile = tmp;
+ path = tmp.getPath();
+ try {
+ tmpFile.deleteOnExit();
+ } catch (NullPointerException npe) {
+ // See JRUBY-4624.
+ // Due to JDK bug, NPE could be thrown
+ // when shutdown is in progress.
+ // Do nothing.
+ } catch (IllegalStateException ise) {
+ // do nothing, shutdown in progress
}
- } catch (IOException e) {
- throw runtime.newIOErrorFromException(e);
+ initializeOpen(ioOptions);
+ } else {
+ throw context.runtime.newErrnoEEXISTError(path);
}
+ } catch (IOException e) {
+ throw context.runtime.newIOErrorFromException(e);
}
- }
- }
- private IRubyObject defaultTmpDir(Ruby runtime, IRubyObject[] args) {
- IRubyObject dir;
- if (args.length == 2) {
- dir = args[1];
- } else {
- // Dir::tmpdir
- runtime.getLoadService().require("tmpdir");
- dir = runtime.getDir().callMethod(runtime.getCurrentContext(), "tmpdir");
+ return context.nil;
}
-
- return dir;
}
- private void initializeOpen() {
- Ruby runtime = getRuntime();
-
- IOOptions ioOptions = newIOOptions(runtime, ModeFlags.RDWR | ModeFlags.EXCL);
+ private void initializeOpen(IOOptions ioOptions) {
getRuntime().getPosix().chmod(path, 0600);
sysopenInternal(path, ioOptions.getModeFlags(), 0600);
}
- /**
- * Compatibility with Tempfile#make_tmpname(basename, n) in MRI
- */
- @JRubyMethod(visibility = PRIVATE)
- @Override
- public IRubyObject make_tmpname(ThreadContext context, IRubyObject basename, IRubyObject n, Block block) {
- Ruby runtime = context.runtime;
- IRubyObject[] newargs = new IRubyObject[5];
-
- IRubyObject base, suffix;
- if (basename instanceof RubyArray) {
- RubyArray array = (RubyArray) basename;
- int length = array.getLength();
-
- base = length > 0 ? array.eltInternal(0) : runtime.getNil();
- suffix = length > 0 ? array.eltInternal(1) : runtime.getNil();
- } else {
- base = basename;
- suffix = runtime.newString("");
- }
-
- newargs[0] = runtime.newString("%s.%d.%d%s");
- newargs[1] = base;
- newargs[2] = runtime.getGlobalVariables().get("$$"); // PID
- newargs[3] = n;
- newargs[4] = suffix;
- return callMethod(context, "sprintf", newargs);
- }
-
@JRubyMethod(visibility = PUBLIC)
- @Override
public IRubyObject open() {
if (!isClosed()) close();
@@ -283,37 +167,29 @@ public IRubyObject open() {
}
@JRubyMethod(visibility = PROTECTED)
- @Override
public IRubyObject _close(ThreadContext context) {
return !isClosed() ? super.close() : context.runtime.getNil();
}
@JRubyMethod(optional = 1, visibility = PUBLIC)
- @Override
public IRubyObject close(ThreadContext context, IRubyObject[] args, Block block) {
boolean unlink = args.length == 1 ? args[0].isTrue() : false;
return unlink ? close_bang(context) : _close(context);
}
@JRubyMethod(name = "close!", visibility = PUBLIC)
- @Override
public IRubyObject close_bang(ThreadContext context) {
- referenceSet.remove(reaper);
- reaper.released = true;
_close(context);
tmpFile.delete();
return context.runtime.getNil();
}
@JRubyMethod(name = {"unlink", "delete"})
- @Override
public IRubyObject unlink(ThreadContext context) {
// JRUBY-6688: delete when closed, warn otherwise
if (isClosed()) {
// the user intends to delete the file immediately, so do it
if (!tmpFile.exists() || tmpFile.delete()) {
- referenceSet.remove(reaper);
- reaper.released = true;
path = null;
}
} else {
@@ -388,48 +264,4 @@ public IRubyObject inspect() {
val.append(">");
return getRuntime().newString(val.toString());
}
-
- // FIXME This reaper never actually runs; delete it or implement it properly
- // For JRUBY-6477, I add the finalize above to do basically what this was
- // intended to do.
- private static final class Reaper extends PhantomReferenceReaper<Tempfile> implements Runnable {
- private volatile boolean released = false;
- private final Ruby runtime;
- private final File tmpFile;
- private final OpenFile openFile;
-
- Reaper(Tempfile file, Ruby runtime, File tmpFile, OpenFile openFile) {
- super(file);
- this.runtime = runtime;
- this.tmpFile = tmpFile;
- this.openFile = openFile;
- }
-
- @Override
- public final void run() {
- referenceSet.remove(this);
- release();
- clear();
- }
-
- final void release() {
- if (!released) {
- released = true;
- if (openFile != null) {
- openFile.cleanup(runtime, false);
- }
- if (tmpFile.exists()) {
- boolean deleted = tmpFile.delete();
- if (runtime.getDebug().isTrue()) {
- String msg = "removing " + tmpFile.getPath() + " ... ";
- if (deleted) {
- runtime.getErr().println(msg + "done");
- } else {
- runtime.getErr().println(msg + "can't delete");
- }
- }
- }
- }
- }
- }
}

0 comments on commit 607c6d5

Please sign in to comment.
Something went wrong with that request. Please try again.