Skip to content

Commit 9632ee1

Browse files
Close DeferredFileOutputStream to prevent FileNotFoundException on temp files (#157)
--------- Co-authored-by: copilot-swe-agent[bot] <[email protected]> Co-authored-by: slachiewicz <[email protected]>
1 parent aef5f5b commit 9632ee1

File tree

3 files changed

+125
-8
lines changed

3 files changed

+125
-8
lines changed

‎src/main/java/org/codehaus/plexus/components/io/resources/Deferred.java‎

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,9 +47,10 @@ public Deferred(final PlexusIoResource resource, PlexusIoResourceCollection owne
4747
.get()
4848
: null;
4949
if (dfos != null){
50-
InputStreaminputStream = owner.getInputStream(resource);
51-
IOUtils.copy(inputStream, dfos);
52-
IOUtils.closeQuietly(inputStream);
50+
try (InputStreaminputStream = owner.getInputStream(resource);
51+
DeferredFileOutputStreamcloseable = dfos){
52+
IOUtils.copy(inputStream, dfos);
53+
}
5354
}
5455
}
5556

‎src/main/java/org/codehaus/plexus/components/io/resources/PlexusIoFileResource.java‎

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -108,11 +108,11 @@ private static DeferredFileOutputStream asDeferredStream(
108108
.setThreshold(5000000)
109109
.setPrefix("p-archiver")
110110
.get();
111-
InputStreaminputStream = supplier.getContents();
112-
InputStreamtransformed = transToUse.transform(resource, inputStream);
113-
IOUtils.copy(transformed, dfos);
114-
IOUtils.closeQuietly(inputStream);
115-
IOUtils.closeQuietly(transformed);
111+
try (InputStreaminputStream = supplier.getContents();
112+
InputStreamtransformed = transToUse.transform(resource, inputStream);
113+
DeferredFileOutputStreamcloseable = dfos){
114+
IOUtils.copy(transformed, dfos);
115+
}
116116
returndfos;
117117
}
118118

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
packageorg.codehaus.plexus.components.io.resources;
2+
3+
importjava.io.File;
4+
importjava.io.IOException;
5+
importjava.io.InputStream;
6+
importjava.io.OutputStream;
7+
importjava.nio.charset.StandardCharsets;
8+
importjava.nio.file.Files;
9+
10+
importorg.apache.commons.io.IOUtils;
11+
importorg.codehaus.plexus.components.io.attributes.FileAttributes;
12+
importorg.codehaus.plexus.components.io.functions.InputStreamTransformer;
13+
importorg.junit.jupiter.api.Test;
14+
importorg.junit.jupiter.api.io.TempDir;
15+
16+
importstaticorg.junit.jupiter.api.Assertions.*;
17+
18+
/**
19+
* Tests for PlexusIoFileResource with DeferredFileOutputStream scenarios.
20+
* This specifically tests the fix for issue #118 where temp files were deleted
21+
* before they could be accessed, causing FileNotFoundException.
22+
*/
23+
publicclassPlexusIoFileResourceDeferredTest{
24+
25+
@TempDir
26+
FiletempDir;
27+
28+
@Test
29+
voidtestFileResourceWithTransformerCanReadContentsMultipleTimes() throwsIOException{
30+
// Create a test file with content larger than typical buffer size
31+
FiletestFile = newFile(tempDir, "test-file.txt");
32+
byte[] largeContent = newbyte[10000]; // 10KB
33+
for (inti = 0; i < largeContent.length; i++){
34+
largeContent[i] = (byte) ('A' + (i % 26));
35+
}
36+
Files.write(testFile.toPath(), largeContent);
37+
38+
// Create a transformer that modifies the content
39+
InputStreamTransformertransformer = (resource, inputStream) ->{
40+
// Simple transformer that reads and returns the same content
41+
returninputStream;
42+
};
43+
44+
// Create PlexusIoFileResource with transformer
45+
PlexusIoFileResourceresource =
46+
newPlexusIoFileResource(testFile, testFile.getName(), newFileAttributes(testFile), null, transformer);
47+
48+
// First read - this should work and not delete the temp file
49+
try (InputStreamis1 = resource.getContents()){
50+
byte[] read1 = IOUtils.toByteArray(is1);
51+
assertEquals(largeContent.length, read1.length);
52+
}
53+
54+
// Second read - this should also work if the temp file wasn't prematurely deleted
55+
// This is the key test - without the fix, this would throw FileNotFoundException
56+
try (InputStreamis2 = resource.getContents()){
57+
byte[] read2 = IOUtils.toByteArray(is2);
58+
assertEquals(largeContent.length, read2.length);
59+
}
60+
}
61+
62+
@Test
63+
voidtestFileResourceWithTransformerLargeFile() throwsIOException{
64+
// Create a large file that exceeds the DeferredFileOutputStream threshold (5MB)
65+
FiletestFile = newFile(tempDir, "large-test-file.bin");
66+
byte[] chunk = newbyte[1024 * 1024]; // 1MB chunks
67+
for (inti = 0; i < chunk.length; i++){
68+
chunk[i] = (byte) i;
69+
}
70+
71+
// Write 6MB to exceed the 5MB threshold
72+
try (OutputStreamos = Files.newOutputStream(testFile.toPath())){
73+
for (inti = 0; i < 6; i++){
74+
os.write(chunk);
75+
}
76+
}
77+
78+
InputStreamTransformertransformer = (resource, inputStream) -> inputStream;
79+
80+
PlexusIoFileResourceresource =
81+
newPlexusIoFileResource(testFile, testFile.getName(), newFileAttributes(testFile), null, transformer);
82+
83+
// Verify we can read the content - this tests that the temp file
84+
// created by DeferredFileOutputStream is properly accessible
85+
longsize = resource.getSize();
86+
assertTrue(size > 5_000_000, "File should be larger than 5MB threshold");
87+
88+
try (InputStreamis = resource.getContents()){
89+
assertNotNull(is);
90+
byte[] firstBytes = newbyte[1024];
91+
intread = is.read(firstBytes);
92+
assertEquals(1024, read);
93+
}
94+
}
95+
96+
@Test
97+
voidtestFileResourceWithTransformerSmallFile() throwsIOException{
98+
// Test with a small file that stays in memory (below 5MB threshold)
99+
FiletestFile = newFile(tempDir, "small-test-file.txt");
100+
Stringcontent = "Hello, World!";
101+
Files.write(testFile.toPath(), content.getBytes(StandardCharsets.UTF_8));
102+
103+
InputStreamTransformertransformer = (resource, inputStream) -> inputStream;
104+
105+
PlexusIoFileResourceresource =
106+
newPlexusIoFileResource(testFile, testFile.getName(), newFileAttributes(testFile), null, transformer);
107+
108+
// Multiple reads should work for small files too
109+
for (inti = 0; i < 3; i++){
110+
try (InputStreamis = resource.getContents()){
111+
StringreadContent = IOUtils.toString(is, StandardCharsets.UTF_8);
112+
assertEquals(content, readContent);
113+
}
114+
}
115+
}
116+
}

0 commit comments

Comments
(0)