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