Skip to content
This repository was archived by the owner on Apr 8, 2020. It is now read-only.

On Windows, patch Node's lstat to work around permissions error. Fixes #1101 #1102

Merged
merged 2 commits into from
Jul 11, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion appveyor.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ install:
- ps: Install-Product node 6.9.2 x64
# .NET Core SDK binaries
# Download .NET Core 2.0 Preview 3 SDK and add to PATH
- ps: $urlCurrent = "https://dotnetcli.azureedge.net/dotnet/Sdk/2.0.0-preview3-006670/dotnet-sdk-2.0.0-preview3-006670-win-x64.zip"
- ps: $urlCurrent = "https://dotnetcli.azureedge.net/dotnet/Sdk/2.0.0-preview3-006729/dotnet-sdk-2.0.0-preview3-006729-win-x64.zip"
- ps: $env:DOTNET_INSTALL_DIR = "$pwd\.dotnetsdk"
- ps: mkdir $env:DOTNET_INSTALL_DIR -Force | Out-Null
- ps: $tempFileCurrent = [System.IO.Path]::Combine([System.IO.Path]::GetTempPath(), [System.IO.Path]::GetRandomFileName())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,10 +55,11 @@
// Limit dependencies to core Node modules. This means the code in this file has to be very low-level and unattractive,
// but simplifies things for the consumer of this module.
__webpack_require__(2);
var http = __webpack_require__(3);
var path = __webpack_require__(4);
var ArgsUtil_1 = __webpack_require__(5);
var ExitWhenParentExits_1 = __webpack_require__(6);
__webpack_require__(4);
var http = __webpack_require__(5);
var path = __webpack_require__(3);
var ArgsUtil_1 = __webpack_require__(6);
var ExitWhenParentExits_1 = __webpack_require__(7);
// Webpack doesn't support dynamic requires for files not present at compile time, so grab a direct
// reference to Node's runtime 'require' function.
var dynamicRequire = eval('require');
Expand Down Expand Up @@ -142,6 +143,64 @@

