resolvedAbsolute = false;
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
if (typeof path !== 'string' || !path) {
}
}
- 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
resolvedDevice = resolvedDevice.replace(/\//g, '\\');
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) {
HandleScope scope;
unsigned int old;
NODE_SET_METHOD(process, "chdir", Chdir);
NODE_SET_METHOD(process, "cwd", Cwd);
+#ifdef _WIN32
+ NODE_SET_METHOD(process, "_cwdForDrive", CwdForDrive);
+#endif
+
NODE_SET_METHOD(process, "umask", Umask);
#ifdef __POSIX__