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