Microsoft.PowerShell.Archive icon indicating copy to clipboard operation
Microsoft.PowerShell.Archive copied to clipboard

Compress-Archive creates a strange directory entry for certain file system configurations

Open ForNeVeR opened this issue 1 year ago • 5 comments

Prerequisites

Steps to reproduce

Sometimes, Compress-Archive creates a weird directory-like entry in the produced archive. The details I was able to find:

  • only in 2nd-level nested directory
  • if said directory contains no files (i.e. is empty or only nested directories)
  • Compress-Archive will create a ZIP entry called <yourDirectoryName>/ not marked as directory according to the output of zipinfo

So, exact steps to reproduce:

$ md playground/pt/fspt/d
$ echo xxx >> playground/pt/fspt/d/file.txt
$ Compress-Archive playground/* -DestinationPath 'file.zip' -Force

Now, examine the resulting archive using zipinfo (I wasn't able to quickly find a zipinfo distribution for Windows, so installed sudo apt install unzip on my Ubuntu into WSL):

$ zipinfo file.zip
Archive:  file.zip
Zip file size: 233 bytes, number of entries: 2
-rw----     2.0 fat        0 b- stor 22-Dec-07 20:56 pt/fspt/
-rw----     2.0 fat        5 b- defN 22-Dec-07 20:56 pt/fspt/d/file.txt
2 files, 5 bytes uncompressed, 7 bytes compressed:  -40.0%

The weird path is the first entry:

-rw----     2.0 fat        0 b- stor 22-Dec-07 20:56 pt/fspt/

Notably, the weird entry goes away if I create a file in directory pt/fspt:

$ echo 123 >> playground/pt/fspt/111.txt
$ Compress-Archive playground/* -DestinationPath 'file.zip' -force && wsl -d Ubuntu zipinfo file.zip
Archive:  file.zip
Zip file size: 254 bytes, number of entries: 2
-rw----     2.0 fat        5 b- defN 22-Dec-07 21:15 pt/fspt/111.txt
-rw----     2.0 fat        5 b- defN 22-Dec-07 20:56 pt/fspt/d/file.txt
2 files, 10 bytes uncompressed, 14 bytes compressed:  -40.0%

I've seen two kinds of other archives:

  1. The ones that contain no directory entries at all.
  2. The ones that contain directory entries with drwxr-xr-x flags instead of -rw----.

At the same time, [System.IO.Compression.ZipFile]::CreateFromDirectory works well:

$ [System.IO.Compression.ZipFile]::CreateFromDirectory($(Resolve-Path playground), "$(Resolve-Path '.')/file2.zip")
$ zipinfo file2.zip
Archive:  file2.zip
Zip file size: 141 bytes, number of entries: 1
-rw----     2.0 fat        5 b- defN 22-Dec-07 20:56 pt/fspt/d/file.txt
1 file, 5 bytes uncompressed, 7 bytes compressed:  -40.0%

So, System.IO.Compression.ZipFile]::CreateFromDirectory doesn't have this problem.

For empty directory, it will still create an entry with -rw---- flags, though, so it is not without problems.

Expected behavior

I'd say that Compress-Archive should work the same way as System.IO.Compression.ZipFile]::CreateFromDirectory.

Actual behavior

Compress-Archive behaves differently from System.IO.Compression.ZipFile]::CreateFromDirectory, and in a very strange way that is.

Environment data

The issue reproduces in both Windows PowerShell 5.1 and PowerShell 7.3.

# pwsh 7.3
Name                           Value
----                           -----
PSVersion                      7.3.0
PSEdition                      Core
GitCommitId                    7.3.0
OS                             Microsoft Windows 10.0.22000
Platform                       Win32NT
PSCompatibleVersions           {1.0, 2.0, 3.0, 4.0…}
PSRemotingProtocolVersion      2.3
SerializationVersion           1.1.0.1
WSManStackVersion              3.0

# powershell 5
Name                           Value
----                           -----
PSVersion                      5.1.22000.832
PSEdition                      Desktop
PSCompatibleVersions           {1.0, 2.0, 3.0, 4.0...}
BuildVersion                   10.0.22000.832
CLRVersion                     4.0.30319.42000
WSManStackVersion              3.0
PSRemotingProtocolVersion      2.3
SerializationVersion           1.1.0.1

ForNeVeR avatar Dec 07 '22 20:12 ForNeVeR

Zip listing strange but resulting zip-archive is correct.

zip

237dmitry avatar Dec 07 '22 22:12 237dmitry

It depends on your definition of "correct".

ForNeVeR avatar Dec 07 '22 22:12 ForNeVeR

It depends on your definition of "correct".

Look at uzip. And unzipping as expected:

7z x file.zip

 $ (dir ./pt -Recurse).FullName
/home/herz/Desktop/pt/fspt
/home/herz/Desktop/pt/fspt/d
/home/herz/Desktop/pt/fspt/d/file.txt

Perhaps this is a compression algorithm when empty directories are "merged" with a file.

237dmitry avatar Dec 07 '22 22:12 237dmitry

If your definition of "correct" is "whatever 7zip works with", then yes, it is correct.

It is not correct w.r.t. every interop scenario, though.

In particular, java.util.zip.ZipEntry::isDirectory has problems with such an archive: it reports directory entries to be files, which breaks things.

Though, after taking a closer look, I see that it only has problems with an archive created by Windows PowerShell 5.1, not PowerShell 7.3: it's the kind of the final slash that turns out to be important for it[^1]. Not the flags reported by zipinfo.

The logic of creating directory entries only for directories of certain nesting level and with no files still looks kinda weird.

Notably, the version from the master branch doesn't have this strange logic: it creates a new entry for every directory it seems.

[^1]: Not sure I mentioned that fact above, but the only notable difference between archives created by pwsh 5.1 and pwsh 7.3 is that 7.3 generated paths inside archives separated with / (even on Windows), while pwsh 5.1 separates paths with \.

ForNeVeR avatar Dec 08 '22 11:12 ForNeVeR

If your definition of "correct" is "whatever 7zip works with", then yes, it is correct.

Yes. file-roller, unzip, 7-zip, mc and Far plugins. All of them extract file.zip without errors.I can't test the other archivers.

237dmitry avatar Dec 08 '22 14:12 237dmitry