Initial commit
[yaffs-website] / node_modules / fs.realpath / old.js
1 // Copyright Joyent, Inc. and other Node contributors.
2 //
3 // Permission is hereby granted, free of charge, to any person obtaining a
4 // copy of this software and associated documentation files (the
5 // "Software"), to deal in the Software without restriction, including
6 // without limitation the rights to use, copy, modify, merge, publish,
7 // distribute, sublicense, and/or sell copies of the Software, and to permit
8 // persons to whom the Software is furnished to do so, subject to the
9 // following conditions:
10 //
11 // The above copyright notice and this permission notice shall be included
12 // in all copies or substantial portions of the Software.
13 //
14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15 // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
17 // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
18 // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
19 // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
20 // USE OR OTHER DEALINGS IN THE SOFTWARE.
21
22 var pathModule = require('path');
23 var isWindows = process.platform === 'win32';
24 var fs = require('fs');
25
26 // JavaScript implementation of realpath, ported from node pre-v6
27
28 var DEBUG = process.env.NODE_DEBUG && /fs/.test(process.env.NODE_DEBUG);
29
30 function rethrow() {
31   // Only enable in debug mode. A backtrace uses ~1000 bytes of heap space and
32   // is fairly slow to generate.
33   var callback;
34   if (DEBUG) {
35     var backtrace = new Error;
36     callback = debugCallback;
37   } else
38     callback = missingCallback;
39
40   return callback;
41
42   function debugCallback(err) {
43     if (err) {
44       backtrace.message = err.message;
45       err = backtrace;
46       missingCallback(err);
47     }
48   }
49
50   function missingCallback(err) {
51     if (err) {
52       if (process.throwDeprecation)
53         throw err;  // Forgot a callback but don't know where? Use NODE_DEBUG=fs
54       else if (!process.noDeprecation) {
55         var msg = 'fs: missing callback ' + (err.stack || err.message);
56         if (process.traceDeprecation)
57           console.trace(msg);
58         else
59           console.error(msg);
60       }
61     }
62   }
63 }
64
65 function maybeCallback(cb) {
66   return typeof cb === 'function' ? cb : rethrow();
67 }
68
69 var normalize = pathModule.normalize;
70
71 // Regexp that finds the next partion of a (partial) path
72 // result is [base_with_slash, base], e.g. ['somedir/', 'somedir']
73 if (isWindows) {
74   var nextPartRe = /(.*?)(?:[\/\\]+|$)/g;
75 } else {
76   var nextPartRe = /(.*?)(?:[\/]+|$)/g;
77 }
78
79 // Regex to find the device root, including trailing slash. E.g. 'c:\\'.
80 if (isWindows) {
81   var splitRootRe = /^(?:[a-zA-Z]:|[\\\/]{2}[^\\\/]+[\\\/][^\\\/]+)?[\\\/]*/;
82 } else {
83   var splitRootRe = /^[\/]*/;
84 }
85
86 exports.realpathSync = function realpathSync(p, cache) {
87   // make p is absolute
88   p = pathModule.resolve(p);
89
90   if (cache && Object.prototype.hasOwnProperty.call(cache, p)) {
91     return cache[p];
92   }
93
94   var original = p,
95       seenLinks = {},
96       knownHard = {};
97
98   // current character position in p
99   var pos;
100   // the partial path so far, including a trailing slash if any
101   var current;
102   // the partial path without a trailing slash (except when pointing at a root)
103   var base;
104   // the partial path scanned in the previous round, with slash
105   var previous;
106
107   start();
108
109   function start() {
110     // Skip over roots
111     var m = splitRootRe.exec(p);
112     pos = m[0].length;
113     current = m[0];
114     base = m[0];
115     previous = '';
116
117     // On windows, check that the root exists. On unix there is no need.
118     if (isWindows && !knownHard[base]) {
119       fs.lstatSync(base);
120       knownHard[base] = true;
121     }
122   }
123
124   // walk down the path, swapping out linked pathparts for their real
125   // values
126   // NB: p.length changes.
127   while (pos < p.length) {
128     // find the next part
129     nextPartRe.lastIndex = pos;
130     var result = nextPartRe.exec(p);
131     previous = current;
132     current += result[0];
133     base = previous + result[1];
134     pos = nextPartRe.lastIndex;
135
136     // continue if not a symlink
137     if (knownHard[base] || (cache && cache[base] === base)) {
138       continue;
139     }
140
141     var resolvedLink;
142     if (cache && Object.prototype.hasOwnProperty.call(cache, base)) {
143       // some known symbolic link.  no need to stat again.
144       resolvedLink = cache[base];
145     } else {
146       var stat = fs.lstatSync(base);
147       if (!stat.isSymbolicLink()) {
148         knownHard[base] = true;
149         if (cache) cache[base] = base;
150         continue;
151       }
152
153       // read the link if it wasn't read before
154       // dev/ino always return 0 on windows, so skip the check.
155       var linkTarget = null;
156       if (!isWindows) {
157         var id = stat.dev.toString(32) + ':' + stat.ino.toString(32);
158         if (seenLinks.hasOwnProperty(id)) {
159           linkTarget = seenLinks[id];
160         }
161       }
162       if (linkTarget === null) {
163         fs.statSync(base);
164         linkTarget = fs.readlinkSync(base);
165       }
166       resolvedLink = pathModule.resolve(previous, linkTarget);
167       // track this, if given a cache.
168       if (cache) cache[base] = resolvedLink;
169       if (!isWindows) seenLinks[id] = linkTarget;
170     }
171
172     // resolve the link, then start over
173     p = pathModule.resolve(resolvedLink, p.slice(pos));
174     start();
175   }
176
177   if (cache) cache[original] = p;
178
179   return p;
180 };
181
182
183 exports.realpath = function realpath(p, cache, cb) {
184   if (typeof cb !== 'function') {
185     cb = maybeCallback(cache);
186     cache = null;
187   }
188
189   // make p is absolute
190   p = pathModule.resolve(p);
191
192   if (cache && Object.prototype.hasOwnProperty.call(cache, p)) {
193     return process.nextTick(cb.bind(null, null, cache[p]));
194   }
195
196   var original = p,
197       seenLinks = {},
198       knownHard = {};
199
200   // current character position in p
201   var pos;
202   // the partial path so far, including a trailing slash if any
203   var current;
204   // the partial path without a trailing slash (except when pointing at a root)
205   var base;
206   // the partial path scanned in the previous round, with slash
207   var previous;
208
209   start();
210
211   function start() {
212     // Skip over roots
213     var m = splitRootRe.exec(p);
214     pos = m[0].length;
215     current = m[0];
216     base = m[0];
217     previous = '';
218
219     // On windows, check that the root exists. On unix there is no need.
220     if (isWindows && !knownHard[base]) {
221       fs.lstat(base, function(err) {
222         if (err) return cb(err);
223         knownHard[base] = true;
224         LOOP();
225       });
226     } else {
227       process.nextTick(LOOP);
228     }
229   }
230
231   // walk down the path, swapping out linked pathparts for their real
232   // values
233   function LOOP() {
234     // stop if scanned past end of path
235     if (pos >= p.length) {
236       if (cache) cache[original] = p;
237       return cb(null, p);
238     }
239
240     // find the next part
241     nextPartRe.lastIndex = pos;
242     var result = nextPartRe.exec(p);
243     previous = current;
244     current += result[0];
245     base = previous + result[1];
246     pos = nextPartRe.lastIndex;
247
248     // continue if not a symlink
249     if (knownHard[base] || (cache && cache[base] === base)) {
250       return process.nextTick(LOOP);
251     }
252
253     if (cache && Object.prototype.hasOwnProperty.call(cache, base)) {
254       // known symbolic link.  no need to stat again.
255       return gotResolvedLink(cache[base]);
256     }
257
258     return fs.lstat(base, gotStat);
259   }
260
261   function gotStat(err, stat) {
262     if (err) return cb(err);
263
264     // if not a symlink, skip to the next path part
265     if (!stat.isSymbolicLink()) {
266       knownHard[base] = true;
267       if (cache) cache[base] = base;
268       return process.nextTick(LOOP);
269     }
270
271     // stat & read the link if not read before
272     // call gotTarget as soon as the link target is known
273     // dev/ino always return 0 on windows, so skip the check.
274     if (!isWindows) {
275       var id = stat.dev.toString(32) + ':' + stat.ino.toString(32);
276       if (seenLinks.hasOwnProperty(id)) {
277         return gotTarget(null, seenLinks[id], base);
278       }
279     }
280     fs.stat(base, function(err) {
281       if (err) return cb(err);
282
283       fs.readlink(base, function(err, target) {
284         if (!isWindows) seenLinks[id] = target;
285         gotTarget(err, target);
286       });
287     });
288   }
289
290   function gotTarget(err, target, base) {
291     if (err) return cb(err);
292
293     var resolvedLink = pathModule.resolve(previous, target);
294     if (cache) cache[base] = resolvedLink;
295     gotResolvedLink(resolvedLink);
296   }
297
298   function gotResolvedLink(resolvedLink) {
299     // resolve the link, then start over
300     p = pathModule.resolve(resolvedLink, p.slice(pos));
301     start();
302   }
303 };