1 /*
2  * Copyright (C) 2015 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 package com.android.timezone.distro;
17 
18 import junit.framework.TestCase;
19 
20 import android.system.Os;
21 import android.system.OsConstants;
22 import android.system.StructStat;
23 
24 import libcore.testing.io.TestIoUtils;
25 
26 import java.io.File;
27 import java.io.FileNotFoundException;
28 import java.io.FileOutputStream;
29 import java.io.IOException;
30 import java.nio.charset.StandardCharsets;
31 import java.util.ArrayList;
32 import java.util.Arrays;
33 import java.util.Collections;
34 import java.util.List;
35 
36 /**
37  * Tests for {@link FileUtils}.
38  */
39 public class FileUtilsTest extends TestCase {
40 
41     private List<File> testFiles = new ArrayList<>();
42 
43     @Override
tearDown()44     public void tearDown() throws Exception {
45         // Delete in reverse order
46         Collections.reverse(testFiles);
47         for (File tempFile : testFiles) {
48             tempFile.delete();
49         }
50         super.tearDown();
51     }
52 
testDeleteRecursive()53     public void testDeleteRecursive() throws Exception {
54         File dir = createTempDir();
55         File file1 = createRegularFile(dir, "file1");
56         File file2 = createRegularFile(dir, "file2");
57         File symLink1 = createSymlink(file1, dir, "symLink1");
58         File subDir = createDir(dir, "subDir");
59         File file3 = createRegularFile(subDir, "subFile1");
60         File file4 = createRegularFile(subDir, "subFile2");
61         File symLink2 = createSymlink(file1, dir, "symLink2");
62 
63         File otherDir = createTempDir();
64         File otherFile = createRegularFile(otherDir, "kept");
65 
66         File linkToOtherDir = createSymlink(otherDir, subDir, "linkToOtherDir");
67         File linkToOtherFile = createSymlink(otherFile, subDir, "linkToOtherFile");
68 
69         File[] filesToDelete = { dir, file1, file2, symLink1, subDir, file3, file4, symLink2,
70                 linkToOtherDir, linkToOtherFile };
71         File[] filesToKeep = { otherDir, otherFile };
72         assertFilesExist(filesToDelete);
73         assertFilesExist(filesToKeep);
74 
75         FileUtils.deleteRecursive(dir);
76         assertFilesDoNotExist(filesToDelete);
77         assertFilesExist(filesToKeep);
78     }
79 
testIsSymlink()80     public void testIsSymlink() throws Exception {
81         File dir = createTempDir();
82         File subDir = createDir(dir, "subDir");
83         File fileInSubDir = createRegularFile(subDir, "fileInSubDir");
84         File normalFile = createRegularFile(dir, "normalFile");
85         File symlinkToDir = createSymlink(subDir, dir, "symlinkToDir");
86         File symlinkToFile = createSymlink(fileInSubDir, dir, "symlinkToFile");
87         File symlinkToFileInSubDir = createSymlink(fileInSubDir, dir, "symlinkToFileInSubDir");
88         File normalFileViaSymlink = new File(symlinkToDir, "normalFile");
89 
90         assertFalse(FileUtils.isSymlink(dir));
91         assertFalse(FileUtils.isSymlink(subDir));
92         assertFalse(FileUtils.isSymlink(fileInSubDir));
93         assertFalse(FileUtils.isSymlink(normalFile));
94         assertTrue(FileUtils.isSymlink(symlinkToDir));
95         assertTrue(FileUtils.isSymlink(symlinkToFile));
96         assertTrue(FileUtils.isSymlink(symlinkToFileInSubDir));
97         assertFalse(FileUtils.isSymlink(normalFileViaSymlink));
98     }
99 
testCreateSubFile()100     public void testCreateSubFile() throws Exception {
101         File dir1 = createTempDir().getCanonicalFile();
102 
103         File actualSubFile = FileUtils.createSubFile(dir1, "file");
104         assertEquals(new File(dir1, "file"), actualSubFile);
105 
106         File existingSubFile = createRegularFile(dir1, "file");
107         actualSubFile = FileUtils.createSubFile(dir1, "file");
108         assertEquals(existingSubFile, actualSubFile);
109 
110         File existingSubDir = createDir(dir1, "subdir");
111         actualSubFile = FileUtils.createSubFile(dir1, "subdir");
112         assertEquals(existingSubDir, actualSubFile);
113 
114         assertCreateSubFileThrows(dir1, "../file");
115         assertCreateSubFileThrows(dir1, "../../file");
116         assertCreateSubFileThrows(dir1, "../otherdir/file");
117 
118         File dir2 = createTempDir().getCanonicalFile();
119         createSymlink(dir2, dir1, "symlinkToDir2");
120         assertCreateSubFileThrows(dir1, "symlinkToDir2");
121 
122         assertCreateSubFileThrows(dir1, "symlinkToDir2/fileInSymlinkedDir");
123 
124         createRegularFile(dir1, "symlinkToDir2/fileInSymlinkedDir");
125         assertCreateSubFileThrows(dir1, "symlinkToDir2/fileInSymlinkedDir");
126     }
127 
testEnsureDirectoryExists()128     public void testEnsureDirectoryExists() throws Exception {
129         File dir = createTempDir();
130 
131         File exists = new File(dir, "exists");
132         assertTrue(exists.mkdir());
133         assertTrue(exists.setReadable(true /* readable */, true /* ownerOnly */));
134         assertTrue(exists.setExecutable(true /* readable */, true /* ownerOnly */));
135         FileUtils.ensureDirectoriesExist(exists, true /* makeWorldReadable */);
136         assertDirExistsAndIsAccessible(exists, false /* requireWorldReadable */);
137 
138         File subDir = new File(dir, "subDir");
139         assertFalse(subDir.exists());
140         FileUtils.ensureDirectoriesExist(subDir, true /* makeWorldReadable */);
141         assertDirExistsAndIsAccessible(subDir, true /* requireWorldReadable */);
142 
143         File one = new File(dir, "one");
144         File two = new File(one, "two");
145         File three = new File(two, "three");
146         FileUtils.ensureDirectoriesExist(three, true /* makeWorldReadable */);
147         assertDirExistsAndIsAccessible(one, true /* requireWorldReadable */);
148         assertDirExistsAndIsAccessible(two, true /* requireWorldReadable */);
149         assertDirExistsAndIsAccessible(three, true /* requireWorldReadable */);
150     }
151 
testEnsureDirectoriesExist_noPermissions()152     public void testEnsureDirectoriesExist_noPermissions() throws Exception {
153         File dir = createTempDir();
154         assertDirExistsAndIsAccessible(dir, false /* requireWorldReadable */);
155 
156         File unreadableSubDir = new File(dir, "unreadableSubDir");
157         assertTrue(unreadableSubDir.mkdir());
158         assertTrue(unreadableSubDir.setReadable(false /* readable */, true /* ownerOnly */));
159         assertTrue(unreadableSubDir.setExecutable(false /* readable */, true /* ownerOnly */));
160 
161         File toCreate = new File(unreadableSubDir, "toCreate");
162         try {
163             FileUtils.ensureDirectoriesExist(toCreate, true /* makeWorldReadable */);
164             fail();
165         } catch (IOException expected) {
166         }
167         assertDirExistsAndIsAccessible(dir, false /* requireWorldReadable */);
168         assertFalse(unreadableSubDir.canRead() && unreadableSubDir.canExecute());
169         assertFalse(toCreate.exists());
170     }
171 
testEnsureFileDoesNotExist()172     public void testEnsureFileDoesNotExist() throws Exception {
173         File dir = createTempDir();
174 
175         FileUtils.ensureFileDoesNotExist(new File(dir, "doesNotExist"));
176 
177         File exists1 = createRegularFile(dir, "exists1");
178         assertTrue(exists1.exists());
179         FileUtils.ensureFileDoesNotExist(exists1);
180         assertFalse(exists1.exists());
181 
182         exists1 = createRegularFile(dir, "exists1");
183         File symlink = createSymlink(exists1, dir, "symlinkToFile");
184         assertTrue(symlink.exists());
185         FileUtils.ensureFileDoesNotExist(symlink);
186         assertFalse(symlink.exists());
187         assertTrue(exists1.exists());
188 
189         // Only files and symlinks supported. We do not delete directories.
190         File emptyDir = createTempDir();
191         try {
192             FileUtils.ensureFileDoesNotExist(emptyDir);
193             fail();
194         } catch (IOException expected) {
195         }
196         assertTrue(emptyDir.exists());
197     }
198 
199     // This test does not pass when run as root because root can do anything even if the permissions
200     // don't allow it.
testEnsureFileDoesNotExist_noPermission()201     public void testEnsureFileDoesNotExist_noPermission() throws Exception {
202         File dir = createTempDir();
203 
204         File protectedDir = createDir(dir, "protected");
205         File undeletable = createRegularFile(protectedDir, "undeletable");
206         assertTrue(protectedDir.setWritable(false));
207         assertTrue(undeletable.exists());
208         try {
209             FileUtils.ensureFileDoesNotExist(undeletable);
210             fail();
211         } catch (IOException expected) {
212         } finally {
213             assertTrue(protectedDir.setWritable(true)); // Reset for clean-up
214         }
215         assertTrue(undeletable.exists());
216     }
217 
testCheckFilesExist()218     public void testCheckFilesExist() throws Exception {
219         File dir = createTempDir();
220         createRegularFile(dir, "exists1");
221         File subDir = createDir(dir, "subDir");
222         createRegularFile(subDir, "exists2");
223         assertTrue(FileUtils.filesExist(dir, "exists1", "subDir/exists2"));
224         assertFalse(FileUtils.filesExist(dir, "doesNotExist"));
225         assertFalse(FileUtils.filesExist(dir, "subDir/doesNotExist"));
226     }
227 
testReadBytes()228     public void testReadBytes() throws Exception {
229         File dir = createTempDir();
230 
231         try {
232             FileUtils.readBytes(new File(dir, "doesNotExist"), 0);
233             fail();
234         } catch (IllegalArgumentException expected) {
235         }
236 
237         try {
238             FileUtils.readBytes(new File(dir, "doesNotExist"), 10);
239             fail();
240         } catch (FileNotFoundException expected) {
241         }
242 
243         byte[] contents = "One\nTwo\nThree\n".getBytes(StandardCharsets.US_ASCII);
244         File file = createFile(contents);
245         byte[] oneByte = FileUtils.readBytes(file, 1);
246         assertEquals(1, oneByte.length);
247         assertEquals(contents[0], oneByte[0]);
248 
249         byte[] allBytes = FileUtils.readBytes(file, contents.length);
250         assertTrue(Arrays.equals(contents, allBytes));
251 
252         byte[] exhaustedFileRead = FileUtils.readBytes(file, contents.length + 1);
253         assertTrue(Arrays.equals(contents, exhaustedFileRead));
254     }
255 
testCreateEmptyFile()256     public void testCreateEmptyFile() throws Exception {
257         File dir = createTempDir();
258         File file = new File(dir, "one");
259         assertFalse(file.exists());
260         FileUtils.createEmptyFile(file);
261         assertTrue(file.exists());
262         assertEquals(0, file.length());
263     }
264 
testCreateEmptyFile_isDir()265     public void testCreateEmptyFile_isDir() throws Exception {
266         File dir = createTempDir();
267         assertTrue(dir.exists());
268         assertTrue(dir.isDirectory());
269 
270         try {
271             FileUtils.createEmptyFile(dir);
272         } catch (FileNotFoundException expected) {
273         }
274         assertTrue(dir.exists());
275         assertTrue(dir.isDirectory());
276     }
277 
testCreateEmptyFile_truncatesExisting()278     public void testCreateEmptyFile_truncatesExisting() throws Exception {
279         File dir = createTempDir();
280         File file = new File(dir, "one");
281 
282         try (FileOutputStream fos = new FileOutputStream(file)) {
283             fos.write(new byte[1000]);
284         }
285         assertTrue(file.exists());
286         assertEquals(1000, file.length());
287 
288         FileUtils.createEmptyFile(file);
289         assertTrue(file.exists());
290         assertEquals(0, file.length());
291     }
292 
createFile(byte[] contents)293     private File createFile(byte[] contents) throws IOException {
294         File file = File.createTempFile(getClass().getSimpleName(), ".txt");
295         try (FileOutputStream fos = new FileOutputStream(file)) {
296             fos.write(contents);
297         }
298         return file;
299     }
300 
createSymlink(File file, File symlinkDir, String symlinkName)301     private File createSymlink(File file, File symlinkDir, String symlinkName) throws Exception {
302         assertTrue(file.exists());
303 
304         File symlink = new File(symlinkDir, symlinkName);
305         Os.symlink(file.getAbsolutePath(), symlink.getAbsolutePath());
306         testFiles.add(symlink);
307         return symlink;
308     }
309 
assertCreateSubFileThrows(File parentDir, String name)310     private static void assertCreateSubFileThrows(File parentDir, String name) {
311         try {
312             FileUtils.createSubFile(parentDir, name);
313             fail();
314         } catch (IOException expected) {
315             assertTrue(expected.getMessage().contains("must exist beneath"));
316         }
317     }
318 
assertFilesDoNotExist(File... files)319     private static void assertFilesDoNotExist(File... files) {
320         for (File f : files) {
321             assertFalse(f + " unexpectedly exists", f.exists());
322         }
323     }
324 
assertFilesExist(File... files)325     private static void assertFilesExist(File... files) {
326         for (File f : files) {
327             assertTrue(f + " expected to exist", f.exists());
328         }
329     }
330 
assertDirExistsAndIsAccessible(File dir, boolean requireWorldReadable)331     private static void assertDirExistsAndIsAccessible(File dir, boolean requireWorldReadable)
332             throws Exception {
333         assertTrue(dir.exists() && dir.isDirectory() && dir.canRead() && dir.canExecute());
334 
335         String path = dir.getCanonicalPath();
336         StructStat sb = Os.stat(path);
337         int mask = OsConstants.S_IXUSR | OsConstants.S_IRUSR;
338         if (requireWorldReadable) {
339             mask = mask | OsConstants.S_IXGRP | OsConstants.S_IRGRP
340                     | OsConstants.S_IXOTH | OsConstants.S_IROTH;
341         }
342         assertTrue("Permission mask required: " + Integer.toOctalString(mask),
343                 (sb.st_mode & mask) == mask);
344     }
345 
createTempDir()346     private File createTempDir() {
347         final String tempPrefix = getClass().getSimpleName();
348         File tempDir = TestIoUtils.createTemporaryDirectory(tempPrefix);
349         testFiles.add(tempDir);
350         return tempDir;
351     }
352 
createDir(File parentDir, String name)353     private File createDir(File parentDir, String name) {
354         File dir = new File(parentDir, name);
355         assertTrue(dir.mkdir());
356         testFiles.add(dir);
357         return dir;
358     }
359 
createRegularFile(File dir, String name)360     private File createRegularFile(File dir, String name) throws Exception {
361         File file = new File(dir, name);
362         try (FileOutputStream fos = new FileOutputStream(file)) {
363             fos.write("Hello".getBytes());
364         }
365         testFiles.add(file);
366         return file;
367     }
368 }
369