kyz / libmspack

A library for some loosely related Microsoft compression formats, CAB, CHM, HLP, LIT, KWAJ and SZDD.
https://www.cabextract.org.uk/libmspack/
169 stars 45 forks source link

Fail to properly create path components coming from the archive #48

Closed iq2luc closed 1 year ago

iq2luc commented 1 year ago

Problem description

Path components coming from the archive are not properly created.

Cause

In function ensure_filepath() from cabextract.c line 1229, lstat() is used to get information about that particular file system entry and then, at line 1231, even if the lstat() call failed (for example the entry does not exist at all in the file system), the st_buf is still used for determining if the path is a directory or not.

Examples

Fail - cabextract does not create the path component coming from the archive

[~]> ls *
dest:

src:
W2KSP4_EN.EXE

[~]> cabextract -d dest -F i386/mspatcha.dl_ src/W2KSP4_EN.EXE
Extracting cabinet: src/W2KSP4_EN.EXE
  extracting dest/i386/mspatcha.dl_
dest/i386/mspatcha.dl_: No such file or directory

All done, errors in processing 1 file(s)

Pass - manually create the path component before calling cabextract

[~]> mkdir dest/i386

[~]> cabextract -d dest -F i386/mspatcha.dl_ src/W2KSP4_EN.EXE
Extracting cabinet: src/W2KSP4_EN.EXE
  extracting dest/i386/mspatcha.dl_

All done, no errors.

Info - program version

[~]> cabextract -v
cabextract version 1.10

Proposed solution

The proposed patch fixes the issue and the archive directory components are properly created.

diff --git a/cabextract/src/cabextract.c b/cabextract/src/cabextract.c
index 0a19a9b..a58b0bd 100644
--- a/cabextract/src/cabextract.c
+++ b/cabextract/src/cabextract.c
@@ -1227,8 +1227,10 @@ static int ensure_filepath(char *path, int n) {
       /* in the archive-determined part of the path and not keeping symlinks:
        * use lstat() and delete symlinks if found */
       ok = (lstat(path, &st_buf) == 0);
-      if (ok && (st_buf.st_mode & S_IFMT) == S_IFLNK) unlink(path);
-      ok = S_ISDIR(st_buf.st_mode);
+      if (ok) {
+         if ((st_buf.st_mode & S_IFMT) == S_IFLNK) unlink(path);
+         ok = S_ISDIR(st_buf.st_mode);
+      }
     }
     if (!ok) ok = (mkdir(path, 0777 & ~user_umask) == 0);
     *p = '/';
kyz commented 1 year ago

Thanks for spotting this, I believe it's fixed in cc09dd3cd01d4293a77497352e79562d00118bc6. Please let me know and I'll release a new version of cabextract.

iq2luc commented 1 year ago

I confirm cc09dd3 fixes the issue and the program is working OK. Thank you for the quick resolution and for the program itself.

kyz commented 1 year ago

This issue has now been fixed in the cabextract 1.11 release