/webapp/node_modules/bower/lib/node_modules/tar-fs/index.js

https://gitlab.com/Infrared-KHTN/aulluminate · JavaScript · 305 lines · 241 code · 63 blank · 1 comment · 76 complexity · 0bdd6458176dcccb465fb81b246f9697 MD5 · raw file

  1. var tar = require('tar-stream')
  2. var pump = require('pump')
  3. var mkdirp = require('mkdirp')
  4. var fs = require('fs')
  5. var path = require('path')
  6. var os = require('os')
  7. var win32 = os.platform() === 'win32'
  8. var noop = function () {}
  9. var echo = function (name) {
  10. return name
  11. }
  12. var normalize = !win32 ? echo : function (name) {
  13. return name.replace(/\\/g, '/').replace(/:/g, '_')
  14. }
  15. var statAll = function (fs, stat, cwd, ignore, entries, sort) {
  16. var queue = entries || ['.']
  17. return function loop (callback) {
  18. if (!queue.length) return callback()
  19. var next = queue.shift()
  20. var nextAbs = path.join(cwd, next)
  21. stat(nextAbs, function (err, stat) {
  22. if (err) return callback(err)
  23. if (!stat.isDirectory()) return callback(null, next, stat)
  24. fs.readdir(nextAbs, function (err, files) {
  25. if (err) return callback(err)
  26. if (sort) files.sort()
  27. for (var i = 0; i < files.length; i++) {
  28. if (!ignore(path.join(cwd, next, files[i]))) queue.push(path.join(next, files[i]))
  29. }
  30. callback(null, next, stat)
  31. })
  32. })
  33. }
  34. }
  35. var strip = function (map, level) {
  36. return function (header) {
  37. header.name = header.name.split('/').slice(level).join('/')
  38. var linkname = header.linkname
  39. if (linkname && (header.type === 'link' || path.isAbsolute(linkname))) {
  40. header.linkname = linkname.split('/').slice(level).join('/')
  41. }
  42. return map(header)
  43. }
  44. }
  45. exports.pack = function (cwd, opts) {
  46. if (!cwd) cwd = '.'
  47. if (!opts) opts = {}
  48. var xfs = opts.fs || fs
  49. var ignore = opts.ignore || opts.filter || noop
  50. var map = opts.map || noop
  51. var mapStream = opts.mapStream || echo
  52. var statNext = statAll(xfs, opts.dereference ? xfs.stat : xfs.lstat, cwd, ignore, opts.entries, opts.sort)
  53. var strict = opts.strict !== false
  54. var dmode = typeof opts.dmode === 'number' ? opts.dmode : 0
  55. var fmode = typeof opts.fmode === 'number' ? opts.fmode : 0
  56. var pack = opts.pack || tar.pack()
  57. if (opts.strip) map = strip(map, opts.strip)
  58. if (opts.readable) {
  59. dmode |= parseInt(555, 8)
  60. fmode |= parseInt(444, 8)
  61. }
  62. if (opts.writable) {
  63. dmode |= parseInt(333, 8)
  64. fmode |= parseInt(222, 8)
  65. }
  66. var onsymlink = function (filename, header) {
  67. xfs.readlink(path.join(cwd, filename), function (err, linkname) {
  68. if (err) return pack.destroy(err)
  69. header.linkname = normalize(linkname)
  70. pack.entry(header, onnextentry)
  71. })
  72. }
  73. var onstat = function (err, filename, stat) {
  74. if (err) return pack.destroy(err)
  75. if (!filename) return pack.finalize()
  76. if (stat.isSocket()) return onnextentry() // tar does not support sockets...
  77. var header = {
  78. name: normalize(filename),
  79. mode: stat.mode | (stat.isDirectory() ? dmode : fmode),
  80. mtime: stat.mtime,
  81. size: stat.size,
  82. type: 'file',
  83. uid: stat.uid,
  84. gid: stat.gid
  85. }
  86. if (stat.isDirectory()) {
  87. header.size = 0
  88. header.type = 'directory'
  89. header = map(header) || header
  90. return pack.entry(header, onnextentry)
  91. }
  92. if (stat.isSymbolicLink()) {
  93. header.size = 0
  94. header.type = 'symlink'
  95. header = map(header) || header
  96. return onsymlink(filename, header)
  97. }
  98. // TODO: add fifo etc...
  99. header = map(header) || header
  100. if (!stat.isFile()) {
  101. if (strict) return pack.destroy(new Error('unsupported type for ' + filename))
  102. return onnextentry()
  103. }
  104. var entry = pack.entry(header, onnextentry)
  105. if (!entry) return
  106. var rs = mapStream(xfs.createReadStream(path.join(cwd, filename)), header)
  107. rs.on('error', function (err) { // always forward errors on destroy
  108. entry.destroy(err)
  109. })
  110. pump(rs, entry)
  111. }
  112. var onnextentry = function (err) {
  113. if (err) return pack.destroy(err)
  114. statNext(onstat)
  115. }
  116. onnextentry()
  117. return pack
  118. }
  119. var head = function (list) {
  120. return list.length ? list[list.length - 1] : null
  121. }
  122. var processGetuid = function () {
  123. return process.getuid ? process.getuid() : -1
  124. }
  125. var processUmask = function () {
  126. return process.umask ? process.umask() : 0
  127. }
  128. exports.extract = function (cwd, opts) {
  129. if (!cwd) cwd = '.'
  130. if (!opts) opts = {}
  131. var xfs = opts.fs || fs
  132. var ignore = opts.ignore || opts.filter || noop
  133. var map = opts.map || noop
  134. var mapStream = opts.mapStream || echo
  135. var own = opts.chown !== false && !win32 && processGetuid() === 0
  136. var extract = opts.extract || tar.extract()
  137. var stack = []
  138. var now = new Date()
  139. var umask = typeof opts.umask === 'number' ? ~opts.umask : ~processUmask()
  140. var dmode = typeof opts.dmode === 'number' ? opts.dmode : 0
  141. var fmode = typeof opts.fmode === 'number' ? opts.fmode : 0
  142. var strict = opts.strict !== false
  143. if (opts.strip) map = strip(map, opts.strip)
  144. if (opts.readable) {
  145. dmode |= parseInt(555, 8)
  146. fmode |= parseInt(444, 8)
  147. }
  148. if (opts.writable) {
  149. dmode |= parseInt(333, 8)
  150. fmode |= parseInt(222, 8)
  151. }
  152. var utimesParent = function (name, cb) { // we just set the mtime on the parent dir again everytime we write an entry
  153. var top
  154. while ((top = head(stack)) && name.slice(0, top[0].length) !== top[0]) stack.pop()
  155. if (!top) return cb()
  156. xfs.utimes(top[0], now, top[1], cb)
  157. }
  158. var utimes = function (name, header, cb) {
  159. if (opts.utimes === false) return cb()
  160. if (header.type === 'directory') return xfs.utimes(name, now, header.mtime, cb)
  161. if (header.type === 'symlink') return utimesParent(name, cb) // TODO: how to set mtime on link?
  162. xfs.utimes(name, now, header.mtime, function (err) {
  163. if (err) return cb(err)
  164. utimesParent(name, cb)
  165. })
  166. }
  167. var chperm = function (name, header, cb) {
  168. var link = header.type === 'symlink'
  169. var chmod = link ? xfs.lchmod : xfs.chmod
  170. var chown = link ? xfs.lchown : xfs.chown
  171. if (!chmod) return cb()
  172. chmod(name, (header.mode | (header.type === 'directory' ? dmode : fmode)) & umask, function (err) {
  173. if (err) return cb(err)
  174. if (!own) return cb()
  175. if (!chown) return cb()
  176. chown(name, header.uid, header.gid, cb)
  177. })
  178. }
  179. extract.on('entry', function (header, stream, next) {
  180. header = map(header) || header
  181. header.name = normalize(header.name)
  182. var name = path.join(cwd, path.join('/', header.name))
  183. if (ignore(name, header)) {
  184. stream.resume()
  185. return next()
  186. }
  187. var stat = function (err) {
  188. if (err) return next(err)
  189. utimes(name, header, function (err) {
  190. if (err) return next(err)
  191. if (win32) return next()
  192. chperm(name, header, next)
  193. })
  194. }
  195. var onsymlink = function () {
  196. if (win32) return next() // skip symlinks on win for now before it can be tested
  197. xfs.unlink(name, function () {
  198. xfs.symlink(header.linkname, name, stat)
  199. })
  200. }
  201. var onlink = function () {
  202. if (win32) return next() // skip links on win for now before it can be tested
  203. xfs.unlink(name, function () {
  204. var srcpath = path.resolve(cwd, header.linkname)
  205. xfs.link(srcpath, name, function (err) {
  206. if (err && err.code === 'EPERM' && opts.hardlinkAsFilesFallback) {
  207. stream = xfs.createReadStream(srcpath)
  208. return onfile()
  209. }
  210. stat(err)
  211. })
  212. })
  213. }
  214. var onfile = function () {
  215. var ws = xfs.createWriteStream(name)
  216. var rs = mapStream(stream, header)
  217. ws.on('error', function (err) { // always forward errors on destroy
  218. rs.destroy(err)
  219. })
  220. pump(rs, ws, function (err) {
  221. if (err) return next(err)
  222. ws.on('close', stat)
  223. })
  224. }
  225. if (header.type === 'directory') {
  226. stack.push([name, header.mtime])
  227. return mkdirp(name, {fs: xfs}, stat)
  228. }
  229. mkdirp(path.dirname(name), {fs: xfs}, function (err) {
  230. if (err) return next(err)
  231. switch (header.type) {
  232. case 'file': return onfile()
  233. case 'link': return onlink()
  234. case 'symlink': return onsymlink()
  235. }
  236. if (strict) return next(new Error('unsupported type for ' + name + ' (' + header.type + ')'))
  237. stream.resume()
  238. next()
  239. })
  240. })
  241. return extract
  242. }