Projekt

Obecné

Profil

Stáhnout (8.34 KB) Statistiky
| Větev: | Revize:
1 3a515b92 cagy
// 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
};