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