FileUtils.java revision 3a44f3f1b446315ef894e01d2ab9b5388c2bd8c4
19066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/* 29066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Copyright (C) 2006 The Android Open Source Project 39066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 49066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License"); 59066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * you may not use this file except in compliance with the License. 69066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * You may obtain a copy of the License at 79066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 89066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * http://www.apache.org/licenses/LICENSE-2.0 99066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Unless required by applicable law or agreed to in writing, software 119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS, 129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * See the License for the specific language governing permissions and 149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * limitations under the License. 159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpackage android.os; 189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1934385d352da19805ae948215e2edbeedd16b7941Elliott Hughesimport android.system.ErrnoException; 203a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport android.text.TextUtils; 2134385d352da19805ae948215e2edbeedd16b7941Elliott Hughesimport android.system.Os; 2234385d352da19805ae948215e2edbeedd16b7941Elliott Hughesimport android.system.OsConstants; 23d9526907d1a51ef0b35bfbbeee43fa209d8b5bbfJeff Sharkeyimport android.util.Log; 24184a0100abc431fc3d6d8dd1b20212b84958cadaJeff Sharkeyimport android.util.Slog; 25184a0100abc431fc3d6d8dd1b20212b84958cadaJeff Sharkey 2690619816d99154d504a14774c6f2d5f4254ff780Guang Zhuimport java.io.BufferedInputStream; 279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.ByteArrayOutputStream; 289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.File; 29184a0100abc431fc3d6d8dd1b20212b84958cadaJeff Sharkeyimport java.io.FileDescriptor; 309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.FileInputStream; 316d25a990afffd5eb385aba3043d5dfad36f1539aWink Savilleimport java.io.FileNotFoundException; 329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.FileOutputStream; 33da8bb74b9d9ffcb095815db800d0816c411f1fbaMike Lockwoodimport java.io.FileWriter; 349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.IOException; 359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.InputStream; 36d9526907d1a51ef0b35bfbbeee43fa209d8b5bbfJeff Sharkeyimport java.util.Arrays; 37d9526907d1a51ef0b35bfbbeee43fa209d8b5bbfJeff Sharkeyimport java.util.Comparator; 389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.regex.Pattern; 396d25a990afffd5eb385aba3043d5dfad36f1539aWink Savilleimport java.util.zip.CRC32; 406d25a990afffd5eb385aba3043d5dfad36f1539aWink Savilleimport java.util.zip.CheckedInputStream; 419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/** 439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Tools for managing files. Not for public consumption. 449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @hide 459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 466d25a990afffd5eb385aba3043d5dfad36f1539aWink Savillepublic class FileUtils { 47d9526907d1a51ef0b35bfbbeee43fa209d8b5bbfJeff Sharkey private static final String TAG = "FileUtils"; 48d9526907d1a51ef0b35bfbbeee43fa209d8b5bbfJeff Sharkey 499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static final int S_IRWXU = 00700; 509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static final int S_IRUSR = 00400; 519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static final int S_IWUSR = 00200; 529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static final int S_IXUSR = 00100; 539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static final int S_IRWXG = 00070; 559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static final int S_IRGRP = 00040; 569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static final int S_IWGRP = 00020; 579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static final int S_IXGRP = 00010; 589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static final int S_IRWXO = 00007; 609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static final int S_IROTH = 00004; 619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static final int S_IWOTH = 00002; 629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static final int S_IXOTH = 00001; 639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** Regular expression for safe filenames: no spaces or metacharacters */ 659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final Pattern SAFE_FILENAME_PATTERN = Pattern.compile("[\\w%+,./=_-]+"); 669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 67184a0100abc431fc3d6d8dd1b20212b84958cadaJeff Sharkey /** 68184a0100abc431fc3d6d8dd1b20212b84958cadaJeff Sharkey * Set owner and mode of of given {@link File}. 69184a0100abc431fc3d6d8dd1b20212b84958cadaJeff Sharkey * 70184a0100abc431fc3d6d8dd1b20212b84958cadaJeff Sharkey * @param mode to apply through {@code chmod} 71184a0100abc431fc3d6d8dd1b20212b84958cadaJeff Sharkey * @param uid to apply through {@code chown}, or -1 to leave unchanged 72184a0100abc431fc3d6d8dd1b20212b84958cadaJeff Sharkey * @param gid to apply through {@code chown}, or -1 to leave unchanged 73184a0100abc431fc3d6d8dd1b20212b84958cadaJeff Sharkey * @return 0 on success, otherwise errno. 74184a0100abc431fc3d6d8dd1b20212b84958cadaJeff Sharkey */ 75184a0100abc431fc3d6d8dd1b20212b84958cadaJeff Sharkey public static int setPermissions(File path, int mode, int uid, int gid) { 76184a0100abc431fc3d6d8dd1b20212b84958cadaJeff Sharkey return setPermissions(path.getAbsolutePath(), mode, uid, gid); 77184a0100abc431fc3d6d8dd1b20212b84958cadaJeff Sharkey } 78184a0100abc431fc3d6d8dd1b20212b84958cadaJeff Sharkey 79184a0100abc431fc3d6d8dd1b20212b84958cadaJeff Sharkey /** 80184a0100abc431fc3d6d8dd1b20212b84958cadaJeff Sharkey * Set owner and mode of of given path. 81184a0100abc431fc3d6d8dd1b20212b84958cadaJeff Sharkey * 82184a0100abc431fc3d6d8dd1b20212b84958cadaJeff Sharkey * @param mode to apply through {@code chmod} 83184a0100abc431fc3d6d8dd1b20212b84958cadaJeff Sharkey * @param uid to apply through {@code chown}, or -1 to leave unchanged 84184a0100abc431fc3d6d8dd1b20212b84958cadaJeff Sharkey * @param gid to apply through {@code chown}, or -1 to leave unchanged 85184a0100abc431fc3d6d8dd1b20212b84958cadaJeff Sharkey * @return 0 on success, otherwise errno. 86184a0100abc431fc3d6d8dd1b20212b84958cadaJeff Sharkey */ 87184a0100abc431fc3d6d8dd1b20212b84958cadaJeff Sharkey public static int setPermissions(String path, int mode, int uid, int gid) { 88184a0100abc431fc3d6d8dd1b20212b84958cadaJeff Sharkey try { 8934385d352da19805ae948215e2edbeedd16b7941Elliott Hughes Os.chmod(path, mode); 90184a0100abc431fc3d6d8dd1b20212b84958cadaJeff Sharkey } catch (ErrnoException e) { 91184a0100abc431fc3d6d8dd1b20212b84958cadaJeff Sharkey Slog.w(TAG, "Failed to chmod(" + path + "): " + e); 92184a0100abc431fc3d6d8dd1b20212b84958cadaJeff Sharkey return e.errno; 93184a0100abc431fc3d6d8dd1b20212b84958cadaJeff Sharkey } 94184a0100abc431fc3d6d8dd1b20212b84958cadaJeff Sharkey 95184a0100abc431fc3d6d8dd1b20212b84958cadaJeff Sharkey if (uid >= 0 || gid >= 0) { 96184a0100abc431fc3d6d8dd1b20212b84958cadaJeff Sharkey try { 9734385d352da19805ae948215e2edbeedd16b7941Elliott Hughes Os.chown(path, uid, gid); 98184a0100abc431fc3d6d8dd1b20212b84958cadaJeff Sharkey } catch (ErrnoException e) { 99184a0100abc431fc3d6d8dd1b20212b84958cadaJeff Sharkey Slog.w(TAG, "Failed to chown(" + path + "): " + e); 100184a0100abc431fc3d6d8dd1b20212b84958cadaJeff Sharkey return e.errno; 101184a0100abc431fc3d6d8dd1b20212b84958cadaJeff Sharkey } 102184a0100abc431fc3d6d8dd1b20212b84958cadaJeff Sharkey } 103184a0100abc431fc3d6d8dd1b20212b84958cadaJeff Sharkey 104184a0100abc431fc3d6d8dd1b20212b84958cadaJeff Sharkey return 0; 105184a0100abc431fc3d6d8dd1b20212b84958cadaJeff Sharkey } 1069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 107184a0100abc431fc3d6d8dd1b20212b84958cadaJeff Sharkey /** 108184a0100abc431fc3d6d8dd1b20212b84958cadaJeff Sharkey * Set owner and mode of of given {@link FileDescriptor}. 109184a0100abc431fc3d6d8dd1b20212b84958cadaJeff Sharkey * 110184a0100abc431fc3d6d8dd1b20212b84958cadaJeff Sharkey * @param mode to apply through {@code chmod} 111184a0100abc431fc3d6d8dd1b20212b84958cadaJeff Sharkey * @param uid to apply through {@code chown}, or -1 to leave unchanged 112184a0100abc431fc3d6d8dd1b20212b84958cadaJeff Sharkey * @param gid to apply through {@code chown}, or -1 to leave unchanged 113184a0100abc431fc3d6d8dd1b20212b84958cadaJeff Sharkey * @return 0 on success, otherwise errno. 114184a0100abc431fc3d6d8dd1b20212b84958cadaJeff Sharkey */ 115184a0100abc431fc3d6d8dd1b20212b84958cadaJeff Sharkey public static int setPermissions(FileDescriptor fd, int mode, int uid, int gid) { 116184a0100abc431fc3d6d8dd1b20212b84958cadaJeff Sharkey try { 11734385d352da19805ae948215e2edbeedd16b7941Elliott Hughes Os.fchmod(fd, mode); 118184a0100abc431fc3d6d8dd1b20212b84958cadaJeff Sharkey } catch (ErrnoException e) { 119184a0100abc431fc3d6d8dd1b20212b84958cadaJeff Sharkey Slog.w(TAG, "Failed to fchmod(): " + e); 120184a0100abc431fc3d6d8dd1b20212b84958cadaJeff Sharkey return e.errno; 121184a0100abc431fc3d6d8dd1b20212b84958cadaJeff Sharkey } 122184a0100abc431fc3d6d8dd1b20212b84958cadaJeff Sharkey 123184a0100abc431fc3d6d8dd1b20212b84958cadaJeff Sharkey if (uid >= 0 || gid >= 0) { 124184a0100abc431fc3d6d8dd1b20212b84958cadaJeff Sharkey try { 12534385d352da19805ae948215e2edbeedd16b7941Elliott Hughes Os.fchown(fd, uid, gid); 126184a0100abc431fc3d6d8dd1b20212b84958cadaJeff Sharkey } catch (ErrnoException e) { 127184a0100abc431fc3d6d8dd1b20212b84958cadaJeff Sharkey Slog.w(TAG, "Failed to fchown(): " + e); 128184a0100abc431fc3d6d8dd1b20212b84958cadaJeff Sharkey return e.errno; 129184a0100abc431fc3d6d8dd1b20212b84958cadaJeff Sharkey } 130184a0100abc431fc3d6d8dd1b20212b84958cadaJeff Sharkey } 131184a0100abc431fc3d6d8dd1b20212b84958cadaJeff Sharkey 132184a0100abc431fc3d6d8dd1b20212b84958cadaJeff Sharkey return 0; 133184a0100abc431fc3d6d8dd1b20212b84958cadaJeff Sharkey } 134184a0100abc431fc3d6d8dd1b20212b84958cadaJeff Sharkey 135184a0100abc431fc3d6d8dd1b20212b84958cadaJeff Sharkey /** 136184a0100abc431fc3d6d8dd1b20212b84958cadaJeff Sharkey * Return owning UID of given path, otherwise -1. 137184a0100abc431fc3d6d8dd1b20212b84958cadaJeff Sharkey */ 138184a0100abc431fc3d6d8dd1b20212b84958cadaJeff Sharkey public static int getUid(String path) { 139184a0100abc431fc3d6d8dd1b20212b84958cadaJeff Sharkey try { 14034385d352da19805ae948215e2edbeedd16b7941Elliott Hughes return Os.stat(path).st_uid; 141184a0100abc431fc3d6d8dd1b20212b84958cadaJeff Sharkey } catch (ErrnoException e) { 142184a0100abc431fc3d6d8dd1b20212b84958cadaJeff Sharkey return -1; 143184a0100abc431fc3d6d8dd1b20212b84958cadaJeff Sharkey } 144184a0100abc431fc3d6d8dd1b20212b84958cadaJeff Sharkey } 145053f61d6a6e23825e680dc49982e55c5b4299d61Dianne Hackborn 1468bdf5935c0db4a66ab33a10b43398d2523cfa15dDianne Hackborn /** 1478bdf5935c0db4a66ab33a10b43398d2523cfa15dDianne Hackborn * Perform an fsync on the given FileOutputStream. The stream at this 1488bdf5935c0db4a66ab33a10b43398d2523cfa15dDianne Hackborn * point must be flushed but not yet closed. 1498bdf5935c0db4a66ab33a10b43398d2523cfa15dDianne Hackborn */ 1508bdf5935c0db4a66ab33a10b43398d2523cfa15dDianne Hackborn public static boolean sync(FileOutputStream stream) { 1518bdf5935c0db4a66ab33a10b43398d2523cfa15dDianne Hackborn try { 1528bdf5935c0db4a66ab33a10b43398d2523cfa15dDianne Hackborn if (stream != null) { 1538bdf5935c0db4a66ab33a10b43398d2523cfa15dDianne Hackborn stream.getFD().sync(); 1548bdf5935c0db4a66ab33a10b43398d2523cfa15dDianne Hackborn } 1558bdf5935c0db4a66ab33a10b43398d2523cfa15dDianne Hackborn return true; 1568bdf5935c0db4a66ab33a10b43398d2523cfa15dDianne Hackborn } catch (IOException e) { 1578bdf5935c0db4a66ab33a10b43398d2523cfa15dDianne Hackborn } 1588bdf5935c0db4a66ab33a10b43398d2523cfa15dDianne Hackborn return false; 1598bdf5935c0db4a66ab33a10b43398d2523cfa15dDianne Hackborn } 1608bdf5935c0db4a66ab33a10b43398d2523cfa15dDianne Hackborn 1619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // copy a file from srcFile to destFile, return true if succeed, return 1629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // false if fail 1639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static boolean copyFile(File srcFile, File destFile) { 1649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project boolean result = false; 1659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 1669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project InputStream in = new FileInputStream(srcFile); 1679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 1689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project result = copyToFile(in, destFile); 1699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } finally { 1709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project in.close(); 1719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (IOException e) { 1739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project result = false; 1749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return result; 1769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 17790619816d99154d504a14774c6f2d5f4254ff780Guang Zhu 1789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 1799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Copy data from a source stream to destFile. 1809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Return true if succeed, return false if failed. 1819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 1829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static boolean copyToFile(InputStream inputStream, File destFile) { 1839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 1841afd1c90ebe789b8d3a137004127a50d2db7e3b5Dianne Hackborn if (destFile.exists()) { 1851afd1c90ebe789b8d3a137004127a50d2db7e3b5Dianne Hackborn destFile.delete(); 1861afd1c90ebe789b8d3a137004127a50d2db7e3b5Dianne Hackborn } 1878bdf5935c0db4a66ab33a10b43398d2523cfa15dDianne Hackborn FileOutputStream out = new FileOutputStream(destFile); 1889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 1899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project byte[] buffer = new byte[4096]; 1909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int bytesRead; 1919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project while ((bytesRead = inputStream.read(buffer)) >= 0) { 1929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project out.write(buffer, 0, bytesRead); 1939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } finally { 1958bdf5935c0db4a66ab33a10b43398d2523cfa15dDianne Hackborn out.flush(); 1968bdf5935c0db4a66ab33a10b43398d2523cfa15dDianne Hackborn try { 1978bdf5935c0db4a66ab33a10b43398d2523cfa15dDianne Hackborn out.getFD().sync(); 1988bdf5935c0db4a66ab33a10b43398d2523cfa15dDianne Hackborn } catch (IOException e) { 1998bdf5935c0db4a66ab33a10b43398d2523cfa15dDianne Hackborn } 2009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project out.close(); 2019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return true; 2039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (IOException e) { 2049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return false; 2059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 2099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Check if a filename is "safe" (no metacharacters or spaces). 2109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param file The file to check 2119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 2129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static boolean isFilenameSafe(File file) { 2139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Note, we check whether it matches what's known to be safe, 2149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // rather than what's known to be unsafe. Non-ASCII, control 2159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // characters, etc. are all unsafe by default. 2169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return SAFE_FILENAME_PATTERN.matcher(file.getPath()).matches(); 2179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 2209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Read a text file into a String, optionally limiting the length. 2219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param file to read (will not seek, so things like /proc files are OK) 2229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param max length (positive for head, negative of tail, 0 for no limit) 2239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param ellipsis to add of the file was truncated (can be null) 2249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return the contents of the file, possibly truncated 2259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @throws IOException if something goes wrong reading the file 2269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 2279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static String readTextFile(File file, int max, String ellipsis) throws IOException { 2289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project InputStream input = new FileInputStream(file); 22990619816d99154d504a14774c6f2d5f4254ff780Guang Zhu // wrapping a BufferedInputStream around it because when reading /proc with unbuffered 23090619816d99154d504a14774c6f2d5f4254ff780Guang Zhu // input stream, bytes read not equal to buffer size is not necessarily the correct 23190619816d99154d504a14774c6f2d5f4254ff780Guang Zhu // indication for EOF; but it is true for BufferedInputStream due to its implementation. 23290619816d99154d504a14774c6f2d5f4254ff780Guang Zhu BufferedInputStream bis = new BufferedInputStream(input); 2339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 23442471dd5552a346dd82a58a663159875ccc4fb79Dan Egnor long size = file.length(); 23542471dd5552a346dd82a58a663159875ccc4fb79Dan Egnor if (max > 0 || (size > 0 && max == 0)) { // "head" mode: read the first N bytes 23642471dd5552a346dd82a58a663159875ccc4fb79Dan Egnor if (size > 0 && (max == 0 || size < max)) max = (int) size; 2379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project byte[] data = new byte[max + 1]; 23890619816d99154d504a14774c6f2d5f4254ff780Guang Zhu int length = bis.read(data); 2399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (length <= 0) return ""; 2409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (length <= max) return new String(data, 0, length); 2419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (ellipsis == null) return new String(data, 0, max); 2429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return new String(data, 0, max) + ellipsis; 24342471dd5552a346dd82a58a663159875ccc4fb79Dan Egnor } else if (max < 0) { // "tail" mode: keep the last N 2449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int len; 2459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project boolean rolled = false; 246d9526907d1a51ef0b35bfbbeee43fa209d8b5bbfJeff Sharkey byte[] last = null; 247d9526907d1a51ef0b35bfbbeee43fa209d8b5bbfJeff Sharkey byte[] data = null; 2489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project do { 2499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (last != null) rolled = true; 2509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project byte[] tmp = last; last = data; data = tmp; 2519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (data == null) data = new byte[-max]; 25290619816d99154d504a14774c6f2d5f4254ff780Guang Zhu len = bis.read(data); 2539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } while (len == data.length); 2549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (last == null && len <= 0) return ""; 2569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (last == null) return new String(data, 0, len); 2579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (len > 0) { 2589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project rolled = true; 2599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project System.arraycopy(last, len, last, 0, last.length - len); 2609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project System.arraycopy(data, 0, last, last.length - len, len); 2619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (ellipsis == null || !rolled) return new String(last); 2639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return ellipsis + new String(last); 26442471dd5552a346dd82a58a663159875ccc4fb79Dan Egnor } else { // "cat" mode: size unknown, read it all in streaming fashion 2659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ByteArrayOutputStream contents = new ByteArrayOutputStream(); 2669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int len; 2679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project byte[] data = new byte[1024]; 2689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project do { 26990619816d99154d504a14774c6f2d5f4254ff780Guang Zhu len = bis.read(data); 2709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (len > 0) contents.write(data, 0, len); 2719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } while (len == data.length); 2729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return contents.toString(); 2739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } finally { 27590619816d99154d504a14774c6f2d5f4254ff780Guang Zhu bis.close(); 2769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project input.close(); 2779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 279da8bb74b9d9ffcb095815db800d0816c411f1fbaMike Lockwood 280da8bb74b9d9ffcb095815db800d0816c411f1fbaMike Lockwood /** 281da8bb74b9d9ffcb095815db800d0816c411f1fbaMike Lockwood * Writes string to file. Basically same as "echo -n $string > $filename" 282da8bb74b9d9ffcb095815db800d0816c411f1fbaMike Lockwood * 283da8bb74b9d9ffcb095815db800d0816c411f1fbaMike Lockwood * @param filename 284da8bb74b9d9ffcb095815db800d0816c411f1fbaMike Lockwood * @param string 285da8bb74b9d9ffcb095815db800d0816c411f1fbaMike Lockwood * @throws IOException 286da8bb74b9d9ffcb095815db800d0816c411f1fbaMike Lockwood */ 287da8bb74b9d9ffcb095815db800d0816c411f1fbaMike Lockwood public static void stringToFile(String filename, String string) throws IOException { 288da8bb74b9d9ffcb095815db800d0816c411f1fbaMike Lockwood FileWriter out = new FileWriter(filename); 289da8bb74b9d9ffcb095815db800d0816c411f1fbaMike Lockwood try { 290da8bb74b9d9ffcb095815db800d0816c411f1fbaMike Lockwood out.write(string); 291da8bb74b9d9ffcb095815db800d0816c411f1fbaMike Lockwood } finally { 292da8bb74b9d9ffcb095815db800d0816c411f1fbaMike Lockwood out.close(); 293da8bb74b9d9ffcb095815db800d0816c411f1fbaMike Lockwood } 294da8bb74b9d9ffcb095815db800d0816c411f1fbaMike Lockwood } 2951b9a6a6e58fd73b5d1b6a434d17f0a69806858ecWink Saville 2966d25a990afffd5eb385aba3043d5dfad36f1539aWink Saville /** 2976d25a990afffd5eb385aba3043d5dfad36f1539aWink Saville * Computes the checksum of a file using the CRC32 checksum routine. 2986d25a990afffd5eb385aba3043d5dfad36f1539aWink Saville * The value of the checksum is returned. 2996d25a990afffd5eb385aba3043d5dfad36f1539aWink Saville * 3006d25a990afffd5eb385aba3043d5dfad36f1539aWink Saville * @param file the file to checksum, must not be null 3016d25a990afffd5eb385aba3043d5dfad36f1539aWink Saville * @return the checksum value or an exception is thrown. 3026d25a990afffd5eb385aba3043d5dfad36f1539aWink Saville */ 3036d25a990afffd5eb385aba3043d5dfad36f1539aWink Saville public static long checksumCrc32(File file) throws FileNotFoundException, IOException { 3046d25a990afffd5eb385aba3043d5dfad36f1539aWink Saville CRC32 checkSummer = new CRC32(); 3056d25a990afffd5eb385aba3043d5dfad36f1539aWink Saville CheckedInputStream cis = null; 3066d25a990afffd5eb385aba3043d5dfad36f1539aWink Saville 3076d25a990afffd5eb385aba3043d5dfad36f1539aWink Saville try { 3086d25a990afffd5eb385aba3043d5dfad36f1539aWink Saville cis = new CheckedInputStream( new FileInputStream(file), checkSummer); 3096d25a990afffd5eb385aba3043d5dfad36f1539aWink Saville byte[] buf = new byte[128]; 3106d25a990afffd5eb385aba3043d5dfad36f1539aWink Saville while(cis.read(buf) >= 0) { 3116d25a990afffd5eb385aba3043d5dfad36f1539aWink Saville // Just read for checksum to get calculated. 3126d25a990afffd5eb385aba3043d5dfad36f1539aWink Saville } 3136d25a990afffd5eb385aba3043d5dfad36f1539aWink Saville return checkSummer.getValue(); 3146d25a990afffd5eb385aba3043d5dfad36f1539aWink Saville } finally { 3156d25a990afffd5eb385aba3043d5dfad36f1539aWink Saville if (cis != null) { 3166d25a990afffd5eb385aba3043d5dfad36f1539aWink Saville try { 3176d25a990afffd5eb385aba3043d5dfad36f1539aWink Saville cis.close(); 3186d25a990afffd5eb385aba3043d5dfad36f1539aWink Saville } catch (IOException e) { 3196d25a990afffd5eb385aba3043d5dfad36f1539aWink Saville } 3206d25a990afffd5eb385aba3043d5dfad36f1539aWink Saville } 3216d25a990afffd5eb385aba3043d5dfad36f1539aWink Saville } 3226d25a990afffd5eb385aba3043d5dfad36f1539aWink Saville } 323d9526907d1a51ef0b35bfbbeee43fa209d8b5bbfJeff Sharkey 324d9526907d1a51ef0b35bfbbeee43fa209d8b5bbfJeff Sharkey /** 325d9526907d1a51ef0b35bfbbeee43fa209d8b5bbfJeff Sharkey * Delete older files in a directory until only those matching the given 326d9526907d1a51ef0b35bfbbeee43fa209d8b5bbfJeff Sharkey * constraints remain. 327d9526907d1a51ef0b35bfbbeee43fa209d8b5bbfJeff Sharkey * 328d9526907d1a51ef0b35bfbbeee43fa209d8b5bbfJeff Sharkey * @param minCount Always keep at least this many files. 329d9526907d1a51ef0b35bfbbeee43fa209d8b5bbfJeff Sharkey * @param minAge Always keep files younger than this age. 330ebf8ad5d91b22eb4359c75711a5b70ddcce0723dJeff Sharkey * @return if any files were deleted. 331d9526907d1a51ef0b35bfbbeee43fa209d8b5bbfJeff Sharkey */ 332ebf8ad5d91b22eb4359c75711a5b70ddcce0723dJeff Sharkey public static boolean deleteOlderFiles(File dir, int minCount, long minAge) { 333d9526907d1a51ef0b35bfbbeee43fa209d8b5bbfJeff Sharkey if (minCount < 0 || minAge < 0) { 334d9526907d1a51ef0b35bfbbeee43fa209d8b5bbfJeff Sharkey throw new IllegalArgumentException("Constraints must be positive or 0"); 335d9526907d1a51ef0b35bfbbeee43fa209d8b5bbfJeff Sharkey } 336d9526907d1a51ef0b35bfbbeee43fa209d8b5bbfJeff Sharkey 337d9526907d1a51ef0b35bfbbeee43fa209d8b5bbfJeff Sharkey final File[] files = dir.listFiles(); 338ebf8ad5d91b22eb4359c75711a5b70ddcce0723dJeff Sharkey if (files == null) return false; 339d9526907d1a51ef0b35bfbbeee43fa209d8b5bbfJeff Sharkey 340d9526907d1a51ef0b35bfbbeee43fa209d8b5bbfJeff Sharkey // Sort with newest files first 341d9526907d1a51ef0b35bfbbeee43fa209d8b5bbfJeff Sharkey Arrays.sort(files, new Comparator<File>() { 342d9526907d1a51ef0b35bfbbeee43fa209d8b5bbfJeff Sharkey @Override 343d9526907d1a51ef0b35bfbbeee43fa209d8b5bbfJeff Sharkey public int compare(File lhs, File rhs) { 344d9526907d1a51ef0b35bfbbeee43fa209d8b5bbfJeff Sharkey return (int) (rhs.lastModified() - lhs.lastModified()); 345d9526907d1a51ef0b35bfbbeee43fa209d8b5bbfJeff Sharkey } 346d9526907d1a51ef0b35bfbbeee43fa209d8b5bbfJeff Sharkey }); 347d9526907d1a51ef0b35bfbbeee43fa209d8b5bbfJeff Sharkey 348d9526907d1a51ef0b35bfbbeee43fa209d8b5bbfJeff Sharkey // Keep at least minCount files 349ebf8ad5d91b22eb4359c75711a5b70ddcce0723dJeff Sharkey boolean deleted = false; 350d9526907d1a51ef0b35bfbbeee43fa209d8b5bbfJeff Sharkey for (int i = minCount; i < files.length; i++) { 351d9526907d1a51ef0b35bfbbeee43fa209d8b5bbfJeff Sharkey final File file = files[i]; 352d9526907d1a51ef0b35bfbbeee43fa209d8b5bbfJeff Sharkey 353d9526907d1a51ef0b35bfbbeee43fa209d8b5bbfJeff Sharkey // Keep files newer than minAge 354d9526907d1a51ef0b35bfbbeee43fa209d8b5bbfJeff Sharkey final long age = System.currentTimeMillis() - file.lastModified(); 355d9526907d1a51ef0b35bfbbeee43fa209d8b5bbfJeff Sharkey if (age > minAge) { 356ebf8ad5d91b22eb4359c75711a5b70ddcce0723dJeff Sharkey if (file.delete()) { 357ebf8ad5d91b22eb4359c75711a5b70ddcce0723dJeff Sharkey Log.d(TAG, "Deleted old file " + file); 358ebf8ad5d91b22eb4359c75711a5b70ddcce0723dJeff Sharkey deleted = true; 359ebf8ad5d91b22eb4359c75711a5b70ddcce0723dJeff Sharkey } 360d9526907d1a51ef0b35bfbbeee43fa209d8b5bbfJeff Sharkey } 361d9526907d1a51ef0b35bfbbeee43fa209d8b5bbfJeff Sharkey } 362ebf8ad5d91b22eb4359c75711a5b70ddcce0723dJeff Sharkey return deleted; 363d9526907d1a51ef0b35bfbbeee43fa209d8b5bbfJeff Sharkey } 3644ca728c064aeab644f6d044e0285eaa056818b8aJeff Sharkey 3654ca728c064aeab644f6d044e0285eaa056818b8aJeff Sharkey /** 3664ca728c064aeab644f6d044e0285eaa056818b8aJeff Sharkey * Test if a file lives under the given directory, either as a direct child 3674ca728c064aeab644f6d044e0285eaa056818b8aJeff Sharkey * or a distant grandchild. 3684ca728c064aeab644f6d044e0285eaa056818b8aJeff Sharkey * <p> 3694ca728c064aeab644f6d044e0285eaa056818b8aJeff Sharkey * Both files <em>must</em> have been resolved using 3704ca728c064aeab644f6d044e0285eaa056818b8aJeff Sharkey * {@link File#getCanonicalFile()} to avoid symlink or path traversal 3714ca728c064aeab644f6d044e0285eaa056818b8aJeff Sharkey * attacks. 3724ca728c064aeab644f6d044e0285eaa056818b8aJeff Sharkey */ 3734ca728c064aeab644f6d044e0285eaa056818b8aJeff Sharkey public static boolean contains(File dir, File file) { 37421de56a94668e0fda1b8bb4ee4f99a09b40d28fdJeff Sharkey String dirPath = dir.getAbsolutePath(); 37521de56a94668e0fda1b8bb4ee4f99a09b40d28fdJeff Sharkey String filePath = file.getAbsolutePath(); 3764ca728c064aeab644f6d044e0285eaa056818b8aJeff Sharkey 3774ca728c064aeab644f6d044e0285eaa056818b8aJeff Sharkey if (dirPath.equals(filePath)) { 3784ca728c064aeab644f6d044e0285eaa056818b8aJeff Sharkey return true; 3794ca728c064aeab644f6d044e0285eaa056818b8aJeff Sharkey } 3804ca728c064aeab644f6d044e0285eaa056818b8aJeff Sharkey 3814ca728c064aeab644f6d044e0285eaa056818b8aJeff Sharkey if (!dirPath.endsWith("/")) { 3824ca728c064aeab644f6d044e0285eaa056818b8aJeff Sharkey dirPath += "/"; 3834ca728c064aeab644f6d044e0285eaa056818b8aJeff Sharkey } 3844ca728c064aeab644f6d044e0285eaa056818b8aJeff Sharkey return filePath.startsWith(dirPath); 3854ca728c064aeab644f6d044e0285eaa056818b8aJeff Sharkey } 3863a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey 3873a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey public static void deleteContents(File dir) { 3883a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey File[] files = dir.listFiles(); 3893a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey if (files != null) { 3903a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey for (File file : files) { 3913a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey if (file.isDirectory()) { 3923a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey deleteContents(file); 3933a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey } 3943a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey file.delete(); 3953a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey } 3963a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey } 3973a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey } 3983a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey 3993a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey /** 4003a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey * Assert that given filename is valid on ext4. 4013a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey */ 4023a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey public static boolean isValidExtFilename(String name) { 4033a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey if (TextUtils.isEmpty(name) || ".".equals(name) || "..".equals(name)) { 4043a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey return false; 4053a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey } 4063a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey for (int i = 0; i < name.length(); i++) { 4073a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey final char c = name.charAt(i); 4083a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey if (c == '\0' || c == '/') { 4093a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey return false; 4103a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey } 4113a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey } 4123a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey return true; 4133a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey } 4149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} 415