Date: Tue, 15 Nov 2005 08:30:54 -0800 (PST) From: Virgil Champlin <champlin@stupidog.org> To: FreeBSD-gnats-submit@FreeBSD.org Subject: ports/89077: The port lang/ruby18 upgrade to 1.8.3 has a flaw in the file rename function. Message-ID: <20051115163054.25D91238B@whisper.stupidog.org> Resent-Message-ID: <200511151640.jAFGeOc9064119@freefall.freebsd.org>
next in thread | raw e-mail | index | archive | help
>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@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:
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20051115163054.25D91238B>