Skip to content

Commit 4d1ded4

Browse files
committed
Add PathMatcherFileFilter to adapt java.nio.file.PathMatcher
- MagicNumberFileFilter.accept(Path, BasicFileAttributes) doesn't its byteOffset before reading. - Move fixes into first changes section
1 parent cee49cf commit 4d1ded4

7 files changed

Lines changed: 155 additions & 40 deletions

File tree

src/changes/changes.xml

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,19 @@ The <action> type attribute can be add,update,fix,remove.
4848

4949
<body>
5050
<release version="2.14.0" date="2023-MM-DD" description="Java 8 required.">
51+
<!-- FIX -->
52+
<action dev="ggregory" type="fix" issue="IO-799" due-to="Jeroen van der Vegt, Gary Gregory">
53+
ReaderInputStream.read() throws an exception instead of returning -1 when called again after returning -1.
54+
</action>
55+
<action dev="ggregory" type="fix" issue="IO-804" due-to="Elliotte Rusty Harold, Gary Gregory">
56+
FileUtils.forceMkdirParent() Javadoc is likely incorrect.
57+
</action>
58+
<action dev="ggregory" type="fix" due-to="step-security-bot, Gary Gregory">
59+
[StepSecurity] ci: Harden GitHub Actions #461.
60+
</action>
61+
<action dev="ggregory" type="fix" due-to="Gary Gregory">
62+
MagicNumberFileFilter.accept(Path, BasicFileAttributes) doesn't its byteOffset before reading.
63+
</action>
5164
<!-- ADD -->
5265
<action dev="ggregory" type="add" due-to="Gary Gregory">
5366
Add DeferredFileOutputStream.getPath().
@@ -82,15 +95,8 @@ The <action> type attribute can be add,update,fix,remove.
8295
<action dev="ggregory" type="add" due-to="Gary Gregory">
8396
IOFileFilter now also extends java.nio.file.PathMatcher.
8497
</action>
85-
<!-- FIX -->
86-
<action dev="ggregory" type="fix" issue="IO-799" due-to="Jeroen van der Vegt, Gary Gregory">
87-
ReaderInputStream.read() throws an exception instead of returning -1 when called again after returning -1.
88-
</action>
89-
<action dev="ggregory" type="fix" issue="IO-804" due-to="Elliotte Rusty Harold, Gary Gregory">
90-
FileUtils.forceMkdirParent() Javadoc is likely incorrect.
91-
</action>
92-
<action dev="ggregory" type="fix" due-to="step-security-bot, Gary Gregory">
93-
[StepSecurity] ci: Harden GitHub Actions #461.
98+
<action dev="ggregory" type="add" due-to="Gary Gregory">
99+
Add PathMatcherFileFilter to adapt java.nio.file.PathMatcher.
94100
</action>
95101
<!-- UPDATE -->
96102
</release>

