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