-
Notifications
You must be signed in to change notification settings - Fork 50
/
_ChecksumFiles.ps1
109 lines (93 loc) · 3.26 KB
/
_ChecksumFiles.ps1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
param (
[string] $root,
[string] $out,
[Switch] $addContentChecksum
)
function Usage
{
Write-Host 'usage: _ChecksumFiles.ps1 -root <folder> [-out <filename>] [-addContentChecksum]'
Exit 1
}
if([String]::IsNullOrWhiteSpace($root)) {
Usage
}
if(-Not [IO.Directory]::Exists($root)) {
Write-Host ([String]::Format('{0} does not exist', $root))
Usage
}
[string] $outFileName;
if(-Not [String]::IsNullOrWhiteSpace($out)) {
$outFileName = $out
$folder = [IO.Path]::GetDirectoryName([IO.Path]::GetFullPath($outFileName))
if(-Not [IO.Directory]::Exists($folder)) {
[IO.Directory]::CreateDirectory($folder)
}
}
[IO.TextWriter] $outWriter = if($outFileName -eq $null) { [Console]::Out } else { [IO.StreamWriter]::new($outFileName, $false)}
$checksummer = [Crc64]::new()
$folder = $root
foreach($fileName in [IO.Directory]::GetFiles($folder, '*.*', [IO.SearchOption]::AllDirectories)) {
$relativePath = $fileName.Substring($folder.Length)
$content = [IO.File]::ReadAllBytes($fileName)
$checksum = $checksummer.ComputeChecksumString($content, 0, $content.Length)
$outWriter.WriteLine([String]::Format(
'{0} {1,9} {2}',
$checksum,
[IO.FileInfo]::new($fileName).Length,
$relativePath
))
}
if($outFileName -ne $null) {
$outWriter.Dispose()
}
if($addContentChecksum.IsPresent -and $outFileName -ne $null) {
$checksums = [IO.File]::ReadAllLines($outFileName)
$checksumBytes = [Text.Encoding]::UTF8.GetBytes([String]::Concat($checksums))
$checksum = $checksummer.ComputeChecksumString($checksumBytes, 0, $checksumBytes.Length)
$contentLines = [string[]]::new($checksums.Length + 1)
$contentLines[0] = [String]::Format(
'{0} {1,9} {2}',
$checksum,
[System.Linq.Enumerable]::Sum($checksums, [Func[string, int]]{ param($r) $r.Length }),
'\**CONTENT CHECKSUM**'
)
for($i = 0;$i -lt $checksums.Length;++$i) {
$contentLines[$i + 1] = $checksums[$i]
}
[IO.File]::WriteAllLines($outFileName, $contentLines)
}
Exit 0
class Crc64
{
[uint64] hidden $_Polynomial
[uint64[]] hidden $_LookupTable = [uint64[]]::new(256)
Crc64()
{
$this._Polynomial = [uint64]"0xC96C5795D7870F42"
for($i = 0;$i -lt 256;++$i) {
[uint64]$crc = $i
for($j = 8;$j -gt 0;--$j) {
if(($crc -band 1) -eq 1) {
$crc = [uint64](($crc -shr 1) -bxor $this._Polynomial)
} else {
$crc = $crc -shr 1
}
}
$this._LookupTable[$i] = $crc
}
}
[string] ComputeChecksumString([byte[]] $bytes, [int] $offset, [int] $length)
{
$crc = $this.ComputeChecksum($bytes, $offset, $length)
return [String]::Format('{0:X16}', $crc)
}
[uint64] ComputeChecksum([byte[]] $bytes, [int] $offset, [int] $length)
{
[uint64] $crc = [uint64]"0xFFFFFFFFFFFFFFFF"
for($i = $offset;$i -lt $offset + $length;++$i) {
$index = [byte](($crc -band 0xff) -bxor $bytes[$i])
$crc = [uint64](($crc -shr 8) -bxor $this._LookupTable[$index])
}
return $crc
}
}