You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cordova.apache.org by ag...@apache.org on 2015/03/11 16:35:22 UTC

[11/13] cordova-plugin-file git commit: CB-6428 android: Add support for directory copies from assets -> filesystem

CB-6428 android: Add support for directory copies from assets -> filesystem


Project: http://git-wip-us.apache.org/repos/asf/cordova-plugin-file/repo
Commit: http://git-wip-us.apache.org/repos/asf/cordova-plugin-file/commit/072acc73
Tree: http://git-wip-us.apache.org/repos/asf/cordova-plugin-file/tree/072acc73
Diff: http://git-wip-us.apache.org/repos/asf/cordova-plugin-file/diff/072acc73

Branch: refs/heads/master
Commit: 072acc733182c4736421e1a516706844e37747e0
Parents: 7051ad3
Author: Andrew Grieve <ag...@chromium.org>
Authored: Tue Mar 10 22:43:14 2015 -0400
Committer: Andrew Grieve <ag...@chromium.org>
Committed: Wed Mar 11 11:35:08 2015 -0400

----------------------------------------------------------------------
 src/android/AssetFilesystem.java |   2 +-
 src/android/Filesystem.java      |   7 +-
 src/android/LocalFilesystem.java | 279 ++++++++++------------------------
 tests/tests.js                   |  34 +++++
 4 files changed, 119 insertions(+), 203 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cordova-plugin-file/blob/072acc73/src/android/AssetFilesystem.java
----------------------------------------------------------------------
diff --git a/src/android/AssetFilesystem.java b/src/android/AssetFilesystem.java
index 40968e0..c1c0d6f 100644
--- a/src/android/AssetFilesystem.java
+++ b/src/android/AssetFilesystem.java
@@ -211,7 +211,7 @@ public class AssetFilesystem extends Filesystem {
     }
 
     @Override
