/* * Copyright (C) 2012 Baidu.com Inc * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.baidu.cafe.local; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.FileWriter; import java.io.IOException; import java.io.InputStream; import java.util.regex.Pattern; import java.util.zip.CRC32; import java.util.zip.CheckedInputStream; import com.baidu.cafe.utils.CommandResult; import com.baidu.cafe.utils.ShellExecute; /** * Tools for managing files. It's ported from package android.os. * * @author luxiaoyu01@baidu.com * @date 2012-11-20 * @version * @todo */ public class FileUtils { public static final int S_IRWXU = 00700; public static final int S_IRUSR = 00400; public static final int S_IWUSR = 00200; public static final int S_IXUSR = 00100; public static final int S_IRWXG = 00070; public static final int S_IRGRP = 00040; public static final int S_IWGRP = 00020; public static final int S_IXGRP = 00010; public static final int S_IRWXO = 00007; public static final int S_IROTH = 00004; public static final int S_IWOTH = 00002; public static final int S_IXOTH = 00001; /** * File status information. This class maps directly to the POSIX stat * structure. * * @hide */ public static final class FileStatus { public int dev; public int ino; public int mode; public int nlink; public int uid; public int gid; public int rdev; public long size; public int blksize; public long blocks; public long atime; public long mtime; public long ctime; } /** * Get the status for the given path. This is equivalent to the POSIX * stat(2) system call. * * @param path * The path of the file to be stat'd. * @param status * Optional argument to fill in. It will only fill in the status * if the file exists. * @return true if the file exists and false if it does not exist. If you do * not have permission to stat the file, then this method will * return false. */ // public static boolean getFileStatus(String path, FileStatus status) { // StrictMode.noteDiskRead(); // return getFileStatusNative(path, status); // } /* * can use `cat file > /dev/null 2>&1;echo $?` */ // private static native boolean getFileStatusNative(String path, FileStatus status); /** Regular expression for safe filenames: no spaces or metacharacters */ private static final Pattern SAFE_FILENAME_PATTERN = Pattern.compile("[\\w%+,./=_-]+"); /** * @param file * @param mode * @param uid * @param gid * @return */ public static int setPermissions(String file, int mode, int uid, int gid) { if (uid >= 0 || gid >= 0) { // chown } CommandResult cr = new ShellExecute().execute("chmod " + Integer.toOctalString(mode) + " " + file, "/", 200); return cr == null ? -1 : cr.ret; } public static native int getPermissions(String file, int[] outPermissions); public static native int setUMask(int mask); /** * returns the FAT file system volume ID for the volume mounted at the given * mount point, or -1 for failure * * @param mountPoint * point for FAT volume * @return volume ID or -1 */ public static native int getFatVolumeId(String mountPoint); /** * Perform an fsync on the given FileOutputStream. The stream at this point * must be flushed but not yet closed. */ public static boolean sync(FileOutputStream stream) { try { if (stream != null) { stream.getFD().sync(); } return true; } catch (IOException e) { } return false; } // copy a file from srcFile to destFile, return true if succeed, return // false if fail public static boolean copyFile(File srcFile, File destFile) { boolean result = false; try { InputStream in = new FileInputStream(srcFile); try { result = copyToFile(in, destFile); } finally { in.close(); } } catch (IOException e) { result = false; } return result; } /** * Copy data from a source stream to destFile. Return true if succeed, * return false if failed. */ public static boolean copyToFile(InputStream inputStream, File destFile) { try { if (destFile.exists()) { destFile.delete(); } FileOutputStream out = new FileOutputStream(destFile); try { byte[] buffer = new byte[4096]; int bytesRead; while ((bytesRead = inputStream.read(buffer)) >= 0) { out.write(buffer, 0, bytesRead); } } finally { out.flush(); try { out.getFD().sync(); } catch (IOException e) { } out.close(); } return true; } catch (IOException e) { return false; } } /** * Check if a filename is "safe" (no metacharacters or spaces). * * @param file * The file to check */ public static boolean isFilenameSafe(File file) { // Note, we check whether it matches what's known to be safe, // rather than what's known to be unsafe. Non-ASCII, control // characters, etc. are all unsafe by default. return SAFE_FILENAME_PATTERN.matcher(file.getPath()).matches(); } /** * Read a text file into a String, optionally limiting the length. * * @param file * to read (will not seek, so things like /proc files are OK) * @param max * length (positive for head, negative of tail, 0 for no limit) * @param ellipsis * to add of the file was truncated (can be null) * @return the contents of the file, possibly truncated * @throws IOException * if something goes wrong reading the file */ public static String readTextFile(File file, int max, String ellipsis) throws IOException { InputStream input = new FileInputStream(file); try { long size = file.length(); if (max > 0 || (size > 0 && max == 0)) { // "head" mode: read the first N bytes if (size > 0 && (max == 0 || size < max)) max = (int) size; byte[] data = new byte[max + 1]; int length = input.read(data); if (length <= 0) return ""; if (length <= max) return new String(data, 0, length); if (ellipsis == null) return new String(data, 0, max); return new String(data, 0, max) + ellipsis; } else if (max < 0) { // "tail" mode: keep the last N int len; boolean rolled = false; byte[] last = null, data = null; do { if (last != null) rolled = true; byte[] tmp = last; last = data; data = tmp; if (data == null) data = new byte[-max]; len = input.read(data); } while (len == data.length); if (last == null && len <= 0) return ""; if (last == null) return new String(data, 0, len); if (len > 0) { rolled = true; System.arraycopy(last, len, last, 0, last.length - len); System.arraycopy(data, 0, last, last.length - len, len); } if (ellipsis == null || !rolled) return new String(last); return ellipsis + new String(last); } else { // "cat" mode: size unknown, read it all in streaming fashion ByteArrayOutputStream contents = new ByteArrayOutputStream(); int len; byte[] data = new byte[1024]; do { len = input.read(data); if (len > 0) contents.write(data, 0, len); } while (len == data.length); return contents.toString(); } } finally { input.close(); } } /** * Writes string to file. Basically same as "echo -n $string > $filename" * * @param filename * @param string * @throws IOException */ public static void stringToFile(String filename, String string) throws IOException { FileWriter out = new FileWriter(filename); try { out.write(string); } finally { out.close(); } } /** * Computes the checksum of a file using the CRC32 checksum routine. The * value of the checksum is returned. * * @param file * the file to checksum, must not be null * @return the checksum value or an exception is thrown. */ public static long checksumCrc32(File file) throws FileNotFoundException, IOException { CRC32 checkSummer = new CRC32(); CheckedInputStream cis = null; try { cis = new CheckedInputStream(new FileInputStream(file), checkSummer); byte[] buf = new byte[128]; while (cis.read(buf) >= 0) { // Just read for checksum to get calculated. } return checkSummer.getValue(); } finally { if (cis != null) { try { cis.close(); } catch (IOException e) { } } } } }