mirror of
https://github.com/S2-/gitlit
synced 2025-08-04 05:10:05 +02:00
packager
This commit is contained in:
184
app/node_modules/decompress-zip/lib/extractors.js
generated
vendored
Normal file
184
app/node_modules/decompress-zip/lib/extractors.js
generated
vendored
Normal file
@@ -0,0 +1,184 @@
|
||||
var stream = require('stream');
|
||||
if (!stream.Readable) {
|
||||
var stream = require('readable-stream');
|
||||
}
|
||||
var fs = require('graceful-fs');
|
||||
var Q = require('q');
|
||||
var path = require('path');
|
||||
var zlib = require('zlib');
|
||||
var touch = Q.denodeify(require('touch'));
|
||||
var mkpath = Q.denodeify(require('mkpath'));
|
||||
var writeFile = Q.denodeify(fs.writeFile);
|
||||
var inflateRaw = Q.denodeify(zlib.inflateRaw);
|
||||
var symlink = Q.denodeify(fs.symlink);
|
||||
var stat = Q.denodeify(fs.stat);
|
||||
|
||||
// Use a cache of promises for building the directory tree. This allows us to
|
||||
// correctly queue up file extractions for after their path has been created,
|
||||
// avoid trying to create the path twice and still be async.
|
||||
var mkdir = function (dir, cache, mode) {
|
||||
dir = path.normalize(path.resolve(process.cwd(), dir) + path.sep);
|
||||
if (mode === undefined) {
|
||||
mode = parseInt('777', 8) & (~process.umask());
|
||||
}
|
||||
|
||||
if (!cache[dir]) {
|
||||
var parent;
|
||||
|
||||
if (fs.existsSync(dir)) {
|
||||
parent = new Q();
|
||||
} else {
|
||||
parent = mkdir(path.dirname(dir), cache, mode);
|
||||
}
|
||||
|
||||
cache[dir] = parent.then(function () {
|
||||
return mkpath(dir, mode);
|
||||
});
|
||||
}
|
||||
|
||||
return cache[dir];
|
||||
};
|
||||
|
||||
// Utility methods for writing output files
|
||||
var extractors = {
|
||||
folder: function (folder, destination, zip) {
|
||||
return mkdir(destination, zip.dirCache, folder.mode)
|
||||
.then(function () {
|
||||
return {folder: folder.path};
|
||||
});
|
||||
},
|
||||
store: function (file, destination, zip) {
|
||||
var writer;
|
||||
|
||||
if (file.uncompressedSize === 0) {
|
||||
writer = touch.bind(null, destination);
|
||||
} else if (file.uncompressedSize <= zip.chunkSize) {
|
||||
writer = function () {
|
||||
return zip.getBuffer(file._offset, file._offset + file.uncompressedSize)
|
||||
.then(function (buffer) {
|
||||
return writeFile(destination, buffer, { mode: file.mode });
|
||||
});
|
||||
};
|
||||
} else {
|
||||
var input = new stream.Readable();
|
||||
input.wrap(fs.createReadStream(zip.filename, {start: file._offset, end: file._offset + file.uncompressedSize - 1}));
|
||||
writer = pipePromise.bind(null, input, destination, { mode: file.mode });
|
||||
}
|
||||
|
||||
return mkdir(path.dirname(destination), zip.dirCache)
|
||||
.then(writer)
|
||||
.then(function () {
|
||||
return {stored: file.path};
|
||||
});
|
||||
},
|
||||
deflate: function (file, destination, zip) {
|
||||
// For Deflate you don't actually need to specify the end offset - and
|
||||
// in fact many ZIP files don't include compressed file sizes for
|
||||
// Deflated files so we don't even know what the end offset is.
|
||||
|
||||
return mkdir(path.dirname(destination), zip.dirCache)
|
||||
.then(function () {
|
||||
if (file._maxSize <= zip.chunkSize) {
|
||||
return zip.getBuffer(file._offset, file._offset + file._maxSize)
|
||||
.then(inflateRaw)
|
||||
.then(function (buffer) {
|
||||
return writeFile(destination, buffer, { mode: file.mode });
|
||||
});
|
||||
} else {
|
||||
// For node 0.8 we need to create the Zlib stream and attach
|
||||
// handlers in the same tick of the event loop, which is why we do
|
||||
// the creation in here
|
||||
var input = new stream.Readable();
|
||||
input.wrap(fs.createReadStream(zip.filename, {start: file._offset}));
|
||||
var inflater = input.pipe(zlib.createInflateRaw({highWaterMark: 32 * 1024}));
|
||||
|
||||
return pipePromise(inflater, destination, { mode: file.mode });
|
||||
}
|
||||
})
|
||||
.then(function () {
|
||||
return {deflated: file.path};
|
||||
});
|
||||
},
|
||||
symlink: function (file, destination, zip, basePath) {
|
||||
var parent = path.dirname(destination);
|
||||
return mkdir(parent, zip.dirCache)
|
||||
.then(function () {
|
||||
return getLinkLocation(file, destination, zip, basePath);
|
||||
})
|
||||
.then(function (linkTo) {
|
||||
return symlink(path.resolve(parent, linkTo), destination)
|
||||
.then(function () {
|
||||
return {symlink: file.path, linkTo: linkTo};
|
||||
});
|
||||
});
|
||||
},
|
||||
// Make a shallow copy of the file/directory this symlink points to instead
|
||||
// of actually creating a link
|
||||
copy: function (file, destination, zip, basePath) {
|
||||
var type;
|
||||
var parent = path.dirname(destination);
|
||||
|
||||
return mkdir(parent, zip.dirCache)
|
||||
.then(function () {
|
||||
return getLinkLocation(file, destination, zip, basePath);
|
||||
})
|
||||
.then(function (linkTo) {
|
||||
return stat(path.resolve(parent, linkTo))
|
||||
.then(function (stats) {
|
||||
if (stats.isFile()) {
|
||||
type = 'File';
|
||||
var input = new stream.Readable();
|
||||
input.wrap(fs.createReadStream(path.resolve(parent, linkTo)));
|
||||
return pipePromise(input, destination);
|
||||
} else if (stats.isDirectory()) {
|
||||
type = 'Directory';
|
||||
return mkdir(destination, zip.dirCache);
|
||||
} else {
|
||||
throw new Error('Could not follow symlink to unknown file type');
|
||||
}
|
||||
})
|
||||
.then(function () {
|
||||
return {copy: file.path, original: linkTo, type: type};
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
var getLinkLocation = function (file, destination, zip, basePath) {
|
||||
var parent = path.dirname(destination);
|
||||
return zip.getBuffer(file._offset, file._offset + file.uncompressedSize)
|
||||
.then(function (buffer) {
|
||||
var linkTo = buffer.toString();
|
||||
var fullLink = path.resolve(parent, linkTo);
|
||||
|
||||
if (path.relative(basePath, fullLink).slice(0, 2) === '..') {
|
||||
throw new Error('Symlink links outside archive');
|
||||
}
|
||||
|
||||
return linkTo;
|
||||
});
|
||||
};
|
||||
|
||||
var pipePromise = function (input, destination, options) {
|
||||
var deferred = Q.defer();
|
||||
var output = fs.createWriteStream(destination, options);
|
||||
var errorHandler = function (error) {
|
||||
deferred.reject(error);
|
||||
};
|
||||
|
||||
input.on('error', errorHandler);
|
||||
output.on('error', errorHandler);
|
||||
|
||||
// For node 0.8 we can't just use the 'finish' event of the pipe
|
||||
input.on('end', function () {
|
||||
output.end(function () {
|
||||
deferred.resolve();
|
||||
});
|
||||
});
|
||||
|
||||
input.pipe(output, {end: false});
|
||||
|
||||
return deferred.promise;
|
||||
};
|
||||
|
||||
module.exports = extractors;
|
Reference in New Issue
Block a user