max-mapper / extract-zip

Zip extraction written in pure JavaScript. Extracts a zip into a directory.
BSD 2-Clause "Simplified" License
388 stars 126 forks source link

Error: EBADF: bad file descriptor, read #30

Closed ErisDS closed 7 years ago

ErisDS commented 7 years ago

Hi, I'm raising this bug a bit early as I'm still in the middle of debugging a pretty serious bug we've discovered in the latest release of Ghost and will update as I go trying to figure out what's happening.

I'm getting an error in extract-zip@1.5.0:

Error: EBADF: bad file descriptor, read

I get a similar error in extract-zip@1.3.0:

~/gscan/node_modules/extract-zip/node_modules/async/lib/async.js:43
            if (fn === null) throw new Error("Callback was already called.");
                             ^

Error: Callback was already called.
    at ~/gscan/node_modules/extract-zip/node_modules/async/lib/async.js:43:36
    at WriteStream.<anonymous> (~/gscan/node_modules/extract-zip/index.js:145:24)
    at emitOne (events.js:82:20)
    at WriteStream.emit (events.js:169:7)
    at WriteStream.<anonymous> (fs.js:1837:12)
    at FSReqWrap.oncomplete (fs.js:82:15)

This happening when extracting a particular zip file. It's not my zip so I can't share it publicly, and I'm still trying to figure out what the discerning factor is with this zip. The tripping factor appears to be a .git folder at the moment.

The first thing I did is upgrade, which gave me a lower level error.

Additionally, what I have done is a) research the error message and determine that it is probably something to do with trying to call .close() on a file descriptor that is already closed and b) write a 50 line version of extract using the example in the README file of the yauzl repository and verify that this does not give me an error.

Therefore, I'm relatively confident I've found a bug, just not sure what it is yet, and wanted to flag it up early in the hope that someone else might have a clue!

This is happening on Node v4.4.7 on my local machine, and also on Ubuntu. It is reproducible when uploading the offending zip to http://gscan.ghost.org. Will be back soon hopefully with a sharable zip that reproduces the error.

/me goes back to debugging...

ErisDS commented 7 years ago

DEBUG output shows that the .git folder is, for some reason, being flagged with isDir false:

extract-zip extracting entry +1ms { filename: 'myzipfile/.git/', isDir: false, isSymlink: false }

Here's the full debug output (I've added a tonne of extra statements)

extract-zip creating target directory +0ms /var/folders/qm/tsdrxdyx2033l7szbx0y14_r0000gn/T/e69008e9-19ec-41df-887e-d828a2843354
  extract-zip opening +2ms /Users/hannah/Downloads/myzipfile.zip with opts { dir: '/var/folders/qm/tsdrxdyx2033l7szbx0y14_r0000gn/T/e69008e9-19ec-41df-887e-d828a2843354' }
  extract-zip zipfile entry +17ms myzipfile/.git/
  extract-zip entry.externalFileAttributes +0ms 18
  extract-zip entry.externalFileAttributes >> 16 +0ms 0
  extract-zip mode +0ms 0
  extract-zip IFMT +0ms 61440
  extract-zip IFDIR +0ms 16384
  extract-zip extracting entry +0ms { filename: 'myzipfile/.git/', isDir: false, isSymlink: false }
  extract-zip mkdirp +1ms { dir: '/var/folders/qm/tsdrxdyx2033l7szbx0y14_r0000gn/T/e69008e9-19ec-41df-887e-d828a2843354/myzipfile' }
  extract-zip opening read stream +0ms /var/folders/qm/tsdrxdyx2033l7szbx0y14_r0000gn/T/e69008e9-19ec-41df-887e-d828a2843354/myzipfile/.git/
  extract-zip finished processing +4ms myzipfile/.git/
  extract-zip write error +1ms { error: 
   { [Error: ENOENT: no such file or directory, open '/var/folders/qm/tsdrxdyx2033l7szbx0y14_r0000gn/T/e69008e9-19ec-41df-887e-d828a2843354/myzipfile/.git/']
     errno: -2,
     code: 'ENOENT',
     syscall: 'open',
     path: '/var/folders/qm/tsdrxdyx2033l7szbx0y14_r0000gn/T/e69008e9-19ec-41df-887e-d828a2843354/myzipfile/.git/' } }
ErisDS commented 7 years ago

Clearly from the above, the externalFileAttributes property doesn't match the expectations of extract-zip for what a directory looks like.

Looking around at the zip spec and also at other implementations, it seems these values can be different if the zip was made on Windows vs no-Windows?

I have a PR incoming, but it's sloppy 😁