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