c0a854d357766363c318262ea0ead787568795c574a79d969124fd90f6938503675d61cdb75e0b3b1dc04d205f35a67fcbb493c1d3b40906d9dab182405f92 1.8 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556
  1. 'use strict'
  2. const fs = require('graceful-fs')
  3. const util = require('util')
  4. const chmod = util.promisify(fs.chmod)
  5. const unlink = util.promisify(fs.unlink)
  6. const stat = util.promisify(fs.stat)
  7. const move = require('move-concurrently')
  8. const pinflight = require('promise-inflight')
  9. module.exports = moveFile
  10. function moveFile (src, dest) {
  11. // This isn't quite an fs.rename -- the assumption is that
  12. // if `dest` already exists, and we get certain errors while
  13. // trying to move it, we should just not bother.
  14. //
  15. // In the case of cache corruption, users will receive an
  16. // EINTEGRITY error elsewhere, and can remove the offending
  17. // content their own way.
  18. //
  19. // Note that, as the name suggests, this strictly only supports file moves.
  20. return new Promise((resolve, reject) => {
  21. fs.link(src, dest, (err) => {
  22. if (err) {
  23. if (err.code === 'EEXIST' || err.code === 'EBUSY') {
  24. // file already exists, so whatever
  25. } else if (err.code === 'EPERM' && process.platform === 'win32') {
  26. // file handle stayed open even past graceful-fs limits
  27. } else {
  28. return reject(err)
  29. }
  30. }
  31. return resolve()
  32. })
  33. })
  34. .then(() => {
  35. // content should never change for any reason, so make it read-only
  36. return Promise.all([
  37. unlink(src),
  38. process.platform !== 'win32' && chmod(dest, '0444')
  39. ])
  40. })
  41. .catch(() => {
  42. return pinflight('cacache-move-file:' + dest, () => {
  43. return stat(dest).catch((err) => {
  44. if (err.code !== 'ENOENT') {
  45. // Something else is wrong here. Bail bail bail
  46. throw err
  47. }
  48. // file doesn't already exist! let's try a rename -> copy fallback
  49. return move(src, dest, { Promise, fs })
  50. })
  51. })
  52. })
  53. }