Files
MultiPar/source/sfv_md5/main.c
2024-11-30 13:08:09 +09:00

878 lines
27 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// main.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 <imagehlp.h>
#include "crc.h"
#include "common.h"
#include "create.h"
#include "verify.h"
#include "ini.h"
#include "version.h"
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void print_help(void)
{
printf(
"Usage\n"
"c(reate) [fo,t, d,u] <checksum file> [input files]\n"
"v(erify) [vs,vd,d,u] <checksum file>\n"
"\nOption\n"
" /fo : Search file only for wildcard\n"
" /t<n> : Save time stamp\n"
" /vs<n>: Skip verification by recent result\n"
" /vd\"*\": Set directory of recent result\n"
" /d\"*\" : Set directory of input files\n"
" /u : Console output is encoded with UTF-8\n"
);
}
// CRC-32 チェックサムを使って自分自身の破損を検出する
long test_checksum(wchar_t *file_path) // 作業用
{
unsigned long rv, crc, chk, chk2;
unsigned char *pAddr;
HANDLE hFile, hMap;
init_crc_table(); // CRC 計算用のテーブルを作成する
// 実行ファイルのパスを取得する
rv = GetModuleFileName(NULL, file_path, MAX_LEN);
if ((rv == 0) || (rv >= MAX_LEN))
return 1;
// 実行ファイルの PE checksum と CRC-32 を検証する
hFile = CreateFile(file_path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
if (hFile == INVALID_HANDLE_VALUE){
print_win32_err();
return 1;
}
rv = GetFileSize(hFile, &chk2);
if (rv == INVALID_FILE_SIZE)
return 1;
hMap = CreateFileMapping(hFile, NULL, PAGE_READONLY, chk2, rv, NULL);
if (hMap == NULL){
CloseHandle(hFile);
return 1;
}
pAddr = MapViewOfFile(hMap, FILE_MAP_READ, 0, 0, rv);
if (pAddr == NULL){
CloseHandle(hMap);
CloseHandle(hFile);
return 1;
}
if (CheckSumMappedFile(pAddr, rv, &chk2, &chk) == NULL){ // PE checksum
UnmapViewOfFile(pAddr);
CloseHandle(hMap);
CloseHandle(hFile);
return 1;
}
crc = crc_update(0xFFFFFFFF, pAddr, rv) ^ 0xFFFFFFFF;
UnmapViewOfFile(pAddr);
CloseHandle(hMap);
CloseHandle(hFile);
if (chk != chk2)
return 2;
if (crc != 0x00000000)
return 3;
return 0;
}
// ファイルを検索してファイル・リストに追加する
static wchar_t * search_files(
wchar_t *list_buf, // ファイル・リスト
wchar_t *search_path, // 検索するファイルのフル・パス
long dir_len, // ディレクトリ部分の長さ
//long file_only, // ファイルのみにするかどうか
unsigned int filter, // 2, FILE_ATTRIBUTE_HIDDEN = 隠しファイルを無視する
// 4, FILE_ATTRIBUTE_SYSTEM = システムファイルを無視する
// 16, FILE_ATTRIBUTE_DIRECTORY = ディレクトリを無視する
long single_file, // -1 = *や?で検索指定、0 = 単独指定
long *list_max, // ファイル・リストの確保サイズ
long *list_len, // ファイル・リストの文字数
__int64 *total_size) // 合計ファイル・サイズ
{
wchar_t *tmp_p;
long len, l_max, l_off, dir_len2;
unsigned int attrib_filter;
HANDLE hFind;
WIN32_FIND_DATA FindData;
// 隠しファイルを見つけるかどうか
attrib_filter = filter & (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM);
if (attrib_filter == 0)
attrib_filter = INVALID_FILE_ATTRIBUTES;
if (list_buf == NULL){
l_off = 0;
l_max = ALLOC_LEN;
list_buf = (wchar_t *)malloc(l_max);
if (list_buf == NULL){
printf("malloc, %d\n", l_max);
return NULL;
}
} else {
l_max = *list_max;
l_off = *list_len;
}
// 検索する
hFind = FindFirstFile(search_path, &FindData);
if (hFind == INVALID_HANDLE_VALUE)
return list_buf; // 見つからなかったらそのまま
do {
if ((single_file < 0) && ((FindData.dwFileAttributes & attrib_filter) == attrib_filter))
continue; // 検索中は隠し属性が付いてるファイルを無視する
len = wcslen(FindData.cFileName);
if (dir_len + len >= MAX_LEN - ADD_LEN - 2){ // 末尾に「\*」を付けて再検索するので
FindClose(hFind);
free(list_buf);
printf("filename is too long\n");
return NULL;
}
// 現在のディレクトリ部分に見つかったファイル名を連結する
wcscpy(search_path + dir_len, FindData.cFileName);
// フォルダなら
if (FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY){
if (((filter & FILE_ATTRIBUTE_DIRECTORY) == 0) && wcscmp(FindData.cFileName, L".") && wcscmp(FindData.cFileName, L"..")){
// フォルダの末尾は「\」にする
wcscat(search_path, L"\\");
// そのフォルダの中身を更に検索する
dir_len2 = wcslen(search_path);
search_path[dir_len2 ] = '*'; // 末尾に「*」を追加する
search_path[dir_len2 + 1] = 0;
list_buf = search_files(list_buf, search_path, dir_len2, filter, single_file, &l_max, &l_off, total_size);
if (list_buf == NULL){
FindClose(hFind);
printf("cannot search inner folder\n");
return NULL;
}
}
} else { // ファイルなら
if (!search_file_path(list_buf, l_off, search_path + base_len)){ // ファイル名が重複しないようにする
if ((l_off + dir_len- base_len + len) * 2 >= l_max){ // 領域が足りなくなるなら拡張する
l_max += ALLOC_LEN;
tmp_p = (wchar_t *)realloc(list_buf, l_max);
if (tmp_p == NULL){
FindClose(hFind);
free(list_buf);
printf("realloc, %d\n", l_max);
return NULL;
} else {
list_buf = tmp_p;
}
}
// リストにコピーする
wcscpy(list_buf + l_off, search_path + base_len);
l_off += dir_len - base_len + len + 1;
file_num++;
(*total_size) += ((__int64)FindData.nFileSizeHigh << 32) | (__int64)FindData.nFileSizeLow;
}
}
} while (FindNextFile(hFind, &FindData)); // 次のファイルを検索する
FindClose(hFind);
*list_max = l_max;
*list_len = l_off;
return list_buf;
}
// ファイルの詳細情報を記録する
long save_detail(
wchar_t *uni_buf,
wchar_t *file_name) // 検査対象のファイル名
{
__int64 file_size;
HANDLE hFile;
FILETIME ftWrite;
SYSTEMTIME stUTC, stLocal;
// 調べるファイルを開く
wcscpy(uni_buf, base_dir);
wcscpy(uni_buf + base_len, file_name);
hFile = CreateFile(uni_buf, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
if (hFile == INVALID_HANDLE_VALUE){
print_win32_err();
return 1;
}
// ファイル・サイズ
if (!GetFileSizeEx(hFile, (PLARGE_INTEGER)&file_size)){
print_win32_err();
CloseHandle(hFile);
return 1;
}
// 更新日時
if (!GetFileTime(hFile, NULL, NULL, &ftWrite)){
print_win32_err();
CloseHandle(hFile);
return 1;
}
FileTimeToSystemTime(&ftWrite, &stUTC);
SystemTimeToTzSpecificLocalTime(NULL, &stUTC, &stLocal);
CloseHandle(hFile);
// サイズと日時を書き込む
wsprintf(uni_buf, L";%13I64d %02d:%02d.%02d %4d-%02d-%02d ", file_size,
stLocal.wHour, stLocal.wMinute, stLocal.wSecond,
stLocal.wYear, stLocal.wMonth, stLocal.wDay);
add_text(uni_buf);
// ファイル名を書き込む
wcscpy(uni_buf, file_name); // 変換前にコピーする
unix_directory(uni_buf);
add_text(uni_buf);
add_text(L"\r\n");
return 0;
}
// チェックサム・ファイルを書き込む
static long write_checksum(wchar_t *uni_buf,
wchar_t *list_buf, long list_len, __int64 total_size, long switch_t)
{
char *ascii_buf;
wchar_t *ads_p;
long err = 0, rv, len, format;
__int64 prog_now = 0;
HANDLE hFile;
FILETIME ftWrite;
len = wcslen(checksum_file);
if (_wcsicmp(checksum_file + (len - 4), L".sfv") == 0){ // SFVファイル
format = 1;
} else if (_wcsicmp(checksum_file + (len - 4), L".md5") == 0){ // MD5ファイル
format = 2;
// } else {
// printf("unknown format\n");
// return 1;
}
// チェックサム・ファイルのテキストを UTF-16 の文字列で作成する
text_len = 0;
text_max = ALLOC_LEN;
text_buf = (wchar_t *)malloc(text_max * 2);
if (text_buf == NULL){
printf("malloc, %d\n", text_max * 2);
return 1;
}
// コメントを書き込む
wsprintf(uni_buf, L"; Generated by SFV/MD5 checker v%hs", PRODUCT_VERSION);
add_text(uni_buf);
if (switch_t >= 1){ // 作成した日時を書き込む
SYSTEMTIME stLocal;
GetLocalTime(&stLocal);
wsprintf(uni_buf, L" on %4d-%02d-%02d at %02d:%02d.%02d",
stLocal.wYear, stLocal.wMonth, stLocal.wDay,
stLocal.wHour, stLocal.wMinute, stLocal.wSecond);
add_text(uni_buf);
if (switch_t >= 2){ // ファイルの詳細を書き込むなら
add_text(L"\r\n;");
if (file_num > 1){
add_text(L"\r\n");
add_text(L"; Size (Bytes) Time Date Filename\n");
add_text(L"; ------------ -------- ---------- ------------");
}
}
}
add_text(L"\r\n");
if (switch_t >= 2){ // ファイルのサイズと更新日時を書き込む
len = 0;
while (len < list_len){
if (save_detail(uni_buf, list_buf + len) != 0){
printf("cannot save detail\n");
free(text_buf);
return 1;
}
len += wcslen(list_buf + len) + 1;
}
add_text(L";\r\n");
}
// 各ファイルのチェックサムを計算する
printf("\n");
print_progress_text(0, "Computing file hash");
len = 0;
while (len < list_len){
if (format == 1){
rv = create_sfv(uni_buf, list_buf + len, &prog_now, total_size);
} else if (format == 2){
rv = create_md5(uni_buf, list_buf + len, &prog_now, total_size);
} else {
rv = 1;
}
if (rv != 0){
free(text_buf);
return rv; // エラー、キャンセルなど
}
len += wcslen(list_buf + len) + 1;
}
print_progress_done(); // 改行して行の先頭に戻しておく
// 既存ファイルの alternate data stream に書き込む場合は更新日時をそのままにする
ads_p = wcschr(offset_file_name(checksum_file), ':');
if (ads_p != NULL){
*ads_p = 0;
hFile = CreateFile(checksum_file, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);
*ads_p = ':';
if (hFile == INVALID_HANDLE_VALUE){
ads_p = NULL;
} else {
if (!GetFileTime(hFile, NULL, NULL, &ftWrite)){
//print_win32_err();
//printf("cannot read time stamp\n");
ads_p = NULL;
}
CloseHandle(hFile);
}
}
// UTF-16 から UTF-8 に変換する
len = text_len * 3;
ascii_buf = (char *)malloc(len);
if (ascii_buf == NULL){
printf("malloc, %d\n", len);
free(text_buf);
return 1;
}
if (utf16_to_cp(text_buf, ascii_buf, len, CP_UTF8) != 0){
printf("cannot encode text\n");
free(ascii_buf);
free(text_buf);
return 1;
}
len = strlen(ascii_buf);
// チェックサム・ファイルを開いて、エンコードしたテキストを書き込む
hFile = CreateFile(checksum_file, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (hFile == INVALID_HANDLE_VALUE){
print_win32_err();
printf("cannot create checksum file\n");
free(ascii_buf);
free(text_buf);
return 1;
}
if (!WriteFile(hFile, ascii_buf, len, &rv, NULL)){
print_win32_err();
printf("cannot write checksum file\n");
CloseHandle(hFile);
free(ascii_buf);
free(text_buf);
return 1;
}
// main stream の更新日時を元に戻す
if (ads_p != NULL)
SetFileTime(hFile, NULL, NULL, &ftWrite);
CloseHandle(hFile); // チェックサム・ファイルを閉じる
free(ascii_buf);
free(text_buf);
printf("\nCreated successfully\n");
return 0;
}
// チェックサム・ファイルを読み込む
static long read_checksum(char *ascii_buf, wchar_t *file_path)
{
unsigned char *data_buf;
unsigned long err = 0, rv, file_size;
HANDLE hFile;
// 読み込むファイルを開く
hFile = CreateFile(checksum_file, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
if (hFile == INVALID_HANDLE_VALUE){
print_win32_err();
printf("cannot open checksum file\n");
return 1;
}
// 2MB を越えるチェックサム・ファイルには対応しない
file_size = GetFileSize(hFile, NULL);
if ((file_size == INVALID_FILE_SIZE) || (file_size > (2 << 21))){
CloseHandle(hFile);
printf("checksum file is too large\n");
return 1;
}
printf("Checksum Size\t: %d\n\n", file_size);
fflush(stdout);
// ハッシュ値を記録するには最低でも 1(ファイル名)+1(スペース)+8(CRC-32) = 10バイト必要
if (file_size < 10){
CloseHandle(hFile);
printf("Status : Damaged\n");
printf("valid file is not found\n");
return 1;
}
// ファイル全体を読み込む
data_buf = (unsigned char *)malloc(file_size + 2);
if (data_buf == NULL){
CloseHandle(hFile);
printf("malloc, %d\n", file_size);
return 1;
}
text_max = file_size + 1; // 全て ASCII 文字と仮定して、末尾に null 文字を付けた時の文字数
text_buf = (wchar_t *)malloc(text_max * 2);
if (text_buf == NULL){
free(data_buf);
CloseHandle(hFile);
printf("malloc, %d\n", text_max * 2);
return 1;
}
if (!ReadFile(hFile, data_buf, file_size, &rv, NULL) || (file_size != rv)){
free(data_buf);
free(text_buf);
CloseHandle(hFile);
printf("ReadFile, %d\n", file_size);
return 1;
}
CloseHandle(hFile);
data_buf[file_size ] = 0; // 末尾に null 文字を付けておく
data_buf[file_size + 1] = 0;
// UTF-16 の文字列に変換する
rv = utf16_to_utf16(data_buf, file_size + 2, text_buf);
if (rv != 0){ // UTF-16 ではなかった
if (check_utf8(data_buf) == 0){ // UTF-8 として変換する
rv = 0; // BOMが付いてるかどうか
if ((data_buf[0] == 0xEF) && (data_buf[1] == 0xBB) && (data_buf[2] == 0xBF))
rv = 3;
rv = cp_to_utf16(data_buf + rv, text_buf, file_size + 1, CP_UTF8);
} else {
rv = cp_to_utf16(data_buf, text_buf, file_size + 1, CP_ACP);
if (rv != 0)
rv = cp_to_utf16(data_buf, text_buf, file_size + 1, 1252); // Latin-1 CP1252 で変換を試みる
}
}
free(data_buf);
if (rv != 0){
free(text_buf);
printf("cannot decode text\n");
return 1;
}
text_len = wcslen(text_buf); // 文字数には末尾の null 文字を含まないことに注意
// チェックサムを検証する
rv = wcslen(checksum_file);
if (_wcsicmp(checksum_file + (rv - 4), L".sfv") == 0){ // SFVファイル
err = verify_sfv(ascii_buf, file_path);
} else if (_wcsicmp(checksum_file + (rv - 4), L".md5") == 0){ // MD5ファイル
err = verify_md5(ascii_buf, file_path);
// } else {
// err = 1;
// printf("unknown format\n");
}
free(text_buf);
close_ini_file();
// 検査結果を表示する
printf("\n");
if (err == 0){
printf("All Files Complete\n");
} else {
if (err & 16)
printf("Checksum File Incomplete\n");
if (err & 0xFFFFFF00){
printf("%d Files Missing or Damaged\n", err >> 8);
//err &= 0xFF;
}
err = ((err & 0x10) << 4) | (err & 0xEF); // 16を 256 に変更する
}
return err;
}
// チェックサム・ファイルとソース・ファイルの名前に問題が無いか確かめる
static long check_filename(
wchar_t *list_buf,
long list_len)
{
wchar_t *tmp_p;
long num, list_off = 0;
// SFV ファイル作成時に、ソース・ファイルの先頭が「;」だとコメントと区別できない
if (_wcsicmp(checksum_file + (wcslen(checksum_file) - 4), L".sfv") == 0){ // SFVファイル
for (num = 0; num < file_num; num++){
tmp_p = list_buf + list_off;
while (list_buf[list_off] != 0)
list_off++;
list_off++;
// ファイル名の先頭を調べる
if (tmp_p[0] == ';'){
printf_cp("filename is invalid, %s\n", tmp_p);
return 1;
}
}
}
// 基準ディレクトリ外にチェックサム・ファイルが存在するなら問題なし
if (_wcsnicmp(checksum_file, base_dir, base_len) != 0)
return 0;
// チェックサム・ファイルとソース・ファイルが同じ名前にならないようにする
for (num = 0; num < file_num; num++){
tmp_p = list_buf + list_off;
while (list_buf[list_off] != 0)
list_off++;
list_off++;
// ファイル名との一致を調べる
if (_wcsicmp(checksum_file + base_len, tmp_p) == 0){
printf_cp("filename is invalid, %s\n", tmp_p);
return 1;
}
}
return 0;
}
wmain(long argc, wchar_t *argv[])
{
char ascii_buf[MAX_LEN * 3];
wchar_t file_path[MAX_LEN], *tmp_p;
long i, j, switch_set = 0;
/*
t = switch_set & 0x00000003
fo= switch_set & 0x00000020
*/
printf("SFV/MD5 checker version " FILE_VERSION " by Yutaka Sawada\n\n");
if (argc < 3){
printf("Self-Test: ");
i = test_checksum(file_path);
if (i == 0){
printf("Success");
} else if (i == 2){
printf("PE checksum is different");
} else if (i == 3){
printf("CRC-32 is different");
} else {
printf("Error\0thedummytext");
}
printf("\n\n");
print_help();
return 0;
}
// 初期化
checksum_file[0] = 0;
base_dir[0] = 0;
ini_path[0] = 0;
file_num = 0;
cp_output = GetConsoleOutputCP();
// コマンド
switch (argv[1][0]){
case 'c': // create
case 'v': // verify
break;
default:
print_help();
return 0;
}
// オプションとチェックサム・ファイルの指定
for (i = 2; i < argc; i++){
tmp_p = argv[i];
// オプション
if (((tmp_p[0] == '/') || (tmp_p[0] == '-')) && (tmp_p[0] == argv[2][0])){
tmp_p++; // 先頭の識別文字をとばす
// オプション
if (wcscmp(tmp_p, L"u") == 0){
cp_output = CP_UTF8;
} else if (wcscmp(tmp_p, L"fo") == 0){
switch_set |= 0x20;
// オプション (数値)
} else if (wcsncmp(tmp_p, L"vs", 2) == 0){
recent_data = 0;
j = 2;
while ((j < 2 + 2) && (tmp_p[j] >= '0') && (tmp_p[j] <= '9')){
recent_data = (recent_data * 10) + (tmp_p[j] - '0');
j++;
}
if ((recent_data == 8) || (recent_data > 15))
recent_data = 0;
} else if (wcsncmp(tmp_p, L"t", 1) == 0){
j = -1;
if ((tmp_p[1] >= '0') && (tmp_p[1] <= '2')) // 02 の範囲
j = tmp_p[1] - '0';
if (j != -1)
switch_set |= j;
// オプション (文字列)
} else if (wcsncmp(tmp_p, L"vd", 2) == 0){
tmp_p += 2;
j = copy_path_prefix(ini_path, MAX_LEN - INI_NAME_LEN - 1, tmp_p, NULL);
if (j == 0){
printf("save-directory is invalid\n");
return 1;
}
if (ini_path[j - 1] != '\\'){ // 末尾が「\」でなければ付けておく
ini_path[j ] = '\\';
ini_path[j + 1] = 0;
}
//printf("Save Directory : %S\n", ini_path);
j = GetFileAttributes(ini_path);
if ((j == INVALID_FILE_ATTRIBUTES) || !(j & FILE_ATTRIBUTE_DIRECTORY)){
printf("save-directory is invalid\n");
return 1;
}
} else if (wcsncmp(tmp_p, L"d", 1) == 0){
tmp_p++;
j = copy_path_prefix(base_dir, MAX_LEN - 2, tmp_p, NULL); // 末尾に追加される分の余裕を見ておく
if (j == 0){
printf("base-directory is invalid\n");
return 1;
}
if (base_dir[j - 1] != '\\'){ // 末尾が「\」でなければ付けておく
base_dir[j ] = '\\';
base_dir[j + 1] = 0;
}
j = GetFileAttributes(base_dir);
if ((j == INVALID_FILE_ATTRIBUTES) || !(j & FILE_ATTRIBUTE_DIRECTORY)){
printf("base-directory is invalid\n");
return 1;
}
} else { // 未対応のオプション
utf16_to_cp(tmp_p - 1, ascii_buf, MAX_LEN * 3, cp_output);
printf("invalid option, %s\n", ascii_buf);
return 1;
}
continue;
}
// オプション以外ならリカバリ・ファイル
j = copy_path_prefix(checksum_file, MAX_LEN, tmp_p, NULL);
if (j == 0){
printf("checksum filename is invalid\n");
return 1;
}
// 拡張子は SFV か MD5 のみ
if (_wcsicmp(checksum_file + (j - 4), L".sfv") == 0){
init_crc_table(); // CRC 計算用のテーブルを作る
} else if (_wcsicmp(checksum_file + (j - 4), L".md5") == 0){
if (recent_data != 0)
init_crc_table();
} else { // 拡張子が違うなら
wcscpy(checksum_file + j, L".sfv"); // 標準で SFV 形式にする
if (argv[1][0] == 'c'){ // 作成なら
init_crc_table();
} else { // 検査なら
if (GetFileAttributes(checksum_file) == INVALID_FILE_ATTRIBUTES){
wcscpy(checksum_file + j, L".md5"); // SFV で駄目なら MD5 にする
if (GetFileAttributes(checksum_file) == INVALID_FILE_ATTRIBUTES){
printf("file format is unknown\n");
return 1;
} else if (recent_data != 0){
init_crc_table();
}
} else {
init_crc_table();
}
}
}
if (argv[1][0] == 'c'){ // 作成なら
// 指定されたファイル名が適切か調べる
if (sanitize_filename(offset_file_name(checksum_file)) != 0){
printf("checksum filename is invalid\n");
return 1;
}
} else { // 検査なら
j = GetFileAttributes(checksum_file);
if ((j == INVALID_FILE_ATTRIBUTES) || (j & FILE_ATTRIBUTE_DIRECTORY)){
wchar_t search_path[MAX_LEN];
long name_len, dir_len, path_len, find_flag = 0;
HANDLE hFind;
WIN32_FIND_DATA FindData;
if (wcspbrk(offset_file_name(checksum_file), L"*?") == NULL){
// 「*」や「?」で検索しない場合、ファイルが見つからなければエラーにする
printf("valid file is not found\n");
return 1;
}
// 指定された拡張子で検索する
path_len = wcslen(checksum_file);
hFind = FindFirstFile(checksum_file, &FindData);
if (hFind != INVALID_HANDLE_VALUE){
get_base_dir(checksum_file, search_path);
dir_len = wcslen(search_path);
do {
//printf("file name = %S\n", FindData.cFileName);
name_len = wcslen(FindData.cFileName);
if ((dir_len + name_len < MAX_LEN) && // ファイル名が長すぎない
(_wcsicmp(FindData.cFileName + (name_len - 4), checksum_file + (path_len - 4)) == 0)){ // 拡張子が同じ
find_flag = 1;
break; // 見つけたファイル名で問題なし
}
} while (FindNextFile(hFind, &FindData)); // 次のファイルを検索する
FindClose(hFind);
}
if (find_flag == 0){
printf("valid file is not found\n");
return 1;
}
wcscpy(checksum_file + dir_len, FindData.cFileName);
}
}
break;
}
if (checksum_file[0] == 0){ // チェックサム・ファイルが指定されてないなら
printf("checksum file is not specified\n");
return 1;
}
// input file の位置が指定されて無くて、
// 最初のソース・ファイル指定に絶対パスや相対パスが含まれてるなら、それを使う
if (argv[1][0] == 'c'){
if ((base_dir[0] == 0) && (i + 1 < argc)){
tmp_p = argv[i + 1];
if (is_full_path(tmp_p) != 0){ // 絶対パスなら
if (copy_path_prefix(file_path, MAX_LEN - 2, tmp_p, NULL) == 0){
printf("base-directory is invalid\n");
return 1;
}
get_base_dir(file_path, base_dir); // 最初のソース・ファイルの位置にする
if (len_without_prefix(base_dir) == 0) // サブ・ディレクトリが無ければ
base_dir[0] = 0;
}
}
}
if (base_dir[0] == 0) // input file の位置が指定されてないなら
get_base_dir(checksum_file, base_dir); // リカバリ・ファイルの位置にする
base_len = wcslen(base_dir);
// 動作環境の表示
// 「\\?\」は常に付加されてるので表示する際には無視する
printf_cp("Base Directory\t: \"%s\"\n", base_dir);
printf_cp("Checksum File\t: \"%s\"\n", checksum_file);
if (argv[1][0] == 'c'){
wchar_t *list_buf;
long dir_len, list_len, list_max;
__int64 total_size = 0; // 合計ファイル・サイズ
unsigned int filter;
// 隠しファイルやフォルダーを無視するかどうか
filter = get_show_hidden();
if (switch_set & 0x20)
filter |= FILE_ATTRIBUTE_DIRECTORY;
// チェックサム・ファイル作成ならソース・ファイルのリストがいる
i++;
if (i >= argc){
printf("input file is not specified\n");
return 1;
}
// 入力ファイルの指定
file_num = 0;
list_len = 0;
list_max = 0;
list_buf = NULL;
for (; i < argc; i++){
// ファイルが基準ディレクトリ以下に存在することを確認する
tmp_p = argv[i];
j = copy_path_prefix(file_path, MAX_LEN - 2, tmp_p, base_dir); // 絶対パスにしてから比較する
if (j == 0){
free(list_buf);
printf_cp("filename is invalid, %s\n", tmp_p);
return 1;
}
if ((j <= base_len) || (_wcsnicmp(base_dir, file_path, base_len) != 0)){ // 基準ディレクトリ外なら
free(list_buf);
printf_cp("out of base-directory, %s\n", tmp_p);
return 1;
}
//printf("%d = %S\n", i, argv[i]);
//printf_cp("search = %s\n", file_path);
// 「*」や「?」で検索しない場合、ファイルが見つからなければエラーにする
j = -1;
if (wcspbrk(file_path + base_len, L"*?") == NULL)
j = file_num;
// ファイルを検索する
dir_len = wcslen(file_path) - 2; // ファイル名末尾の「\」を無視して、ディレクトリ部分の長さを求める
while (file_path[dir_len] != '\\')
dir_len--;
dir_len++;
list_buf = search_files(list_buf, file_path, dir_len, filter, j, &list_max, &list_len, &total_size);
if (list_buf == NULL)
return 1;
if ((j != -1) && (j == file_num)){ // ファイルが見つかったか確かめる
free(list_buf);
printf_cp("input file is not found, %s\n", file_path + base_len);
return 1;
}
}
if (list_len == 0){
if (list_buf)
free(list_buf);
printf("input file is not found\n");
return 1;
}
if (check_filename(list_buf, list_len)){
free(list_buf);
return 1;
}
/*{
FILE *fp;
fp = fopen("list_buf.txt", "wb");
fwrite(list_buf, 2, list_len, fp);
fclose(fp);
}*/
// ファイル・リストの内容を並び替える (リストの末尾は null 1個にすること)
sort_list(list_buf, list_len);
printf("\nInput File count\t: %d\n", file_num);
printf("Input File total size\t: %I64d\n", total_size);
i = write_checksum(file_path, list_buf, list_len, total_size, switch_set & 3);
} else {
// 検査結果ファイルの位置が指定されてないなら
if ((recent_data != 0) && (ini_path[0] == 0)){
// 実行ファイルのディレクトリにする
j = GetModuleFileName(NULL, ini_path, MAX_LEN);
if ((j == 0) || (j >= MAX_LEN)){
printf("GetModuleFileName\n");
return 1;
}
while (j > 0){
if (ini_path[j - 1] == '\\'){
ini_path[j] = 0;
break;
}
j--;
}
if (j >= MAX_LEN - INI_NAME_LEN - 1){
printf("save-directory is invalid\n");
return 1;
}
}
i = read_checksum(ascii_buf, file_path);
}
//printf("ExitCode: %d\n", i);
return i;
}