Uploaded image for project: 'Confluence Data Center'
  1. Confluence Data Center
  2. CONFSERVER-59957

When exporting a Space to XML Confluence doesn't check if temporary attachment folder was properly created

XMLWordPrintable

    • Icon: Bug Bug
    • Resolution: Unresolved
    • Icon: Low Low
    • None
    • 6.13.10, 7.4.1, 7.5.0
    • None

      Issue Summary

      When exporting a Space to XML, Confluence copies pages' attachments from the attachments directory <confluence-home>/attachments/ver003/ to a temporary directory such as <confluence-home>/temp/xmlexport-<date>/attachments/<pageId>/<attachmentID>.

      If Confluence is unable to create any of the directories in the above structure, the export fails on a subsequent operation without a meaningful entry in the log on why the directory wasn't created.

      The reason why the directory wasn't created isn't the problem for this bug, since it could be something on the OS level.
      The problem is that Confluence uses a method that doesn't throw an exception if creating a directory fails.

      Steps to Reproduce

      The steps below is a way to reproduce a problem on which Confluence tries to create a directory but it isn't possible due to a problem on the OS level.
      The problem on the OS isn't the goal for this bug. This occurs because of a limitation of ext3 file system on a maximum number of subdirectories, which will be reached during the export.

      1. Have a Linux server with an ext3 partition with enough space to install Confluence.
      2. Install a vanilla instance of Confluence making sure <confluence-home> is on the ext3 file system.
        • This is validated in Confluence 6.13.10 and 7.4.1.
        • Confluence still uses the same code path on 7.5.0.
      3. Create a sample space.
      4. On that space, create 35,000 pages with one attachment in each.
        • The following script may be helpful to automate that task.
          USRNAME=admin
          USRPWD=admin
          CONFBASEURL=http://127.0.0.1:8090/conf741
          SPACE_KEY=TS2
          PARENT_PAGEID=786434
          PAGE_TITLE_PRE=PageNumber
          INIT_PAGE=1
          MAX_PAGES=35000
            
          for PAGE_NUM in $(seq ${INIT_PAGE} ${MAX_PAGES}); do
           NEW_PAGE_ID=$(curl --user $USRNAME:$USRPWD \
           -H "Content-Type: application/json" \
           -H "Accept: application/json" \
           -d '{"type":"page","title":"'$PAGE_TITLE_PRE$PAGE_NUM'", "ancestors":[{"type":"page","id":'$PARENT_PAGEID'}], "space":{"key":"'$SPACE_KEY'"},"body":{"storage":{"value":"<p>This is <br/> another new page</p>","representation": "storage"}}}' \
           -X POST $CONFBASEURL/rest/api/content 2>/dev/null | jq -r '.id')
           echo "$PAGE_TITLE_PRE$PAGE_NUM created with pageid: ${NEW_PAGE_ID}"
           
           FILENAME=testing${PAGE_NUM}.txt
           echo "this is a text file" > $FILENAME
           curl -D- -u $USRNAME:$USRPWD \
           -X POST \
           -H "X-Atlassian-Token: nocheck" -F "file=@${FILENAME}" -F "comment=This is my File" \
           ${CONFBASEURL}/rest/api/content/${NEW_PAGE_ID}/child/attachment >/dev/null 2>&1
           rm -f $FILENAME
          done
          
      5. Try to export the Space as XML.

      Expected Results

      The Space export fails because it wasn't able to create a directory to place one of the attachments.
      Checking the Confluence logs we would see an exception thrown during the directory creation and a meaningful message to understand why it couldn't create the directory.

      Actual Results

      The Space export fails because it wasn't able to create a temporary file in the target directory because one of the directories in the expected hierarchy didn't exist.
      There's no meaningful entry in the log telling which specific directory wasn't created and why.

      2020-06-17 21:02:37,069 ERROR [Long running task: Export Space] [confluence.importexport.actions.ExportSpaceLongRunningTask] doInTransactionWithoutResult Error during export
       -- url: /spaces/doexportspace.action | referer: http://10.125.91.230:8090/spaces/exportspacexml.action?key=SO | traceId: bfffe08bb52b53d2 | userName: admin | action: doexportspace
      java.lang.RuntimeException: Error creating temp file in folder: /home/ubuntu/deployments/conf741/confluence-home/temp/xmlexport-20200617-201632-1/attachments/1342429/1342433
      	at com.atlassian.confluence.pages.persistence.dao.filesystem.FileSystemAttachmentDataUtil.createTempFile(FileSystemAttachmentDataUtil.java:66)
      	at com.atlassian.confluence.pages.persistence.dao.filesystem.FileSystemAttachmentDataUtil.writeStreamToFile(FileSystemAttachmentDataUtil.java:37)
      	at com.atlassian.confluence.pages.persistence.dao.FileSystemAttachmentDataDao.writeStreamToFile(FileSystemAttachmentDataDao.java:253)
      	at com.atlassian.confluence.pages.persistence.dao.FileSystemAttachmentDataDao.saveDataForAttachment(FileSystemAttachmentDataDao.java:240)
      	at com.atlassian.confluence.pages.persistence.dao.FileSystemAttachmentDataDao.saveDataForAttachment(FileSystemAttachmentDataDao.java:205)
      	at com.atlassian.confluence.pages.persistence.dao.hibernate.AbstractHibernateAttachmentDao$IntraHibernateAttachmentCopier.saveAttachmentData(AbstractHibernateAttachmentDao.java:869)
      	at com.atlassian.confluence.pages.persistence.dao.hibernate.AbstractHibernateAttachmentDao$IntraHibernateAttachmentCopier.copy(AbstractHibernateAttachmentDao.java:840)
      	at com.atlassian.confluence.importexport.impl.FileXmlExporter.backupAttachments(FileXmlExporter.java:160)
      	at com.atlassian.confluence.importexport.impl.FileXmlExporter.backupEverything(FileXmlExporter.java:99)
      	at com.atlassian.confluence.importexport.impl.AbstractXmlExporter.doExport(AbstractXmlExporter.java:94)
      	at com.atlassian.confluence.importexport.impl.FileXmlExporter.doExportInternal(FileXmlExporter.java:60)
      	at com.atlassian.confluence.importexport.impl.FileXmlExporter.doExport(FileXmlExporter.java:54)
      	at com.atlassian.confluence.importexport.impl.XmlExporter.doExport(XmlExporter.java:52)
      	at com.atlassian.confluence.importexport.DefaultImportExportManager.doExport(DefaultImportExportManager.java:212)
      	at com.atlassian.confluence.importexport.DefaultImportExportManager.exportAs(DefaultImportExportManager.java:178)
      (...)
      	at java.util.concurrent.FutureTask.run(FutureTask.java:266)
      	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
      	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
      	at java.lang.Thread.run(Thread.java:748)
      Caused by: java.io.IOException: No such file or directory
      	at java.io.UnixFileSystem.createFileExclusively(Native Method)
      	at java.io.File.createTempFile(File.java:2024)
      	at com.atlassian.confluence.pages.persistence.dao.filesystem.FileSystemAttachmentDataUtil.createTempFile(FileSystemAttachmentDataUtil.java:64)
      	... 43 more
      

      This occurs because this portion of the code was implemented using java.io.Files.mkdirs() method which doesn't throw any exception when it fails.
      Although this method doesn't throw an exception on failure, it provide an option to check if it went successfully, which is not used within the code.

      An option could be to migrate to java.nio.file.Files.createDirectories() method.

      Workaround

      Currently there is no known workaround for this behavior. A workaround will be added here when available

              Unassigned Unassigned
              tmasutti Thiago Masutti
              Votes:
              3 Vote for this issue
              Watchers:
              2 Start watching this issue

                Created:
                Updated: