1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44 package org.eclipse.jgit.util;
45
46 import static org.junit.Assert.assertEquals;
47 import static org.junit.Assert.assertFalse;
48 import static org.junit.Assert.assertTrue;
49 import static org.junit.Assume.assumeNoException;
50 import static org.junit.Assume.assumeTrue;
51
52 import java.io.File;
53 import java.io.IOException;
54 import java.nio.charset.Charset;
55 import java.nio.file.Files;
56 import java.nio.file.InvalidPathException;
57 import java.nio.file.Path;
58 import java.nio.file.attribute.FileTime;
59 import java.nio.file.attribute.PosixFileAttributeView;
60 import java.nio.file.attribute.PosixFilePermission;
61 import java.time.Duration;
62 import java.time.ZoneId;
63 import java.time.format.DateTimeFormatter;
64 import java.util.Locale;
65 import java.util.Set;
66 import java.util.concurrent.TimeUnit;
67
68 import org.eclipse.jgit.errors.CommandFailedException;
69 import org.eclipse.jgit.junit.RepositoryTestCase;
70 import org.junit.After;
71 import org.junit.Assume;
72 import org.junit.Before;
73 import org.junit.Test;
74
75 public class FSTest {
76 private File trash;
77
78 @Before
79 public void setUp() throws Exception {
80 trash = File.createTempFile("tmp_", "");
81 trash.delete();
82 assertTrue("mkdir " + trash, trash.mkdir());
83 }
84
85 @After
86 public void tearDown() throws Exception {
87 FileUtils.delete(trash, FileUtils.RECURSIVE | FileUtils.RETRY);
88 }
89
90
91
92
93
94
95
96
97
98
99
100 @Test
101 public void testSymlinkAttributes() throws IOException, InterruptedException {
102 Assume.assumeTrue(FS.DETECTED.supportsSymlinks());
103 FS fs = FS.DETECTED;
104 File link = new File(trash, "a");
105 File target = new File(trash, "b");
106 fs.createSymLink(link, "b");
107 assertTrue(fs.exists(link));
108 String targetName = fs.readSymLink(link);
109 assertEquals("b", targetName);
110 assertTrue(fs.lastModified(link) > 0);
111 assertTrue(fs.exists(link));
112 assertFalse(fs.canExecute(link));
113
114 assertEquals(1, fs.length(link));
115 assertFalse(fs.exists(target));
116 assertFalse(fs.isFile(target));
117 assertFalse(fs.isDirectory(target));
118 assertFalse(fs.canExecute(target));
119
120 RepositoryTestCase.fsTick(link);
121
122 FileUtils.createNewFile(target);
123 assertTrue(fs.exists(link));
124 assertTrue(fs.lastModified(link) > 0);
125 assertTrue(fs.lastModified(target) > fs.lastModified(link));
126 assertFalse(fs.canExecute(link));
127 fs.setExecute(target, true);
128 assertFalse(fs.canExecute(link));
129 assumeTrue(fs.supportsExecute());
130 assertTrue(fs.canExecute(target));
131 }
132
133 @Test
134 public void testUnicodeFilePath() throws IOException {
135 Assume.assumeTrue(FS.DETECTED.supportsSymlinks());
136 FS fs = FS.DETECTED;
137 File link = new File(trash, "ä");
138 File target = new File(trash, "å");
139
140 try {
141
142 link.toPath();
143 target.toPath();
144 } catch (InvalidPathException e) {
145
146
147
148
149
150
151 assumeNoException(e);
152 }
153
154 fs.createSymLink(link, "å");
155 assertTrue(fs.exists(link));
156 assertEquals("å", fs.readSymLink(link));
157 }
158
159 @Test
160 public void testExecutableAttributes() throws Exception {
161 FS fs = FS.DETECTED.newInstance();
162
163 assumeTrue(fs instanceof FS_POSIX);
164 ((FS_POSIX) fs).setUmask(0022);
165
166 File f = new File(trash, "bla");
167 assertTrue(f.createNewFile());
168 assertFalse(fs.canExecute(f));
169
170 Set<PosixFilePermission> permissions = readPermissions(f);
171 assertTrue(!permissions.contains(PosixFilePermission.OTHERS_EXECUTE));
172 assertTrue(!permissions.contains(PosixFilePermission.GROUP_EXECUTE));
173 assertTrue(!permissions.contains(PosixFilePermission.OWNER_EXECUTE));
174
175 fs.setExecute(f, true);
176
177 permissions = readPermissions(f);
178 assertTrue("'owner' execute permission not set",
179 permissions.contains(PosixFilePermission.OWNER_EXECUTE));
180 assertTrue("'group' execute permission not set",
181 permissions.contains(PosixFilePermission.GROUP_EXECUTE));
182 assertTrue("'others' execute permission not set",
183 permissions.contains(PosixFilePermission.OTHERS_EXECUTE));
184
185 ((FS_POSIX) fs).setUmask(0033);
186 fs.setExecute(f, false);
187 assertFalse(fs.canExecute(f));
188 fs.setExecute(f, true);
189
190 permissions = readPermissions(f);
191 assertTrue("'owner' execute permission not set",
192 permissions.contains(PosixFilePermission.OWNER_EXECUTE));
193 assertFalse("'group' execute permission set",
194 permissions.contains(PosixFilePermission.GROUP_EXECUTE));
195 assertFalse("'others' execute permission set",
196 permissions.contains(PosixFilePermission.OTHERS_EXECUTE));
197 }
198
199 private Set<PosixFilePermission> readPermissions(File f) throws IOException {
200 return Files
201 .getFileAttributeView(f.toPath(), PosixFileAttributeView.class)
202 .readAttributes().permissions();
203 }
204
205 @Test(expected = CommandFailedException.class)
206 public void testReadPipePosixCommandFailure()
207 throws CommandFailedException {
208 FS fs = FS.DETECTED.newInstance();
209 assumeTrue(fs instanceof FS_POSIX);
210
211 FS.readPipe(fs.userHome(),
212 new String[] { "/bin/sh", "-c", "exit 1" },
213 Charset.defaultCharset().name());
214 }
215
216 @Test(expected = CommandFailedException.class)
217 public void testReadPipeCommandStartFailure()
218 throws CommandFailedException {
219 FS fs = FS.DETECTED.newInstance();
220
221 FS.readPipe(fs.userHome(),
222 new String[] { "this-command-does-not-exist" },
223 Charset.defaultCharset().name());
224 }
225
226 @Test
227 public void testFsTimestampResolution() throws Exception {
228 DateTimeFormatter formatter = DateTimeFormatter
229 .ofPattern("uuuu-MMM-dd HH:mm:ss.nnnnnnnnn", Locale.ENGLISH)
230 .withZone(ZoneId.systemDefault());
231 Path dir = Files.createTempDirectory("probe-filesystem");
232 Duration resolution = FS.getFsTimerResolution(dir);
233 long resolutionNs = resolution.toNanos();
234 assertTrue(resolutionNs > 0);
235 for (int i = 0; i < 10; i++) {
236 Path f = null;
237 try {
238 f = dir.resolve("testTimestampResolution" + i);
239 Files.createFile(f);
240 FileUtils.touch(f);
241 FileTime t1 = Files.getLastModifiedTime(f);
242 TimeUnit.NANOSECONDS.sleep(resolutionNs);
243 FileUtils.touch(f);
244 FileTime t2 = Files.getLastModifiedTime(f);
245 assertTrue(String.format(
246 "expected t2=%s to be larger than t1=%s\nsince file timestamp resolution was measured to be %,d ns",
247 formatter.format(t2.toInstant()),
248 formatter.format(t1.toInstant()),
249 Long.valueOf(resolutionNs)), t2.compareTo(t1) > 0);
250 } finally {
251 Files.delete(f);
252 }
253 }
254 }
255 }