// 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 #include #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; }