-
-
Notifications
You must be signed in to change notification settings - Fork 1.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Allow case sensitive local file rename #3593
Changes from 2 commits
e878230
8bc1656
b56b12b
73cf6a0
9a1b5ac
46a7a2a
5cb5d69
c54f3f2
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -441,6 +441,61 @@ public static void rename( | |
|
||
private final DataUtils dataUtils = DataUtils.getInstance(); | ||
|
||
private final Boolean isCaseSensitiveRename = | ||
!oldFile.getSimpleName().equals(newFile.getSimpleName()) | ||
&& oldFile.getSimpleName().equalsIgnoreCase(newFile.getSimpleName()); | ||
|
||
// random string that is appended to file to prevent name collision, max file name is 255 | ||
// bytes | ||
private static final String TEMP_FILE_EXT = "u0CtHRqWUnvxIaeBQ@nY2umVm9MDyR1P"; | ||
|
||
private boolean localRename(@NonNull HybridFile oldFile, @NonNull HybridFile newFile) { | ||
File file = new File(oldFile.getPath()); | ||
File file1 = new File(newFile.getPath()); | ||
boolean result = false; | ||
|
||
switch (oldFile.getMode()) { | ||
case FILE: | ||
int mode = checkFolder(file.getParentFile(), context); | ||
if (mode == 2) { | ||
errorCallBack.launchSAF(oldFile, newFile); | ||
stevealexr marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} else if (mode == 1 || mode == 0) { | ||
try { | ||
RenameOperation.renameFolder(file, file1, context); | ||
result = true; | ||
} catch (ShellNotRunningException e) { | ||
LOG.warn("failed to rename file in local filesystem", e); | ||
} | ||
boolean a = !file.exists() && file1.exists(); | ||
if (!a && rootMode) { | ||
try { | ||
RenameFileCommand.INSTANCE.renameFile(file.getPath(), file1.getPath()); | ||
result = true; | ||
} catch (ShellNotRunningException e) { | ||
LOG.warn("failed to rename file in local filesystem", e); | ||
} | ||
oldFile.setMode(OpenMode.ROOT); | ||
newFile.setMode(OpenMode.ROOT); | ||
a = !file.exists() && file1.exists(); | ||
} | ||
errorCallBack.done(newFile, a); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Need a fallback mechanism in case the second rename fails, fallback should attempt to rename back to original file name. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I added a simple check that attempt to rename back to original file name once, not sure if it is sufficient. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks, changes seem fine. It would be a good practice to LOG.warn the inner else condition in case second rename fails. Check warning on line 673 in app/src/main/java/com/amaze/filemanager/filesystem/Operations.java Codacy Production There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I added a log message and combined those if statements. |
||
} | ||
break; | ||
case ROOT: | ||
try { | ||
RenameFileCommand.INSTANCE.renameFile(file.getPath(), file1.getPath()); | ||
result = true; | ||
} catch (ShellNotRunningException e) { | ||
LOG.warn("failed to rename file in root", e); | ||
} | ||
|
||
newFile.setMode(OpenMode.ROOT); | ||
errorCallBack.done(newFile, true); | ||
break; | ||
} | ||
return result; | ||
} | ||
|
||
private Function<DocumentFile, Void> safRenameFile = | ||
input -> { | ||
boolean result = false; | ||
|
@@ -462,7 +517,7 @@ protected Void doInBackground(Void... params) { | |
return null; | ||
} | ||
|
||
if (newFile.exists()) { | ||
if (newFile.exists() && !isCaseSensitiveRename) { | ||
errorCallBack.exists(newFile); | ||
return null; | ||
} | ||
|
@@ -610,44 +665,18 @@ public Boolean executeWithFtpClient(@NonNull FTPClient ftpClient) | |
false)); | ||
return null; | ||
} else { | ||
File file = new File(oldFile.getPath()); | ||
File file1 = new File(newFile.getPath()); | ||
switch (oldFile.getMode()) { | ||
case FILE: | ||
int mode = checkFolder(file.getParentFile(), context); | ||
if (mode == 2) { | ||
errorCallBack.launchSAF(oldFile, newFile); | ||
} else if (mode == 1 || mode == 0) { | ||
try { | ||
RenameOperation.renameFolder(file, file1, context); | ||
} catch (ShellNotRunningException e) { | ||
LOG.warn("failed to rename file in local filesystem", e); | ||
} | ||
boolean a = !file.exists() && file1.exists(); | ||
if (!a && rootMode) { | ||
try { | ||
RenameFileCommand.INSTANCE.renameFile(file.getPath(), file1.getPath()); | ||
} catch (ShellNotRunningException e) { | ||
LOG.warn("failed to rename file in local filesystem", e); | ||
} | ||
oldFile.setMode(OpenMode.ROOT); | ||
newFile.setMode(OpenMode.ROOT); | ||
a = !file.exists() && file1.exists(); | ||
} | ||
errorCallBack.done(newFile, a); | ||
return null; | ||
if (isCaseSensitiveRename) { | ||
HybridFile tempFile = | ||
new HybridFile(oldFile.mode, oldFile.getPath().concat(TEMP_FILE_EXT)); | ||
if (localRename(oldFile, tempFile)) { | ||
// stop if first rename failed | ||
if (!localRename(tempFile, newFile)) { | ||
// revert changes | ||
localRename(tempFile, oldFile); | ||
} | ||
break; | ||
case ROOT: | ||
try { | ||
RenameFileCommand.INSTANCE.renameFile(file.getPath(), file1.getPath()); | ||
} catch (ShellNotRunningException e) { | ||
LOG.warn("failed to rename file in root", e); | ||
} | ||
|
||
newFile.setMode(OpenMode.ROOT); | ||
errorCallBack.done(newFile, true); | ||
break; | ||
} | ||
} else { | ||
localRename(oldFile, newFile); | ||
} | ||
} | ||
return null; | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is the case sensitive rename different? Shouldn't there just be filesystems that support case sensitive renames and filesystems that do not? And the renames be the same function?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This approach only cares about the value changed and not the type of filesystem. Although it does unnecessary double renaming in case-sensitive filesystem, it doesn't need to check the type of filesystem.
The 'localRename' function (can't think of a better name) is extracted from the original code to avoid code duplication.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this should be okay as we know for sure most file systems that android supports doesn't support case sensitivity (exception ext4 in which case it needs to be kernel enabled). But I think it would make a marginal performance improvement if second part of the AND condition in this is used first.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am more concerned on code legibility.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I added comment on the purpose of isCaseSensitiveRename variable and refactored double rename part. Hopefully it is clearer.