You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jackrabbit.apache.org by kw...@apache.org on 2022/07/13 15:44:46 UTC

[jackrabbit-filevault] branch bugfix/JCRVLT-644-final created (now 15ff683c)

This is an automated email from the ASF dual-hosted git repository.

kwin pushed a change to branch bugfix/JCRVLT-644-final
in repository https://gitbox.apache.org/repos/asf/jackrabbit-filevault.git


      at 15ff683c JCRVLT-644 catch and log SaxException when not in strict mode

This branch includes the following new commits:

     new 15ff683c JCRVLT-644 catch and log SaxException when not in strict mode

The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.



[jackrabbit-filevault] 01/01: JCRVLT-644 catch and log SaxException when not in strict mode

Posted by kw...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

kwin pushed a commit to branch bugfix/JCRVLT-644-final
in repository https://gitbox.apache.org/repos/asf/jackrabbit-filevault.git

commit 15ff683cb4d04d3cca62a52bbe75dfda86a3a178
Author: Konrad Windszus <kw...@apache.org>
AuthorDate: Wed Jul 13 16:32:56 2022 +0200

    JCRVLT-644 catch and log SaxException when not in strict mode
    
    This restores pre 3.6.0 behaviour
---
 .../vault/fs/impl/io/AbstractArtifactHandler.java  | 49 +++++++----
 .../vault/fs/impl/io/FileArtifactHandler.java      |  3 +-
 .../vault/fs/impl/io/FolderArtifactHandler.java    |  2 +-
 .../vault/fs/impl/io/GenericArtifactHandler.java   | 11 +--
 .../apache/jackrabbit/vault/fs/io/Importer.java    | 16 ++--
 .../packaging/integration/IntegrationTestBase.java |  1 -
 .../integration/NotWellFormedDocViewXmlsIT.java    | 98 ++++++++++++++++++++++
 .../META-INF/vault/filter.xml                      |  4 +
 .../META-INF/vault/nodetypes.cnd                   |  9 ++
 .../META-INF/vault/properties.xml                  | 18 ++++
 .../xml-nwf-truncated.zip/jcr_root/.content.xml    | 16 ++++
 .../jcr_root/testroot/.content.xml                 |  4 +
 .../jcr_root/testroot/_cq_content.xml              | 20 +++++
 13 files changed, 218 insertions(+), 33 deletions(-)

