overleaf/services/web/app/coffee/Features/Uploads/ArchiveManager.coffee

109 lines
3 KiB
CoffeeScript
Raw Normal View History

2014-02-12 05:23:40 -05:00
child = require "child_process"
logger = require "logger-sharelatex"
metrics = require "../../infrastructure/Metrics"
fs = require "fs"
Path = require "path"
2016-03-12 10:43:16 -05:00
_ = require("underscore")
2014-02-12 05:23:40 -05:00
2016-03-12 07:38:21 -05:00
ONE_MEG = 1024 * 1024
2014-02-12 05:23:40 -05:00
module.exports = ArchiveManager =
2016-03-12 10:43:16 -05:00
_isZipTooLarge: (source, callback = (err, isTooLarge)->)->
callback = _.once callback
unzip = child.spawn("unzip", ["-l", source])
output = ""
unzip.stdout.on "data", (d)->
output += d
error = null
unzip.stderr.on "data", (chunk) ->
error ||= ""
error += chunk
unzip.on "error", (err) ->
2016-03-21 09:15:57 -04:00
logger.error {err, source}, "unzip failed"
2016-03-12 10:43:16 -05:00
if err.code == "ENOENT"
logger.error "unzip command not found. Please check the unzip command is installed"
callback(err)
unzip.on "close", (exitCode) ->
2016-03-12 10:43:16 -05:00
if error?
error = new Error(error)
2016-03-21 09:15:57 -04:00
logger.error err:error, source: source, "error checking zip size"
2016-03-12 10:43:16 -05:00
lines = output.split("\n")
lastLine = lines[lines.length - 2]?.trim()
totalSizeInBytes = lastLine?.split(" ")?[0]
2016-03-21 12:00:12 -04:00
totalSizeInBytesAsInt = parseInt(totalSizeInBytes)
2016-03-12 10:43:16 -05:00
2016-03-21 12:00:12 -04:00
if !totalSizeInBytesAsInt? or isNaN(totalSizeInBytesAsInt)
logger.err source:source, totalSizeInBytes:totalSizeInBytes, totalSizeInBytesAsInt:totalSizeInBytesAsInt, lastLine:lastLine, exitCode:exitCode, "error getting bytes of zip"
2016-03-21 12:00:12 -04:00
return callback(new Error("error getting bytes of zip"))
2016-03-12 10:43:16 -05:00
isTooLarge = totalSizeInBytes > (ONE_MEG * 300)
callback(error, isTooLarge)
extractZipArchive: (source, destination, _callback = (err) ->) ->
callback = (args...) ->
_callback(args...)
_callback = () ->
2016-03-12 10:43:16 -05:00
ArchiveManager._isZipTooLarge source, (err, isTooLarge)->
2016-03-12 07:38:21 -05:00
if err?
logger.err err:err, "error checking size of zip file"
return callback(err)
2016-03-12 10:43:16 -05:00
if isTooLarge
return callback(new Error("zip_too_large"))
2016-03-12 07:38:21 -05:00
timer = new metrics.Timer("unzipDirectory")
logger.log source: source, destination: destination, "unzipping file"
2014-02-12 05:23:40 -05:00
2016-03-12 07:38:21 -05:00
unzip = child.spawn("unzip", [source, "-d", destination])
2014-02-12 05:23:40 -05:00
2016-03-12 07:38:21 -05:00
# don't remove this line, some zips need
# us to listen on this for some unknow reason
unzip.stdout.on "data", (d)->
2016-03-12 07:38:21 -05:00
error = null
unzip.stderr.on "data", (chunk) ->
error ||= ""
error += chunk
2014-02-12 05:23:40 -05:00
2016-03-12 07:38:21 -05:00
unzip.on "error", (err) ->
logger.error {err, source, destination}, "unzip failed"
if err.code == "ENOENT"
logger.error "unzip command not found. Please check the unzip command is installed"
callback(err)
unzip.on "close", () ->
2016-03-12 07:38:21 -05:00
timer.done()
if error?
error = new Error(error)
logger.error err:error, source: source, destination: destination, "error unzipping file"
callback(error)
findTopLevelDirectory: (directory, callback = (error, topLevelDir) ->) ->
fs.readdir directory, (error, files) ->
return callback(error) if error?
if files.length == 1
childPath = Path.join(directory, files[0])
fs.stat childPath, (error, stat) ->
return callback(error) if error?
if stat.isDirectory()
return callback(null, childPath)
else
return callback(null, directory)
else
return callback(null, directory)
2014-02-12 05:23:40 -05:00