1 /* 2 * Copyright (C) 2012 Google, Inc. 3 * 4 * This library is free software; you can redistribute it and/or modify it 5 * under the terms of the GNU Lesser General Public License as published 6 * by the Free Software Foundation; either version 2.1 of the License, or 7 * (at your option) any later version. 8 * 9 * This library is distributed in the hope that it will be useful, but 10 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 11 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 12 * License for more details. 13 * 14 * You should have received a copy of the GNU Lesser General Public License 15 * along with this library; If not, write to the Free Software Foundation, Inc., 16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 */ 18 19 package de.waldheinz.fs.fat; 20 21 import java.security.SecureRandom; 22 23 /** 24 * Generates dummy 8.3 buffers that are associated with the long names. 25 * 26 * @author Daniel Galpin <dgalpin@google.com> based upon the work of 27 * Andrew Tridgell <tridge@samba.org> 28 */ 29 final class Dummy83BufferGenerator { 30 final SecureRandom mRandom; 31 32 /** 33 * Creates a new instance of {@code Dummy83BufferGenerator} that uses 34 * randomness only to avoid short name collisions. 35 */ Dummy83BufferGenerator()36 public Dummy83BufferGenerator() { 37 mRandom = new SecureRandom(); 38 } 39 40 /* 41 * Its in the DOS manual!(DOS 5: page 72) Valid: A..Z 0..9 _ ^ $ ~ ! # % & - {} () @ ' ` 42 * 43 * Invalid: spaces/periods, 44 */ validChar(char toTest)45 public static boolean validChar(char toTest) { 46 if (toTest >= 'A' && toTest <= 'Z') return true; 47 if (toTest >= 'a' && toTest <= 'z') return true; 48 if (toTest >= '0' && toTest <= '9') return true; 49 if (toTest == '_' || toTest == '^' || toTest == '$' || toTest == '~' || 50 toTest == '!' || toTest == '#' || toTest == '%' || toTest == '&' || 51 toTest == '-' || toTest == '{' || toTest == '}' || toTest == '(' || 52 toTest == ')' || toTest == '@' || toTest == '\'' || toTest == '`') 53 return true; 54 55 return false; 56 } 57 isSkipChar(char c)58 public static boolean isSkipChar(char c) { 59 return (c == '.') || (c == ' '); 60 } 61 tidyString(String dirty)62 public static String tidyString(String dirty) { 63 final StringBuilder result = new StringBuilder(); 64 65 /* epurate it from alien characters */ 66 for (int src=0; src < dirty.length(); src++) { 67 final char toTest = Character.toUpperCase(dirty.charAt(src)); 68 if (isSkipChar(toTest)) continue; 69 70 if (validChar(toTest)) { 71 result.append(toTest); 72 } else { 73 result.append('_'); 74 } 75 } 76 77 return result.toString(); 78 } 79 cleanString(String s)80 public static boolean cleanString(String s) { 81 for (int i=0; i < s.length(); i++) { 82 if (isSkipChar(s.charAt(i))) return false; 83 if (!validChar(s.charAt(i))) return false; 84 } 85 86 return true; 87 } 88 stripLeadingPeriods(String str)89 public static String stripLeadingPeriods(String str) { 90 final StringBuilder sb = new StringBuilder(str.length()); 91 92 for (int i=0; i < str.length(); i++) { 93 if (str.charAt(i) != '.') { //NOI18N 94 sb.append(str.substring(i)); 95 break; 96 } 97 } 98 99 return sb.toString(); 100 } /* 101 * These characters are all invalid in 8.3 names, plus have been shown to be 102 * harmless on all tested devices 103 */ 104 static final private char[] invalidchar = { 105 (char) 0x01, (char) 0x02, (char) 0x03, (char) 0x04, (char) 0x05, (char) 0x06, 106 (char) 0x0B, 107 (char) 0x0C, (char) 0x0E, (char) 0x0F, (char) 0x10, (char) 0x11, (char) 0x12, 108 (char) 0x13, 109 (char) 0x14, (char) 0x15, (char) 0x16, (char) 0x17, (char) 0x18, (char) 0x19, 110 (char) 0x1A, 111 (char) 0x1B, (char) 0x1C, (char) 0x1D, (char) 0x1E, (char) 0x1F, (char) 0x22, 112 (char) 0x2a, 113 (char) 0x3a, (char) 0x3c, (char) 0x3e, (char) 0x3f, (char) 0x5b, (char) 0x5d, 114 (char) 0x7c 115 }; 116 117 /** 118 * See original C Linux patch by Andrew Tridgell <tridge@samba.org> 119 * build a 11 byte 8.3 buffer which is not a short filename. We want 11 120 * bytes which: - will be seen as a constant string to all APIs on Linux and 121 * Windows - cannot be matched with wildcard patterns - cannot be used to 122 * access the file - has a low probability of collision within a directory - 123 * has an invalid 3 byte extension - contains at least one non-space and 124 * non-nul byte 125 * 126 * @param longFullName the long file name to generate the buffer for 127 * @return the generated 8.3 buffer 128 */ generate83BufferNew(String longFullName)129 public ShortName generate83BufferNew(String longFullName) 130 throws IllegalStateException { 131 132 char[] retBuffer = new char[11]; 133 134 boolean hasRealShortName = false;// getRealShortNameInstead(longFullName, 135 // retBuffer); 136 if (!hasRealShortName) { 137 int i, tilde_pos, slash_pos; 138 int randomNumber = Math.abs(mRandom.nextInt()); 139 140 /* 141 * the '/' makes sure that even unpatched Linux systems can't get at 142 * files by the 8.3 entry. 143 */ 144 145 slash_pos = randomNumber % 8; 146 randomNumber >>= 3; 147 148 /* 149 * fill in the first 8 bytes with invalid characters. Note that we 150 * need to be careful not to run out of randomness. We use the same 151 * extension for all buffers. 152 */ 153 for (i = 0; i < 8; i++) { 154 if (i == slash_pos) 155 retBuffer[i] = '/'; 156 else { 157 retBuffer[i] = 158 invalidchar[randomNumber % invalidchar.length]; 159 randomNumber /= invalidchar.length; 160 if (randomNumber < invalidchar.length) 161 randomNumber = Math.abs(mRandom.nextInt()); 162 } 163 } 164 165 for ( i = 0; i < 8; i ++ ) { 166 if (retBuffer[i] == 0xe5) { 167 throw new RuntimeException(); 168 } 169 } 170 171 retBuffer[8] = 'i'; 172 retBuffer[9] = 'f'; 173 retBuffer[10] = 'l'; 174 } 175 ShortName retName = new ShortName(retBuffer); 176 retName.setHasShortNameOnly(hasRealShortName); 177 return retName; 178 } 179 180 } 181