// 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 #include #include #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] [input files]\n" "v(erify) [vs,vd,d,u] \n" "\nOption\n" " /fo : Search file only for wildcard\n" " /t : Save time stamp\n" " /vs: 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')) // 0~2 の範囲 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; }