970 lines
31 KiB
C
970 lines
31 KiB
C
// verify.c
|
|
// Copyright : 2024-11-30 Yutaka Sawada
|
|
// License : The MIT license
|
|
|
|
#ifndef _UNICODE
|
|
#define _UNICODE
|
|
#endif
|
|
#ifndef UNICODE
|
|
#define UNICODE
|
|
#endif
|
|
#ifndef _WIN32_WINNT
|
|
#define _WIN32_WINNT 0x0601 // Windows 7 or later
|
|
#endif
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <windows.h>
|
|
|
|
#include "common.h"
|
|
#include "crc.h"
|
|
#include "verify.h"
|
|
#include "ini.h"
|
|
#include "phmd5.h"
|
|
|
|
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
|
|
|
// CRC-32 を比較する
|
|
// 0 = ファイルが存在して完全である
|
|
// 1 = ファイルが存在しない
|
|
// 2 = ファイルが破損してる
|
|
static int file_crc32_check(
|
|
int num,
|
|
char *ascii_name,
|
|
wchar_t *uni_name,
|
|
wchar_t *file_path,
|
|
unsigned int crc2)
|
|
{
|
|
unsigned char buf[IO_SIZE];
|
|
int len, off, bad_flag;
|
|
unsigned int crc, time_last, meta_data[7];
|
|
__int64 file_size = 0, file_left;
|
|
HANDLE hFile;
|
|
|
|
prog_last = -1;
|
|
time_last = GetTickCount() / UPDATE_TIME; // 時刻の変化時に経過を表示する
|
|
wcscpy(file_path, base_dir);
|
|
// 先頭の「..\」を許可してるので、基準ディレクトリから上に遡る。
|
|
len = base_len - 1;
|
|
off = 0;
|
|
while ((uni_name[off] == '.') && (uni_name[off + 1] == '.') && (uni_name[off + 2] == '\\')){
|
|
off += 3;
|
|
file_path[len] = 0;
|
|
while (file_path[len] != '\\'){
|
|
file_path[len] = 0;
|
|
len--;
|
|
}
|
|
}
|
|
wcscat(file_path, uni_name + off);
|
|
|
|
// 読み込むファイルを開く
|
|
hFile = CreateFile(file_path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
|
|
if (hFile == INVALID_HANDLE_VALUE){
|
|
bad_flag = 1; // 消失は記録しない
|
|
} else {
|
|
bad_flag = check_ini_state(num, meta_data, hFile);
|
|
memcpy(&file_size, meta_data, 8);
|
|
if (bad_flag == -2){ // 記録が無い場合 (属性取得エラーは不明にする)
|
|
file_left = file_size;
|
|
crc = 0xFFFFFFFF; // 初期化
|
|
while (file_left > 0){
|
|
len = IO_SIZE;
|
|
if (file_left < IO_SIZE)
|
|
len = (int)file_left;
|
|
if (!ReadFile(hFile, buf, len, &bad_flag, NULL) || (len != bad_flag))
|
|
break; // 読み取りエラーは必ず破損になる
|
|
file_left -= len;
|
|
// CRC-32 を更新する
|
|
crc = crc_update(crc, buf, len);
|
|
|
|
// 経過表示
|
|
if (GetTickCount() / UPDATE_TIME != time_last){
|
|
if (print_progress_file((int)(((file_size - file_left) * 1000) / file_size), uni_name)){
|
|
CloseHandle(hFile);
|
|
return 2;
|
|
}
|
|
time_last = GetTickCount() / UPDATE_TIME;
|
|
}
|
|
}
|
|
crc ^= 0xFFFFFFFF; // 最終処理
|
|
if ((crc != crc2) || (file_left > 0)){
|
|
bad_flag = 2; // ハッシュ値が異なる、または途中まで
|
|
} else {
|
|
bad_flag = 0; // 完全
|
|
}
|
|
write_ini_state(num, meta_data, bad_flag); // 検査結果を記録する、完全か破損
|
|
}
|
|
CloseHandle(hFile);
|
|
}
|
|
|
|
switch (bad_flag){
|
|
case 0:
|
|
printf("%13I64d Complete : \"%s\"\n", file_size, ascii_name);
|
|
break;
|
|
case 1:
|
|
printf(" 0 Missing : \"%s\"\n", ascii_name);
|
|
bad_flag = 4 | 8;
|
|
break;
|
|
case 2:
|
|
printf("%13I64d Damaged : \"%s\"\n", file_size, ascii_name);
|
|
bad_flag = 4;
|
|
break;
|
|
default: // IOエラー等
|
|
printf(" ? Unknown : \"%s\"\n", ascii_name);
|
|
bad_flag = 4;
|
|
break;
|
|
}
|
|
fflush(stdout);
|
|
return bad_flag;
|
|
}
|
|
|
|
// SFV ファイル
|
|
int verify_sfv(
|
|
char *ascii_buf,
|
|
wchar_t *file_path)
|
|
{
|
|
wchar_t *line_off, uni_buf[MAX_LEN];
|
|
unsigned int err = 0, rv, line_len, name_len, crc, line_num, num, comment;
|
|
|
|
// ファイル数を調べる
|
|
comment = 0;
|
|
num = 0;
|
|
line_num = 1;
|
|
line_off = text_buf;
|
|
while (*line_off != 0){ // 一行ずつ処理する
|
|
line_len = 0;
|
|
while (line_off[line_len] != 0){ // 改行までを一行とする
|
|
if (line_off[line_len] == '\n')
|
|
break;
|
|
if (line_off[line_len] == '\r')
|
|
break;
|
|
line_len++;
|
|
}
|
|
// 行の内容が適正か調べる
|
|
if (line_off[0] == ';'){ // コメント
|
|
if (((comment & 1) == 0) && (line_len > 8) && (line_len < MAX_LEN)){
|
|
// クリエイターの表示がまだなら
|
|
if (wcsncmp(line_off, L"; Generated by ", 15) == 0){ // WIN-SFV32, SFV32nix
|
|
wcsncpy(uni_buf, line_off + 15, line_len - 15);
|
|
uni_buf[line_len - 15] = 0;
|
|
comment |= 1;
|
|
} else if (wcsncmp(line_off, L"; Using ", 8) == 0){
|
|
wcsncpy(uni_buf, line_off + 8, line_len - 8);
|
|
uni_buf[line_len - 8] = 0;
|
|
comment |= 1; // 同一行を二度表示しない
|
|
}
|
|
if (comment & 1){
|
|
uni_buf[COMMENT_LEN - 1] = 0; // 表示する文字数を制限する
|
|
utf16_to_cp(uni_buf, ascii_buf, COMMENT_LEN * 3, cp_output);
|
|
printf("Creator : %s\n", ascii_buf);
|
|
comment |= 4;
|
|
}
|
|
}
|
|
if (((comment & 6) == 0) && (line_len < MAX_LEN)){
|
|
// 最初のコメントの表示がまだなら
|
|
crc = 1;
|
|
while (crc < line_len){
|
|
if (line_off[crc] != ' ')
|
|
break;
|
|
crc++;
|
|
}
|
|
if (crc < line_len){
|
|
wcsncpy(uni_buf, line_off + crc, line_len - crc);
|
|
uni_buf[line_len - crc] = 0;
|
|
uni_buf[COMMENT_LEN - 1] = 0; // 表示する文字数を制限する
|
|
utf16_to_cp(uni_buf, ascii_buf, COMMENT_LEN * 3, cp_output);
|
|
printf("Comment : %s\n", ascii_buf);
|
|
}
|
|
comment |= 2; // 「;」だけの行も認識する
|
|
}
|
|
comment &= ~4; // bit 4 を消す
|
|
} else if ((line_len > 9) && (line_off[line_len - 9] == ' ') // CRC の前がスペース
|
|
&& (base16_len(line_off + (line_len - 8)) == 8)){ // 16進数で8文字
|
|
// ファイル名
|
|
name_len = line_len - 9;
|
|
if (base_len + name_len < MAX_LEN){
|
|
while (line_off[name_len - 1] == ' ')
|
|
name_len--;
|
|
// ファイル名の前後が「"」で囲まれてる場合は取り除く
|
|
if ((line_off[0] == '"') && (line_off[name_len - 1] == '"')){
|
|
name_len -= 2;
|
|
wcsncpy(uni_buf, line_off + 1, name_len);
|
|
} else {
|
|
wcsncpy(uni_buf, line_off, name_len);
|
|
}
|
|
uni_buf[name_len] = 0;
|
|
rv = sanitize_filename(uni_buf); // ファイル名を浄化する
|
|
if (rv > 1){
|
|
if ((comment & 8) == 0){
|
|
comment |= 8;
|
|
printf("\nWarning about filenames :\n");
|
|
}
|
|
if (rv == 16){
|
|
printf("line%d: filename is invalid\n", line_num);
|
|
num++; // 浄化できないファイル名
|
|
} else if ((rv & 6) == 0){
|
|
utf16_to_cp(uni_buf, ascii_buf, MAX_LEN * 3, cp_output);
|
|
printf("line%d: \"%s\" is invalid\n", line_num, ascii_buf);
|
|
} else {
|
|
utf16_to_cp(uni_buf, ascii_buf, MAX_LEN * 3, cp_output);
|
|
printf("line%d: \"%s\" was sanitized\n", line_num, ascii_buf);
|
|
}
|
|
}
|
|
if (rv != 16)
|
|
file_num++;
|
|
} else {
|
|
if ((comment & 8) == 0){
|
|
comment |= 8;
|
|
printf("\nWarning about filenames :\n");
|
|
}
|
|
printf("line%d: filename is invalid\n", line_num);
|
|
num++; // 長すぎるファイル名
|
|
}
|
|
} else if (line_len > 0){
|
|
//printf("line %d is invalid\n", line_num);
|
|
num++; // 内容が認識できない行
|
|
}
|
|
// 次の行へ
|
|
line_off += line_len;
|
|
if (*line_off == '\n')
|
|
line_off++;
|
|
if (*line_off == '\r'){
|
|
line_off++;
|
|
if (*line_off == '\n') // 「\r\n」を一つの改行として扱う
|
|
line_off++;
|
|
}
|
|
line_num++;
|
|
}
|
|
if (comment & 8)
|
|
printf("\n");
|
|
// チェックサム・ファイルの状態
|
|
if (num == 0){
|
|
printf("Status : Good\n");
|
|
} else {
|
|
printf("Status : Damaged\n");
|
|
err |= 16; // 後で 256に変更する
|
|
}
|
|
if (file_num == 0){
|
|
printf("valid file is not found\n");
|
|
return 1;
|
|
}
|
|
|
|
printf("\nInput File list : %d\n", file_num);
|
|
printf(" CRC-32 : Filename\n");
|
|
fflush(stdout);
|
|
line_off = text_buf;
|
|
while (*line_off != 0){ // 一行ずつ処理する
|
|
line_len = 0;
|
|
while (line_off[line_len] != 0){ // 改行までを一行とする
|
|
if (line_off[line_len] == '\n')
|
|
break;
|
|
if (line_off[line_len] == '\r')
|
|
break;
|
|
line_len++;
|
|
}
|
|
// 行の内容が適正か調べる
|
|
if ((line_off[0] != ';') && // コメントではない
|
|
(line_len > 9) && (line_off[line_len - 9] == ' ') // CRC の前がスペース
|
|
&& (base16_len(line_off + (line_len - 8)) == 8)){ // 16進数で8文字
|
|
// ファイル名
|
|
name_len = line_len - 9;
|
|
if (base_len + name_len < MAX_LEN){
|
|
while (line_off[name_len - 1] == ' ')
|
|
name_len--;
|
|
// ファイル名の前後が「"」で囲まれてる場合は取り除く
|
|
if ((line_off[0] == '"') && (line_off[name_len - 1] == '"')){
|
|
name_len -= 2;
|
|
wcsncpy(uni_buf, line_off + 1, name_len);
|
|
} else {
|
|
wcsncpy(uni_buf, line_off, name_len);
|
|
}
|
|
uni_buf[name_len] = 0;
|
|
rv = sanitize_filename(uni_buf); // ファイル名を浄化する
|
|
if (rv != 16){
|
|
utf16_to_cp(uni_buf, ascii_buf, MAX_LEN * 3, cp_output);
|
|
// CRC
|
|
crc = get_val32h(line_off + (line_len - 8));
|
|
printf("%08X : \"%s\"\n", crc, ascii_buf);
|
|
}
|
|
}
|
|
}
|
|
// 次の行へ
|
|
line_off += line_len;
|
|
if (*line_off == '\n')
|
|
line_off++;
|
|
if (*line_off == '\r'){
|
|
line_off++;
|
|
if (*line_off == '\n') // 「\r\n」を一つの改行として扱う
|
|
line_off++;
|
|
}
|
|
}
|
|
|
|
|
|
printf("\nVerifying Input File :\n");
|
|
printf(" Size Status : Filename\n");
|
|
fflush(stdout);
|
|
if (recent_data != 0){ // 前回の検査結果を使うなら
|
|
PHMD5 ctx;
|
|
// チェックサム・ファイル識別用にハッシュ値を計算する
|
|
Phmd5Begin(&ctx);
|
|
Phmd5Process(&ctx, (unsigned char *)text_buf, text_len * 2);
|
|
Phmd5End(&ctx);
|
|
// 前回の検査結果が存在するか
|
|
check_ini_file(ctx.hash, text_len);
|
|
}
|
|
num = 0;
|
|
line_off = text_buf;
|
|
while (*line_off != 0){ // 一行ずつ処理する
|
|
line_len = 0;
|
|
while (line_off[line_len] != 0){ // 改行までを一行とする
|
|
if (line_off[line_len] == '\n')
|
|
break;
|
|
if (line_off[line_len] == '\r')
|
|
break;
|
|
line_len++;
|
|
}
|
|
// 行の内容が適正か調べる
|
|
if ((line_off[0] != ';') && // コメントではない
|
|
(line_len > 9) && (line_off[line_len - 9] == ' ') // CRC の前がスペース
|
|
&& (base16_len(line_off + (line_len - 8)) == 8)){ // 16進数で8文字
|
|
// ファイル名
|
|
name_len = line_len - 9;
|
|
if (base_len + name_len < MAX_LEN){
|
|
while (line_off[name_len - 1] == ' ')
|
|
name_len--;
|
|
// ファイル名の前後が「"」で囲まれてる場合は取り除く
|
|
if ((line_off[0] == '"') && (line_off[name_len - 1] == '"')){
|
|
name_len -= 2;
|
|
wcsncpy(uni_buf, line_off + 1, name_len);
|
|
} else {
|
|
wcsncpy(uni_buf, line_off, name_len);
|
|
}
|
|
uni_buf[name_len] = 0;
|
|
rv = sanitize_filename(uni_buf); // ファイル名を浄化する
|
|
if (rv != 16){
|
|
utf16_to_cp(uni_buf, ascii_buf, MAX_LEN * 3, cp_output);
|
|
// CRC
|
|
crc = get_val32h(line_off + (line_len - 8));
|
|
rv = file_crc32_check(num, ascii_buf, uni_buf, file_path, crc);
|
|
if (rv & 3){
|
|
err = rv;
|
|
break;
|
|
}
|
|
if (rv & 0xC){ // Missing or Damaged
|
|
err |= rv;
|
|
err += 0x100;
|
|
}
|
|
num++;
|
|
}
|
|
}
|
|
}
|
|
// 次の行へ
|
|
line_off += line_len;
|
|
if (*line_off == '\n')
|
|
line_off++;
|
|
if (*line_off == '\r'){
|
|
line_off++;
|
|
if (*line_off == '\n') // 「\r\n」を一つの改行として扱う
|
|
line_off++;
|
|
}
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
|
|
|
// MD5 を比較する
|
|
// 0 = ファイルが存在して完全である
|
|
// 1 = ファイルが存在しない
|
|
// 2 = ファイルが破損してる
|
|
static int file_md5_check(
|
|
int num,
|
|
char *ascii_name,
|
|
wchar_t *uni_name,
|
|
wchar_t *file_path,
|
|
unsigned char *hash)
|
|
{
|
|
unsigned char buf[IO_SIZE];
|
|
int len, off, bad_flag;
|
|
unsigned int time_last, meta_data[8];
|
|
__int64 file_size = 0, file_left;
|
|
HANDLE hFile;
|
|
PHMD5 ctx;
|
|
|
|
prog_last = -1;
|
|
time_last = GetTickCount() / UPDATE_TIME; // 時刻の変化時に経過を表示する
|
|
wcscpy(file_path, base_dir);
|
|
// 先頭の「..\」を許可してるので、基準ディレクトリから上に遡る。
|
|
len = base_len - 1;
|
|
off = 0;
|
|
while ((uni_name[off] == '.') && (uni_name[off + 1] == '.') && (uni_name[off + 2] == '\\')){
|
|
off += 3;
|
|
file_path[len] = 0;
|
|
while (file_path[len] != '\\'){
|
|
file_path[len] = 0;
|
|
len--;
|
|
}
|
|
}
|
|
wcscat(file_path, uni_name + off);
|
|
//printf("path = \"%S\"\n", file_path);
|
|
|
|
// 読み込むファイルを開く
|
|
hFile = CreateFile(file_path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
|
|
if (hFile == INVALID_HANDLE_VALUE){
|
|
bad_flag = 1; // 消失は記録しない
|
|
} else {
|
|
bad_flag = check_ini_state(num, meta_data, hFile);
|
|
memcpy(&file_size, meta_data, 8);
|
|
if (bad_flag == -2){ // 記録が無い場合 (属性取得エラーは不明にする)
|
|
file_left = file_size;
|
|
Phmd5Begin(&ctx); // 初期化
|
|
while (file_left > 0){
|
|
len = IO_SIZE;
|
|
if (file_left < IO_SIZE)
|
|
len = (int)file_left;
|
|
if (!ReadFile(hFile, buf, len, &bad_flag, NULL) || (len != bad_flag))
|
|
break; // 読み取りエラーは必ず破損になる
|
|
file_left -= len;
|
|
// MD5 を更新する
|
|
Phmd5Process(&ctx, buf, len);
|
|
|
|
// 経過表示
|
|
if (GetTickCount() / UPDATE_TIME != time_last){
|
|
if (print_progress_file((int)(((file_size - file_left) * 1000) / file_size), uni_name)){
|
|
CloseHandle(hFile);
|
|
return 2;
|
|
}
|
|
time_last = GetTickCount() / UPDATE_TIME;
|
|
}
|
|
}
|
|
Phmd5End(&ctx); // 最終処理
|
|
// printf("%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X %d\n",
|
|
// ctx.hash[0], ctx.hash[1], ctx.hash[2], ctx.hash[3], ctx.hash[4], ctx.hash[5], ctx.hash[6], ctx.hash[7],
|
|
// ctx.hash[8], ctx.hash[9], ctx.hash[10], ctx.hash[11], ctx.hash[12], ctx.hash[13], ctx.hash[14], ctx.hash[15]);
|
|
if ((memcmp(hash, ctx.hash, 16) != 0) || (file_left > 0)){
|
|
bad_flag = 2; // ハッシュ値が異なる、または途中まで
|
|
} else {
|
|
bad_flag = 0; // 完全
|
|
}
|
|
write_ini_state(num, meta_data, bad_flag); // 検査結果を記録する、完全か破損
|
|
}
|
|
CloseHandle(hFile);
|
|
}
|
|
|
|
switch (bad_flag){
|
|
case 0:
|
|
printf("%13I64d Complete : \"%s\"\n", file_size, ascii_name);
|
|
break;
|
|
case 1:
|
|
printf(" 0 Missing : \"%s\"\n", ascii_name);
|
|
bad_flag = 4 | 8;
|
|
break;
|
|
case 2:
|
|
printf("%13I64d Damaged : \"%s\"\n", file_size, ascii_name);
|
|
bad_flag = 4;
|
|
break;
|
|
default: // IOエラー等
|
|
printf(" ? Unknown : \"%s\"\n", ascii_name);
|
|
bad_flag = 4;
|
|
break;
|
|
}
|
|
fflush(stdout);
|
|
return bad_flag;
|
|
}
|
|
|
|
// MD5 ファイル
|
|
int verify_md5(
|
|
char *ascii_buf,
|
|
wchar_t *file_path)
|
|
{
|
|
unsigned char hash[16];
|
|
wchar_t *line_off, uni_buf[MAX_LEN], num_buf[3];
|
|
unsigned int err = 0, i, rv, line_len, name_len, line_num, num, comment;
|
|
|
|
// ファイル数を調べる
|
|
comment = 0;
|
|
num = 0;
|
|
line_num = 1;
|
|
line_off = text_buf;
|
|
while (*line_off != 0){ // 一行ずつ処理する
|
|
line_len = 0;
|
|
while (line_off[line_len] != 0){ // 改行までを一行とする
|
|
if (line_off[line_len] == '\n')
|
|
break;
|
|
if (line_off[line_len] == '\r')
|
|
break;
|
|
line_len++;
|
|
}
|
|
// 行の内容が適正か調べる
|
|
if (line_off[0] == ';'){ // コメント
|
|
if (((comment & 1) == 0) && (line_len > 8) && (line_len < MAX_LEN)){
|
|
// クリエイターの表示がまだなら
|
|
if (wcsncmp(line_off, L"; Generated by ", 15) == 0){ // md5sum, Easy MD5 Creator
|
|
wcsncpy(uni_buf, line_off + 15, line_len - 15);
|
|
uni_buf[line_len - 15] = 0;
|
|
comment = 1;
|
|
} else if (wcsncmp(line_off, L"; Using ", 8) == 0){
|
|
wcsncpy(uni_buf, line_off + 8, line_len - 8);
|
|
uni_buf[line_len - 8] = 0;
|
|
comment = 1;
|
|
}
|
|
if (comment & 1){
|
|
uni_buf[COMMENT_LEN - 1] = 0; // 表示する文字数を制限する
|
|
utf16_to_cp(uni_buf, ascii_buf, COMMENT_LEN * 3, cp_output);
|
|
printf("Creator : %s\n", ascii_buf);
|
|
comment |= 4; // 同一行を二度表示しない
|
|
}
|
|
}
|
|
if (((comment & 6) == 0) && (line_len < MAX_LEN)){
|
|
// 最初のコメントの表示がまだなら
|
|
i = 1;
|
|
while (i < line_len){
|
|
if (line_off[i] != ' ')
|
|
break;
|
|
i++;
|
|
}
|
|
if (i < line_len){
|
|
wcsncpy(uni_buf, line_off + i, line_len - i);
|
|
uni_buf[line_len - i] = 0;
|
|
uni_buf[COMMENT_LEN - 1] = 0; // 表示する文字数を制限する
|
|
utf16_to_cp(uni_buf, ascii_buf, COMMENT_LEN * 3, cp_output);
|
|
printf("Comment : %s\n", ascii_buf);
|
|
}
|
|
comment |= 2; // 「;」だけの行も認識する
|
|
}
|
|
comment &= ~4; // bit 4 を消す
|
|
} else if (line_off[0] == '#'){ // コメント
|
|
if (((comment & 1) == 0) && (line_len > 8) && (line_len < MAX_LEN)){
|
|
// クリエイターの表示がまだなら
|
|
if (wcsncmp(line_off, L"# Generated by ", 15) == 0){ // OpenHashTab
|
|
wcsncpy(uni_buf, line_off + 15, line_len - 15);
|
|
uni_buf[line_len - 15] = 0;
|
|
comment = 1;
|
|
} else if (wcsncmp(line_off, L"# MD5 checksum generated by ", 28) == 0){ // IsoBuster
|
|
wcsncpy(uni_buf, line_off + 28, line_len - 28);
|
|
uni_buf[line_len - 28] = 0;
|
|
comment = 1;
|
|
} else if (wcsncmp(line_off, L"#MD5 checksums generated by ", 28) == 0){ // xACT
|
|
wcsncpy(uni_buf, line_off + 28, line_len - 28);
|
|
uni_buf[line_len - 28] = 0;
|
|
comment = 1;
|
|
} else if (wcsncmp(line_off, L"# MD5 checksums generated by ", 29) == 0){ // MD5summer
|
|
wcsncpy(uni_buf, line_off + 29, line_len - 29);
|
|
uni_buf[line_len - 29] = 0;
|
|
comment = 1;
|
|
}
|
|
if (comment & 1){
|
|
uni_buf[COMMENT_LEN - 1] = 0; // 表示する文字数を制限する
|
|
utf16_to_cp(uni_buf, ascii_buf, COMMENT_LEN * 3, cp_output);
|
|
printf("Creator : %s\n", ascii_buf);
|
|
}
|
|
}
|
|
} else if (line_len > 33){ // コメントではない
|
|
// MD5 の後がスペース (md5sum 形式)
|
|
if ((line_off[32] == ' ') && (base16_len(line_off) == 32)){
|
|
// ファイル名
|
|
name_len = line_len - 33;
|
|
if (base_len + name_len < MAX_LEN){
|
|
// タイプ記号「*」までのスペースは複数個でもいい
|
|
while (line_off[line_len - name_len] == ' ')
|
|
name_len--;
|
|
if (line_off[line_len - name_len] == '*')
|
|
name_len--;
|
|
wcsncpy(uni_buf, line_off + (line_len - name_len), name_len);
|
|
uni_buf[name_len] = 0;
|
|
rv = sanitize_filename(uni_buf); // ファイル名を浄化する
|
|
if (rv > 1){
|
|
if ((comment & 8) == 0){
|
|
comment |= 8;
|
|
printf("\nWarning about filenames :\n");
|
|
}
|
|
if (rv == 16){
|
|
printf("line%d: filename is invalid\n", line_num);
|
|
num++; // 浄化できないファイル名
|
|
} else if ((rv & 6) == 0){
|
|
utf16_to_cp(uni_buf, ascii_buf, MAX_LEN * 3, cp_output);
|
|
printf("line%d: \"%s\" is invalid\n", line_num, ascii_buf);
|
|
} else {
|
|
utf16_to_cp(uni_buf, ascii_buf, MAX_LEN * 3, cp_output);
|
|
printf("line%d: \"%s\" was sanitized\n", line_num, ascii_buf);
|
|
}
|
|
}
|
|
if (rv != 16)
|
|
file_num++;
|
|
} else {
|
|
if ((comment & 8) == 0){
|
|
comment |= 8;
|
|
printf("\nWarning about filenames :\n");
|
|
}
|
|
printf("line%d: filename is invalid\n", line_num);
|
|
num++; // 長すぎるファイル名
|
|
}
|
|
|
|
// ファイル名の後にMD5
|
|
} else if ((line_off[line_len - 33] == ' ') && (base16_len(line_off + (line_len - 32)) == 32)){
|
|
// MD5 の前が括弧 (BSD/OpenSSL 形式)
|
|
if (((wcsncmp(line_off, L"MD5(", 4) == 0) || (wcsncmp(line_off, L"MD5 (", 5) == 0))
|
|
&& ((wcsncmp(line_off + (line_len - 35), L")= ", 3) == 0) ||
|
|
(wcsncmp(line_off + (line_len - 36), L") = ", 4) == 0))){
|
|
// ファイル名
|
|
name_len = line_len - 35 - 4;
|
|
if (base_len + name_len < MAX_LEN){
|
|
if (line_off[line_len - 35] != ')')
|
|
name_len--;
|
|
if (line_off[3] == ' '){
|
|
name_len--;
|
|
wcsncpy(uni_buf, line_off + 5, name_len);
|
|
} else {
|
|
wcsncpy(uni_buf, line_off + 4, name_len);
|
|
}
|
|
uni_buf[name_len] = 0;
|
|
rv = sanitize_filename(uni_buf); // ファイル名を浄化する
|
|
if (rv > 1){
|
|
if ((comment & 8) == 0){
|
|
comment |= 8;
|
|
printf("\nWarning about filenames :\n");
|
|
}
|
|
if (rv == 16){
|
|
printf("line%d: filename is invalid\n", line_num);
|
|
num++; // 浄化できないファイル名
|
|
} else if ((rv & 6) == 0){
|
|
utf16_to_cp(uni_buf, ascii_buf, MAX_LEN * 3, cp_output);
|
|
printf("line%d: \"%s\" is invalid\n", line_num, ascii_buf);
|
|
} else {
|
|
utf16_to_cp(uni_buf, ascii_buf, MAX_LEN * 3, cp_output);
|
|
printf("line%d: \"%s\" was sanitized\n", line_num, ascii_buf);
|
|
}
|
|
}
|
|
if (rv != 16)
|
|
file_num++;
|
|
} else {
|
|
if ((comment & 8) == 0){
|
|
comment |= 8;
|
|
printf("\nWarning about filenames :\n");
|
|
}
|
|
printf("line%d: filename is invalid\n", line_num);
|
|
num++; // 長すぎるファイル名
|
|
}
|
|
} else { // MD5 の前がスペース (Easy MD5 Creator 形式)
|
|
// ファイル名
|
|
name_len = line_len - 33;
|
|
if (base_len + name_len < MAX_LEN){
|
|
while (line_off[name_len - 1] == ' ')
|
|
name_len--;
|
|
wcsncpy(uni_buf, line_off, name_len);
|
|
uni_buf[name_len] = 0;
|
|
rv = sanitize_filename(uni_buf); // ファイル名を浄化する
|
|
if (rv > 1){
|
|
if ((comment & 8) == 0){
|
|
comment |= 8;
|
|
printf("\nWarning about filenames :\n");
|
|
}
|
|
if (rv == 16){
|
|
printf("line%d: filename is invalid\n", line_num);
|
|
num++; // 浄化できないファイル名
|
|
} else if ((rv & 6) == 0){
|
|
utf16_to_cp(uni_buf, ascii_buf, MAX_LEN * 3, cp_output);
|
|
printf("line%d: \"%s\" is invalid\n", line_num, ascii_buf);
|
|
} else {
|
|
utf16_to_cp(uni_buf, ascii_buf, MAX_LEN * 3, cp_output);
|
|
printf("line%d: \"%s\" was sanitized\n", line_num, ascii_buf);
|
|
}
|
|
}
|
|
if (rv != 16)
|
|
file_num++;
|
|
} else {
|
|
if ((comment & 8) == 0){
|
|
comment |= 8;
|
|
printf("\nWarning about filenames :\n");
|
|
}
|
|
printf("line%d: filename is invalid\n", line_num);
|
|
num++; // 長すぎるファイル名
|
|
}
|
|
}
|
|
} else {
|
|
num++; // 内容が認識できない行
|
|
}
|
|
} else if (line_len > 0){
|
|
num++; // 内容が認識できない行
|
|
}
|
|
// 次の行へ
|
|
line_off += line_len;
|
|
if (*line_off == '\n')
|
|
line_off++;
|
|
if (*line_off == '\r'){
|
|
line_off++;
|
|
if (*line_off == '\n') // 「\r\n」を一つの改行として扱う
|
|
line_off++;
|
|
}
|
|
line_num++;
|
|
}
|
|
if (comment & 8)
|
|
printf("\n");
|
|
// チェックサム・ファイルの状態
|
|
if (num == 0){
|
|
printf("Status : Good\n");
|
|
} else {
|
|
printf("Status : Damaged\n");
|
|
err |= 16; // 後で 256に変更する
|
|
}
|
|
if (file_num == 0){
|
|
printf("valid file is not found\n");
|
|
return 1;
|
|
}
|
|
|
|
printf("\nInput File list : %d\n", file_num);
|
|
printf("\t MD5 Hash\t\t : Filename\n");
|
|
fflush(stdout);
|
|
line_off = text_buf;
|
|
while (*line_off != 0){ // 一行ずつ処理する
|
|
line_len = 0;
|
|
while (line_off[line_len] != 0){ // 改行までを一行とする
|
|
if (line_off[line_len] == '\n')
|
|
break;
|
|
if (line_off[line_len] == '\r')
|
|
break;
|
|
line_len++;
|
|
}
|
|
// 行の内容が適正か調べる
|
|
if ((line_off[0] != ';') && (line_len > 33)){ // コメントではない
|
|
// MD5 の後がスペース (md5sum 形式)
|
|
if ((line_off[32] == ' ') && (base16_len(line_off) == 32)){
|
|
// ファイル名
|
|
name_len = line_len - 33;
|
|
if (base_len + name_len < MAX_LEN){
|
|
// タイプ記号「*」までのスペースは複数個でもいい
|
|
while (line_off[line_len - name_len] == ' ')
|
|
name_len--;
|
|
if (line_off[line_len - name_len] == '*')
|
|
name_len--;
|
|
wcsncpy(uni_buf, line_off + (line_len - name_len), name_len);
|
|
uni_buf[name_len] = 0;
|
|
rv = sanitize_filename(uni_buf); // ファイル名を浄化する
|
|
if (rv != 16){
|
|
utf16_to_cp(uni_buf, ascii_buf, MAX_LEN * 3, cp_output);
|
|
// MD5
|
|
num_buf[2] = 0;
|
|
for (i = 0; i < 16; i++){
|
|
wcsncpy(num_buf, line_off + (i * 2), 2);
|
|
hash[i] = (unsigned char)get_val32h(num_buf);
|
|
}
|
|
printf("%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X : \"%s\"\n",
|
|
hash[0], hash[1], hash[2], hash[3], hash[4], hash[5], hash[6], hash[7],
|
|
hash[8], hash[9], hash[10], hash[11], hash[12], hash[13], hash[14], hash[15], ascii_buf);
|
|
}
|
|
}
|
|
|
|
// ファイル名の後にMD5
|
|
} else if ((line_off[line_len - 33] == ' ') && (base16_len(line_off + (line_len - 32)) == 32)){
|
|
// MD5 の前が括弧 (BSD/OpenSSL 形式)
|
|
if (((wcsncmp(line_off, L"MD5(", 4) == 0) || (wcsncmp(line_off, L"MD5 (", 5) == 0))
|
|
&& ((wcsncmp(line_off + (line_len - 35), L")= ", 3) == 0) ||
|
|
(wcsncmp(line_off + (line_len - 36), L") = ", 4) == 0))){
|
|
// ファイル名
|
|
name_len = line_len - 35 - 4;
|
|
if (base_len + name_len < MAX_LEN){
|
|
if (line_off[line_len - 35] != ')')
|
|
name_len--;
|
|
if (line_off[3] == ' '){
|
|
name_len--;
|
|
wcsncpy(uni_buf, line_off + 5, name_len);
|
|
} else {
|
|
wcsncpy(uni_buf, line_off + 4, name_len);
|
|
}
|
|
uni_buf[name_len] = 0;
|
|
rv = sanitize_filename(uni_buf); // ファイル名を浄化する
|
|
if (rv != 16){
|
|
utf16_to_cp(uni_buf, ascii_buf, MAX_LEN * 3, cp_output);
|
|
// MD5
|
|
num_buf[2] = 0;
|
|
for (i = 0; i < 16; i++){
|
|
wcsncpy(num_buf, line_off + (line_len - 32 + (i * 2)), 2);
|
|
hash[i] = (unsigned char)get_val32h(num_buf);
|
|
}
|
|
printf("%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X : \"%s\"\n",
|
|
hash[0], hash[1], hash[2], hash[3], hash[4], hash[5], hash[6], hash[7],
|
|
hash[8], hash[9], hash[10], hash[11], hash[12], hash[13], hash[14], hash[15], ascii_buf);
|
|
}
|
|
}
|
|
} else { // MD5 の前がスペース (Easy MD5 Creator 形式)
|
|
// ファイル名
|
|
name_len = line_len - 33;
|
|
if (base_len + name_len < MAX_LEN){
|
|
while (line_off[name_len - 1] == ' ')
|
|
name_len--;
|
|
wcsncpy(uni_buf, line_off, name_len);
|
|
uni_buf[name_len] = 0;
|
|
rv = sanitize_filename(uni_buf); // ファイル名を浄化する
|
|
if (rv != 16){
|
|
utf16_to_cp(uni_buf, ascii_buf, MAX_LEN * 3, cp_output);
|
|
// MD5
|
|
num_buf[2] = 0;
|
|
for (i = 0; i < 16; i++){
|
|
wcsncpy(num_buf, line_off + (line_len - 32 + (i * 2)), 2);
|
|
hash[i] = (unsigned char)get_val32h(num_buf);
|
|
}
|
|
printf("%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X : \"%s\"\n",
|
|
hash[0], hash[1], hash[2], hash[3], hash[4], hash[5], hash[6], hash[7],
|
|
hash[8], hash[9], hash[10], hash[11], hash[12], hash[13], hash[14], hash[15], ascii_buf);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
// 次の行へ
|
|
line_off += line_len;
|
|
if (*line_off == '\n')
|
|
line_off++;
|
|
if (*line_off == '\r'){
|
|
line_off++;
|
|
if (*line_off == '\n') // 「\r\n」を一つの改行として扱う
|
|
line_off++;
|
|
}
|
|
}
|
|
|
|
printf("\nVerifying Input File :\n");
|
|
printf(" Size Status : Filename\n");
|
|
fflush(stdout);
|
|
if (recent_data != 0){ // 前回の検査結果を使うなら
|
|
PHMD5 ctx;
|
|
// チェックサム・ファイル識別用にハッシュ値を計算する
|
|
Phmd5Begin(&ctx);
|
|
Phmd5Process(&ctx, (unsigned char *)text_buf, text_len * 2);
|
|
Phmd5End(&ctx);
|
|
// 前回の検査結果が存在するか
|
|
check_ini_file(ctx.hash, text_len);
|
|
}
|
|
num = 0;
|
|
line_off = text_buf;
|
|
while (*line_off != 0){ // 一行ずつ処理する
|
|
line_len = 0;
|
|
while (line_off[line_len] != 0){ // 改行までを一行とする
|
|
if (line_off[line_len] == '\n')
|
|
break;
|
|
if (line_off[line_len] == '\r')
|
|
break;
|
|
line_len++;
|
|
}
|
|
// 行の内容が適正か調べる
|
|
if ((line_off[0] != ';') && (line_len > 33)){ // コメントではない
|
|
// MD5 の後がスペース (md5sum 形式)
|
|
if ((line_off[32] == ' ') && (base16_len(line_off) == 32)){
|
|
// ファイル名
|
|
name_len = line_len - 33;
|
|
if (base_len + name_len < MAX_LEN){
|
|
// タイプ記号「*」までのスペースは複数個でもいい
|
|
while (line_off[line_len - name_len] == ' ')
|
|
name_len--;
|
|
if (line_off[line_len - name_len] == '*')
|
|
name_len--;
|
|
wcsncpy(uni_buf, line_off + (line_len - name_len), name_len);
|
|
uni_buf[name_len] = 0;
|
|
rv = sanitize_filename(uni_buf); // ファイル名を浄化する
|
|
if (rv != 16){
|
|
utf16_to_cp(uni_buf, ascii_buf, MAX_LEN * 3, cp_output);
|
|
// MD5
|
|
num_buf[2] = 0;
|
|
for (i = 0; i < 16; i++){
|
|
wcsncpy(num_buf, line_off + (i * 2), 2);
|
|
hash[i] = (unsigned char)get_val32h(num_buf);
|
|
}
|
|
rv = file_md5_check(num, ascii_buf, uni_buf, file_path, hash);
|
|
if (rv & 3){
|
|
err = rv;
|
|
break;
|
|
}
|
|
if (rv & 0xC){ // Missing or Damaged
|
|
err |= rv;
|
|
err += 0x100;
|
|
}
|
|
num++;
|
|
}
|
|
}
|
|
|
|
// ファイル名の後にMD5
|
|
} else if ((line_off[line_len - 33] == ' ') && (base16_len(line_off + (line_len - 32)) == 32)){
|
|
// MD5 の前が括弧 (BSD/OpenSSL 形式)
|
|
if (((wcsncmp(line_off, L"MD5(", 4) == 0) || (wcsncmp(line_off, L"MD5 (", 5) == 0))
|
|
&& ((wcsncmp(line_off + (line_len - 35), L")= ", 3) == 0) ||
|
|
(wcsncmp(line_off + (line_len - 36), L") = ", 4) == 0))){
|
|
// ファイル名
|
|
name_len = line_len - 35 - 4;
|
|
if (base_len + name_len < MAX_LEN){
|
|
if (line_off[line_len - 35] != ')')
|
|
name_len--;
|
|
if (line_off[3] == ' '){
|
|
name_len--;
|
|
wcsncpy(uni_buf, line_off + 5, name_len);
|
|
} else {
|
|
wcsncpy(uni_buf, line_off + 4, name_len);
|
|
}
|
|
uni_buf[name_len] = 0;
|
|
rv = sanitize_filename(uni_buf); // ファイル名を浄化する
|
|
if (rv != 16){
|
|
utf16_to_cp(uni_buf, ascii_buf, MAX_LEN * 3, cp_output);
|
|
// MD5
|
|
num_buf[2] = 0;
|
|
for (i = 0; i < 16; i++){
|
|
wcsncpy(num_buf, line_off + (line_len - 32 + (i * 2)), 2);
|
|
hash[i] = (unsigned char)get_val32h(num_buf);
|
|
}
|
|
rv = file_md5_check(num, ascii_buf, uni_buf, file_path, hash);
|
|
if (rv & 3){
|
|
err = rv;
|
|
break;
|
|
}
|
|
if (rv & 0xC){ // Missing or Damaged
|
|
err |= rv;
|
|
err += 0x100;
|
|
}
|
|
num++;
|
|
}
|
|
}
|
|
} else { // MD5 の前がスペース (Easy MD5 Creator 形式)
|
|
// ファイル名
|
|
name_len = line_len - 33;
|
|
if (base_len + name_len < MAX_LEN){
|
|
while (line_off[name_len - 1] == ' ')
|
|
name_len--;
|
|
wcsncpy(uni_buf, line_off, name_len);
|
|
uni_buf[name_len] = 0;
|
|
rv = sanitize_filename(uni_buf); // ファイル名を浄化する
|
|
if (rv != 16){
|
|
utf16_to_cp(uni_buf, ascii_buf, MAX_LEN * 3, cp_output);
|
|
// MD5
|
|
num_buf[2] = 0;
|
|
for (i = 0; i < 16; i++){
|
|
wcsncpy(num_buf, line_off + (line_len - 32 + (i * 2)), 2);
|
|
hash[i] = (unsigned char)get_val32h(num_buf);
|
|
}
|
|
rv = file_md5_check(num, ascii_buf, uni_buf, file_path, hash);
|
|
if (rv & 3){
|
|
err = rv;
|
|
break;
|
|
}
|
|
if (rv & 0xC){ // Missing or Damaged
|
|
err |= rv;
|
|
err += 0x100;
|
|
}
|
|
num++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
// 次の行へ
|
|
line_off += line_len;
|
|
if (*line_off == '\n')
|
|
line_off++;
|
|
if (*line_off == '\r'){
|
|
line_off++;
|
|
if (*line_off == '\n') // 「\r\n」を一つの改行として扱う
|
|
line_off++;
|
|
}
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|