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