node-fs.js 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  1. "use strict";
  2. var nodeFs = require("fs");
  3. var nodePath = require("path");
  4. // Implements the fs interface required by js-git/fs-db
  5. var fs = module.exports = {};
  6. fs.readFile = readFile;
  7. fs.readChunk = readChunk;
  8. fs.writeFile = writeFile;
  9. fs.readDir = readDir;
  10. fs.rename = rename;
  11. // Reads all bytes for given path.
  12. // => binary
  13. // => undefined if file does not exist
  14. function readFile(path, callback) {
  15. nodeFs.readFile(path, function (err, binary) {
  16. if (err) {
  17. if (err.code === "ENOENT") return callback();
  18. return callback(err);
  19. }
  20. return callback(null, binary);
  21. });
  22. }
  23. // Reads bytes from inclusive [start, end) exclusive for given path.
  24. // => binary
  25. // => undefined if file does not exist
  26. function readChunk(path, start, end, callback) {
  27. if (end < 0) {
  28. return readLastChunk(path, start, end, callback);
  29. }
  30. var stream = nodeFs.createReadStream(path, {
  31. start: start,
  32. end: end - 1
  33. });
  34. var chunks = [];
  35. stream.on("readable", function () {
  36. var chunk = stream.read();
  37. if (chunk === null) return callback(null, Buffer.concat(chunks));
  38. return chunks.push(chunk);
  39. });
  40. stream.on("error", function (err) {
  41. if (err.code === "ENOENT") return callback();
  42. return callback(err);
  43. });
  44. }
  45. // Node.js readable streams do not support reading from a position to the end
  46. // of the file, but we can roll our own using the lower-level fs.open and
  47. // fs.read on a file descriptor, which allows read to seek.
  48. function readLastChunk(path, start, end, callback) {
  49. nodeFs.open(path, "r", function (err, fd) {
  50. if (err) {
  51. if (err.code === "EACCES") return callback();
  52. return callback(err);
  53. }
  54. var buffer = new Buffer(4096);
  55. var length = 0;
  56. read();
  57. // Only the first read needs to seek.
  58. // All subsequent reads will continue from the end of the previous.
  59. start = null;
  60. function read() {
  61. if (buffer.length - length === 0) {
  62. grow();
  63. }
  64. nodeFs.read(fd, buffer, length, buffer.length - length, start, onread);
  65. }
  66. function onread(err, bytesRead) {
  67. if (err) return callback(err);
  68. length += bytesRead;
  69. if (bytesRead === 0) {
  70. return callback(null, buffer.slice(0, buffer.length + end));
  71. }
  72. read();
  73. }
  74. function grow() {
  75. var newBuffer = new Buffer(buffer.length * 2);
  76. buffer.copy(newBuffer);
  77. buffer = newBuffer;
  78. }
  79. });
  80. }
  81. // Writes all bytes over file at given path.
  82. // Creates all necessary parent directories.
  83. // => undefined
  84. function writeFile(path, binary, callback) {
  85. mkdirp(nodePath.dirname(path), function (err) {
  86. if (err) return callback(err);
  87. nodeFs.writeFile(path, binary, callback);
  88. });
  89. }
  90. // Renames the given file.
  91. // Creates all necessary parent directories.
  92. // => undefined
  93. function rename(oldPath, newPath, callback) {
  94. var oldBase = nodePath.dirname(oldPath);
  95. var newBase = nodePath.dirname(newPath);
  96. if (oldBase === newBase) {
  97. return nodeFs.rename(oldPath, newPath, callback);
  98. }
  99. mkdirp(nodePath.dirname(path), function (err) {
  100. if (err) return callback(err);
  101. nodeFs.rename(oldPath, newPath, callback);
  102. });
  103. }
  104. // Reads all entry names for a given path.
  105. // All names are relative to the directory itself, not fully qualified paths.
  106. // => array<name>
  107. // => undefined if directory does not exist
  108. function readDir(path, callback) {
  109. nodeFs.readdir(path, function (err, names) {
  110. if (err) {
  111. if (err.code === "ENOENT") return callback();
  112. return callback(err);
  113. }
  114. return callback(null, names);
  115. });
  116. }
  117. function mkdirp(path, callback) {
  118. nodeFs.mkdir(path, function (err) {
  119. if (err) {
  120. if (err.code === "ENOENT") {
  121. return mkdirp(nodePath.dirname(path), function (err) {
  122. if (err) return callback(err);
  123. nodeFs.mkdir(path, function (err) {
  124. if (err && err.code !== "EEXIST") return callback(err);
  125. return callback();
  126. });
  127. });
  128. }
  129. if (err.code === "EEXIST") return callback();
  130. return callback(err);
  131. }
  132. callback();
  133. });
  134. }