michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: "use strict"; michael@0: michael@0: module.metadata = { michael@0: "stability": "experimental" michael@0: }; michael@0: michael@0: const {Cc,Ci,Cr} = require("chrome"); michael@0: const byteStreams = require("./byte-streams"); michael@0: const textStreams = require("./text-streams"); michael@0: michael@0: // Flags passed when opening a file. See nsprpub/pr/include/prio.h. michael@0: const OPEN_FLAGS = { michael@0: RDONLY: parseInt("0x01"), michael@0: WRONLY: parseInt("0x02"), michael@0: CREATE_FILE: parseInt("0x08"), michael@0: APPEND: parseInt("0x10"), michael@0: TRUNCATE: parseInt("0x20"), michael@0: EXCL: parseInt("0x80") michael@0: }; michael@0: michael@0: var dirsvc = Cc["@mozilla.org/file/directory_service;1"] michael@0: .getService(Ci.nsIProperties); michael@0: michael@0: function MozFile(path) { michael@0: var file = Cc['@mozilla.org/file/local;1'] michael@0: .createInstance(Ci.nsILocalFile); michael@0: file.initWithPath(path); michael@0: return file; michael@0: } michael@0: michael@0: function ensureReadable(file) { michael@0: if (!file.isReadable()) michael@0: throw new Error("path is not readable: " + file.path); michael@0: } michael@0: michael@0: function ensureDir(file) { michael@0: ensureExists(file); michael@0: if (!file.isDirectory()) michael@0: throw new Error("path is not a directory: " + file.path); michael@0: } michael@0: michael@0: function ensureFile(file) { michael@0: ensureExists(file); michael@0: if (!file.isFile()) michael@0: throw new Error("path is not a file: " + file.path); michael@0: } michael@0: michael@0: function ensureExists(file) { michael@0: if (!file.exists()) michael@0: throw friendlyError(Cr.NS_ERROR_FILE_NOT_FOUND, file.path); michael@0: } michael@0: michael@0: function friendlyError(errOrResult, filename) { michael@0: var isResult = typeof(errOrResult) === "number"; michael@0: var result = isResult ? errOrResult : errOrResult.result; michael@0: switch (result) { michael@0: case Cr.NS_ERROR_FILE_NOT_FOUND: michael@0: return new Error("path does not exist: " + filename); michael@0: } michael@0: return isResult ? new Error("XPCOM error code: " + errOrResult) : errOrResult; michael@0: } michael@0: michael@0: exports.exists = function exists(filename) { michael@0: return MozFile(filename).exists(); michael@0: }; michael@0: michael@0: exports.isFile = function isFile(filename) { michael@0: return MozFile(filename).isFile(); michael@0: }; michael@0: michael@0: exports.read = function read(filename, mode) { michael@0: if (typeof(mode) !== "string") michael@0: mode = ""; michael@0: michael@0: // Ensure mode is read-only. michael@0: mode = /b/.test(mode) ? "b" : ""; michael@0: michael@0: var stream = exports.open(filename, mode); michael@0: try { michael@0: var str = stream.read(); michael@0: } michael@0: finally { michael@0: stream.close(); michael@0: } michael@0: michael@0: return str; michael@0: }; michael@0: michael@0: exports.join = function join(base) { michael@0: if (arguments.length < 2) michael@0: throw new Error("need at least 2 args"); michael@0: base = MozFile(base); michael@0: for (var i = 1; i < arguments.length; i++) michael@0: base.append(arguments[i]); michael@0: return base.path; michael@0: }; michael@0: michael@0: exports.dirname = function dirname(path) { michael@0: var parent = MozFile(path).parent; michael@0: return parent ? parent.path : ""; michael@0: }; michael@0: michael@0: exports.basename = function basename(path) { michael@0: var leafName = MozFile(path).leafName; michael@0: michael@0: // On Windows, leafName when the path is a volume letter and colon ("c:") is michael@0: // the path itself. But such a path has no basename, so we want the empty michael@0: // string. michael@0: return leafName == path ? "" : leafName; michael@0: }; michael@0: michael@0: exports.list = function list(path) { michael@0: var file = MozFile(path); michael@0: ensureDir(file); michael@0: ensureReadable(file); michael@0: michael@0: var entries = file.directoryEntries; michael@0: var entryNames = []; michael@0: while(entries.hasMoreElements()) { michael@0: var entry = entries.getNext(); michael@0: entry.QueryInterface(Ci.nsIFile); michael@0: entryNames.push(entry.leafName); michael@0: } michael@0: return entryNames; michael@0: }; michael@0: michael@0: exports.open = function open(filename, mode) { michael@0: var file = MozFile(filename); michael@0: if (typeof(mode) !== "string") michael@0: mode = ""; michael@0: michael@0: // File opened for write only. michael@0: if (/w/.test(mode)) { michael@0: if (file.exists()) michael@0: ensureFile(file); michael@0: var stream = Cc['@mozilla.org/network/file-output-stream;1']. michael@0: createInstance(Ci.nsIFileOutputStream); michael@0: var openFlags = OPEN_FLAGS.WRONLY | michael@0: OPEN_FLAGS.CREATE_FILE | michael@0: OPEN_FLAGS.TRUNCATE; michael@0: var permFlags = parseInt("0644", 8); // u+rw go+r michael@0: try { michael@0: stream.init(file, openFlags, permFlags, 0); michael@0: } michael@0: catch (err) { michael@0: throw friendlyError(err, filename); michael@0: } michael@0: return /b/.test(mode) ? michael@0: new byteStreams.ByteWriter(stream) : michael@0: new textStreams.TextWriter(stream); michael@0: } michael@0: michael@0: // File opened for read only, the default. michael@0: ensureFile(file); michael@0: stream = Cc['@mozilla.org/network/file-input-stream;1']. michael@0: createInstance(Ci.nsIFileInputStream); michael@0: try { michael@0: stream.init(file, OPEN_FLAGS.RDONLY, 0, 0); michael@0: } michael@0: catch (err) { michael@0: throw friendlyError(err, filename); michael@0: } michael@0: return /b/.test(mode) ? michael@0: new byteStreams.ByteReader(stream) : michael@0: new textStreams.TextReader(stream); michael@0: }; michael@0: michael@0: exports.remove = function remove(path) { michael@0: var file = MozFile(path); michael@0: ensureFile(file); michael@0: file.remove(false); michael@0: }; michael@0: michael@0: exports.mkpath = function mkpath(path) { michael@0: var file = MozFile(path); michael@0: if (!file.exists()) michael@0: file.create(Ci.nsIFile.DIRECTORY_TYPE, parseInt("0755", 8)); // u+rwx go+rx michael@0: else if (!file.isDirectory()) michael@0: throw new Error("The path already exists and is not a directory: " + path); michael@0: }; michael@0: michael@0: exports.rmdir = function rmdir(path) { michael@0: var file = MozFile(path); michael@0: ensureDir(file); michael@0: try { michael@0: file.remove(false); michael@0: } michael@0: catch (err) { michael@0: // Bug 566950 explains why we're not catching a specific exception here. michael@0: throw new Error("The directory is not empty: " + path); michael@0: } michael@0: };