From 01d4b5d0aa84346889b8d380965a674ac108a2c1 Mon Sep 17 00:00:00 2001 From: Thomas Mortagne Date: Thu, 31 Oct 2024 14:55:08 +0100 Subject: [PATCH] XCOMMONS-2387: Exception when saving status because file path too long --- .../job/internal/DefaultJobStatusStore.java | 17 +++++++++++++++-- .../job/internal/DefaultJobStatusStoreTest.java | 16 +++++++++++++++- 2 files changed, 30 insertions(+), 3 deletions(-) diff --git a/xwiki-commons-core/xwiki-commons-job/xwiki-commons-job-default/src/main/java/org/xwiki/job/internal/DefaultJobStatusStore.java b/xwiki-commons-core/xwiki-commons-job/xwiki-commons-job-default/src/main/java/org/xwiki/job/internal/DefaultJobStatusStore.java index eac07b9cfa..d3c9117ca5 100644 --- a/xwiki-commons-core/xwiki-commons-job/xwiki-commons-job-default/src/main/java/org/xwiki/job/internal/DefaultJobStatusStore.java +++ b/xwiki-commons-core/xwiki-commons-job/xwiki-commons-job-default/src/main/java/org/xwiki/job/internal/DefaultJobStatusStore.java @@ -35,6 +35,7 @@ import javax.inject.Inject; import javax.inject.Singleton; +import org.apache.commons.codec.binary.Base64; import org.apache.commons.configuration2.PropertiesConfiguration; import org.apache.commons.configuration2.builder.FileBasedConfigurationBuilder; import org.apache.commons.configuration2.builder.fluent.Parameters; @@ -343,8 +344,20 @@ private File getJobFolder(List id) File folder = this.configuration.getStorage(); if (id != null) { - for (String idElement : id) { - folder = new File(folder, encode(idElement)); + // Create a different folder for each element + for (String fullIdElement : id) { + // But cut each element is it's bigger than 255 bytes (and not characters) since it's a very common + // limit for a single element of the path among file systems + // To be sure to deal with characters not taking more than 1 byte, we start by encoding it in base 64 + String encodedIdElement = Base64.encodeBase64String(fullIdElement.getBytes()); + if (encodedIdElement.length() > 255) { + do { + folder = new File(folder, encode(encodedIdElement.substring(0, 255))); + encodedIdElement = encodedIdElement.substring(255); + } while (encodedIdElement.length() > 255); + } else { + folder = new File(folder, encode(encodedIdElement)); + } } } diff --git a/xwiki-commons-core/xwiki-commons-job/xwiki-commons-job-default/src/test/java/org/xwiki/job/internal/DefaultJobStatusStoreTest.java b/xwiki-commons-core/xwiki-commons-job/xwiki-commons-job-default/src/test/java/org/xwiki/job/internal/DefaultJobStatusStoreTest.java index 2f81f379a9..ab199cc21a 100644 --- a/xwiki-commons-core/xwiki-commons-job/xwiki-commons-job-default/src/test/java/org/xwiki/job/internal/DefaultJobStatusStoreTest.java +++ b/xwiki-commons-core/xwiki-commons-job/xwiki-commons-job-default/src/test/java/org/xwiki/job/internal/DefaultJobStatusStoreTest.java @@ -26,7 +26,9 @@ import javax.inject.Provider; +import org.apache.commons.codec.binary.Base64; import org.apache.commons.io.FileUtils; +import org.apache.commons.lang3.StringUtils; import org.junit.jupiter.api.Test; import org.mockito.invocation.InvocationOnMock; import org.mockito.stubbing.Answer; @@ -396,6 +398,17 @@ void storeJobStatusWithNullId() this.store.store(jobStatus); } + @Test + void storeJobStatusWithBigId() + { + DefaultRequest request = new DefaultRequest(); + request.setId(StringUtils.repeat('a', 768)); + + JobStatus jobStatus = new DefaultJobStatus("type", request, null, null, null); + + this.store.store(jobStatus); + } + @Test void storeUnserializableJobStatus() { @@ -442,7 +455,8 @@ void storeJobStatusWhenSerializable() // Verify that the status has been serialized, indirectly verifying that isSerializable() has been called and // returned true. - assertTrue(new File(this.storeDirectory, "newstatus/status.xml.zip").exists()); + assertTrue(new File(this.storeDirectory, Base64.encodeBase64String(id.get(0).getBytes()) + "/status.xml.zip") + .exists()); } @Test