diff --git a/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/impl/io/AbstractArtifactHandler.java b/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/impl/io/AbstractArtifactHandler.java
index 545f7122..89d66430 100644
--- a/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/impl/io/AbstractArtifactHandler.java
+++ b/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/impl/io/AbstractArtifactHandler.java
@@ -39,6 +39,8 @@ import org.apache.jackrabbit.vault.fs.io.ImportOptions;
 import org.apache.jackrabbit.vault.fs.spi.ACLManagement;
 import org.apache.jackrabbit.vault.fs.spi.ServiceProviderFactory;
 import org.jetbrains.annotations.NotNull;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 import org.xml.sax.InputSource;
 
 /**
@@ -47,6 +49,11 @@ import org.xml.sax.InputSource;
  */
 public abstract class AbstractArtifactHandler implements ArtifactHandler, Dumpable {
 
+    /**
+     * default logger
+     */
+    private static final Logger log = LoggerFactory.getLogger(AbstractArtifactHandler.class);
+
     /**
      * access control handling.
      * todo: would be better to pass via some kind of import context
@@ -110,34 +117,32 @@ public abstract class AbstractArtifactHandler implements ArtifactHandler, Dumpab
         return aclManagement;
     }
 
-    /**
-     * {@inheritDoc}
-     */
+    @Override
     public ImportInfo accept(Session session, Aggregate file,
                              ArtifactSet artifacts)
             throws RepositoryException, IOException {
         Node node = file.getNode();
         String name = node.getName();
-        return accept(new ImportOptions(), file.getManager().getWorkspaceFilter(),
+        return accept(new ImportOptions(), true, file.getManager().getWorkspaceFilter(),
                 name.length() == 0 ? node : node.getParent(),
                 name, (ArtifactSetImpl) artifacts);
     }
 
-    /**
-     * {@inheritDoc}
-     */
+    @Override
     public ImportInfo accept(Session session, Aggregate parent, String name,
                              ArtifactSet artifacts)
             throws RepositoryException, IOException {
         Node node = parent.getNode();
-        return accept(new ImportOptions(), parent.getManager().getWorkspaceFilter(),
+        return accept(new ImportOptions(), true, parent.getManager().getWorkspaceFilter(),
                 node, name, (ArtifactSetImpl) artifacts);
     }
 
     /**
      * Imports an artifact set below the node.
+     * This method is not part of the public API!
      *
      * @param options the import options
+     * @param isStrictByDefault whether the package should be imported with strict setting by default (i.e. in case ImportOptions has no explicit other flag value set)
      * @param wspFilter the workspace filter
      * @param parent the parent node
      * @param name the name of the (new) import
@@ -146,7 +151,7 @@ public abstract class AbstractArtifactHandler implements ArtifactHandler, Dumpab
      * @throws RepositoryException if an error occurs.
      * @throws IOException if an I/O error occurs.
      */
-    protected abstract ImportInfoImpl accept(@NotNull ImportOptions options, WorkspaceFilter wspFilter, Node parent,
+    public abstract ImportInfoImpl accept(@NotNull ImportOptions options, boolean isStrictByDefault, WorkspaceFilter wspFilter, Node parent,
                                          String name, ArtifactSetImpl artifacts)
             throws RepositoryException, IOException;
 
@@ -158,17 +163,29 @@ public abstract class AbstractArtifactHandler implements ArtifactHandler, Dumpab
     }
 
     protected ImportInfoImpl importDocView(InputSource source, Node parentNode, String rootNodeName, ArtifactSetImpl artifacts, WorkspaceFilter wspFilter, IdConflictPolicy idConflictPolicy) throws IOException, RepositoryException {
+        return importDocView(source, parentNode, rootNodeName, artifacts, true, wspFilter, idConflictPolicy);
+    }
+
+    protected ImportInfoImpl importDocView(InputSource source, Node parentNode, String rootNodeName, ArtifactSetImpl artifacts, boolean isStrict, WorkspaceFilter wspFilter, IdConflictPolicy idConflictPolicy) throws IOException, RepositoryException {
         DocViewImporter handler = new DocViewImporter(parentNode, rootNodeName, artifacts, wspFilter, idConflictPolicy, getAcHandling(), getCugHandling());
+        String rootNodePath = parentNode.getPath();
+        if (!rootNodePath.equals("/")) {
+            rootNodePath += "/";
+        }
+        rootNodePath += rootNodeName;
         try {
-            String rootNodePath = parentNode.getPath();
-            if (!rootNodePath.equals("/")) {
-                rootNodePath += "/";
-            }
-            rootNodePath += rootNodeName;
             new DocViewParser(parentNode.getSession()).parse(rootNodePath, source, handler);
         } catch (XmlParseException e) {
-            // wrap as repositoryException although not semantically correct for backwards compatibility
-            throw new RepositoryException(e);
+            if (!isStrict) {
+                // for backwards-compatibility (JCRVLT-644)
+                ImportInfoImpl info = new ImportInfoImpl();
+                info.onError(rootNodePath, e);
+                log.error("Error while parsing {}: {}", source.getSystemId(), e);
+                return info;
+            } else {
+                // wrap as repositoryException although not semantically correct for backwards compatibility
+                throw new RepositoryException(e);
+            }
         }
         return handler.getInfo();
     }
diff --git a/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/impl/io/FileArtifactHandler.java b/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/impl/io/FileArtifactHandler.java
index 3e9ce060..03d4b9eb 100644
--- a/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/impl/io/FileArtifactHandler.java
+++ b/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/impl/io/FileArtifactHandler.java
@@ -110,7 +110,8 @@ public class FileArtifactHandler extends AbstractArtifactHandler  {
      * <p>
      * Handles generic artifact sets
      */
-    public ImportInfoImpl accept(@NotNull ImportOptions options, WorkspaceFilter wspFilter, Node parent,
+    @Override
+    public ImportInfoImpl accept(@NotNull ImportOptions options, boolean isStrictByDefault, WorkspaceFilter wspFilter, Node parent,
                                 String name, ArtifactSetImpl artifacts)
             throws RepositoryException, IOException {
         // check if any file artifacts was removed
diff --git a/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/impl/io/FolderArtifactHandler.java b/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/impl/io/FolderArtifactHandler.java
index 7b421807..79b3fbae 100644
--- a/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/impl/io/FolderArtifactHandler.java
+++ b/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/impl/io/FolderArtifactHandler.java
@@ -107,7 +107,7 @@ public class FolderArtifactHandler extends AbstractArtifactHandler {
      * Handles generic artifact sets
      */
     @Override
-    public ImportInfoImpl accept(@NotNull ImportOptions options, WorkspaceFilter wspFilter, Node parent, String name,
+    public ImportInfoImpl accept(@NotNull ImportOptions options, boolean isStrictByDefault, WorkspaceFilter wspFilter, Node parent, String name,
                              ArtifactSetImpl artifacts)
             throws RepositoryException, IOException {
         Artifact dir = artifacts.getDirectory();
diff --git a/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/impl/io/GenericArtifactHandler.java b/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/impl/io/GenericArtifactHandler.java
index de38b783..e0da8ea6 100644
--- a/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/impl/io/GenericArtifactHandler.java
+++ b/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/impl/io/GenericArtifactHandler.java
@@ -33,6 +33,7 @@ import org.apache.jackrabbit.vault.fs.spi.ACLManagement;
 import org.apache.jackrabbit.vault.fs.spi.ServiceProviderFactory;
 import org.apache.jackrabbit.vault.fs.spi.UserManagement;
 import org.apache.jackrabbit.vault.util.PathUtil;
+import org.jetbrains.annotations.NotNull;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.xml.sax.InputSource;
@@ -53,12 +54,8 @@ public class GenericArtifactHandler extends AbstractArtifactHandler {
 
     private ACLManagement aclManagement = ServiceProviderFactory.getProvider().getACLManagement();
 
-    /**
-     * {@inheritDoc}
-     *
-     * Handles generic artifact sets
-     */
-    public ImportInfoImpl accept(ImportOptions options, WorkspaceFilter wspFilter, Node parent,
+    @Override
+    public ImportInfoImpl accept(@NotNull ImportOptions options, boolean isStrictByDefault, WorkspaceFilter wspFilter, Node parent,
                                  String name, ArtifactSetImpl artifacts)
             throws RepositoryException, IOException {
         Artifact primary = artifacts.getPrimaryData();
@@ -88,7 +85,7 @@ public class GenericArtifactHandler extends AbstractArtifactHandler {
                     }
                 }
             }
-            info.merge(importDocView(source, parent, name, artifacts, wspFilter, options.getIdConflictPolicy()));
+            info.merge(importDocView(source, parent, name, artifacts, options.isStrict(isStrictByDefault), wspFilter, options.getIdConflictPolicy()));
         }
         return info;
     }
diff --git a/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/io/Importer.java b/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/io/Importer.java
index 1b2c6dd6..3bb69fd4 100644
--- a/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/io/Importer.java
+++ b/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/io/Importer.java
@@ -274,6 +274,7 @@ public class Importer {
      */
     private Map<String, TxInfo> removedIntermediates = new LinkedHashMap<String, TxInfo>();
 
+    private final boolean isStrict;
     private final boolean isStrictByDefault;
     private final boolean overwritePrimaryTypesOfFoldersByDefault;
 
@@ -291,6 +292,7 @@ public class Importer {
 
     public Importer(ImportOptions opts, boolean isStrictByDefault, boolean overwritePrimaryTypesOfFoldersByDefault) {
         this.opts = opts;
+        this.isStrict = opts.isStrict(isStrictByDefault);
         this.isStrictByDefault = isStrictByDefault;
         this.overwritePrimaryTypesOfFoldersByDefault = overwritePrimaryTypesOfFoldersByDefault;
     }
@@ -512,7 +514,7 @@ public class Importer {
         } else {
             if (hasErrors) {
                 track("Package imported (with errors, check logs!)", "");
-                if (opts.isStrict(isStrictByDefault)) {
+                if (isStrict) {
                     throw new RepositoryException("Some errors occurred while installing packages. Please check the logs for details. First exception is logged as cause.", firstException);
                 }
                 log.error("There were errors during package install. Please check the logs for details.");
@@ -561,7 +563,7 @@ public class Importer {
                 log.debug("Installing node types...");
                 installer.install(tracker, nodeTypes);
             } catch (RepositoryException e) {
-                if (opts.isStrict(isStrictByDefault)) {
+                if (isStrict) {
                     throw e;
                 }
                 track(e, "Packaged node types");
@@ -579,7 +581,7 @@ public class Importer {
                 log.debug("Registering privileges...");
                 installer.install(tracker, privileges);
             } catch (RepositoryException e) {
-                if (opts.isStrict(isStrictByDefault)) {
+                if (isStrict) {
                     throw e;
                 }
                 track(e, "Packaged privileges");
@@ -927,7 +929,7 @@ public class Importer {
                 imp = new ImportInfoImpl();
                 imp.onError(info.path, new IllegalStateException("Parent node not found."));
             } else {
-                imp = genericHandler.accept(opts, filter, node, info.artifacts.getPrimaryData().getRelativePath(), info.artifacts);
+                imp = genericHandler.accept(opts, isStrictByDefault, filter, node, info.artifacts.getPrimaryData().getRelativePath(), info.artifacts);
                 if (imp == null) {
                     throw new IllegalStateException("generic handler did not accept " + info.path);
                 }
@@ -958,12 +960,12 @@ public class Importer {
                     log.trace("skipping intermediate node at {}", info.path);
                 } else if (info.artifacts.getPrimaryData() == null) {
                     // create nt:folder node if not exists
-                    imp = folderHandler.accept(opts, filter, node, info.name,  info.artifacts);
+                    imp = folderHandler.accept(opts, isStrictByDefault, filter, node, info.name,  info.artifacts);
                     if (imp == null) {
                         throw new IllegalStateException("folder handler did not accept " + info.path);
                     }
                 } else {
-                    imp = genericHandler.accept(opts, filter, node, info.artifacts.getDirectory().getRelativePath(), info.artifacts);
+                    imp = genericHandler.accept(opts, isStrictByDefault, filter, node, info.artifacts.getDirectory().getRelativePath(), info.artifacts);
                     if (imp == null) {
                         throw new IllegalStateException("generic handler did not accept " + info.path);
                     }
@@ -975,7 +977,7 @@ public class Importer {
                 imp = new ImportInfoImpl();
                 imp.onError(info.path, new IllegalStateException("Parent node not found."));
             } else {
-                imp = fileHandler.accept(opts, filter, node, info.name,  info.artifacts);
+                imp = fileHandler.accept(opts, isStrictByDefault, filter, node, info.name,  info.artifacts);
                 if (imp == null) {
                     throw new IllegalStateException("file handler did not accept " + info.path);
                 }
diff --git a/vault-core/src/test/java/org/apache/jackrabbit/vault/packaging/integration/IntegrationTestBase.java b/vault-core/src/test/java/org/apache/jackrabbit/vault/packaging/integration/IntegrationTestBase.java
index 416459a3..b03a02b3 100644
--- a/vault-core/src/test/java/org/apache/jackrabbit/vault/packaging/integration/IntegrationTestBase.java
+++ b/vault-core/src/test/java/org/apache/jackrabbit/vault/packaging/integration/IntegrationTestBase.java
@@ -468,7 +468,6 @@ public class IntegrationTestBase  {
      */
     public VaultPackage extractVaultPackageStrict(String name) throws IOException, PackageException, RepositoryException {
         ImportOptions  opts = getDefaultOptions();
-        opts.setStrict(true);
         return extractVaultPackage(name, opts);
     }
 
diff --git a/vault-core/src/test/java/org/apache/jackrabbit/vault/packaging/integration/NotWellFormedDocViewXmlsIT.java b/vault-core/src/test/java/org/apache/jackrabbit/vault/packaging/integration/NotWellFormedDocViewXmlsIT.java
new file mode 100644
index 00000000..896a4648
--- /dev/null
+++ b/vault-core/src/test/java/org/apache/jackrabbit/vault/packaging/integration/NotWellFormedDocViewXmlsIT.java
@@ -0,0 +1,98 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.vault.packaging.integration;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import javax.jcr.RepositoryException;
+
+import org.apache.jackrabbit.vault.fs.api.ProgressTrackerListener;
+import org.apache.jackrabbit.vault.fs.io.DocViewParser.XmlParseException;
+import org.apache.jackrabbit.vault.fs.io.ImportOptions;
+import org.junit.Test;
+
+/**
+ * Tests how importing not well-formed DocView XMLs behaves
+ */
+public class NotWellFormedDocViewXmlsIT extends IntegrationTestBase {
+
+    @Override
+    public void tearDown() throws Exception {
+        try {
+            if (admin.nodeExists("/testroot")) {
+                admin.getNode("/testroot").remove();
+                admin.save();
+            }
+        } finally {
+            super.tearDown();
+        }
+    }
+
+    @Test
+    public void testHandlingTruncatedContentXMLWithNonStrictMode() throws Exception {
+        assertNodeMissing("/testroot");
+        ImportOptions options = getDefaultOptions();
+        options.setStrict(false);
+        CapturingProgressTrackerListener listener = new CapturingProgressTrackerListener();
+        options.setListener(listener);
+        extractVaultPackage("/test-packages/xml-nwf-truncated.zip", options);
+        assertNodeExists("/testroot");
+        assertEquals(1, listener.getErrorMap().size());
+        Entry<String, Exception> firstEntry = listener.getErrorMap().entrySet().iterator().next();
+        assertTrue(firstEntry.getValue() instanceof XmlParseException);
+        assertEquals("/", firstEntry.getKey());
+    }
+
+    static final class CapturingProgressTrackerListener implements ProgressTrackerListener {
+
+        private final Map<String, Exception> errorMap;
+        public CapturingProgressTrackerListener() {
+            errorMap = new HashMap<>();
+        }
+        @Override
+        public void onMessage(Mode mode, String action, String path) {
+            // ignore regular messages
+        }
+
+        @Override
+        public void onError(Mode mode, String path, Exception e) {
+            errorMap.put(path, e);
+        }
+
+        public Map<String, Exception> getErrorMap() {
+            return errorMap;
+        }
+    }
+
+    @Test
+    public void testHandlingTruncatedContentXMLWithStrictMode() throws Exception {
+        assertNodeMissing("/testroot");
+        try {
+            ImportOptions options = getDefaultOptions();
+            options.setStrict(true);
+            extractVaultPackage("/test-packages/xml-nwf-truncated.zip", options);
+        } catch (RepositoryException expected) {
+            // expected
+        }
+        assertNodeMissing("/testroot");
+    }
+}
diff --git a/vault-core/src/test/resources/test-packages/xml-nwf-truncated.zip/META-INF/vault/filter.xml b/vault-core/src/test/resources/test-packages/xml-nwf-truncated.zip/META-INF/vault/filter.xml
new file mode 100644
index 00000000..bbbd616d
--- /dev/null
+++ b/vault-core/src/test/resources/test-packages/xml-nwf-truncated.zip/META-INF/vault/filter.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<workspaceFilter version="1.0">
+    <filter root="/testroot"/>
+</workspaceFilter>
diff --git a/vault-core/src/test/resources/test-packages/xml-nwf-truncated.zip/META-INF/vault/nodetypes.cnd b/vault-core/src/test/resources/test-packages/xml-nwf-truncated.zip/META-INF/vault/nodetypes.cnd
new file mode 100644
index 00000000..3771ba50
--- /dev/null
+++ b/vault-core/src/test/resources/test-packages/xml-nwf-truncated.zip/META-INF/vault/nodetypes.cnd
@@ -0,0 +1,9 @@
+<'sling'='http://sling.apache.org/jcr/sling/1.0'>
+<'nt'='http://www.jcp.org/jcr/nt/1.0'>
+<'cq'='http://www.day.com/jcr/cq/1.0'>
+
+[sling:Folder] > nt:folder
+  - * (undefined)
+  - * (undefined) multiple
+  + * (nt:base) = sling:Folder version
+
diff --git a/vault-core/src/test/resources/test-packages/xml-nwf-truncated.zip/META-INF/vault/properties.xml b/vault-core/src/test/resources/test-packages/xml-nwf-truncated.zip/META-INF/vault/properties.xml
new file mode 100644
index 00000000..c606e192
--- /dev/null
+++ b/vault-core/src/test/resources/test-packages/xml-nwf-truncated.zip/META-INF/vault/properties.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8" standalone="no"?>
+<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
+<properties>
+<comment>FileVault Package Properties</comment>
+<entry key="createdBy">admin</entry>
+<entry key="name">import-modes-test</entry>
+<entry key="lastModified">2011-11-15T09:45:14.664+01:00</entry>
+<entry key="lastModifiedBy">admin</entry>
+<entry key="created">2011-11-15T09:45:14.685+01:00</entry>
+<entry key="buildCount">1</entry>
+<entry key="version"/>
+<entry key="dependencies"/>
+<entry key="packageFormatVersion">2</entry>
+<entry key="description"/>
+<entry key="lastWrapped">2011-11-15T09:45:14.664+01:00</entry>
+<entry key="group"/>
+<entry key="lastWrappedBy">admin</entry>
+</properties>
diff --git a/vault-core/src/test/resources/test-packages/xml-nwf-truncated.zip/jcr_root/.content.xml b/vault-core/src/test/resources/test-packages/xml-nwf-truncated.zip/jcr_root/.content.xml
new file mode 100644
index 00000000..1bdc10cb
--- /dev/null
+++ b/vault-core/src/test/resources/test-packages/xml-nwf-truncated.zip/jcr_root/.content.xml
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<jcr:root xmlns:sling="http://sling.apache.org/jcr/sling/1.0" xmlns:jcr="http://www.jcp.org/jcr/1.0" xmlns:rep="internal"
+    jcr:mixinTypes="[rep:AccessControllable]"
+    jcr:primaryType="rep:root"
+    sling:resourceType="sling:redirect"
+    sling:target="/index.html">
+    <rep:policy/>
+    <jcr:system/>
+    <var/>
+    <libs/>
+    <etc/>
+    <apps/>
+    <content/>
+    <tmp/>
+    <home/>
+    <testroot/>
diff --git a/vault-core/src/test/resources/test-packages/xml-nwf-truncated.zip/jcr_root/testroot/.content.xml b/vault-core/src/test/resources/test-packages/xml-nwf-truncated.zip/jcr_root/testroot/.content.xml
new file mode 100644
index 00000000..c5cf582a
--- /dev/null
+++ b/vault-core/src/test/resources/test-packages/xml-nwf-truncated.zip/jcr_root/testroot/.content.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<jcr:root xmlns:sling="http://sling.apache.org/jcr/sling/1.0" xmlns:jcr="http://www.jcp.org/jcr/1.0" xmlns:rep="internal" xmlns:my="http://jackrabbit.apache.org/filevault/testing"
+    jcr:primaryType="sling:Folder">
+</jcr:root>
diff --git a/vault-core/src/test/resources/test-packages/xml-nwf-truncated.zip/jcr_root/testroot/_cq_content.xml b/vault-core/src/test/resources/test-packages/xml-nwf-truncated.zip/jcr_root/testroot/_cq_content.xml
new file mode 100644
index 00000000..531bf71b
--- /dev/null
+++ b/vault-core/src/test/resources/test-packages/xml-nwf-truncated.zip/jcr_root/testroot/_cq_content.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+<jcr:root xmlns:jcr="http://www.jcp.org/jcr/1.0"
+    jcr:primaryType="nt:unstructured">
+</jcr:root>