Commit f53fc03c authored by Skylot's avatar Skylot

core: use dynamic check for filesystem case-sensitivity (#158)

parent 9278c510
......@@ -4,7 +4,7 @@ dependencies {
runtime files(jadxClasspath)
compile files('lib/dx-1.13.jar')
compile 'commons-io:commons-io:2.4'
compile 'commons-io:commons-io:2.6'
compile 'org.ow2.asm:asm:5.0.3'
compile 'com.intellij:annotations:12.0'
compile 'uk.com.robust-it:cloning:1.9.2'
......
package jadx.core.dex.visitors;
import java.io.File;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.apache.commons.io.FilenameUtils;
import jadx.api.IJadxArgs;
import jadx.core.Consts;
import jadx.core.codegen.TypeGen;
......@@ -15,20 +22,11 @@ import jadx.core.dex.nodes.FieldNode;
import jadx.core.dex.nodes.MethodNode;
import jadx.core.dex.nodes.RootNode;
import jadx.core.utils.exceptions.JadxException;
import jadx.core.utils.files.FileUtils;
import jadx.core.utils.files.InputFile;
import java.io.File;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.io.IOCase;
public class RenameVisitor extends AbstractVisitor {
private static final boolean CASE_SENSITIVE_FS = IOCase.SYSTEM.isCaseSensitive();
private Deobfuscator deobfuscator;
@Override
......@@ -36,7 +34,7 @@ public class RenameVisitor extends AbstractVisitor {
IJadxArgs args = root.getArgs();
List<DexNode> dexNodes = root.getDexNodes();
if (dexNodes.size() == 0) {
if (dexNodes.isEmpty()) {
return;
}
InputFile firstInputFile = dexNodes.get(0).getDexFile().getInputFile();
......@@ -50,7 +48,8 @@ public class RenameVisitor extends AbstractVisitor {
if (deobfuscationOn) {
deobfuscator.execute();
}
checkClasses(root);
boolean isCaseSensitive = FileUtils.isCaseSensitiveFS(new File(inputPath)); // args.getOutDir() - not set in gui
checkClasses(root, isCaseSensitive);
}
@Override
......@@ -63,11 +62,11 @@ public class RenameVisitor extends AbstractVisitor {
return false;
}
private void checkClasses(RootNode root) {
private void checkClasses(RootNode root, boolean caseSensitive) {
Set<String> clsNames = new HashSet<>();
for (ClassNode cls : root.getClasses(true)) {
checkClassName(cls);
if (!CASE_SENSITIVE_FS) {
if (!caseSensitive) {
ClassInfo classInfo = cls.getClassInfo();
String clsFileName = classInfo.getAlias().getFullPath();
if (!clsNames.add(clsFileName.toLowerCase())) {
......
......@@ -40,8 +40,8 @@ public class ExportGradleProject {
public void init() {
try {
FileUtils.makeDirsForFile(srcOutDir);
FileUtils.makeDirsForFile(resOutDir);
FileUtils.makeDirs(srcOutDir);
FileUtils.makeDirs(resOutDir);
saveBuildGradle();
skipGeneratedClasses();
} catch (Exception e) {
......
package jadx.core.utils.files;
import jadx.core.utils.exceptions.JadxRuntimeException;
import java.io.BufferedInputStream;
import java.io.Closeable;
import java.io.File;
......@@ -18,10 +16,14 @@ import java.util.jar.JarOutputStream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import org.apache.commons.io.IOCase;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import jadx.core.utils.exceptions.JadxRuntimeException;
public class FileUtils {
private static final Logger LOG = LoggerFactory.getLogger(FileUtils.class);
......@@ -43,12 +45,19 @@ public class FileUtils {
}
public static void makeDirsForFile(File file) {
File dir = file.getParentFile();
if (dir != null && !dir.exists()) {
// if directory already created in other thread mkdirs will return false,
// so check dir existence again
if (!dir.mkdirs() && !dir.exists()) {
throw new JadxRuntimeException("Can't create directory " + dir);
if (file != null) {
makeDirs(file.getParentFile());
}
}
private static final Object MKDIR_SYNC = new Object();
public static void makeDirs(@Nullable File dir) {
if (dir != null) {
synchronized (MKDIR_SYNC) {
if (!dir.exists() && !dir.mkdirs()) {
throw new JadxRuntimeException("Can't create directory " + dir);
}
}
}
}
......@@ -186,4 +195,32 @@ public class FileUtils {
}
}
}
public static boolean isCaseSensitiveFS(File testDir) {
if (testDir != null) {
File caseCheckUpper = new File(testDir, "CaseCheck");
File caseCheckLow = new File(testDir, "casecheck");
try {
makeDirs(testDir);
if (caseCheckUpper.createNewFile()) {
boolean caseSensitive = !caseCheckLow.exists();
LOG.debug("Filesystem at {} is {} case-sensitive", testDir.getAbsolutePath(),
(caseSensitive ? "" : "NOT"));
return caseSensitive;
} else {
LOG.debug("Failed to create file: {}", caseCheckUpper.getAbsolutePath());
}
} catch (Exception e) {
LOG.debug("Failed to detect filesystem case-sensitivity by file creation", e);
} finally {
try {
caseCheckUpper.delete();
caseCheckLow.delete();
} catch (Exception e) {
// ignore
}
}
}
return IOCase.SYSTEM.isCaseSensitive();
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment