提交 ce7982b6 编写于 作者: B Benjamin Pasero

introduce and use extfs.realpath

上级 fda3ed38
......@@ -374,13 +374,13 @@ export function writeFileAndFlush(path: string, data: string | NodeBuffer, optio
/**
* Copied from: https://github.com/Microsoft/vscode-node-debug/blob/master/src/node/pathUtilities.ts#L83
*
* Given an absolute, normalized, and existing file path 'realpath' returns the exact path that the file has on disk.
* Given an absolute, normalized, and existing file path 'realcase' returns the exact path that the file has on disk.
* On a case insensitive file system, the returned path might differ from the original path by character casing.
* On a case sensitive file system, the returned path will always be identical to the original path.
* In case of errors, null is returned. But you cannot use this function to verify that a path exists.
* realpathSync does not handle '..' or '.' path segments and it does not take the locale into account.
* realcaseSync does not handle '..' or '.' path segments and it does not take the locale into account.
*/
export function realpathSync(path: string): string {
export function realcaseSync(path: string): string {
const dir = paths.dirname(path);
if (path === dir) { // end recursion
return path;
......@@ -392,7 +392,7 @@ export function realpathSync(path: string): string {
const found = entries.filter(e => e.toLowerCase() === name); // use a case insensitive search
if (found.length === 1) {
// on a case sensitive filesystem we cannot determine here, whether the file exists or not, hence we need the 'file exists' precondition
const prefix = realpathSync(dir); // recurse
const prefix = realcaseSync(dir); // recurse
if (prefix) {
return paths.join(prefix, found[0]);
}
......@@ -400,7 +400,7 @@ export function realpathSync(path: string): string {
// must be a case sensitive $filesystem
const ix = found.indexOf(name);
if (ix >= 0) { // case sensitive
const prefix = realpathSync(dir); // recurse
const prefix = realcaseSync(dir); // recurse
if (prefix) {
return paths.join(prefix, found[ix]);
}
......@@ -411,4 +411,44 @@ export function realpathSync(path: string): string {
}
return null;
}
export function realpathSync(path: string): string {
try {
return fs.realpathSync(path);
} catch (error) {
// We hit an error calling fs.realpathSync(). Since fs.realpathSync() is doing some path normalization
// we now do a similar normalization and then try again if we can access the path with read
// permissions at least. If that succeeds, we return that path.
// fs.realpath() is resolving symlinks and that can fail in certain cases. The workaround is
// to not resolve links but to simply see if the path is read accessible or not.
const normalizedPath = normalizePath(path);
fs.accessSync(normalizedPath, fs.constants.R_OK); // throws in case of an error
return normalizedPath;
}
}
export function realpath(path: string, callback: (error: Error, realpath: string) => void): void {
return fs.realpath(path, (error, realpath) => {
if (!error) {
return callback(null, realpath);
}
// We hit an error calling fs.realpath(). Since fs.realpath() is doing some path normalization
// we now do a similar normalization and then try again if we can access the path with read
// permissions at least. If that succeeds, we return that path.
// fs.realpath() is resolving symlinks and that can fail in certain cases. The workaround is
// to not resolve links but to simply see if the path is read accessible or not.
const normalizedPath = normalizePath(path);
return fs.access(normalizedPath, fs.constants.R_OK, error => {
return callback(error, normalizedPath);
});
});
}
function normalizePath(path: string): string {
return strings.rtrim(paths.normalize(path), paths.sep);
}
\ No newline at end of file
......@@ -72,7 +72,7 @@ export function rimraf(path: string): TPromise<void> {
}
export function realpath(path: string): TPromise<string> {
return nfcall(fs.realpath, path, null);
return nfcall(extfs.realpath, path);
}
export function stat(path: string): TPromise<fs.Stats> {
......
......@@ -203,7 +203,7 @@ suite('Extfs', () => {
});
});
test('realpath', (done) => {
test('realcase', (done) => {
const id = uuid.generateUuid();
const parentDir = path.join(os.tmpdir(), 'vsctests', id);
const newDir = path.join(parentDir, 'extfs', id);
......@@ -213,7 +213,7 @@ suite('Extfs', () => {
// assume case insensitive file system
if (process.platform === 'win32' || process.platform === 'darwin') {
const upper = newDir.toUpperCase();
const real = extfs.realpathSync(upper);
const real = extfs.realcaseSync(upper);
if (real) { // can be null in case of permission errors
assert.notEqual(real, upper);
......@@ -224,11 +224,45 @@ suite('Extfs', () => {
// linux, unix, etc. -> assume case sensitive file system
else {
const real = extfs.realpathSync(newDir);
const real = extfs.realcaseSync(newDir);
assert.equal(real, newDir);
}
extfs.del(parentDir, os.tmpdir(), () => { }, done);
});
});
test('realpath', (done) => {
const id = uuid.generateUuid();
const parentDir = path.join(os.tmpdir(), 'vsctests', id);
const newDir = path.join(parentDir, 'extfs', id);
extfs.mkdirp(newDir, 493, (error) => {
extfs.realpath(newDir, (error, realpath) => {
assert.ok(realpath);
assert.ok(!error);
extfs.del(parentDir, os.tmpdir(), () => { }, done);
});
});
});
test('realpathSync', (done) => {
const id = uuid.generateUuid();
const parentDir = path.join(os.tmpdir(), 'vsctests', id);
const newDir = path.join(parentDir, 'extfs', id);
extfs.mkdirp(newDir, 493, (error) => {
let realpath: string;
try {
realpath = extfs.realpathSync(newDir);
} catch (error) {
assert.ok(!error);
}
assert.ok(realpath);
extfs.del(parentDir, os.tmpdir(), () => { }, done);
});
});
});
\ No newline at end of file
......@@ -5,7 +5,6 @@
'use strict';
import * as fs from 'original-fs';
import * as path from 'path';
import * as arrays from 'vs/base/common/arrays';
import * as strings from 'vs/base/common/strings';
......@@ -13,6 +12,7 @@ import * as paths from 'vs/base/common/paths';
import * as platform from 'vs/base/common/platform';
import * as types from 'vs/base/common/types';
import { ParsedArgs } from 'vs/platform/environment/common/environment';
import { realpathSync } from "vs/base/node/extfs";
export function validatePaths(args: ParsedArgs): ParsedArgs {
......@@ -43,7 +43,7 @@ function doValidatePaths(args: string[], gotoLineMode?: boolean): string[] {
let realPath: string;
try {
realPath = fs.realpathSync(pathCandidate);
realPath = realpathSync(pathCandidate);
} catch (error) {
// in case of an error, assume the user wants to create this file
// if the path is relative, we join it to the cwd
......
......@@ -15,7 +15,7 @@ import { TPromise } from 'vs/base/common/winjs.base';
import { FileChangeType } from 'vs/platform/files/common/files';
import { ThrottledDelayer } from 'vs/base/common/async';
import strings = require('vs/base/common/strings');
import { realpathSync } from 'vs/base/node/extfs';
import { realcaseSync } from 'vs/base/node/extfs';
import { isMacintosh } from 'vs/base/common/platform';
import watcher = require('vs/workbench/services/files/node/watcher/common');
import { IWatcherRequest, IWatcherService } from './watcher';
......@@ -43,7 +43,7 @@ export class ChokidarWatcherService implements IWatcherService {
// so we have to find the real casing of the path and do some path massaging to fix this
// see https://github.com/paulmillr/chokidar/issues/418
const originalBasePath = request.basePath;
const realBasePath = isMacintosh ? (realpathSync(originalBasePath) || originalBasePath) : originalBasePath;
const realBasePath = isMacintosh ? (realcaseSync(originalBasePath) || originalBasePath) : originalBasePath;
const realBasePathLength = realBasePath.length;
const realBasePathDiffers = (originalBasePath !== realBasePath);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册