Windows: correctly resolve drive-relative paths
This commit is contained in:
parent
cbcf4fe768
commit
86fba381fd
28
lib/path.js
28
lib/path.js
@ -86,7 +86,18 @@ if (isWindows) {
|
|||||||
resolvedAbsolute = false;
|
resolvedAbsolute = false;
|
||||||
|
|
||||||
for (var i = arguments.length - 1; i >= -1; i--) {
|
for (var i = arguments.length - 1; i >= -1; i--) {
|
||||||
var path = (i >= 0) ? arguments[i] : process.cwd();
|
var path;
|
||||||
|
if (i >= 0) {
|
||||||
|
path = arguments[i];
|
||||||
|
} else if (!resolvedDevice) {
|
||||||
|
path = process.cwd();
|
||||||
|
} else {
|
||||||
|
// Windows has the concept of drive-specific current working
|
||||||
|
// directories. If we've resolved a drive letter but not yet an
|
||||||
|
// absolute path, get cwd for that drive. We're sure the device is not
|
||||||
|
// an unc path at this points, because unc paths are always absolute.
|
||||||
|
path = process._cwdForDrive(resolvedDevice[0]);
|
||||||
|
}
|
||||||
|
|
||||||
// Skip empty and invalid entries
|
// Skip empty and invalid entries
|
||||||
if (typeof path !== 'string' || !path) {
|
if (typeof path !== 'string' || !path) {
|
||||||
@ -119,21 +130,6 @@ if (isWindows) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!resolvedAbsolute && resolvedDevice) {
|
|
||||||
// If we still don't have an absolute path,
|
|
||||||
// prepend the current path for the device found.
|
|
||||||
|
|
||||||
// TODO
|
|
||||||
// Windows stores the current directories for 'other' drives
|
|
||||||
// as hidden environment variables like =C:=c:\windows (literally)
|
|
||||||
// var deviceCwd = os.getCwdForDrive(resolvedDevice);
|
|
||||||
var deviceCwd = '';
|
|
||||||
|
|
||||||
// If there is no cwd set for the drive, it is at root
|
|
||||||
resolvedTail = deviceCwd + '\\' + resolvedTail;
|
|
||||||
resolvedAbsolute = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Replace slashes (in UNC share name) by backslashes
|
// Replace slashes (in UNC share name) by backslashes
|
||||||
resolvedDevice = resolvedDevice.replace(/\//g, '\\');
|
resolvedDevice = resolvedDevice.replace(/\//g, '\\');
|
||||||
|
|
||||||
|
74
src/node.cc
74
src/node.cc
@ -1178,6 +1178,76 @@ static Handle<Value> Cwd(const Arguments& args) {
|
|||||||
return scope.Close(cwd);
|
return scope.Close(cwd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
static Handle<Value> CwdForDrive(const Arguments& args) {
|
||||||
|
HandleScope scope;
|
||||||
|
|
||||||
|
if (args.Length() < 1) {
|
||||||
|
Local<Value> exception = Exception::Error(
|
||||||
|
String::New("process._cwdForDrive takes exactly 1 argument."));
|
||||||
|
return ThrowException(exception);
|
||||||
|
}
|
||||||
|
|
||||||
|
Local<String> driveLetter = args[0]->ToString();
|
||||||
|
if (driveLetter->Length() != 1) {
|
||||||
|
Local<Value> exception = Exception::Error(
|
||||||
|
String::New("Drive name should be 1 character."));
|
||||||
|
return ThrowException(exception);
|
||||||
|
}
|
||||||
|
|
||||||
|
char drive;
|
||||||
|
|
||||||
|
driveLetter->WriteAscii(&drive, 0, 1, 0);
|
||||||
|
if (drive >= 'a' && drive <= 'z') {
|
||||||
|
// Convert to uppercase
|
||||||
|
drive += 'A' - 'a';
|
||||||
|
} else if (drive < 'A' || drive > 'Z') {
|
||||||
|
// Not a letter
|
||||||
|
Local<Value> exception = Exception::Error(
|
||||||
|
String::New("Drive name should be a letter."));
|
||||||
|
return ThrowException(exception);
|
||||||
|
}
|
||||||
|
|
||||||
|
WCHAR env_key[] = L"=X:";
|
||||||
|
env_key[1] = (WCHAR) drive;
|
||||||
|
|
||||||
|
DWORD len = GetEnvironmentVariableW(env_key, NULL, 0);
|
||||||
|
if (len == 0 && GetLastError() == ERROR_ENVVAR_NOT_FOUND) {
|
||||||
|
// There is no current directory for that drive. Default to drive + ":\".
|
||||||
|
Local<String> cwd = String::Concat(String::New(&drive, 1),
|
||||||
|
String::New(":\\"));
|
||||||
|
return scope.Close(cwd);
|
||||||
|
|
||||||
|
} else if (len == 0) {
|
||||||
|
// Error
|
||||||
|
Local<Value> exception = Exception::Error(
|
||||||
|
String::New(winapi_strerror(GetLastError())));
|
||||||
|
return ThrowException(exception);
|
||||||
|
}
|
||||||
|
|
||||||
|
WCHAR* buffer = new WCHAR[len];
|
||||||
|
if (buffer == NULL) {
|
||||||
|
Local<Value> exception = Exception::Error(
|
||||||
|
String::New("Out of memory."));
|
||||||
|
return ThrowException(exception);
|
||||||
|
}
|
||||||
|
|
||||||
|
DWORD len2 = GetEnvironmentVariableW(env_key, buffer, len);
|
||||||
|
if (len2 == 0 || len2 >= len) {
|
||||||
|
// Error
|
||||||
|
delete[] buffer;
|
||||||
|
Local<Value> exception = Exception::Error(
|
||||||
|
String::New(winapi_strerror(GetLastError())));
|
||||||
|
return ThrowException(exception);
|
||||||
|
}
|
||||||
|
|
||||||
|
Local<String> cwd = String::New(reinterpret_cast<uint16_t*>(buffer), len2);
|
||||||
|
delete[] buffer;
|
||||||
|
return scope.Close(cwd);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
static Handle<Value> Umask(const Arguments& args) {
|
static Handle<Value> Umask(const Arguments& args) {
|
||||||
HandleScope scope;
|
HandleScope scope;
|
||||||
unsigned int old;
|
unsigned int old;
|
||||||
@ -1931,6 +2001,10 @@ Handle<Object> SetupProcessObject(int argc, char *argv[]) {
|
|||||||
NODE_SET_METHOD(process, "chdir", Chdir);
|
NODE_SET_METHOD(process, "chdir", Chdir);
|
||||||
NODE_SET_METHOD(process, "cwd", Cwd);
|
NODE_SET_METHOD(process, "cwd", Cwd);
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
NODE_SET_METHOD(process, "_cwdForDrive", CwdForDrive);
|
||||||
|
#endif
|
||||||
|
|
||||||
NODE_SET_METHOD(process, "umask", Umask);
|
NODE_SET_METHOD(process, "umask", Umask);
|
||||||
|
|
||||||
#ifdef __POSIX__
|
#ifdef __POSIX__
|
||||||
|
Loading…
x
Reference in New Issue
Block a user