Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What can go wrong with file.renameTo(file) in Android

I'm reading the documentation of renameTo(File) in the File.class of the Android SDK doc.

We've been using this method for a while in production, still I have been wondering what are the possible things that can go wrong. The documentation says

Renames this file to newPath. This operation is supported for both files and directories.

Many failures are possible. Some of the more likely failures include:

  • Write permission is required on the directories containing both the source and destination paths.

  • Search permission is required for all parents of both paths.

  • Both paths be on the same mount point. On Android, applications are most likely to hit this restriction when attempting to copy between internal storage and an SD card. Note that this method does not throw IOException on failure. Callers must check the return value.

What are other possible reasons why renameTo() might fail (referring to more likely failures)? Is there a guaranteed state after calling renameTo? When renameTo() fails, can I rely on having still my original file? Any other conditions I want to check to uber sure that it works beside the described ones from the docs?

like image 973
philipp Avatar asked Aug 21 '13 23:08

philipp


3 Answers

The three that are listed are the more likely failures. Less likely (but possible!) failures include

  • user error (e.g. source is a file and destination is an existing directory, or vice versa)
  • no space left on device
  • file system mounted read-only
  • corrupt file system
  • bad sector on rotational disk
  • ...

As Android is based on Linux you can probably rely on these though:

  • if rename fails both files are left as they were
  • if the destination file exists, and rename succeeds, at no point will any process find the destination file missing (the replacement is atomic)
like image 111
Joni Avatar answered Nov 07 '22 23:11

Joni


In Android File.renameTo calls Linux rename() (via libcore). You can check POSIX standard for the list of possible failures, it may be slightly different on Linux, but should give you general idea.

Also note this statement:

If the rename() function fails for any reason other than [EIO], any file named by new shall be unaffected.

like image 41
msh Avatar answered Nov 08 '22 00:11

msh


For the reason that I don't know, it's not possible to use file.rename() to move files between to different mounted directory in Android (like sdcard0 and sdcard1), here is my solution and it work for me:

if(canRename(f1, f2)) {
    if(!f1.renameTo(f2)) {
        Log.e(TAG, "Error to move new app: " + f1 + " > " + f2);
    }
} else {
    try {
        copy(f1, f2);
        f1.delete();
    } catch (Exception ex) {
        Log.e(TAG, "Error to move new app: " + f1 + " > " + f2);
    }
}

private void copy(final File f1, final File f2) throws IOException {
    f2.createNewFile();

    final RandomAccessFile file1 = new RandomAccessFile(f1, "r");
    final RandomAccessFile file2 = new RandomAccessFile(f2, "rw");

    file2.getChannel().write(file1.getChannel().map(FileChannel.MapMode.READ_ONLY, 0, f1.length()));

    file1.close();
    file2.close();
}

private boolean canRename(final File f1, final File f2) {
    final String p1 = f1.getAbsolutePath().replaceAll("^(/mnt/|/)", "");
    final String p2 = f2.getAbsolutePath().replaceAll("^(/mnt/|/)", "");

    return p1.replaceAll("\\/\\w+", "").equals(p2.replaceAll("\\/\\w+", ""));
}
like image 34
user1079877 Avatar answered Nov 07 '22 23:11

user1079877