Skip to content

Commit 53f6d2a

Browse files
Use NIO Files for creating temporary files
File.createTempFile should not be used due to security issues
1 parent 49de4c3 commit 53f6d2a

File tree

4 files changed

+73
-54
lines changed

4 files changed

+73
-54
lines changed

src/main/java/org/codehaus/plexus/archiver/zip/DeferredScatterOutputStream.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ public class DeferredScatterOutputStream implements ScatterGatherBackingStore
2929

3030
public DeferredScatterOutputStream( int threshold )
3131
{
32-
dfos = new OffloadingOutputStream( threshold, "scatterzipfragment", "zip", null );
32+
dfos = new OffloadingOutputStream( threshold, "scatterzipfragment", "zip" );
3333
}
3434

3535
@Override

src/main/java/org/codehaus/plexus/archiver/zip/OffloadingOutputStream.java

+18-51
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,12 @@
2323
import java.io.OutputStream;
2424
import java.io.SequenceInputStream;
2525
import java.nio.file.Files;
26+
import java.nio.file.Path;
2627

2728
import org.apache.commons.io.output.ThresholdingOutputStream;
2829

2930
/**
30-
* Offloads to disk when a given memory consumption has been reacehd
31+
* Offloads to disk when a given memory consumption has been reached
3132
*/
3233
class OffloadingOutputStream extends ThresholdingOutputStream
3334
{
@@ -48,9 +49,9 @@ class OffloadingOutputStream extends ThresholdingOutputStream
4849
private OutputStream currentOutputStream;
4950

5051
/**
51-
* The file to which output will be directed if the threshold is exceeded.
52+
* The path to which output will be directed if the threshold is exceeded.
5253
*/
53-
private File outputFile = null;
54+
private Path outputPath = null;
5455

5556
/**
5657
* The temporary file prefix.
@@ -62,58 +63,30 @@ class OffloadingOutputStream extends ThresholdingOutputStream
6263
*/
6364
private final String suffix;
6465

65-
/**
66-
* The directory to use for temporary files.
67-
*/
68-
private final File directory;
69-
70-
/**
71-
* True when close() has been called successfully.
72-
*/
73-
private boolean closed = false;
74-
7566
// ----------------------------------------------------------- Constructors
7667

7768
/**
7869
* Constructs an instance of this class which will trigger an event at the
7970
* specified threshold, and save data to a temporary file beyond that point.
8071
*
8172
* @param threshold The number of bytes at which to trigger an event.
82-
* @param prefix Prefix to use for the temporary file.
83-
* @param suffix Suffix to use for the temporary file.
84-
* @param directory Temporary file directory.
85-
*
73+
* @param prefix Prefix to use for the temporary file.
74+
* @param suffix Suffix to use for the temporary file.
8675
* @since 1.4
8776
*/
88-
public OffloadingOutputStream( int threshold, String prefix, String suffix, File directory )
77+
public OffloadingOutputStream( int threshold, String prefix, String suffix )
8978
{
90-
this( threshold, null, prefix, suffix, directory );
79+
super( threshold );
80+
9181
if ( prefix == null )
9282
{
9383
throw new IllegalArgumentException( "Temporary file prefix is missing" );
9484
}
95-
}
96-
97-
/**
98-
* Constructs an instance of this class which will trigger an event at the
99-
* specified threshold, and save data either to a file beyond that point.
100-
*
101-
* @param threshold The number of bytes at which to trigger an event.
102-
* @param outputFile The file to which data is saved beyond the threshold.
103-
* @param prefix Prefix to use for the temporary file.
104-
* @param suffix Suffix to use for the temporary file.
105-
* @param directory Temporary file directory.
106-
*/
107-
private OffloadingOutputStream( int threshold, File outputFile, String prefix, String suffix, File directory )
108-
{
109-
super( threshold );
110-
this.outputFile = outputFile;
11185

11286
memoryOutputStream = new ByteArrayOutputStream( threshold / 10 );
11387
currentOutputStream = memoryOutputStream;
11488
this.prefix = prefix;
11589
this.suffix = suffix;
116-
this.directory = directory;
11790
}
11891

11992
// --------------------------------------- ThresholdingOutputStream methods
@@ -123,8 +96,7 @@ private OffloadingOutputStream( int threshold, File outputFile, String prefix, S
12396
* based, depending on the current state with respect to the threshold.
12497
*
12598
* @return The underlying output stream.
126-
*
127-
* @exception java.io.IOException if an error occurs.
99+
* @throws java.io.IOException if an error occurs.
128100
*/
129101
@Override
130102
protected OutputStream getStream() throws IOException
@@ -138,27 +110,24 @@ protected OutputStream getStream() throws IOException
138110
* much data is being written to keep in memory, so we elect to switch to
139111
* disk-based storage.
140112
*
141-
* @exception java.io.IOException if an error occurs.
113+
* @throws java.io.IOException if an error occurs.
142114
*/
143115
@Override
144116
protected void thresholdReached() throws IOException
145117
{
146-
if ( prefix != null )
147-
{
148-
outputFile = File.createTempFile( prefix, suffix, directory );
149-
}
150-
currentOutputStream = Files.newOutputStream( outputFile.toPath() );
118+
outputPath = Files.createTempFile( prefix, suffix );
119+
currentOutputStream = Files.newOutputStream( outputPath );
151120
}
152121

153122
public InputStream getInputStream() throws IOException
154123
{
155124

156125
InputStream memoryAsInput = memoryOutputStream.toInputStream();
157-
if ( outputFile == null )
126+
if ( outputPath == null )
158127
{
159128
return memoryAsInput;
160129
}
161-
return new SequenceInputStream( memoryAsInput, Files.newInputStream( outputFile.toPath() ) );
130+
return new SequenceInputStream( memoryAsInput, Files.newInputStream( outputPath ) );
162131
}
163132

164133
// --------------------------------------------------------- Public methods
@@ -196,20 +165,18 @@ public byte[] getData()
196165
*/
197166
public File getFile()
198167
{
199-
return outputFile;
168+
return outputPath != null ? outputPath.toFile() : null;
200169
}
201170

202171
/**
203-
* Closes underlying output stream, and mark this as closed
172+
* Closes underlying output stream.
204173
*
205-
* @exception java.io.IOException if an error occurs.
174+
* @throws java.io.IOException if an error occurs.
206175
*/
207176
@Override
208177
public void close() throws IOException
209178
{
210179
super.close();
211-
closed = true;
212180
currentOutputStream.close();
213181
}
214-
215182
}

src/test/java/org/codehaus/plexus/archiver/BasePlexusArchiverTest.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,8 @@ protected void waitUntilNewTimestamp( File outputFile, long timestampReference )
5151
throws IOException
5252
{
5353
long startTime = System.currentTimeMillis();
54-
File tmpFile = File.createTempFile(
55-
"BasePlexusArchiverTest.waitUntilNewTimestamp", null );
54+
File tmpFile = Files.createTempFile(
55+
"BasePlexusArchiverTest.waitUntilNewTimestamp", null ).toFile();
5656
long newTimestamp;
5757

5858
// We could easily just set the last modified time using
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
/*
2+
* Copyright The Plexus developers.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.codehaus.plexus.archiver.zip;
18+
19+
import java.io.File;
20+
import java.io.IOException;
21+
import java.nio.file.Files;
22+
23+
import org.junit.jupiter.api.Test;
24+
25+
import static org.assertj.core.api.Assertions.assertThat;
26+
27+
28+
class OffloadingOutputStreamTest
29+
{
30+
31+
@Test
32+
void temporaryFileShouldBeCreated() throws IOException
33+
{
34+
File streamFile = null;
35+
try ( OffloadingOutputStream stream = new OffloadingOutputStream( 100, "test", "test" ) )
36+
{
37+
stream.write( new byte[256] );
38+
stream.close();
39+
streamFile = stream.getFile();
40+
assertThat( streamFile )
41+
.isFile()
42+
.hasSize( 256 );
43+
}
44+
finally
45+
{
46+
if ( streamFile != null )
47+
{
48+
Files.delete( streamFile.toPath() );
49+
}
50+
}
51+
}
52+
}

0 commit comments

Comments
 (0)