sindresorhus / gulp-zip

ZIP compress files
MIT License
270 stars 47 forks source link

Unzip doesn't work on macOS with links #79

Open vasek opened 8 years ago

vasek commented 8 years ago

When I zip a soft link to a larger file (>1KB), unzip stop working (either using Archive Utility or unzip).

macOS version: 10.12 gulp-zip version: 3.2.0

Steps to reproduce

  1. Create a folder containing a larger file (>1KB) and a link to it.
  2. Zip all content using gulp-zip.
  3. Try to unzip.
$ unzip test.zip
Archive:  test.zip
  inflating: file
  inflating: link                    -> Lorem ipsum dolor sit amet, sed eu eius ornatus postulant, mea eu summo nostrud. Ei tation appellantur mel. Mea in eros probo atomorum. Congue suavitate vix ea, vel vocent option id. Vitae aliquando ne ius, ex sanctus splendide ius.^J^JConsulatu imperdiet consectetuer cu nec, per in tota aliquip adipiscing. Ex vide erat euismod his. Sea adhuc omnesque ad, sed etiam hendrerit incorrupte ne, sit graece voluptatum ei. Per in zril dolorem, his at quem suas necessitatibus.^J^JIus ei quodsi phaedrum pertinacia, eu vim porro civibus. Affert latine mel ea, sed eu adhuc fabulas corpora, omnes veniam eam ex. Ad pri petentium intellegebat, novum congue deleniti at usu, omnium disputationi ius ut. Mea cu legere impedit appellantur, nibh euripidis conceptam has at. His te choro adversarium philosophia, odio dicam in eos.^J^JVocibus deserunt ei duo, mel et euismod fuisset. Mel ponderum iudicabit id. His cu nisl graecis, numquam debitis efficiendi at mel. Ne phaedrum torquatos deseruisse nam, et qui ridens graecis accommodare, nulla labores ad usu. Quo eu vide assueverit instructior, ea pro postea equidem.^J
finishing deferred symbolic links:
  link                   -> Lorem ipsum dolor sit amet, sed eu eius ornatus postulant, mea eu summo nostrud. Ei tation appellantur mel. Mea in eros probo atomorum. Congue suavitate vix ea, vel vocent option id. Vitae aliquando ne ius, ex sanctus splendide ius.^J^JConsulatu imperdiet consectetuer cu nec, per in tota aliquip adipiscing. Ex vide erat euismod his. Sea adhuc omnesque ad, sed etiam hendrerit incorrupte ne, sit graece voluptatum ei. Per in zril dolorem, his at quem suas necessitatibus.^J^JIus ei quodsi phaedrum pertinacia, eu vim porro civibus. Affert latine mel ea, sed eu adhuc fabulas corpora, omnes veniam eam ex. Ad pri petentium intellegebat, novum congue deleniti at usu, omnium disputationi ius ut. Mea cu legere impedit appellantur, nibh euripidis conceptam has at. His te choro adversarium philosophia, odio dicam in eos.^J^JVocibus deserunt ei duo, mel et euismod fuisset. Mel ponderum iudicabit id. His cu nisl graecis, numquam debitis efficiendi at mel. Ne phaedrum torquatos deseruisse nam, et qui ridens graecis accommodare, nulla labores ad usu. Quo eu vide assueverit instructior, ea pro postea equidem.^J
symlink error: File name too long
lchmod (file attributes) error: No such file or directory

file is roughly 1KB file with generated Lorem ipsum link is a soft link to it (ln -s file link)

Slightly modified version of gulp-tar (only changed #L14 from var archive = archiver('tar'); to var archive = archiver('zip');) unzips fine however it doesn't preserve the link (the file and link are identical files after zip + unzip).

Original files:

$ ls -l src
total 16
-rw-r--r--+ 1 vasek  staff  1103 Oct 19 11:28 file
lrwxr-xr-x  1 vasek  staff     4 Oct 19 11:28 link -> file

After zip + unzip (using modified gulp-tar package)

ls -l dist
total 16
-rw-r--r--+ 1 vasek  staff  1103 Oct 19 09:28 file
-rwxr-xr-x+ 1 vasek  staff  1103 Oct 19 09:28 link
sindresorhus commented 8 years ago

Since it works if you use archiver('zip') instead, it's probably a bug in the underlaying module used for zipping here: https://github.com/thejoshwolfe/yazl I would open an issue there.

vasek commented 8 years ago

I've looked into the issue more and found out why this doesn't work.

The problem is that gulp.src follows symlinks so file.contents here equals to the contents of linked file (not the reference to it). The stat object includes mode of the link file (which contains information about the file being a symlink). So the file created in the zip archive is a symlink referencing the contents of a linked file (instead of a path to it).

In gulp < 4.0 I haven't found a way to get the correct contents of the symlink. Gulp 4.0 will add option followSymlinks to gulp.src which when set to false will add file.symlink with the correct reference to a linked file.

// using gulp#4.0
var contents = file.stat && file.stat.isSymbolicLink() ? file.symlink : file.contents;
if (file.isStream()) {
    zip.addReadStream(contents, pathname, stat);
}
if (file.isBuffer()) {
    zip.addBuffer(contents, pathname, stat);
}

It is possible to simply copy the linked file instead of preserving the link (just like the modified gulp-tar does it). It will require changing the mode of link to "regular file". However I don't know how to find the file mode of the linked file. file.stat is lstat output so the file.stat.mode refers to link file (not the linked one).

var stat = {
    compress: opts.compress,
    mtime: file.stat ? file.stat.mtime : new Date(),
    mode: file.stat ? file.stat.mode : null
};
if (file.stat && file.stat.isSymbolicLink()) {
    // unable to find the correct mode
    // maybe use the default one? 
    stat.mode = 0100664;
}
rochapablo commented 7 years ago

Hi everyone,

I'm having a problem that could be related to this issue, but I don't know exactly what it is, so If you guys know something about it, please let me know.

This is what I have today, which I select the files and copy to another location.

var dirname = 'upgrade/builds/watch';
  var filename = 'my-plugin.zip';
  var src = gulp.src([
    'src/core/**/*.php',
    'src/core/**/*.phtml',
    'src/core/**/*.js',
    'src/bootstrap.php',
    'index.php',
    'composer.json',
    'composer.lock'
  ], { base: '.', follow: true });
  src.pipe(gulp.dest(dirname + '/' + filename.replace('.zip', '')));
  src.pipe(zip(filename, { dot: true, nodir: true })).pipe(gulp.dest(dirname));

In my tests this is working, the files and folders are copied to the destination. But when I unzip the zip file on server (Google Cloud Platform) that structure mess up just like this

-rw-rw-r--  1 daemon daemon    0 Feb 24 11:40 \.gitkeep
-rw-rw-r--  1 daemon daemon  257 Feb 24 11:40 \index.php
-rw-rw-r--  1 daemon daemon   34 Feb 24 11:40 \src\bootstrap.php
-rw-rw-r--  1 daemon daemon    0 Feb 24 11:40 my-plugin\.gitkeep
-rw-rw-r--  1 daemon daemon  300 Feb 24 11:40 my-plugin\index.php
-rw-rw-r--  1 daemon daemon   34 Feb 24 11:40 my-plugin\src\bootstrap.php

So... anyone?

bytestream commented 4 years ago

I have an issue where gulp-zip copies the contents of linked file instead of maintaining the links when generating the zip. The linked files are all within directory which I'm archiving so there's no reason why they need to be copied.

Did anyone find a solution for this? @sindresorhus