fix(windows): clear readonly when no other file attributes remain

This commit is contained in:
morluto committed 2026-10-15 08:49:11 +08:00
1 parent 930dd5357f
commit c553d1138e
2 files changed
+7 -3

No files matched your search

+3
View File
@@ -473,6 +473,9 @@ static void dispose(HANDLE handle, const std::wstring& path) {
require(GetFileInformationByHandleEx(handle, FileBasicInfo, &info, sizeof(info)), "Read cleanup attributes failed", path);
if ((info.FileAttributes & FILE_ATTRIBUTE_READONLY) != 0) {
info.FileAttributes &= ~FILE_ATTRIBUTE_READONLY;
// Zero means "leave attributes unchanged" to FileBasicInfo. A file whose
// sole attribute was READONLY needs NORMAL to actually clear that marker.
if (info.FileAttributes == 0) info.FileAttributes = FILE_ATTRIBUTE_NORMAL;
require(SetFileInformationByHandle(handle, FileBasicInfo, &info, sizeof(info)), "Clear owned readonly attribute failed", path);
}
FILE_DISPOSITION_INFO deletion{TRUE};
+4 -3
View File
@@ -588,7 +588,7 @@ process.stdout.write(JSON.stringify({executable:basename(process.execPath),abiVe
"-NoProfile",
"-NonInteractive",
"-Command",
"$ErrorActionPreference='Stop'; $items=ConvertFrom-Json -InputObject $env:REA_TEST_READONLY_CHILDREN; @($items | ForEach-Object { [IO.File]::SetAttributes($_,[IO.FileAttributes]([int][IO.File]::GetAttributes($_) -bor 1)); $a=[int][IO.File]::GetAttributes($_); @{readonly=(($a -band 1) -ne 0); directory=(($a -band 16) -ne 0)} }) | ConvertTo-Json -Compress",
"$ErrorActionPreference='Stop'; $items=ConvertFrom-Json -InputObject $env:REA_TEST_READONLY_CHILDREN; @($items | ForEach-Object { $current=[int][IO.File]::GetAttributes($_); $next=if(($current -band 16) -ne 0){$current -bor 1}else{1}; [IO.File]::SetAttributes($_,[IO.FileAttributes]$next); $a=[int][IO.File]::GetAttributes($_); @{readonly=(($a -band 1) -ne 0); directory=(($a -band 16) -ne 0); onlyReadonly=($a -eq 1)} }) | ConvertTo-Json -Compress",
],
{
encoding: "utf8",
@@ -604,8 +604,8 @@ process.stdout.write(JSON.stringify({executable:basename(process.execPath),abiVe
),
);
assert.deepEqual(readonlyChildren, [
{ readonly: true, directory: true },
{ readonly: true, directory: false },
{ readonly: true, directory: true, onlyReadonly: false },
{ readonly: true, directory: false, onlyReadonly: true },
]);
} catch (failure) {
runtimeVerificationErrors.push(failure);
@@ -626,6 +626,7 @@ process.stdout.write(JSON.stringify({executable:basename(process.execPath),abiVe
assert.equal(await readFile(sentinel, "utf8"), "preserve");
report.controls.cleanupDoesNotTraverseJunctions = true;
report.controls.readonlyRootAndChildrenRemoved = true;
report.controls.readonlyFileWithoutArchiveAttributeRemoved = true;
const fixture = join(workspace, "tree.mjs");
await writeFile(
fixture,