touch.js 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  1. var fs = require("fs")
  2. , cons = require("constants")
  3. module.exports = touch
  4. touch.touchSync = touch.sync = function (f, options) {
  5. return touch(f, options)
  6. }
  7. touch.ftouch = ftouch
  8. touch.ftouchSync = ftouch.sync = function (fd, options) {
  9. return ftouch(fd, options)
  10. }
  11. function validOpts (options) {
  12. options = Object.create(options || {})
  13. // {mtime: true}, {ctime: true}
  14. // If set to something else, then treat as epoch ms value
  15. var now = new Date(options.time || Date.now())
  16. if (!options.atime && !options.mtime) {
  17. options.atime = options.mtime = now
  18. } else {
  19. if (true === options.atime) {
  20. options.atime = now
  21. }
  22. if (true === options.mtime) {
  23. options.mtime = now
  24. }
  25. }
  26. var oflags = 0
  27. if (!options.force) {
  28. oflags = oflags | cons.O_RDWR
  29. }
  30. if (!options.nocreate) {
  31. oflags = oflags | cons.O_CREAT
  32. }
  33. options.oflags = oflags
  34. return options
  35. }
  36. function optionsRef (then, arg, options, cb) {
  37. if (!options.ref) return then(arg, options, cb)
  38. return cb
  39. ? fs.stat(options.ref, optionsRefcb(then, arg, options, cb))
  40. : optionsRefcb(then, arg, options)(null, fs.statSync(options.ref))
  41. }
  42. function optionsRefcb (then, arg, options, cb) { return function (er, s) {
  43. if (er) {
  44. er.path = er.file = options.ref
  45. return cb(er)
  46. }
  47. options.atime = options.atime && s.atime.getTime()
  48. options.mtime = options.mtime && s.mtime.getTime()
  49. // so we don't keep doing this.
  50. options.ref = null
  51. return then(arg, options, cb)
  52. }}
  53. function touch (f, options, cb) {
  54. if (typeof options === "function") cb = options, options = null
  55. options = validOpts(options)
  56. return optionsRef(touch_, f, validOpts(options), cb)
  57. }
  58. function touch_ (f, options, cb) {
  59. return openThenF(f, options, cb)
  60. }
  61. function openThenF (f, options, cb) {
  62. options.closeAfter = true
  63. return cb
  64. ? fs.open(f, options.oflags, openThenFcb(options, cb))
  65. : openThenFcb(options)(null, fs.openSync(f, options.oflags))
  66. }
  67. function openThenFcb (options, cb) { return function (er, fd) {
  68. if (er) {
  69. if (fd && options.closeAfter) fs.close(fd, function () {})
  70. return cb(er)
  71. }
  72. return ftouch(fd, options, cb)
  73. }}
  74. function ftouch (fd, options, cb) {
  75. if (typeof options === "function") cb = options, options = null
  76. return optionsRef(ftouch_, fd, validOpts(options), cb)
  77. }
  78. function ftouch_ (fd, options, cb) {
  79. // still not set. leave as what the file already has.
  80. return fstatThenFutimes(fd, options, cb)
  81. }
  82. function fstatThenFutimes (fd, options, cb) {
  83. if (options.atime && options.mtime) return thenFutimes(fd, options, cb)
  84. return cb
  85. ? fs.fstat(fd, fstatThenFutimescb(fd, options, cb))
  86. : fstatThenFutimescb(fd, options)(null, fs.fstatSync(fd))
  87. }
  88. function fstatThenFutimescb (fd, options, cb) { return function (er, s) {
  89. if (er) {
  90. if (options.closeAfter) fs.close(fd, function () {})
  91. return cb(er)
  92. }
  93. options.atime = options.atime || s.atime.getTime()
  94. options.mtime = options.mtime || s.mtime.getTime()
  95. return thenFutimes(fd, options, cb)
  96. }}
  97. function thenFutimes (fd, options, cb) {
  98. if (typeof options.atime === "object") {
  99. options.atime = options.atime.getTime()
  100. }
  101. if (typeof options.mtime === "object") {
  102. options.mtime = options.mtime.getTime()
  103. }
  104. var a = parseInt(options.atime / 1000, 10)
  105. , m = parseInt(options.mtime / 1000, 10)
  106. return cb
  107. ? fs.futimes(fd, a, m, thenFutimescb(fd, options, cb))
  108. : thenFutimescb(fd, options)(null, fs.futimesSync(fd, a, m))
  109. }
  110. function thenFutimescb (fd, options, cb) { return function (er, res) {
  111. if (er) {
  112. if (options.closeAfter) fs.close(fd, function () {})
  113. return cb(er)
  114. }
  115. return finish(fd, options, res, cb)
  116. }}
  117. function finish (fd, options, res, cb) {
  118. return options.closeAfter ? finishClose(fd, options, res, cb)
  119. : cb ? cb(null, res)
  120. : res
  121. }
  122. function finishClose (fd, options, res, cb) {
  123. return cb
  124. ? fs.close(fd, finishClosecb(res, options, cb))
  125. : finishClosecb(res, options)(null, fs.closeSync(fd))
  126. }
  127. function finishClosecb (res, options, cb) { return function (er) {
  128. if (er) return cb(er)
  129. options.closeAfter = null
  130. return finish(null, options, res, cb)
  131. }}