/***/ },
/* 2 */
/***/ function(module, exports, __webpack_require__) {

"use strict";
var path = __webpack_require__(3);
var startsWith = function (str, prefix) { return str.substring(0, prefix.length) === prefix; };
var appRootDir = process.cwd();
function patchedLStat(pathToStatLong) {
try {
// If the lstat completes without errors, we don't modify its behavior at all
return origLStat.apply(this, arguments);
}
catch (ex) {
var shouldOverrideError = startsWith(ex.message, 'EPERM') // It's a permissions error
&& typeof appRootDirLong === 'string'
&& startsWith(appRootDirLong, pathToStatLong) // ... for an ancestor directory
&& ex.stack.indexOf('Object.realpathSync ') >= 0; // ... during symlink resolution
if (shouldOverrideError) {
// Fake the result to give the same result as an 'lstat' on the app root dir.
// This stops Node failing to load modules just because it doesn't know whether
// ancestor directories are symlinks or not. If there's a genuine file
// permissions issue, it will still surface later when Node actually
// tries to read the file.
return origLStat.call(this, appRootDir);
}
else {
// In any other case, preserve the original error
throw ex;
}
}
}
;
// It's only necessary to apply this workaround on Windows
var appRootDirLong = null;
var origLStat = null;
if (/^win/.test(process.platform)) {
try {
// Get the app's root dir in Node's internal "long" format (e.g., \\?\C:\dir\subdir)
appRootDirLong = path._makeLong(appRootDir);
// Actually apply the patch, being as defensive as possible
var bindingFs = process.binding('fs');
origLStat = bindingFs.lstat;
if (typeof origLStat === 'function') {
bindingFs.lstat = patchedLStat;
}
}
catch (ex) {
}
}


/***/ },
/* 3 */
/***/ function(module, exports) {

module.exports = require("path");

/***/ },
/* 4 */
/***/ function(module, exports) {

// When Node writes to stdout/strerr, we capture that and convert the lines into calls on the
Expand Down Expand Up @@ -182,19 +241,13 @@


/***/ },
/* 3 */
/* 5 */
/***/ function(module, exports) {

module.exports = require("http");

/***/ },
/* 4 */
/***/ function(module, exports) {

module.exports = require("path");

/***/ },
/* 5 */
/* 6 */
/***/ function(module, exports) {

"use strict";
Expand All @@ -220,7 +273,7 @@


/***/ },
/* 6 */
/* 7 */
/***/ function(module, exports) {

/*
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// Limit dependencies to core Node modules. This means the code in this file has to be very low-level and unattractive,
// but simplifies things for the consumer of this module.
import './Util/PatchModuleResolutionLStat';
import './Util/OverrideStdOutputs';
import * as http from 'http';
import * as path from 'path';
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import * as path from 'path';
const startsWith = (str: string, prefix: string) => str.substring(0, prefix.length) === prefix;
const appRootDir = process.cwd();

function patchedLStat(pathToStatLong: string) {
try {
// If the lstat completes without errors, we don't modify its behavior at all
return origLStat.apply(this, arguments);
} catch(ex) {
const shouldOverrideError =
startsWith(ex.message, 'EPERM') // It's a permissions error
&& typeof appRootDirLong === 'string'
&& startsWith(appRootDirLong, pathToStatLong) // ... for an ancestor directory
&& ex.stack.indexOf('Object.realpathSync ') >= 0; // ... during symlink resolution

if (shouldOverrideError) {
// Fake the result to give the same result as an 'lstat' on the app root dir.
// This stops Node failing to load modules just because it doesn't know whether
// ancestor directories are symlinks or not. If there's a genuine file
// permissions issue, it will still surface later when Node actually
// tries to read the file.
return origLStat.call(this, appRootDir);
} else {
// In any other case, preserve the original error
throw ex;
}
}
};

// It's only necessary to apply this workaround on Windows
let appRootDirLong: string = null;
let origLStat: Function = null;
if (/^win/.test(process.platform)) {
try {
// Get the app's root dir in Node's internal "long" format (e.g., \\?\C:\dir\subdir)
appRootDirLong = (path as any)._makeLong(appRootDir);

// Actually apply the patch, being as defensive as possible
const bindingFs = (process as any).binding('fs');
origLStat = bindingFs.lstat;
if (typeof origLStat === 'function') {
bindingFs.lstat = patchedLStat;
}
} catch(ex) {
// If some future version of Node throws (e.g., to prevent use of process.binding()),
// don't apply the patch, but still let the application run.
}
}
12 changes: 6 additions & 6 deletions templates/AngularSpa/AngularSpa.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,17 @@
</PropertyGroup>

<ItemGroup Condition="'$(TargetFrameworkOverride)' == ''">
<PackageReference Include="Microsoft.AspNetCore.All" Version="2.0.0-preview3-26096" />
<PackageReference Include="Microsoft.AspNetCore.All" Version="2.0.0-rtm-26190" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFrameworkOverride)' != ''">
<PackageReference Include="Microsoft.AspNetCore" Version="2.0.0-preview3-26096" />
<PackageReference Include="Microsoft.AspNetCore.Mvc" Version="2.0.0-preview3-26096" />
<PackageReference Include="Microsoft.AspNetCore.SpaServices" Version="2.0.0-preview3-26096" />
<PackageReference Include="Microsoft.AspNetCore.StaticFiles" Version="2.0.0-preview3-26096" />
<PackageReference Include="Microsoft.AspNetCore" Version="2.0.0-rtm-26190" />
<PackageReference Include="Microsoft.AspNetCore.Mvc" Version="2.0.0-rtm-26190" />
<PackageReference Include="Microsoft.AspNetCore.SpaServices" Version="2.0.0-rtm-26190" />
<PackageReference Include="Microsoft.AspNetCore.StaticFiles" Version="2.0.0-rtm-26190" />
</ItemGroup>

<ItemGroup>
<DotNetCliToolReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Tools" Version="2.0.0-preview3-26096" />
<DotNetCliToolReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Tools" Version="2.0.0-rtm-26190" />
</ItemGroup>

<ItemGroup>
Expand Down
10 changes: 5 additions & 5 deletions templates/AureliaSpa/AureliaSpa.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,13 @@
</PropertyGroup>

<ItemGroup Condition="'$(TargetFrameworkOverride)' == ''">
<PackageReference Include="Microsoft.AspNetCore.All" Version="2.0.0-preview3-26096" />
<PackageReference Include="Microsoft.AspNetCore.All" Version="2.0.0-rtm-26190" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFrameworkOverride)' != ''">
<PackageReference Include="Microsoft.AspNetCore" Version="2.0.0-preview3-26096" />
<PackageReference Include="Microsoft.AspNetCore.Mvc" Version="2.0.0-preview3-26096" />
<PackageReference Include="Microsoft.AspNetCore.SpaServices" Version="2.0.0-preview3-26096" />
<PackageReference Include="Microsoft.AspNetCore.StaticFiles" Version="2.0.0-preview3-26096" />
<PackageReference Include="Microsoft.AspNetCore" Version="2.0.0-rtm-26190" />
<PackageReference Include="Microsoft.AspNetCore.Mvc" Version="2.0.0-rtm-26190" />
<PackageReference Include="Microsoft.AspNetCore.SpaServices" Version="2.0.0-rtm-26190" />
<PackageReference Include="Microsoft.AspNetCore.StaticFiles" Version="2.0.0-rtm-26190" />
</ItemGroup>

<ItemGroup>
Expand Down
10 changes: 5 additions & 5 deletions templates/KnockoutSpa/KnockoutSpa.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,13 @@
</PropertyGroup>

<ItemGroup Condition="'$(TargetFrameworkOverride)' == ''">
<PackageReference Include="Microsoft.AspNetCore.All" Version="2.0.0-preview3-26096" />
<PackageReference Include="Microsoft.AspNetCore.All" Version="2.0.0-rtm-26190" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFrameworkOverride)' != ''">
<PackageReference Include="Microsoft.AspNetCore" Version="2.0.0-preview3-26096" />
<PackageReference Include="Microsoft.AspNetCore.Mvc" Version="2.0.0-preview3-26096" />
<PackageReference Include="Microsoft.AspNetCore.SpaServices" Version="2.0.0-preview3-26096" />
<PackageReference Include="Microsoft.AspNetCore.StaticFiles" Version="2.0.0-preview3-26096" />
<PackageReference Include="Microsoft.AspNetCore" Version="2.0.0-rtm-26190" />
<PackageReference Include="Microsoft.AspNetCore.Mvc" Version="2.0.0-rtm-26190" />
<PackageReference Include="Microsoft.AspNetCore.SpaServices" Version="2.0.0-rtm-26190" />
<PackageReference Include="Microsoft.AspNetCore.StaticFiles" Version="2.0.0-rtm-26190" />
</ItemGroup>

<ItemGroup>
Expand Down
10 changes: 5 additions & 5 deletions templates/ReactReduxSpa/ReactReduxSpa.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,13 @@
</PropertyGroup>

<ItemGroup Condition="'$(TargetFrameworkOverride)' == ''">
<PackageReference Include="Microsoft.AspNetCore.All" Version="2.0.0-preview3-26096" />
<PackageReference Include="Microsoft.AspNetCore.All" Version="2.0.0-rtm-26190" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFrameworkOverride)' != ''">
<PackageReference Include="Microsoft.AspNetCore" Version="2.0.0-preview3-26096" />
<PackageReference Include="Microsoft.AspNetCore.Mvc" Version="2.0.0-preview3-26096" />
<PackageReference Include="Microsoft.AspNetCore.SpaServices" Version="2.0.0-preview3-26096" />
<PackageReference Include="Microsoft.AspNetCore.StaticFiles" Version="2.0.0-preview3-26096" />
<PackageReference Include="Microsoft.AspNetCore" Version="2.0.0-rtm-26190" />
<PackageReference Include="Microsoft.AspNetCore.Mvc" Version="2.0.0-rtm-26190" />
<PackageReference Include="Microsoft.AspNetCore.SpaServices" Version="2.0.0-rtm-26190" />
<PackageReference Include="Microsoft.AspNetCore.StaticFiles" Version="2.0.0-rtm-26190" />
</ItemGroup>

<ItemGroup>
Expand Down
10 changes: 5 additions & 5 deletions templates/ReactSpa/ReactSpa.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,13 @@
</PropertyGroup>

<ItemGroup Condition="'$(TargetFrameworkOverride)' == ''">
<PackageReference Include="Microsoft.AspNetCore.All" Version="2.0.0-preview3-26096" />
<PackageReference Include="Microsoft.AspNetCore.All" Version="2.0.0-rtm-26190" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFrameworkOverride)' != ''">
<PackageReference Include="Microsoft.AspNetCore" Version="2.0.0-preview3-26096" />
<PackageReference Include="Microsoft.AspNetCore.Mvc" Version="2.0.0-preview3-26096" />
<PackageReference Include="Microsoft.AspNetCore.SpaServices" Version="2.0.0-preview3-26096" />
<PackageReference Include="Microsoft.AspNetCore.StaticFiles" Version="2.0.0-preview3-26096" />
<PackageReference Include="Microsoft.AspNetCore" Version="2.0.0-rtm-26190" />
<PackageReference Include="Microsoft.AspNetCore.Mvc" Version="2.0.0-rtm-26190" />
<PackageReference Include="Microsoft.AspNetCore.SpaServices" Version="2.0.0-rtm-26190" />
<PackageReference Include="Microsoft.AspNetCore.StaticFiles" Version="2.0.0-rtm-26190" />
</ItemGroup>

<ItemGroup>
Expand Down
10 changes: 5 additions & 5 deletions templates/VueSpa/VueSpa.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,13 @@
</PropertyGroup>

<ItemGroup Condition="'$(TargetFrameworkOverride)' == ''">
<PackageReference Include="Microsoft.AspNetCore.All" Version="2.0.0-preview3-26096" />
<PackageReference Include="Microsoft.AspNetCore.All" Version="2.0.0-rtm-26190" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFrameworkOverride)' != ''">
<PackageReference Include="Microsoft.AspNetCore" Version="2.0.0-preview3-26096" />
<PackageReference Include="Microsoft.AspNetCore.Mvc" Version="2.0.0-preview3-26096" />
<PackageReference Include="Microsoft.AspNetCore.SpaServices" Version="2.0.0-preview3-26096" />
<PackageReference Include="Microsoft.AspNetCore.StaticFiles" Version="2.0.0-preview3-26096" />
<PackageReference Include="Microsoft.AspNetCore" Version="2.0.0-rtm-26190" />
<PackageReference Include="Microsoft.AspNetCore.Mvc" Version="2.0.0-rtm-26190" />
<PackageReference Include="Microsoft.AspNetCore.SpaServices" Version="2.0.0-rtm-26190" />
<PackageReference Include="Microsoft.AspNetCore.StaticFiles" Version="2.0.0-rtm-26190" />
</ItemGroup>

<ItemGroup>
Expand Down