Add files via upload
This commit is contained in:
1048
source/par1j/common1.c
Normal file
1048
source/par1j/common1.c
Normal file
File diff suppressed because it is too large
Load Diff
134
source/par1j/common1.h
Normal file
134
source/par1j/common1.h
Normal file
@@ -0,0 +1,134 @@
|
||||
#ifndef _COMMON_H_
|
||||
#define _COMMON_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
#define MAX_LEN 1024 // ファイル名の最大文字数 (末尾のNULL文字も含む)
|
||||
#define ADD_LEN 8 // 作業中にファイル名に追加する文字数
|
||||
#define EXT_LEN 16 // 拡張子として認識する最大文字数
|
||||
#define COMMENT_LEN 128 // コメントの最大文字数
|
||||
#define ALLOC_LEN 4096 // 可変長領域を何バイトごとに確保するか
|
||||
#define IO_SIZE 65536
|
||||
#define UPDATE_TIME 1024 // 更新間隔 ms
|
||||
|
||||
|
||||
// グローバル変数
|
||||
extern wchar_t recovery_file[MAX_LEN]; // リカバリ・ファイルのパス
|
||||
extern wchar_t base_dir[MAX_LEN]; // ソース・ファイルの基準ディレクトリ
|
||||
extern wchar_t ini_path[MAX_LEN]; // 検査結果ファイルのパス
|
||||
|
||||
extern unsigned int cp_output;
|
||||
|
||||
// Windown OS の precomposed UTF-16 から Console Output Code Page に変換する
|
||||
int utf16_to_cp(wchar_t *in, char *out);
|
||||
|
||||
// UTF-16 のファイル・パスを画面出力用の Code Page を使って表示する
|
||||
void printf_cp(unsigned char *format, wchar_t *path);
|
||||
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
// ファイル・パスがファイル・リスト上に既に存在するか調べる
|
||||
int search_file_path(
|
||||
wchar_t *list, // ファイル・リスト
|
||||
int total_len, // ファイル・リストの文字数
|
||||
wchar_t *search_file); // 検索するファイルのパス
|
||||
|
||||
// ファイル・リストの内容を並び替える
|
||||
void sort_list(
|
||||
wchar_t *list, // ファイル・リスト
|
||||
int total_len); // ファイル・リストの文字数
|
||||
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
// ファイル・パスからファイル名の位置を戻す
|
||||
wchar_t * offset_file_name(wchar_t *file_path);
|
||||
|
||||
// ファイル・パスからファイル名だけ取り出す
|
||||
void get_file_name(
|
||||
wchar_t *file_path, // ファイル・パス
|
||||
wchar_t *file_name); // ファイル名
|
||||
|
||||
// ファイル・パスからディレクトリだけ取り出す、末尾は「\」か「/」
|
||||
void get_base_dir(
|
||||
wchar_t *file_path, // ファイル・パス
|
||||
wchar_t *base_path); // ディレクトリ
|
||||
|
||||
// 絶対パスかどうかを判定する
|
||||
int is_full_path(wchar_t *path);
|
||||
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
// 相対パスを絶対パスに変換し、パスの先頭に "\\?\" を追加する
|
||||
// 戻り値 : 0=エラー, 5~=新しいパスの長さ
|
||||
int copy_path_prefix(
|
||||
wchar_t *new_path, // 新しいパス
|
||||
int max_len, // 新しいパスの最大長さ (末尾の null文字も含む)
|
||||
wchar_t *src_path, // 元のパス (相対パスでもよい)
|
||||
wchar_t *dir_path); // 相対パスの場合に基準となるディレクトリ (NULL ならカレント・ディレクトリ)
|
||||
|
||||
// ファイル・パスから、先頭にある "\\?\" を省いた長さを戻す
|
||||
int len_without_prefix(wchar_t *file_path);
|
||||
|
||||
// ファイル・パスから、先頭にある "\\?\" を省いてコピーする
|
||||
int copy_without_prefix(
|
||||
wchar_t *dst_path, // コピー先
|
||||
wchar_t *src_path); // コピー元のパス
|
||||
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
// ファイルを置き換える (ファイル名の修正、テンポラリー・ファイルからの書き戻しなど)
|
||||
int replace_file(
|
||||
wchar_t *dest_path, // 置き換える先のパス (移動先、修正されたファイル名)
|
||||
wchar_t *sorc_path, // 置き換える元のパス (移動元、現在のファイル名)
|
||||
int switch_b); // 既存のファイルをバックアップするかどうか
|
||||
|
||||
// ファイルを指定サイズに縮小する
|
||||
int shorten_file(
|
||||
wchar_t *file_path, // ファイル・パス
|
||||
__int64 new_size,
|
||||
int switch_b); // 既存のファイルをバックアップするかどうか
|
||||
|
||||
// ファイル名が有効か確かめて、問題があれば浄化する
|
||||
int sanitize_filename(wchar_t *name);
|
||||
|
||||
// 修復中のテンポラリ・ファイルの名前を作る
|
||||
void get_temp_name(
|
||||
wchar_t *file_path, // ファイル・パス
|
||||
wchar_t *temp_path); // テンポラリ・ファイルのパス
|
||||
|
||||
void print_hash(unsigned char hash[16]);
|
||||
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
extern unsigned int memory_use; // メモリー使用量 0=auto, 1~7 -> 1/8 ~ 7/8
|
||||
|
||||
// 空きメモリー量と制限値から使用できるメモリー量を計算する
|
||||
unsigned int get_mem_size(unsigned __int64 data_size);
|
||||
|
||||
extern int prog_last; // 前回と同じ進捗状況は出力しないので記録しておく
|
||||
|
||||
// 経過のパーセント表示、キャンセルと一時停止ができる
|
||||
// 普段は 0 を返す、キャンセル時は 0以外
|
||||
int print_progress(int prog_now); // 表示する % 値
|
||||
void print_progress_text(int prog_now, char *text);
|
||||
int print_progress_file(int prog_now, wchar_t *file_name);
|
||||
void print_progress_done(void);
|
||||
|
||||
// キャンセルと一時停止を行う
|
||||
int cancel_progress(void);
|
||||
|
||||
// Win32 API のエラー・メッセージを表示する
|
||||
void print_win32_err(void);
|
||||
|
||||
// ファイルをゴミ箱に移す
|
||||
int delete_file_recycle(wchar_t *file_path);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
205
source/par1j/gf8.c
Normal file
205
source/par1j/gf8.c
Normal file
@@ -0,0 +1,205 @@
|
||||
// This is a sub-set of Galois.c
|
||||
// Modified by Yutaka Sawada for 8-bit only
|
||||
|
||||
/* Galois.c
|
||||
* James S. Plank
|
||||
* April, 2007
|
||||
|
||||
Galois.tar - Fast Galois Field Arithmetic Library in C/C++
|
||||
Copright (C) 2007 James S. Plank
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License aint with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
James S. Plank
|
||||
Department of Computer Science
|
||||
University of Tennessee
|
||||
Knoxville, TN 37996
|
||||
plank@cs.utk.edu
|
||||
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "gf8.h"
|
||||
|
||||
#define NW 256
|
||||
#define NWM1 255
|
||||
#define PRIM_POLY 0x11D
|
||||
|
||||
static int *galois_log_table = NULL;
|
||||
static int *galois_exp_table;
|
||||
|
||||
static int *galois_mult_table = NULL;
|
||||
static int *galois_div_table;
|
||||
|
||||
int galois_create_log_tables(void)
|
||||
{
|
||||
int j, b;
|
||||
|
||||
if (galois_log_table != NULL) return 0;
|
||||
galois_log_table = _aligned_malloc(sizeof(int) * NW * 4, 64);
|
||||
if (galois_log_table == NULL) return -1;
|
||||
galois_exp_table = galois_log_table + NW + 1; // 後で境界をあわせるため
|
||||
|
||||
b = 1;
|
||||
for (j = 0; j < NWM1; j++){
|
||||
galois_log_table[b] = j;
|
||||
galois_exp_table[j] = b;
|
||||
b = b << 1;
|
||||
if (b & NW) b ^= PRIM_POLY;
|
||||
}
|
||||
galois_log_table[0] = -1;
|
||||
|
||||
for (j = 0; j < NWM1; j++){
|
||||
galois_exp_table[j + NWM1 ] = galois_exp_table[j];
|
||||
galois_exp_table[j + NWM1 * 2] = galois_exp_table[j];
|
||||
}
|
||||
galois_exp_table += NWM1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int galois_create_mult_tables(void)
|
||||
{
|
||||
int j, x, y, logx;
|
||||
|
||||
if (galois_mult_table != NULL) return 0;
|
||||
galois_mult_table = _aligned_malloc(sizeof(int) * NW * NW * 2, 64);
|
||||
if (galois_mult_table == NULL) return -1;
|
||||
galois_div_table = galois_mult_table + NW * NW;
|
||||
|
||||
if (galois_log_table == NULL) {
|
||||
if (galois_create_log_tables() < 0) {
|
||||
_aligned_free(galois_mult_table);
|
||||
galois_mult_table = NULL;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Set mult/div tables for x = 0 */
|
||||
j = 0;
|
||||
galois_mult_table[j] = 0; /* y = 0 */
|
||||
galois_div_table[j] = -1;
|
||||
j++;
|
||||
for (y = 1; y < NW; y++) { /* y > 0 */
|
||||
galois_mult_table[j] = 0;
|
||||
galois_div_table[j] = 0;
|
||||
j++;
|
||||
}
|
||||
|
||||
for (x = 1; x < NW; x++){ /* x > 0 */
|
||||
galois_mult_table[j] = 0; /* y = 0 */
|
||||
galois_div_table[j] = -1;
|
||||
j++;
|
||||
logx = galois_log_table[x];
|
||||
for (y = 1; y < NW; y++){ /* y > 0 */
|
||||
galois_mult_table[j] = galois_exp_table[logx + galois_log_table[y]];
|
||||
galois_div_table[j] = galois_exp_table[logx - galois_log_table[y]];
|
||||
j++;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int galois_multtable_multiply(int x, int y)
|
||||
{
|
||||
return galois_mult_table[(x << 8) | y];
|
||||
}
|
||||
|
||||
int galois_multtable_divide(int x, int y)
|
||||
{
|
||||
return galois_div_table[(x << 8) | y];
|
||||
}
|
||||
|
||||
// ガロア体上での乗数計算、x の y 乗
|
||||
int galois_power(int x, int y)
|
||||
{
|
||||
int sum_j;
|
||||
|
||||
if (y == 0) return 1; // x^0 = 1
|
||||
sum_j = x;
|
||||
while (y > 1){
|
||||
sum_j = galois_multtable_multiply(sum_j, x);
|
||||
y--;
|
||||
}
|
||||
return sum_j;
|
||||
}
|
||||
|
||||
void galois_free_tables(void) // テーブルを一括して解放するために追加
|
||||
{
|
||||
if (galois_mult_table != NULL) {
|
||||
_aligned_free(galois_mult_table);
|
||||
galois_mult_table = NULL;
|
||||
}
|
||||
if (galois_log_table != NULL) {
|
||||
_aligned_free(galois_log_table);
|
||||
galois_log_table = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void galois_region_xor(
|
||||
unsigned char *r1, // Region 1
|
||||
unsigned char *r2, // Sum region (r2 = r1 ^ r2)
|
||||
int nbytes) // Number of bytes in region
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < nbytes; i++)
|
||||
r2[i] ^= r1[i];
|
||||
}
|
||||
|
||||
void galois_region_multiply(
|
||||
unsigned char *r1, // Region to multiply
|
||||
unsigned char *r2, // products go here.
|
||||
int nbytes, // Number of bytes in region
|
||||
int multby) // Number to multiply by
|
||||
{
|
||||
int i, *table;
|
||||
|
||||
table = galois_mult_table + (multby << 8);
|
||||
for (i = 0; i < nbytes; i++)
|
||||
r2[i] ^= table[ r1[i] ];
|
||||
}
|
||||
|
||||
// チェックサムを計算する
|
||||
void checksum4(unsigned char *data, unsigned char *hash, int byte_size)
|
||||
{
|
||||
int i, count;
|
||||
unsigned int *data4, temp, prev, mask;
|
||||
|
||||
data4 = (unsigned int *)data;
|
||||
count = byte_size / 4;
|
||||
prev = 0;
|
||||
|
||||
while (count > 0){ // HASH_RANGE バイトごとに
|
||||
// 4バイトに XOR する
|
||||
temp = 0;
|
||||
for (i = 0; i < HASH_RANGE / 4; i++){
|
||||
temp ^= data4[i];
|
||||
count--;
|
||||
if (count == 0)
|
||||
break;
|
||||
}
|
||||
data4 += HASH_RANGE / 4;
|
||||
|
||||
// 前回の値を 2倍して、今回の値を追加する
|
||||
mask = (prev & 0x80808080) >> 7; // 0x01010101 or 0x00000000
|
||||
prev = (prev & 0x7F7F7F7F) << 1; // 3倍する場合は「^=」にすればいい
|
||||
prev ^= mask * 0x1D; // 0x1D1D1D1D or 0x00000000
|
||||
|
||||
prev ^= temp;
|
||||
}
|
||||
*((unsigned int *)hash) = prev;
|
||||
}
|
||||
|
||||
67
source/par1j/gf8.h
Normal file
67
source/par1j/gf8.h
Normal file
@@ -0,0 +1,67 @@
|
||||
// This is a sub-set of Galois.h , and changed for 8-bit only
|
||||
|
||||
/* Galois.h
|
||||
* James S. Plank
|
||||
|
||||
Galois.tar - Fast Galois Field Arithmetic Library in C/C++
|
||||
Copright (C) 2007 James S. Plank
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
James S. Plank
|
||||
Department of Computer Science
|
||||
University of Tennessee
|
||||
Knoxville, TN 37996
|
||||
plank@cs.utk.edu
|
||||
|
||||
*/
|
||||
|
||||
#ifndef _GF8_H_
|
||||
#define _GF8_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
extern int galois_create_log_tables(void); /* Returns 0 on success, -1 on failure */
|
||||
extern int galois_create_mult_tables(void);
|
||||
extern int galois_multtable_multiply(int x, int y);
|
||||
extern int galois_multtable_divide(int x, int y);
|
||||
|
||||
extern int galois_power(int x, int y); // 乗数計算用に追加
|
||||
extern void galois_free_tables(void); // 解放用に追加
|
||||
|
||||
void galois_region_xor(
|
||||
unsigned char *r1, // Region 1
|
||||
unsigned char *r2, // Sum region (r2 = r1 ^ r2)
|
||||
int nbytes); // Number of bytes in region
|
||||
|
||||
void galois_region_multiply(
|
||||
unsigned char *r1, // Region to multiply
|
||||
unsigned char *r2, // products go here.
|
||||
int nbytes, // Number of bytes in region
|
||||
int multby); // Number to multiply by
|
||||
|
||||
#define HASH_SIZE 4
|
||||
#define HASH_RANGE 128
|
||||
void checksum4(unsigned char *data, unsigned char *hash, int byte_size);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
446
source/par1j/ini.c
Normal file
446
source/par1j/ini.c
Normal file
@@ -0,0 +1,446 @@
|
||||
// ini.c
|
||||
// Copyright : 2022-01-15 Yutaka Sawada
|
||||
// License : GPL
|
||||
|
||||
#ifndef _UNICODE
|
||||
#define _UNICODE
|
||||
#endif
|
||||
#ifndef UNICODE
|
||||
#define UNICODE
|
||||
#endif
|
||||
#ifndef _WIN32_WINNT
|
||||
#define _WIN32_WINNT 0x0600 // Windows Vista or later
|
||||
#endif
|
||||
|
||||
#include <malloc.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include "common1.h"
|
||||
#include "ini.h"
|
||||
|
||||
/*
|
||||
ファイル名は 1_#.bin (2+32+4 = 38文字)
|
||||
「#」部分は Set ID を 16進数表記にする。
|
||||
|
||||
ファイル・フォーマット
|
||||
<!-- 検査結果ファイル識別用 -->
|
||||
2: 検査結果の書式バージョン
|
||||
4: 6バイト目以降からの CRC-32 チェックサム
|
||||
<!-- リカバリ・セットの識別用 -->
|
||||
4: ソース・ブロック数 (PAR1ではブロックを持つファイルだけが Set ID に反映される)
|
||||
|
||||
<!-- 検査状態をファイルごとに記録する -->
|
||||
前半 13バイトでファイル項目を識別して、後半 17バイトに状態を保存する。
|
||||
1: 0~255=ソース・ファイル番号 (リカバリ・ファイルは常に 255)
|
||||
4: ボリュームのシリアル番号
|
||||
8: ファイルのオブジェクトID
|
||||
8: ソース・ファイルのサイズ
|
||||
4: ソース・ファイルの作成日時
|
||||
4: ソース・ファイルの更新日時
|
||||
1: ファイルの状態 0=完全, 1=破損あるいはエラー, 4=追加, +16=リカバリ・ファイル
|
||||
|
||||
*/
|
||||
|
||||
#define INI_VERSION 0x1270 // 検査結果の書式が決まった時のバージョン
|
||||
#define REUSE_MIN 16384 // ファイル・サイズがこれより大きければ検査結果を利用する (16KB 以上 2GB 未満)
|
||||
#define HEADER_SIZE 10
|
||||
#define STATE_SIZE 30
|
||||
#define STATE_READ 136
|
||||
//#define VERBOSE 1 // 状態を冗長に出力する
|
||||
|
||||
static HANDLE hIniBin = NULL; // バイナリ・データ用の検査結果ファイル
|
||||
static int ini_off;
|
||||
|
||||
// 検査結果をどのくらいの期間保存するか
|
||||
int recent_data = 0;
|
||||
/*
|
||||
0 = 検査結果の再利用機能を無効にする(読み込まないし、記録もしない)
|
||||
1~7= 前回の検査結果を読み込んで、今回のを記録する。
|
||||
指定された期間よりも経過した古い記録は削除される。
|
||||
1= 1日, 2= 3日, 3= 1週間, 4= 半月, 5= 1ヶ月, 6= 1年, 7= 無制限
|
||||
+8 = 同じセットの記録を削除する、今回の結果は記録する。
|
||||
他のセットは指定された期間よりも古いものだけ削除する。
|
||||
*/
|
||||
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
// File Time (UTC) を UNIX Time (UTC) に変換する
|
||||
static unsigned int time_f_u(FILETIME *file_time)
|
||||
{
|
||||
unsigned __int64 int8;
|
||||
|
||||
// 1970/01/01 の File Time との差を求める
|
||||
memcpy(&int8, file_time, 8);
|
||||
int8 = (int8 - 116444736000000000) / 10000000;
|
||||
|
||||
return (unsigned int)int8;
|
||||
}
|
||||
|
||||
#ifdef VERBOSE
|
||||
// File Time (UTC) を日付の文字列に変換する
|
||||
static void time_f_date(FILETIME *ft, char *buf)
|
||||
{
|
||||
int len;
|
||||
SYSTEMTIME st_utc, st;
|
||||
|
||||
FileTimeToSystemTime(ft, &st_utc);
|
||||
if (SystemTimeToTzSpecificLocalTime(NULL, &st_utc, &st) == 0)
|
||||
memcpy(&st, &st_utc, sizeof(SYSTEMTIME));
|
||||
len = GetDateFormatA(LOCALE_USER_DEFAULT, DATE_SHORTDATE | LOCALE_USE_CP_ACP, &st, NULL, buf, 32);
|
||||
if (len > 0){
|
||||
buf[len - 1] = ' ';
|
||||
len = GetTimeFormatA(LOCALE_USER_DEFAULT, LOCALE_USE_CP_ACP, &st, NULL, buf + len, 32 - len);
|
||||
}
|
||||
if (len == 0){
|
||||
wsprintfA(buf, "%4d/%02d/%02d %2d:%02d:%02d",
|
||||
st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// 2GB 未満のファイルの開始位置以降のハッシュ値を計算する
|
||||
static unsigned int file_crc_part(HANDLE hFile)
|
||||
{
|
||||
unsigned char buf[4096], *p;
|
||||
unsigned int rv, crc = 0xFFFFFFFF;
|
||||
unsigned int len, tmp, i;
|
||||
|
||||
// 末尾まで読み込む
|
||||
do {
|
||||
if (!ReadFile(hFile, buf, 4096, &rv, NULL) || (rv == 0))
|
||||
break;
|
||||
// CRC-32 計算
|
||||
p = buf;
|
||||
len = rv;
|
||||
while (len--){
|
||||
tmp = (*p++);
|
||||
for (i = 0; i < 8; i++){
|
||||
if ((tmp ^ crc) & 1){
|
||||
crc = (crc >> 1) ^ 0xEDB88320;
|
||||
} else {
|
||||
crc = crc >> 1;
|
||||
}
|
||||
tmp = tmp >> 1;
|
||||
}
|
||||
}
|
||||
} while (rv > 0);
|
||||
|
||||
return crc ^ 0xFFFFFFFF;
|
||||
}
|
||||
|
||||
// .BIN ファイルの offset バイト目から size バイトのデータを buf に読み込む
|
||||
static int file_read_bin(
|
||||
int offset,
|
||||
unsigned char *buf,
|
||||
unsigned int size)
|
||||
{
|
||||
unsigned int rv;
|
||||
|
||||
// ファイルの位置を offsetバイト目にする
|
||||
rv = SetFilePointer(hIniBin, offset, NULL, FILE_BEGIN);
|
||||
if (rv == INVALID_SET_FILE_POINTER)
|
||||
return 1;
|
||||
|
||||
// size バイトを読み込む
|
||||
if ((!ReadFile(hIniBin, buf, size, &rv, NULL)) || (size != rv))
|
||||
return 1; // 指定サイズを読み込めなかったらエラーになる
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// .BIN ファイルの offset バイト目に size バイトのデータを buf から書き込む
|
||||
static int file_write_bin(
|
||||
int offset,
|
||||
unsigned char *buf,
|
||||
unsigned int size)
|
||||
{
|
||||
unsigned int rv;
|
||||
|
||||
// ファイルの位置を offsetバイト目にする
|
||||
rv = SetFilePointer(hIniBin, offset, NULL, FILE_BEGIN);
|
||||
if (rv == INVALID_SET_FILE_POINTER)
|
||||
return 1;
|
||||
|
||||
// size バイトを書き込む
|
||||
if (!WriteFile(hIniBin, buf, size, &rv, NULL))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
// 検査結果ファイルを利用する為の関数
|
||||
|
||||
// ini_path で指定されてる検査結果ファイルを削除する
|
||||
static void delete_ini_file(void)
|
||||
{
|
||||
// 開いてるなら閉じる
|
||||
if (hIniBin != NULL){
|
||||
CloseHandle(hIniBin);
|
||||
hIniBin = NULL;
|
||||
}
|
||||
|
||||
DeleteFile(ini_path); // .bin ファイルを削除する
|
||||
|
||||
recent_data = 0; // これ以降は検査結果は利用できない
|
||||
}
|
||||
|
||||
// 検査するチェックサム・ファイルが同じであれば、再検査する必要は無い
|
||||
int check_ini_file(unsigned char *set_hash, int block_num)
|
||||
{
|
||||
unsigned char set_data[HEADER_SIZE * 2];
|
||||
wchar_t path[MAX_LEN], ini_name[INI_NAME_LEN + 1];
|
||||
int i, match;
|
||||
unsigned int file_time, time_now, time_limit;
|
||||
HANDLE hFind;
|
||||
WIN32_FIND_DATA FindData;
|
||||
FILETIME ft;
|
||||
|
||||
if (recent_data == 0)
|
||||
return 0;
|
||||
|
||||
// 設定ファイルのパス
|
||||
swprintf(ini_name, _countof(ini_name), L"1_%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X.bin",
|
||||
set_hash[0], set_hash[1], set_hash[2], set_hash[3], set_hash[4], set_hash[5], set_hash[6], set_hash[7],
|
||||
set_hash[8], set_hash[9], set_hash[10], set_hash[11],set_hash[12], set_hash[13], set_hash[14], set_hash[15]);
|
||||
|
||||
// 期限を設定する
|
||||
switch (recent_data & 7){
|
||||
case 1:
|
||||
time_limit = 3600 * 24; // 1 day
|
||||
break;
|
||||
case 2:
|
||||
time_limit = 3600 * 24 * 3; // 3 days
|
||||
break;
|
||||
case 3:
|
||||
time_limit = 3600 * 24 * 7; // 1 week
|
||||
break;
|
||||
case 4:
|
||||
time_limit = 3600 * 24 * 15; // half month
|
||||
break;
|
||||
case 5:
|
||||
time_limit = 3600 * 24 * 30; // 1 month
|
||||
break;
|
||||
case 6:
|
||||
time_limit = 3600 * 24 * 365; // 1 year
|
||||
break;
|
||||
case 7:
|
||||
time_limit = 0xFFFFFFFF; // unlimited
|
||||
break;
|
||||
default: // 期間が指定されてない
|
||||
recent_data = 0;
|
||||
return 0;
|
||||
}
|
||||
GetSystemTimeAsFileTime(&ft); // 現在のシステム時刻 (UTC) を取得する
|
||||
time_now = time_f_u(&ft); // UNIX Time に変換する
|
||||
|
||||
// 記録の日時を調べて、古いのは削除する
|
||||
match = 0;
|
||||
wcscpy(path, ini_path);
|
||||
wcscat(path, L"1_*.bin"); // 文字数は後でチェックする
|
||||
hFind = FindFirstFile(path, &FindData);
|
||||
if (hFind != INVALID_HANDLE_VALUE){
|
||||
do {
|
||||
if (((FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0) &&
|
||||
(wcslen(FindData.cFileName) == INI_NAME_LEN)){
|
||||
// 指定時間より古い記録は削除する
|
||||
file_time = time_f_u(&(FindData.ftLastWriteTime)); // 更新日時
|
||||
if (time_now - file_time > time_limit){
|
||||
wcscpy(path, ini_path);
|
||||
wcscat(path, FindData.cFileName);
|
||||
DeleteFile(path);
|
||||
#if VERBOSE > 1
|
||||
time_f_date(&(FindData.ftLastWriteTime), (char *)path);
|
||||
printf("Delete result: %S, %s\n", FindData.cFileName, (char *)path);
|
||||
#endif
|
||||
} else if (wcscmp(FindData.cFileName, ini_name) == 0){
|
||||
if (recent_data & 8){ // 検査結果を読み込まないが、今回のは書き込む場合
|
||||
// 以前の検査結果が存在すれば削除する
|
||||
wcscpy(path, ini_path);
|
||||
wcscat(path, ini_name);
|
||||
DeleteFile(path);
|
||||
#if VERBOSE > 1
|
||||
printf("Delete result: %S\n", ini_name);
|
||||
#endif
|
||||
} else {
|
||||
match = 1; // 設定ファイルが存在する
|
||||
}
|
||||
#ifdef VERBOSE
|
||||
ft = FindData.ftLastWriteTime; // 検査結果の更新日時
|
||||
#endif
|
||||
}
|
||||
}
|
||||
} while (FindNextFile(hFind, &FindData)); // 次のファイルを検索する
|
||||
FindClose(hFind);
|
||||
}
|
||||
|
||||
// バイナリ・データ用の設定ファイルを開く
|
||||
wcscat(ini_path, ini_name);
|
||||
hIniBin = CreateFile(ini_path, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_FLAG_RANDOM_ACCESS, NULL);
|
||||
if (hIniBin == INVALID_HANDLE_VALUE){
|
||||
hIniBin = NULL;
|
||||
recent_data = 0; // 開けない場合は再利用しない
|
||||
return 0;
|
||||
}
|
||||
//printf("ini file path = %S\n", ini_path);
|
||||
|
||||
// 既に同名の (Set ID が同じ) ファイルが存在する場合
|
||||
set_data[0] = INI_VERSION >> 8; // 検査結果の書式バージョン
|
||||
set_data[1] = INI_VERSION & 0xFF;
|
||||
memset(set_data + 2, 0, 4); // CRC-32 は後で書き込む
|
||||
memcpy(set_data + 6, &block_num, 4);
|
||||
if (match != 0){ // ID が同じでも Set 内容が異なる場合は初期化する
|
||||
i = file_read_bin(0, set_data + HEADER_SIZE, HEADER_SIZE);
|
||||
if ((set_data[HEADER_SIZE ] != (INI_VERSION >> 8)) ||
|
||||
(set_data[HEADER_SIZE + 1] != (INI_VERSION & 0xFF))){
|
||||
i = 1; // 古いバージョンの検査結果は参照しない
|
||||
}
|
||||
if (i == 0){ // 検査結果が破損してないか確かめる
|
||||
if (SetFilePointer(hIniBin, 6, 0, FILE_BEGIN) != INVALID_SET_FILE_POINTER)
|
||||
time_now = file_crc_part(hIniBin);
|
||||
i = memcmp(&time_now, set_data + (HEADER_SIZE + 2), 4);
|
||||
}
|
||||
if (i == 0) // ソース・ブロック数を比較する
|
||||
i = memcmp(set_data + 6, set_data + (HEADER_SIZE + 6), HEADER_SIZE - 6);
|
||||
if (i != 0) // ID が同じでも Set 内容が異なる場合は初期化する
|
||||
match = 0;
|
||||
}
|
||||
|
||||
// 一致しなかった場合は今回のデータを記録する
|
||||
if (match == 0){
|
||||
// 今回のデータを書き込む
|
||||
if (file_write_bin(0, set_data, HEADER_SIZE) != 0){
|
||||
delete_ini_file();
|
||||
return 0;
|
||||
}
|
||||
if (SetEndOfFile(hIniBin) == 0){
|
||||
delete_ini_file();
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
#ifdef VERBOSE
|
||||
} else {
|
||||
time_f_date(&ft, (char *)path);
|
||||
printf("Date of result: %s\n", (char *)path);
|
||||
#endif
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
// 検査結果ファイルを閉じる
|
||||
void close_ini_file(void)
|
||||
{
|
||||
if ((recent_data != 0) && (hIniBin != NULL)){
|
||||
unsigned int new_crc, old_crc;
|
||||
|
||||
// 閉じる前に検査結果の CRC-32 を計算して記録しておく
|
||||
FlushFileBuffers(hIniBin);
|
||||
file_read_bin(2, (unsigned char *)&old_crc, 4);
|
||||
new_crc = file_crc_part(hIniBin);
|
||||
if (new_crc != old_crc) // 検査結果が同じなら更新しない
|
||||
file_write_bin(2, (unsigned char *)&new_crc, 4);
|
||||
CloseHandle(hIniBin);
|
||||
hIniBin = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
// 検査結果が記録されてるかどうか
|
||||
// -1=エラー, -2=記録なし、またはファイル項目はあるが状態が変化してる
|
||||
// ファイルの状態 0=完全, 1=破損, 2=追加
|
||||
int check_ini_state(
|
||||
int num, // ファイル番号
|
||||
unsigned int meta[7], // サイズ、作成日時、更新日時、ボリューム番号、オブジェクト番号
|
||||
HANDLE hFile) // そのファイルのハンドル
|
||||
{
|
||||
unsigned char buf[STATE_SIZE * STATE_READ], buf2[STATE_SIZE];
|
||||
unsigned int rv, off;
|
||||
BY_HANDLE_FILE_INFORMATION fi;
|
||||
|
||||
// 現在のファイル属性を取得する
|
||||
memset(&fi, 0, sizeof(BY_HANDLE_FILE_INFORMATION));
|
||||
if (GetFileInformationByHandle(hFile, &fi) != 0){
|
||||
meta[0] = fi.nFileSizeLow;
|
||||
meta[1] = fi.nFileSizeHigh;
|
||||
if ((recent_data == 0) || ((fi.nFileSizeLow <= REUSE_MIN) && (fi.nFileSizeHigh == 0)))
|
||||
return -2; // 小さなファイルは記録を参照しない
|
||||
meta[2] = time_f_u(&(fi.ftCreationTime));
|
||||
meta[3] = time_f_u(&(fi.ftLastWriteTime));
|
||||
meta[4] = fi.dwVolumeSerialNumber;
|
||||
meta[5] = fi.nFileIndexLow;
|
||||
meta[6] = fi.nFileIndexHigh;
|
||||
} else {
|
||||
return -1; // 属性の読み取りエラー
|
||||
}
|
||||
|
||||
// 参照するファイル項目
|
||||
buf2[0] = (unsigned char)(num & 0xFF);
|
||||
memcpy(buf2 + 1, meta + 4, 12);
|
||||
memcpy(buf2 + 13, meta, 16);
|
||||
buf2[29] = (unsigned char)(num >> 8);
|
||||
|
||||
// ヘッダーの直後から開始する
|
||||
if (SetFilePointer(hIniBin, HEADER_SIZE, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER){
|
||||
delete_ini_file();
|
||||
return -2;
|
||||
}
|
||||
ini_off = HEADER_SIZE; // ファイル項目の位置
|
||||
// 一度に STATE_READ 個ずつ読み込む
|
||||
while (ReadFile(hIniBin, buf, STATE_SIZE * STATE_READ, &rv, NULL) != 0){
|
||||
if (rv < STATE_SIZE)
|
||||
break;
|
||||
// ファイル識別番号から同じファイルの記録を探す
|
||||
for (off = 0; off < rv; off += STATE_SIZE){
|
||||
if ((memcmp(buf + off, buf2, 13) == 0) && ((buf[off + 29] & 0x10) == buf2[29])){
|
||||
ini_off += off; // 同じファイルの記録があった
|
||||
#ifdef VERBOSE
|
||||
printf("check state, num = %d, offset = %d, state = 0x%02X\n", num & 0xFF, ini_off, buf[off + 29]);
|
||||
#endif
|
||||
// ファイルのサイズと日時を比較する
|
||||
if (memcmp(buf + (off + 13), buf2 + 13, 16) == 0)
|
||||
return buf[off + 29] & 0x0F;
|
||||
return -2; // 状態が変化してる
|
||||
}
|
||||
}
|
||||
ini_off += rv;
|
||||
}
|
||||
|
||||
ini_off = 0;
|
||||
return -2; // これ以上の検査記録は無い
|
||||
}
|
||||
|
||||
// ソース・ファイル状態は完全か破損だけ (消失だと検査しない)
|
||||
void write_ini_state(
|
||||
int num, // ファイル番号
|
||||
unsigned int meta[7], // サイズ、作成日時、更新日時、ボリューム番号、オブジェクト番号
|
||||
int state) // 状態、0=完全, 1=破損, 2=追加
|
||||
{
|
||||
unsigned char buf[STATE_SIZE];
|
||||
|
||||
if ((recent_data == 0) || ((meta[0] <= REUSE_MIN) && (meta[1] == 0)))
|
||||
return; // 小さなファイルは検査結果を記録しない
|
||||
|
||||
if (ini_off == 0){ // 記録が無ければ末尾に追加する
|
||||
ini_off = GetFileSize(hIniBin, NULL);
|
||||
if (ini_off == INVALID_FILE_SIZE){
|
||||
delete_ini_file();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// 今回の状態を書き込む
|
||||
buf[0] = (unsigned char)(num & 0xFF);
|
||||
memcpy(buf + 1, meta + 4, 12);
|
||||
memcpy(buf + 13, meta, 16);
|
||||
buf[29] = (unsigned char)((state & 0x0F) | (num >> 8));
|
||||
#ifdef VERBOSE
|
||||
printf("write state, num = %d, offset = %d, state = 0x%02X\n", num & 0xFF, ini_off, buf[29]);
|
||||
#endif
|
||||
if (file_write_bin(ini_off, buf, STATE_SIZE) != 0){
|
||||
delete_ini_file();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
32
source/par1j/ini.h
Normal file
32
source/par1j/ini.h
Normal file
@@ -0,0 +1,32 @@
|
||||
#ifndef _INI_H_
|
||||
#define _INI_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
#define INI_NAME_LEN 38 // 検査結果ファイルのファイル名の文字数
|
||||
|
||||
extern int recent_data;
|
||||
|
||||
int check_ini_file(unsigned char *set_hash, int file_num);
|
||||
void close_ini_file(void);
|
||||
void write_ini_file(void);
|
||||
|
||||
int check_ini_state(
|
||||
int num, // ファイル番号
|
||||
unsigned int meta[7], // サイズ、作成日時、更新日時、ボリューム番号、オブジェクト番号
|
||||
HANDLE hFile); // そのファイルのハンドル
|
||||
|
||||
void write_ini_state(
|
||||
int num, // ファイル番号
|
||||
unsigned int meta[7], // サイズ、作成日時、更新日時、ボリューム番号、オブジェクト番号
|
||||
int state); // 状態
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
223
source/par1j/md5_1.c
Normal file
223
source/par1j/md5_1.c
Normal file
@@ -0,0 +1,223 @@
|
||||
// md5_1.c
|
||||
// Copyright : 2021-05-14 Yutaka Sawada
|
||||
// License : GPL
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include "common1.h"
|
||||
#include "phmd5.h"
|
||||
#include "md5_1.h"
|
||||
|
||||
|
||||
// バイト配列の MD5 ハッシュ値を求める
|
||||
void data_md5(
|
||||
unsigned char *data_in, // ハッシュ値を求めるバイト配列
|
||||
unsigned int data_len, // 入力バイト数
|
||||
unsigned char *hash) // ハッシュ値 16バイト
|
||||
{
|
||||
PHMD5 ctx;
|
||||
|
||||
Phmd5Begin(&ctx);
|
||||
Phmd5Process(&ctx, data_in, data_len);
|
||||
Phmd5End(&ctx);
|
||||
memcpy(hash, ctx.hash, 16);
|
||||
}
|
||||
|
||||
// ファイルの MD5 ハッシュ値を求める
|
||||
int file_md5(
|
||||
wchar_t *file_name, // 表示するファイル名
|
||||
HANDLE hFileRead, // ハッシュ値を求めるファイルのハンドル
|
||||
unsigned __int64 file_size,
|
||||
unsigned char *hash) // ハッシュ値 (16バイト)
|
||||
{
|
||||
unsigned char buf[IO_SIZE];
|
||||
unsigned int rv, len;
|
||||
unsigned int time_last;
|
||||
unsigned __int64 file_left;
|
||||
PHMD5 hash_ctx;
|
||||
|
||||
// ファイルの先頭に戻す
|
||||
file_left = 0;
|
||||
if (!SetFilePointerEx(hFileRead, *((PLARGE_INTEGER)&file_left), NULL, FILE_BEGIN))
|
||||
return 1;
|
||||
|
||||
prog_last = -1; // 検証中のファイル名を毎回表示する
|
||||
time_last = GetTickCount();
|
||||
file_left = file_size;
|
||||
Phmd5Begin(&hash_ctx); // 初期化
|
||||
|
||||
while (file_left > 0){
|
||||
if (file_left < IO_SIZE){
|
||||
len = (unsigned int)file_left;
|
||||
} else {
|
||||
len = IO_SIZE;
|
||||
}
|
||||
if (!ReadFile(hFileRead, buf, len, &rv, NULL) || (len != rv))
|
||||
return 1;
|
||||
file_left -= len;
|
||||
|
||||
// MD5 計算
|
||||
Phmd5Process(&hash_ctx, buf, len);
|
||||
|
||||
// 経過表示
|
||||
if (GetTickCount() - time_last >= UPDATE_TIME){
|
||||
if (print_progress_file((int)(((file_size - file_left) * 1000) / file_size), file_name))
|
||||
return 2;
|
||||
time_last = GetTickCount();
|
||||
}
|
||||
}
|
||||
Phmd5End(&hash_ctx); // 最終処理
|
||||
memcpy(hash, hash_ctx.hash, 16);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// ファイルの MD5 ハッシュ値を求めて、全体的な経過を表示する
|
||||
int file_md5_total(
|
||||
HANDLE hFileRead, // ハッシュ値を求めるファイルのハンドル
|
||||
unsigned __int64 file_size,
|
||||
unsigned char *hash, // ハッシュ値 (16バイト)
|
||||
unsigned char *hash16, // 先頭 16KB 分のハッシュ値
|
||||
__int64 total_file_size,
|
||||
__int64 *prog_now) // 経過表示での現在位置
|
||||
{
|
||||
unsigned char buf[IO_SIZE];
|
||||
unsigned int rv, len;
|
||||
unsigned int time_last;
|
||||
unsigned __int64 file_left;
|
||||
PHMD5 hash_ctx;
|
||||
|
||||
// ファイルの先頭に戻す
|
||||
file_left = 0;
|
||||
if (!SetFilePointerEx(hFileRead, *((PLARGE_INTEGER)&file_left), NULL, FILE_BEGIN))
|
||||
return 1;
|
||||
|
||||
time_last = GetTickCount() / UPDATE_TIME; // 時刻の変化時に経過を表示する
|
||||
file_left = file_size;
|
||||
Phmd5Begin(&hash_ctx); // 初期化
|
||||
|
||||
while (file_left > 0){
|
||||
if (file_left < IO_SIZE){
|
||||
len = (unsigned int)file_left;
|
||||
} else {
|
||||
len = IO_SIZE;
|
||||
}
|
||||
if (!ReadFile(hFileRead, buf, len, &rv, NULL) || (len != rv))
|
||||
return 2;
|
||||
(*prog_now) += len;
|
||||
if (file_left == file_size){ // 最初だけ先頭 16KB 分のハッシュ値を計算する
|
||||
if (len > 16384){
|
||||
Phmd5Process(&hash_ctx, buf, 16384);
|
||||
Phmd5End(&hash_ctx); // 最終処理
|
||||
memcpy(hash16, hash_ctx.hash, 16);
|
||||
Phmd5Begin(&hash_ctx); // 初期化しなおす
|
||||
} else { // ファイル・サイズが 16KB 以下なら
|
||||
Phmd5Process(&hash_ctx, buf, len);
|
||||
Phmd5End(&hash_ctx); // 最終処理
|
||||
memcpy(hash, hash_ctx.hash, 16);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
file_left -= len;
|
||||
|
||||
// MD5 計算
|
||||
Phmd5Process(&hash_ctx, buf, len);
|
||||
|
||||
// 経過表示
|
||||
if (GetTickCount() / UPDATE_TIME != time_last){
|
||||
if (print_progress((int)(((*prog_now) * 1000) / total_file_size)))
|
||||
return -2;
|
||||
time_last = GetTickCount() / UPDATE_TIME;
|
||||
}
|
||||
}
|
||||
Phmd5End(&hash_ctx); // 最終処理
|
||||
memcpy(hash, hash_ctx.hash, 16);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// ファイルの先頭 16KB 分の MD5 ハッシュ値を求める
|
||||
int file_md5_16k(
|
||||
HANDLE hFileRead, // ハッシュ値を求めるファイルのハンドル
|
||||
unsigned __int64 file_size,
|
||||
unsigned char *hash) // ハッシュ値 (16バイト)
|
||||
{
|
||||
unsigned char buf[16384];
|
||||
unsigned int len;
|
||||
LARGE_INTEGER qwi; // Quad Word Integer
|
||||
PHMD5 hash_ctx;
|
||||
|
||||
// ファイルの先頭に戻す
|
||||
qwi.QuadPart = 0;
|
||||
if (!SetFilePointerEx(hFileRead, qwi, NULL, FILE_BEGIN))
|
||||
return 1;
|
||||
|
||||
Phmd5Begin(&hash_ctx); // 初期化
|
||||
|
||||
if (!ReadFile(hFileRead, buf, 16384, &len, NULL))
|
||||
return 2;
|
||||
if ((unsigned __int64)len > file_size)
|
||||
len = (unsigned int)file_size;
|
||||
|
||||
// MD5 計算
|
||||
Phmd5Process(&hash_ctx, buf, len);
|
||||
Phmd5End(&hash_ctx); // 最終処理
|
||||
memcpy(hash, hash_ctx.hash, 16);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// ファイルの先頭 32バイト目からの MD5 ハッシュ値を求める
|
||||
int file_md5_from32(
|
||||
wchar_t *file_name, // 表示するファイル名
|
||||
HANDLE hFileRead, // ハッシュ値を求めるファイルのハンドル
|
||||
unsigned char *hash) // ハッシュ値 (16バイト)
|
||||
{
|
||||
unsigned char buf[IO_SIZE];
|
||||
unsigned int rv, len;
|
||||
unsigned int time_last;
|
||||
unsigned __int64 file_size, file_left;
|
||||
LARGE_INTEGER qwi; // Quad Word Integer
|
||||
PHMD5 hash_ctx;
|
||||
|
||||
// ファイル・サイズを取得する
|
||||
if (!GetFileSizeEx(hFileRead, (PLARGE_INTEGER)&file_size))
|
||||
return 1;
|
||||
if (file_size <= 32)
|
||||
return 1;
|
||||
|
||||
// ファイルの開始位置を 32バイト目にする
|
||||
qwi.QuadPart = 32;
|
||||
if (!SetFilePointerEx(hFileRead, qwi, NULL, FILE_BEGIN))
|
||||
return 1;
|
||||
|
||||
prog_last = -1; // 検証中のファイル名を毎回表示する
|
||||
time_last = GetTickCount();
|
||||
file_left = file_size - 32;
|
||||
Phmd5Begin(&hash_ctx); // 初期化
|
||||
|
||||
while (file_left > 0){
|
||||
if (file_left < IO_SIZE){
|
||||
len = (unsigned int)file_left;
|
||||
} else {
|
||||
len = IO_SIZE;
|
||||
}
|
||||
if (!ReadFile(hFileRead, buf, len, &rv, NULL) || (len != rv))
|
||||
return 1;
|
||||
file_left -= len;
|
||||
|
||||
// MD5 計算
|
||||
Phmd5Process(&hash_ctx, buf, len);
|
||||
|
||||
// 経過表示
|
||||
if (GetTickCount() - time_last >= UPDATE_TIME){
|
||||
if (print_progress_file((int)(((file_size - file_left) * 1000) / file_size), file_name))
|
||||
return 2;
|
||||
time_last = GetTickCount();
|
||||
}
|
||||
}
|
||||
Phmd5End(&hash_ctx); // 最終処理
|
||||
memcpy(hash, hash_ctx.hash, 16);
|
||||
|
||||
return 0;
|
||||
}
|
||||
48
source/par1j/md5_1.h
Normal file
48
source/par1j/md5_1.h
Normal file
@@ -0,0 +1,48 @@
|
||||
#ifndef _MD5_H
|
||||
#define _MD5_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
// バイト配列の MD5 ハッシュ値を求める
|
||||
void data_md5(
|
||||
unsigned char *data_in, // ハッシュ値を求めるバイト配列
|
||||
unsigned int data_len, // 入力バイト数
|
||||
unsigned char *hash); // ハッシュ値 16バイト
|
||||
|
||||
// ファイルの MD5 ハッシュ値を求める
|
||||
int file_md5(
|
||||
wchar_t *file_name, // 表示するファイル名
|
||||
HANDLE hFileRead, // ハッシュ値を求めるファイルのハンドル
|
||||
unsigned __int64 file_size,
|
||||
unsigned char *hash); // ハッシュ値 (16バイト)
|
||||
|
||||
// ファイルの MD5 ハッシュ値を求めて、全体的な経過を表示する
|
||||
int file_md5_total(
|
||||
HANDLE hFileRead, // ハッシュ値を求めるファイルのハンドル
|
||||
unsigned __int64 file_size,
|
||||
unsigned char *hash, // ハッシュ値 (16バイト)
|
||||
unsigned char *hash16, // 先頭 16KB 分のハッシュ値
|
||||
__int64 total_file_size,
|
||||
__int64 *prog_now); // 経過表示での現在位置
|
||||
|
||||
// ファイルの先頭 16KB 分の MD5 ハッシュ値を求める
|
||||
int file_md5_16k(
|
||||
HANDLE hFileRead, // ハッシュ値を求めるファイルのハンドル
|
||||
unsigned __int64 file_size,
|
||||
unsigned char *hash); // ハッシュ値 (16バイト)
|
||||
|
||||
// ファイルの先頭 32バイト目からの MD5 ハッシュ値を求める
|
||||
int file_md5_from32(
|
||||
wchar_t *file_name, // 表示するファイル名
|
||||
HANDLE hFileRead, // ハッシュ値を求めるファイルのハンドル
|
||||
unsigned char *hash); // ハッシュ値 (16バイト)
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // md5.h
|
||||
3031
source/par1j/par1.c
Normal file
3031
source/par1j/par1.c
Normal file
File diff suppressed because it is too large
Load Diff
46
source/par1j/par1.h
Normal file
46
source/par1j/par1.h
Normal file
@@ -0,0 +1,46 @@
|
||||
#ifndef _PAR1_H_
|
||||
#define _PAR1_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
// リカバリ・ファイルを作成する
|
||||
int par1_create(
|
||||
int switch_p, // インデックス・ファイルを作らない
|
||||
int block_num, // ソース・ブロックの数
|
||||
__int64 block_size, // ブロック・サイズ (最大ファイル・サイズ)
|
||||
int parity_num, // パリティ・ブロックの数
|
||||
int first_vol, // 最初のリカバリ・ファイル番号
|
||||
int file_num, // ソース・ファイルの数
|
||||
wchar_t *list_buf, // ソース・ファイルのリスト
|
||||
int list_len, // ファイル・リストの文字数
|
||||
wchar_t *par_comment); // コメント
|
||||
|
||||
// ソース・ファイルの破損や欠損を調べる
|
||||
int par1_verify(
|
||||
int switch_b, // 既存のファイルを別名にしてどかす
|
||||
int switch_p, // インデックス・ファイルを作り直す
|
||||
wchar_t *par_comment); // コメント
|
||||
|
||||
// ソース・ファイルの破損や欠損を修復する
|
||||
int par1_repair(
|
||||
int switch_b, // 既存のファイルを別名にしてどかす
|
||||
int switch_p, // インデックス・ファイルを作り直す
|
||||
wchar_t *par_comment); // コメント
|
||||
|
||||
// ソース・ファイルの一覧を表示する
|
||||
int par1_list(
|
||||
int switch_h, // ハッシュ値も表示する
|
||||
wchar_t *par_comment); // コメント
|
||||
|
||||
// CRC-32 チェックサムを使って自分自身の破損を検出する
|
||||
int par1_checksum(wchar_t *uni_buf); // 作業用
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
753
source/par1j/par1_cmd.c
Normal file
753
source/par1j/par1_cmd.c
Normal file
@@ -0,0 +1,753 @@
|
||||
// par1_cmd.c
|
||||
// Copyright : 2022-02-16 Yutaka Sawada
|
||||
// License : GPL
|
||||
|
||||
#ifndef _UNICODE
|
||||
#define _UNICODE
|
||||
#endif
|
||||
#ifndef UNICODE
|
||||
#define UNICODE
|
||||
#endif
|
||||
#ifndef _WIN32_WINNT
|
||||
#define _WIN32_WINNT 0x0600 // Windows Vista or later
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include "common1.h"
|
||||
#include "par1.h"
|
||||
#include "ini.h"
|
||||
#include "version.h"
|
||||
|
||||
|
||||
void print_help(void)
|
||||
{
|
||||
printf(
|
||||
"Usage\n"
|
||||
"c(reate) [f,fu,r,n,p,m,c,d,in,u] <par file> [input files]\n"
|
||||
"v(erify) [ vs,vd,d,i,u,b,br] <par file>\n"
|
||||
"r(epair) [m,vs,vd,d,i,u,b,br] <par file>\n"
|
||||
"l(ist) [u,h] <par file>\n"
|
||||
"\nOption\n"
|
||||
" /f : Use file-list instead of files\n"
|
||||
" /fu : Use file-list which is encoded with UTF-8\n"
|
||||
" /r<n> : Rate of redundancy (%%)\n"
|
||||
" /n<n> : Number of parity volumes\n"
|
||||
" /p<n> : First parity volume number\n"
|
||||
" /m<n> : Memory usage\n"
|
||||
" /vs<n>: Skip verification by recent result\n"
|
||||
" /vd\"*\": Set directory of recent result\n"
|
||||
" /c\"*\" : Set comment\n"
|
||||
" /d\"*\" : Set directory of input files\n"
|
||||
" /i : Recreate index file\n"
|
||||
" /in : Do not create index file\n"
|
||||
" /u : Console output is encoded with UTF-8\n"
|
||||
" /b : Backup existing files at repair\n"
|
||||
" /br : Send existing files into recycle bin at repair\n"
|
||||
" /h : List hash value of input files\n"
|
||||
);
|
||||
}
|
||||
|
||||
// 動作環境の表示
|
||||
static void print_environment(void)
|
||||
{
|
||||
MEMORYSTATUSEX statex;
|
||||
|
||||
// 「\\?\」は常に付加されてるので表示する際には無視する
|
||||
printf_cp("Base Directory\t: \"%s\"\n", base_dir);
|
||||
printf_cp("Recovery File\t: \"%s\"\n", recovery_file);
|
||||
|
||||
printf("Memory usage\t: ");
|
||||
if (memory_use == 0){
|
||||
printf("Auto");
|
||||
} else {
|
||||
printf("%d/8", memory_use);
|
||||
}
|
||||
statex.dwLength = sizeof(statex);
|
||||
if (GlobalMemoryStatusEx(&statex))
|
||||
printf(" (%I64d MB available)", statex.ullAvailPhys >> 20);
|
||||
printf("\n\n");
|
||||
}
|
||||
|
||||
// 格納ファイル・リストを読み込んでバッファーに書き込む
|
||||
static wchar_t * read_list(
|
||||
wchar_t *list_path, // リストのパス
|
||||
int *file_num, // データ・ファイルの数
|
||||
int *list_len, // ファイル・リストの文字数
|
||||
int *block_num, // ソース・ブロックの数
|
||||
__int64 *block_size, // ブロック・サイズ (最大ファイル・サイズ)
|
||||
int switch_f) // 1=CP_OEMCP, 2=CP_UTF8
|
||||
{
|
||||
char buf[MAX_LEN * 3];
|
||||
wchar_t *list_buf, file_name[MAX_LEN], file_path[MAX_LEN], *tmp_p;
|
||||
int len, base_len, l_max, l_off = 0;
|
||||
__int64 file_size;
|
||||
FILE *fp;
|
||||
WIN32_FILE_ATTRIBUTE_DATA AttrData;
|
||||
|
||||
base_len = wcslen(base_dir);
|
||||
if (switch_f == 2){
|
||||
switch_f = CP_UTF8;
|
||||
} else {
|
||||
switch_f = CP_OEMCP;
|
||||
}
|
||||
l_max = ALLOC_LEN;
|
||||
list_buf = malloc(l_max);
|
||||
if (list_buf == NULL){
|
||||
printf("malloc, %d\n", l_max);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// 読み込むファイルを開く
|
||||
fp = _wfopen(list_path, L"rb");
|
||||
if (fp == NULL){
|
||||
utf16_to_cp(list_path, buf);
|
||||
free(list_buf);
|
||||
printf("cannot open file-list, %s\n", buf);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// 一行ずつ読み込む
|
||||
while (fgets(buf, MAX_LEN * 3, fp)){
|
||||
if (ferror(fp))
|
||||
break;
|
||||
buf[MAX_LEN * 3 - 1] = 0;
|
||||
// 末尾に改行があれば削除する
|
||||
for (len = 0; len < MAX_LEN * 3; len++){
|
||||
if (buf[len] == 0)
|
||||
break;
|
||||
if ((buf[len] == '\n') || (buf[len] == '\r')){
|
||||
buf[len] = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (buf[0] == 0)
|
||||
continue; // 改行だけなら次の行へ
|
||||
|
||||
// 読み込んだ内容をユニコードに変換する
|
||||
if (!MultiByteToWideChar(switch_f, 0, buf, -1, file_name, MAX_LEN)){
|
||||
fclose(fp);
|
||||
free(list_buf);
|
||||
printf("MultiByteToWideChar, %s\n", buf);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// ファイルが基準ディレクトリ以下に存在することを確認する
|
||||
len = copy_path_prefix(file_path, MAX_LEN - ADD_LEN, file_name, base_dir); // 絶対パスにしてから比較する
|
||||
if (len == 0){
|
||||
fclose(fp);
|
||||
free(list_buf);
|
||||
printf_cp("filename is invalid, %s\n", file_name);
|
||||
return NULL;
|
||||
}
|
||||
if ((len <= base_len) || (_wcsnicmp(base_dir, file_path, base_len) != 0)){ // 基準ディレクトリ外なら
|
||||
fclose(fp);
|
||||
free(list_buf);
|
||||
printf("out of base-directory, %s\n", buf);
|
||||
return NULL;
|
||||
}
|
||||
wcscpy(file_name, file_path + base_len);
|
||||
if (wcschr(file_name, '\\') != NULL){ // サブ・ディレクトリは拒否する
|
||||
fclose(fp);
|
||||
free(list_buf);
|
||||
printf_cp("sub-directory is not supported, %s\n", file_name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// ファイルが存在するか確かめる
|
||||
if (!GetFileAttributesEx(file_path, GetFileExInfoStandard, &AttrData)){
|
||||
print_win32_err();
|
||||
fclose(fp);
|
||||
free(list_buf);
|
||||
printf("input file is not found, %s\n", buf);
|
||||
return NULL;
|
||||
}
|
||||
if (AttrData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY){
|
||||
fclose(fp);
|
||||
free(list_buf);
|
||||
printf("folder is not supported, %s\n", buf);
|
||||
return NULL;
|
||||
}
|
||||
file_size = ((unsigned __int64)AttrData.nFileSizeHigh << 32) | (unsigned __int64)AttrData.nFileSizeLow;
|
||||
if (*block_size < file_size)
|
||||
*block_size = file_size;
|
||||
|
||||
// ファイル名が重複しないようにする
|
||||
if (search_file_path(list_buf, l_off, file_name))
|
||||
continue;
|
||||
|
||||
// バッファー容量が足りなければ再確保する
|
||||
len = wcslen(file_name);
|
||||
if ((l_off + len) * 2 >= l_max){
|
||||
l_max += ALLOC_LEN;
|
||||
tmp_p = (wchar_t *)realloc(list_buf, l_max);
|
||||
if (tmp_p == NULL){
|
||||
free(list_buf);
|
||||
printf("realloc, %d\n", l_max);
|
||||
return NULL;
|
||||
} else {
|
||||
list_buf = tmp_p;
|
||||
}
|
||||
}
|
||||
|
||||
// リストにコピーする
|
||||
wcscpy(list_buf + l_off, file_name);
|
||||
l_off += (len + 1);
|
||||
*file_num += 1;
|
||||
if (file_size > 0)
|
||||
*block_num += 1; // 空のファイルはブロックの計算に含めない
|
||||
}
|
||||
*list_len = l_off;
|
||||
fclose(fp);
|
||||
/*
|
||||
fp = fopen("list_buf.txt", "wb");
|
||||
len = 0;
|
||||
while (len < l_off){
|
||||
fwprintf(fp, L"%s\n", list_buf + len);
|
||||
len += (wcslen(list_buf + len) + 1);
|
||||
}
|
||||
fclose(fp);
|
||||
*/
|
||||
return list_buf;
|
||||
}
|
||||
|
||||
// ファイルを検索してファイル・リストに追加する
|
||||
static wchar_t * search_files(
|
||||
wchar_t *list_buf, // ファイル・リスト
|
||||
wchar_t *search_path, // 検索するファイルのフル・パス
|
||||
int dir_len, // ディレクトリ部分の長さ
|
||||
int single_file, // -1 = *や?で検索指定、0~ = 単独指定
|
||||
int *file_num, // データ・ファイルの数
|
||||
int *list_max, // ファイル・リストの確保サイズ
|
||||
int *list_len, // ファイル・リストの文字数
|
||||
int *block_num, // ソース・ブロックの数
|
||||
__int64 *block_size) // ブロック・サイズ (最大ファイル・サイズ)
|
||||
{
|
||||
wchar_t *tmp_p;
|
||||
int len, l_max, l_off;
|
||||
__int64 file_size;
|
||||
HANDLE hFind;
|
||||
WIN32_FIND_DATA FindData;
|
||||
|
||||
if (list_buf == NULL){
|
||||
l_off = 0;
|
||||
l_max = ALLOC_LEN;
|
||||
list_buf = 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 (FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
|
||||
continue; // フォルダは無視する
|
||||
|
||||
if ((single_file < 0) && (FindData.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN))
|
||||
continue; // 検索中は隠し属性が付いてるファイルを無視する
|
||||
|
||||
// フォルダは無視する、ファイル名が重複しないようにする
|
||||
if (!search_file_path(list_buf, l_off, FindData.cFileName)){
|
||||
//printf("FindData.cFileName =\n%S\n\n", FindData.cFileName);
|
||||
len = wcslen(FindData.cFileName);
|
||||
if (dir_len + len >= MAX_LEN - ADD_LEN){
|
||||
FindClose(hFind);
|
||||
free(list_buf);
|
||||
printf("filename is too long\n");
|
||||
return NULL;
|
||||
}
|
||||
if ((l_off + 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;
|
||||
}
|
||||
}
|
||||
|
||||
file_size = ((unsigned __int64)FindData.nFileSizeHigh << 32) | (unsigned __int64)FindData.nFileSizeLow;
|
||||
if (*block_size < file_size)
|
||||
*block_size = file_size;
|
||||
|
||||
// リストにコピーする
|
||||
wcscpy(list_buf + l_off, FindData.cFileName);
|
||||
l_off += len + 1;
|
||||
*file_num += 1;
|
||||
if (file_size > 0)
|
||||
*block_num += 1; // 空のファイルはブロックの計算に含めない
|
||||
}
|
||||
} while (FindNextFile(hFind, &FindData)); // 次のファイルを検索する
|
||||
FindClose(hFind);
|
||||
|
||||
*list_max = l_max;
|
||||
*list_len = l_off;
|
||||
return list_buf;
|
||||
}
|
||||
|
||||
// リカバリ・ファイルとソース・ファイルが同じ名前にならないようにする
|
||||
static int check_recovery_match(
|
||||
int file_num,
|
||||
wchar_t *list_buf,
|
||||
int list_len,
|
||||
int switch_p) // インデックス・ファイルを作らない
|
||||
{
|
||||
wchar_t *tmp_p;
|
||||
int i, num, len, list_off = 0, recovery_len, base_len;
|
||||
|
||||
// 基準ディレクトリ外にリカバリ・ファイルが存在するなら問題なし
|
||||
base_len = wcslen(base_dir);
|
||||
if (_wcsnicmp(recovery_file, base_dir, base_len) != 0)
|
||||
return 0;
|
||||
|
||||
// リカバリ・ファイル (*.PXX) の名前の基
|
||||
recovery_len = wcslen(recovery_file);
|
||||
recovery_len -= base_len + 2; // 末尾の 2文字を除くファイル名の長さ
|
||||
|
||||
// ファイルごとに比較する
|
||||
for (num = 0; num < file_num; num++){
|
||||
tmp_p = list_buf + list_off;
|
||||
while (list_buf[list_off] != 0)
|
||||
list_off++;
|
||||
list_off++;
|
||||
|
||||
// ファイル名との前方一致を調べる
|
||||
if (_wcsnicmp(recovery_file + base_len, tmp_p, recovery_len) == 0){ // リカバリ・ファイルと基準が同じ
|
||||
len = wcslen(tmp_p);
|
||||
// 拡張子も同じか調べる
|
||||
if (len == recovery_len + 2){
|
||||
// インデックス・ファイルと比較する
|
||||
if (switch_p == 0){
|
||||
if (_wcsicmp(tmp_p + recovery_len, L"ar") == 0){
|
||||
printf_cp("filename is invalid, %s\n", tmp_p);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
// リカバリ・ファイル (*.PXX) と比較する
|
||||
for (i = 1; i <= 99; i++){
|
||||
if ((tmp_p[recovery_len ] == '0' + (i / 10)) &&
|
||||
(tmp_p[recovery_len + 1] == '0' + (i % 10))){
|
||||
printf_cp("filename is invalid, %s\n", tmp_p);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
wmain(int argc, wchar_t *argv[])
|
||||
{
|
||||
wchar_t file_path[MAX_LEN], *list_buf;
|
||||
wchar_t par_comment[COMMENT_LEN], *tmp_p;
|
||||
int i, j;
|
||||
int switch_b = 0, switch_p = 0, switch_f = 0, switch_r = 0, switch_h = 0;
|
||||
int file_num = 0, source_num = 0, list_len = 0, parity_num = 0, first_vol = 1;
|
||||
__int64 block_size = 0;
|
||||
|
||||
printf("Parchive 1.0 client version " FILE_VERSION " by Yutaka Sawada\n\n");
|
||||
if (argc < 3){
|
||||
printf("Self-Test: ");
|
||||
i = par1_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;
|
||||
}
|
||||
|
||||
// 初期化
|
||||
recovery_file[0] = 0;
|
||||
par_comment[0] = 0;
|
||||
base_dir[0] = 0;
|
||||
ini_path[0] = 0;
|
||||
cp_output = GetConsoleOutputCP();
|
||||
memory_use = 0;
|
||||
|
||||
// コマンド
|
||||
switch (argv[1][0]){
|
||||
case 'c': // create
|
||||
case 'v': // verify
|
||||
case 'r': // repair
|
||||
case 'l': // list
|
||||
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"b") == 0){
|
||||
switch_b = 1;
|
||||
} else if (wcscmp(tmp_p, L"br") == 0){
|
||||
switch_b = 2;
|
||||
} else if (wcscmp(tmp_p, L"f") == 0){
|
||||
switch_f = 1;
|
||||
} else if (wcscmp(tmp_p, L"fu") == 0){
|
||||
switch_f = 2;
|
||||
} else if (wcscmp(tmp_p, L"i") == 0){
|
||||
switch_p = 1;
|
||||
} else if (wcscmp(tmp_p, L"in") == 0){
|
||||
switch_p = 2;
|
||||
} else if (wcscmp(tmp_p, L"u") == 0){
|
||||
cp_output = CP_UTF8;
|
||||
} else if (wcscmp(tmp_p, L"h") == 0){
|
||||
switch_h = 1;
|
||||
|
||||
// オプション (数値)
|
||||
} else if (wcsncmp(tmp_p, L"n", 1) == 0){
|
||||
j = 1;
|
||||
while ((j < 1 + 4) && (tmp_p[j] >= 48) && (tmp_p[j] <= 57)){
|
||||
parity_num = (parity_num * 10) + (tmp_p[j] - 48);
|
||||
j++;
|
||||
}
|
||||
} else if (wcsncmp(tmp_p, L"r", 1) == 0){
|
||||
j = 1;
|
||||
while ((j < 1 + 5) && (tmp_p[j] >= 48) && (tmp_p[j] <= 57)){
|
||||
switch_r = (switch_r * 10) + (tmp_p[j] - 48);
|
||||
j++;
|
||||
}
|
||||
} else if (wcsncmp(tmp_p, L"p", 1) == 0){
|
||||
j = 1;
|
||||
first_vol = 0;
|
||||
while ((j < 1 + 4) && (tmp_p[j] >= 48) && (tmp_p[j] <= 57)){
|
||||
first_vol = (first_vol * 10) + (tmp_p[j] - 48);
|
||||
j++;
|
||||
}
|
||||
if (first_vol < 1)
|
||||
first_vol = 1;
|
||||
if (first_vol > 99)
|
||||
first_vol = 99;
|
||||
} else if (wcsncmp(tmp_p, L"m", 1) == 0){
|
||||
if ((tmp_p[1] >= 48) && (tmp_p[1] <= 55)) // 0~7 の範囲
|
||||
memory_use = tmp_p[1] - 48;
|
||||
} 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"c", 1) == 0){
|
||||
tmp_p++;
|
||||
if (wcslen(tmp_p) >= COMMENT_LEN){
|
||||
printf("comment is too long\n");
|
||||
return 1;
|
||||
}
|
||||
wcscpy(par_comment, tmp_p);
|
||||
//printf("comment = %S\n", tmp_p);
|
||||
} 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 { // 未対応のオプション
|
||||
printf_cp("invalid option, %s\n", tmp_p - 1);
|
||||
return 1;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
// オプション以外ならリカバリ・ファイル
|
||||
j = copy_path_prefix(recovery_file, MAX_LEN - 4, tmp_p, NULL); // 「.par」が追加されるかも
|
||||
if (j == 0){
|
||||
printf("PAR filename is invalid\n");
|
||||
return 1;
|
||||
}
|
||||
if (argv[1][0] == 'c'){ // 作成なら
|
||||
// 指定されたファイル名が適切か調べる
|
||||
if (sanitize_filename(offset_file_name(recovery_file)) != 0){
|
||||
printf("PAR filename is invalid\n");
|
||||
return 1;
|
||||
}
|
||||
// 拡張子が「.par」以外なら標準の拡張子を追加する
|
||||
j = wcslen(recovery_file); // 浄化でファイル名が短縮されるかもしれない
|
||||
if (_wcsicmp(recovery_file + (j - 4), L".par"))
|
||||
wcscpy(recovery_file + j, L".par");
|
||||
} else { // 検査や修復なら
|
||||
if (_wcsicmp(recovery_file + (j - 4), L".par")){
|
||||
// 拡張子が「.par」以外でも「.p??」ならよい
|
||||
if ((recovery_file[j - 4] != '.') ||
|
||||
((recovery_file[j - 3] != 'p') && (recovery_file[j - 3] != 'P')) ||
|
||||
(recovery_file[j - 2] < 48) || (recovery_file[j - 2] > 57) ||
|
||||
(recovery_file[j - 1] < 48) || (recovery_file[j - 1] > 57) ){
|
||||
wcscpy(recovery_file + j, L".par");
|
||||
}
|
||||
}
|
||||
j = GetFileAttributes(recovery_file);
|
||||
if ((j == INVALID_FILE_ATTRIBUTES) || (j & FILE_ATTRIBUTE_DIRECTORY)){
|
||||
wchar_t search_path[MAX_LEN];
|
||||
int name_len, dir_len, path_len, find_flag = 0;
|
||||
HANDLE hFind;
|
||||
WIN32_FIND_DATA FindData;
|
||||
path_len = wcslen(recovery_file);
|
||||
if (wcspbrk(offset_file_name(recovery_file), L"*?") != NULL){
|
||||
// 「*」や「?」で検索する場合は指定された拡張子を優先する
|
||||
hFind = FindFirstFile(recovery_file, &FindData);
|
||||
if (hFind != INVALID_HANDLE_VALUE){
|
||||
get_base_dir(recovery_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), recovery_file + (path_len - 4)) == 0)){
|
||||
find_flag = 1;
|
||||
break; // 見つけたファイル名で問題なし
|
||||
}
|
||||
} while (FindNextFile(hFind, &FindData)); // 次のファイルを検索する
|
||||
FindClose(hFind);
|
||||
}
|
||||
}
|
||||
if (find_flag == 0){ // リカバリ・ファイルの拡張子を「.p??」にして検索する
|
||||
wcscpy(search_path, recovery_file);
|
||||
search_path[path_len - 2] = '?';
|
||||
search_path[path_len - 1] = '?';
|
||||
hFind = FindFirstFile(search_path, &FindData);
|
||||
if (hFind != INVALID_HANDLE_VALUE){
|
||||
get_base_dir(recovery_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) && // ファイル名が長すぎない
|
||||
(FindData.cFileName[name_len - 4] == '.') &&
|
||||
((FindData.cFileName[name_len - 3] == 'p') || (FindData.cFileName[name_len - 3] == 'P')) &&
|
||||
(FindData.cFileName[name_len - 2] >= '0') && (FindData.cFileName[name_len - 2] <= '9') &&
|
||||
(FindData.cFileName[name_len - 1] >= '0') && (FindData.cFileName[name_len - 1] <= '9')){
|
||||
find_flag = 1;
|
||||
break; // 見つけたファイル名で問題なし
|
||||
}
|
||||
} while (FindNextFile(hFind, &FindData)); // 次のファイルを検索する
|
||||
FindClose(hFind);
|
||||
}
|
||||
}
|
||||
if (find_flag == 0){
|
||||
printf("valid file is not found\n");
|
||||
return 1;
|
||||
}
|
||||
wcscpy(recovery_file + dir_len, FindData.cFileName);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
//printf("m = %d, f = %d, p = %d, n = %d\n", switch_b, switch_f, switch_p, parity_num);
|
||||
if (recovery_file[0] == 0){ // リカバリ・ファイルが指定されてないなら
|
||||
printf("PAR file is not specified\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
// input file の位置が指定されて無くて、
|
||||
// 最初のソース・ファイル指定に絶対パスが含まれてるなら、それを使う
|
||||
if (argv[1][0] == 'c'){
|
||||
if ((base_dir[0] == 0) && (switch_f == 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(recovery_file, base_dir); // リカバリ・ファイルの位置にする
|
||||
|
||||
// 環境の表示
|
||||
print_environment();
|
||||
|
||||
switch (argv[1][0]){
|
||||
case 'c':
|
||||
// リカバリ・ファイル作成ならソース・ファイルのリストがいる
|
||||
i++;
|
||||
if (i >= argc){
|
||||
printf("input file is not specified\n");
|
||||
return 1;
|
||||
}
|
||||
if (switch_f){ // ファイル・リストの読み込み
|
||||
list_buf = read_list(argv[i], &file_num, &list_len, &source_num, &block_size, switch_f);
|
||||
if (list_buf == NULL)
|
||||
return 1;
|
||||
} else { // 入力ファイルの指定
|
||||
int base_len, list_max;
|
||||
base_len = wcslen(base_dir);
|
||||
list_max = 0;
|
||||
list_buf = NULL;
|
||||
for (; i < argc; i++){
|
||||
// 絶対パスや、親パスへの移動を含むパスは危険なのでファイル名だけにする
|
||||
tmp_p = argv[i];
|
||||
j = copy_path_prefix(file_path, MAX_LEN - ADD_LEN, 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;
|
||||
}
|
||||
if (wcschr(file_path + base_len, '\\') != NULL){
|
||||
free(list_buf);
|
||||
printf_cp("sub-directory is not supported, %s\n", file_path + base_len);
|
||||
return 1;
|
||||
}
|
||||
//printf("%d = %S\nsearch = %S\n", i, argv[i], file_path);
|
||||
// 「*」や「?」で検索しない場合、ファイルが見つからなければエラーにする
|
||||
j = -1;
|
||||
if (wcspbrk(file_path + base_len, L"*?") == NULL)
|
||||
j = file_num;
|
||||
// ファイルを検索する
|
||||
list_buf = search_files(list_buf, file_path, base_len, j, &file_num, &list_max, &list_len, &source_num, &block_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_recovery_match(file_num, list_buf, list_len, switch_p & 2)){
|
||||
free(list_buf);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// ファイル・リストの内容を並び替える (リストの末尾は null 1個にすること)
|
||||
sort_list(list_buf, list_len);
|
||||
//printf("file_num = %d, source_num = %d, block_size = %I64d\n", file_num, source_num, block_size);
|
||||
|
||||
if ((parity_num == 0) && (switch_r > 0)){
|
||||
parity_num = (source_num * switch_r) / 100;
|
||||
if (parity_num == 0)
|
||||
parity_num = 1;
|
||||
}
|
||||
printf("Input File count: %d\n", file_num);
|
||||
printf("Data File count : %d\n", source_num);
|
||||
printf("Max file size\t: %I64d\n", block_size);
|
||||
printf("Parity Volume count\t: %d\n", parity_num);
|
||||
if (first_vol > 1)
|
||||
printf("Parity Volume start\t: %d\n", first_vol);
|
||||
if (source_num != 0){
|
||||
i = 100 * parity_num / source_num;
|
||||
} else {
|
||||
i = 0;
|
||||
}
|
||||
printf("Redundancy rate : %d%%\n", i);
|
||||
if (source_num + parity_num + first_vol - 1 > 256){
|
||||
free(list_buf);
|
||||
printf("too many total volumes %d\n", source_num + parity_num + first_vol - 1);
|
||||
return 1;
|
||||
}
|
||||
if (parity_num + first_vol - 1 > 99){
|
||||
free(list_buf);
|
||||
printf("too many parity volumes %d\n", parity_num + first_vol - 1);
|
||||
return 1;
|
||||
}
|
||||
i = par1_create(switch_p & 2, source_num, block_size, parity_num, first_vol,
|
||||
file_num, list_buf, list_len, par_comment);
|
||||
break;
|
||||
case 'v':
|
||||
case 'r':
|
||||
// 検査結果ファイルの位置が指定されてないなら
|
||||
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;
|
||||
}
|
||||
}
|
||||
if (argv[1][0] == 'v'){
|
||||
i = par1_verify(switch_b, switch_p & 1, par_comment);
|
||||
} else {
|
||||
i = par1_repair(switch_b, switch_p & 1, par_comment);
|
||||
}
|
||||
break;
|
||||
case 'l':
|
||||
i = par1_list(switch_h, par_comment);
|
||||
break;
|
||||
}
|
||||
|
||||
//printf("ExitCode: 0x%02X\n", i);
|
||||
return i;
|
||||
}
|
||||
|
||||
79
source/par1j/phmd5.c
Normal file
79
source/par1j/phmd5.c
Normal file
@@ -0,0 +1,79 @@
|
||||
/*----------------------------------------------------------------------------
|
||||
;
|
||||
; MD5 hash generator -- Paul Houle (paulhoule.com) 11/13/2017
|
||||
;
|
||||
; Non-time critical C logic. All API entry points are here.
|
||||
; See phmd5.h for documentation.
|
||||
;
|
||||
;---------------------------------------------------------------------------*/
|
||||
|
||||
#include <string.h>
|
||||
#include "phmd5.h"
|
||||
|
||||
// First call -- initialize pmd5 structure for use.
|
||||
void Phmd5Begin(PHMD5 *pmd5) {
|
||||
unsigned __int32 *uhash = (unsigned __int32 *) pmd5->hash;
|
||||
|
||||
uhash[0] = 0x67452301; // init hash per rfc1321
|
||||
uhash[1] = 0xEFCDAB89;
|
||||
uhash[2] = 0x98BADCFE;
|
||||
uhash[3] = 0x10325476;
|
||||
|
||||
pmd5->totbyt = 0; // init count of data bytes processed
|
||||
}
|
||||
|
||||
// Last call -- after this, pmd5->hash holds final MD5 hash.
|
||||
void Phmd5End(PHMD5 *pmd5) {
|
||||
char pad[72]; // pad buffer (worst case is 72 bytes)
|
||||
unsigned padc; // size of needed pad (9-72 bytes)
|
||||
|
||||
padc = 64 - ((unsigned) pmd5->totbyt & 63); // pad to 64-byte boundary
|
||||
if (padc < 9) padc += 64; // add a block if we need more room
|
||||
memset(pad, 0, padc); // clear entire pad area
|
||||
pad[0] = (char) 0x80; // place input stream terminator
|
||||
// place 64-bit input data bit count
|
||||
*(unsigned __int64 *) &pad[padc - 8] = pmd5->totbyt << 3;
|
||||
Phmd5Process(pmd5, pad, padc); // process the pad
|
||||
}
|
||||
|
||||
// Work done here -- call for as many input blocks that need to be processed.
|
||||
// pdata points to the input data, bytecnt is pdata size (0..n bytes).
|
||||
// See phmd5.h regarding how to use this optimally.
|
||||
void Phmd5Process(PHMD5 *pmd5, char *pdata, size_t bytecnt) {
|
||||
unsigned resid = (unsigned) pmd5->totbyt;
|
||||
|
||||
pmd5->totbyt += bytecnt; // update total bytes processed
|
||||
|
||||
resid &= 63; // count of bytes now in pmd5->buf
|
||||
|
||||
// This block handles the case of residual data in pmd5->buf.
|
||||
// After this block pmd5->buf is empty (except perhaps on exit).
|
||||
|
||||
if (resid) { // if residual exists,
|
||||
unsigned cb = 64 - resid;
|
||||
if (cb > bytecnt) cb = (unsigned) bytecnt;
|
||||
memcpy(pmd5->buf + resid, pdata, cb);
|
||||
pdata += cb;
|
||||
bytecnt -= cb;
|
||||
if (resid + cb < 64) return;
|
||||
Phmd5DoBlocks(pmd5->hash, pmd5->buf, 64);
|
||||
}
|
||||
|
||||
// This block processes input data in-place, if the data is dword
|
||||
// aligned and in 64-byte chunks.
|
||||
|
||||
if ((unsigned) bytecnt & ~63 && ((size_t) pdata & 3) == 0) {
|
||||
Phmd5DoBlocks(pmd5->hash, pdata, bytecnt & ~63);
|
||||
pdata += bytecnt & ~63;
|
||||
bytecnt &= 63;
|
||||
}
|
||||
|
||||
while (bytecnt) { // handle residual/non-aligned data
|
||||
unsigned cb = 64 > (unsigned) bytecnt ? (unsigned) bytecnt : 64;
|
||||
memcpy(pmd5->buf, pdata, cb);
|
||||
pdata += cb;
|
||||
bytecnt -= cb;
|
||||
if (cb < 64) return;
|
||||
Phmd5DoBlocks(pmd5->hash, pmd5->buf, 64);
|
||||
};
|
||||
}
|
||||
59
source/par1j/phmd5.h
Normal file
59
source/par1j/phmd5.h
Normal file
@@ -0,0 +1,59 @@
|
||||
/*----------------------------------------------------------------------------
|
||||
;
|
||||
; MD5 hash generator -- Paul Houle (paulhoule.com) 11/13/2017
|
||||
;
|
||||
; This code is in the public domain. Please attribute the author.
|
||||
;
|
||||
; There are a lot of MD5 generators; here's another. This one targets a
|
||||
; little-endian memory architecture only (eg X86). The benefit of this
|
||||
; is speed -- bytes within larger elements never need to be reversed,
|
||||
; which means the source data can be processed in-place.
|
||||
;
|
||||
; Though other compilers might be usable, this was developed using
|
||||
; Microsoft 32/64-bit C 12.0 [Version 18.00.30723]. Vendor specific
|
||||
; definitions (eg. _rotl, __int32, __int64) are used.
|
||||
; Build commands:
|
||||
;
|
||||
; cl /c /Ox phmd5.c
|
||||
; cl /c /Ox phmd5a.c
|
||||
;
|
||||
; Link the resulting .obj's into your executable and #include "phmd5.h"
|
||||
;
|
||||
; How to call the routines to generate a hash:
|
||||
;
|
||||
; (1) Allocate a PHMD5 type struct -- it's small, can be static or local.
|
||||
; A pointer to this struct is the first argument to all functions.
|
||||
;
|
||||
; (2) Call Phmd5Begin() once -- this initializes the PHMD5 struct.
|
||||
;
|
||||
; (3) Call Phmd5Process() as many times as necessary for all data
|
||||
; to be included in the MD5 hash.
|
||||
;
|
||||
; (4) Call Phmd5End() once. The final 16-byte MD5 hash will then be
|
||||
; available in PHMD5->hash. Note the finished hash is a simple array
|
||||
; of bytes, and must be treated/displayed/copied/etc that way.
|
||||
;
|
||||
; For best performance the Phmd5Process() "pdata" pointer should be 32-bit
|
||||
; aligned (a multiple of 4) and "bytecnt" should be a multiple of 64.
|
||||
; As long as both of these conditions continue to be met the input data is
|
||||
; processed in-place; otherwise, some speed (10-15%) is lost as the data
|
||||
; is copied to an internal blocking buffer before being proceessed.
|
||||
;
|
||||
;---------------------------------------------------------------------------*/
|
||||
|
||||
#ifndef _PHMD5_DEFINED // include guard
|
||||
#define _PHMD5_DEFINED
|
||||
|
||||
#include <stddef.h>
|
||||
typedef struct {
|
||||
unsigned char hash[16]; // final 16-byte hash winds up here
|
||||
unsigned __int64 totbyt; // processed byte count
|
||||
char buf[64]; // input blocking buffer
|
||||
} PHMD5;
|
||||
|
||||
void Phmd5Begin(PHMD5 *pmd5);
|
||||
void Phmd5Process(PHMD5 *pmd5, char *pdata, size_t bytecnt);
|
||||
void Phmd5End(PHMD5 *pmd5);
|
||||
void Phmd5DoBlocks(unsigned char *hash, char *pdata, size_t bytecnt);
|
||||
|
||||
#endif
|
||||
130
source/par1j/phmd5a.c
Normal file
130
source/par1j/phmd5a.c
Normal file
@@ -0,0 +1,130 @@
|
||||
/*----------------------------------------------------------------------------
|
||||
;
|
||||
; MD5 hash generator -- Paul Houle (paulhoule.com) 11/13/2017
|
||||
;
|
||||
; Called only from phmd5.c -- see phmd5.h for overview
|
||||
;
|
||||
; This is the same logic in phmd5a.asm, implemented (after the fact) in C.
|
||||
; The C compiler must support the "_rotl()" function generated inline to
|
||||
; achieve maximal performance.
|
||||
;
|
||||
; It turns out the MSFT C compiler, coupled with newer processor, results
|
||||
; in timings comparable to the 32-bit only phmd5a.asm hand-written assembly.
|
||||
; Therefore this "C" implementation is now used.
|
||||
; Avoiding assembly allows the code to be compiled either 32 or 64 bit.
|
||||
;
|
||||
; Note that a "little-endian" memory architecture is assumed.
|
||||
;
|
||||
; The Fx() and MD5STEP() macros were written by Colin Plumb in 1993.
|
||||
; MD5STEP() was changed slightly to match how phmd5a.asm operates.
|
||||
;
|
||||
;---------------------------------------------------------------------------*/
|
||||
|
||||
#include <stdlib.h> // for _rotl()
|
||||
#include "phmd5.h"
|
||||
|
||||
// MD5 Optimisation Tricks by Anime Tosho
|
||||
// https://github.com/animetosho/md5-optimisation#optimisation-tricks-single-buffer
|
||||
// Dependency shortcut in G function
|
||||
#define F1(x, y, z) ((x & y) + (~x & z))
|
||||
|
||||
//#define F1(x, y, z) (z ^ (x & (y ^ z)))
|
||||
#define F2(x, y, z) F1(z, x, y)
|
||||
#define F3(x, y, z) (x ^ y ^ z)
|
||||
#define F4(x, y, z) (y ^ (x | ~z))
|
||||
|
||||
#define MD5STEP(f, w, x, y, z, ix, s, sc) \
|
||||
w = _rotl(w + f(x, y, z) + ((unsigned *) pdata)[ix] + sc, s) + x
|
||||
|
||||
void Phmd5DoBlocks(
|
||||
unsigned char *hash,
|
||||
char *pdata,
|
||||
size_t bytecnt
|
||||
) {
|
||||
unsigned __int32 a = *(unsigned __int32 *) &hash[ 0];
|
||||
unsigned __int32 b = *(unsigned __int32 *) &hash[ 4];
|
||||
unsigned __int32 c = *(unsigned __int32 *) &hash[ 8];
|
||||
unsigned __int32 d = *(unsigned __int32 *) &hash[12];
|
||||
|
||||
do {
|
||||
MD5STEP(F1, a, b, c, d, 0, 7, 0xd76aa478);
|
||||
MD5STEP(F1, d, a, b, c, 1, 12, 0xe8c7b756);
|
||||
MD5STEP(F1, c, d, a, b, 2, 17, 0x242070db);
|
||||
MD5STEP(F1, b, c, d, a, 3, 22, 0xc1bdceee);
|
||||
MD5STEP(F1, a, b, c, d, 4, 7, 0xf57c0faf);
|
||||
MD5STEP(F1, d, a, b, c, 5, 12, 0x4787c62a);
|
||||
MD5STEP(F1, c, d, a, b, 6, 17, 0xa8304613);
|
||||
MD5STEP(F1, b, c, d, a, 7, 22, 0xfd469501);
|
||||
MD5STEP(F1, a, b, c, d, 8, 7, 0x698098d8);
|
||||
MD5STEP(F1, d, a, b, c, 9, 12, 0x8b44f7af);
|
||||
MD5STEP(F1, c, d, a, b, 10, 17, 0xffff5bb1);
|
||||
MD5STEP(F1, b, c, d, a, 11, 22, 0x895cd7be);
|
||||
MD5STEP(F1, a, b, c, d, 12, 7, 0x6b901122);
|
||||
MD5STEP(F1, d, a, b, c, 13, 12, 0xfd987193);
|
||||
MD5STEP(F1, c, d, a, b, 14, 17, 0xa679438e);
|
||||
MD5STEP(F1, b, c, d, a, 15, 22, 0x49b40821);
|
||||
|
||||
MD5STEP(F2, a, b, c, d, 1, 5, 0xf61e2562);
|
||||
MD5STEP(F2, d, a, b, c, 6, 9, 0xc040b340);
|
||||
MD5STEP(F2, c, d, a, b, 11, 14, 0x265e5a51);
|
||||
MD5STEP(F2, b, c, d, a, 0, 20, 0xe9b6c7aa);
|
||||
MD5STEP(F2, a, b, c, d, 5, 5, 0xd62f105d);
|
||||
MD5STEP(F2, d, a, b, c, 10, 9, 0x02441453);
|
||||
MD5STEP(F2, c, d, a, b, 15, 14, 0xd8a1e681);
|
||||
MD5STEP(F2, b, c, d, a, 4, 20, 0xe7d3fbc8);
|
||||
MD5STEP(F2, a, b, c, d, 9, 5, 0x21e1cde6);
|
||||
MD5STEP(F2, d, a, b, c, 14, 9, 0xc33707d6);
|
||||
MD5STEP(F2, c, d, a, b, 3, 14, 0xf4d50d87);
|
||||
MD5STEP(F2, b, c, d, a, 8, 20, 0x455a14ed);
|
||||
MD5STEP(F2, a, b, c, d, 13, 5, 0xa9e3e905);
|
||||
MD5STEP(F2, d, a, b, c, 2, 9, 0xfcefa3f8);
|
||||
MD5STEP(F2, c, d, a, b, 7, 14, 0x676f02d9);
|
||||
MD5STEP(F2, b, c, d, a, 12, 20, 0x8d2a4c8a);
|
||||
|
||||
MD5STEP(F3, a, b, c, d, 5, 4, 0xfffa3942);
|
||||
MD5STEP(F3, d, a, b, c, 8, 11, 0x8771f681);
|
||||
MD5STEP(F3, c, d, a, b, 11, 16, 0x6d9d6122);
|
||||
MD5STEP(F3, b, c, d, a, 14, 23, 0xfde5380c);
|
||||
MD5STEP(F3, a, b, c, d, 1, 4, 0xa4beea44);
|
||||
MD5STEP(F3, d, a, b, c, 4, 11, 0x4bdecfa9);
|
||||
MD5STEP(F3, c, d, a, b, 7, 16, 0xf6bb4b60);
|
||||
MD5STEP(F3, b, c, d, a, 10, 23, 0xbebfbc70);
|
||||
MD5STEP(F3, a, b, c, d, 13, 4, 0x289b7ec6);
|
||||
MD5STEP(F3, d, a, b, c, 0, 11, 0xeaa127fa);
|
||||
MD5STEP(F3, c, d, a, b, 3, 16, 0xd4ef3085);
|
||||
MD5STEP(F3, b, c, d, a, 6, 23, 0x04881d05);
|
||||
MD5STEP(F3, a, b, c, d, 9, 4, 0xd9d4d039);
|
||||
MD5STEP(F3, d, a, b, c, 12, 11, 0xe6db99e5);
|
||||
MD5STEP(F3, c, d, a, b, 15, 16, 0x1fa27cf8);
|
||||
MD5STEP(F3, b, c, d, a, 2, 23, 0xc4ac5665);
|
||||
|
||||
MD5STEP(F4, a, b, c, d, 0, 6, 0xf4292244);
|
||||
MD5STEP(F4, d, a, b, c, 7, 10, 0x432aff97);
|
||||
MD5STEP(F4, c, d, a, b, 14, 15, 0xab9423a7);
|
||||
MD5STEP(F4, b, c, d, a, 5, 21, 0xfc93a039);
|
||||
MD5STEP(F4, a, b, c, d, 12, 6, 0x655b59c3);
|
||||
MD5STEP(F4, d, a, b, c, 3, 10, 0x8f0ccc92);
|
||||
MD5STEP(F4, c, d, a, b, 10, 15, 0xffeff47d);
|
||||
MD5STEP(F4, b, c, d, a, 1, 21, 0x85845dd1);
|
||||
MD5STEP(F4, a, b, c, d, 8, 6, 0x6fa87e4f);
|
||||
MD5STEP(F4, d, a, b, c, 15, 10, 0xfe2ce6e0);
|
||||
MD5STEP(F4, c, d, a, b, 6, 15, 0xa3014314);
|
||||
MD5STEP(F4, b, c, d, a, 13, 21, 0x4e0811a1);
|
||||
MD5STEP(F4, a, b, c, d, 4, 6, 0xf7537e82);
|
||||
MD5STEP(F4, d, a, b, c, 11, 10, 0xbd3af235);
|
||||
MD5STEP(F4, c, d, a, b, 2, 15, 0x2ad7d2bb);
|
||||
MD5STEP(F4, b, c, d, a, 9, 21, 0xeb86d391);
|
||||
|
||||
a += *(unsigned __int32 *) &hash[ 0];
|
||||
b += *(unsigned __int32 *) &hash[ 4];
|
||||
c += *(unsigned __int32 *) &hash[ 8];
|
||||
d += *(unsigned __int32 *) &hash[12];
|
||||
|
||||
*(unsigned __int32 *) &hash[ 0] = a;
|
||||
*(unsigned __int32 *) &hash[ 4] = b;
|
||||
*(unsigned __int32 *) &hash[ 8] = c;
|
||||
*(unsigned __int32 *) &hash[12] = d;
|
||||
|
||||
pdata += 64;
|
||||
} while (bytecnt -= 64);
|
||||
}
|
||||
BIN
source/par1j/res_par1j.rc
Normal file
BIN
source/par1j/res_par1j.rc
Normal file
Binary file not shown.
2
source/par1j/version.h
Normal file
2
source/par1j/version.h
Normal file
@@ -0,0 +1,2 @@
|
||||
#define FILE_VERSION "1.3.2.8" // ファイルのバージョン番号
|
||||
#define PRODUCT_VERSION 0x132 // クライアントのバージョン番号
|
||||
Reference in New Issue
Block a user