file.js 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196
  1. /* This Source Code Form is subject to the terms of the Mozilla Public
  2. * License, v. 2.0. If a copy of the MPL was not distributed with this
  3. * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  4. "use strict";
  5. module.metadata = {
  6. "stability": "experimental"
  7. };
  8. const {Cc,Ci,Cr} = require("chrome");
  9. const byteStreams = require("./byte-streams");
  10. const textStreams = require("./text-streams");
  11. // Flags passed when opening a file. See nsprpub/pr/include/prio.h.
  12. const OPEN_FLAGS = {
  13. RDONLY: parseInt("0x01"),
  14. WRONLY: parseInt("0x02"),
  15. CREATE_FILE: parseInt("0x08"),
  16. APPEND: parseInt("0x10"),
  17. TRUNCATE: parseInt("0x20"),
  18. EXCL: parseInt("0x80")
  19. };
  20. var dirsvc = Cc["@mozilla.org/file/directory_service;1"]
  21. .getService(Ci.nsIProperties);
  22. function MozFile(path) {
  23. var file = Cc['@mozilla.org/file/local;1']
  24. .createInstance(Ci.nsILocalFile);
  25. file.initWithPath(path);
  26. return file;
  27. }
  28. function ensureReadable(file) {
  29. if (!file.isReadable())
  30. throw new Error("path is not readable: " + file.path);
  31. }
  32. function ensureDir(file) {
  33. ensureExists(file);
  34. if (!file.isDirectory())
  35. throw new Error("path is not a directory: " + file.path);
  36. }
  37. function ensureFile(file) {
  38. ensureExists(file);
  39. if (!file.isFile())
  40. throw new Error("path is not a file: " + file.path);
  41. }
  42. function ensureExists(file) {
  43. if (!file.exists())
  44. throw friendlyError(Cr.NS_ERROR_FILE_NOT_FOUND, file.path);
  45. }
  46. function friendlyError(errOrResult, filename) {
  47. var isResult = typeof(errOrResult) === "number";
  48. var result = isResult ? errOrResult : errOrResult.result;
  49. switch (result) {
  50. case Cr.NS_ERROR_FILE_NOT_FOUND:
  51. return new Error("path does not exist: " + filename);
  52. }
  53. return isResult ? new Error("XPCOM error code: " + errOrResult) : errOrResult;
  54. }
  55. exports.exists = function exists(filename) {
  56. return MozFile(filename).exists();
  57. };
  58. exports.isFile = function isFile(filename) {
  59. return MozFile(filename).isFile();
  60. };
  61. exports.read = function read(filename, mode) {
  62. if (typeof(mode) !== "string")
  63. mode = "";
  64. // Ensure mode is read-only.
  65. mode = /b/.test(mode) ? "b" : "";
  66. var stream = exports.open(filename, mode);
  67. try {
  68. var str = stream.read();
  69. }
  70. finally {
  71. stream.close();
  72. }
  73. return str;
  74. };
  75. exports.join = function join(base) {
  76. if (arguments.length < 2)
  77. throw new Error("need at least 2 args");
  78. base = MozFile(base);
  79. for (var i = 1; i < arguments.length; i++)
  80. base.append(arguments[i]);
  81. return base.path;
  82. };
  83. exports.dirname = function dirname(path) {
  84. var parent = MozFile(path).parent;
  85. return parent ? parent.path : "";
  86. };
  87. exports.basename = function basename(path) {
  88. var leafName = MozFile(path).leafName;
  89. // On Windows, leafName when the path is a volume letter and colon ("c:") is
  90. // the path itself. But such a path has no basename, so we want the empty
  91. // string.
  92. return leafName == path ? "" : leafName;
  93. };
  94. exports.list = function list(path) {
  95. var file = MozFile(path);
  96. ensureDir(file);
  97. ensureReadable(file);
  98. var entries = file.directoryEntries;
  99. var entryNames = [];
  100. while(entries.hasMoreElements()) {
  101. var entry = entries.getNext();
  102. entry.QueryInterface(Ci.nsIFile);
  103. entryNames.push(entry.leafName);
  104. }
  105. return entryNames;
  106. };
  107. exports.open = function open(filename, mode) {
  108. var file = MozFile(filename);
  109. if (typeof(mode) !== "string")
  110. mode = "";
  111. // File opened for write only.
  112. if (/w/.test(mode)) {
  113. if (file.exists())
  114. ensureFile(file);
  115. var stream = Cc['@mozilla.org/network/file-output-stream;1'].
  116. createInstance(Ci.nsIFileOutputStream);
  117. var openFlags = OPEN_FLAGS.WRONLY |
  118. OPEN_FLAGS.CREATE_FILE |
  119. OPEN_FLAGS.TRUNCATE;
  120. var permFlags = parseInt("0644", 8); // u+rw go+r
  121. try {
  122. stream.init(file, openFlags, permFlags, 0);
  123. }
  124. catch (err) {
  125. throw friendlyError(err, filename);
  126. }
  127. return /b/.test(mode) ?
  128. new byteStreams.ByteWriter(stream) :
  129. new textStreams.TextWriter(stream);
  130. }
  131. // File opened for read only, the default.
  132. ensureFile(file);
  133. stream = Cc['@mozilla.org/network/file-input-stream;1'].
  134. createInstance(Ci.nsIFileInputStream);
  135. try {
  136. stream.init(file, OPEN_FLAGS.RDONLY, 0, 0);
  137. }
  138. catch (err) {
  139. throw friendlyError(err, filename);
  140. }
  141. return /b/.test(mode) ?
  142. new byteStreams.ByteReader(stream) :
  143. new textStreams.TextReader(stream);
  144. };
  145. exports.remove = function remove(path) {
  146. var file = MozFile(path);
  147. ensureFile(file);
  148. file.remove(false);
  149. };
  150. exports.mkpath = function mkpath(path) {
  151. var file = MozFile(path);
  152. if (!file.exists())
  153. file.create(Ci.nsIFile.DIRECTORY_TYPE, parseInt("0755", 8)); // u+rwx go+rx
  154. else if (!file.isDirectory())
  155. throw new Error("The path already exists and is not a directory: " + path);
  156. };
  157. exports.rmdir = function rmdir(path) {
  158. var file = MozFile(path);
  159. ensureDir(file);
  160. try {
  161. file.remove(false);
  162. }
  163. catch (err) {
  164. // Bug 566950 explains why we're not catching a specific exception here.
  165. throw new Error("The directory is not empty: " + path);
  166. }
  167. };