FileUtils.java revision 4e920f70f38d52d3a74c6a3133388a2e2cb6c175
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 17package android.os; 18 19import java.io.ByteArrayOutputStream; 20import java.io.File; 21import java.io.FileInputStream; 22import java.io.FileOutputStream; 23import java.io.IOException; 24import java.io.InputStream; 25import java.io.OutputStream; 26import java.util.regex.Pattern; 27 28 29/** 30 * Tools for managing files. Not for public consumption. 31 * @hide 32 */ 33public class FileUtils 34{ 35 public static final int S_IRWXU = 00700; 36 public static final int S_IRUSR = 00400; 37 public static final int S_IWUSR = 00200; 38 public static final int S_IXUSR = 00100; 39 40 public static final int S_IRWXG = 00070; 41 public static final int S_IRGRP = 00040; 42 public static final int S_IWGRP = 00020; 43 public static final int S_IXGRP = 00010; 44 45 public static final int S_IRWXO = 00007; 46 public static final int S_IROTH = 00004; 47 public static final int S_IWOTH = 00002; 48 public static final int S_IXOTH = 00001; 49 50 51 /** 52 * File status information. This class maps directly to the POSIX stat structure. 53 * @hide 54 */ 55 public static final class FileStatus { 56 public int dev; 57 public int ino; 58 public int mode; 59 public int nlink; 60 public int uid; 61 public int gid; 62 public int rdev; 63 public long size; 64 public int blksize; 65 public long blocks; 66 public long atime; 67 public long mtime; 68 public long ctime; 69 } 70 71 /** 72 * Get the status for the given path. This is equivalent to the POSIX stat(2) system call. 73 * @param path The path of the file to be stat'd. 74 * @param status Optional argument to fill in. It will only fill in the status if the file 75 * exists. 76 * @return true if the file exists and false if it does not exist. If you do not have 77 * permission to stat the file, then this method will return false. 78 */ 79 public static boolean getFileStatus(String path, FileStatus status) { 80 StrictMode.noteDiskRead(); 81 return getFileStatusNative(path, status); 82 } 83 84 private static native boolean getFileStatusNative(String path, FileStatus status); 85 86 /** Regular expression for safe filenames: no spaces or metacharacters */ 87 private static final Pattern SAFE_FILENAME_PATTERN = Pattern.compile("[\\w%+,./=_-]+"); 88 89 public static native int setPermissions(String file, int mode, int uid, int gid); 90 91 public static native int getPermissions(String file, int[] outPermissions); 92 93 public static native int setUMask(int mask); 94 95 /** returns the FAT file system volume ID for the volume mounted 96 * at the given mount point, or -1 for failure 97 * @param mount point for FAT volume 98 * @return volume ID or -1 99 */ 100 public static native int getFatVolumeId(String mountPoint); 101 102 /** 103 * Perform an fsync on the given FileOutputStream. The stream at this 104 * point must be flushed but not yet closed. 105 */ 106 public static boolean sync(FileOutputStream stream) { 107 try { 108 if (stream != null) { 109 stream.getFD().sync(); 110 } 111 return true; 112 } catch (IOException e) { 113 } 114 return false; 115 } 116 117 // copy a file from srcFile to destFile, return true if succeed, return 118 // false if fail 119 public static boolean copyFile(File srcFile, File destFile) { 120 boolean result = false; 121 try { 122 InputStream in = new FileInputStream(srcFile); 123 try { 124 result = copyToFile(in, destFile); 125 } finally { 126 in.close(); 127 } 128 } catch (IOException e) { 129 result = false; 130 } 131 return result; 132 } 133 134 /** 135 * Copy data from a source stream to destFile. 136 * Return true if succeed, return false if failed. 137 */ 138 public static boolean copyToFile(InputStream inputStream, File destFile) { 139 try { 140 if (destFile.exists()) { 141 destFile.delete(); 142 } 143 FileOutputStream out = new FileOutputStream(destFile); 144 try { 145 byte[] buffer = new byte[4096]; 146 int bytesRead; 147 while ((bytesRead = inputStream.read(buffer)) >= 0) { 148 out.write(buffer, 0, bytesRead); 149 } 150 } finally { 151 out.flush(); 152 try { 153 out.getFD().sync(); 154 } catch (IOException e) { 155 } 156 out.close(); 157 } 158 return true; 159 } catch (IOException e) { 160 return false; 161 } 162 } 163 164 /** 165 * Check if a filename is "safe" (no metacharacters or spaces). 166 * @param file The file to check 167 */ 168 public static boolean isFilenameSafe(File file) { 169 // Note, we check whether it matches what's known to be safe, 170 // rather than what's known to be unsafe. Non-ASCII, control 171 // characters, etc. are all unsafe by default. 172 return SAFE_FILENAME_PATTERN.matcher(file.getPath()).matches(); 173 } 174 175 /** 176 * Read a text file into a String, optionally limiting the length. 177 * @param file to read (will not seek, so things like /proc files are OK) 178 * @param max length (positive for head, negative of tail, 0 for no limit) 179 * @param ellipsis to add of the file was truncated (can be null) 180 * @return the contents of the file, possibly truncated 181 * @throws IOException if something goes wrong reading the file 182 */ 183 public static String readTextFile(File file, int max, String ellipsis) throws IOException { 184 InputStream input = new FileInputStream(file); 185 try { 186 long size = file.length(); 187 if (max > 0 || (size > 0 && max == 0)) { // "head" mode: read the first N bytes 188 if (size > 0 && (max == 0 || size < max)) max = (int) size; 189 byte[] data = new byte[max + 1]; 190 int length = input.read(data); 191 if (length <= 0) return ""; 192 if (length <= max) return new String(data, 0, length); 193 if (ellipsis == null) return new String(data, 0, max); 194 return new String(data, 0, max) + ellipsis; 195 } else if (max < 0) { // "tail" mode: keep the last N 196 int len; 197 boolean rolled = false; 198 byte[] last = null, data = null; 199 do { 200 if (last != null) rolled = true; 201 byte[] tmp = last; last = data; data = tmp; 202 if (data == null) data = new byte[-max]; 203 len = input.read(data); 204 } while (len == data.length); 205 206 if (last == null && len <= 0) return ""; 207 if (last == null) return new String(data, 0, len); 208 if (len > 0) { 209 rolled = true; 210 System.arraycopy(last, len, last, 0, last.length - len); 211 System.arraycopy(data, 0, last, last.length - len, len); 212 } 213 if (ellipsis == null || !rolled) return new String(last); 214 return ellipsis + new String(last); 215 } else { // "cat" mode: size unknown, read it all in streaming fashion 216 ByteArrayOutputStream contents = new ByteArrayOutputStream(); 217 int len; 218 byte[] data = new byte[1024]; 219 do { 220 len = input.read(data); 221 if (len > 0) contents.write(data, 0, len); 222 } while (len == data.length); 223 return contents.toString(); 224 } 225 } finally { 226 input.close(); 227 } 228 } 229} 230