src/main/java/org/apache/commons/io/filefilter/MagicNumberFileFilter.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -293,6 +293,7 @@ public FileVisitResult accept(final Path file, final BasicFileAttributes attribu
293293
try {
294294
try (FileChannel fileChannel = FileChannel.open(file)) {
295295
final ByteBuffer byteBuffer = ByteBuffer.allocate(this.magicNumbers.length);
296+
fileChannel.position(byteOffset);
296297
final int read = fileChannel.read(byteBuffer);
297298
if (read != magicNumbers.length) {
298299
return FileVisitResult.TERMINATE;
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one or more
3+
* contributor license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright ownership.
5+
* The ASF licenses this file to You under the Apache License, Version 2.0
6+
* (the "License"); you may not use this file except in compliance with
7+
* the License. You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
18+
package org.apache.commons.io.filefilter;
19+
20+
import java.io.File;
21+
import java.nio.file.Path;
22+
import java.nio.file.PathMatcher;
23+
24+
/**
25+
* Delegates matching to a {@link PathMatcher}.
26+
*
27+
* @since 2.14.0
28+
*/
29+
public class PathMatcherFileFilter extends AbstractFileFilter {
30+
31+
private final PathMatcher pathMatcher;
32+
33+
/**
34+
* Constructs a new instance to perform matching with a PathMatcher.
35+
*
36+
* @param pathMatcher The PathMatcher delegate.
37+
*/
38+
public PathMatcherFileFilter(final PathMatcher pathMatcher) {
39+
this.pathMatcher = pathMatcher;
40+
}
41+
42+
@Override
43+
public boolean accept(File file) {
44+
return file != null && matches(file.toPath());
45+
}
46+
@Override
47+
public boolean matches(final Path path) {
48+
return pathMatcher.matches(path);
49+
}
50+
}

src/test/java/org/apache/commons/io/filefilter/AbstractFilterTest.java

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import java.nio.file.FileVisitResult;
2525
import java.nio.file.Files;
2626
import java.nio.file.Path;
27+
import java.nio.file.attribute.BasicFileAttributes;
2728

2829
import org.apache.commons.io.IOCase;
2930
import org.junit.jupiter.api.io.TempDir;
@@ -43,14 +44,21 @@ public class AbstractFilterTest {
4344
@TempDir
4445
public File temporaryFolder;
4546

46-
void assertFiltering(final IOFileFilter filter, final File file, final boolean expected) {
47+
void assertFiltering(final IOFileFilter filter, final File file, final boolean expected) throws IOException {
4748
// Note. This only tests the (File, String) version if the parent of
4849
// the File passed in is not null
4950
assertEquals(expected, filter.accept(file), "Filter(File) " + filter.getClass().getName() + " not " + expected + " for " + file);
5051

5152
if (file != null && file.getParentFile() != null) {
5253
assertEquals(expected, filter.accept(file.getParentFile(), file.getName()),
5354
"Filter(File, String) " + filter.getClass().getName() + " not " + expected + " for " + file);
55+
final Path path = file.toPath();
56+
assertEquals(expected, filter.accept(path, null) != FileVisitResult.TERMINATE, filter::toString);
57+
if (Files.isRegularFile(path)) {
58+
assertEquals(expected, filter.accept(path, Files.readAttributes(path, BasicFileAttributes.class)) != FileVisitResult.TERMINATE,
59+
filter::toString);
60+
}
61+
assertEquals(expected, filter.matches(path), filter::toString);
5462
} else if (file == null) {
5563
assertEquals(expected, filter.accept(null), "Filter(File, String) " + filter.getClass().getName() + " not " + expected + " for null");
5664
assertEquals(expected, filter.matches(null), "Filter(File, String) " + filter.getClass().getName() + " not " + expected + " for null");
@@ -63,7 +71,7 @@ void assertFiltering(final IOFileFilter filter, final Path path, final boolean e
6371
// the File passed in is not null
6472
final FileVisitResult expectedFileVisitResult = AbstractFileFilter.toDefaultFileVisitResult(expected);
6573
assertEquals(expectedFileVisitResult, filter.accept(path, null),
66-
"Filter(Path) " + filter.getClass().getName() + " not " + expectedFileVisitResult + " for " + path);
74+
"Filter(Path) " + filter.getClass().getName() + " not " + expectedFileVisitResult + " for " + path);
6775

6876
if (path != null && path.getParent() != null) {
6977
assertEquals(expectedFileVisitResult, filter.accept(path, null),
@@ -79,7 +87,7 @@ void assertFiltering(final IOFileFilter filter, final Path path, final boolean e
7987
assertNotNull(filter.toString());
8088
}
8189

82-
void assertFooBarFileFiltering(IOFileFilter filter) {
90+
void assertFooBarFileFiltering(IOFileFilter filter) throws IOException {
8391
assertFiltering(filter, new File("foo"), true);
8492
assertFiltering(filter, new File("foo"), true);
8593
assertFiltering(filter, new File("bar"), true);
@@ -89,7 +97,7 @@ void assertFooBarFileFiltering(IOFileFilter filter) {
8997
assertFiltering(filter, new File("bar").toPath(), true);
9098
assertFiltering(filter, new File("fred").toPath(), false);
9199

92-
filter = new NameFileFilter(new String[] {"foo", "bar"}, IOCase.SENSITIVE);
100+
filter = new NameFileFilter(new String[] { "foo", "bar" }, IOCase.SENSITIVE);
93101
assertFiltering(filter, new File("foo"), true);
94102
assertFiltering(filter, new File("bar"), true);
95103
assertFiltering(filter, new File("FOO"), false);
@@ -99,7 +107,7 @@ void assertFooBarFileFiltering(IOFileFilter filter) {
99107
assertFiltering(filter, new File("FOO").toPath(), false);
100108
assertFiltering(filter, new File("BAR").toPath(), false);
101109

102-
filter = new NameFileFilter(new String[] {"foo", "bar"}, IOCase.INSENSITIVE);
110+
filter = new NameFileFilter(new String[] { "foo", "bar" }, IOCase.INSENSITIVE);
103111
assertFiltering(filter, new File("foo"), true);
104112
assertFiltering(filter, new File("bar"), true);
105113
assertFiltering(filter, new File("FOO"), true);
@@ -109,7 +117,7 @@ void assertFooBarFileFiltering(IOFileFilter filter) {
109117
assertFiltering(filter, new File("FOO").toPath(), true);
110118
assertFiltering(filter, new File("BAR").toPath(), true);
111119

112-
filter = new NameFileFilter(new String[] {"foo", "bar"}, IOCase.SYSTEM);
120+
filter = new NameFileFilter(new String[] { "foo", "bar" }, IOCase.SYSTEM);
113121
assertFiltering(filter, new File("foo"), true);
114122
assertFiltering(filter, new File("bar"), true);
115123
assertFiltering(filter, new File("FOO"), WINDOWS);
@@ -119,7 +127,7 @@ void assertFooBarFileFiltering(IOFileFilter filter) {
119127
assertFiltering(filter, new File("FOO").toPath(), WINDOWS);
120128
assertFiltering(filter, new File("BAR").toPath(), WINDOWS);
121129

122-
filter = new NameFileFilter(new String[] {"foo", "bar"}, null);
130+
filter = new NameFileFilter(new String[] { "foo", "bar" }, null);
123131
assertFiltering(filter, new File("foo"), true);
124132
assertFiltering(filter, new File("bar"), true);
125133
assertFiltering(filter, new File("FOO"), false);

src/test/java/org/apache/commons/io/filefilter/FileFilterTest.java

Lines changed: 22 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
import java.io.File;
3030
import java.io.FileFilter;
3131
import java.io.FilenameFilter;
32+
import java.io.IOException;
3233
import java.io.OutputStream;
3334
import java.nio.charset.StandardCharsets;
3435
import java.nio.file.FileVisitResult;
@@ -153,7 +154,7 @@ public void testAgeFilter() throws Exception {
153154
}
154155

155156
@Test
156-
public void testAnd() {
157+
public void testAnd() throws IOException {
157158
final IOFileFilter trueFilter = TrueFileFilter.INSTANCE;
158159
final IOFileFilter falseFilter = FalseFileFilter.INSTANCE;
159160
assertFiltering(trueFilter.and(trueFilter), new File("foo.test"), true);
@@ -163,7 +164,7 @@ public void testAnd() {
163164
}
164165

165166
@Test
166-
public void testAnd2() {
167+
public void testAnd2() throws IOException {
167168
final IOFileFilter trueFilter = TrueFileFilter.INSTANCE;
168169
final IOFileFilter falseFilter = FalseFileFilter.INSTANCE;
169170
assertFiltering(new AndFileFilter(trueFilter, trueFilter), new File("foo.test"), true);
@@ -181,7 +182,7 @@ public void testAnd2() {
181182
}
182183

183184
@Test
184-
public void testAndArray() {
185+
public void testAndArray() throws IOException {
185186
final IOFileFilter trueFilter = TrueFileFilter.INSTANCE;
186187
final IOFileFilter falseFilter = FalseFileFilter.INSTANCE;
187188
assertFiltering(new AndFileFilter(trueFilter, trueFilter, trueFilter), new File("foo.test"), true);
@@ -252,7 +253,7 @@ public void testCanWrite() throws Exception {
252253
}
253254

254255
@Test
255-
public void testDelegateFileFilter() {
256+
public void testDelegateFileFilter() throws IOException {
256257
final OrFileFilter orFilter = new OrFileFilter();
257258
final File testFile = new File("test.txt");
258259

@@ -276,7 +277,7 @@ public void testDelegation() { // TODO improve these tests
276277

277278
@SuppressWarnings("deprecation")
278279
@Test
279-
public void testDeprecatedWildcard() {
280+
public void testDeprecatedWildcard() throws IOException {
280281
IOFileFilter filter = new WildcardFilter("*.txt");
281282
final List<String> patternList = Arrays.asList("*.txt", "*.xml", "*.gif");
282283
final IOFileFilter listFilter = new WildcardFilter(patternList);
@@ -355,7 +356,7 @@ public void testDeprecatedWildcard() {
355356
}
356357

357358
@Test
358-
public void testDirectory() {
359+
public void testDirectory() throws IOException {
359360
// XXX: This test presumes the current working dir is the base dir of the source checkout.
360361
final IOFileFilter filter = new DirectoryFileFilter();
361362

@@ -432,7 +433,7 @@ public void testEnsureTestCoverage() {
432433
}
433434

434435
@Test
435-
public void testFalse() {
436+
public void testFalse() throws IOException {
436437
final IOFileFilter filter = FileFilterUtils.falseFileFilter();
437438
assertFiltering(filter, new File("foo.test"), false);
438439
assertFiltering(filter, new File("foo.test").toPath(), false);
@@ -447,13 +448,13 @@ public void testFalse() {
447448
}
448449

449450
@Test
450-
public void testFileEqualsFilter() {
451+
public void testFileEqualsFilter() throws IOException {
451452
assertFooBarFileFiltering(
452453
new FileEqualsFileFilter(new File("foo")).or(new FileEqualsFileFilter(new File("bar"))));
453454
}
454455

455456
@Test
456-
public void testFileFilterUtils_and() {
457+
public void testFileFilterUtils_and() throws IOException {
457458
final IOFileFilter trueFilter = TrueFileFilter.INSTANCE;
458459
final IOFileFilter falseFilter = FalseFileFilter.INSTANCE;
459460
assertFiltering(FileFilterUtils.and(trueFilter, trueFilter, trueFilter), new File("foo.test"), true);
@@ -463,7 +464,7 @@ public void testFileFilterUtils_and() {
463464
}
464465

465466
@Test
466-
public void testFileFilterUtils_or() {
467+
public void testFileFilterUtils_or() throws IOException {
467468
final IOFileFilter trueFilter = TrueFileFilter.INSTANCE;
468469
final IOFileFilter falseFilter = FalseFileFilter.INSTANCE;
469470
final File testFile = new File("foo.test");
@@ -474,7 +475,7 @@ public void testFileFilterUtils_or() {
474475
}
475476

476477
@Test
477-
public void testFiles() {
478+
public void testFiles() throws IOException {
478479
// XXX: This test presumes the current working dir is the base dir of the source checkout.
479480
final IOFileFilter filter = FileFileFilter.INSTANCE;
480481

@@ -700,7 +701,7 @@ public void testFilterSetNullParameters() {
700701
}
701702

702703
@Test
703-
public void testHidden() {
704+
public void testHidden() throws IOException {
704705
final File hiddenDirFile = new File(SVN_DIR_NAME);
705706
final Path hiddenDirPath = hiddenDirFile.toPath();
706707
if (hiddenDirFile.exists()) {
@@ -797,8 +798,6 @@ public void testMagicNumberFileFilterBytesOffset() throws Exception {
797798
assertFiltering(filter, dir, false);
798799
}
799800

800-
// -----------------------------------------------------------------------
801-
802801
@Test
803802
public void testMagicNumberFileFilterString() throws Exception {
804803
final byte[] classFileMagicNumber = {(byte) 0xCA, (byte) 0xFE, (byte) 0xBA, (byte) 0xBE};
@@ -1037,7 +1036,7 @@ public void testMakeSVNAware() throws Exception {
10371036
}
10381037

10391038
@Test
1040-
public void testNameFilter() {
1039+
public void testNameFilter() throws IOException {
10411040
assertFooBarFileFiltering(new NameFileFilter("foo", "bar"));
10421041
}
10431042

@@ -1061,7 +1060,7 @@ public void testNameFilterNullListArgument() {
10611060
}
10621061

10631062
@Test
1064-
public void testNegate() {
1063+
public void testNegate() throws IOException {
10651064
final IOFileFilter filter = FileFilterUtils.notFileFilter(FileFilterUtils.trueFileFilter());
10661065
assertFiltering(filter, new File("foo.test"), false);
10671066
assertFiltering(filter, new File("foo"), false);
@@ -1077,7 +1076,7 @@ public void testNullFilters() {
10771076
}
10781077

10791078
@Test
1080-
public void testOr() {
1079+
public void testOr() throws IOException {
10811080
final IOFileFilter trueFilter = TrueFileFilter.INSTANCE;
10821081
final IOFileFilter falseFilter = FalseFileFilter.INSTANCE;
10831082
final File testFile = new File("foo.test");
@@ -1124,13 +1123,13 @@ public void testOr() {
11241123
}
11251124

11261125
@Test
1127-
public void testPathEqualsFilter() {
1126+
public void testPathEqualsFilter() throws IOException {
11281127
assertFooBarFileFiltering(
11291128
new PathEqualsFileFilter(Paths.get("foo")).or(new PathEqualsFileFilter(Paths.get("bar"))));
11301129
}
11311130

11321131
@Test
1133-
public void testPrefix() {
1132+
public void testPrefix() throws IOException {
11341133
IOFileFilter filter = new PrefixFileFilter("foo", "bar");
11351134
final File testFile = new File("test");
11361135
final Path testPath = testFile.toPath();
@@ -1194,7 +1193,7 @@ public void testPrefix() {
11941193
}
11951194

11961195
@Test
1197-
public void testPrefixCaseInsensitive() {
1196+
public void testPrefixCaseInsensitive() throws IOException {
11981197

11991198
IOFileFilter filter = new PrefixFileFilter(new String[] {"foo", "bar"}, IOCase.INSENSITIVE);
12001199
assertFiltering(filter, new File("foo.test1"), true);
@@ -1323,7 +1322,7 @@ public void testSizeFilterOnPaths() throws Exception {
13231322
}
13241323

13251324
@Test
1326-
public void testSuffix() {
1325+
public void testSuffix() throws IOException {
13271326
IOFileFilter filter = new SuffixFileFilter("tes", "est");
13281327
final File testFile = new File("test");
13291328
final Path testPath = testFile.toPath();
@@ -1380,7 +1379,7 @@ public void testSuffix() {
13801379
}
13811380

13821381
@Test
1383-
public void testSuffixCaseInsensitive() {
1382+
public void testSuffixCaseInsensitive() throws IOException {
13841383

13851384
IOFileFilter filter = new SuffixFileFilter(new String[] {"tes", "est"}, IOCase.INSENSITIVE);
13861385
assertFiltering(filter, new File("foo.tes"), true);
@@ -1414,7 +1413,7 @@ public void testSuffixCaseInsensitive() {
14141413
}
14151414

14161415
@Test
1417-
public void testTrue() {
1416+
public void testTrue() throws IOException {
14181417
final IOFileFilter filter = FileFilterUtils.trueFileFilter();
14191418
assertFiltering(filter, new File("foo.test"), true);
14201419
assertFiltering(filter, new File("foo"), true);

0 commit comments

Comments
 (0)