I found a bug in the VFS code for copying a file when the source and dest files are 
accessed through the same FTP session.  This creates a race condition between reading 
the source file and writing to the dest file (I think).

Anyway, you can check out the code comments enclosed.  I also added a unit test.  Let 
me know if it seems to make sense.
Index: vfs/src/java/org/apache/commons/vfs/provider/ftp/FtpFileObject.java
===================================================================
RCS file: 
/home/cvspublic/jakarta-commons-sandbox/vfs/src/java/org/apache/commons/vfs/provider/ftp/FtpFileObject.java,v

retrieving revision 1.9
diff -u -r1.9 FtpFileObject.java
--- vfs/src/java/org/apache/commons/vfs/provider/ftp/FtpFileObject.java 20 Nov 2002 
23:55:36 -0000      1.9
+++ vfs/src/java/org/apache/commons/vfs/provider/ftp/FtpFileObject.java 20 Jan 2003 
+21:16:34 -0000
@@ -60,6 +60,8 @@
 import org.apache.commons.net.ftp.FTPClient;
 import org.apache.commons.net.ftp.FTPFile;
 import org.apache.commons.vfs.FileName;
+import org.apache.commons.vfs.FileObject;
+import org.apache.commons.vfs.FileSelector;
 import org.apache.commons.vfs.FileSystemException;
 import org.apache.commons.vfs.FileType;
 import org.apache.commons.vfs.provider.AbstractFileObject;
@@ -75,7 +77,7 @@
 {
     private static final FTPFile[] EMPTY_FTP_FILE_ARRAY = {};
 
-    private final FtpFileSystem ftpFs;
+    private FtpFileSystem ftpFs;
     private final String relPath;
 
     // Cached info
@@ -91,6 +93,60 @@
         ftpFs = fileSystem;
         relPath = rootName.getRelativeName( name );
     }
+
+       /**
+        * Copies another file, and all its descendents, to this file.
+        *
+        * If this file does not exist, it is created.  Its parent folder is also
+        * created, if necessary.  If this file does exist, it is deleted first.
+        *
+        * <p>This method is not transactional.  If it fails and throws an
+        * exception, this file will potentially only be partially copied.
+        *
+        * @param file The source file to copy.
+        * @param selector The selector to use to select which files to copy.
+        *
+        * @throws FileSystemException
+        *      If this file is read-only, or if the source file does not exist,
+        *      or on error copying the file.
+        */
+       public void copyFrom( final FileObject file, final FileSelector selector )
+               throws FileSystemException      {
+               
+               // We override copyFrom here for the specific case where the source 
+               // and destination files in the copy are from the same FTPFileSystem.  
+
+               // The problem is this can't be done through one FTP session
+               // concurrently( I think it creates a race condition) So we 
+               // temporarily create a new one just for use during this copy
+               // and then return everything to the way it was afterward.
+               
+               // if we're copying to and from the same FileSystem
+               if ( file.getFileSystem().equals( this.getFileSystem() ) ) {
+                       
+                       FtpFileNameParser parser = new FtpFileNameParser();
+
+                       // save the old file system for later
+                       FtpFileSystem oldFs = this.ftpFs;
+                       
+                       // create a new file system for use temporarily
+                       FtpUri uri = parser.parseFtpUri( this.getURL().toString() );
+                       this.ftpFs = new FtpFileSystem( oldFs.getRoot().getName(),
+                                                                                      
+  uri.getHostName(),
+                                                                                      
+  uri.getUserName(),
+                                                                                      
+  uri.getPassword() ); 
+
+                       // use our parent's copy functionality
+                       super.copyFrom( file, selector );
+                       
+                       // return the filesystem to the way it was
+                       this.ftpFs.close();
+                       this.ftpFs = oldFs;
+               }
+               // otherwise proceed normally
+               else {
+                       super.copyFrom( file, selector );
+               }
+       }
 
     /**
      * Called by child file objects, to locate their ftp file info.
Index: vfs/src/test/org/apache/commons/vfs/test/ProviderWriteTests.java
===================================================================
RCS file: 
/home/cvspublic/jakarta-commons-sandbox/vfs/src/test/org/apache/commons/vfs/test/ProviderWriteTests.java,v

retrieving revision 1.4
diff -u -r1.4 ProviderWriteTests.java
--- vfs/src/test/org/apache/commons/vfs/test/ProviderWriteTests.java    23 Nov 2002 
00:41:10 -0000      1.4
+++ vfs/src/test/org/apache/commons/vfs/test/ProviderWriteTests.java    20 Jan 2003 
+21:16:34 -0000
@@ -55,6 +55,7 @@
  */
 package org.apache.commons.vfs.test;
 
+import java.io.DataOutputStream;
 import java.io.OutputStream;
 import java.util.ArrayList;
 import java.util.HashSet;
@@ -446,4 +447,42 @@
             assertEquals( "Missing event", 0, events.size() );
         }
     }
+
+       /**
+        * Tests file copy to and from the same filesystem type.  This was a problem
+        * w/ FTP.  
+        * 
+        * @see org.apache.commons.vfs.provider.ftp.FtpFileObject#copyFrom
+        * (FileObject, FileSelector)
+        */
+       public void testFileCopySameFileSystem() throws Exception
+       {
+               FileObject scratchFolder = createScratchFolder();
+
+               // Create direct child of the test folder
+               FileObject file = scratchFolder.resolveFile( "file1.txt" );
+               assertTrue( !file.exists() );
+               file.createFile();
+               assertTrue( file.exists() );
+               assertSame( FileType.FILE, file.getType() );
+               assertEquals( 0, file.getContent().getSize() );
+
+               // add content to the file
+               DataOutputStream os = null;
+               try {
+                       os = new DataOutputStream( file.getContent().getOutputStream() 
+);
+                       os.writeChars( "Here is some sample content for the file.  
+Blah Blah Blah." );
+               }
+               finally {
+                       os.close();
+               }
+               
+               // make sure we can copy the new file to another file on the same 
+filesystem
+               FileObject fileCopy = scratchFolder.resolveFile( "file1copy.txt" );
+               assertTrue( !fileCopy.exists() );
+               fileCopy.copyFrom( file, Selectors.SELECT_SELF );
+               assertTrue( fileCopy.exists() );
+
+       }
+
 }
--
To unsubscribe, e-mail:   <mailto:[EMAIL PROTECTED]>
For additional commands, e-mail: <mailto:[EMAIL PROTECTED]>

Reply via email to