Add files via upload

This commit is contained in:
Yutaka Sawada
2023-03-12 10:41:47 +09:00
committed by GitHub
parent 0f1519770b
commit e218f5f634
16 changed files with 6303 additions and 0 deletions

753
source/par1j/par1_cmd.c Normal file
View 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)) // 07 の範囲
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;
}