diff --git a/lib/paperclip/io_adapters/abstract_adapter.rb b/lib/paperclip/io_adapters/abstract_adapter.rb index 17f41ed56..a31515c37 100644 --- a/lib/paperclip/io_adapters/abstract_adapter.rb +++ b/lib/paperclip/io_adapters/abstract_adapter.rb @@ -58,12 +58,18 @@ def copy_to_tempfile(src) def link_or_copy_file(src, dest) Paperclip.log("Trying to link #{src} to #{dest}") - FileUtils.ln(src, dest, force: true) # overwrite existing + + begin + FileUtils.ln(src, dest, force: true) # overwrite existing + rescue Errno::EXDEV, Errno::EPERM, Errno::ENOENT, Errno::EEXIST => e + Paperclip.log( + "Link failed with #{e.message}; copying link #{src} to #{dest}", + ) + FileUtils.cp(src, dest) + end + @destination.close @destination.open.binmode - rescue Errno::EXDEV, Errno::EPERM, Errno::ENOENT, Errno::EEXIST => e - Paperclip.log("Link failed with #{e.message}; copying link #{src} to #{dest}") - FileUtils.cp(src, dest) end end end diff --git a/spec/paperclip/io_adapters/abstract_adapter_spec.rb b/spec/paperclip/io_adapters/abstract_adapter_spec.rb index 6186b3beb..4d21733b5 100644 --- a/spec/paperclip/io_adapters/abstract_adapter_spec.rb +++ b/spec/paperclip/io_adapters/abstract_adapter_spec.rb @@ -98,4 +98,39 @@ def content_type expect { subject.original_filename = nil }.not_to raise_error end end + + context "#link_or_copy_file" do + class TestLinkOrCopyAdapter < Paperclip::AbstractAdapter + public :copy_to_tempfile, :destination + end + + subject { TestLinkOrCopyAdapter.new(nil) } + let(:body) { "body" } + + let(:file) do + t = Tempfile.new("destination") + t.print(body) + t.rewind + t + end + + after do + file.close + file.unlink + end + + it "should be able to read the file" do + expect(subject.copy_to_tempfile(file).read).to eq(body) + end + + it "should be able to reopen the file after symlink has failed" do + FileUtils.expects(:ln).raises(Errno::EXDEV) + # after the failed symlink the file reports a size of zero + # which makes it necessary to reopen it + # we simulate this condition by closing the file + subject.destination.close + + expect(subject.copy_to_tempfile(file).read).to eq(body) + end + end end