1 /* 2 * Copyright (C) 2006 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.os; 18 19 import java.io.BufferedInputStream; 20 import java.io.ByteArrayOutputStream; 21 import java.io.File; 22 import java.io.FileInputStream; 23 import java.io.FileNotFoundException; 24 import java.io.FileOutputStream; 25 import java.io.FileWriter; 26 import java.io.IOException; 27 import java.io.InputStream; 28 import java.util.regex.Pattern; 29 import java.util.zip.CRC32; 30 import java.util.zip.CheckedInputStream; 31 32 /** 33 * Tools for managing files. Not for public consumption. 34 * @hide 35 */ 36 public class FileUtils { 37 public static final int S_IRWXU = 00700; 38 public static final int S_IRUSR = 00400; 39 public static final int S_IWUSR = 00200; 40 public static final int S_IXUSR = 00100; 41 42 public static final int S_IRWXG = 00070; 43 public static final int S_IRGRP = 00040; 44 public static final int S_IWGRP = 00020; 45 public static final int S_IXGRP = 00010; 46 47 public static final int S_IRWXO = 00007; 48 public static final int S_IROTH = 00004; 49 public static final int S_IWOTH = 00002; 50 public static final int S_IXOTH = 00001; 51 52 /** Regular expression for safe filenames: no spaces or metacharacters */ 53 private static final Pattern SAFE_FILENAME_PATTERN = Pattern.compile("[\\w%+,./=_-]+"); 54 setPermissions(String file, int mode, int uid, int gid)55 public static native int setPermissions(String file, int mode, int uid, int gid); 56 57 /** returns the FAT file system volume ID for the volume mounted 58 * at the given mount point, or -1 for failure 59 * @param mountPoint point for FAT volume 60 * @return volume ID or -1 61 */ getFatVolumeId(String mountPoint)62 public static native int getFatVolumeId(String mountPoint); 63 64 /** 65 * Perform an fsync on the given FileOutputStream. The stream at this 66 * point must be flushed but not yet closed. 67 */ sync(FileOutputStream stream)68 public static boolean sync(FileOutputStream stream) { 69 try { 70 if (stream != null) { 71 stream.getFD().sync(); 72 } 73 return true; 74 } catch (IOException e) { 75 } 76 return false; 77 } 78 79 // copy a file from srcFile to destFile, return true if succeed, return 80 // false if fail copyFile(File srcFile, File destFile)81 public static boolean copyFile(File srcFile, File destFile) { 82 boolean result = false; 83 try { 84 InputStream in = new FileInputStream(srcFile); 85 try { 86 result = copyToFile(in, destFile); 87 } finally { 88 in.close(); 89 } 90 } catch (IOException e) { 91 result = false; 92 } 93 return result; 94 } 95 96 /** 97 * Copy data from a source stream to destFile. 98 * Return true if succeed, return false if failed. 99 */ copyToFile(InputStream inputStream, File destFile)100 public static boolean copyToFile(InputStream inputStream, File destFile) { 101 try { 102 if (destFile.exists()) { 103 destFile.delete(); 104 } 105 FileOutputStream out = new FileOutputStream(destFile); 106 try { 107 byte[] buffer = new byte[4096]; 108 int bytesRead; 109 while ((bytesRead = inputStream.read(buffer)) >= 0) { 110 out.write(buffer, 0, bytesRead); 111 } 112 } finally { 113 out.flush(); 114 try { 115 out.getFD().sync(); 116 } catch (IOException e) { 117 } 118 out.close(); 119 } 120 return true; 121 } catch (IOException e) { 122 return false; 123 } 124 } 125 126 /** 127 * Check if a filename is "safe" (no metacharacters or spaces). 128 * @param file The file to check 129 */ isFilenameSafe(File file)130 public static boolean isFilenameSafe(File file) { 131 // Note, we check whether it matches what's known to be safe, 132 // rather than what's known to be unsafe. Non-ASCII, control 133 // characters, etc. are all unsafe by default. 134 return SAFE_FILENAME_PATTERN.matcher(file.getPath()).matches(); 135 } 136 137 /** 138 * Read a text file into a String, optionally limiting the length. 139 * @param file to read (will not seek, so things like /proc files are OK) 140 * @param max length (positive for head, negative of tail, 0 for no limit) 141 * @param ellipsis to add of the file was truncated (can be null) 142 * @return the contents of the file, possibly truncated 143 * @throws IOException if something goes wrong reading the file 144 */ readTextFile(File file, int max, String ellipsis)145 public static String readTextFile(File file, int max, String ellipsis) throws IOException { 146 InputStream input = new FileInputStream(file); 147 // wrapping a BufferedInputStream around it because when reading /proc with unbuffered 148 // input stream, bytes read not equal to buffer size is not necessarily the correct 149 // indication for EOF; but it is true for BufferedInputStream due to its implementation. 150 BufferedInputStream bis = new BufferedInputStream(input); 151 try { 152 long size = file.length(); 153 if (max > 0 || (size > 0 && max == 0)) { // "head" mode: read the first N bytes 154 if (size > 0 && (max == 0 || size < max)) max = (int) size; 155 byte[] data = new byte[max + 1]; 156 int length = bis.read(data); 157 if (length <= 0) return ""; 158 if (length <= max) return new String(data, 0, length); 159 if (ellipsis == null) return new String(data, 0, max); 160 return new String(data, 0, max) + ellipsis; 161 } else if (max < 0) { // "tail" mode: keep the last N 162 int len; 163 boolean rolled = false; 164 byte[] last = null, data = null; 165 do { 166 if (last != null) rolled = true; 167 byte[] tmp = last; last = data; data = tmp; 168 if (data == null) data = new byte[-max]; 169 len = bis.read(data); 170 } while (len == data.length); 171 172 if (last == null && len <= 0) return ""; 173 if (last == null) return new String(data, 0, len); 174 if (len > 0) { 175 rolled = true; 176 System.arraycopy(last, len, last, 0, last.length - len); 177 System.arraycopy(data, 0, last, last.length - len, len); 178 } 179 if (ellipsis == null || !rolled) return new String(last); 180 return ellipsis + new String(last); 181 } else { // "cat" mode: size unknown, read it all in streaming fashion 182 ByteArrayOutputStream contents = new ByteArrayOutputStream(); 183 int len; 184 byte[] data = new byte[1024]; 185 do { 186 len = bis.read(data); 187 if (len > 0) contents.write(data, 0, len); 188 } while (len == data.length); 189 return contents.toString(); 190 } 191 } finally { 192 bis.close(); 193 input.close(); 194 } 195 } 196 197 /** 198 * Writes string to file. Basically same as "echo -n $string > $filename" 199 * 200 * @param filename 201 * @param string 202 * @throws IOException 203 */ stringToFile(String filename, String string)204 public static void stringToFile(String filename, String string) throws IOException { 205 FileWriter out = new FileWriter(filename); 206 try { 207 out.write(string); 208 } finally { 209 out.close(); 210 } 211 } 212 213 /** 214 * Computes the checksum of a file using the CRC32 checksum routine. 215 * The value of the checksum is returned. 216 * 217 * @param file the file to checksum, must not be null 218 * @return the checksum value or an exception is thrown. 219 */ checksumCrc32(File file)220 public static long checksumCrc32(File file) throws FileNotFoundException, IOException { 221 CRC32 checkSummer = new CRC32(); 222 CheckedInputStream cis = null; 223 224 try { 225 cis = new CheckedInputStream( new FileInputStream(file), checkSummer); 226 byte[] buf = new byte[128]; 227 while(cis.read(buf) >= 0) { 228 // Just read for checksum to get calculated. 229 } 230 return checkSummer.getValue(); 231 } finally { 232 if (cis != null) { 233 try { 234 cis.close(); 235 } catch (IOException e) { 236 } 237 } 238 } 239 } 240 } 241