Loading core/java/android/content/pm/PackageParser.java +12 −7 Original line number Diff line number Diff line Loading @@ -36,6 +36,7 @@ import android.content.res.TypedArray; import android.content.res.XmlResourceParser; import android.os.Build; import android.os.Bundle; import android.os.FileUtils; import android.os.PatternMatcher; import android.os.UserHandle; import android.text.TextUtils; Loading Loading @@ -1194,7 +1195,8 @@ public class PackageParser { } } private static String validateName(String name, boolean requiresSeparator) { private static String validateName(String name, boolean requireSeparator, boolean requireFilename) { final int N = name.length(); boolean hasSep = false; boolean front = true; Loading @@ -1216,7 +1218,10 @@ public class PackageParser { } return "bad character '" + c + "'"; } return hasSep || !requiresSeparator if (requireFilename && !FileUtils.isValidExtFilename(name)) { return "Invalid filename"; } return hasSep || !requireSeparator ? null : "must have at least one '.' separator"; } Loading @@ -1240,7 +1245,7 @@ public class PackageParser { final String packageName = attrs.getAttributeValue(null, "package"); if (!"android".equals(packageName)) { final String error = validateName(packageName, true); final String error = validateName(packageName, true, true); if (error != null) { throw new PackageParserException(INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME, "Invalid manifest package: " + error); Loading @@ -1252,7 +1257,7 @@ public class PackageParser { if (splitName.length() == 0) { splitName = null; } else { final String error = validateName(splitName, false); final String error = validateName(splitName, false, false); if (error != null) { throw new PackageParserException(INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME, "Invalid manifest split: " + error); Loading Loading @@ -1391,7 +1396,7 @@ public class PackageParser { String str = sa.getNonConfigurationString( com.android.internal.R.styleable.AndroidManifest_sharedUserId, 0); if (str != null && str.length() > 0) { String nameError = validateName(str, true); String nameError = validateName(str, true, false); if (nameError != null && !"android".equals(pkgName)) { outError[0] = "<manifest> specifies bad sharedUserId name \"" + str + "\": " + nameError; Loading Loading @@ -1973,7 +1978,7 @@ public class PackageParser { return null; } String subName = proc.substring(1); String nameError = validateName(subName, false); String nameError = validateName(subName, false, false); if (nameError != null) { outError[0] = "Invalid " + type + " name " + proc + " in package " + pkg + ": " + nameError; Loading @@ -1981,7 +1986,7 @@ public class PackageParser { } return (pkg + proc).intern(); } String nameError = validateName(proc, true); String nameError = validateName(proc, true, false); if (nameError != null && !"system".equals(proc)) { outError[0] = "Invalid " + type + " name " + proc + " in package " + pkg + ": " + nameError; Loading core/java/android/os/FileUtils.java +26 −0 Original line number Diff line number Diff line Loading @@ -24,6 +24,8 @@ import android.util.Log; import android.util.Slog; import android.webkit.MimeTypeMap; import com.android.internal.annotations.VisibleForTesting; import java.io.BufferedInputStream; import java.io.ByteArrayOutputStream; import java.io.File; Loading @@ -34,6 +36,7 @@ import java.io.FileOutputStream; import java.io.FileWriter; import java.io.IOException; import java.io.InputStream; import java.nio.charset.StandardCharsets; import java.util.Arrays; import java.util.Comparator; import java.util.Objects; Loading Loading @@ -456,6 +459,7 @@ public class FileUtils { res.append('_'); } } trimFilename(res, 255); return res.toString(); } Loading Loading @@ -504,9 +508,31 @@ public class FileUtils { res.append('_'); } } // Even though vfat allows 255 UCS-2 chars, we might eventually write to // ext4 through a FUSE layer, so use that limit. trimFilename(res, 255); return res.toString(); } @VisibleForTesting public static String trimFilename(String str, int maxBytes) { final StringBuilder res = new StringBuilder(str); trimFilename(res, maxBytes); return res.toString(); } private static void trimFilename(StringBuilder res, int maxBytes) { byte[] raw = res.toString().getBytes(StandardCharsets.UTF_8); if (raw.length > maxBytes) { maxBytes -= 3; while (raw.length > maxBytes) { res.deleteCharAt(res.length() / 2); raw = res.toString().getBytes(StandardCharsets.UTF_8); } res.insert(res.length() / 2, "..."); } } public static String rewriteAfterRename(File beforeDir, File afterDir, String path) { if (path == null) return null; final File result = rewriteAfterRename(beforeDir, afterDir, new File(path)); Loading core/tests/coretests/src/android/os/FileUtilsTest.java +12 −0 Original line number Diff line number Diff line Loading @@ -232,6 +232,18 @@ public class FileUtilsTest extends AndroidTestCase { assertEquals("foo_bar__baz", FileUtils.buildValidFatFilename("foo?bar**baz")); } public void testTrimFilename() throws Exception { assertEquals("short.txt", FileUtils.trimFilename("short.txt", 16)); assertEquals("extrem...eme.txt", FileUtils.trimFilename("extremelylongfilename.txt", 16)); final String unicode = "a\u03C0\u03C0\u03C0\u03C0z"; assertEquals("a\u03C0\u03C0\u03C0\u03C0z", FileUtils.trimFilename(unicode, 10)); assertEquals("a\u03C0...\u03C0z", FileUtils.trimFilename(unicode, 9)); assertEquals("a...\u03C0z", FileUtils.trimFilename(unicode, 8)); assertEquals("a...\u03C0z", FileUtils.trimFilename(unicode, 7)); assertEquals("a...z", FileUtils.trimFilename(unicode, 6)); } public void testBuildUniqueFile_normal() throws Exception { assertNameEquals("test.jpg", FileUtils.buildUniqueFile(mTarget, "image/jpeg", "test")); assertNameEquals("test.jpg", FileUtils.buildUniqueFile(mTarget, "image/jpeg", "test.jpg")); Loading Loading
core/java/android/content/pm/PackageParser.java +12 −7 Original line number Diff line number Diff line Loading @@ -36,6 +36,7 @@ import android.content.res.TypedArray; import android.content.res.XmlResourceParser; import android.os.Build; import android.os.Bundle; import android.os.FileUtils; import android.os.PatternMatcher; import android.os.UserHandle; import android.text.TextUtils; Loading Loading @@ -1194,7 +1195,8 @@ public class PackageParser { } } private static String validateName(String name, boolean requiresSeparator) { private static String validateName(String name, boolean requireSeparator, boolean requireFilename) { final int N = name.length(); boolean hasSep = false; boolean front = true; Loading @@ -1216,7 +1218,10 @@ public class PackageParser { } return "bad character '" + c + "'"; } return hasSep || !requiresSeparator if (requireFilename && !FileUtils.isValidExtFilename(name)) { return "Invalid filename"; } return hasSep || !requireSeparator ? null : "must have at least one '.' separator"; } Loading @@ -1240,7 +1245,7 @@ public class PackageParser { final String packageName = attrs.getAttributeValue(null, "package"); if (!"android".equals(packageName)) { final String error = validateName(packageName, true); final String error = validateName(packageName, true, true); if (error != null) { throw new PackageParserException(INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME, "Invalid manifest package: " + error); Loading @@ -1252,7 +1257,7 @@ public class PackageParser { if (splitName.length() == 0) { splitName = null; } else { final String error = validateName(splitName, false); final String error = validateName(splitName, false, false); if (error != null) { throw new PackageParserException(INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME, "Invalid manifest split: " + error); Loading Loading @@ -1391,7 +1396,7 @@ public class PackageParser { String str = sa.getNonConfigurationString( com.android.internal.R.styleable.AndroidManifest_sharedUserId, 0); if (str != null && str.length() > 0) { String nameError = validateName(str, true); String nameError = validateName(str, true, false); if (nameError != null && !"android".equals(pkgName)) { outError[0] = "<manifest> specifies bad sharedUserId name \"" + str + "\": " + nameError; Loading Loading @@ -1973,7 +1978,7 @@ public class PackageParser { return null; } String subName = proc.substring(1); String nameError = validateName(subName, false); String nameError = validateName(subName, false, false); if (nameError != null) { outError[0] = "Invalid " + type + " name " + proc + " in package " + pkg + ": " + nameError; Loading @@ -1981,7 +1986,7 @@ public class PackageParser { } return (pkg + proc).intern(); } String nameError = validateName(proc, true); String nameError = validateName(proc, true, false); if (nameError != null && !"system".equals(proc)) { outError[0] = "Invalid " + type + " name " + proc + " in package " + pkg + ": " + nameError; Loading
core/java/android/os/FileUtils.java +26 −0 Original line number Diff line number Diff line Loading @@ -24,6 +24,8 @@ import android.util.Log; import android.util.Slog; import android.webkit.MimeTypeMap; import com.android.internal.annotations.VisibleForTesting; import java.io.BufferedInputStream; import java.io.ByteArrayOutputStream; import java.io.File; Loading @@ -34,6 +36,7 @@ import java.io.FileOutputStream; import java.io.FileWriter; import java.io.IOException; import java.io.InputStream; import java.nio.charset.StandardCharsets; import java.util.Arrays; import java.util.Comparator; import java.util.Objects; Loading Loading @@ -456,6 +459,7 @@ public class FileUtils { res.append('_'); } } trimFilename(res, 255); return res.toString(); } Loading Loading @@ -504,9 +508,31 @@ public class FileUtils { res.append('_'); } } // Even though vfat allows 255 UCS-2 chars, we might eventually write to // ext4 through a FUSE layer, so use that limit. trimFilename(res, 255); return res.toString(); } @VisibleForTesting public static String trimFilename(String str, int maxBytes) { final StringBuilder res = new StringBuilder(str); trimFilename(res, maxBytes); return res.toString(); } private static void trimFilename(StringBuilder res, int maxBytes) { byte[] raw = res.toString().getBytes(StandardCharsets.UTF_8); if (raw.length > maxBytes) { maxBytes -= 3; while (raw.length > maxBytes) { res.deleteCharAt(res.length() / 2); raw = res.toString().getBytes(StandardCharsets.UTF_8); } res.insert(res.length() / 2, "..."); } } public static String rewriteAfterRename(File beforeDir, File afterDir, String path) { if (path == null) return null; final File result = rewriteAfterRename(beforeDir, afterDir, new File(path)); Loading
core/tests/coretests/src/android/os/FileUtilsTest.java +12 −0 Original line number Diff line number Diff line Loading @@ -232,6 +232,18 @@ public class FileUtilsTest extends AndroidTestCase { assertEquals("foo_bar__baz", FileUtils.buildValidFatFilename("foo?bar**baz")); } public void testTrimFilename() throws Exception { assertEquals("short.txt", FileUtils.trimFilename("short.txt", 16)); assertEquals("extrem...eme.txt", FileUtils.trimFilename("extremelylongfilename.txt", 16)); final String unicode = "a\u03C0\u03C0\u03C0\u03C0z"; assertEquals("a\u03C0\u03C0\u03C0\u03C0z", FileUtils.trimFilename(unicode, 10)); assertEquals("a\u03C0...\u03C0z", FileUtils.trimFilename(unicode, 9)); assertEquals("a...\u03C0z", FileUtils.trimFilename(unicode, 8)); assertEquals("a...\u03C0z", FileUtils.trimFilename(unicode, 7)); assertEquals("a...z", FileUtils.trimFilename(unicode, 6)); } public void testBuildUniqueFile_normal() throws Exception { assertNameEquals("test.jpg", FileUtils.buildUniqueFile(mTarget, "image/jpeg", "test")); assertNameEquals("test.jpg", FileUtils.buildUniqueFile(mTarget, "image/jpeg", "test.jpg")); Loading