0 votes
by (250 points)

tried to extract zip Archive which contains some links in mono on linux.

extract manually using unzip works in Linux Shell, I got following file:

lrwxrwxrwx 1 root root 8 Nov 7 18:40 ncurses.h -> curses.h

with a C# Code snippet:

using (var archive = new ZipArchive(InstallationFile))
{
    var action = ActionOnExistingFiles.OverwriteAll;
    archive.ExtractAll(DatabasePath, TransferMethod.Copy, action);
}

I got following exception on ExtractAll Method:

Rebex.IO.Compression.ZipException Link detected ('\/pgsql\/include\/ncurses\/ncurses.h'). Rebex.BatchProblemEventArgs HandleException(System.Exception, Rebex.IO.TransferProblemType, Rebex.TransferItem, Rebex.TransferItem, Rebex.BatchProblemReactions, Rebex.BatchProblemReactions, Rebex.BatchProblemReactions ByRef)   at Rebex.BatchTransfer.HandleException (System.Exception ex, Rebex.IO.TransferProblemType type, Rebex.TransferItem remoteItem, Rebex.TransferItem localItem, Rebex.BatchProblemReactions defaultAction, Rebex.BatchProblemReactions possibleReactions, Rebex.BatchProblemReactions& chosenAction) [0x001b0] in <89ad118348324dbfbe4b9279af8ac151>:0 
  at Rebex.BatchTransfer.ProcessLink (Rebex.TraversalPathInfo info, Rebex.BatchProblemReactions possibleActions, Rebex.BatchProblemReactions& chosenAction) [0x0009d] in <89ad118348324dbfbe4b9279af8ac151>:0 
  at Rebex.BatchTransfer.ProcessPath (Rebex.TraversalPathInfo info) [0x00196] in <89ad118348324dbfbe4b9279af8ac151>:0 
  at Rebex.BatchTransfer.RetrieveHierarchy () [0x002a1] in <89ad118348324dbfbe4b9279af8ac151>:0 
  at Rebex.BatchTransfer.Transfer (Rebex.IO.TransferAction action, Rebex.BatchFileSetCollection sourceFilter, System.String targetPath, Rebex.IO.TransferMethod transferMethod, Rebex.IO.MoveMode moveMode, Rebex.IO.LinkProcessingMode actionOnLinks, Rebex.IO.ActionOnExistingFiles actionOnExistingFiles, Rebex.TransferItem expectedRootItem) [0x00227] in <89ad118348324dbfbe4b9279af8ac151>:0 
  at Rebex.IO.Compression.ZipBatchTransfer.Transfer (Rebex.IO.Compression.ArchiveOperation operation, Rebex.BatchFileSetCollection sourceFilter, System.String targetPath, Rebex.IO.TransferMethod transferMethod, Rebex.IO.ActionOnExistingFiles actionOnExistingFiles) [0x0002c] in <89ad118348324dbfbe4b9279af8ac151>:0 
  at Rebex.IO.Compression.ZipArchive.ExtractSync (Rebex.BatchFileSetCollection setCollection, System.String targetDirectoryPath, Rebex.IO.TransferMethod transferMethod, Rebex.IO.ActionOnExistingFiles actionOnExistingFiles) [0x0001a] in <89ad118348324dbfbe4b9279af8ac151>:0 
  at Rebex.IO.Compression.ZipArchive.Extract (System.String archivePathOrMask, System.String targetDirectoryPath, Rebex.IO.TraversalMode mode, Rebex.IO.TransferMethod transferMethod, Rebex.IO.ActionOnExistingFiles defaultActionOnExistingFiles, System.Boolean fromOldApi) [0x0001a] in <89ad118348324dbfbe4b9279af8ac151>:0 
  at Rebex.IO.Compression.ZipArchive.Extract (System.String archivePathOrMask, System.String targetDirectoryPath, Rebex.IO.TraversalMode mode, Rebex.IO.TransferMethod transferMethod, Rebex.IO.ActionOnExistingFiles defaultActionOnExistingFiles) [0x00001] in <89ad118348324dbfbe4b9279af8ac151>:0 
  at Rebex.IO.Compression.ZipArchive.ExtractAll (System.String targetDirectoryPath, Rebex.IO.TransferMethod transferMethod, Rebex.IO.ActionOnExistingFiles defaultActionOnExistingFiles) [0x0000d] in <89ad118348324dbfbe4b9279af8ac151>:0 

How to fix?

Applies to: Rebex ZIP

1 Answer

0 votes
by (73.5k points)
edited by

Extraction of links is not supported yet.
If you want to skip all links set MultiFileLinkMode to SkipLinks:

archive.Options.MultiFileLinkMode = LinkProcessingMode.SkipLinks;

However, you can determine the target of a link using the ZipItem.LinkTarget:

archive.GetItem("path").LinkTarget

// or

archive["path"].LinkTarget

UPDATE:

With a little effort you can extract links manually:

using (var archive = new ZipArchive(InstallationFile))
{
    // create cache of items for later use
    var items = new Dictionary<string, ZipItem>();
    foreach (var item in archive)
    {
        items.Add(item.Path, item);
    }

    // register event to handle LinkDetected problems
    archive.ProblemDetected += (s, e) =>
    {
        if (e.ProblemType == ArchiveProblemType.LinkDetected &&
            e.Operation == ArchiveOperation.Extract)
        {
            string externalPath = e.ExternalItemPath;
            string linkTarget = items[e.ArchiveItemPath].LinkTarget;

            // do what you need, e.g.:
            // var f = new UnixFileInfo(externalPath);
            // f.CreateSymbolicLink(linkTarget);                            

            // skip processing by library
            e.Action = ArchiveProblemActions.Skip;
        }
    };

    // extract all items
    var action = ActionOnExistingFiles.OverwriteAll;
    archive.ExtractAll(DatabasePath, TransferMethod.Copy, action);
}
by (250 points)
Thank you for your reply. unfortunately this won't work due recursive processing of directories.

Solved this by Invoke an external method in Zip/Shared/BatchTransfer.cs
and processed this myself by:
        private void ProcessLink(bool isDownload, string itemPath, string linkTarget,

            out BatchProblemReactions chosenAction)

        {

            if (isDownload)

            {

                Log.Info($"create Link {itemPath} to {linkTarget}");

                var f = new UnixFileInfo(itemPath);

                f.CreateSymbolicLink(linkTarget);

            }

            chosenAction = BatchProblemReactions.Skip;

        }
by (73.5k points)
Great, that you was able to solve the problem yourself. Actually, you brought me to a solution available for those users without source code edition. It is possible to achieve same behavior using `ProblemDetected` event. Please, see my updated answer above.
by (250 points)
Lukas, this works only, if LinkTarget gets public in BatchTransfer.cs.
This has to be exposed like:
        public string LinkTargetName
        {
            get
            {
                if (this._inner is ZipItem) return ((ZipItem)_inner).LinkTarget;
                return String.Empty;
            }
        }
by (73.5k points)
I don't understand. `LinkTarget` is exposed on `ZipItem`. I tried my code and it is working without exposing anything special.

The `ZipProblemDetectedEventArgs` has only `ArchiveItemPath` and `ExternalItemPath`, so I cached collection of `ZipItem`s to be able to get the `LinkTarget` for specified path. And this is enough to make it working.

However, I realized that it would be nice to have `ZipItem` on event directly. Or enable possibility to get the `ZipItem` during events for read-only access.
...