Skip to content

Commit 9c335b1

Browse files
Copilotslachiewicz
andcommitted
Fix: Delete existing file before extracting to handle read-only files
Co-authored-by: slachiewicz <[email protected]>
1 parent 8599e56 commit 9c335b1

File tree

2 files changed

+35
-3
lines changed

2 files changed

+35
-3
lines changed

src/main/java/org/codehaus/plexus/archiver/AbstractUnArchiver.java

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,6 @@
3838
import org.slf4j.Logger;
3939
import org.slf4j.LoggerFactory;
4040

41-
import static java.nio.file.StandardCopyOption.REPLACE_EXISTING;
42-
4341
// TODO there should really be constructors which take the source file.
4442

4543
/**
@@ -324,7 +322,12 @@ protected void extractFile(
324322
} else if (isDirectory) {
325323
targetFileName.mkdirs();
326324
} else {
327-
Files.copy(compressedInputStream, targetFileName.toPath(), REPLACE_EXISTING);
325+
// Delete existing file first to handle read-only files
326+
// This matches the behavior of tar and unzip
327+
if (targetFileName.exists()) {
328+
targetFileName.delete();
329+
}
330+
Files.copy(compressedInputStream, targetFileName.toPath());
328331
}
329332

330333
targetFileName.setLastModified(entryDate.getTime());

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

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,4 +188,33 @@ void shouldExtractWhenCasingDifferOnlyInEntryNamePath(@TempDir File temporaryFol
188188
assertTrue(abstractUnArchiver.shouldExtractEntry(temporaryFolder, file, entryName, entryDate));
189189
assertEquals(0, abstractUnArchiver.casingMessageEmitted.get());
190190
}
191+
192+
@Test
193+
void shouldExtractReadOnlyFile(@TempDir File temporaryFolder) throws Exception {
194+
// given
195+
File readOnlyFile = new File(temporaryFolder, "readonly.txt");
196+
readOnlyFile.createNewFile();
197+
java.nio.file.Files.write(readOnlyFile.toPath(), "original content".getBytes());
198+
199+
// Make the file read-only (simulate -r-xr-xr-x permissions)
200+
readOnlyFile.setWritable(false);
201+
assertTrue(readOnlyFile.exists());
202+
assertFalse(readOnlyFile.canWrite());
203+
204+
// Create a mock input stream with new content
205+
String newContent = "new content";
206+
java.io.InputStream inputStream = new java.io.ByteArrayInputStream(newContent.getBytes());
207+
208+
// when
209+
abstractUnArchiver.setOverwrite(true);
210+
abstractUnArchiver.extractFile(
211+
null, temporaryFolder, inputStream, "readonly.txt", new Date(), false, null, null, null);
212+
213+
// then
214+
// The file should have been successfully overwritten
215+
assertTrue(readOnlyFile.exists());
216+
byte[] actualBytes = java.nio.file.Files.readAllBytes(readOnlyFile.toPath());
217+
String actualContent = new String(actualBytes);
218+
assertEquals(newContent, actualContent);
219+
}
191220
}

0 commit comments

Comments
 (0)