wincmd/scripts/ntfs_admin_smoke.ps1

178 lines
4.6 KiB
PowerShell
Raw Permalink Normal View History

param(
[switch]$Elevated,
[string]$ResultFile
)
$ErrorActionPreference = 'Stop'
$repo = [System.IO.Path]::GetFullPath((Join-Path $PSScriptRoot '..'))
function Test-IsAdministrator {
$identity = [Security.Principal.WindowsIdentity]::GetCurrent()
$principal = New-Object Security.Principal.WindowsPrincipal($identity)
return $principal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)
}
function New-SmokeSource([string]$Kind) {
switch ($Kind) {
'mft' {
@'
package main
import (
"fmt"
"io"
"b612.me/wincmd/ntfs/mft"
)
func main() {
r, n, err := mft.GetMFTFileReader(`C:\`)
if err != nil {
panic(err)
}
defer r.Close()
buf := make([]byte, 1024)
got, err := io.ReadFull(r, buf)
if err != nil && err != io.ErrUnexpectedEOF {
panic(err)
}
fmt.Printf("mft_length=%d\n", n)
fmt.Printf("mft_first_read=%d\n", got)
fmt.Printf("mft_sig=%x\n", buf[:4])
}
'@
}
'usn' {
@'
package main
import (
"fmt"
"os"
"path/filepath"
"syscall"
"b612.me/wincmd/ntfs/usn"
"b612.me/win32api"
)
func main() {
dir, err := os.MkdirTemp("", "wincmd-usn-admin-")
if err != nil { panic(err) }
defer os.RemoveAll(dir)
path := filepath.Join(dir, "admin-usn.txt")
if err := os.WriteFile(path, []byte("admin smoke"), 0600); err != nil { panic(err) }
f, err := os.Open(path)
if err != nil { panic(err) }
defer f.Close()
var info syscall.ByHandleFileInformation
if err := syscall.GetFileInformationByHandle(syscall.Handle(f.Fd()), &info); err != nil { panic(err) }
vol := filepath.VolumeName(path) + `\`
vh, err := usn.CreateFile(`\\.\`+vol[:len(vol)-1], syscall.O_RDONLY, win32api.FILE_ATTRIBUTE_NORMAL)
if err != nil { panic(err) }
defer syscall.Close(vh)
id := win32api.DWORDLONG(uint64(info.FileIndexHigh)<<32 | uint64(info.FileIndexLow))
fh, err := usn.OpenFileByIdWithfd(vh, id, syscall.O_RDONLY, win32api.FILE_ATTRIBUTE_NORMAL)
if err != nil { panic(err) }
defer syscall.Close(fh)
var info2 syscall.ByHandleFileInformation
if err := syscall.GetFileInformationByHandle(fh, &info2); err != nil { panic(err) }
fmt.Printf("usn_id_ok=true\n")
fmt.Printf("usn_idx_hi=%d\n", info2.FileIndexHigh)
fmt.Printf("usn_idx_lo=%d\n", info2.FileIndexLow)
}
'@
}
default {
throw "unknown smoke source kind: $Kind"
}
}
}
function Invoke-GoSmoke([string]$Kind, [System.Collections.Generic.List[string]]$Lines) {
$tmpGo = Join-Path $env:TEMP ("wincmd_ntfs_{0}_smoke.go" -f $Kind)
try {
Set-Content -Path $tmpGo -Value (New-SmokeSource $Kind) -Encoding utf8
$output = & go run $tmpGo 2>&1 | Out-String
$Lines.Add(("{0}_smoke_ok=true" -f $Kind))
foreach ($line in ($output -split "`r?`n")) {
if ($line -ne '') {
$Lines.Add($line)
}
}
} catch {
$Lines.Add(("{0}_smoke_ok=false" -f $Kind))
$Lines.Add(("{0}_smoke_err={1}" -f $Kind, $_.Exception.Message))
throw
} finally {
Remove-Item $tmpGo -Force -ErrorAction SilentlyContinue
}
}
function Write-Result([System.Collections.Generic.List[string]]$Lines, [string]$ResultFilePath) {
if ($ResultFilePath) {
Set-Content -Path $ResultFilePath -Value $Lines -Encoding utf8
} else {
foreach ($line in $Lines) {
Write-Output $line
}
}
}
if (-not $Elevated -and -not (Test-IsAdministrator)) {
if (-not $ResultFile) {
$ResultFile = Join-Path $env:TEMP 'wincmd_ntfs_admin_smoke_result.txt'
}
Remove-Item $ResultFile -Force -ErrorAction SilentlyContinue
$process = Start-Process pwsh.exe -Verb RunAs -ArgumentList '-NoProfile','-ExecutionPolicy','Bypass','-File',$PSCommandPath,'-Elevated','-ResultFile',$ResultFile -PassThru
$process.WaitForExit()
if (Test-Path $ResultFile) {
Get-Content $ResultFile -Encoding utf8
Remove-Item $ResultFile -Force -ErrorAction SilentlyContinue
} else {
Write-Output 'result_file_missing'
}
exit $process.ExitCode
}
Set-Location $repo
$lines = New-Object 'System.Collections.Generic.List[string]'
$lines.Add('admin=' + (Test-IsAdministrator))
$failed = $false
try {
& go test ./ntfs/mft -run '^$' *> $null
$lines.Add('mft_pkg_ok=true')
} catch {
$failed = $true
$lines.Add('mft_pkg_ok=false')
$lines.Add('mft_pkg_err=' + $_.Exception.Message)
}
try {
Invoke-GoSmoke -Kind 'mft' -Lines $lines
} catch {
$failed = $true
}
try {
Invoke-GoSmoke -Kind 'usn' -Lines $lines
} catch {
$failed = $true
}
Write-Result -Lines $lines -ResultFilePath $ResultFile
if ($failed) {
exit 1
}