ports/89077: The port lang/ruby18 upgrade to 1.8.3 has a flaw in the file rename function.
Virgil Champlin
champlin at stupidog.org
Tue Nov 15 16:40:25 UTC 2005
>Number: 89077
>Category: ports
>Synopsis: The port lang/ruby18 upgrade to 1.8.3 has a flaw in the file rename function.
>Confidential: no
>Severity: non-critical
>Priority: low
>Responsible: freebsd-ports-bugs
>State: open
>Quarter:
>Keywords:
>Date-Required:
>Class: sw-bug
>Submitter-Id: current-users
>Arrival-Date: Tue Nov 15 16:40:24 GMT 2005
>Closed-Date:
>Last-Modified:
>Originator: Virgil Champlin
>Release: FreeBSD 5.4-RELEASE-p8 i386
>Organization:
Stupidog.org
>Environment:
System: FreeBSD eeyore.stupidog.org 5.4-RELEASE-p8 FreeBSD 5.4-RELEASE-p8 #21: Wed Oct 12 11:02:47 PDT 2005 root at whisper.stupidog.org:/usr/obj/usr/src/sys/STUPIDOG i386
/usr/local/lib/ruby/1.8/fileutils.rb
>Description:
The Ruby function to rename files, FileUtils.mv in lib/fileutils.rb,
does not remove (unlink) the source file when the source and destination
are on different file systems. This is new behavior.
>How-To-Repeat:
This is noticeable in the behavior of pkg_fetch, a function in the
dependent port, sysutils/portupgrade. When upgrading from remote
repository packages, pkg_fetch retrieves the prospective package to a
temporary directory created in PKG_TMPDIR. It then applies some sanity and moves
successful packages to the PACKAGES directory. The default for
PKG_TMPDIR is /var/tmp which in many cases will not be the same file
system as PACKAGES. The lingering original file will be noticed when a
subsequent removal of the temporary directory fails because it is not
empty. e.g.
** Could not clean up temporary directory: Directory not empty - /var/tmp/portupgradeaOSUjspd
This does not prevent the upgrade but will leave the temporary directory
and its lone file cluttering PKG_TMPDIR with each successful pkg_fetch.
You can easily demonstrate this with the assistance of Ruby's
interactive interpreter, irb. Create a small file on one file system; use
Ruby to rename it as another file on the same file system; then use Ruby
to rename it across a file system boundary. The second operation is
effectively a copy.
Bash> echo "Hello World" >foo.txt
Bash> irb -r fileutils
irb(main):001:0> FileUtils.mv "foo.txt", "foo1.txt"
=> 0
irb(main):002:0> FileUtils.mv "foo1.txt", "/tmp/foo2.txt"
=> nil
Bash> ls -l foo* /tmp/foo*
-rw-r--r-- 1 champlin champlin 12 Nov 12 22:15 /tmp/foo2.txt
-rw-r--r-- 1 champlin champlin 12 Nov 12 22:15 foo1.txt
>Fix:
This is noticeable in the behavior of pkg_fetch, a function in the
dependent port, sysutils/portupgrade. When upgrading from remote
repository packages, pkg_fetch retrieves the prospective package to a
temporary directory created in PKG_TMPDIR. It then applies some sanity and moves
successful packages to the PACKAGES directory. The default for
PKG_TMPDIR is /var/tmp which in many cases will not be the same file
system as PACKAGES. The lingering original file will be noticed when a
subsequent removal of the temporary directory fails because it is not
empty. e.g.
** Could not clean up temporary directory: Directory not empty - /var/tmp/portupgradeaOSUjspd
This does not prevent the upgrade but will leave the temporary directory
and its lone file cluttering PKG_TMPDIR with each successful pkg_fetch.
You can easily demonstrate this with the assistance of Ruby's
interactive interpreter, irb. Create a small file on one file system; use
Ruby to rename it as another file on the same file system; then use Ruby
to rename it across a file system boundary. The second operation is
effectively a copy.
Bash> echo "Hello World" >foo.txt
Bash> irb -r fileutils
irb(main):001:0> FileUtils.mv "foo.txt", "foo1.txt"
=> 0
irb(main):002:0> FileUtils.mv "foo1.txt", "/tmp/foo2.txt"
=> nil
Bash> ls -l foo* /tmp/foo*
-rw-r--r-- 1 champlin champlin 12 Nov 12 22:15 /tmp/foo2.txt
-rw-r--r-- 1 champlin champlin 12 Nov 12 22:15 foo1.txt
FIX
A commit for version 1.36.2.6 of fileutils.rb (ruby_1_8 branch) on Dec
27, 2004 removed the File.unlink that accompanied the special case of
crossing file system boundaries. It was actually propagating the change
from the MAIN branch and I could not determine the reason for its
removal. Restoring the File.unlink to FileUtils.mv restored the
expected behavior. You can view the cvs log, focused on 1.36.2.6 at:
http://www.ruby-lang.org/cgi-bin/cvsweb.cgi/ruby/lib/fileutils.rb#rev1.36.2.6
The following patch restores the unlink but should be reviewed by
someone that actually knows ruby.
--- /usr/local/lib/ruby/1.8/fileutils.rb.orig Tue Nov 15 08:08:48 2005
+++ /usr/local/lib/ruby/1.8/fileutils.rb Tue Nov 15 08:10:21 2005
@@ -500,7 +500,10 @@
begin
File.rename s, d
rescue Errno::EXDEV
- copy_entry s, d, true
+ begin
+ copy_entry s, d, true
+ File.unlink s
+ end
end
rescue SystemCallError
raise unless options[:force]
APOLOGY
This is way too verbose but I don't know how to tell a short story the
right way. It always comes out long so please forgive. I also wished
to submit this to the Ruby folks but couldn't quite figure out the
acceptable way. I am unfamiliar with Ruby and its culture so hoped that
the port maintainer would be kind enough to correct either myself or the
Ruby project. Thank you very much for your patience and wonderful
efforts. -virgil
>Release-Note:
>Audit-Trail:
>Unformatted:
More information about the freebsd-ports-bugs
mailing list