1 /* 2 * [The "BSD licence"] 3 * Copyright (c) 2010 Ben Gruver 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. The name of the author may not be used to endorse or promote products 14 * derived from this software without specific prior written permission. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 * INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 */ 27 28 package com.android.tools.smali.util; 29 30 import com.google.common.collect.Lists; 31 32 import java.io.File; 33 import java.io.FileNotFoundException; 34 import java.io.FileReader; 35 import java.io.FileWriter; 36 import java.io.IOException; 37 import java.nio.CharBuffer; 38 import java.util.ArrayList; 39 import java.util.List; 40 41 public class PathUtil { PathUtil()42 private PathUtil() { 43 } 44 getRelativeFile(File baseFile, File fileToRelativize)45 public static File getRelativeFile(File baseFile, File fileToRelativize) throws IOException { 46 if (baseFile.isFile()) { 47 baseFile = baseFile.getParentFile(); 48 } 49 50 return new File(getRelativeFileInternal(baseFile.getCanonicalFile(), fileToRelativize.getCanonicalFile())); 51 } 52 getRelativeFileInternal(File canonicalBaseFile, File canonicalFileToRelativize)53 static String getRelativeFileInternal(File canonicalBaseFile, File canonicalFileToRelativize) { 54 List<String> basePath = getPathComponents(canonicalBaseFile); 55 List<String> pathToRelativize = getPathComponents(canonicalFileToRelativize); 56 57 //if the roots aren't the same (i.e. different drives on a windows machine), we can't construct a relative 58 //path from one to the other, so just return the canonical file 59 if (!basePath.get(0).equals(pathToRelativize.get(0))) { 60 return canonicalFileToRelativize.getPath(); 61 } 62 63 int commonDirs; 64 StringBuilder sb = new StringBuilder(); 65 66 for (commonDirs=1; commonDirs<basePath.size() && commonDirs<pathToRelativize.size(); commonDirs++) { 67 if (!basePath.get(commonDirs).equals(pathToRelativize.get(commonDirs))) { 68 break; 69 } 70 } 71 72 boolean first = true; 73 for (int i=commonDirs; i<basePath.size(); i++) { 74 if (!first) { 75 sb.append(File.separatorChar); 76 } else { 77 first = false; 78 } 79 80 sb.append(".."); 81 } 82 83 first = true; 84 for (int i=commonDirs; i<pathToRelativize.size(); i++) { 85 if (first) { 86 if (sb.length() != 0) { 87 sb.append(File.separatorChar); 88 } 89 first = false; 90 } else { 91 sb.append(File.separatorChar); 92 } 93 94 sb.append(pathToRelativize.get(i)); 95 } 96 97 if (sb.length() == 0) { 98 return "."; 99 } 100 101 return sb.toString(); 102 } 103 getPathComponents(File file)104 private static List<String> getPathComponents(File file) { 105 ArrayList<String> path = new ArrayList<String>(); 106 107 while (file != null) { 108 File parentFile = file.getParentFile(); 109 110 if (parentFile == null) { 111 path.add(file.getPath()); 112 } else { 113 path.add(file.getName()); 114 } 115 116 file = parentFile; 117 } 118 119 return Lists.reverse(path); 120 } 121 testCaseSensitivity(File path)122 public static boolean testCaseSensitivity(File path) throws IOException { 123 int num = 1; 124 File f, f2; 125 do { 126 f = new File(path, "test." + num); 127 f2 = new File(path, "TEST." + num++); 128 } while(f.exists() || f2.exists()); 129 130 try { 131 try { 132 FileWriter writer = new FileWriter(f); 133 writer.write("test"); 134 writer.flush(); 135 writer.close(); 136 } catch (IOException ex) { 137 try {f.delete();} catch (Exception ex2) {} 138 throw ex; 139 } 140 141 if (f2.exists()) { 142 return false; 143 } 144 145 if (f2.createNewFile()) { 146 return true; 147 } 148 149 //the above 2 tests should catch almost all cases. But maybe there was a failure while creating f2 150 //that isn't related to case sensitivity. Let's see if we can open the file we just created using 151 //f2 152 try { 153 CharBuffer buf = CharBuffer.allocate(32); 154 FileReader reader = new FileReader(f2); 155 156 while (reader.read(buf) != -1 && buf.length() < 4); 157 if (buf.length() == 4 && buf.toString().equals("test")) { 158 return false; 159 } else { 160 //we probably shouldn't get here. If the filesystem was case-sensetive, creating a new 161 //FileReader should have thrown a FileNotFoundException. Otherwise, we should have opened 162 //the file and read in the string "test". It's remotely possible that someone else modified 163 //the file after we created it. Let's be safe and return false here as well 164 assert(false); 165 return false; 166 } 167 } catch (FileNotFoundException ex) { 168 return true; 169 } 170 } finally { 171 try { f.delete(); } catch (Exception ex) {} 172 try { f2.delete(); } catch (Exception ex) {} 173 } 174 } 175 } 176