-    boolean recursiveRemoveFileAtLocalURL(LocalFilesystemURL inputURL) throws FileExistsException, NoModificationAllowedException {
+    boolean recursiveRemoveFileAtLocalURL(LocalFilesystemURL inputURL) throws NoModificationAllowedException {
         throw new NoModificationAllowedException("Assets are read-only");
     }
 

http://git-wip-us.apache.org/repos/asf/cordova-plugin-file/blob/072acc73/src/android/Filesystem.java
----------------------------------------------------------------------
diff --git a/src/android/Filesystem.java b/src/android/Filesystem.java
index 309c0b8..45047c8 100644
--- a/src/android/Filesystem.java
+++ b/src/android/Filesystem.java
@@ -198,7 +198,7 @@ public abstract class Filesystem {
 		return getEntryForLocalURL(LocalFilesystemURL.parse(parentUri));
 	}
 
-    protected LocalFilesystemURL makeDestinationURL(String newName, LocalFilesystemURL srcURL, LocalFilesystemURL destURL) {
+    protected LocalFilesystemURL makeDestinationURL(String newName, LocalFilesystemURL srcURL, LocalFilesystemURL destURL, boolean isDirectory) {
         // I know this looks weird but it is to work around a JSON bug.
         if ("null".equals(newName) || "".equals(newName)) {
             newName = srcURL.uri.getLastPathSegment();;
@@ -210,6 +210,9 @@ public abstract class Filesystem {
         } else {
             newDest = newDest + "/" + newName;
         }
+        if (isDirectory) {
+            newDest += '/';
+        }
         return LocalFilesystemURL.parse(newDest);
     }
 
@@ -224,7 +227,7 @@ public abstract class Filesystem {
         if (move && !srcFs.canRemoveFileAtLocalURL(srcURL)) {
             throw new NoModificationAllowedException("Cannot move file at source URL");
         }
-        final LocalFilesystemURL destination = makeDestinationURL(newName, srcURL, destURL);
+        final LocalFilesystemURL destination = makeDestinationURL(newName, srcURL, destURL, srcURL.isDirectory);
 
         Uri srcNativeUri = srcFs.toNativeUri(srcURL);
 

http://git-wip-us.apache.org/repos/asf/cordova-plugin-file/blob/072acc73/src/android/LocalFilesystem.java
----------------------------------------------------------------------
diff --git a/src/android/LocalFilesystem.java b/src/android/LocalFilesystem.java
index 93ba2b0..cc0ff57 100644
--- a/src/android/LocalFilesystem.java
+++ b/src/android/LocalFilesystem.java
@@ -20,17 +20,12 @@ package org.apache.cordova.file;
 
 import java.io.ByteArrayInputStream;
 import java.io.File;
-import java.io.FileInputStream;
 import java.io.FileNotFoundException;
 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.RandomAccessFile;
 import java.nio.channels.FileChannel;
-import java.util.ArrayList;
-import java.util.Arrays;
-
 import org.apache.cordova.CordovaResourceApi;
-import org.json.JSONArray;
 import org.json.JSONException;
 import org.json.JSONObject;
 
@@ -263,182 +258,72 @@ public class LocalFilesystem extends Filesystem {
         return metadata;
 	}
 
-    /**
-     * Check to see if the user attempted to copy an entry into its parent without changing its name,
-     * or attempted to copy a directory into a directory that it contains directly or indirectly.
-     */
-    private boolean isCopyOnItself(String src, String dest) {
-
-        // This weird test is to determine if we are copying or moving a directory into itself.
-        // Copy /sdcard/myDir to /sdcard/myDir-backup is okay but
-        // Copy /sdcard/myDir to /sdcard/myDir/backup should throw an INVALID_MODIFICATION_ERR
-        return dest.equals(src) || dest.startsWith(src + File.separator);
-    }
-
-    /**
-     * Copy a file
-     *
-     * @param srcFile file to be copied
-     * @param destFile destination to be copied to
-     * @return a FileEntry object
-     * @throws IOException
-     * @throws InvalidModificationException
-     * @throws JSONException
-     */
-    private JSONObject copyFile(File srcFile, File destFile) throws IOException, InvalidModificationException, JSONException {
-        // Renaming a file to an existing directory should fail
-        if (destFile.exists() && destFile.isDirectory()) {
-            throw new InvalidModificationException("Can't rename a file to a directory");
+    private void copyFile(Filesystem srcFs, LocalFilesystemURL srcURL, File destFile, boolean move) throws IOException, InvalidModificationException, NoModificationAllowedException {
+        if (move) {
+            String realSrcPath = srcFs.filesystemPathForURL(srcURL);
+            if (realSrcPath != null) {
+                File srcFile = new File(realSrcPath);
+                if (srcFile.renameTo(destFile)) {
+                    return;
+                }
+                // Trying to rename the file failed.  Possibly because we moved across file system on the device.
+            }
         }
 
-        copyAction(srcFile, destFile);
-
-        return makeEntryForFile(destFile);
-    }
-
-    /**
-     * Moved this code into it's own method so moveTo could use it when the move is across file systems
-     */
-    private void copyAction(File srcFile, File destFile)
-            throws FileNotFoundException, IOException {
-        FileInputStream istream = new FileInputStream(srcFile);
-        FileOutputStream ostream = new FileOutputStream(destFile);
-        FileChannel input = istream.getChannel();
-        FileChannel output = ostream.getChannel();
+        CordovaResourceApi.OpenForReadResult offr = resourceApi.openForRead(srcFs.toNativeUri(srcURL));
+        resourceApi.copyResource(offr, new FileOutputStream(destFile));
 
-        try {
-            input.transferTo(0, input.size(), output);
-        } finally {
-            istream.close();
-            ostream.close();
-            input.close();
-            output.close();
+        if (move) {
+            srcFs.removeFileAtLocalURL(srcURL);
         }
     }
 
-    /**
-     * Copy a directory
-     *
-     * @param srcDir directory to be copied
-     * @param destinationDir destination to be copied to
-     * @return a DirectoryEntry object
-     * @throws JSONException
-     * @throws IOException
-     * @throws NoModificationAllowedException
-     * @throws InvalidModificationException
-     */
-    private JSONObject copyDirectory(File srcDir, File destinationDir) throws JSONException, IOException, NoModificationAllowedException, InvalidModificationException {
-        // Renaming a file to an existing directory should fail
-        if (destinationDir.exists() && destinationDir.isFile()) {
-            throw new InvalidModificationException("Can't rename a file to a directory");
-        }
-
-        // Check to make sure we are not copying the directory into itself
-        if (isCopyOnItself(srcDir.getAbsolutePath(), destinationDir.getAbsolutePath())) {
-            throw new InvalidModificationException("Can't copy itself into itself");
+    private void copyDirectory(Filesystem srcFs, LocalFilesystemURL srcURL, File dstDir, boolean move) throws IOException, NoModificationAllowedException, InvalidModificationException, FileExistsException {
+        if (move) {
+            String realSrcPath = srcFs.filesystemPathForURL(srcURL);
+            if (realSrcPath != null) {
+                File srcDir = new File(realSrcPath);
+                // If the destination directory already exists and is empty then delete it.  This is according to spec.
+                if (dstDir.exists()) {
+                    if (dstDir.list().length > 0) {
+                        throw new InvalidModificationException("directory is not empty");
+                    }
+                    dstDir.delete();
+                }
+                // Try to rename the directory
+                if (srcDir.renameTo(dstDir)) {
+                    return;
+                }
+                // Trying to rename the file failed.  Possibly because we moved across file system on the device.
+            }
         }
 
-        // See if the destination directory exists. If not create it.
-        if (!destinationDir.exists()) {
-            if (!destinationDir.mkdir()) {
+        if (dstDir.exists()) {
+            if (dstDir.list().length > 0) {
+                throw new InvalidModificationException("directory is not empty");
+            }
+        } else {
+            if (!dstDir.mkdir()) {
                 // If we can't create the directory then fail
                 throw new NoModificationAllowedException("Couldn't create the destination directory");
             }
         }
-        
 
-        for (File file : srcDir.listFiles()) {
-            File destination = new File(destinationDir.getAbsoluteFile() + File.separator + file.getName());
-            if (file.isDirectory()) {
-                copyDirectory(file, destination);
+        LocalFilesystemURL[] children = srcFs.listChildren(srcURL);
+        for (LocalFilesystemURL childLocalUrl : children) {
+            File target = new File(dstDir, new File(childLocalUrl.path).getName());
+            if (childLocalUrl.isDirectory) {
+                copyDirectory(srcFs, childLocalUrl, target, false);
             } else {
-                copyFile(file, destination);
+                copyFile(srcFs, childLocalUrl, target, false);
             }
         }
 
-        return makeEntryForFile(destinationDir);
-    }
-
-    /**
-     * Move a file
-     *
-     * @param srcFile file to be copied
-     * @param destFile destination to be copied to
-     * @return a FileEntry object
-     * @throws IOException
-     * @throws InvalidModificationException
-     * @throws JSONException
-     */
-    private JSONObject moveFile(File srcFile, File destFile) throws IOException, JSONException, InvalidModificationException {
-        // Renaming a file to an existing directory should fail
-        if (destFile.exists() && destFile.isDirectory()) {
-            throw new InvalidModificationException("Can't rename a file to a directory");
-        }
-
-        // Try to rename the file
-        if (!srcFile.renameTo(destFile)) {
-            // Trying to rename the file failed.  Possibly because we moved across file system on the device.
-            // Now we have to do things the hard way
-            // 1) Copy all the old file
-            // 2) delete the src file
-            copyAction(srcFile, destFile);
-            if (destFile.exists()) {
-                srcFile.delete();
-            } else {
-                throw new IOException("moved failed");
-            }
+        if (move) {
+            srcFs.recursiveRemoveFileAtLocalURL(srcURL);
         }
-
-        return makeEntryForFile(destFile);
     }
 
-    /**
-     * Move a directory
-     *
-     * @param srcDir directory to be copied
-     * @param destinationDir destination to be copied to
-     * @return a DirectoryEntry object
-     * @throws JSONException
-     * @throws IOException
-     * @throws InvalidModificationException
-     * @throws NoModificationAllowedException
-     * @throws FileExistsException
-     */
-    private JSONObject moveDirectory(File srcDir, File destinationDir) throws IOException, JSONException, InvalidModificationException, NoModificationAllowedException, FileExistsException {
-        // Renaming a file to an existing directory should fail
-        if (destinationDir.exists() && destinationDir.isFile()) {
-            throw new InvalidModificationException("Can't rename a file to a directory");
-        }
-
-        // Check to make sure we are not copying the directory into itself
-        if (isCopyOnItself(srcDir.getAbsolutePath(), destinationDir.getAbsolutePath())) {
-            throw new InvalidModificationException("Can't move itself into itself");
-        }
-
-        // If the destination directory already exists and is empty then delete it.  This is according to spec.
-        if (destinationDir.exists()) {
-            if (destinationDir.list().length > 0) {
-                throw new InvalidModificationException("directory is not empty");
-            }
-        }
-
-        // Try to rename the directory
-        if (!srcDir.renameTo(destinationDir)) {
-            // Trying to rename the directory failed.  Possibly because we moved across file system on the device.
-            // Now we have to do things the hard way
-            // 1) Copy all the old files
-            // 2) delete the src directory
-            copyDirectory(srcDir, destinationDir);
-            if (destinationDir.exists()) {
-                removeDirRecursively(srcDir);
-            } else {
-                throw new IOException("moved failed");
-            }
-        }
-
-        return makeEntryForFile(destinationDir);
-    }
-	
 	@Override
 	public JSONObject copyFileToURL(LocalFilesystemURL destURL, String newName,
 			Filesystem srcFs, LocalFilesystemURL srcURL, boolean move) throws IOException, InvalidModificationException, JSONException, NoModificationAllowedException, FileExistsException {
@@ -451,45 +336,39 @@ public class LocalFilesystem extends Filesystem {
             throw new FileNotFoundException("The source does not exist");
         }
         
-	    if (LocalFilesystem.class.isInstance(srcFs)) {
-	        /* Same FS, we can shortcut with NSFileManager operations */
-
-            // Figure out where we should be copying to
-            final LocalFilesystemURL destinationURL = makeDestinationURL(newName, srcURL, destURL);
-
-	        String srcFilesystemPath = srcFs.filesystemPathForURL(srcURL);
-            File sourceFile = new File(srcFilesystemPath);
-            String destFilesystemPath = this.filesystemPathForURL(destinationURL);
-            File destinationFile = new File(destFilesystemPath);
-
-            if (!sourceFile.exists()) {
-	            // The file/directory we are copying doesn't exist so we should fail.
-	            throw new FileNotFoundException("The source does not exist");
-	        }
-
-	        // Check to see if source and destination are the same file
-            if (sourceFile.getAbsolutePath().equals(destinationFile.getAbsolutePath())) {
-	            throw new InvalidModificationException("Can't copy a file onto itself");
-	        }
-
-            if (sourceFile.isDirectory()) {
-	            if (move) {
-                    return moveDirectory(sourceFile, destinationFile);
-	            } else {
-                    return copyDirectory(sourceFile, destinationFile);
-	            }
-	        } else {
-	            if (move) {
-                    return moveFile(sourceFile, destinationFile);
-	            } else {
-                    return copyFile(sourceFile, destinationFile);
-	            }
-	        }
-	    	
-	    } else {
-	        // Need to copy the hard way
-            return super.copyFileToURL(destURL, newName, srcFs, srcURL, move);
-    	}
+        // Figure out where we should be copying to
+        final LocalFilesystemURL destinationURL = makeDestinationURL(newName, srcURL, destURL, srcURL.isDirectory);
+
+        Uri dstNativeUri = toNativeUri(destinationURL);
+        Uri srcNativeUri = srcFs.toNativeUri(srcURL);
+        // Check to see if source and destination are the same file
+        if (dstNativeUri.equals(srcNativeUri)) {
+            throw new InvalidModificationException("Can't copy onto itself");
+        }
+
+        if (move && !srcFs.canRemoveFileAtLocalURL(srcURL)) {
+            throw new InvalidModificationException("Source URL is read-only (cannot move)");
+        }
+
+        File destFile = new File(dstNativeUri.getPath());
+        if (destFile.exists()) {
+            if (!srcURL.isDirectory && destFile.isDirectory()) {
+                throw new InvalidModificationException("Can't copy/move a file to an existing directory");
+            } else if (srcURL.isDirectory && destFile.isFile()) {
+                throw new InvalidModificationException("Can't copy/move a directory to an existing file");
+            }
+        }
+
+        if (srcURL.isDirectory) {
+            // E.g. Copy /sdcard/myDir to /sdcard/myDir/backup
+            if (dstNativeUri.toString().startsWith(srcNativeUri.toString() + '/')) {
+                throw new InvalidModificationException("Can't copy directory into itself");
+            }
+            copyDirectory(srcFs, srcURL, destFile, move);
+        } else {
+            copyFile(srcFs, srcURL, destFile, move);
+        }
+        return makeEntryForURL(destinationURL);
 	}
     
 	@Override

http://git-wip-us.apache.org/repos/asf/cordova-plugin-file/blob/072acc73/tests/tests.js
----------------------------------------------------------------------
diff --git a/tests/tests.js b/tests/tests.js
index 5735af1..239a0d3 100644
--- a/tests/tests.js
+++ b/tests/tests.js
@@ -3480,6 +3480,40 @@ exports.defineAutoTests = function () {
                     }, transfer);
                 });
             });
+            it("file.spec.144 copyTo: asset directory", function (done) {
+                var srcUrl = 'file:///android_asset/www/plugins/org.apache.cordova.file';
+                var dstDir = "entry.copy.dstDir";
+                var dstPath = joinURL(root.fullPath, dstDir);
+                // create a new directory entry to kick off it
+                deleteEntry(dstDir, function () {
+                    resolveLocalFileSystemURL(srcUrl, function(directory) {
+                        directory.copyTo(root, dstDir, function (directory) {
+                            expect(directory).toBeDefined();
+                            expect(directory.isFile).toBe(false);
+                            expect(directory.isDirectory).toBe(true);
+                            expect(directory.fullPath).toCanonicallyMatch(dstPath);
+                            expect(directory.name).toCanonicallyMatch(dstDir);
+                            root.getDirectory(dstDir, {
+                                create : false
+                            }, function (dirEntry) {
+                                expect(dirEntry).toBeDefined();
+                                expect(dirEntry.isFile).toBe(false);
+                                expect(dirEntry.isDirectory).toBe(true);
+                                expect(dirEntry.fullPath).toCanonicallyMatch(dstPath);
+                                expect(dirEntry.name).toCanonicallyMatch(dstDir);
+                                dirEntry.getFile('www/File.js', {
+                                    create : false
+                                }, function (fileEntry) {
+                                    expect(fileEntry).toBeDefined();
+                                    expect(fileEntry.isFile).toBe(true);
+                                    // cleanup
+                                    deleteEntry(dstDir, done);
+                                }, failed.bind(null, done, 'dirEntry.getFile - Error getting subfile'));
+                            }, failed.bind(null, done, 'root.getDirectory - Error getting copied directory'));
+                        }, failed.bind(null, done, 'directory.copyTo - Error copying directory'));
+                    }, failed.bind(null, done, 'resolving src dir'));
+                }, failed.bind(null, done, 'deleteEntry - Error removing directory : ' + dstDir));
+            });
         }
     });
 


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@cordova.apache.org
For additional commands, e-mail: commits-help@cordova.apache.org